- // FIXME: make sure _peer gets deleted
- // TODO: socket ownership goes to the peer! (-> use shared ptr later...)
- _peer = new LegacyPeer(this, socket, this);
- // only in compat mode
- connect(_peer, SIGNAL(protocolVersionMismatch(int,int)), SLOT(onProtocolVersionMismatch(int,int)));
+ socket()->read((char*)&magic, 4); // read the 4 bytes we've just peeked at
+ }
+
+ // read the list of protocols supported by the client
+ while (socket()->bytesAvailable() >= 4 && _supportedProtos.size() < 16) { // sanity check
+ quint32 data;
+ socket()->read((char*)&data, 4);
+ data = qFromBigEndian<quint32>(data);
+
+ auto type = static_cast<Protocol::Type>(data & 0xff);
+ auto protoFeatures = static_cast<quint16>(data >> 8 & 0xffff);
+ _supportedProtos.append(PeerFactory::ProtoDescriptor(type, protoFeatures));
+
+ if (data >= 0x80000000) { // last protocol
+ Compressor::CompressionLevel level;
+ if (_connectionFeatures & Protocol::Compression)
+ level = Compressor::BestCompression;
+ else
+ level = Compressor::NoCompression;
+
+ RemotePeer* peer = PeerFactory::createPeer(_supportedProtos, this, socket(), level, this);
+ if (!peer) {
+ qWarning() << "Received invalid handshake data from client" << socket()->peerAddress().toString();
+ close();
+ return;
+ }
+
+ if (peer->protocol() == Protocol::LegacyProtocol) {
+ _legacy = true;
+ connect(peer, &RemotePeer::protocolVersionMismatch, this, &CoreAuthHandler::onProtocolVersionMismatch);
+ }
+ setPeer(peer);
+
+ // inform the client
+ quint32 reply = peer->protocol() | peer->enabledFeatures() << 8 | _connectionFeatures << 24;
+ reply = qToBigEndian<quint32>(reply);
+ socket()->write((char*)&reply, 4);
+ socket()->flush();
+
+ if (!_legacy && (_connectionFeatures & Protocol::Encryption))
+ startSsl(); // legacy peer enables it later
+ return;
+ }
+ }