void NetInterface::handleConnectChallengeResponse(const Address &address, BitStream *stream) { NetConnection *conn = findPendingConnection(address); if(!conn || conn->getConnectionState() != NetConnection::AwaitingChallengeResponse) return; Nonce theNonce; theNonce.read(stream); ConnectionParameters &theParams = conn->getConnectionParameters(); if(theNonce != theParams.mNonce) return; stream->read(&theParams.mClientIdentity); // see if the server wants us to solve a client puzzle theParams.mServerNonce.read(stream); stream->read(&theParams.mPuzzleDifficulty); if(theParams.mPuzzleDifficulty > ClientPuzzleManager::MaxPuzzleDifficulty) return; // see if the connection needs to be authenticated or uses key exchange if(stream->readFlag()) { if(stream->readFlag()) { theParams.mCertificate = new Certificate(stream); if(!theParams.mCertificate->isValid() || !conn->validateCertficate(theParams.mCertificate, true)) return; theParams.mPublicKey = theParams.mCertificate->getPublicKey(); } else { theParams.mPublicKey = new AsymmetricKey(stream); if(!theParams.mPublicKey->isValid() || !conn->validatePublicKey(theParams.mPublicKey, true)) return; } if(mPrivateKey.isNull() || mPrivateKey->getKeySize() != theParams.mPublicKey->getKeySize()) { // we don't have a private key, so generate one for this connection theParams.mPrivateKey = new AsymmetricKey(theParams.mPublicKey->getKeySize()); } else theParams.mPrivateKey = mPrivateKey; theParams.mSharedSecret = theParams.mPrivateKey->computeSharedSecretKey(theParams.mPublicKey); //logprintf("shared secret (client) %s", theParams.mSharedSecret->encodeBase64()->getBuffer()); Random::read(theParams.mSymmetricKey, SymmetricCipher::KeySize); theParams.mUsingCrypto = true; } TNLLogMessageV(LogNetInterface, ("Received Challenge Response: %8x", theParams.mClientIdentity )); conn->setConnectionState(NetConnection::ComputingPuzzleSolution); conn->mConnectSendCount = 0; theParams.mPuzzleSolution = 0; conn->mConnectLastSendTime = getCurrentTime(); continuePuzzleSolution(conn); }
void NetInterface::sendConnectChallengeResponse(const Address &addr, Nonce &clientNonce, bool wantsKeyExchange, bool wantsCertificate) { PacketStream out; out.write(U8(ConnectChallengeResponse)); clientNonce.write(&out); U32 identityToken = computeClientIdentityToken(addr, clientNonce); out.write(identityToken); // write out a client puzzle Nonce serverNonce = mPuzzleManager.getCurrentNonce(); U32 difficulty = mPuzzleManager.getCurrentDifficulty(); serverNonce.write(&out); out.write(difficulty); if(out.writeFlag(mRequiresKeyExchange || (wantsKeyExchange && !mPrivateKey.isNull()))) { if(out.writeFlag(wantsCertificate && !mCertificate.isNull())) out.write(mCertificate); else out.write(mPrivateKey->getPublicKey()); } TNLLogMessageV(LogNetInterface, ("Sending Challenge Response: %8x", identityToken)); out.sendto(mSocket, addr); }
void NetInterface::handleConnectChallengeRequest(const Address &addr, BitStream *stream) { TNLLogMessageV(LogNetInterface, ("Received Connect Challenge Request from %s", addr.toString())); if(!mAllowConnections) return; Nonce clientNonce; clientNonce.read(stream); bool wantsKeyExchange = stream->readFlag(); bool wantsCertificate = stream->readFlag(); sendConnectChallengeResponse(addr, clientNonce, wantsKeyExchange, wantsCertificate); }
void NetInterface::sendConnectChallengeRequest(NetConnection *conn) { TNLLogMessageV(LogNetInterface, ("Sending Connect Challenge Request to %s", conn->getNetAddress().toString())); PacketStream out; out.write(U8(ConnectChallengeRequest)); ConnectionParameters ¶ms = conn->getConnectionParameters(); params.mNonce.write(&out); out.writeFlag(params.mRequestKeyExchange); out.writeFlag(params.mRequestCertificate); conn->mConnectSendCount++; conn->mConnectLastSendTime = getCurrentTime(); out.sendto(mSocket, conn->getNetAddress()); }
void NetInterface::handleConnectAccept(const Address &address, BitStream *stream) { Nonce nonce, serverNonce; nonce.read(stream); serverNonce.read(stream); U32 decryptPos = stream->getBytePosition(); stream->setBytePosition(decryptPos); NetConnection *conn = findPendingConnection(address); if(!conn || conn->getConnectionState() != NetConnection::AwaitingConnectResponse) return; ConnectionParameters &theParams = conn->getConnectionParameters(); if(theParams.mNonce != nonce || theParams.mServerNonce != serverNonce) return; if(theParams.mUsingCrypto) { SymmetricCipher theCipher(theParams.mSharedSecret); if(!stream->decryptAndCheckHash(NetConnection::MessageSignatureBytes, decryptPos, &theCipher)) return; } U32 recvSequence; stream->read(&recvSequence); conn->setInitialRecvSequence(recvSequence); const char *errorString = NULL; if(!conn->readConnectAccept(stream, &errorString)) { removePendingConnection(conn); return; } if(theParams.mUsingCrypto) { stream->read(SymmetricCipher::KeySize, theParams.mInitVector); conn->setSymmetricCipher(new SymmetricCipher(theParams.mSymmetricKey, theParams.mInitVector)); } addConnection(conn); // first, add it as a regular connection removePendingConnection(conn); // remove from the pending connection list conn->setConnectionState(NetConnection::Connected); conn->onConnectionEstablished(); // notify the connection that it has been established TNLLogMessageV(LogNetInterface, ("Received Connect Accept - connection established.")); }
void NetInterface::sendConnectRequest(NetConnection *conn) { TNLLogMessageV(LogNetInterface, ("Sending Connect Request")); PacketStream out; ConnectionParameters &theParams = conn->getConnectionParameters(); 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(); }
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 GhostConnection::activateGhosting() { if(!doesGhostFrom()) return; mGhostingSequence++; TNLLogMessageV(LogGhostConnection, ("Ghosting activated - %d", mGhostingSequence)); TNLAssert((mGhostFreeIndex == 0) && (mGhostZeroUpdateIndex == 0), "Error: ghosts in the ghost list before activate."); // iterate through the ghost always objects and InScope them... // also post em all to the other side. S32 j; for(j = 0; j < MaxGhostCount; j++) { mGhostArray[j] = mGhostRefs + j; mGhostArray[j]->arrayIndex = j; } mScoping = true; // so that objectInScope will work rpcStartGhosting(mGhostingSequence); //TNLAssert(validateGhostArray(), "Invalid ghost array!"); }
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::sendConnectAccept(NetConnection *conn) { TNLLogMessageV(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 GhostConnection::writePacket(BitStream *bstream, PacketNotify *pnotify) { Parent::writePacket(bstream, pnotify); GhostPacketNotify *notify = static_cast<GhostPacketNotify *>(pnotify); if(mConnectionParameters.mDebugObjectSizes) bstream->writeInt(DebugChecksum, 32); notify->ghostList = NULL; if(!doesGhostFrom()) return; if(!bstream->writeFlag(mGhosting && mScopeObject.isValid())) return; // fill a packet (or two) with ghosting data // 2. call scoped objects' priority functions if the flag set is nonzero // A removed ghost is assumed to have a high priority // 3. call updates based on sorted priority until the packet is // full. set flags to zero for all updated objects GhostInfo *walk; for(S32 i = mGhostZeroUpdateIndex - 1; i >= 0; i--) { if(!(mGhostArray[i]->flags & GhostInfo::InScope)) detachObject(mGhostArray[i]); } U32 maxIndex = 0; for(S32 i = mGhostZeroUpdateIndex - 1; i >= 0; i--) { walk = mGhostArray[i]; if(walk->index > maxIndex) maxIndex = walk->index; // clear out any kill objects that haven't been ghosted yet if((walk->flags & GhostInfo::KillGhost) && (walk->flags & GhostInfo::NotYetGhosted)) { freeGhostInfo(walk); continue; } // don't do any ghost processing on objects that are being killed // or in the process of ghosting else if(!(walk->flags & (GhostInfo::KillingGhost | GhostInfo::Ghosting))) { if(walk->flags & GhostInfo::KillGhost) walk->priority = 10000; else walk->priority = walk->obj->getUpdatePriority(mScopeObject, walk->updateMask, walk->updateSkipCount); } else walk->priority = 0; } GhostRef *updateList = NULL; qsort(mGhostArray, mGhostZeroUpdateIndex, sizeof(GhostInfo *), UQECompare); // reset the array indices... for(S32 i = mGhostZeroUpdateIndex - 1; i >= 0; i--) mGhostArray[i]->arrayIndex = i; S32 sendSize = 1; while(maxIndex >>= 1) sendSize++; if(sendSize < 3) sendSize = 3; bstream->writeInt(sendSize - 3, 3); // 0-7 3 bit number U32 count = 0; // for(S32 i = mGhostZeroUpdateIndex - 1; i >= 0 && !bstream->isFull(); i--) { GhostInfo *walk = mGhostArray[i]; if(walk->flags & (GhostInfo::KillingGhost | GhostInfo::Ghosting)) continue; size_t updateStart = bstream->getBitPosition(); U32 updateMask = walk->updateMask; U32 retMask = 0; bstream->writeFlag(true); bstream->writeInt(walk->index, sendSize); if(!bstream->writeFlag(walk->flags & GhostInfo::KillGhost)) { // this is an update of some kind: if(mConnectionParameters.mDebugObjectSizes) bstream->advanceBitPosition(BitStreamPosBitSize); size_t startPos = bstream->getBitPosition(); if(walk->flags & GhostInfo::NotYetGhosted) { S32 classId = walk->obj->getClassId(getNetClassGroup()); bstream->writeClassId(classId, NetClassTypeObject, getNetClassGroup()); NetObject::mIsInitialUpdate = true; } // update the object retMask = walk->obj->packUpdate(this, updateMask, bstream); if(NetObject::mIsInitialUpdate) { NetObject::mIsInitialUpdate = false; walk->obj->getClassRep()->addInitialUpdate(bstream->getBitPosition() - startPos); } else walk->obj->getClassRep()->addPartialUpdate(bstream->getBitPosition() - startPos); if(mConnectionParameters.mDebugObjectSizes){ size_t bpL = bstream->getBitPosition(); U32 bp = static_cast<U32>(bpL); TNLAssert(bp == bpL, "This stream position is too long"); bstream->writeIntAt(bp, BitStreamPosBitSize, startPos - BitStreamPosBitSize); } TNLLogMessageV(LogGhostConnection, ("GhostConnection %s GHOST %d", walk->obj->getClassName(), bstream->getBitPosition() - 16 - startPos)); TNLAssert((retMask & (~updateMask)) == 0, "Cannot set new bits in packUpdate return"); } // check for packet overrun, and rewind this update if there // was one: if(bstream->getBitSpaceAvailable() < MinimumPaddingBits) { bstream->setBitPosition(updateStart); bstream->clearError(); break; } // otherwise, create a record of this ghost update and // attach it to the packet. GhostRef *upd = new GhostRef; upd->nextRef = updateList; updateList = upd; if(walk->lastUpdateChain) walk->lastUpdateChain->updateChain = upd; walk->lastUpdateChain = upd; upd->ghost = walk; upd->ghostInfoFlags = 0; upd->updateChain = NULL; if(walk->flags & GhostInfo::KillGhost) { walk->flags &= ~GhostInfo::KillGhost; walk->flags |= GhostInfo::KillingGhost; walk->updateMask = 0; upd->mask = updateMask; ghostPushToZero(walk); upd->ghostInfoFlags = GhostInfo::KillingGhost; } else { if(walk->flags & GhostInfo::NotYetGhosted) { walk->flags &= ~GhostInfo::NotYetGhosted; walk->flags |= GhostInfo::Ghosting; upd->ghostInfoFlags = GhostInfo::Ghosting; } walk->updateMask = retMask; if(!retMask) ghostPushToZero(walk); upd->mask = updateMask & ~retMask; walk->updateSkipCount = 0; count++; } } // count # of ghosts have been updated, // mGhostZeroUpdateIndex # of ghosts remain to be updated. // no more objects... bstream->writeFlag(false); notify->ghostList = updateList; }
void NetInterface::handlePunch(const Address &theAddress, BitStream *stream) { S32 i, j; NetConnection *conn; Nonce firstNonce; firstNonce.read(stream); ByteBuffer b(firstNonce.data, Nonce::NonceSize); TNLLogMessageV(LogNetInterface, ("Received punch packet from %s - %s", theAddress.toString(), b.encodeBase64()->getBuffer())); for(i = 0; i < mPendingConnections.size(); i++) { conn = mPendingConnections[i]; ConnectionParameters &theParams = conn->getConnectionParameters(); if(conn->getConnectionState() != NetConnection::SendingPunchPackets) continue; if((theParams.mIsInitiator && firstNonce != theParams.mServerNonce) || (!theParams.mIsInitiator && firstNonce != theParams.mNonce)) continue; // first see if the address is in the possible addresses list: for(j = 0; j < theParams.mPossibleAddresses.size(); j++) if(theAddress == theParams.mPossibleAddresses[j]) break; // if there was an exact match, just exit the loop, or // continue on to the next pending if this is not an initiator: if(j != theParams.mPossibleAddresses.size()) { if(theParams.mIsInitiator) break; else continue; } // if there was no exact match, we may have a funny NAT in the // middle. But since a packet got through from the remote host // we'll want to send a punch to the address it came from, as long // as only the port is not an exact match: for(j = 0; j < theParams.mPossibleAddresses.size(); j++) if(theAddress.isEqualAddress(theParams.mPossibleAddresses[j])) break; // if the address wasn't even partially in the list, just exit out if(j == theParams.mPossibleAddresses.size()) continue; // otherwise, as long as we don't have too many ping addresses, // add this one to the list: if(theParams.mPossibleAddresses.size() < 5) theParams.mPossibleAddresses.push_back(theAddress); // if this is the initiator of the arranged connection, then // process the punch packet from the remote host by issueing a // connection request. if(theParams.mIsInitiator) break; } if(i == mPendingConnections.size()) return; ConnectionParameters &theParams = conn->getConnectionParameters(); SymmetricCipher theCipher(theParams.mArrangedSecret); if(!stream->decryptAndCheckHash(NetConnection::MessageSignatureBytes, stream->getBytePosition(), &theCipher)) return; Nonce nextNonce; nextNonce.read(stream); if(nextNonce != theParams.mNonce) return; // see if the connection needs to be authenticated or uses key exchange if(stream->readFlag()) { if(stream->readFlag()) { theParams.mCertificate = new Certificate(stream); if(!theParams.mCertificate->isValid() || !conn->validateCertficate(theParams.mCertificate, true)) return; theParams.mPublicKey = theParams.mCertificate->getPublicKey(); } else { theParams.mPublicKey = new AsymmetricKey(stream); if(!theParams.mPublicKey->isValid() || !conn->validatePublicKey(theParams.mPublicKey, true)) return; } if(mPrivateKey.isNull() || mPrivateKey->getKeySize() != theParams.mPublicKey->getKeySize()) { // we don't have a private key, so generate one for this connection theParams.mPrivateKey = new AsymmetricKey(theParams.mPublicKey->getKeySize()); } else theParams.mPrivateKey = mPrivateKey; theParams.mSharedSecret = theParams.mPrivateKey->computeSharedSecretKey(theParams.mPublicKey); //logprintf("shared secret (client) %s", theParams.mSharedSecret->encodeBase64()->getBuffer()); Random::read(theParams.mSymmetricKey, SymmetricCipher::KeySize); theParams.mUsingCrypto = true; } conn->setNetAddress(theAddress); TNLLogMessageV(LogNetInterface, ("Punch from %s matched nonces - connecting...", theAddress.toString())); conn->setConnectionState(NetConnection::AwaitingConnectResponse); conn->mConnectSendCount = 0; conn->mConnectLastSendTime = getCurrentTime(); sendArrangedConnectRequest(conn); }
void NetInterface::handleConnectRequest(const Address &address, BitStream *stream) { if(!mAllowConnections) return; ConnectionParameters theParams; theParams.mNonce.read(stream); theParams.mServerNonce.read(stream); stream->read(&theParams.mClientIdentity); if(theParams.mClientIdentity != computeClientIdentityToken(address, theParams.mNonce)) return; stream->read(&theParams.mPuzzleDifficulty); stream->read(&theParams.mPuzzleSolution); // see if the connection is in the main connection table. // If the connection is in the connection table and it has // the same initiatorSequence, we'll just resend the connect // acceptance packet, assuming that the last time we sent it // it was dropped. NetConnection *connect = findConnection(address); if(connect) { ConnectionParameters &cp = connect->getConnectionParameters(); if(cp.mNonce == theParams.mNonce && cp.mServerNonce == theParams.mServerNonce) { sendConnectAccept(connect); return; } } // check the puzzle solution ClientPuzzleManager::ErrorCode result = mPuzzleManager.checkSolution( theParams.mPuzzleSolution, theParams.mNonce, theParams.mServerNonce, theParams.mPuzzleDifficulty, theParams.mClientIdentity); if(result != ClientPuzzleManager::Success) { sendConnectReject(&theParams, address, "Puzzle"); return; } if(stream->readFlag()) { if(mPrivateKey.isNull()) return; theParams.mUsingCrypto = true; theParams.mPublicKey = new AsymmetricKey(stream); theParams.mPrivateKey = mPrivateKey; U32 decryptPos = stream->getBytePosition(); stream->setBytePosition(decryptPos); theParams.mSharedSecret = theParams.mPrivateKey->computeSharedSecretKey(theParams.mPublicKey); //logprintf("shared secret (server) %s", theParams.mSharedSecret->encodeBase64()->getBuffer()); SymmetricCipher theCipher(theParams.mSharedSecret); if(!stream->decryptAndCheckHash(NetConnection::MessageSignatureBytes, decryptPos, &theCipher)) return; // now read the first part of the connection's symmetric key stream->read(SymmetricCipher::KeySize, theParams.mSymmetricKey); Random::read(theParams.mInitVector, SymmetricCipher::KeySize); } U32 connectSequence; theParams.mDebugObjectSizes = stream->readFlag(); stream->read(&connectSequence); TNLLogMessageV(LogNetInterface, ("Received Connect Request %8x", theParams.mClientIdentity)); if(connect) disconnect(connect, NetConnection::ReasonSelfDisconnect, "NewConnection"); char connectionClass[256]; stream->readString(connectionClass); NetConnection *conn = NetConnectionRep::create(connectionClass); if(!conn) return; RefPtr<NetConnection> theConnection = conn; conn->getConnectionParameters() = theParams; conn->setNetAddress(address); conn->setInitialRecvSequence(connectSequence); conn->setInterface(this); if(theParams.mUsingCrypto) conn->setSymmetricCipher(new SymmetricCipher(theParams.mSymmetricKey, theParams.mInitVector)); const char *errorString = NULL; if(!conn->readConnectRequest(stream, &errorString)) { sendConnectReject(&theParams, address, errorString); return; } addConnection(conn); conn->setConnectionState(NetConnection::Connected); conn->onConnectionEstablished(); sendConnectAccept(conn); }
void NetInterface::handleArrangedConnectRequest(const Address &theAddress, BitStream *stream) { S32 i, j; NetConnection *conn; Nonce nonce, serverNonce; nonce.read(stream); // see if the connection is in the main connection table. // If the connection is in the connection table and it has // the same initiatorSequence, we'll just resend the connect // acceptance packet, assuming that the last time we sent it // it was dropped. NetConnection *oldConnection = findConnection(theAddress); if(oldConnection) { ConnectionParameters &cp = oldConnection->getConnectionParameters(); if(cp.mNonce == nonce) { sendConnectAccept(oldConnection); return; } } for(i = 0; i < mPendingConnections.size(); i++) { conn = mPendingConnections[i]; ConnectionParameters &theParams = conn->getConnectionParameters(); if(conn->getConnectionState() != NetConnection::SendingPunchPackets || theParams.mIsInitiator) continue; if(nonce != theParams.mNonce) continue; for(j = 0; j < theParams.mPossibleAddresses.size(); j++) if(theAddress.isEqualAddress(theParams.mPossibleAddresses[j])) break; if(j != theParams.mPossibleAddresses.size()) break; } if(i == mPendingConnections.size()) return; ConnectionParameters &theParams = conn->getConnectionParameters(); SymmetricCipher theCipher(theParams.mArrangedSecret); if(!stream->decryptAndCheckHash(NetConnection::MessageSignatureBytes, stream->getBytePosition(), &theCipher)) return; stream->setBytePosition(stream->getBytePosition()); serverNonce.read(stream); if(serverNonce != theParams.mServerNonce) return; if(stream->readFlag()) { if(mPrivateKey.isNull()) return; theParams.mUsingCrypto = true; theParams.mPublicKey = new AsymmetricKey(stream); theParams.mPrivateKey = mPrivateKey; U32 decryptPos = stream->getBytePosition(); stream->setBytePosition(decryptPos); theParams.mSharedSecret = theParams.mPrivateKey->computeSharedSecretKey(theParams.mPublicKey); SymmetricCipher theCipher(theParams.mSharedSecret); if(!stream->decryptAndCheckHash(NetConnection::MessageSignatureBytes, decryptPos, &theCipher)) return; // now read the first part of the connection's session (symmetric) key stream->read(SymmetricCipher::KeySize, theParams.mSymmetricKey); Random::read(theParams.mInitVector, SymmetricCipher::KeySize); } U32 connectSequence; theParams.mDebugObjectSizes = stream->readFlag(); stream->read(&connectSequence); TNLLogMessageV(LogNetInterface, ("Received Arranged Connect Request")); if(oldConnection) disconnect(oldConnection, NetConnection::ReasonSelfDisconnect, ""); conn->setNetAddress(theAddress); conn->setInitialRecvSequence(connectSequence); if(theParams.mUsingCrypto) conn->setSymmetricCipher(new SymmetricCipher(theParams.mSymmetricKey, theParams.mInitVector)); const char *errorString = NULL; if(!conn->readConnectRequest(stream, &errorString)) { sendConnectReject(&theParams, theAddress, errorString); removePendingConnection(conn); return; } addConnection(conn); removePendingConnection(conn); conn->setConnectionState(NetConnection::Connected); conn->onConnectionEstablished(); sendConnectAccept(conn); }