libvisiontransfer  6.1.1
datablockprotocol.h
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 #ifndef VISIONTRANSFER_DATABLOCKPROTOCOL_H
16 #define VISIONTRANSFER_DATABLOCKPROTOCOL_H
17 
18 #include <map>
19 #include <vector>
20 #include <memory>
21 #include <chrono>
22 #include <deque>
23 
24 #include "visiontransfer/alignedallocator.h"
25 
43 public:
44  enum ProtocolType {
45  PROTOCOL_TCP,
46  PROTOCOL_UDP
47  };
48 
49  // Constants that are also used in other places.
50  static const int MAX_TCP_BYTES_TRANSFER = 0xFFFF; //64K - 1
51  static const int MAX_UDP_RECEPTION = 0x4000; //16K
52  static const int MAX_OUTSTANDING_BYTES = 2*MAX_TCP_BYTES_TRANSFER;
53 
62  DataBlockProtocol(bool server, ProtocolType protType, int maxUdpPacketSize);
63 
68  int getProtocolOverhead() const {
69  return protType == PROTOCOL_UDP ? sizeof(int) : 0;
70  }
71 
75  int getMaxReceptionSize() const;
76 
80  void resetTransfer();
81 
96  void setTransferHeader(unsigned char* data, int headerSize, int transferSize);
97 
112  void setTransferData(unsigned char* data, int validBytes = 0x7FFFFFFF);
113 
123  void setTransferValidBytes(int validBytes);
124 
134  const unsigned char* getTransferMessage(int& length);
135 
139  bool transferComplete();
140 
149  unsigned char* getNextReceiveBuffer(int maxLength);
150 
157  void resetReception(bool dropped);
158 
168  void processReceivedMessage(int length, bool& transferComplete);
169 
179  unsigned char* getReceivedData(int& length);
180 
192  unsigned char* getReceivedHeader(int& length);
193 
198  int getDroppedReceptions() const {
199  return droppedReceptions;
200  }
201 
209  bool newClientConnected();
210 
217  bool isConnected() const;
218 
229  const unsigned char* getNextControlMessage(int& length);
230 
231 private:
232  // The pimpl idiom is not necessary here, as this class is usually not
233  // used directly
234 
235  struct MissingReceiveSegment {
236  int offset;
237  int length;
238  bool isEof;
239  unsigned char subsequentData[4];
240  };
241 
242  static constexpr int HEARTBEAT_INTERVAL_MS = 1000;
243  static constexpr int RECONNECT_TIMEOUT_MS = 1000;
244 
245  static constexpr unsigned char CONNECTION_MESSAGE = 0x01;
246  static constexpr unsigned char CONFIRM_MESSAGE = 0x02;
247  static constexpr unsigned char HEADER_MESSAGE = 0x03;
248  static constexpr unsigned char RESEND_MESSAGE = 0x04;
249  static constexpr unsigned char EOF_MESSAGE = 0x05;
250  static constexpr unsigned char HEARTBEAT_MESSAGE = 0x06;
251 
252  bool isServer;
253  ProtocolType protType;
254  int maxPayloadSize;
255  int minPayloadSize;
256 
257  // Transfer related variables
258  bool transferDone;
259  unsigned char* rawData;
260  int rawValidBytes;
261  int transferOffset;
262  int transferSize;
263  int overwrittenTransferData;
264  int overwrittenTransferIndex;
265  unsigned char* transferHeaderData;
266  int transferHeaderSize;
267 
268  // Reliability related variables
269  std::deque<MissingReceiveSegment> missingReceiveSegments;
270  std::deque<std::pair<int, int> > missingTransferSegments;
271  bool waitingForMissingSegments;
272  int totalReceiveSize;
273 
274  unsigned char controlMessageBuffer[1024];
275 
276  // Connection related variables
277  bool connectionConfirmed;
278  bool confirmationMessagePending;
279  bool eofMessagePending;
280  bool clientConnectionPending;
281  bool resendMessagePending;
282  std::chrono::steady_clock::time_point lastRemoteHostActivity;
283  std::chrono::steady_clock::time_point lastSentHeartbeat;
284  std::chrono::steady_clock::time_point lastReceivedHeartbeat;
285 
286  // Reception related variables
287  std::vector<unsigned char, AlignedAllocator<unsigned char> > receiveBuffer;
288  int receiveDataSize;
289  int receiveOffset;
290  std::vector<unsigned char> receivedHeader;
291  bool finishedReception;
292  int droppedReceptions;
293  unsigned char unprocessedMsgPart[MAX_OUTSTANDING_BYTES];
294  int unprocessedMsgLength;
295  bool headerReceived;
296 
297  const unsigned char* extractPayload(const unsigned char* data, int& length, bool& error);
298  bool processControlMessage(int length);
299  void restoreTransferBuffer();
300  bool generateResendRequest(int& length);
301  void getNextTransferSegment(int& offset, int& length);
302  void parseResendMessage(int length);
303  void parseEofMessage(int length);
304  int getNextUdpReceiveOffset(int lastSegmentOffset, int lastSegmentSize);
305  void processReceivedUdpMessage(int length, bool& transferComplete);
306  void processReceivedTcpMessage(int length, bool& transferComplete);
307  void resizeReceiveBuffer();
308  int parseReceivedHeader(int length, int offset);
309 };
310 
311 #endif
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...
A protocol for transmitting large blocks of data over a network.
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 getProtocolOverhead() const
Returns the size of the overhead data that is required for transferring a single network message...
bool isConnected() const
Returns true if a remote connection is established.
int getDroppedReceptions() const
Returns the internal counter of dropped transfers during reception.
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