libvisiontransfer  6.0.0
datablockprotocol.cpp
1 /*******************************************************************************
2  * Copyright (c) 2018 Nerian Vision GmbH
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *******************************************************************************/
14 
15 #include <algorithm>
16 #include <iostream>
17 #include <cstring>
18 
19 #include "visiontransfer/datablockprotocol.h"
20 #include "visiontransfer/exceptions.h"
21 
22 // Network headers
23 #ifdef _WIN32
24 #include <winsock2.h>
25 #else
26 #include <arpa/inet.h>
27 #endif
28 
29 #define LOG_ERROR(expr)
30 //#define LOG_ERROR(expr) std::cout << "DataBlockProtocol: " << expr << std::endl
31 
32 using namespace std;
33 
34 DataBlockProtocol::DataBlockProtocol(bool server, ProtocolType protType, int maxUdpPacketSize)
35  : isServer(server), protType(protType),
36  transferDone(true), rawData(nullptr), rawValidBytes(0),
37  transferOffset(0), transferSize(0), overwrittenTransferData(0),
38  overwrittenTransferIndex(-1), transferHeaderData(nullptr),
39  transferHeaderSize(0), waitingForMissingSegments(false),
40  totalReceiveSize(0), connectionConfirmed(false),
41  confirmationMessagePending(false), eofMessagePending(false),
42  clientConnectionPending(false), resendMessagePending(false),
43  lastRemoteHostActivity(), lastSentHeartbeat(),
44  lastReceivedHeartbeat(std::chrono::steady_clock::now()),
45  receiveOffset(0), finishedReception(false), droppedReceptions(0),
46  unprocessedMsgLength(0), headerReceived(false) {
47  // Determine the maximum allowed payload size
48  if(protType == PROTOCOL_TCP) {
49  maxPayloadSize = MAX_TCP_BYTES_TRANSFER;
50  minPayloadSize = 0;
51  } else {
52  maxPayloadSize = maxUdpPacketSize - sizeof(int);
53  minPayloadSize = maxPayloadSize;
54  }
55  resizeReceiveBuffer();
56 }
57 
59  transferDone = true;
60  overwrittenTransferIndex = -1;
61  transferOffset = 0;
62  transferSize = 0;
63  missingTransferSegments.clear();
64 }
65 
66 void DataBlockProtocol::setTransferHeader(unsigned char* data, int headerSize, int transferSize) {
67  if(!transferDone && transferOffset > 0) {
68  throw ProtocolException("Header data set while transfer is active!");
69  } else if(headerSize + 9 > static_cast<int>(sizeof(controlMessageBuffer))) {
70  throw ProtocolException("Transfer header is too large!");
71  }
72 
73  transferDone = false;
74  this->transferSize = transferSize;
75 
76  transferHeaderData = &data[-6];
77 
78  unsigned short netHeaderSize = htons(static_cast<unsigned short>(headerSize));
79  memcpy(transferHeaderData, &netHeaderSize, sizeof(netHeaderSize));
80 
81  unsigned int netTransferSize = htonl(static_cast<unsigned int>(transferSize));
82  memcpy(&transferHeaderData[2], &netTransferSize, sizeof(netTransferSize));
83  headerSize += 6;
84 
85  if(protType == PROTOCOL_UDP) {
86  // In UDP mode we still need to make this a control message
87  transferHeaderData[headerSize++] = HEADER_MESSAGE;
88  transferHeaderData[headerSize++] = 0xFF;
89  transferHeaderData[headerSize++] = 0xFF;
90  transferHeaderData[headerSize++] = 0xFF;
91  transferHeaderData[headerSize++] = 0xFF;
92  }
93 
94  transferHeaderSize = headerSize;
95 }
96 
97 void DataBlockProtocol::setTransferData(unsigned char* data, int validBytes) {
98  if(transferHeaderSize == 0 || transferHeaderData == nullptr) {
99  throw ProtocolException("The transfer header has not yet been set!");
100  }
101 
102  transferDone = false;
103  rawData = data;
104  transferOffset = 0;
105  overwrittenTransferIndex = -1;
106  rawValidBytes = min(transferSize, validBytes);
107 }
108 
110  if(validBytes >= transferSize) {
111  rawValidBytes = transferSize;
112  } else if(validBytes < static_cast<int>(sizeof(int))) {
113  rawValidBytes = 0;
114  } else {
115  rawValidBytes = validBytes;
116  }
117 }
118 
119 const unsigned char* DataBlockProtocol::getTransferMessage(int& length) {
120  if(transferDone || rawValidBytes == 0) {
121  // No more data to be transferred
122  length = 0;
123  return nullptr;
124  }
125 
126  // For TCP we always send the header first
127  if(protType == PROTOCOL_TCP && transferOffset == 0 && transferHeaderData != nullptr) {
128  length = transferHeaderSize;
129  const unsigned char* ret = transferHeaderData;
130  transferHeaderData = nullptr;
131  return ret;
132  }
133 
134  // The transfer buffer might have been altered by the previous transfer
135  // and first needs to be restored
136  restoreTransferBuffer();
137 
138  // Determine which data segment to transfer next
139  int offset;
140  getNextTransferSegment(offset, length);
141  if(length == 0) {
142  return nullptr;
143  }
144 
145  if(protType == PROTOCOL_UDP) {
146  // For udp, we always append a segment offset
147  overwrittenTransferIndex = offset + length;
148  int* offsetPtr = reinterpret_cast<int*>(&rawData[offset + length]);
149  overwrittenTransferData = *offsetPtr;
150  *offsetPtr = static_cast<int>(htonl(offset));
151  length += sizeof(int);
152  }
153 
154  return &rawData[offset];
155 }
156 
157 void DataBlockProtocol::getNextTransferSegment(int& offset, int& length) {
158  if(missingTransferSegments.size() == 0) {
159  // This is a regular data segment
160  length = min(maxPayloadSize, rawValidBytes - transferOffset);
161  if(length == 0 || (length < minPayloadSize && rawValidBytes != transferSize)) {
162  length = 0;
163  return;
164  }
165 
166  offset = transferOffset;
167  transferOffset += length; // for next transfer
168 
169  if(transferOffset >= transferSize && protType == PROTOCOL_UDP) {
170  eofMessagePending = true;
171  }
172  } else {
173  // This is a segment that is re-transmitted due to packet loss
174  length = min(maxPayloadSize, missingTransferSegments.front().second);
175  offset = missingTransferSegments.front().first;
176  LOG_ERROR("Re-transmitting: " << offset << " - " << (offset + length));
177 
178  int remaining = missingTransferSegments[0].second - length;
179  if(remaining == 0) {
180  // The segment is competed
181  missingTransferSegments.pop_front();
182  } else {
183  // The segment is only partially complete
184  missingTransferSegments.front().first += length;
185  missingTransferSegments.front().second = remaining;
186  }
187  }
188 }
189 
190 void DataBlockProtocol::restoreTransferBuffer() {
191  if(overwrittenTransferIndex > 0) {
192  *reinterpret_cast<int*>(&rawData[overwrittenTransferIndex]) = overwrittenTransferData;
193  }
194  overwrittenTransferIndex = -1;
195 }
196 
198  return transferOffset >= transferSize && !eofMessagePending;
199 }
200 
202  if(protType == PROTOCOL_TCP) {
203  return MAX_TCP_BYTES_TRANSFER;
204  } else {
205  return MAX_UDP_RECEPTION;
206  }
207 }
208 
209 unsigned char* DataBlockProtocol::getNextReceiveBuffer(int maxLength) {
210  if(static_cast<int>(receiveBuffer.size() - receiveOffset) < maxLength) {
211  throw ProtocolException("No more receive buffers available!");
212  }
213 
214  return &receiveBuffer[receiveOffset];
215 }
216 
218  transferComplete = false;
219  if(length <= 0) {
220  return; // Nothing received
221  }
222 
223  if(finishedReception) {
224  // First reset for next frame
225  resetReception(false);
226  }
227 
228  if(protType == PROTOCOL_UDP) {
229  processReceivedUdpMessage(length, transferComplete);
230  } else {
231  processReceivedTcpMessage(length, transferComplete);
232  }
233 
234  transferComplete = finishedReception;
235 }
236 
237 void DataBlockProtocol::processReceivedUdpMessage(int length, bool& transferComplete) {
238  if(length < static_cast<int>(sizeof(int)) ||
239  receiveOffset + length > static_cast<int>(receiveBuffer.size())) {
240  throw ProtocolException("Received message size is invalid!");
241  }
242 
243  // Extract the sequence number
244  int segmentOffset = ntohl(*reinterpret_cast<int*>(
245  &receiveBuffer[receiveOffset + length - sizeof(int)]));
246 
247  if(segmentOffset == static_cast<int>(0xFFFFFFFF)) {
248  // This is a control packet
249  processControlMessage(length);
250  } else if(segmentOffset < 0) {
251  throw ProtocolException("Received illegal network packet");
252  } else {
253  // Correct the length by subtracting the size of the segment offset
254  int payloadLength = length - sizeof(int);
255 
256  if(segmentOffset != receiveOffset) {
257  // The segment offset doesn't match what we expected. Probably
258  // a packet was dropped
259  if(!waitingForMissingSegments && receiveOffset > 0 && segmentOffset > receiveOffset) {
260  // We can just ask for a retransmission of this packet
261  LOG_ERROR("Missing segment: " << receiveOffset << " - " << segmentOffset
262  << " (" << missingReceiveSegments.size() << ")");
263 
264  MissingReceiveSegment missingSeg;
265  missingSeg.offset = receiveOffset;
266  missingSeg.length = segmentOffset - receiveOffset;
267  missingSeg.isEof = false;
268  memcpy(missingSeg.subsequentData, &receiveBuffer[receiveOffset],
269  sizeof(missingSeg.subsequentData));
270  missingReceiveSegments.push_back(missingSeg);
271 
272  // Move the received data to the right place in the buffer
273  memcpy(&receiveBuffer[segmentOffset], &receiveBuffer[receiveOffset], payloadLength);
274  receiveOffset = segmentOffset;
275  } else {
276  // In this case we cannot recover from the packet loss or
277  // we just didn't get the EOF packet and everything is
278  // actually fine
279  resetReception(receiveOffset > 0);
280  if(segmentOffset > 0 ) {
281  if(receiveOffset > 0) {
282  LOG_ERROR("Resend failed!");
283  }
284  return;
285  } else {
286  LOG_ERROR("Missed EOF message!");
287  }
288  }
289  }
290 
291  if(segmentOffset == 0) {
292  // This is the beginning of a new frame
293  lastRemoteHostActivity = std::chrono::steady_clock::now();
294  }
295 
296  // Update the receive buffer offset
297  receiveOffset = getNextUdpReceiveOffset(segmentOffset, payloadLength);
298  }
299 }
300 
301 int DataBlockProtocol::getNextUdpReceiveOffset(int lastSegmentOffset, int lastSegmentSize) {
302  if(!waitingForMissingSegments) {
303  // Just need to increment the offset during normal transmission
304  return lastSegmentOffset + lastSegmentSize;
305  } else {
306  // Things get more complicated when re-transmitting dropped packets
307  MissingReceiveSegment& firstSeg = missingReceiveSegments.front();
308  if(lastSegmentOffset != firstSeg.offset) {
309  LOG_ERROR("Received invalid resend: " << lastSegmentOffset);
310  resetReception(true);
311  return 0;
312  } else {
313  firstSeg.offset += lastSegmentSize;
314  firstSeg.length -= lastSegmentSize;
315  if(firstSeg.length == 0) {
316  if(!firstSeg.isEof) {
317  memcpy(&receiveBuffer[firstSeg.offset + firstSeg.length],
318  firstSeg.subsequentData, sizeof(firstSeg.subsequentData));
319  }
320  missingReceiveSegments.pop_front();
321  }
322 
323  if(missingReceiveSegments.size() == 0) {
324  waitingForMissingSegments = false;
325  finishedReception = true;
326  return min(totalReceiveSize, static_cast<int>(receiveBuffer.size()));
327  } else {
328  return missingReceiveSegments.front().offset;
329  }
330  }
331  }
332 }
333 
334 void DataBlockProtocol::processReceivedTcpMessage(int length, bool& transferComplete) {
335  // For TCP we might have some outstanding bytes from the
336  // previous transfer. Lets copy that part from a separate buffer.
337  if(unprocessedMsgLength != 0) {
338  if(length + unprocessedMsgLength > MAX_OUTSTANDING_BYTES) {
339  throw ProtocolException("Received too much data!");
340  }
341 
342  ::memmove(&receiveBuffer[unprocessedMsgLength], &receiveBuffer[0], length);
343  ::memcpy(&receiveBuffer[0], &unprocessedMsgPart[0], unprocessedMsgLength);
344  length += unprocessedMsgLength;
345  unprocessedMsgLength = 0;
346  }
347 
348  // In TCP mode the header must be the first data item to be transmitted
349  if(!headerReceived) {
350  int totalHeaderSize = parseReceivedHeader(length, receiveOffset);
351  if(totalHeaderSize == 0) {
352  // Not yet enough data. Keep on buffering.
353  ::memcpy(unprocessedMsgPart, &receiveBuffer[0], length);
354  unprocessedMsgLength = length;
355  return;
356  } else {
357  // Header successfully parsed
358  // Move the remaining data to the beginning of the buffer
359  length -= totalHeaderSize;
360  if(length == 0) {
361  return; // No more data remaining
362  }
363  ::memmove(&receiveBuffer[0], &receiveBuffer[totalHeaderSize], length);
364  }
365  }
366 
367  // The message might also contain extra bytes for the next
368  // transfer. Lets copy that part into a separate buffer.
369  if(receiveOffset + length > totalReceiveSize) {
370  int newLength = static_cast<int>(totalReceiveSize - receiveOffset);
371 
372  if(unprocessedMsgLength != 0 || length - newLength > MAX_OUTSTANDING_BYTES) {
373  throw ProtocolException("Received too much data!");
374  }
375 
376  unprocessedMsgLength = length - newLength;
377  ::memcpy(unprocessedMsgPart, &receiveBuffer[receiveOffset + newLength], unprocessedMsgLength);
378 
379  length = newLength;
380  }
381 
382  // Advancing the receive offset in TCP mode just requires an increment
383  receiveOffset += length;
384 
385  if(receiveOffset == totalReceiveSize) {
386  // We are done once we received the expected amount of data
387  finishedReception = true;
388  }
389 }
390 
391 int DataBlockProtocol::parseReceivedHeader(int length, int offset) {
392  constexpr int headerExtraBytes = 6;
393 
394  if(length < headerExtraBytes) {
395  return 0;
396  }
397 
398  unsigned short headerSize = ntohs(*reinterpret_cast<unsigned short*>(&receiveBuffer[offset]));
399  totalReceiveSize = static_cast<int>(ntohl(*reinterpret_cast<unsigned int*>(&receiveBuffer[offset + 2])));
400 
401  if(headerSize + headerExtraBytes > static_cast<int>(receiveBuffer.size())
402  || totalReceiveSize < 0 || headerSize + headerExtraBytes > length ) {
403  throw ProtocolException("Received invalid header!");
404  }
405 
406  headerReceived = true;
407  receivedHeader.assign(receiveBuffer.begin() + offset + headerExtraBytes,
408  receiveBuffer.begin() + offset + headerSize + headerExtraBytes);
409  resizeReceiveBuffer();
410 
411  return headerSize + headerExtraBytes;
412 }
413 
415  headerReceived = false;
416  receiveOffset = 0;
417  missingReceiveSegments.clear();
418  receivedHeader.clear();
419  waitingForMissingSegments = false;
420  totalReceiveSize = 0;
421  finishedReception = false;
422  if(dropped) {
423  droppedReceptions++;
424  }
425 }
426 
427 unsigned char* DataBlockProtocol::getReceivedData(int& length) {
428  length = receiveOffset;
429  if(missingReceiveSegments.size() > 0) {
430  length = min(length, missingReceiveSegments[0].offset);
431  }
432  return &receiveBuffer[0];
433 }
434 
435 unsigned char* DataBlockProtocol::getReceivedHeader(int& length) {
436  if(receivedHeader.size() > 0) {
437  length = static_cast<int>(receivedHeader.size());
438  return &receivedHeader[0];
439  } else {
440  return nullptr;
441  }
442 }
443 
444 bool DataBlockProtocol::processControlMessage(int length) {
445  if(length < static_cast<int>(sizeof(int) + 1)) {
446  return false;
447  }
448 
449  int payloadLength = length - sizeof(int) - 1;
450 
451  switch(receiveBuffer[receiveOffset + payloadLength]) {
452  case CONFIRM_MESSAGE:
453  // Our connection request has been accepted
454  connectionConfirmed = true;
455  break;
456  case CONNECTION_MESSAGE:
457  // We establish a new connection
458  connectionConfirmed = true;
459  confirmationMessagePending = true;
460  clientConnectionPending = true;
461 
462  // A connection request is just as good as a heartbeat
463  lastReceivedHeartbeat = std::chrono::steady_clock::now();
464  break;
465  case HEADER_MESSAGE: {
466  int offset = receiveOffset;
467  if(receiveOffset != 0) {
468  if(receiveOffset == totalReceiveSize) {
469  LOG_ERROR("No EOF message received!");
470  } else {
471  LOG_ERROR("Received header too late/early!");
472  }
473  resetReception(true);
474  }
475  if(parseReceivedHeader(payloadLength, offset) == 0) {
476  throw ProtocolException("Received header is too short!");
477  }
478  }
479  break;
480  case EOF_MESSAGE:
481  // This is the end of the frame
482  if(receiveOffset != 0) {
483  parseEofMessage(length);
484  }
485  break;
486  case RESEND_MESSAGE: {
487  // The client requested retransmission of missing packets
488  parseResendMessage(payloadLength);
489  break;
490  }
491  case HEARTBEAT_MESSAGE:
492  // A cyclic heartbeat message
493  lastReceivedHeartbeat = std::chrono::steady_clock::now();
494  break;
495  default:
496  throw ProtocolException("Received invalid control message!");
497  break;
498  }
499 
500  return true;
501 }
502 
504  if(protType == PROTOCOL_TCP) {
505  // Connection is handled by TCP and not by us
506  return true;
507  } else if(connectionConfirmed) {
508  return !isServer || std::chrono::duration_cast<std::chrono::milliseconds>(
509  std::chrono::steady_clock::now() - lastReceivedHeartbeat).count()
510  < 2*HEARTBEAT_INTERVAL_MS;
511  } else return false;
512 }
513 
514 const unsigned char* DataBlockProtocol::getNextControlMessage(int& length) {
515  length = 0;
516 
517  if(protType == PROTOCOL_TCP) {
518  // There are no control messages for TCP
519  return nullptr;
520  }
521 
522  if(confirmationMessagePending) {
523  // Send confirmation message
524  confirmationMessagePending = false;
525  controlMessageBuffer[0] = CONFIRM_MESSAGE;
526  length = 1;
527  } else if(!isServer && std::chrono::duration_cast<std::chrono::milliseconds>(
528  std::chrono::steady_clock::now() - lastRemoteHostActivity).count() > RECONNECT_TIMEOUT_MS) {
529  // Send a new connection request
530  controlMessageBuffer[0] = CONNECTION_MESSAGE;
531  length = 1;
532 
533  // Also update time stamps
534  lastRemoteHostActivity = lastSentHeartbeat = std::chrono::steady_clock::now();
535  } else if(transferHeaderData != nullptr && isConnected()) {
536  // We need to send a new protocol header
537  length = transferHeaderSize;
538  const unsigned char* ret = transferHeaderData;
539  transferHeaderData = nullptr;
540  return ret;
541  } else if(eofMessagePending) {
542  // Send end of frame message
543  eofMessagePending = false;
544  unsigned int networkOffset = htonl(static_cast<unsigned int>(transferOffset));
545  memcpy(&controlMessageBuffer[0], &networkOffset, sizeof(int));
546  controlMessageBuffer[sizeof(int)] = EOF_MESSAGE;
547  length = 5;
548  } else if(resendMessagePending) {
549  // Send a re-send request for missing messages
550  resendMessagePending = false;
551  if(!generateResendRequest(length)) {
552  length = 0;
553  return nullptr;
554  }
555  } else if(!isServer && std::chrono::duration_cast<std::chrono::milliseconds>(
556  std::chrono::steady_clock::now() - lastSentHeartbeat).count() > HEARTBEAT_INTERVAL_MS) {
557  // Send a heartbeat message
558  controlMessageBuffer[0] = HEARTBEAT_MESSAGE;
559  length = 1;
560  lastSentHeartbeat = std::chrono::steady_clock::now();
561  } else {
562  return nullptr;
563  }
564 
565  // Mark this message as a control message
566  controlMessageBuffer[length++] = 0xff;
567  controlMessageBuffer[length++] = 0xff;
568  controlMessageBuffer[length++] = 0xff;
569  controlMessageBuffer[length++] = 0xff;
570  return controlMessageBuffer;
571 }
572 
574  if(clientConnectionPending) {
575  clientConnectionPending = false;
576  return true;
577  } else {
578  return false;
579  }
580 }
581 
582 bool DataBlockProtocol::generateResendRequest(int& length) {
583  length = static_cast<int>(missingReceiveSegments.size() * (sizeof(int) + sizeof(unsigned short)));
584  if(length + sizeof(int) + 1> sizeof(controlMessageBuffer)) {
585  return false;
586  }
587 
588  length = 0;
589  for(MissingReceiveSegment segment: missingReceiveSegments) {
590  unsigned int segOffset = htonl(static_cast<unsigned int>(segment.offset));
591  unsigned int segLen = htonl(static_cast<unsigned int>(segment.length));
592 
593  memcpy(&controlMessageBuffer[length], &segOffset, sizeof(segOffset));
594  length += sizeof(unsigned int);
595  memcpy(&controlMessageBuffer[length], &segLen, sizeof(segLen));
596  length += sizeof(unsigned int);
597  }
598 
599  controlMessageBuffer[length++] = RESEND_MESSAGE;
600 
601  return true;
602 }
603 
604 void DataBlockProtocol::parseResendMessage(int length) {
605  missingTransferSegments.clear();
606 
607  int num = length / (sizeof(unsigned int) + sizeof(unsigned short));
608  int bufferOffset = receiveOffset;
609 
610  for(int i=0; i<num; i++) {
611  unsigned int segOffsetNet = *reinterpret_cast<unsigned int*>(&receiveBuffer[bufferOffset]);
612  bufferOffset += sizeof(unsigned int);
613  unsigned int segLenNet = *reinterpret_cast<unsigned int*>(&receiveBuffer[bufferOffset]);
614  bufferOffset += sizeof(unsigned int);
615 
616  int segOffset = static_cast<int>(ntohl(segOffsetNet));
617  int segLen = static_cast<int>(ntohl(segLenNet));
618 
619  if(segOffset >= 0 && segLen > 0 && segOffset + segLen < rawValidBytes) {
620  missingTransferSegments.push_back(std::pair<int, int>(
621  segOffset, segLen));
622  }
623 
624  LOG_ERROR("Requested resend: " << segOffset << " - " << (segOffset + segLen));
625  }
626 }
627 
628 void DataBlockProtocol::parseEofMessage(int length) {
629  if(length >= 4) {
630  totalReceiveSize = static_cast<int>(ntohl(*reinterpret_cast<unsigned int*>(
631  &receiveBuffer[receiveOffset])));
632  if(totalReceiveSize < receiveOffset) {
633  throw ProtocolException("Received invalid resend request");
634  }
635  if(totalReceiveSize != receiveOffset && receiveOffset != 0) {
636  // Add final missing segment
637  MissingReceiveSegment missingSeg;
638  missingSeg.offset = receiveOffset;
639  missingSeg.length = totalReceiveSize - receiveOffset;
640  missingSeg.isEof = true;
641  missingReceiveSegments.push_back(missingSeg);
642  }
643  if(missingReceiveSegments.size() > 0) {
644  waitingForMissingSegments = true;
645  resendMessagePending = true;
646  receiveOffset = missingReceiveSegments[0].offset;
647  } else {
648  finishedReception = true;
649  }
650  }
651 }
652 
653 void DataBlockProtocol::resizeReceiveBuffer() {
654  if(totalReceiveSize < 0) {
655  throw ProtocolException("Received invalid transfer size!");
656  }
657 
658  // We increase the requested size to allow for one
659  // additional network message and the protocol overhead
660  int bufferSize = totalReceiveSize + getMaxReceptionSize()
661  + MAX_OUTSTANDING_BYTES + sizeof(int);
662 
663  // Resize the buffer
664  if(static_cast<int>(receiveBuffer.size()) < bufferSize) {
665  receiveBuffer.resize(bufferSize);
666  }
667 }
Exception class that is used for all protocol exceptions.
Definition: exceptions.h:23
void setTransferData(unsigned char *data, int validBytes=0x7FFFFFFF)
Sets the payload data for the next transfer.
const unsigned char * getTransferMessage(int &length)
Gets the next network message for the current transfer.
const unsigned char * getNextControlMessage(int &length)
If a control message is pending to be transmitted, then the message data will be returned by this met...
DataBlockProtocol(bool server, ProtocolType protType, int maxUdpPacketSize)
Creates a new instance.
unsigned char * getReceivedData(int &length)
Returns the data that has been received for the current transfer.
void resetTransfer()
Resets all transfer related internal variables.
unsigned char * getNextReceiveBuffer(int maxLength)
Gets a buffer for receiving the next network message.
int getMaxReceptionSize() const
Returns the maximum payload size that can be received.
bool isConnected() const
Returns true if a remote connection is established.
bool newClientConnected()
Returns true if the last network message has established a new connection from a client.
void processReceivedMessage(int length, bool &transferComplete)
Handles a received network message.
void resetReception(bool dropped)
Resets the message reception.
bool transferComplete()
Returns true if the current transfer has been completed.
void setTransferHeader(unsigned char *data, int headerSize, int transferSize)
Sets a user-defined header that shall be transmitted with the next transfer.
void setTransferValidBytes(int validBytes)
Updates the number of valid bytes in a partial transfer.
unsigned char * getReceivedHeader(int &length)
Returns the header data that has been received for the current transfer.
Nerian Vision Technologies