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()) {
360 setsockopt(clientSocket, IPPROTO_TCP, TCP_CORK, (
char *) &flag,
sizeof(
int));
365 if(currentMsg ==
nullptr) {
366 currentMsgOffset = 0;
367 currentMsg = protocol->getTransferMessage(currentMsgLen);
369 if(currentMsg ==
nullptr) {
370 if(protocol->transferComplete()) {
379 bool dataTransferred = (currentMsg !=
nullptr);
380 while(currentMsg !=
nullptr) {
381 int writing = (int)(currentMsgLen - currentMsgOffset);
383 if(sendNetworkMessage(¤tMsg[currentMsgOffset], writing)) {
385 currentMsgOffset = 0;
386 currentMsg = protocol->getTransferMessage(currentMsgLen);
396 setsockopt(clientSocket, IPPROTO_TCP, TCP_CORK, (
char *) &flag,
sizeof(
int));
400 setsockopt(clientSocket, IPPROTO_TCP, TCP_NODELAY, (
char *) &flag,
sizeof(
int));
402 setsockopt(clientSocket, IPPROTO_TCP, TCP_NODELAY, (
char *) &flag,
sizeof(
int));
408 receiveNetworkData(
false);
411 if(protocol->transferComplete()) {
418 bool ImageTransfer::Pimpl::receiveImageSet(
ImageSet& imageSet) {
420 bool complete =
false;
422 std::chrono::steady_clock::time_point startTime = std::chrono::steady_clock::now();
428 unsigned int time =
static_cast<unsigned int>(std::chrono::duration_cast<std::chrono::milliseconds>(
429 std::chrono::steady_clock::now() - startTime).count());
438 bool ImageTransfer::Pimpl::receivePartialImageSet(
ImageSet& imageSet,
439 int& validRows,
bool& complete) {
440 unique_lock<recursive_mutex> lock(receiveMutex);
444 while(!protocol->imagesReceived() && receiveNetworkData(block)) {
449 return protocol->getPartiallyReceivedImageSet(imageSet, validRows, complete);
452 bool ImageTransfer::Pimpl::receiveNetworkData(
bool block) {
453 unique_lock<recursive_mutex> lock = block ?
454 unique_lock<recursive_mutex>(receiveMutex) : unique_lock<recursive_mutex>(receiveMutex, std::try_to_lock);
456 if(clientSocket == INVALID_SOCKET) {
461 sendPendingControlMessages();
463 if(!lock.owns_lock()) {
469 if(!block && !selectSocket(
true,
false)) {
474 char* buffer =
reinterpret_cast<char*
>(protocol->getNextReceiveBuffer(maxLength));
477 sockaddr_in fromAddress;
478 socklen_t fromSize =
sizeof(fromAddress);
480 int bytesReceived = recvfrom(clientSocket, buffer, maxLength,
481 0, reinterpret_cast<sockaddr*>(&fromAddress), &fromSize);
486 }
else if(bytesReceived < 0 && errno != EWOULDBLOCK && errno != EINTR &&
487 errno != ETIMEDOUT && errno != WSA_IO_PENDING && errno != WSAECONNRESET) {
490 }
else if(bytesReceived > 0) {
491 protocol->processReceivedMessage(bytesReceived);
492 if(protocol->newClientConnected()) {
494 memcpy(&remoteAddress, &fromAddress,
sizeof(remoteAddress));
498 return bytesReceived > 0;
501 void ImageTransfer::Pimpl::disconnect() {
504 unique_lock<recursive_mutex> recvLock(receiveMutex);
505 unique_lock<recursive_mutex> sendLock(sendMutex);
508 Networking::closeSocket(clientSocket);
510 memset(&remoteAddress, 0,
sizeof(remoteAddress));
513 bool ImageTransfer::Pimpl::isConnected()
const {
514 unique_lock<recursive_mutex> lock(const_cast<recursive_mutex&>(sendMutex));
516 return remoteAddress.sin_family == AF_INET && protocol->isConnected();
519 bool ImageTransfer::Pimpl::sendNetworkMessage(
const unsigned char* msg,
int length) {
522 sockaddr_in destAddr;
525 unique_lock<recursive_mutex> lock(sendMutex);
526 destAddr = remoteAddress;
527 destSocket = clientSocket;
530 if(destAddr.sin_family != AF_INET) {
534 written = sendto(destSocket, reinterpret_cast<const char*>(msg), length, 0,
535 reinterpret_cast<sockaddr*>(&destAddr),
sizeof(destAddr));
539 unique_lock<recursive_mutex> lock(sendMutex);
540 destSocket = clientSocket;
542 written = send(destSocket, reinterpret_cast<const char*>(msg), length, 0);
545 unsigned long sendError = errno;
548 if(sendError == EAGAIN || sendError == EWOULDBLOCK || sendError == ETIMEDOUT) {
551 }
else if(sendError == EPIPE) {
556 TransferException ex(
"Error sending network packet: " +
string(strerror(sendError)));
559 }
else if(written != length) {
565 currentMsgOffset += written;
573 void ImageTransfer::Pimpl::sendPendingControlMessages() {
574 const unsigned char* controlMsgData =
nullptr;
575 int controlMsgLen = 0;
578 unique_lock<recursive_mutex> lock(sendMutex);
579 if(remoteAddress.sin_family != AF_INET) {
583 controlMsgData = protocol->getNextControlMessage(controlMsgLen);
585 if(controlMsgData !=
nullptr) {
586 sendNetworkMessage(controlMsgData, controlMsgLen);
593 int ImageTransfer::Pimpl::getNumDroppedFrames()
const {
594 return protocol->getNumDroppedFrames();
597 bool ImageTransfer::Pimpl::selectSocket(
bool read,
bool wait) {
600 unique_lock<recursive_mutex> lock(sendMutex);
615 if(select(sock+1, (read ? &fds :
nullptr), (!read ? &fds :
nullptr),
nullptr, &tv) <= 0) {
621 constexpr
int timeoutMillisec = 100;
625 if (poll(&pfd, 1, wait ? timeoutMillisec: 0) <= 0) {
634 std::string ImageTransfer::statusReport() {
635 return pimpl->statusReport();
637 std::string ImageTransfer::Pimpl::statusReport() {
638 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.