22 #include "visiontransfer/imagetransfer.h" 23 #include "visiontransfer/exceptions.h" 24 #include "visiontransfer/datablockprotocol.h" 25 #include "visiontransfer/networking.h" 35 class ImageTransfer::Pimpl {
38 bool server,
int bufferSize,
int maxUdpPacketSize);
42 void setRawTransferData(
const ImageSet& metaData,
const std::vector<unsigned char*>& rawData,
43 int firstTileWidth = 0,
int secondTileWidth = 0,
int validBytes = 0x7FFFFFFF);
44 void setRawValidBytes(
const std::vector<int>& validBytes);
45 void setTransferImageSet(
const ImageSet& imageSet);
46 TransferStatus transferData();
47 bool receiveImageSet(
ImageSet& imageSet);
48 bool receivePartialImageSet(
ImageSet& imageSet,
int& validRows,
bool& complete);
49 int getNumDroppedFrames()
const;
50 bool isConnected()
const;
52 std::string getRemoteAddress()
const;
55 std::string statusReport();
64 std::recursive_mutex receiveMutex;
65 std::recursive_mutex sendMutex;
69 SOCKET tcpServerSocket;
70 sockaddr_in remoteAddress;
73 std::unique_ptr<ImageProtocol> protocol;
78 const unsigned char* currentMsg;
81 void setSocketOptions();
84 void initTcpServer(
const addrinfo* addressInfo);
85 void initTcpClient(
const addrinfo* addressInfo);
86 void initUdp(
const addrinfo* addressInfo);
89 bool receiveNetworkData(
bool block);
92 bool sendNetworkMessage(
const unsigned char* msg,
int length);
93 void sendPendingControlMessages();
95 bool selectSocket(
bool read,
bool wait);
100 ImageTransfer::ImageTransfer(
const char* address,
const char* service,
102 pimpl(new Pimpl(address, service, protType, server, bufferSize, maxUdpPacketSize)) {
107 pimpl(new Pimpl(device.getIpAddress().c_str(),
"7681", static_cast<
ImageProtocol::ProtocolType>(device.getNetworkProtocol()),
108 false, bufferSize, maxUdpPacketSize)) {
112 ImageTransfer::~ImageTransfer() {
117 int firstTileWidth,
int secondTileWidth,
int validBytes) {
118 pimpl->setRawTransferData(metaData, rawData, firstTileWidth, secondTileWidth, validBytes);
122 pimpl->setRawValidBytes(validBytes);
126 pimpl->setTransferImageSet(imageSet);
130 return pimpl->transferData();
134 return pimpl->receiveImageSet(imageSet);
138 return pimpl->receivePartialImageSet(imageSet, validRows, complete);
142 return pimpl->getNumDroppedFrames();
146 return pimpl->isConnected();
154 return pimpl->getRemoteAddress();
158 return pimpl->tryAccept();
162 ImageTransfer::Pimpl::Pimpl(
const char* address,
const char* service,
164 bufferSize,
int maxUdpPacketSize)
165 : protType(protType), isServer(server), bufferSize(bufferSize),
166 maxUdpPacketSize(maxUdpPacketSize),
167 clientSocket(INVALID_SOCKET), tcpServerSocket(INVALID_SOCKET),
168 currentMsgLen(0), currentMsgOffset(0), currentMsg(
nullptr) {
170 Networking::initNetworking();
173 signal(SIGPIPE, SIG_IGN);
176 memset(&remoteAddress, 0,
sizeof(remoteAddress));
179 if(address ==
nullptr ||
string(address) ==
"") {
183 addrinfo* addressInfo = Networking::resolveAddress(address, service);
187 initUdp(addressInfo);
189 initTcpServer(addressInfo);
191 initTcpClient(addressInfo);
194 freeaddrinfo(addressInfo);
198 if(addressInfo !=
nullptr) {
199 freeaddrinfo(addressInfo);
203 ImageTransfer::Pimpl::~Pimpl() {
204 if(clientSocket != INVALID_SOCKET) {
205 Networking::closeSocket(clientSocket);
207 if(tcpServerSocket != INVALID_SOCKET) {
208 Networking::closeSocket(tcpServerSocket);
212 void ImageTransfer::Pimpl::initTcpClient(
const addrinfo* addressInfo) {
214 clientSocket = Networking::connectTcpSocket(addressInfo);
215 memcpy(&remoteAddress, addressInfo->ai_addr,
sizeof(remoteAddress));
221 void ImageTransfer::Pimpl::initTcpServer(
const addrinfo* addressInfo) {
225 tcpServerSocket = ::socket(addressInfo->ai_family, addressInfo->ai_socktype,
226 addressInfo->ai_protocol);
227 if (tcpServerSocket == INVALID_SOCKET) {
233 Networking::enableReuseAddress(tcpServerSocket,
true);
236 Networking::bindSocket(tcpServerSocket, addressInfo);
237 clientSocket = INVALID_SOCKET;
240 Networking::setSocketBlocking(tcpServerSocket,
false);
243 listen(tcpServerSocket, 1);
246 void ImageTransfer::Pimpl::initUdp(
const addrinfo* addressInfo) {
249 clientSocket = socket(AF_INET, SOCK_DGRAM, 0);
250 if(clientSocket == INVALID_SOCKET) {
251 TransferException ex(
"Error creating receive socket: " +
string(strerror(errno)));
256 Networking::enableReuseAddress(clientSocket,
true);
259 if(isServer && addressInfo !=
nullptr) {
260 Networking::bindSocket(clientSocket, addressInfo);
264 memcpy(&remoteAddress, addressInfo->ai_addr,
sizeof(remoteAddress));
271 bool ImageTransfer::Pimpl::tryAccept() {
276 unique_lock<recursive_mutex> recvLock(receiveMutex);
277 unique_lock<recursive_mutex> sendLock(sendMutex);
280 SOCKET newSocket = Networking::acceptConnection(tcpServerSocket, remoteAddress);
281 if(newSocket == INVALID_SOCKET) {
286 if(clientSocket != INVALID_SOCKET) {
287 Networking::closeSocket(clientSocket);
289 clientSocket = newSocket;
295 protocol->resetTransfer();
296 protocol->resetReception();
297 currentMsg =
nullptr;
302 std::string ImageTransfer::Pimpl::getRemoteAddress()
const {
303 unique_lock<recursive_mutex> lock(const_cast<recursive_mutex&>(sendMutex));
305 if(remoteAddress.sin_family != AF_INET) {
310 snprintf(strPort,
sizeof(strPort),
":%d", remoteAddress.sin_port);
312 return string(inet_ntoa(remoteAddress.sin_addr)) + strPort;
315 void ImageTransfer::Pimpl::setSocketOptions() {
318 setsockopt(clientSocket, SOL_SOCKET, SO_RCVBUF, reinterpret_cast<char*>(&bufferSize),
sizeof(bufferSize));
319 setsockopt(clientSocket, SOL_SOCKET, SO_SNDBUF, reinterpret_cast<char*>(&bufferSize),
sizeof(bufferSize));
322 Networking::setSocketTimeout(clientSocket, 500);
323 Networking::setSocketBlocking(clientSocket,
true);
326 void ImageTransfer::Pimpl::setRawTransferData(
const ImageSet& metaData,
327 const std::vector<unsigned char*>& rawDataVec,
int firstTileWidth,
int secondTileWidth,
int validBytes) {
328 unique_lock<recursive_mutex> sendLock(sendMutex);
329 protocol->setRawTransferData(metaData, rawDataVec, firstTileWidth, secondTileWidth, validBytes);
330 currentMsg =
nullptr;
333 void ImageTransfer::Pimpl::setRawValidBytes(
const std::vector<int>& validBytes) {
334 unique_lock<recursive_mutex> sendLock(sendMutex);
335 protocol->setRawValidBytes(validBytes);
338 void ImageTransfer::Pimpl::setTransferImageSet(
const ImageSet& imageSet) {
339 unique_lock<recursive_mutex> sendLock(sendMutex);
340 protocol->setTransferImageSet(imageSet);
341 currentMsg =
nullptr;
345 unique_lock<recursive_mutex> lock(sendMutex);
349 receiveNetworkData(
false);
352 if(remoteAddress.sin_family != AF_INET || !protocol->isConnected()) {
357 if(currentMsg ==
nullptr) {
358 currentMsgOffset = 0;
359 currentMsg = protocol->getTransferMessage(currentMsgLen);
361 if(currentMsg ==
nullptr) {
362 if(protocol->transferComplete()) {
371 bool dataTransferred = (currentMsg !=
nullptr);
372 while(currentMsg !=
nullptr) {
373 int writing = (int)(currentMsgLen - currentMsgOffset);
375 if(sendNetworkMessage(¤tMsg[currentMsgOffset], writing)) {
377 currentMsgOffset = 0;
378 currentMsg = protocol->getTransferMessage(currentMsgLen);
387 setsockopt(clientSocket, IPPROTO_TCP, TCP_NODELAY, (
char *) &flag,
sizeof(
int));
389 setsockopt(clientSocket, IPPROTO_TCP, TCP_NODELAY, (
char *) &flag,
sizeof(
int));
394 receiveNetworkData(
false);
397 if(protocol->transferComplete()) {
404 bool ImageTransfer::Pimpl::receiveImageSet(
ImageSet& imageSet) {
406 bool complete =
false;
408 std::chrono::steady_clock::time_point startTime = std::chrono::steady_clock::now();
414 unsigned int time =
static_cast<unsigned int>(std::chrono::duration_cast<std::chrono::milliseconds>(
415 std::chrono::steady_clock::now() - startTime).count());
424 bool ImageTransfer::Pimpl::receivePartialImageSet(
ImageSet& imageSet,
425 int& validRows,
bool& complete) {
426 unique_lock<recursive_mutex> lock(receiveMutex);
430 while(!protocol->imagesReceived() && receiveNetworkData(block)) {
435 return protocol->getPartiallyReceivedImageSet(imageSet, validRows, complete);
438 bool ImageTransfer::Pimpl::receiveNetworkData(
bool block) {
439 unique_lock<recursive_mutex> lock = block ?
440 unique_lock<recursive_mutex>(receiveMutex) : unique_lock<recursive_mutex>(receiveMutex, std::try_to_lock);
442 if(clientSocket == INVALID_SOCKET) {
447 sendPendingControlMessages();
449 if(!lock.owns_lock()) {
455 if(!block && !selectSocket(
true,
false)) {
460 char* buffer =
reinterpret_cast<char*
>(protocol->getNextReceiveBuffer(maxLength));
463 sockaddr_in fromAddress;
464 socklen_t fromSize =
sizeof(fromAddress);
466 int bytesReceived = recvfrom(clientSocket, buffer, maxLength,
467 0, reinterpret_cast<sockaddr*>(&fromAddress), &fromSize);
474 }
else if(bytesReceived < 0 && errno != EWOULDBLOCK && errno != EINTR &&
475 errno != ETIMEDOUT && errno != WSA_IO_PENDING && errno != WSAECONNRESET) {
478 }
else if(bytesReceived > 0) {
479 protocol->processReceivedMessage(bytesReceived);
480 if(protocol->newClientConnected()) {
482 memcpy(&remoteAddress, &fromAddress,
sizeof(remoteAddress));
486 return bytesReceived > 0;
489 void ImageTransfer::Pimpl::disconnect() {
492 unique_lock<recursive_mutex> recvLock(receiveMutex);
493 unique_lock<recursive_mutex> sendLock(sendMutex);
496 Networking::closeSocket(clientSocket);
498 memset(&remoteAddress, 0,
sizeof(remoteAddress));
501 bool ImageTransfer::Pimpl::isConnected()
const {
502 unique_lock<recursive_mutex> lock(const_cast<recursive_mutex&>(sendMutex));
504 return remoteAddress.sin_family == AF_INET && protocol->isConnected();
507 bool ImageTransfer::Pimpl::sendNetworkMessage(
const unsigned char* msg,
int length) {
510 sockaddr_in destAddr;
513 unique_lock<recursive_mutex> lock(sendMutex);
514 destAddr = remoteAddress;
515 destSocket = clientSocket;
518 if(destAddr.sin_family != AF_INET) {
522 written = sendto(destSocket, reinterpret_cast<const char*>(msg), length, 0,
523 reinterpret_cast<sockaddr*>(&destAddr),
sizeof(destAddr));
527 unique_lock<recursive_mutex> lock(sendMutex);
528 destSocket = clientSocket;
530 written = send(destSocket, reinterpret_cast<const char*>(msg), length, 0);
533 unsigned long sendError = errno;
536 if(sendError == EAGAIN || sendError == EWOULDBLOCK || sendError == ETIMEDOUT) {
539 }
else if(sendError == EPIPE) {
544 TransferException ex(
"Error sending network packet: " +
string(strerror(sendError)));
547 }
else if(written != length) {
553 currentMsgOffset += written;
561 void ImageTransfer::Pimpl::sendPendingControlMessages() {
562 const unsigned char* controlMsgData =
nullptr;
563 int controlMsgLen = 0;
566 unique_lock<recursive_mutex> lock(sendMutex);
567 if(remoteAddress.sin_family != AF_INET) {
571 controlMsgData = protocol->getNextControlMessage(controlMsgLen);
573 if(controlMsgData !=
nullptr) {
575 sendNetworkMessage(controlMsgData, controlMsgLen);
582 int ImageTransfer::Pimpl::getNumDroppedFrames()
const {
583 return protocol->getNumDroppedFrames();
586 bool ImageTransfer::Pimpl::selectSocket(
bool read,
bool wait) {
589 unique_lock<recursive_mutex> lock(sendMutex);
604 if(select(sock+1, (read ? &fds :
nullptr), (!read ? &fds :
nullptr),
nullptr, &tv) <= 0) {
610 constexpr
int timeoutMillisec = 100;
614 if (poll(&pfd, 1, wait ? timeoutMillisec: 0) <= 0) {
623 std::string ImageTransfer::statusReport() {
624 return pimpl->statusReport();
626 std::string ImageTransfer::Pimpl::statusReport() {
627 return protocol->statusReport();
std::string getRemoteAddress() const
Returns the address of the remote host.
int getNumDroppedFrames() const
Returns the number of frames that have been dropped since connecting to the current remote host...
bool receivePartialImageSet(ImageSet &imageSet, int &validRows, bool &complete)
Returns the received image set, even if it is not yet complete.
The operation would block and blocking as been disabled.
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.
The connection-less UDP transport protocol.
bool tryAccept()
Tries to accept a client connection.
void disconnect()
Terminates the current connection.
void setRawValidBytes(const std::vector< int > &validBytes)
Updates the number of valid bytes in a partial raw transmission.
bool receiveImageSet(ImageSet &imageSet)
Waits for and receives a new image set.
A lightweight protocol for transferring image sets.
No network connection has been established.
TransferStatus transferData()
Performs a partial (or full) image transmission.
ProtocolType
Supported network protocols.
bool isConnected() const
Returns true if a remote connection is established.
Aggregates information about a discovered device.
There is currently no more data that could be transmitted.
The image set has been transferred completely.
A set of one to three images, but usually two (the left camera image and the disparity map)...
Exception class that is used for all transfer exceptions.
void setTransferImageSet(const ImageSet &imageSet)
Sets a new image set that shall be transmitted.
void setRawTransferData(const ImageSet &metaData, const std::vector< unsigned char *> &rawData, int firstTileWidth=0, int secondTileWidth=0, int validBytes=0x7FFFFFFF)
Sets the raw pixel data for a partial image transmission.
The connection oriented TCP transport protocol.
TransferStatus
The result of a partial image transfer.