libvisiontransfer  6.2.1
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 if(headerReceived) {
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.
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.
int getMaxReceptionSize() const
Returns the maximum payload size that can be received.
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