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