From e53274c4ddd9986ca679b398d447f25a0cba889d Mon Sep 17 00:00:00 2001 From: Drew Fisher Date: Wed, 16 Apr 2014 22:13:19 -0700 Subject: [PATCH] Parse and validate messages as JSON Disconnect clients that send invalid frames Log the invalid frames and the hex --- ribbon/ribbonserver.cpp | 13 +++++++++++-- ribbon/ribbonsocket.cpp | 27 +++++++++++++++++---------- ribbon/ribbonsocket.h | 2 ++ 3 files changed, 30 insertions(+), 12 deletions(-) diff --git a/ribbon/ribbonserver.cpp b/ribbon/ribbonserver.cpp index 1c2ea15..1c8e3a8 100644 --- a/ribbon/ribbonserver.cpp +++ b/ribbon/ribbonserver.cpp @@ -3,6 +3,7 @@ #include #include +#include #include RibbonServer::RibbonServer(QObject* parent) : @@ -54,6 +55,14 @@ void RibbonServer::onDisconnection(RibbonSocket* r) void RibbonServer::onMessageReceived(RibbonSocket* r, QByteArray buf) { qDebug() << "server: got data from" << r->s()->peerAddress() << r->s()->peerPort(); - qDebug() << " message was:" << buf.constData(); - // TODO: do something with the packet in buf.constData() + QJsonParseError err; + QJsonDocument json = QJsonDocument::fromJson(buf, &err); + if (json.isNull()) { + qWarning() << "Json did not validate:" << err.errorString(); + qWarning() << buf.constData(); + qWarning() << "hexencoded:" << buf.toHex().constData(); + r->abort(); + } else { + qDebug() << "json document:" << json; + } } diff --git a/ribbon/ribbonsocket.cpp b/ribbon/ribbonsocket.cpp index 8b7e2e5..c9c5dc9 100644 --- a/ribbon/ribbonsocket.cpp +++ b/ribbon/ribbonsocket.cpp @@ -1,16 +1,18 @@ #include "ribbonsocket.h" -#include RibbonSocket::RibbonSocket(QTcpSocket* sock, QObject* parent) : QObject(parent), socket(sock), state(WANT_LENGTH), - bytes_wanted(0) + bytes_wanted(0), + aborting(false) { QObject::connect(socket, SIGNAL(disconnected()), this, SLOT(onDisconnect())); QObject::connect(socket, SIGNAL(readyRead()), this, SLOT(onReadyRead())); + // Take ownership of the socket + socket->setParent(this); } RibbonSocket::~RibbonSocket() @@ -22,6 +24,12 @@ const QTcpSocket* RibbonSocket::s() return socket; } +void RibbonSocket::abort() +{ + aborting = true; + socket->abort(); +} + void RibbonSocket::onDisconnect() { emit disconnected(this); @@ -35,7 +43,6 @@ bool RibbonSocket::tryProcess() { switch(state) { case WANT_LENGTH: - qDebug() << "Want length, buf size before read:" << buf.length(); if (readUntilBufHas(4)) { // Slice 4 octets off as big-endian integer QByteArray size_buf = buf.left(4); @@ -46,19 +53,17 @@ bool RibbonSocket::tryProcess() // TODO: decide on a maximum acceptable packet length, to avoid // arbitrarily large packet buffer buf.reserve(bytes_wanted); - qDebug() << "length:" << bytes_wanted; + qDebug() << "socket: got length:" << bytes_wanted; state = WANT_DATA; return true; } break; case WANT_DATA: - qDebug() << "Want data, buf size before read:" << buf.length(); if (readUntilBufHas(bytes_wanted)) { QByteArray data = buf.left(bytes_wanted); buf = buf.mid(bytes_wanted); // Memory optimization: release the rest of the buffer buf.squeeze(); - qDebug() << "data:" << buf; emit messageReceived(this, data); state = WANT_LENGTH; return true; @@ -74,10 +79,12 @@ bool RibbonSocket::tryProcess() */ bool RibbonSocket::readUntilBufHas(int desired_buffer_length) { - int size_to_read = desired_buffer_length - buf.length(); - QByteArray tmp = socket->read(size_to_read); - qDebug() << "read" << tmp.length() << "from socket"; - buf += tmp; + // If we're shutting down the socket, don't try to read more from it + if (!aborting) { + int size_to_read = desired_buffer_length - buf.length(); + QByteArray tmp = socket->read(size_to_read); + buf += tmp; + } return buf.length() >= desired_buffer_length; } diff --git a/ribbon/ribbonsocket.h b/ribbon/ribbonsocket.h index e72ab6c..672c4b8 100644 --- a/ribbon/ribbonsocket.h +++ b/ribbon/ribbonsocket.h @@ -15,6 +15,7 @@ public: RibbonSocket(QTcpSocket* socket, QObject* parent=0); // Consider s to be final. Don't modify it. const QTcpSocket* s(); + void abort(); signals: void disconnected(RibbonSocket* s); void messageReceived(RibbonSocket* s, QByteArray buf); @@ -24,6 +25,7 @@ private: QByteArray buf; RibbonSocketState state; quint32 bytes_wanted; + bool aborting; bool tryProcess(); bool readUntilBufHas(int desired_buffer_length); private slots: -- 2.39.2