void NetInterface::disconnect(NetConnection *conn, NetConnection::TerminationReason reason, const char *reasonString)
{
   if(conn->getConnectionState() == NetConnection::AwaitingChallengeResponse ||
      conn->getConnectionState() == NetConnection::AwaitingConnectResponse)
   {
      conn->onConnectTerminated(reason, reasonString);
      removePendingConnection(conn);
   }
   else if(conn->getConnectionState() == NetConnection::Connected)
   {
      conn->setConnectionState(NetConnection::Disconnected);
      conn->onConnectionTerminated(reason, reasonString);
      if(conn->isNetworkConnection())
      {
         // send a disconnect packet...
         PacketStream out;
         out.write(U8(Disconnect));
         ConnectionParameters &theParams = conn->getConnectionParameters();
         theParams.mNonce.write(&out);
         theParams.mServerNonce.write(&out);
         U32 encryptPos = out.getBytePosition();
         out.setBytePosition(encryptPos);
         out.writeString(reasonString);

         if(theParams.mUsingCrypto)
         {
            SymmetricCipher theCipher(theParams.mSharedSecret);
            out.hashAndEncrypt(NetConnection::MessageSignatureBytes, encryptPos, &theCipher);
         }
         out.sendto(mSocket, conn->getNetAddress());
      }
      removeConnection(conn);
   }
}
void NetInterface::sendConnectAccept(NetConnection *conn)
{
   logprintf(LogConsumer::LogNetInterface, "Sending Connect Accept - connection established.");

   PacketStream out;
   out.write(U8(ConnectAccept));
   ConnectionParameters &theParams = conn->getConnectionParameters();

   theParams.mNonce.write(&out);
   theParams.mServerNonce.write(&out);
   U32 encryptPos = out.getBytePosition();
   out.setBytePosition(encryptPos);

   out.write(conn->getInitialSendSequence());
   conn->writeConnectAccept(&out);

   if(theParams.mUsingCrypto)
   {
      out.write(SymmetricCipher::KeySize, theParams.mInitVector);
      SymmetricCipher theCipher(theParams.mSharedSecret);
      out.hashAndEncrypt(NetConnection::MessageSignatureBytes, encryptPos, &theCipher);
   }

   out.sendto(mSocket, conn->getNetAddress());
}
void NetInterface::sendArrangedConnectRequest(NetConnection *conn)
{
   TNLLogMessageV(LogNetInterface, ("Sending Arranged Connect Request"));
   PacketStream out;

   ConnectionParameters &theParams = conn->getConnectionParameters();

   out.write(U8(ArrangedConnectRequest));
   theParams.mNonce.write(&out);
   U32 encryptPos = out.getBytePosition();
   U32 innerEncryptPos = 0;

   out.setBytePosition(encryptPos);

   theParams.mServerNonce.write(&out);
   if(out.writeFlag(theParams.mUsingCrypto))
   {
      out.write(theParams.mPrivateKey->getPublicKey());
      innerEncryptPos = out.getBytePosition();
      out.setBytePosition(innerEncryptPos);
      out.write(SymmetricCipher::KeySize, theParams.mSymmetricKey);
   }
   out.writeFlag(theParams.mDebugObjectSizes);
   out.write(conn->getInitialSendSequence());
   conn->writeConnectRequest(&out);

   if(innerEncryptPos)
   {
      SymmetricCipher theCipher(theParams.mSharedSecret);
      out.hashAndEncrypt(NetConnection::MessageSignatureBytes, innerEncryptPos, &theCipher);
   }
   SymmetricCipher theCipher(theParams.mArrangedSecret);
   out.hashAndEncrypt(NetConnection::MessageSignatureBytes, encryptPos, &theCipher);

   conn->mConnectSendCount++;
   conn->mConnectLastSendTime = getCurrentTime();

   out.sendto(mSocket, conn->getNetAddress());
}
void NetInterface::sendConnectRequest(NetConnection *conn)
{
   PacketStream out;
   ConnectionParameters &theParams = conn->getConnectionParameters();

   const char *destDescr;
   if(theParams.mIsLocal)
      destDescr = "local in-process server";
   else
      destDescr = conn->getNetAddress().toString();

   logprintf(LogConsumer::LogNetInterface, "Sending connect request to %s", destDescr);

   out.write(U8(ConnectRequest));
   theParams.mNonce.write(&out);
   theParams.mServerNonce.write(&out);
   out.write(theParams.mClientIdentity);
   out.write(theParams.mPuzzleDifficulty);
   out.write(theParams.mPuzzleSolution);

   U32 encryptPos = 0;

   if(out.writeFlag(theParams.mUsingCrypto))
   {
      out.write(theParams.mPrivateKey->getPublicKey());
      encryptPos = out.getBytePosition();
      out.setBytePosition(encryptPos);
      out.write(SymmetricCipher::KeySize, theParams.mSymmetricKey);
   }
   out.writeFlag(theParams.mDebugObjectSizes);
   out.write(conn->getInitialSendSequence());
   out.writeString(conn->getClassName());
   conn->writeConnectRequest(&out);

   if(encryptPos)
   {
      // if we're using crypto on this connection,
      // then write a hash of everything we wrote into the packet
      // key.  Then we'll symmetrically encrypt the packet from
      // the end of the public key to the end of the signature.

      SymmetricCipher theCipher(theParams.mSharedSecret);
      out.hashAndEncrypt(NetConnection::MessageSignatureBytes, encryptPos, &theCipher);
   }

   conn->mConnectSendCount++;
   conn->mConnectLastSendTime = getCurrentTime();

   out.sendto(mSocket, conn->getNetAddress());
}
void NetInterface::sendPunchPackets(NetConnection *conn)
{
   ConnectionParameters &theParams = conn->getConnectionParameters();
   PacketStream out;
   out.write(U8(Punch));

   if(theParams.mIsInitiator)
      theParams.mNonce.write(&out);
   else
      theParams.mServerNonce.write(&out);

   U32 encryptPos = out.getBytePosition();
   out.setBytePosition(encryptPos);

   if(theParams.mIsInitiator)
      theParams.mServerNonce.write(&out);
   else
   {
      theParams.mNonce.write(&out);
      if(out.writeFlag(mRequiresKeyExchange || (theParams.mRequestKeyExchange && !mPrivateKey.isNull())))
      {
         if(out.writeFlag(theParams.mRequestCertificate && !mCertificate.isNull()))
            out.write(mCertificate);
         else
            out.write(mPrivateKey->getPublicKey());
      }
   }
   SymmetricCipher theCipher(theParams.mArrangedSecret);
   out.hashAndEncrypt(NetConnection::MessageSignatureBytes, encryptPos, &theCipher);

   for(S32 i = 0; i < theParams.mPossibleAddresses.size(); i++)
   {
      out.sendto(mSocket, theParams.mPossibleAddresses[i]);

      TNLLogMessageV(LogNetInterface, ("Sending punch packet (%s, %s) to %s",
         ByteBuffer(theParams.mNonce.data, Nonce::NonceSize).encodeBase64()->getBuffer(),
         ByteBuffer(theParams.mServerNonce.data, Nonce::NonceSize).encodeBase64()->getBuffer(),
         theParams.mPossibleAddresses[i].toString()));
   }
   conn->mConnectSendCount++;
   conn->mConnectLastSendTime = getCurrentTime();
}