summaryrefslogtreecommitdiffstats
path: root/src/shared
diff options
context:
space:
mode:
authorsr2013-02-04 19:50:31 +0100
committersr2013-02-04 19:50:31 +0100
commit1a5709501f94014d41987b956338bb6424b9f90c (patch)
treed3b93fe8dc406bca56aff147ef5cc4cbf9ed6be0 /src/shared
parentTest (diff)
downloadpvs2-1a5709501f94014d41987b956338bb6424b9f90c.tar.gz
pvs2-1a5709501f94014d41987b956338bb6424b9f90c.tar.xz
pvs2-1a5709501f94014d41987b956338bb6424b9f90c.zip
Initial commit
Diffstat (limited to 'src/shared')
-rw-r--r--src/shared/network.cpp50
-rw-r--r--src/shared/network.h25
-rw-r--r--src/shared/networkmessage.cpp296
-rw-r--r--src/shared/networkmessage.h69
-rw-r--r--src/shared/settings.h12
-rw-r--r--src/shared/util.cpp22
-rw-r--r--src/shared/util.h15
7 files changed, 489 insertions, 0 deletions
diff --git a/src/shared/network.cpp b/src/shared/network.cpp
new file mode 100644
index 0000000..6dd6a73
--- /dev/null
+++ b/src/shared/network.cpp
@@ -0,0 +1,50 @@
+/*
+ * network.cpp
+ *
+ * Created on: 28.01.2013
+ * Author: sr
+ */
+
+#include "network.h"
+#include <QNetworkInterface>
+#include <QHostAddress>
+#include <QList>
+
+namespace Network
+{
+
+
+/**
+ * Returns list of all addresses assigned to the interfaces of this machine.
+ * Every address is surrounded by '|', eg:
+ * |1.2.3.4|3.66.77.88|123:34::1|
+ */
+QString interfaceAddressesToString()
+{
+ QList<QHostAddress> list(QNetworkInterface::allAddresses());
+ return interfaceAddressesToString(list);
+}
+
+QString interfaceAddressesToString(const QList<QHostAddress>& list)
+{
+ QString ret;
+ ret.reserve(500);
+ for (QList<QHostAddress>::const_iterator it(list.begin()); it != list.end(); ++it)
+ {
+ if (*it == QHostAddress::LocalHost || *it == QHostAddress::LocalHostIPv6)
+ continue; // TODO: Filter other addresses/ranges?
+ ret.append("|");
+ ret.append(it->toString());
+ }
+ ret.append("|");
+ return ret;
+}
+
+bool isAddressInList(const QString& list, const QString& address)
+{
+ static const QString find("|%1|");
+ return list.contains(find.arg(address), Qt::CaseSensitive);
+}
+
+
+}
diff --git a/src/shared/network.h b/src/shared/network.h
new file mode 100644
index 0000000..4a763be
--- /dev/null
+++ b/src/shared/network.h
@@ -0,0 +1,25 @@
+/*
+ * network.h
+ *
+ * Created on: 28.01.2013
+ * Author: sr
+ */
+
+#ifndef NETWORK_H_
+#define NETWORK_H_
+
+#include <QString>
+#include <QHostAddress>
+
+namespace Network
+{
+
+
+QString interfaceAddressesToString();
+QString interfaceAddressesToString(const QList<QHostAddress>& list);
+bool isAddressInList(const QString& list, const QString& address);
+
+
+}
+
+#endif /* NETWORK_H_ */
diff --git a/src/shared/networkmessage.cpp b/src/shared/networkmessage.cpp
new file mode 100644
index 0000000..9a7ba9f
--- /dev/null
+++ b/src/shared/networkmessage.cpp
@@ -0,0 +1,296 @@
+/*
+ * NetworkMessage.cpp
+ *
+ * Created on: 18.01.2013
+ * Author: sr
+ */
+
+#include <QtCore>
+#include <QtNetwork>
+#include "networkmessage.h"
+
+#define HEADER_LEN 8
+#define MAX_MSG_LEN 60000
+
+#define BYTE_SWAP4(x) \
+ (((x & 0xFF000000) >> 24) | \
+ ((x & 0x00FF0000) >> 8) | \
+ ((x & 0x0000FF00) << 8) | \
+ ((x & 0x000000FF) << 24))
+
+#define BYTE_SWAP2(x) \
+ (((x & 0xFF00) >> 8) | \
+ ((x & 0x00FF) << 8))
+
+static quint16 _htons(quint16 x)
+{
+ if (QSysInfo::ByteOrder == QSysInfo::BigEndian)
+ return x;
+ return BYTE_SWAP2(x);
+}
+
+static quint16 _ntohs(quint16 x)
+{
+ if (QSysInfo::ByteOrder == QSysInfo::BigEndian)
+ return x;
+ return BYTE_SWAP2(x);
+}
+
+static quint32 _htonl(quint32 x)
+{
+ if (QSysInfo::ByteOrder == QSysInfo::BigEndian)
+ return x;
+ return BYTE_SWAP4(x);
+}
+
+static quint32 _ntohl(quint32 x)
+{
+ if (QSysInfo::ByteOrder == QSysInfo::BigEndian)
+ return x;
+ return BYTE_SWAP4(x);
+}
+
+/*
+ // ####################################################### \\ ° . °
+ \\ ####################################################### // \___/
+ */
+
+NetworkMessage::NetworkMessage() :
+ _buffer(NULL), _bufferSize(0), _bufferPos(0), _lastBufferSize(0), _mode(0)
+{
+ //
+}
+
+NetworkMessage::~NetworkMessage()
+{
+ if (_buffer)
+ delete[] _buffer;
+}
+
+inline void NetworkMessage::allocBuffer()
+{
+ if (_lastBufferSize < _bufferSize || _buffer == NULL)
+ {
+ if (_buffer)
+ delete[] _buffer;
+ _lastBufferSize = _bufferSize;
+ _buffer = new char[_lastBufferSize];
+ }
+}
+
+bool NetworkMessage::readMessage(QAbstractSocket* socket)
+{
+ // Check/Set the _mode variable, so read and write calls are not mixed
+ if (_mode != 1)
+ {
+ if (_mode != 0)
+ {
+ qDebug("NetworkMessage::readMessage(TCP) called when class was in mode %d!", _mode);
+ return false;
+ }
+ _mode = 1;
+ }
+ // buffer size == 0 means the header hasn't been received yet. do so and set things up
+ if (_bufferSize == 0)
+ {
+ if (socket->bytesAvailable() < HEADER_LEN)
+ return true;
+ char header[HEADER_LEN];
+ if (socket->read(header, HEADER_LEN) != HEADER_LEN)
+ {
+ qDebug("FIXME: Socket said 8 bytes available, but could not read 8...");
+ return false;
+ }
+ if (!this->parseHeader(header))
+ return false;
+ //qDebug() << "Expecting message of " << _bufferSize << " bytes";
+ allocBuffer();
+ }
+ if (_bufferSize > _bufferPos)
+ {
+ while (_bufferSize > _bufferPos && socket->bytesAvailable() > 0)
+ {
+ const qint64 ret = socket->read(_buffer + _bufferPos, _bufferSize - _bufferPos);
+ //qDebug() << "Read " << ret << " bytes";
+ if (ret < 0)
+ return false;
+ _bufferPos += ret;
+ //qDebug() << "Buffer has now " << _bufferPos << " of " << _bufferSize << " bytes";
+ }
+ if (_bufferSize == _bufferPos)
+ {
+ if (!this->parseMessage(_buffer))
+ return false;
+ }
+ }
+ return true;
+}
+
+bool NetworkMessage::readMessage(char* data, quint32 len)
+{
+ // Check/Set the _mode variable, so read and write calls are not mixed
+ if (_mode != 1)
+ {
+ if (_mode != 0)
+ {
+ qDebug("NetworkMessage::readMessage(UDP) called when class was in mode %d!", _mode);
+ return false;
+ }
+ _mode = 1;
+ }
+ if (len < HEADER_LEN)
+ {
+ qDebug("UDP message shorter than 8 bytes. ignored.");
+ return false;
+ }
+ if (!this->parseHeader(data))
+ return false;
+ if (len != _bufferSize + HEADER_LEN)
+ {
+ qDebug("UDP packet has wrong size. Is %d, expected %d", (int)_bufferSize, len - HEADER_LEN);
+ return false;
+ }
+ return this->parseMessage(data + HEADER_LEN);
+}
+
+bool NetworkMessage::parseHeader(char *header)
+{
+ if (header[0] != 'P' || header[1] != 'V' || header[2] != 'S' || header[3] != '2')
+ {
+ qDebug("Protocol magic wrong.");
+ return false;
+ }
+ _bufferPos = 0;
+ _bufferSize = _ntohl(*(quint32*)(header + 4));
+ if (_bufferSize > MAX_MSG_LEN)
+ {
+ qDebug("Disconnecting Client: MAX_MSG_LEN exceeded.");
+ return false;
+ }
+ if (_bufferSize < 4) // TODO: magic number. msg needs to be at least 4 bytes for 1 key/value pair of length 0 each.
+ {
+ qDebug("A Client sent an empty message.");
+ return false;
+ }
+ return true;
+}
+
+bool NetworkMessage::parseMessage(char *buffer)
+{
+ char *ptr = buffer;
+ while (_bufferSize - (ptr - buffer) >= 4)
+ {
+ const quint16 keyLen = _ntohs(*(quint16*)(ptr));
+ ptr += 2;
+ const quint16 valLen = _ntohs(*(quint16*)(ptr));
+ ptr += 2;
+ if (_bufferSize - (ptr - buffer) < keyLen + valLen)
+ {
+ qDebug() << "Warning: Error parsing message. key(" << keyLen << ")+value(" << valLen
+ << ") length > total remaining bytes (" << (_bufferSize - (ptr - buffer)) << ")";
+ return false;
+ }
+ _fields.insert(QString::fromUtf8(ptr, keyLen), QByteArray(ptr + keyLen, valLen));
+ //qDebug() << "Got " << QString::fromUtf8(ptr, keyLen) << " -> " << QString::fromUtf8(ptr + keyLen, valLen);
+ ptr += keyLen + valLen;
+ }
+ _mode = 3;
+ return true;
+}
+
+bool NetworkMessage::writeMessage(QAbstractSocket* socket)
+{
+ if (_mode != 2)
+ {
+ if (_mode == 1)
+ {
+ qDebug("NetworkMessage::writeMessage called when class was in mode %d!", _mode);
+ return false;
+ }
+ _mode = 1;
+ _bufferPos = 0;
+ }
+ // key/value pairs have not been serialized yet...
+ if (_bufferSize == 0)
+ {
+ this->serializeMessage();
+ }
+ const qint64 ret = socket->write(_buffer + _bufferPos, _bufferSize - _bufferPos);
+ if (ret == 0)
+ return true;
+ if (ret < 0)
+ return false;
+ _bufferPos += ret;
+ if (_bufferPos == _bufferSize)
+ {
+ _bufferPos = 0;
+ _mode = 4;
+ }
+ return true;
+}
+
+bool NetworkMessage::writeMessage(QUdpSocket* socket, const QHostAddress& address, quint16 port)
+{
+ if (_mode != 4)
+ {
+ if (_mode == 1)
+ {
+ qDebug("NetworkMessage::writeMessage called when class was in mode %d!", _mode);
+ return false;
+ }
+ _mode = 4;
+ _bufferPos = 0;
+ }
+ // key/value pairs have not been serialized yet...
+ if (_bufferSize == 0)
+ {
+ this->serializeMessage();
+ }
+ const qint64 ret = socket->writeDatagram(_buffer, _bufferSize, address, port);
+ if (ret != _bufferSize)
+ return false;
+ if (ret < 0)
+ return false;
+ _bufferPos = 0;
+ return true;
+}
+
+void NetworkMessage::serializeMessage()
+{
+ QByteArray buf;
+ //qDebug() << "Default size: " << buf.capacity();
+ buf.reserve(_lastBufferSize > 0 ? _lastBufferSize : 200);
+ for (QHash<QString, QByteArray>::const_iterator it = _fields.begin(); it != _fields.end(); ++it)
+ {
+ const QByteArray &ba = it.key().toUtf8();
+ const QByteArray &val = it.value();
+ quint16 keyLen = _htons((quint16)ba.size());
+ quint16 valLen = _htons((quint16)val.size());
+ //qDebug() << "Adding to msg(" << ba.size() << "/" << val.size() << "): " << ba << " -> " << val;
+ buf.append((char*)&keyLen, 2);
+ buf.append((char*)&valLen, 2);
+ buf.append(ba);
+ buf.append(val);
+ }
+ _bufferSize = buf.length() + HEADER_LEN;
+ allocBuffer();
+ memcpy(_buffer + HEADER_LEN, buf.data(), buf.size());
+ _buffer[0] = 'P';
+ _buffer[1] = 'V';
+ _buffer[2] = 'S';
+ _buffer[3] = '2';
+ const quint32 flipped = _htonl(_bufferSize - HEADER_LEN);
+ memcpy(_buffer + 4, &flipped, 4);
+}
+
+void NetworkMessage::buildErrorMessage(const QString& error)
+{
+ this->reset();
+ this->setField(_ID, _ERROR);
+ this->setField(_ERROR, error);
+}
+
+void NetworkMessage::buildErrorMessage(const char* error)
+{
+ this->buildErrorMessage(QString::fromUtf8(error));
+}
diff --git a/src/shared/networkmessage.h b/src/shared/networkmessage.h
new file mode 100644
index 0000000..5a8b2c2
--- /dev/null
+++ b/src/shared/networkmessage.h
@@ -0,0 +1,69 @@
+/*
+ * NetworkMessage.h
+ *
+ * Created on: 18.01.2013
+ * Author: sr
+ */
+
+#ifndef NETWORKMESSAGE_H_
+#define NETWORKMESSAGE_H_
+
+#include <QtCore>
+
+class QAbstractSocket;
+class QUdpSocket;
+
+// define qstrings for message ids. this prevents implicit instanciation of the same qstrings over and over again
+#define MSGTYPE(name) static const QString _ ## name ( #name )
+MSGTYPE(ID);
+MSGTYPE(IMG);
+MSGTYPE(LOGIN);
+MSGTYPE(THUMB);
+MSGTYPE(X);
+MSGTYPE(Y);
+MSGTYPE(VNCSERVER);
+MSGTYPE(VNCCLIENT);
+MSGTYPE(LOCK);
+MSGTYPE(HASH);
+MSGTYPE(SALT1);
+MSGTYPE(SALT2);
+MSGTYPE(IPLIST);
+MSGTYPE(PORT);
+MSGTYPE(CERT);
+MSGTYPE(CHALLENGE);
+MSGTYPE(ERROR);
+
+class NetworkMessage
+{
+private:
+ char *_buffer;
+ quint32 _bufferSize, _bufferPos, _lastBufferSize;
+ QHash<QString, QByteArray> _fields;
+ int _mode; // 0 = none, 1 = reading, 2 = writing, 3 = read complete, 4 = write complete
+
+ void allocBuffer();
+ bool parseHeader(char *header);
+ bool parseMessage(char *buffer);
+ void serializeMessage();
+
+public:
+ NetworkMessage();
+ virtual ~NetworkMessage();
+ bool readMessage(QAbstractSocket* socket);
+ bool readMessage(char* data, quint32 len);
+ bool writeMessage(QAbstractSocket* socket);
+ bool writeMessage(QUdpSocket* socket, const QHostAddress& address, quint16 port);
+ void reset() { _fields.clear(); _bufferSize = 0; _mode = 0; }
+ const bool readComplete() const { return _mode == 3; }
+ const bool writeComplete() const { return _mode == 4; }
+ const bool hasField(const QString& key) const { return _fields.contains(key); }
+ const QString getFieldString(const QString& key) const { return QString::fromUtf8(_fields.value(key)); }
+ const QByteArray getFieldBytes(const QString& key) const { return _fields.value(key); }
+ void setField(const QString& key, const QByteArray& value) { if (_mode == 1 || _mode == 2) qFatal("setField called in bad state."); _fields.insert(key, value); _mode = 0; }
+ void setField(const QString& key, const QString& value) { setField(key, value.toUtf8()); }
+ // Convenience
+ void buildErrorMessage(const QString& error);
+ void buildErrorMessage(const char* error);
+};
+
+#endif /* NETWORKMESSAGE_H_ */
diff --git a/src/shared/settings.h b/src/shared/settings.h
new file mode 100644
index 0000000..c1c45c1
--- /dev/null
+++ b/src/shared/settings.h
@@ -0,0 +1,12 @@
+#ifndef _SETTINGS_H_
+#define _SETTINGS_H_
+
+#define CLIENT_PORT 5194
+static const QString CLIENT_PORT_STR(QString::number(CLIENT_PORT));
+static const QByteArray CLIENT_PORT_ARRAY(QString::number(CLIENT_PORT).toUtf8());
+
+#define SERVICE_DISCOVERY_PORT 3492
+
+#define PING_TIMEOUT_MS 30000
+
+#endif
diff --git a/src/shared/util.cpp b/src/shared/util.cpp
new file mode 100644
index 0000000..d5c101e
--- /dev/null
+++ b/src/shared/util.cpp
@@ -0,0 +1,22 @@
+/*
+ * util.cpp
+ *
+ * Created on: 30.01.2013
+ * Author: sr
+ */
+
+#include "util.h"
+#include <QCryptographicHash>
+
+static QCryptographicHash sha1(QCryptographicHash::Sha1);
+
+QByteArray genSha1(const QByteArray* a, const QByteArray* b, const QByteArray* c, const QByteArray* d, const QByteArray* e)
+{
+ sha1.reset();
+ sha1.addData(*a);
+ if (b) sha1.addData(*b);
+ if (c) sha1.addData(*c);
+ if (d) sha1.addData(*d);
+ if (e) sha1.addData(*e);
+ return sha1.result();
+}
diff --git a/src/shared/util.h b/src/shared/util.h
new file mode 100644
index 0000000..c2e5145
--- /dev/null
+++ b/src/shared/util.h
@@ -0,0 +1,15 @@
+/*
+ * util.h
+ *
+ * Created on: 30.01.2013
+ * Author: sr
+ */
+
+#ifndef UTIL_H_
+#define UTIL_H_
+
+#include <QByteArray>
+
+QByteArray genSha1(const QByteArray* a, const QByteArray* b = NULL, const QByteArray* c = NULL, const QByteArray* d = NULL, const QByteArray* e = NULL);
+
+#endif /* UTIL_H_ */