22 #include "visiontransfer/imagetransfer.h" 23 #include "visiontransfer/exceptions.h" 24 #include "visiontransfer/datablockprotocol.h" 29 #define snprintf _snprintf_s 35 #define _WIN32_WINNT 0x501 37 #define _WINSOCK_DEPRECATED_NO_WARNINGS 58 #define EWOULDBLOCK WSAEWOULDBLOCK 59 #define ECONNRESET WSAECONNRESET 60 #define ETIMEDOUT WSAETIMEDOUT 61 #define MSG_DONTWAIT 0 63 #define close closesocket 68 #define errno WSAGetLastError() 69 #define strerror win_strerror 71 std::string win_strerror(
unsigned long error) {
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";
80 snprintf(buffer,
sizeof(buffer),
"%s (%lu)", str, error);
82 return std::string(buffer);
87 #include <arpa/inet.h> 88 #include <netinet/tcp.h> 89 #include <sys/types.h> 90 #include <sys/socket.h> 92 #include <netinet/in.h> 99 #define INVALID_SOCKET -1 102 #define WSA_IO_PENDING 0 109 class ImageTransfer::Pimpl {
111 Pimpl(OperationMode mode,
const char* remoteAddress,
const char* remoteService,
112 const char* localAddress,
const char* localService,
int bufferSize);
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);
124 bool isClientConnected()
const;
126 std::string getClientAddress()
const;
129 static constexpr
int UDP_BUFFERS = 256;
130 static constexpr
int TCP_BUFFER_SIZE = 0xFFFF;
142 sockaddr_in clientAddress;
145 sockaddr_in udpAddress;
148 std::unique_ptr<ImageProtocol> protocol;
152 int currentMsgOffset;
153 const unsigned char* currentMsg;
159 bool receptionFailed;
161 bool socketIsBlocking;
164 void setSocketOptions();
167 void initTcpClient(
const addrinfo& remoteAddressInfo,
const addrinfo& localAddressInfo);
168 void initTcpServer(
const addrinfo& localAddressInfo);
169 void initUdp(
const addrinfo& remoteAddressInfo,
const addrinfo& localAddressInfo);
172 int receiveSingleNetworkMessages(
bool block);
173 bool receiveNetworkData(
bool block);
175 void win32SetBlocking(
bool block);
181 const char* remoteService,
const char* localAddress,
const char* localService,
int bufferSize):
182 pimpl(new Pimpl(mode, remoteAddress, remoteService, localAddress, localService, bufferSize)) {
186 ImageTransfer::~ImageTransfer() {
191 int secondTileWidth,
int validBytes) {
192 pimpl->setRawTransferData(metaData, rawData, secondTileWidth, validBytes);
196 pimpl->setRawValidBytes(validBytes);
200 pimpl->setTransferImagePair(imagePair);
204 return pimpl->transferData(block);
208 return pimpl->receiveImagePair(imagePair, block);
212 return pimpl->receivePartialImagePair(imagePair, validRows, complete, block);
216 return pimpl->tryAccept();
220 return pimpl->isClientConnected();
228 return pimpl->getClientAddress();
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) {
241 if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
246 signal(SIGPIPE, SIG_IGN);
250 if(remoteAddress ==
nullptr ||
string(remoteAddress) ==
"") {
251 remoteAddress =
"0.0.0.0";
253 if(localAddress ==
nullptr ||
string(localAddress) ==
"") {
254 localAddress =
"0.0.0.0";
259 memset(&hints, 0,
sizeof(hints));
260 hints.ai_family = AF_INET;
263 hints.ai_protocol = 0;
265 addrinfo* remoteAddressInfo =
nullptr;
266 if(getaddrinfo(remoteAddress, remoteService, &hints, &remoteAddressInfo) != 0 || remoteAddressInfo ==
nullptr) {
267 TransferException ex(
"Error resolving remote address: " +
string(strerror(errno)));
271 addrinfo* localAddressInfo =
nullptr;
272 if(getaddrinfo(localAddress, localService, &hints, &localAddressInfo) != 0 || localAddressInfo ==
nullptr) {
273 TransferException ex(
"Error resolving local address: " +
string(strerror(errno)));
280 case TCP_CLIENT: initTcpClient(*remoteAddressInfo, *localAddressInfo);
break;
281 case TCP_SERVER: initTcpServer(*localAddressInfo);
break;
282 case UDP: initUdp(*remoteAddressInfo, *localAddressInfo);
break;
286 freeaddrinfo(remoteAddressInfo);
287 freeaddrinfo(localAddressInfo);
291 freeaddrinfo(remoteAddressInfo);
292 freeaddrinfo(localAddressInfo);
295 ImageTransfer::Pimpl::~Pimpl() {
296 if(socket != INVALID_SOCKET) {
300 if(serverSocket != INVALID_SOCKET) {
305 void ImageTransfer::Pimpl::initTcpClient(
const addrinfo& remoteAddressInfo,
const addrinfo& localAddressInfo) {
309 socket = ::socket(remoteAddressInfo.ai_family, remoteAddressInfo.ai_socktype,
310 remoteAddressInfo.ai_protocol);
311 if(socket == INVALID_SOCKET) {
318 setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&enable),
sizeof(
int));
321 if (::bind(socket, localAddressInfo.ai_addr, static_cast<int>(localAddressInfo.ai_addrlen)) < 0) {
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)));
336 void ImageTransfer::Pimpl::initTcpServer(
const addrinfo& localAddressInfo) {
340 serverSocket = ::socket(localAddressInfo.ai_family, localAddressInfo.ai_socktype,
341 localAddressInfo.ai_protocol);
342 if (serverSocket == INVALID_SOCKET) {
349 setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&enable),
sizeof(
int));
352 if (::bind(serverSocket, localAddressInfo.ai_addr, static_cast<int>(localAddressInfo.ai_addrlen)) < 0) {
359 unsigned long on = 1;
360 ioctlsocket(serverSocket, FIONBIO, &on);
362 fcntl(serverSocket, F_SETFL, O_NONBLOCK);
366 listen(serverSocket, 1);
369 void ImageTransfer::Pimpl::initUdp(
const addrinfo& remoteAddressInfo,
const addrinfo& localAddressInfo) {
372 socket = ::socket(localAddressInfo.ai_family, localAddressInfo.ai_socktype,
373 localAddressInfo.ai_protocol);
374 if(socket == INVALID_SOCKET) {
381 setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<char*>(&enable),
sizeof(
int));
384 if (::bind(socket, localAddressInfo.ai_addr, static_cast<int>(localAddressInfo.ai_addrlen)) < 0) {
390 if(remoteAddressInfo.ai_addrlen !=
sizeof(udpAddress)) {
393 memcpy(&udpAddress, remoteAddressInfo.ai_addr,
sizeof(udpAddress));
399 bool ImageTransfer::Pimpl::tryAccept() {
405 socklen_t clientAddressLength =
sizeof(clientAddress);
407 SOCKET newSocket = accept(serverSocket,
408 reinterpret_cast<sockaddr *>(&clientAddress),
409 &clientAddressLength);
411 if(newSocket == INVALID_SOCKET) {
412 if(errno == EWOULDBLOCK || errno == ETIMEDOUT) {
422 if(socket != INVALID_SOCKET) {
431 protocol->resetTransfer();
432 protocol->resetReception();
437 std::string ImageTransfer::Pimpl::getClientAddress()
const {
438 if(socket == INVALID_SOCKET) {
443 snprintf(strPort,
sizeof(strPort),
":%d", clientAddress.sin_port);
445 return string(inet_ntoa(clientAddress.sin_addr)) + strPort;
448 void ImageTransfer::Pimpl::setSocketOptions() {
452 unsigned long on = 0;
453 ioctlsocket(socket, FIONBIO, &on);
455 fcntl(socket, F_SETFL, 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));
467 unsigned int timeout = 1000;
469 struct timeval timeout;
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));
478 unsigned char loop = 0;
479 setsockopt(socket, IPPROTO_IP, IP_MULTICAST_LOOP, reinterpret_cast<char*>(&loop),
sizeof(loop));
482 #ifdef TCP_CONGESTION 485 strcpy(optval,
"westwood");
486 if (setsockopt(socket, IPPROTO_TCP, TCP_CONGESTION, optval, strlen(optval)) < 0) {
488 strcpy(optval,
"reno");
489 setsockopt(socket, IPPROTO_TCP, TCP_CONGESTION, optval, strlen(optval));
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;
501 void ImageTransfer::Pimpl::setRawValidBytes(
int validBytes) {
502 protocol->setRawValidBytes(validBytes);
505 void ImageTransfer::Pimpl::setTransferImagePair(
const ImagePair& imagePair) {
506 protocol->setTransferImagePair(imagePair);
507 currentMsg =
nullptr;
510 void ImageTransfer::Pimpl::win32SetBlocking(
bool block) {
512 if(block != socketIsBlocking) {
514 unsigned long on = block ? 0 : 1;
515 ioctlsocket(socket, FIONBIO, &on);
517 socketIsBlocking = block;
523 if(currentMsg ==
nullptr) {
524 currentMsgOffset = 0;
525 currentMsg = protocol->getTransferMessage(currentMsgLen);
527 if(currentMsg ==
nullptr) {
532 while(currentMsg !=
nullptr) {
533 int writing = (int)(currentMsgLen - currentMsgOffset);
536 win32SetBlocking(block);
541 written = send(socket, reinterpret_cast<const char*>(¤tMsg[currentMsgOffset]), writing,
542 block ? 0 : MSG_DONTWAIT);
545 written = sendto(socket, reinterpret_cast<const char*>(¤tMsg[currentMsgOffset]), writing,
546 block ? 0 : MSG_DONTWAIT, reinterpret_cast<sockaddr*>(&udpAddress),
sizeof(udpAddress));
550 unsigned long sendError = errno;
553 if(!block && (sendError == EAGAIN || sendError == EWOULDBLOCK || sendError == ETIMEDOUT)) {
560 socket = INVALID_SOCKET;
566 }
else if(written != writing) {
572 currentMsgOffset+= written;
578 currentMsg =
nullptr;
582 currentMsg = protocol->getTransferMessage(currentMsgLen);
583 currentMsgOffset = 0;
587 if(mode ==
TCP_SERVER && protocol->transferComplete()) {
590 setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (
char *) &flag,
sizeof(
int));
592 setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (
char *) &flag,
sizeof(
int));
595 if(protocol->transferComplete()) {
602 bool ImageTransfer::Pimpl::receiveImagePair(
ImagePair& imagePair,
bool block) {
604 bool complete =
false;
615 bool ImageTransfer::Pimpl::receivePartialImagePair(
ImagePair& imagePair,
616 int& validRows,
bool& complete,
bool block) {
617 if(receptionFailed) {
619 receptionFailed =
false;
624 while(!protocol->imagesReceived() && receiveNetworkData(block)) {
629 return protocol->getPartiallyReceivedImagePair(imagePair, validRows, complete);
632 int ImageTransfer::Pimpl::receiveSingleNetworkMessages(
bool block) {
634 char* buffer =
reinterpret_cast<char*
>(protocol->getNextReceiveBuffer(maxLength));
636 int bytesReceived = recv(socket, buffer, maxLength,
640 block ? 0 : MSG_DONTWAIT
644 if(bytesReceived > 0) {
645 if(!protocol->processReceivedMessage(bytesReceived)) {
647 receptionFailed =
true;
652 return bytesReceived;
655 bool ImageTransfer::Pimpl::receiveNetworkData(
bool block) {
656 win32SetBlocking(block);
658 int received = receiveSingleNetworkMessages(block);
664 socket = INVALID_SOCKET;
666 }
else if(received < 0) {
667 if(errno == EWOULDBLOCK || errno == EINTR || errno == ETIMEDOUT || errno == WSA_IO_PENDING) {
680 void ImageTransfer::Pimpl::disconnect() {
684 if(socket != INVALID_SOCKET) {
686 socket = INVALID_SOCKET;
690 bool ImageTransfer::Pimpl::isClientConnected()
const {
691 return socket != INVALID_SOCKET;
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.
Using TCP and acting as communication server.
A lightweight protocol for transferring image pairs.
OperationMode
Supported transfer modes.
Using TCP and acting as communication client.
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.
Exception class that is used for all transfer exceptions.
The image pair has been transferred completely.
TransferStatus
The result of a partial image transfer.
A set of two images, which are usually the left camera image and the disparity map.
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.
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.
The connection oriented TCP transport protocol.