void NetInterface::handleConnectReject(const Address &address, BitStream *stream)
{
   Nonce nonce;
   Nonce serverNonce;

   nonce.read(stream);
   serverNonce.read(stream);

   NetConnection *conn = findPendingConnection(address);
   if(!conn || (conn->getConnectionState() != NetConnection::AwaitingChallengeResponse &&
                conn->getConnectionState() != NetConnection::AwaitingConnectResponse))
      return;
   ConnectionParameters &p = conn->getConnectionParameters();
   if(p.mNonce != nonce || p.mServerNonce != serverNonce)
      return;


   NetConnection::TerminationReason reason = (NetConnection::TerminationReason) stream->readEnum(NetConnection::TerminationReasons);

   char reasonStr[256];
   stream->readString(reasonStr);

   logprintf(LogConsumer::LogNetInterface, "Received Connect Reject - reason code %d (%s)", reason, reasonStr);

   // If the reason is a bad puzzle solution, try once more with a new nonce
   if(reason == NetConnection::ReasonPuzzle && !p.mPuzzleRetried)
   {
      p.mPuzzleRetried = true;
      conn->setConnectionState(NetConnection::AwaitingChallengeResponse);
      conn->mConnectSendCount = 0;
      p.mNonce.getRandom();                  // Generate new nonce
      sendConnectChallengeRequest(conn);
      return;
   }

   conn->setConnectionState(NetConnection::ConnectRejected);
   conn->onConnectTerminated(reason, reasonStr);
   removePendingConnection(conn);
}
void NetInterface::handleConnectReject(const Address &address, BitStream *stream)
{
   Nonce nonce;
   Nonce serverNonce;

   nonce.read(stream);
   serverNonce.read(stream);

   NetConnection *conn = findPendingConnection(address);
   if(!conn || (conn->getConnectionState() != NetConnection::AwaitingChallengeResponse &&
                conn->getConnectionState() != NetConnection::AwaitingConnectResponse))
      return;
   ConnectionParameters &p = conn->getConnectionParameters();
   if(p.mNonce != nonce || p.mServerNonce != serverNonce)
      return;

   char reason[256];
   stream->readString(reason);

   TNLLogMessageV(LogNetInterface, ("Received Connect Reject - reason %s", reason));
   // if the reason is a bad puzzle solution, try once more with a
   // new nonce.
   if(!strcmp(reason, "Puzzle") && !p.mPuzzleRetried)
   {
      p.mPuzzleRetried = true;
      conn->setConnectionState(NetConnection::AwaitingChallengeResponse);
      conn->mConnectSendCount = 0;
      p.mNonce.getRandom();
      sendConnectChallengeRequest(conn);
      return;
   }

   conn->setConnectionState(NetConnection::ConnectRejected);
   conn->onConnectTerminated(NetConnection::ReasonRemoteHostRejectedConnection, reason);
   removePendingConnection(conn);
}
void NetInterface::processConnections()
{
   mCurrentTime = Platform::getRealMilliseconds();
   mPuzzleManager.tick(mCurrentTime);

   // first see if there are any delayed packets that need to be sent...
   while(mSendPacketList && mSendPacketList->sendTime < getCurrentTime())
   {
      DelaySendPacket *next = mSendPacketList->nextPacket;
      mSocket.sendto(mSendPacketList->remoteAddress,
            mSendPacketList->packetData, mSendPacketList->packetSize);
      free(mSendPacketList);
      mSendPacketList = next;
   }

   NetObject::collapseDirtyList(); // collapse all the mask bits...
   for(S32 i = 0; i < mConnectionList.size(); i++)
      mConnectionList[i]->checkPacketSend(false, getCurrentTime());

   if(getCurrentTime() > mLastTimeoutCheckTime + TimeoutCheckInterval)
   {
      for(S32 i = 0; i < mPendingConnections.size();)
      {
         NetConnection *pending = mPendingConnections[i];

         if(pending->getConnectionState() == NetConnection::AwaitingChallengeResponse &&
            getCurrentTime() > pending->mConnectLastSendTime + ChallengeRetryTime)
         {
            if(pending->mConnectSendCount > ChallengeRetryCount)
            {
               pending->setConnectionState(NetConnection::ConnectTimedOut);
               pending->onConnectTerminated(NetConnection::ReasonTimedOut, "Timeout");
               removePendingConnection(pending);
               continue;
            }
            else
               sendConnectChallengeRequest(pending);
         }
         else if(pending->getConnectionState() == NetConnection::AwaitingConnectResponse &&
            getCurrentTime() > pending->mConnectLastSendTime + ConnectRetryTime)
         {
            if(pending->mConnectSendCount > ConnectRetryCount)
            {
               pending->setConnectionState(NetConnection::ConnectTimedOut);
               pending->onConnectTerminated(NetConnection::ReasonTimedOut, "Timeout");
               removePendingConnection(pending);
               continue;
            }
            else
            {
               if(pending->getConnectionParameters().mIsArranged)
                  sendArrangedConnectRequest(pending);
               else
                  sendConnectRequest(pending);
            }
         }
         else if(pending->getConnectionState() == NetConnection::SendingPunchPackets &&
            getCurrentTime() > pending->mConnectLastSendTime + PunchRetryTime)
         {
            if(pending->mConnectSendCount > PunchRetryCount)
            {
               pending->setConnectionState(NetConnection::ConnectTimedOut);
               pending->onConnectTerminated(NetConnection::ReasonTimedOut, "Timeout");
               removePendingConnection(pending);
               continue;
            }
            else
               sendPunchPackets(pending);
         }
         else if(pending->getConnectionState() == NetConnection::ComputingPuzzleSolution &&
            getCurrentTime() > pending->mConnectLastSendTime + PuzzleSolutionTimeout)
         {
            pending->setConnectionState(NetConnection::ConnectTimedOut);
            pending->onConnectTerminated(NetConnection::ReasonTimedOut, "Timeout");
            removePendingConnection(pending);
         }
         i++;
      }
      mLastTimeoutCheckTime = getCurrentTime();

      for(S32 i = 0; i < mConnectionList.size();)
      {
         if(mConnectionList[i]->checkTimeout(getCurrentTime()))
         {
            mConnectionList[i]->setConnectionState(NetConnection::TimedOut);
            mConnectionList[i]->onConnectionTerminated(NetConnection::ReasonTimedOut, "Timeout");
            removeConnection(mConnectionList[i]);
         }
         else
            i++;
      }
   }

   // check if we're trying to solve any client connection puzzles
   for(S32 i = 0; i < mPendingConnections.size(); i++)
   {
      if(mPendingConnections[i]->getConnectionState() == NetConnection::ComputingPuzzleSolution)
      {
         continuePuzzleSolution(mPendingConnections[i]);
         break;
      }
   }
}