libvisiontransfer  4.1.5
imagetransfer.cpp
1 /*******************************************************************************
2  * Copyright (c) 2017 Nerian Vision Technologies
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 <cstdio>
16 #include <iostream>
17 #include <cstring>
18 #include <memory>
19 #include <fcntl.h>
20 #include <string>
21 #include <vector>
22 #include "visiontransfer/imagetransfer.h"
23 #include "visiontransfer/exceptions.h"
24 #include "visiontransfer/datablockprotocol.h"
25 
26 
27 #ifdef _MSC_VER
28  // Visual studio does not come with snprintf
29  #define snprintf _snprintf_s
30 #endif
31 
32 // Network headers
33 #ifdef _WIN32
34  #ifndef _WIN32_WINNT
35  #define _WIN32_WINNT 0x501
36  #endif
37  #define _WINSOCK_DEPRECATED_NO_WARNINGS
38 
39  #ifndef NOMINMAX
40  #define NOMINMAX
41  #endif
42 
43  #include <winsock2.h>
44  #include <ws2tcpip.h>
45 
46  // Some defines to make windows socket look more like
47  // posix sockets.
48  #ifdef EWOULDBLOCK
49  #undef EWOULDBLOCK
50  #endif
51  #ifdef ECONNRESET
52  #undef ECONNRESET
53  #endif
54  #ifdef ETIMEDOUT
55  #undef ETIMEDOUT
56  #endif
57 
58  #define EWOULDBLOCK WSAEWOULDBLOCK
59  #define ECONNRESET WSAECONNRESET
60  #define ETIMEDOUT WSAETIMEDOUT
61  #define MSG_DONTWAIT 0
62 
63  #define close closesocket
64 
65  // Emulate posix errno. Does not work in a throw
66  // statement (WTF?)
67  #undef errno
68  #define errno WSAGetLastError()
69  #define strerror win_strerror
70 
71  std::string win_strerror(unsigned long error) {
72  char* str = nullptr;
73  if(FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
74  FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
75  nullptr, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
76  (LPSTR)&str, 0, nullptr) == 0 || str == nullptr) {
77  return "Unknown error";
78  } else {
79  char buffer[512];
80  snprintf(buffer, sizeof(buffer), "%s (%lu)", str, error);
81  LocalFree(str);
82  return std::string(buffer);
83  }
84  }
85 
86 #else
87  #include <arpa/inet.h>
88  #include <netinet/tcp.h>
89  #include <sys/types.h>
90  #include <sys/socket.h>
91  #include <netdb.h>
92  #include <netinet/in.h>
93  #include <errno.h>
94  #include <unistd.h>
95  #include <signal.h>
96 
97  // Unfortunately we have to use a winsock like socket type
98  typedef int SOCKET;
99  #define INVALID_SOCKET -1
100 
101  // Also we need some additional windock defines
102  #define WSA_IO_PENDING 0
103 #endif
104 
105 using namespace std;
106 
107 /*************** Pimpl class containing all private members ***********/
108 
109 class ImageTransfer::Pimpl {
110 public:
111  Pimpl(OperationMode mode, const char* remoteAddress, const char* remoteService,
112  const char* localAddress, const char* localService, int bufferSize);
113  ~Pimpl();
114 
115  // Redeclaration of public members
116  void setRawTransferData(const ImagePair& metaData, unsigned char* rawData,
117  int secondTileWidth = 0, int validBytes = 0x7FFFFFFF);
118  void setRawValidBytes(int validBytes);
119  void setTransferImagePair(const ImagePair& imagePair);
120  TransferStatus transferData(bool block);
121  bool receiveImagePair(ImagePair& imagePair, bool block);
122  bool receivePartialImagePair(ImagePair& imagePair, int& validRows, bool& complete, bool block);
123  bool tryAccept();
124  bool isClientConnected() const;
125  void disconnect();
126  std::string getClientAddress() const;
127 
128 private:
129  static constexpr int UDP_BUFFERS = 256;
130  static constexpr int TCP_BUFFER_SIZE = 0xFFFF; //64K - 1
131 
132  // The chosen operation mode for this connection
133  OperationMode mode;
134 
135  // The socket file descriptor
136  SOCKET socket;
137 
138  // In server mode: Socket listening on the server port
139  SOCKET serverSocket;
140 
141  // In server mode: Address if the connected client
142  sockaddr_in clientAddress;
143 
144  // Address for UDP transmissions
145  sockaddr_in udpAddress;
146 
147  // Object for encoding and decoding the network protocol
148  std::unique_ptr<ImageProtocol> protocol;
149 
150  // Outstanding network message that still has to be transferred
151  int currentMsgLen;
152  int currentMsgOffset;
153  const unsigned char* currentMsg;
154 
155  // Size of the socket buffers
156  int bufferSize;
157 
158  // Buffered error state the current reception
159  bool receptionFailed;
160 
161  bool socketIsBlocking;
162 
163  // Sets some required socket options for TCP sockets
164  void setSocketOptions();
165 
166  // Initialization functions for different operation modes
167  void initTcpClient(const addrinfo& remoteAddressInfo, const addrinfo& localAddressInfo);
168  void initTcpServer(const addrinfo& localAddressInfo);
169  void initUdp(const addrinfo& remoteAddressInfo, const addrinfo& localAddressInfo);
170 
171  // Receives some network data and forwards it to the protocol
172  int receiveSingleNetworkMessages(bool block);
173  bool receiveNetworkData(bool block);
174 
175  void win32SetBlocking(bool block);
176 };
177 
178 /******************** Stubs for all public members ********************/
179 
180 ImageTransfer::ImageTransfer(OperationMode mode, const char* remoteAddress,
181  const char* remoteService, const char* localAddress, const char* localService, int bufferSize):
182  pimpl(new Pimpl(mode, remoteAddress, remoteService, localAddress, localService, bufferSize)) {
183  // All initialization in the pimpl class
184 }
185 
186 ImageTransfer::~ImageTransfer() {
187  delete pimpl;
188 }
189 
190 void ImageTransfer::setRawTransferData(const ImagePair& metaData, unsigned char* rawData,
191  int secondTileWidth, int validBytes) {
192  pimpl->setRawTransferData(metaData, rawData, secondTileWidth, validBytes);
193 }
194 
195 void ImageTransfer::setRawValidBytes(int validBytes) {
196  pimpl->setRawValidBytes(validBytes);
197 }
198 
200  pimpl->setTransferImagePair(imagePair);
201 }
202 
204  return pimpl->transferData(block);
205 }
206 
207 bool ImageTransfer::receiveImagePair(ImagePair& imagePair, bool block) {
208  return pimpl->receiveImagePair(imagePair, block);
209 }
210 
211 bool ImageTransfer::receivePartialImagePair(ImagePair& imagePair, int& validRows, bool& complete, bool block) {
212  return pimpl->receivePartialImagePair(imagePair, validRows, complete, block);
213 }
214 
216  return pimpl->tryAccept();
217 }
218 
220  return pimpl->isClientConnected();
221 }
222 
224  pimpl->disconnect();
225 }
226 
227 std::string ImageTransfer::getClientAddress() const {
228  return pimpl->getClientAddress();
229 }
230 
231 /******************** Implementation in pimpl class *******************/
232 
233 ImageTransfer::Pimpl::Pimpl(OperationMode mode, const char* remoteAddress, const char* remoteService,
234  const char* localAddress, const char* localService, int bufferSize)
235  : mode(mode), socket(INVALID_SOCKET), serverSocket(INVALID_SOCKET), currentMsgLen(0),
236  currentMsgOffset(0), currentMsg(nullptr), bufferSize(bufferSize), receptionFailed(false), socketIsBlocking(true) {
237 
238 #ifdef _WIN32
239  // In windows, we first have to initialize winsock
240  WSADATA wsaData;
241  if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
242  throw TransferException("WSAStartup failed!");
243  }
244 #else
245  // We don't want to be interrupted by the pipe signal
246  signal(SIGPIPE, SIG_IGN);
247 #endif
248 
249  // If address is null we use the any address
250  if(remoteAddress == nullptr || string(remoteAddress) == "") {
251  remoteAddress = "0.0.0.0";
252  }
253  if(localAddress == nullptr || string(localAddress) == "") {
254  localAddress = "0.0.0.0";
255  }
256 
257  // Resolve address
258  addrinfo hints;
259  memset(&hints, 0, sizeof(hints));
260  hints.ai_family = AF_INET; // Use IPv4
261  hints.ai_socktype = (mode == TCP_CLIENT || mode == TCP_SERVER) ? SOCK_STREAM : SOCK_DGRAM;
262  hints.ai_flags = 0;
263  hints.ai_protocol = 0;
264 
265  addrinfo* remoteAddressInfo = nullptr;
266  if(getaddrinfo(remoteAddress, remoteService, &hints, &remoteAddressInfo) != 0 || remoteAddressInfo == nullptr) {
267  TransferException ex("Error resolving remote address: " + string(strerror(errno)));
268  throw ex;
269  }
270 
271  addrinfo* localAddressInfo = nullptr;
272  if(getaddrinfo(localAddress, localService, &hints, &localAddressInfo) != 0 || localAddressInfo == nullptr) {
273  TransferException ex("Error resolving local address: " + string(strerror(errno)));
274  throw ex;
275  }
276 
277  // Perform initialization depending on the selected operation mode
278  try {
279  switch(mode) {
280  case TCP_CLIENT: initTcpClient(*remoteAddressInfo, *localAddressInfo); break;
281  case TCP_SERVER: initTcpServer(*localAddressInfo); break;
282  case UDP: initUdp(*remoteAddressInfo, *localAddressInfo); break;
283  default: throw TransferException("Illegal operation mode");
284  }
285  } catch(...) {
286  freeaddrinfo(remoteAddressInfo);
287  freeaddrinfo(localAddressInfo);
288  throw;
289  }
290 
291  freeaddrinfo(remoteAddressInfo);
292  freeaddrinfo(localAddressInfo);
293 }
294 
295 ImageTransfer::Pimpl::~Pimpl() {
296  if(socket != INVALID_SOCKET) {
297  close(socket);
298  }
299 
300  if(serverSocket != INVALID_SOCKET) {
301  close(serverSocket);
302  }
303 }
304 
305 void ImageTransfer::Pimpl::initTcpClient(const addrinfo& remoteAddressInfo, const addrinfo& localAddressInfo) {
306  protocol.reset(new ImageProtocol(ImageProtocol::PROTOCOL_TCP));
307 
308  // Connect
309  socket = ::socket(remoteAddressInfo.ai_family, remoteAddressInfo.ai_socktype,
310  remoteAddressInfo.ai_protocol);
311  if(socket == INVALID_SOCKET) {
312  TransferException ex("Error creating socket: " + string(strerror(errno)));
313  throw ex;
314  }
315 
316  // Enable reuse address
317  int enable = 1;
318  setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&enable), sizeof(int));
319 
320  // Bind to local port
321  if (::bind(socket, localAddressInfo.ai_addr, static_cast<int>(localAddressInfo.ai_addrlen)) < 0) {
322  TransferException ex("Error binding socket: " + string(strerror(errno)));
323  throw ex;
324  }
325 
326  // Perform connection
327  if(connect(socket, remoteAddressInfo.ai_addr, static_cast<int>(remoteAddressInfo.ai_addrlen)) < 0) {
328  TransferException ex("Error connection to destination address: " + string(strerror(errno)));
329  throw ex;
330  }
331 
332  // Set special socket options
333  setSocketOptions();
334 }
335 
336 void ImageTransfer::Pimpl::initTcpServer(const addrinfo& localAddressInfo) {
337  protocol.reset(new ImageProtocol(ImageProtocol::PROTOCOL_TCP));
338 
339  // Create socket
340  serverSocket = ::socket(localAddressInfo.ai_family, localAddressInfo.ai_socktype,
341  localAddressInfo.ai_protocol);
342  if (serverSocket == INVALID_SOCKET) {
343  TransferException ex("Error opening socket: " + string(strerror(errno)));
344  throw ex;
345  }
346 
347  // Enable reuse address
348  int enable = 1;
349  setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&enable), sizeof(int));
350 
351  // Open a server port
352  if (::bind(serverSocket, localAddressInfo.ai_addr, static_cast<int>(localAddressInfo.ai_addrlen)) < 0) {
353  TransferException ex("Error binding socket: " + string(strerror(errno)));
354  throw ex;
355  }
356 
357  // Make the server socket non-blocking
358 #ifdef _WIN32
359  unsigned long on = 1;
360  ioctlsocket(serverSocket, FIONBIO, &on);
361 #else
362  fcntl(serverSocket, F_SETFL, O_NONBLOCK);
363 #endif
364 
365  // Listen on port
366  listen(serverSocket, 1);
367 }
368 
369 void ImageTransfer::Pimpl::initUdp(const addrinfo& remoteAddressInfo, const addrinfo& localAddressInfo) {
370  protocol.reset(new ImageProtocol(ImageProtocol::PROTOCOL_UDP));
371  // Create socket
372  socket = ::socket(localAddressInfo.ai_family, localAddressInfo.ai_socktype,
373  localAddressInfo.ai_protocol);
374  if(socket == INVALID_SOCKET) {
375  TransferException ex("Error creating socket: " + string(strerror(errno)));
376  throw ex;
377  }
378 
379  // Enable reuse address
380  int enable = 1;
381  setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&enable), sizeof(int));
382 
383  // Bind socket to port
384  if (::bind(socket, localAddressInfo.ai_addr, static_cast<int>(localAddressInfo.ai_addrlen)) < 0) {
385  TransferException ex("Error binding socket: " + string(strerror(errno)));
386  throw ex;
387  }
388 
389  // Store remote address
390  if(remoteAddressInfo.ai_addrlen != sizeof(udpAddress)) {
391  throw TransferException("Illegal address length");
392  }
393  memcpy(&udpAddress, remoteAddressInfo.ai_addr, sizeof(udpAddress));
394 
395  // Set special socket options
396  setSocketOptions();
397 }
398 
399 bool ImageTransfer::Pimpl::tryAccept() {
400  if(mode != TCP_SERVER) {
401  throw TransferException("Connections can only be accepted in tcp server mode");
402  }
403 
404  // Accept one connection
405  socklen_t clientAddressLength = sizeof(clientAddress);
406 
407  SOCKET newSocket = accept(serverSocket,
408  reinterpret_cast<sockaddr *>(&clientAddress),
409  &clientAddressLength);
410 
411  if(newSocket == INVALID_SOCKET) {
412  if(errno == EWOULDBLOCK || errno == ETIMEDOUT) {
413  // No connection
414  return false;
415  } else {
416  TransferException ex("Error accepting connection: " + string(strerror(errno)));
417  throw ex;
418  }
419  }
420 
421  // Close old socket and set new socket
422  if(socket != INVALID_SOCKET) {
423  close(socket);
424  }
425  socket = newSocket;
426 
427  // Set special socket options
428  setSocketOptions();
429 
430  // Reset connection data
431  protocol->resetTransfer();
432  protocol->resetReception();
433 
434  return true;
435 }
436 
437 std::string ImageTransfer::Pimpl::getClientAddress() const {
438  if(socket == INVALID_SOCKET) {
439  return ""; // No client connected
440  }
441 
442  char strPort[11];
443  snprintf(strPort, sizeof(strPort), ":%d", clientAddress.sin_port);
444 
445  return string(inet_ntoa(clientAddress.sin_addr)) + strPort;
446 }
447 
448 void ImageTransfer::Pimpl::setSocketOptions() {
449  if(mode == TCP_SERVER) {
450  // Make sure the client socket didn't inherit the non-blocking mode from the server socket
451 #ifdef _WIN32
452  unsigned long on = 0;
453  ioctlsocket(socket, FIONBIO, &on);
454 #else
455  fcntl(socket, F_SETFL, 0);
456 #endif
457  }
458 
459  // Set the socket buffer sizes
460  if(bufferSize > 0) {
461  setsockopt(socket, SOL_SOCKET, SO_RCVBUF, reinterpret_cast<char*>(&bufferSize), sizeof(bufferSize));
462  setsockopt(socket, SOL_SOCKET, SO_SNDBUF, reinterpret_cast<char*>(&bufferSize), sizeof(bufferSize));
463  }
464 
465  // Set sending and receive timeouts
466 #ifdef _WIN32
467  unsigned int timeout = 1000;
468 #else
469  struct timeval timeout;
470  timeout.tv_sec = 1;
471  timeout.tv_usec = 0;
472 #endif
473 
474  setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast<char*>(&timeout), sizeof(timeout));
475  setsockopt(socket, SOL_SOCKET, SO_SNDTIMEO, reinterpret_cast<char*>(&timeout), sizeof(timeout));
476 
477  // Disable multicast loops for improved performance
478  unsigned char loop = 0;
479  setsockopt(socket, IPPROTO_IP, IP_MULTICAST_LOOP, reinterpret_cast<char*>(&loop), sizeof(loop));
480 
481  // Try to set a more suitable congestion control algorithm for TCP streams
482 #ifdef TCP_CONGESTION
483  if(mode == TCP_SERVER || mode == TCP_CLIENT) {
484  char optval[16];
485  strcpy(optval, "westwood");
486  if (setsockopt(socket, IPPROTO_TCP, TCP_CONGESTION, optval, strlen(optval)) < 0) {
487  // Can't set westwood. Let's try reno
488  strcpy(optval, "reno");
489  setsockopt(socket, IPPROTO_TCP, TCP_CONGESTION, optval, strlen(optval));
490  }
491  }
492 #endif
493 }
494 
495 void ImageTransfer::Pimpl::setRawTransferData(const ImagePair& metaData,
496  unsigned char* rawData, int secondTileWidth, int validBytes) {
497  protocol->setRawTransferData(metaData, rawData, secondTileWidth, validBytes);
498  currentMsg = nullptr;
499 }
500 
501 void ImageTransfer::Pimpl::setRawValidBytes(int validBytes) {
502  protocol->setRawValidBytes(validBytes);
503 }
504 
505 void ImageTransfer::Pimpl::setTransferImagePair(const ImagePair& imagePair) {
506  protocol->setTransferImagePair(imagePair);
507  currentMsg = nullptr;
508 }
509 
510 void ImageTransfer::Pimpl::win32SetBlocking(bool block) {
511 #ifdef _WIN32
512  if(block != socketIsBlocking) {
513  // Windows doesn't support MSG_DONTWAIT. Have to touch the socket
514  unsigned long on = block ? 0 : 1;
515  ioctlsocket(socket, FIONBIO, &on);
516 
517  socketIsBlocking = block;
518  }
519 #endif
520 }
521 
522 ImageTransfer::TransferStatus ImageTransfer::Pimpl::transferData(bool block) {
523  if(currentMsg == nullptr) {
524  currentMsgOffset = 0;
525  currentMsg = protocol->getTransferMessage(currentMsgLen);
526 
527  if(currentMsg == nullptr) {
528  return NO_VALID_DATA;
529  }
530  }
531 
532  while(currentMsg != nullptr) {
533  int writing = (int)(currentMsgLen - currentMsgOffset);
534  int written = 0;
535 
536  win32SetBlocking(block);
537 
538  switch(mode) {
539  case TCP_SERVER:
540  case TCP_CLIENT:
541  written = send(socket, reinterpret_cast<const char*>(&currentMsg[currentMsgOffset]), writing,
542  block ? 0 : MSG_DONTWAIT);
543  break;
544  case UDP:
545  written = sendto(socket, reinterpret_cast<const char*>(&currentMsg[currentMsgOffset]), writing,
546  block ? 0 : MSG_DONTWAIT, reinterpret_cast<sockaddr*>(&udpAddress), sizeof(udpAddress));
547  break;
548  }
549 
550  unsigned long sendError = errno;
551 
552  if(written < 0) {
553  if(!block && (sendError == EAGAIN || sendError == EWOULDBLOCK || sendError == ETIMEDOUT)) {
554  // The socket is not yet ready for a new transfer
555  return WOULD_BLOCK;
556  }
557  else if(sendError == ECONNRESET && (mode == TCP_SERVER || mode == TCP_CLIENT)) {
558  // Connection closed by remote host
559  close(socket);
560  socket = INVALID_SOCKET;
561  return CONNECTION_CLOSED;
562  } else {
563  TransferException ex("Error sending message: " + string(strerror(sendError)));
564  throw ex;
565  }
566  } else if(written != writing) {
567  // The message has been transmitted partially
568  if(mode == UDP) {
569  throw TransferException("Unable to transmit complete UDP message");
570  }
571 
572  currentMsgOffset+= written;
573  if(!block) {
574  return PARTIAL_TRANSFER;
575  }
576  } else if(!block) {
577  // Only one iteration allowed in non-blocking mode
578  currentMsg = nullptr;
579  break;
580  } else {
581  // Get next message
582  currentMsg = protocol->getTransferMessage(currentMsgLen);
583  currentMsgOffset = 0;
584  }
585  }
586 
587  if(mode == TCP_SERVER && protocol->transferComplete()) {
588  // Force a flush by turning the nagle algorithm off and on
589  int flag = 1;
590  setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));
591  flag = 0;
592  setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));
593  }
594 
595  if(protocol->transferComplete()) {
596  return ALL_TRANSFERRED;
597  } else {
598  return PARTIAL_TRANSFER;
599  }
600 }
601 
602 bool ImageTransfer::Pimpl::receiveImagePair(ImagePair& imagePair, bool block) {
603  int validRows = 0;
604  bool complete = false;
605 
606  while(!complete) {
607  if(!receivePartialImagePair(imagePair, validRows, complete, block)) {
608  return false;
609  }
610  }
611 
612  return true;
613 }
614 
615 bool ImageTransfer::Pimpl::receivePartialImagePair(ImagePair& imagePair,
616  int& validRows, bool& complete, bool block) {
617  if(receptionFailed) {
618  // Notify about reception errors by returning false once
619  receptionFailed = false;
620  return false;
621  }
622 
623  // Try to receive further image data
624  while(!protocol->imagesReceived() && receiveNetworkData(block)) {
625  block = false;
626  }
627 
628  // Get received image
629  return protocol->getPartiallyReceivedImagePair(imagePair, validRows, complete);
630 }
631 
632 int ImageTransfer::Pimpl::receiveSingleNetworkMessages(bool block) {
633  int maxLength = 0;
634  char* buffer = reinterpret_cast<char*>(protocol->getNextReceiveBuffer(maxLength));
635 
636  int bytesReceived = recv(socket, buffer, maxLength,
637 #ifdef _WIN32
638  0
639 #else
640  block ? 0 : MSG_DONTWAIT
641 #endif
642  );
643 
644  if(bytesReceived > 0) {
645  if(!protocol->processReceivedMessage(bytesReceived)) {
646  if(mode == TCP_CLIENT) {
647  receptionFailed = true;
648  }
649  }
650  }
651 
652  return bytesReceived;
653 }
654 
655 bool ImageTransfer::Pimpl::receiveNetworkData(bool block) {
656  win32SetBlocking(block);
657 
658  int received = receiveSingleNetworkMessages(block);
659  bool ret = true;
660 
661  if(received == 0 && (mode == TCP_SERVER || mode == TCP_CLIENT)) {
662  // Connection closed by remote host
663  close(socket);
664  socket = INVALID_SOCKET;
665  ret = false;
666  } else if(received < 0) {
667  if(errno == EWOULDBLOCK || errno == EINTR || errno == ETIMEDOUT || errno == WSA_IO_PENDING) {
668  // Reception was cancelled because it took too long,
669  // or because of some signal. We reset reception for the current frame.
670  ret = false;
671  } else {
672  TransferException ex("Error reading from socket: " + string(strerror(errno)));
673  throw ex;
674  }
675  }
676 
677  return ret;
678 }
679 
680 void ImageTransfer::Pimpl::disconnect() {
681  if(mode != TCP_SERVER && mode != TCP_CLIENT) {
682  throw TransferException("Only TCP transfers can be disconnected");
683  }
684  if(socket != INVALID_SOCKET) {
685  close(socket);
686  socket = INVALID_SOCKET;
687  }
688 }
689 
690 bool ImageTransfer::Pimpl::isClientConnected() const {
691  return socket != INVALID_SOCKET;
692 }
bool receivePartialImagePair(ImagePair &imagePair, int &validRows, bool &complete, bool block=false)
Returns the received image pair, even if it is not yet complete.
TransferStatus transferData(bool block)
Performs a partial (or full) image transmission.
The connection has been closed by the remote host.
Definition: imagetransfer.h:48
Using TCP and acting as communication server.
Definition: imagetransfer.h:42
A lightweight protocol for transferring image pairs.
Definition: imageprotocol.h:36
OperationMode
Supported transfer modes.
Definition: imagetransfer.h:33
Using TCP and acting as communication client.
Definition: imagetransfer.h:39
bool tryAccept()
Tries to accept a client connection.
ImageTransfer(OperationMode mode, const char *remoteAddress, const char *remoteService, const char *localAddress, const char *localService, int bufferSize=1000000)
Creates a new transfer object.
void setTransferImagePair(const ImagePair &imagePair)
Sets a new image pair that shall be transmitted.
void setRawTransferData(const ImagePair &metaData, unsigned char *rawData, int secondTileWidth=0, int validBytes=0x7FFFFFFF)
Sets the raw pixel data for a partial image transmission.
The connection-less UDP transport protocol.
Definition: imageprotocol.h:44
Exception class that is used for all transfer exceptions.
Definition: exceptions.h:31
The image pair has been transferred completely.
Definition: imagetransfer.h:51
TransferStatus
The result of a partial image transfer.
Definition: imagetransfer.h:46
A set of two images, which are usually the left camera image and the disparity map.
Definition: imagepair.h:30
bool isClientConnected() const
Returns true if a client is connected.
void disconnect()
Terminates the current connection.
The operation would block and blocking as been disabled.
Definition: imagetransfer.h:61
void setRawValidBytes(int validBytes)
Updates the number of valid bytes in a partial raw transmission.
std::string getClientAddress() const
Returns the address of the connected client.
bool receiveImagePair(ImagePair &imagePair, bool block=true)
Waits for and receives a new image pair.
There is currently no more data that could be transmitted.
Definition: imagetransfer.h:58
The connection oriented TCP transport protocol.
Definition: imageprotocol.h:41
Nerian Vision Technologies