Pool Video Switch v2
Software video switch for distributed remote display in a lecture environment
networkmessage.cpp
Go to the documentation of this file.
1 /*
2  * NetworkMessage.cpp
3  *
4  * Created on: 18.01.2013
5  * Author: sr
6  */
7 
8 #include <QtCore>
9 #include <QtNetwork>
10 #include "networkmessage.h"
11 
12 #define HEADER_LEN 8
13 #define MAX_MSG_LEN 60000
14 
15 #define BYTE_SWAP4(x) \
16  ((((x) & 0xFF000000u) >> 24) | \
17  (((x) & 0x00FF0000u) >> 8) | \
18  (((x) & 0x0000FF00u) << 8) | \
19  (((x) & 0x000000FFu) << 24))
20 
21 #define BYTE_SWAP2(x) \
22  ((((x) & 0xFF00u) >> 8) | \
23  (((x) & 0x00FFu) << 8))
24 
25 static quint16 _htons(const quint16 x)
26 {
27  if (QSysInfo::ByteOrder == QSysInfo::BigEndian)
28  return x;
29  return quint16(BYTE_SWAP2(x));
30 }
31 
32 static quint32 _htonl(const quint32 x)
33 {
34  if (QSysInfo::ByteOrder == QSysInfo::BigEndian)
35  return x;
36  return quint32(BYTE_SWAP4(x));
37 }
38 
39 static quint16 _ntohs(const char *in)
40 {
41  return quint16(quint8(in[0]) << 8
42  | quint8(in[1]));
43 }
44 
45 static quint32 _ntohl(const char *in)
46 {
47  return quint32(quint8(in[0])) << 24
48  | quint32(quint8(in[1])) << 16
49  | quint32(quint8(in[2])) << 8
50  | quint32(quint8(in[3]));
51 }
52 
53 /*
54  // ####################################################### \\ ° . °
55  \\ ####################################################### // \___/
56  */
57 
59  _buffer(nullptr), _bufferSize(0), _bufferPos(0), _lastBufferSize(0), _mode(0)
60 {
61  //
62 }
63 
65 {
66  if (_buffer)
67  delete[] _buffer;
68 }
69 
71 {
72  if (_lastBufferSize < _bufferSize || _buffer == nullptr) {
73  if (_buffer)
74  delete[] _buffer;
76  _buffer = new char[_lastBufferSize];
77  }
78 }
79 
80 int NetworkMessage::readMessage(QAbstractSocket* socket)
81 {
82  // Check/Set the _mode variable, so read and write calls are not mixed
83  if (_mode != 1) {
84  if (_mode != 0) {
85  qDebug("NetworkMessage::readMessage(TCP) called when class was in mode %d!", _mode);
86  return NM_READ_FAILED;
87  }
88  _mode = 1;
89  }
90  // buffer size == 0 means the header hasn't been received yet. do so and set things up
91  if (_bufferSize == 0) {
92  if (socket->bytesAvailable() < HEADER_LEN)
93  return NM_READ_INCOMPLETE;
94  char header[HEADER_LEN];
95  if (socket->read(header, HEADER_LEN) != HEADER_LEN) {
96  qDebug("FIXME: Socket said 8 bytes available, but could not read 8...");
97  return NM_READ_FAILED;
98  }
99  if (!this->parseHeader(header))
100  return NM_READ_FAILED;
101  //qDebug() << "Expecting message of " << _bufferSize << " bytes";
102  allocBuffer();
103  }
104  if (_bufferSize > _bufferPos) {
105  while (_bufferSize > _bufferPos && socket->bytesAvailable() > 0) {
106  const qint64 ret = socket->read(_buffer + _bufferPos, _bufferSize - _bufferPos);
107  //qDebug() << "Read " << ret << " bytes";
108  if (ret < 0 || ret > (_bufferSize - _bufferPos)) {
109  qDebug("Socket read failed (TCP), return code %d", int(ret));
110  return NM_READ_FAILED;
111  }
112  _bufferPos += quint32(ret);
113  //qDebug() << "Buffer has now " << _bufferPos << " of " << _bufferSize << " bytes";
114  }
115  if (_bufferSize == _bufferPos) {
116  if (!this->parseMessage(_buffer))
117  return NM_READ_FAILED;
118  }
119  }
120  return NM_READ_OK;
121 }
122 
123 int NetworkMessage::readMessage(char* data, quint32 len)
124 {
125  // Check/Set the _mode variable, so read and write calls are not mixed
126  if (_mode != 1) {
127  if (_mode != 0) {
128  qDebug("NetworkMessage::readMessage(UDP) called when class was in mode %d!", _mode);
129  return NM_READ_FAILED;
130  }
131  _mode = 1;
132  }
133  if (len < HEADER_LEN) {
134  qDebug("UDP message shorter than 8 bytes. ignored.");
135  return NM_READ_FAILED;
136  }
137  if (!this->parseHeader(data))
138  return NM_READ_FAILED;
139  if (len != _bufferSize + HEADER_LEN) {
140  qDebug("UDP packet has wrong size. Is %d, expected %d", int(_bufferSize), len - HEADER_LEN);
141  return NM_READ_FAILED;
142  }
143  return this->parseMessage(data + HEADER_LEN) ? NM_READ_OK : NM_READ_FAILED;
144 }
145 
146 bool NetworkMessage::parseHeader(char *header)
147 {
148  if (header[0] != 'P' || header[1] != 'V' || header[2] != 'S' || header[3] != '2') {
149  qDebug("Protocol magic wrong.");
150  return false;
151  }
152  _bufferPos = 0;
153  _bufferSize = _ntohl(header + 4);
154  if (_bufferSize > MAX_MSG_LEN) {
155  qDebug("Disconnecting Client: MAX_MSG_LEN exceeded.");
156  return false;
157  }
158  if (_bufferSize < 4) { // TODO: magic number. msg needs to be at least 4 bytes for 1 key/value pair of length 0 each.
159  qDebug("A Client sent an empty message.");
160  return false;
161  }
162  return true;
163 }
164 
166 {
167  char *ptr = buffer;
168  while (_bufferSize - (ptr - buffer) >= 4) {
169  const quint16 keyLen = _ntohs(ptr);
170  ptr += 2;
171  const quint16 valLen = _ntohs(ptr);
172  ptr += 2;
173  if (_bufferSize - (ptr - buffer) < keyLen + valLen) {
174  qDebug() << "Warning: Error parsing message. key(" << keyLen << ")+value(" << valLen
175  << ") length > total remaining bytes (" << (_bufferSize - (ptr - buffer)) << ")";
176  return false;
177  }
178  _fields.insert(QByteArray(ptr, keyLen), QByteArray(ptr + keyLen, valLen));
179  //qDebug() << "Got " << QString::fromUtf8(ptr, keyLen) << " -> " << QString::fromUtf8(ptr + keyLen, valLen);
180  ptr += keyLen + valLen;
181  }
182  _mode = 3;
183  return true;
184 }
185 
186 bool NetworkMessage::writeMessage(QAbstractSocket * const socket)
187 {
188  if (_mode != 2) {
189  if (_mode == 1) {
190  qDebug("NetworkMessage::writeMessage called when class was in mode %d!", _mode);
191  return false;
192  }
193  _mode = 1;
194  _bufferPos = 0;
195  }
196  // key/value pairs have not been serialized yet...
197  if (_bufferSize == 0) {
198  this->serializeMessage();
199  }
200  const qint64 ret = socket->write(_buffer + _bufferPos, _bufferSize - _bufferPos);
201  if (ret == 0)
202  return true;
203  if (ret < 0 || ret > (_bufferSize - _bufferPos))
204  return false;
205  _bufferPos += quint32(ret);
206  if (_bufferPos == _bufferSize) {
207  _bufferPos = 0;
208  _mode = 4;
209  }
210  return true;
211 }
212 
213 bool NetworkMessage::writeMessage(QUdpSocket* socket, const QHostAddress& address, quint16 port)
214 {
215  if (_mode != 4) {
216  if (_mode == 1) {
217  qDebug("NetworkMessage::writeMessage called when class was in mode %d!", _mode);
218  return false;
219  }
220  _mode = 4;
221  _bufferPos = 0;
222  }
223  // key/value pairs have not been serialized yet...
224  if (_bufferSize == 0) {
225  this->serializeMessage();
226  }
227  const qint64 ret = socket->writeDatagram(_buffer, _bufferSize, address, port);
228  if (ret != _bufferSize)
229  return false;
230  if (ret < 0)
231  return false;
232  _bufferPos = 0;
233  return true;
234 }
235 
237 {
238  QByteArray buf;
239  //qDebug() << "Default size: " << buf.capacity();
240  buf.reserve(_lastBufferSize > 0 ? int(_lastBufferSize) : 200);
241  for (QHash<QByteArray, QByteArray>::const_iterator it = _fields.begin(); it != _fields.end(); ++it) {
242  const QByteArray &ba = it.key();
243  const QByteArray &val = it.value();
244  quint16 keyLen = _htons(quint16(ba.size()));
245  quint16 valLen = _htons(quint16(val.size()));
246  //qDebug() << "Adding to msg(" << ba.size() << "/" << val.size() << "): " << ba << " -> " << val;
247  buf.append(reinterpret_cast<const char*>(&keyLen), 2);
248  buf.append(reinterpret_cast<const char*>(&valLen), 2);
249  buf.append(ba);
250  buf.append(val);
251  }
252  _bufferSize = quint32(buf.length() + HEADER_LEN);
253  allocBuffer();
254  memcpy(_buffer + HEADER_LEN, buf.data(), size_t(buf.size()));
255  _buffer[0] = 'P';
256  _buffer[1] = 'V';
257  _buffer[2] = 'S';
258  _buffer[3] = '2';
259  const quint32 flipped = _htonl(_bufferSize - HEADER_LEN);
260  memcpy(_buffer + 4, &flipped, 4);
261 }
262 
263 void NetworkMessage::buildErrorMessage(const QString& error)
264 {
265  this->reset();
266  this->setField(_ID, _ERROR);
267  this->setField(_ERROR, error);
268 }
#define NM_READ_INCOMPLETE
bool writeMessage(QAbstractSocket *socket)
#define NM_READ_OK
bool parseHeader(char *header)
virtual ~NetworkMessage()
#define BYTE_SWAP4(x)
#define HEADER_LEN
quint32 _bufferPos
int readMessage(QAbstractSocket *socket)
quint32 _lastBufferSize
#define BYTE_SWAP2(x)
static quint32 _htonl(const quint32 x)
QHash< QByteArray, QByteArray > _fields
#define MAX_MSG_LEN
quint32 _bufferSize
#define NM_READ_FAILED
static quint16 _htons(const quint16 x)
static quint16 _ntohs(const char *in)
void setField(const QByteArray &key, const QByteArray &value)
static quint32 _ntohl(const char *in)
bool parseMessage(char *buffer)
void buildErrorMessage(const QString &error)