18 #ifdef MRPT_OS_WINDOWS 20 #define _WINSOCK_DEPRECATED_NO_WARNINGS 23 #if defined(__BORLANDC__) || defined(_MSC_VER) 24 #pragma comment(lib, "WS2_32.LIB") 28 #define INVALID_SOCKET (-1) 29 #include <sys/socket.h> 33 #include <sys/types.h> 34 #include <sys/ioctl.h> 36 #include <arpa/inet.h> 37 #include <netinet/in.h> 38 #include <netinet/tcp.h> 47 unsigned int CClientTCPSocket::DNS_LOOKUP_TIMEOUT_MS = 3000;
49 CClientTCPSocket::CClientTCPSocket()
53 #ifdef MRPT_OS_WINDOWS 56 WORD wVersionRequested;
59 wVersionRequested = MAKEWORD(2, 0);
61 if (WSAStartup(wVersionRequested, &wsaData))
72 CClientTCPSocket::~CClientTCPSocket()
76 #ifdef MRPT_OS_WINDOWS 83 void CClientTCPSocket::close()
87 #ifdef MRPT_OS_WINDOWS 99 shutdown(m_hSock, SHUT_RDWR);
110 size_t CClientTCPSocket::Read(
void* Buffer,
size_t Count)
114 return readAsync(Buffer, Count);
122 size_t CClientTCPSocket::Write(
const void* Buffer,
size_t Count)
126 return writeAsync(Buffer, Count);
136 Write(str.c_str(), str.size());
142 bool CClientTCPSocket::sendMessage(
const CMessage& outMsg,
const int timeout_ms)
144 uint32_t contentLen, toWrite, written;
149 const char* magic =
"MRPTMessage";
150 toWrite = strlen(magic);
152 written = writeAsync(magic, toWrite, timeout_ms);
153 if (written != toWrite)
return false;
158 toWrite =
sizeof(outMsg.
type);
160 written = writeAsync(&outMsg.
type, toWrite, timeout_ms);
161 if (written != toWrite)
return false;
166 contentLen = outMsg.
content.size();
167 toWrite =
sizeof(contentLen);
169 written = writeAsync(&contentLen, toWrite, timeout_ms);
170 if (written != toWrite)
return false;
175 toWrite = contentLen;
177 written = writeAsync(&outMsg.
content[0], toWrite, timeout_ms);
178 if (written != toWrite)
return false;
186 bool CClientTCPSocket::receiveMessage(
187 CMessage& inMsg,
unsigned int timeoutStart_ms,
188 unsigned int timeoutBetween_ms)
190 uint32_t contentLen, toRead, actRead;
198 actRead = readAsync(magic, toRead, timeoutStart_ms, timeoutBetween_ms);
199 if (actRead != toRead)
return false;
203 if (0 !=
os::_strcmpi(
"MRPTMessage", magic))
return false;
208 toRead =
sizeof(inMsg.
type);
211 readAsync(&inMsg.
type, toRead, timeoutBetween_ms, timeoutBetween_ms);
212 if (actRead != toRead)
return false;
217 toRead =
sizeof(contentLen);
220 readAsync(&contentLen, toRead, timeoutBetween_ms, timeoutBetween_ms);
221 if (actRead != toRead)
return false;
224 inMsg.
content.resize(contentLen);
232 &inMsg.
content[0], toRead, timeoutBetween_ms, timeoutBetween_ms);
233 if (actRead != toRead)
return false;
241 void CClientTCPSocket::connect(
242 const std::string& remotePartAddress,
unsigned short remotePartTCPPort,
243 unsigned int timeout_ms)
251 if (
INVALID_SOCKET == (m_hSock = socket(AF_INET, SOCK_STREAM, 0)))
254 "Error creating new client socket:\n%s",
255 getLastErrorStr().c_str()));
257 struct sockaddr_in otherAddress;
259 otherAddress.sin_family = AF_INET;
260 otherAddress.sin_port = htons(remotePartTCPPort);
265 remotePartAddress, solved_IP, DNS_LOOKUP_TIMEOUT_MS))
267 "DNS lookup failed for '%s'", remotePartAddress.c_str());
270 otherAddress.sin_addr.s_addr = inet_addr(solved_IP.c_str());
271 if (INADDR_NONE == otherAddress.sin_addr.s_addr)
273 "Invalid IP address provided: %s", solved_IP.c_str());
276 #ifdef MRPT_OS_WINDOWS 277 unsigned long non_block_mode = 1;
278 if (ioctlsocket(m_hSock, FIONBIO, &non_block_mode))
279 THROW_EXCEPTION(
"Error entering non-blocking mode with ioctlsocket().");
281 int oldflags = fcntl(m_hSock, F_GETFL, 0);
282 if (oldflags == -1)
THROW_EXCEPTION(
"Error retrieving fcntl() of socket.");
283 oldflags |= O_NONBLOCK;
284 if (-1 == fcntl(m_hSock, F_SETFL, oldflags))
290 m_hSock, (
struct sockaddr*)&otherAddress,
sizeof(otherAddress));
291 #ifdef MRPT_OS_WINDOWS 292 int er = WSAGetLastError();
293 if (
r < 0 && er != WSAEINPROGRESS && er != WSAEWOULDBLOCK)
296 if (
r < 0 && er != EINPROGRESS)
300 "Error connecting to %s:%hu. Error: %s [%d]",
301 remotePartAddress.c_str(), remotePartTCPPort, strerror(er),
308 FD_ZERO(&socket_set);
309 FD_SET(m_hSock, &socket_set);
311 timer.tv_sec = timeout_ms / 1000;
312 timer.tv_usec = 1000 * (timeout_ms % 1000);
314 int sel_ret = select(
319 timeout_ms == 0 ?
nullptr : &timer);
324 "Timeout connecting to '%s:%hu':\n%s",
325 remotePartAddress.c_str(), remotePartTCPPort,
326 getLastErrorStr().c_str()));
330 "Error connecting to '%s:%hu':\n%s", remotePartAddress.c_str(),
331 remotePartTCPPort, getLastErrorStr().c_str()));
335 #ifdef MRPT_OS_WINDOWS 336 int lon =
sizeof(int);
337 getsockopt(m_hSock, SOL_SOCKET, SO_ERROR, (
char*)(&valopt), &
lon);
339 socklen_t
lon =
sizeof(int);
340 getsockopt(m_hSock, SOL_SOCKET, SO_ERROR, (
void*)(&valopt), &
lon);
343 #ifdef MRPT_OS_WINDOWS 347 "Error connecting to %s:%hu. Error: %i.",
348 remotePartAddress.c_str(), remotePartTCPPort, valopt));
353 "Error connecting to %s:%hu. Error: %s.",
354 remotePartAddress.c_str(), remotePartTCPPort,
360 #ifdef MRPT_OS_WINDOWS 362 if (ioctlsocket(m_hSock, FIONBIO, &non_block_mode))
365 oldflags &= ~O_NONBLOCK;
366 if (-1 == fcntl(m_hSock, F_SETFL, oldflags))
371 m_remotePartIP = remotePartAddress;
383 size_t CClientTCPSocket::readAsync(
384 void* Buffer,
const size_t Count,
const int timeoutStart_ms,
385 const int timeoutBetween_ms)
391 size_t remainToRead, alreadyRead = 0;
393 bool timeoutExpired =
false;
395 struct timeval timeoutSelect;
396 struct timeval* ptrTimeout;
401 FD_SET(m_hSock, &sockArr);
404 while (alreadyRead < Count && !timeoutExpired)
407 int curTimeout = alreadyRead == 0 ? timeoutStart_ms : timeoutBetween_ms;
410 ptrTimeout =
nullptr;
413 timeoutSelect.tv_sec = curTimeout / 1000;
414 timeoutSelect.tv_usec = 1000 * (curTimeout % 1000);
415 ptrTimeout = &timeoutSelect;
419 int selRet = ::select(
428 "Error reading from socket: %s", getLastErrorStr().c_str());
433 timeoutExpired =
true;
438 remainToRead = Count - alreadyRead;
442 m_hSock, ((
char*)Buffer) + alreadyRead, (
int)remainToRead, 0);
447 alreadyRead += readNow;
456 if (readNow == 0 && remainToRead != 0)
460 timeoutExpired =
true;
474 size_t CClientTCPSocket::writeAsync(
475 const void* Buffer,
const size_t Count,
const int timeout_ms)
481 size_t remainToWrite, alreadyWritten = 0;
483 bool timeoutExpired =
false;
485 struct timeval timeoutSelect;
486 struct timeval* ptrTimeout;
491 FD_SET(m_hSock, &sockArr);
496 ptrTimeout =
nullptr;
500 timeoutSelect.tv_sec = timeout_ms / 1000;
501 timeoutSelect.tv_usec = 1000 * (timeout_ms % 1000);
502 ptrTimeout = &timeoutSelect;
506 while (alreadyWritten < Count && !timeoutExpired)
509 int selRet = ::select(
518 "Error writing to socket: %s", getLastErrorStr().c_str());
523 timeoutExpired =
true;
530 remainToWrite = Count - alreadyWritten;
534 m_hSock, ((
char*)Buffer) + alreadyWritten, (
int)remainToWrite,
540 alreadyWritten += writtenNow;
546 return alreadyWritten;
554 size_t CClientTCPSocket::getReadPendingBytes()
557 unsigned long ret = 0;
559 #ifdef MRPT_OS_WINDOWS
560 ioctlsocket(m_hSock, FIONREAD, &ret)
562 ioctl(m_hSock, FIONREAD, &ret)
575 int CClientTCPSocket::setTCPNoDelay(
const int& newValue)
577 int length =
sizeof(newValue);
580 m_hSock, IPPROTO_TCP, TCP_NODELAY, (
char*)&newValue,
length);
586 int CClientTCPSocket::getTCPNoDelay()
589 #ifdef MRPT_OS_WINDOWS 595 getsockopt(m_hSock, IPPROTO_TCP, TCP_NODELAY, (
char*)&
value, &
length);
606 int CClientTCPSocket::setSOSendBufffer(
const int& newValue)
608 const unsigned int length =
sizeof(newValue);
610 return setsockopt(m_hSock, SOL_SOCKET, SO_SNDBUF, (
char*)&newValue,
length);
616 int CClientTCPSocket::getSOSendBufffer()
619 #ifdef MRPT_OS_WINDOWS 624 getsockopt(m_hSock, SOL_SOCKET, SO_SNDBUF, (
char*)&
value, &
length);
Classes for serialization, sockets, ini-file manipulation, streams, list of properties-values, timewatch, extensions to STL.
This namespace provides a OS-independent interface to many useful functions: filenames manipulation...
#define THROW_EXCEPTION(msg)
#define THROW_EXCEPTION_FMT(_FORMAT_STRING,...)
std::string getLastSocketErrorStr()
Returns a description of the last Sockets error.
bool DNS_resolve_async(const std::string &server_name, std::string &out_ip, const unsigned int timeout_ms=3000)
Resolve a server address by its name, returning its IP address as a string - This method has a timeou...
std::string format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
GLsizei const GLchar ** string
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
GLdouble GLdouble GLdouble r
GLuint GLsizei GLsizei * length
std::vector< uint8_t > content
The contents of the message (memory is automatically handled by the std::vector object) ...
GLsizei const GLfloat * value
Serial and networking devices and utilities.
unsigned __int32 uint32_t
A class that contain generic messages, that can be sent and received from a "CClientTCPSocket" object...
uint32_t type
An identifier of the message type (only the least-sig byte is typically sent)
int _strcmpi(const char *str1, const char *str2) noexcept
An OS-independent version of strcmpi.