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