libvisiontransfer  6.1.1
imagetransfer.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 <cstdio>
16 #include <iostream>
17 #include <cstring>
18 #include <memory>
19 #include <fcntl.h>
20 #include <string>
21 #include <vector>
22 #include <mutex>
23 #include "visiontransfer/imagetransfer.h"
24 #include "visiontransfer/exceptions.h"
25 #include "visiontransfer/datablockprotocol.h"
26 #include "visiontransfer/networking.h"
27 
28 using namespace std;
29 
30 /*************** Pimpl class containing all private members ***********/
31 
32 class ImageTransfer::Pimpl {
33 public:
34  Pimpl(const char* address, const char* service, ImageProtocol::ProtocolType protType,
35  bool server, int bufferSize, int maxUdpPacketSize);
36  ~Pimpl();
37 
38  // Redeclaration of public members
39  void setRawTransferData(const ImagePair& metaData, unsigned char* rawData,
40  int secondTileWidth = 0, int validBytes = 0x7FFFFFFF);
41  void setRawValidBytes(int validBytes);
42  void setTransferImagePair(const ImagePair& imagePair);
43  TransferStatus transferData();
44  bool receiveImagePair(ImagePair& imagePair);
45  bool receivePartialImagePair(ImagePair& imagePair, int& validRows, bool& complete);
46  int getNumDroppedFrames() const;
47  bool isConnected() const;
48  void disconnect();
49  std::string getRemoteAddress() const;
50  bool tryAccept();
51 
52 private:
53  // Configuration parameters
55  bool isServer;
56  int bufferSize;
57  int maxUdpPacketSize;
58 
59  // Thread synchronization
60  std::recursive_mutex receiveMutex;
61  std::recursive_mutex sendMutex;
62 
63  // Transfer related members
64  SOCKET clientSocket;
65  SOCKET tcpServerSocket;
66  sockaddr_in remoteAddress;
67 
68  // Object for encoding and decoding the network protocol
69  std::unique_ptr<ImageProtocol> protocol;
70 
71  // Outstanding network message that still has to be transferred
72  int currentMsgLen;
73  int currentMsgOffset;
74  const unsigned char* currentMsg;
75 
76  // Socket configuration
77  void setSocketOptions();
78  void setSocketBlocking(bool blocking, SOCKET socket);
79 
80  // Network socket initialization
81  void initTcpServer(const addrinfo* addressInfo);
82  void initTcpClient(const addrinfo* addressInfo);
83  void initUdp(const addrinfo* addressInfo);
84 
85  // Data reception
86  bool receiveNetworkData(bool block);
87 
88  // Data transmission
89  bool sendNetworkMessage(const unsigned char* msg, int length);
90  void sendPendingControlMessages();
91 
92  bool selectSocket(bool read, bool wait);
93  void closeSocket(SOCKET& socket);
94 };
95 
96 /******************** Stubs for all public members ********************/
97 
98 ImageTransfer::ImageTransfer(const char* address, const char* service,
99  ImageProtocol::ProtocolType protType, bool server, int bufferSize, int maxUdpPacketSize):
100  pimpl(new Pimpl(address, service, protType, server, bufferSize, maxUdpPacketSize)) {
101  // All initialization in the pimpl class
102 }
103 
104 ImageTransfer::ImageTransfer(const DeviceInfo& device, int bufferSize, int maxUdpPacketSize):
105  pimpl(new Pimpl(device.getIpAddress().c_str(), "7681", static_cast<ImageProtocol::ProtocolType>(device.getNetworkProtocol()),
106  false, bufferSize, maxUdpPacketSize)) {
107  // All initialization in the pimpl class
108 }
109 
110 ImageTransfer::~ImageTransfer() {
111  delete pimpl;
112 }
113 
114 void ImageTransfer::setRawTransferData(const ImagePair& metaData, unsigned char* rawData,
115  int secondTileWidth, int validBytes) {
116  pimpl->setRawTransferData(metaData, rawData, secondTileWidth, validBytes);
117 }
118 
119 void ImageTransfer::setRawValidBytes(int validBytes) {
120  pimpl->setRawValidBytes(validBytes);
121 }
122 
124  pimpl->setTransferImagePair(imagePair);
125 }
126 
128  return pimpl->transferData();
129 }
130 
132  return pimpl->receiveImagePair(imagePair);
133 }
134 
135 bool ImageTransfer::receivePartialImagePair(ImagePair& imagePair, int& validRows, bool& complete) {
136  return pimpl->receivePartialImagePair(imagePair, validRows, complete);
137 }
138 
140  return pimpl->getNumDroppedFrames();
141 }
142 
144  return pimpl->isConnected();
145 }
146 
148  pimpl->disconnect();
149 }
150 
151 std::string ImageTransfer::getRemoteAddress() const {
152  return pimpl->getRemoteAddress();
153 }
154 
156  return pimpl->tryAccept();
157 }
158 
159 /******************** Implementation in pimpl class *******************/
160 ImageTransfer::Pimpl::Pimpl(const char* address, const char* service,
161  ImageProtocol::ProtocolType protType, bool server, int
162  bufferSize, int maxUdpPacketSize)
163  : protType(protType), isServer(server), bufferSize(bufferSize),
164  maxUdpPacketSize(maxUdpPacketSize),
165  clientSocket(INVALID_SOCKET), tcpServerSocket(INVALID_SOCKET),
166  currentMsgLen(0), currentMsgOffset(0), currentMsg(nullptr) {
167 
168 #ifdef _WIN32
169  // In windows, we first have to initialize winsock
170  WSADATA wsaData;
171  if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
172  throw TransferException("WSAStartup failed!");
173  }
174 #else
175  // We don't want to be interrupted by the pipe signal
176  signal(SIGPIPE, SIG_IGN);
177 #endif
178 
179  memset(&remoteAddress, 0, sizeof(remoteAddress));
180 
181  // If address is null we use the any address
182  if(address == nullptr || string(address) == "") {
183  address = "0.0.0.0";
184  }
185 
186  // Resolve address
187  addrinfo hints;
188  memset(&hints, 0, sizeof(hints));
189  hints.ai_family = AF_INET; // Use IPv4
190  hints.ai_socktype = (protType == ImageProtocol::PROTOCOL_TCP ? SOCK_STREAM : SOCK_DGRAM);
191  hints.ai_flags = 0;
192  hints.ai_protocol = 0;
193 
194  addrinfo* addressInfo = nullptr;
195  if(service != nullptr && string(service) != "") {
196  if(getaddrinfo(address, service, &hints, &addressInfo) != 0 || addressInfo == nullptr) {
197  TransferException ex("Error resolving address: " + string(strerror(errno)));
198  throw ex;
199  }
200  }
201 
202  if(addressInfo->ai_addrlen != sizeof(remoteAddress)) {
203  throw TransferException("Illegal address length");
204  }
205 
206  try {
207  if(protType == ImageProtocol::PROTOCOL_UDP) {
208  initUdp(addressInfo);
209  } else if(protType == ImageProtocol::PROTOCOL_TCP && isServer) {
210  initTcpServer(addressInfo);
211  } else {
212  initTcpClient(addressInfo);
213  }
214  } catch(...) {
215  freeaddrinfo(addressInfo);
216  throw;
217  }
218 
219  if(addressInfo != nullptr) {
220  freeaddrinfo(addressInfo);
221  }
222 }
223 
224 ImageTransfer::Pimpl::~Pimpl() {
225  if(clientSocket != INVALID_SOCKET) {
226  closeSocket(clientSocket);
227  }
228  if(tcpServerSocket != INVALID_SOCKET) {
229  closeSocket(tcpServerSocket);
230  }
231 }
232 
233 void ImageTransfer::Pimpl::initTcpClient(const addrinfo* addressInfo) {
234  protocol.reset(new ImageProtocol(isServer, ImageProtocol::PROTOCOL_TCP));
235 
236  // Connect
237  clientSocket = ::socket(addressInfo->ai_family, addressInfo->ai_socktype,
238  addressInfo->ai_protocol);
239  if(clientSocket == INVALID_SOCKET) {
240  TransferException ex("Error creating socket: " + string(strerror(errno)));
241  throw ex;
242  }
243 
244  // Perform connection
245  if(connect(clientSocket, addressInfo->ai_addr, static_cast<int>(addressInfo->ai_addrlen)) < 0) {
246  TransferException ex("Error connection to destination address: " + string(strerror(errno)));
247  throw ex;
248  }
249 
250  memcpy(&remoteAddress, addressInfo->ai_addr, sizeof(remoteAddress));
251 
252  // Set special socket options
253  setSocketOptions();
254 }
255 
256 void ImageTransfer::Pimpl::initTcpServer(const addrinfo* addressInfo) {
257  protocol.reset(new ImageProtocol(isServer, ImageProtocol::PROTOCOL_TCP));
258 
259  // Create socket
260  tcpServerSocket = ::socket(addressInfo->ai_family, addressInfo->ai_socktype,
261  addressInfo->ai_protocol);
262  if (tcpServerSocket == INVALID_SOCKET) {
263  TransferException ex("Error opening socket: " + string(strerror(errno)));
264  throw ex;
265  }
266 
267  // Enable reuse address
268  int enable = 1;
269  setsockopt(tcpServerSocket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&enable), sizeof(int));
270 
271  // Open a server port
272  if (::bind(tcpServerSocket, addressInfo->ai_addr, static_cast<int>(addressInfo->ai_addrlen)) < 0) {
273  TransferException ex("Error binding socket: " + string(strerror(errno)));
274  throw ex;
275  }
276 
277  clientSocket = INVALID_SOCKET;
278 
279  // Make the server socket non-blocking
280  setSocketBlocking(false, tcpServerSocket);
281 
282  // Listen on port
283  listen(tcpServerSocket, 1);
284 }
285 
286 void ImageTransfer::Pimpl::initUdp(const addrinfo* addressInfo) {
287  protocol.reset(new ImageProtocol(isServer, ImageProtocol::PROTOCOL_UDP, maxUdpPacketSize));
288  // Create sockets
289  clientSocket = socket(AF_INET, SOCK_DGRAM, 0);
290  if(clientSocket == INVALID_SOCKET) {
291  TransferException ex("Error creating receive socket: " + string(strerror(errno)));
292  throw ex;
293  }
294 
295  // Enable reuse address
296  int enable = 1;
297  setsockopt(clientSocket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&enable), sizeof(int));
298 
299  // Bind socket to port
300  if(isServer && addressInfo != nullptr) {
301  if (::bind(clientSocket, addressInfo->ai_addr, static_cast<int>(addressInfo->ai_addrlen)) < 0) {
302  TransferException ex("Error binding socket: " + string(strerror(errno)));
303  throw ex;
304  }
305  }
306 
307  if(!isServer) {
308  memcpy(&remoteAddress, addressInfo->ai_addr, sizeof(remoteAddress));
309  }
310 
311  // Set special socket options
312  setSocketOptions();
313 }
314 
315 bool ImageTransfer::Pimpl::tryAccept() {
316  if(protType != ImageProtocol::PROTOCOL_TCP || ! isServer) {
317  throw TransferException("Connections can only be accepted in tcp server mode");
318  }
319 
320  unique_lock<recursive_mutex> recvLock(receiveMutex);
321  unique_lock<recursive_mutex> sendLock(sendMutex);
322 
323  // Accept one connection
324  socklen_t clientAddressLength = sizeof(remoteAddress);
325 
326  SOCKET newSocket = accept(tcpServerSocket,
327  reinterpret_cast<sockaddr *>(&remoteAddress),
328  &clientAddressLength);
329 
330  if(clientAddressLength != sizeof(remoteAddress)) {
331  throw TransferException("Received network address with invalid length");
332  }
333 
334  if(newSocket == INVALID_SOCKET) {
335  if(errno == EWOULDBLOCK || errno == ETIMEDOUT) {
336  // No connection
337  return false;
338  } else {
339  TransferException ex("Error accepting connection: " + string(strerror(errno)));
340  throw ex;
341  }
342  }
343 
344  // Close old socket and set new socket
345  if(clientSocket != INVALID_SOCKET) {
346  closeSocket(clientSocket);
347  }
348  clientSocket = newSocket;
349 
350  // Set special socket options
351  setSocketOptions();
352 
353  // Reset connection data
354  protocol->resetTransfer();
355  protocol->resetReception();
356  currentMsg = nullptr;
357 
358  return true;
359 }
360 
361 std::string ImageTransfer::Pimpl::getRemoteAddress() const {
362  unique_lock<recursive_mutex> lock(const_cast<recursive_mutex&>(sendMutex)); // either mutex will work
363 
364  if(remoteAddress.sin_family != AF_INET) {
365  return "";
366  }
367 
368  char strPort[11];
369  snprintf(strPort, sizeof(strPort), ":%d", remoteAddress.sin_port);
370 
371  return string(inet_ntoa(remoteAddress.sin_addr)) + strPort;
372 }
373 
374 void ImageTransfer::Pimpl::setSocketOptions() {
375  // Set the socket buffer sizes
376  if(bufferSize > 0) {
377  setsockopt(clientSocket, SOL_SOCKET, SO_RCVBUF, reinterpret_cast<char*>(&bufferSize), sizeof(bufferSize));
378  setsockopt(clientSocket, SOL_SOCKET, SO_SNDBUF, reinterpret_cast<char*>(&bufferSize), sizeof(bufferSize));
379  }
380 
381  // Set sending and receive timeouts
382 #ifdef _WIN32
383  unsigned int timeout = 500;
384 #else
385  struct timeval timeout;
386  timeout.tv_sec = 0;
387  timeout.tv_usec = 500000;
388 #endif
389 
390  setsockopt(clientSocket, SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast<char*>(&timeout), sizeof(timeout));
391  setsockopt(clientSocket, SOL_SOCKET, SO_SNDTIMEO, reinterpret_cast<char*>(&timeout), sizeof(timeout));
392  setSocketBlocking(true, clientSocket);
393 }
394 
395 void ImageTransfer::Pimpl::setSocketBlocking(bool blocking, SOCKET socket) {
396 #ifdef _WIN32
397  unsigned long on = (blocking ? 0 : 1);
398  ioctlsocket(socket, FIONBIO, &on);
399 #else
400  int flags = fcntl(socket, F_GETFL, 0);
401  if(flags != -1) {
402  if(blocking) {
403  flags &= ~O_NONBLOCK;
404  } else {
405  flags |= O_NONBLOCK;
406  }
407  fcntl(socket, F_SETFL, flags);
408  }
409 #endif
410 }
411 
412 void ImageTransfer::Pimpl::setRawTransferData(const ImagePair& metaData,
413  unsigned char* rawData, int secondTileWidth, int validBytes) {
414  unique_lock<recursive_mutex> sendLock(sendMutex);
415  protocol->setRawTransferData(metaData, rawData, secondTileWidth, validBytes);
416  currentMsg = nullptr;
417 }
418 
419 void ImageTransfer::Pimpl::setRawValidBytes(int validBytes) {
420  unique_lock<recursive_mutex> sendLock(sendMutex);
421  protocol->setRawValidBytes(validBytes);
422 }
423 
424 void ImageTransfer::Pimpl::setTransferImagePair(const ImagePair& imagePair) {
425  unique_lock<recursive_mutex> sendLock(sendMutex);
426  protocol->setTransferImagePair(imagePair);
427  currentMsg = nullptr;
428 }
429 
430 ImageTransfer::TransferStatus ImageTransfer::Pimpl::transferData() {
431  unique_lock<recursive_mutex> lock(sendMutex);
432 
433  // First receive data in case a control message arrives
434  if(protType == ImageProtocol::PROTOCOL_UDP) {
435  receiveNetworkData(false);
436  }
437 
438  if(remoteAddress.sin_family != AF_INET || !protocol->isConnected()) {
439  return NOT_CONNECTED;
440  }
441 
442  // Get first message to transfer
443  if(currentMsg == nullptr) {
444  currentMsgOffset = 0;
445  currentMsg = protocol->getTransferMessage(currentMsgLen);
446 
447  if(currentMsg == nullptr) {
448  if(protocol->transferComplete()) {
449  return ALL_TRANSFERRED;
450  } else {
451  return NO_VALID_DATA;
452  }
453  }
454  }
455 
456  // Try transferring messages
457  bool dataTransferred = (currentMsg != nullptr);
458  while(currentMsg != nullptr) {
459  int writing = (int)(currentMsgLen - currentMsgOffset);
460 
461  if(sendNetworkMessage(&currentMsg[currentMsgOffset], writing)) {
462  // Get next message
463  currentMsgOffset = 0;
464  currentMsg = protocol->getTransferMessage(currentMsgLen);
465  } else {
466  return WOULD_BLOCK;
467  }
468  }
469 
470  if(dataTransferred && protType == ImageProtocol::PROTOCOL_TCP && protocol->transferComplete()) {
471  // Force a flush for TCP by turning the nagle algorithm off and on
472  int flag = 1;
473  setsockopt(clientSocket, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));
474  flag = 0;
475  setsockopt(clientSocket, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));
476  }
477 
478  // Also check for control messages at the end
479  if(protType == ImageProtocol::PROTOCOL_UDP) {
480  receiveNetworkData(false);
481  }
482 
483  if(protocol->transferComplete()) {
484  return ALL_TRANSFERRED;
485  } else {
486  return PARTIAL_TRANSFER;
487  }
488 }
489 
490 bool ImageTransfer::Pimpl::receiveImagePair(ImagePair& imagePair) {
491  int validRows = 0;
492  bool complete = false;
493 
494  std::chrono::steady_clock::time_point startTime = std::chrono::steady_clock::now();
495  while(!complete) {
496  if(!receivePartialImagePair(imagePair, validRows, complete)) {
497  return false;
498  }
499 
500  unsigned int time = static_cast<unsigned int>(std::chrono::duration_cast<std::chrono::milliseconds>(
501  std::chrono::steady_clock::now() - startTime).count());
502  if(time > 1000) {
503  return false;
504  }
505  }
506 
507  return true;
508 }
509 
510 bool ImageTransfer::Pimpl::receivePartialImagePair(ImagePair& imagePair,
511  int& validRows, bool& complete) {
512  unique_lock<recursive_mutex> lock(receiveMutex);
513 
514  // Try to receive further image data if needed
515  bool block = true;
516  while(!protocol->imagesReceived() && receiveNetworkData(block)) {
517  block = false;
518  }
519 
520  // Get received image
521  return protocol->getPartiallyReceivedImagePair(imagePair, validRows, complete);
522 }
523 
524 bool ImageTransfer::Pimpl::receiveNetworkData(bool block) {
525  unique_lock<recursive_mutex> lock = block ?
526  unique_lock<recursive_mutex>(receiveMutex) : unique_lock<recursive_mutex>(receiveMutex, std::try_to_lock);
527 
528  if(clientSocket == INVALID_SOCKET) {
529  return false; // Not connected
530  }
531 
532  // First send control messages if necessary
533  sendPendingControlMessages();
534 
535  if(!lock.owns_lock()) {
536  // Waiting for the lock would block this call
537  return false;
538  }
539 
540  // Test if the socket has data available
541  if(!block && !selectSocket(true, false)) {
542  return 0;
543  }
544 
545  int maxLength = 0;
546  char* buffer = reinterpret_cast<char*>(protocol->getNextReceiveBuffer(maxLength));
547 
548  // Receive data
549  sockaddr_in fromAddress;
550  socklen_t fromSize = sizeof(fromAddress);
551 
552  int bytesReceived = recvfrom(clientSocket, buffer, maxLength,
553  0, reinterpret_cast<sockaddr*>(&fromAddress), &fromSize);
554 
555  if(bytesReceived == 0 || (protType == ImageProtocol::PROTOCOL_TCP && bytesReceived < 0 && errno == WSAECONNRESET)) {
556  // Connection closed
557  disconnect();
558  } else if(bytesReceived < 0 && errno != EWOULDBLOCK && errno != EINTR &&
559  errno != ETIMEDOUT && errno != WSA_IO_PENDING && errno != WSAECONNRESET) {
560  TransferException ex("Error reading from socket: " + string(strerror(errno)));
561  throw ex;
562  } else if(bytesReceived > 0) {
563  protocol->processReceivedMessage(bytesReceived);
564  if(protocol->newClientConnected()) {
565  // We have just established a new connection
566  memcpy(&remoteAddress, &fromAddress, sizeof(remoteAddress));
567  }
568  }
569 
570  return bytesReceived > 0;
571 }
572 
573 void ImageTransfer::Pimpl::disconnect() {
574  // We just need to forget the remote address in order to
575  // disconnect
576  unique_lock<recursive_mutex> recvLock(receiveMutex);
577  unique_lock<recursive_mutex> sendLock(sendMutex);
578 
579  if(clientSocket != INVALID_SOCKET && protType == ImageProtocol::PROTOCOL_TCP) {
580  closeSocket(clientSocket);
581  }
582  memset(&remoteAddress, 0, sizeof(remoteAddress));
583 }
584 
585 bool ImageTransfer::Pimpl::isConnected() const {
586  unique_lock<recursive_mutex> lock(const_cast<recursive_mutex&>(sendMutex)); //either mutex will work
587 
588  return remoteAddress.sin_family == AF_INET && protocol->isConnected();
589 }
590 
591 bool ImageTransfer::Pimpl::sendNetworkMessage(const unsigned char* msg, int length) {
592  int written = 0;
593  if(protType == ImageProtocol::PROTOCOL_UDP) {
594  sockaddr_in destAddr;
595  SOCKET destSocket;
596  {
597  unique_lock<recursive_mutex> lock(sendMutex);
598  destAddr = remoteAddress;
599  destSocket = clientSocket;
600  }
601 
602  if(destAddr.sin_family != AF_INET) {
603  return false; // Not connected
604  }
605 
606  written = sendto(destSocket, reinterpret_cast<const char*>(msg), length, 0,
607  reinterpret_cast<sockaddr*>(&destAddr), sizeof(destAddr));
608  } else {
609  SOCKET destSocket;
610  {
611  unique_lock<recursive_mutex> lock(sendMutex);
612  destSocket = clientSocket;
613  }
614  written = send(destSocket, reinterpret_cast<const char*>(msg), length, 0);
615  }
616 
617  unsigned long sendError = errno;
618 
619  if(written < 0) {
620  if(sendError == EAGAIN || sendError == EWOULDBLOCK || sendError == ETIMEDOUT) {
621  // The socket is not yet ready for a new transfer
622  return false;
623  } else if(sendError == EPIPE) {
624  // The connection has been closed
625  disconnect();
626  return false;
627  } else {
628  TransferException ex("Error sending network packet: " + string(strerror(errno)));
629  throw ex;
630  }
631  } else if(written != length) {
632  if(protType == ImageProtocol::PROTOCOL_UDP) {
633  // The message has been transmitted partially
634  throw TransferException("Unable to transmit complete UDP message");
635  } else {
636  // For TCP we can transmit the remaining data later
637  currentMsgOffset += written;
638  return false;
639  }
640  } else {
641  return true;
642  }
643 }
644 
645 void ImageTransfer::Pimpl::sendPendingControlMessages() {
646  const unsigned char* controlMsgData = nullptr;
647  int controlMsgLen = 0;
648 
649  while(true) {
650  unique_lock<recursive_mutex> lock(sendMutex);
651  if(remoteAddress.sin_family != AF_INET) {
652  return;
653  }
654 
655  controlMsgData = protocol->getNextControlMessage(controlMsgLen);
656 
657  if(controlMsgData != nullptr) {
658  sendNetworkMessage(controlMsgData, controlMsgLen);
659  } else {
660  break;
661  }
662  }
663 }
664 
665 int ImageTransfer::Pimpl::getNumDroppedFrames() const {
666  return protocol->getNumDroppedFrames();
667 }
668 
669 bool ImageTransfer::Pimpl::selectSocket(bool read, bool wait) {
670  SOCKET sock;
671  {
672  unique_lock<recursive_mutex> lock(sendMutex); // Either mutex will do
673  sock = clientSocket;
674  }
675 
676  fd_set fds;
677  struct timeval tv;
678  FD_ZERO(&fds);
679  FD_SET(sock, &fds);
680  tv.tv_sec = 0;
681  if(wait) {
682  tv.tv_usec = 100000;
683  } else {
684  tv.tv_usec = 0;
685  }
686 
687  if(select(sock+1, (read ? &fds : nullptr), (!read ? &fds : nullptr), nullptr, &tv) <= 0) {
688  // The socket is currently not ready
689  return false;
690  } else {
691  return true;
692  }
693 }
694 
695 void ImageTransfer::Pimpl::closeSocket(SOCKET& socket) {
696  shutdown(socket, SHUT_WR);
697 
698  // Receive remaining data
699  char buffer[1024];
700  for(int i=0; i<3; i++) {
701  int received = recv(clientSocket, buffer, sizeof(buffer), 0);
702  if(received <= 0) {
703  break;
704  }
705  }
706 
707  close(socket);
708  socket = INVALID_SOCKET;
709 }
bool isConnected() const
Returns true if a remote connection is established.
No network connection has been established.
Definition: imagetransfer.h:52
A lightweight protocol for transferring image pairs.
Definition: imageprotocol.h:36
int getNumDroppedFrames() const
Returns the number of frames that have been dropped since connecting to the current remote host...
bool receivePartialImagePair(ImagePair &imagePair, int &validRows, bool &complete)
Returns the received image pair, even if it is not yet complete.
bool tryAccept()
Tries to accept a client connection.
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
std::string getRemoteAddress() const
Returns the address of the remote host.
The image pair has been transferred completely.
Definition: imagetransfer.h:39
ProtocolType
Supported network protocols.
Definition: imageprotocol.h:39
TransferStatus
The result of a partial image transfer.
Definition: imagetransfer.h:37
A set of two images, which are usually the left camera image and the disparity map.
Definition: imagepair.h:31
void disconnect()
Terminates the current connection.
The operation would block and blocking as been disabled.
Definition: imagetransfer.h:49
void setRawValidBytes(int validBytes)
Updates the number of valid bytes in a partial raw transmission.
ImageTransfer(const char *address, const char *service="7681", ImageProtocol::ProtocolType protType=ImageProtocol::PROTOCOL_UDP, bool server=false, int bufferSize=1048576, int maxUdpPacketSize=1472)
Creates a new transfer object by manually specifying the target address.
Aggregates information about a discovered device.
Definition: deviceinfo.h:23
bool receiveImagePair(ImagePair &imagePair)
Waits for and receives a new image pair.
There is currently no more data that could be transmitted.
Definition: imagetransfer.h:46
The connection oriented TCP transport protocol.
Definition: imageprotocol.h:41
TransferStatus transferData()
Performs a partial (or full) image transmission.
Nerian Vision Technologies