diff options
Diffstat (limited to '')
-rw-r--r-- | server/socket.cpp | 214 |
1 files changed, 214 insertions, 0 deletions
diff --git a/server/socket.cpp b/server/socket.cpp new file mode 100644 index 0000000..56c5258 --- /dev/null +++ b/server/socket.cpp @@ -0,0 +1,214 @@ +#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); +} |