#include "socket.h" #include "bouncer.h" #include "packetreader.h" Socket::Socket(QObject *parent) : QObject(parent) { m_identified = false; m_socket = NULL; m_lastSentPacketID = 0; m_lastReceivedPacketID = 0; qDebug("[%p] Socket::Socket()", this); } Socket::~Socket() { unlinkSocket(/*disconnect=*/true); qDebug("[%p] Socket::~Socket()", this); } void Socket::setup(QTcpSocket *socket) { unlinkSocket(/*disconnect=*/true); socket->setParent(this); m_socket = socket; m_readBuffer.clear(); m_handshakeStatus = 0; connect(socket, SIGNAL(connected()), this, SLOT(socketConnected())); connect(socket, SIGNAL(readyRead()), this, SLOT(socketReceived())); connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError(QAbstractSocket::SocketError))); connect(socket, SIGNAL(disconnected()), this, SLOT(socketDisconnected())); } void Socket::unlinkSocket(bool disconnect) { if (!m_socket) return; qDebug("[%p] Socket::unlinkSocket...", this); QObject::disconnect(m_socket, SIGNAL(connected()), this, SLOT(socketConnected())); QObject::disconnect(m_socket, SIGNAL(readyRead()), this, SLOT(socketReceived())); QObject::disconnect(m_socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError(QAbstractSocket::SocketError))); QObject::disconnect(m_socket, SIGNAL(disconnected()), this, SLOT(socketDisconnected())); if (disconnect) { m_socket->flush(); m_socket->close(); m_socket->deleteLater(); } m_socket = NULL; } void Socket::socketReceived() { QByteArray readIt = m_socket->readAll(); m_readBuffer.append(readIt); quint8 *buf = (quint8 *)m_readBuffer.data(); int bufSize = m_readBuffer.length(); int position = 0; while ((position + 8) <= bufSize) { PacketReader reader(&buf[position], bufSize - position); quint32 packetType = reader.readU32(); quint32 packetSize = reader.readU32(); if (bufSize > 128000 || packetSize > 128000) { // Something's not right here... // (TODO: investigate if this is really a good thing to do?) m_readBuffer.clear(); return; } // Out-of-band packets have 8 bytes header, otherwise 16 bytes int headerSize = 8; if (!(packetType & 0x80000000)) headerSize = 16; if (bufSize >= (position + packetSize + headerSize)) { // We have the whole of this packet // If it's not out-of-band, deal with the IDs qDebug("Recv: [%08x] %d bytes", packetType, packetSize); bool isUnnecessaryPacket = false; if (!(packetType & 0x80000000)) { quint32 packetID = reader.readU32(); quint32 lastReceivedID = reader.readU32(); // Clear messages they already have from our own cache clearAcknowledgedPackets(lastReceivedID); if (packetID > m_lastReceivedPacketID) { // New packet, so update this m_lastReceivedPacketID = packetID; } else { // We already got this packet (presumably)... // ...so ignore it! isUnnecessaryPacket = true; } qDebug(" packetID=%d, lastReceivedID=%d", packetID, lastReceivedID); } // If we haven't received this message, handle it! if (!isUnnecessaryPacket) { PacketReader subReader(&buf[position + headerSize], packetSize); handlePacket(packetType, subReader); } position += headerSize + packetSize; } else { // We don't have the whole of this packet yet, so wait. break; } } // If we managed to handle anything, lop it off the buffer if (position > 0) { if (position >= bufSize) { m_readBuffer.clear(); } else { memmove(buf, &buf[position], bufSize - position); m_readBuffer.resize(bufSize - position); } } } void Socket::socketConnected() { // we do nothing here, but this is used by Client } void Socket::socketError(QAbstractSocket::SocketError error) { // welp! qDebug("Connection error!"); unlinkSocket(/*disconnect=*/true); if (!m_identified) emit finished(); } void Socket::socketDisconnected() { // welp 2. qDebug("Connection closed!"); unlinkSocket(/*disconnect=*/true); if (!m_identified) emit finished(); } void Socket::takeOverSocket(Socket *donor) { setup(donor->m_socket); m_readBuffer = donor->m_readBuffer; donor->unlinkSocket(/*disconnect=*/false); emit donor->finished(); } void Socket::sendPacketOverSocket(const Packet &packet) { quint32 packetHeader[4]; int headerSize = 8; packetHeader[0] = packet.type; packetHeader[1] = packet.data.size(); if (!packet.isOutOfBand()) { headerSize = 16; packetHeader[2] = packet.id; packetHeader[3] = m_lastReceivedPacketID; } m_socket->write((const char *)&packetHeader, headerSize); m_socket->write(packet.data); } void Socket::clearAcknowledgedPackets(int lastReceivedID) { while (!m_packetCache.empty() && m_packetCache.at(0).id <= lastReceivedID) m_packetCache.removeFirst(); } void Socket::flushPacketCache() { foreach (const Packet &packet, m_packetCache) sendPacketOverSocket(packet); } void Socket::handlePacket(int type, PacketReader &reader) { // stub (void)type; (void)reader; } void Socket::sendPacket(Packet &packet, bool isHandshakePacket) { if (!packet.isOutOfBand()) { m_lastSentPacketID++; packet.id = m_lastSentPacketID; m_packetCache.append(packet); } if ((m_socket != NULL) && (isHandshakePacket || (m_handshakeStatus > 0))) sendPacketOverSocket(packet); else if (packet.isOutOfBand()) qWarning("WARNING: Out-of-band message %08x was lost!", packet.type); }