38 #include <sys/types.h>
41 # pragma comment (lib, "Ws2_32.lib")
45 # include <sys/socket.h>
47 # include <arpa/inet.h>
48 # include <netinet/in.h>
49 # include <netinet/tcp.h>
83 #define SDH_TCP_DEBUG 1
120 static bool wsa_startup_called;
122 if ( !wsa_startup_called && WSAStartup ( MAKEWORD ( 1, 1 ) , &wsa ) != 0 )
126 wsa_startup_called =
true;
129 tcp_adr = string( _tcp_adr );
130 tcp_port = _tcp_port;
132 SetTimeout( _timeout );
139 struct hostent *host;
140 struct sockaddr_in addr;
143 if ( (addr.sin_addr.s_addr = inet_addr ( tcp_adr.c_str() )) == -1 )
145 if ( !inet_aton( tcp_adr.c_str(), &addr.sin_addr ) )
149 host = gethostbyname( tcp_adr.c_str() );
152 throw new cTCPSerialException(
cMsg(
"Invalid hostname \"%s\", gethostbyname() failed: %s", tcp_adr.c_str(), GetLastErrorMessage() ) );
154 addr.sin_addr = *(
struct in_addr*) host->h_addr;
156 fd = socket( PF_INET, SOCK_STREAM, 0 );
157 if ( fd == INVALID_SOCKET )
158 throw new cTCPSerialException(
cMsg(
"Could not create TCP socket, socket() failed: %s", GetLastErrorMessage() ) );
160 DBG( dbg <<
"Opening TCP connection to host: " << inet_ntoa( addr.sin_addr ) <<
", port: " << tcp_port <<
"\n" );
162 addr.sin_port = htons( tcp_port );
163 addr.sin_family = AF_INET;
165 int rc = connect( fd, (
struct sockaddr*) &addr,
sizeof(addr) );
167 throw new cTCPSerialException(
cMsg(
"Could not connect to \"%s:%d\", connect() failed: %s", tcp_adr.c_str(), tcp_port, GetLastErrorMessage() ) );
172 rc = setsockopt( fd, SOL_SOCKET, TCP_NODELAY, (
const char*) &one,
sizeof( one ) );
173 #elif defined( OSNAME_CYGWIN )
175 rc = setsockopt( fd, SOL_SOCKET, TCP_NODELAY, &one,
sizeof( one ) );
182 throw new cTCPSerialException(
cMsg(
"Could not set option TCP_NODELAY for connection to \"%s:%d\", setsockopt failed: %s", tcp_adr.c_str(), tcp_port, GetLastErrorMessage() ) );
185 SetTimeout( GetTimeout() );
193 return ( fd != INVALID_SOCKET );
203 DBG( dbg <<
"Closing TCP connection\n" );
219 len = int( strlen( ptr ) );
221 DBG( dbg <<
"cTCPSerial::write(): sending " << len <<
" bytes (hex): " <<
cHexByteString( ptr, len ) <<
"\n" );
224 int bytes_sent = send( fd, ptr, len, 0 );
226 if ( bytes_sent < 0 && errno == EAGAIN && timeout_us != TIMEOUT_WAIT_FOR_EVER_US )
229 if ( bytes_sent < 0 )
230 throw new cTCPSerialException(
cMsg(
"Error from send to TCP \"%s:%d\": %s", tcp_adr.c_str(), tcp_port, GetLastErrorMessage() ) );
231 if ( bytes_sent != len )
232 throw new cTCPSerialException(
cMsg(
"Could only send %d/%d bytes via TCP \"%s:%d\"", bytes_sent, len, tcp_adr.c_str(), tcp_port ) );
244 char* data = (
char*) _data;
248 if ( _timeout_us != timeout_us )
250 SetTimeout(
double(_timeout_us) / 1E6 );
255 int bytes_received = 0;
256 int bytes_received_inc = 0;
258 if ( _timeout_us > 0L )
272 FD_ZERO( &(readfds) );
273 FD_SET( fd, &(readfds) );
283 struct timeval timeout_timeval_maybe_overwritten = timeout_timeval;
284 rc = select( (
int) max_socket, &readfds,
NULL,
NULL, &timeout_timeval_maybe_overwritten );
286 throw new cTCPSerialException(
cMsg(
"Error from select() for TCP connection to \"%s:%d\": %s", tcp_adr.c_str(), tcp_port, GetLastErrorMessage() ) );
292 if ( !FD_ISSET( fd, &readfds ) )
294 DBG( dbg <<
"cTCPSerial::Read(): read1 " << bytes_received <<
"/" <<
size <<
" bytes (hex): " <<
cHexByteString( data, bytes_received ) <<
"\n" );
295 return bytes_received;
302 bytes_received_inc = recv( fd, data+bytes_received,
size-bytes_received, 0 );
305 if ( bytes_received_inc < 0 && errno == EAGAIN && timeout_us == TIMEOUT_RETURN_IMMEDITELY_US )
308 DBG( dbg <<
"cTCPSerial::Read(): read2 " << bytes_received <<
"/" <<
size <<
" bytes (hex): " <<
cHexByteString( data, bytes_received ) <<
" (ignored)\n" );
311 if ( bytes_received_inc < 0 )
312 throw new cTCPSerialException(
cMsg(
"Error from recv() for TCP connection to \"%s:%d\": %s", tcp_adr.c_str(), tcp_port, GetLastErrorMessage() ) );
314 bytes_received += bytes_received_inc;
315 }
while ( bytes_received <
size && !return_on_less_data );
318 if ( bytes_received <
size && !return_on_less_data )
320 DBG( dbg <<
"cTCPSerial::Read(): read3 ignoring " << bytes_received <<
"/" <<
size <<
" bytes (hex): " <<
cHexByteString( data, bytes_received ) <<
"\n" );
321 throw new cTCPSerialException(
cMsg(
"Could only receive %d/%ld bytes via TCP \"%s:%d\"", bytes_received,
size, tcp_adr.c_str(), tcp_port ) );
325 DBG( dbg <<
"cTCPSerial::Read(): read4 " << bytes_received <<
"/" <<
size <<
" bytes (hex): " <<
cHexByteString( data, bytes_received ) <<
"\n" );
326 return bytes_received;
333 DBG( dbg <<
"cTCPSerial::SetTimeout(): " << _timeout <<
"\n" );
335 if ( _timeout < 0.0 )
337 _timeout = TIMEOUT_WAIT_FOR_EVER_S;
338 timeout_us = TIMEOUT_WAIT_FOR_EVER_US;
339 timeout_timeval.tv_sec = 0;
340 timeout_timeval.tv_usec = 0;
345 double v3 = (_timeout - ((double)timeout_timeval.tv_sec)) * 1.0E6;
346 timeout_timeval.tv_usec = (
tTimevalUSec) ( (_timeout - ((
double)timeout_timeval.tv_sec)) * 1.0E6 );
348 double v = (_timeout*1.0E6);
349 timeout_us = (long)v;
357 u_long mode = (_timeout == 0.0);
358 ioctlsocket( fd, FIONBIO, &mode );
360 int flags = fcntl( fd, F_GETFL );
361 if ( _timeout == 0.0 )
362 fcntl( fd, F_SETFL, flags | O_NONBLOCK );
364 fcntl( fd, F_SETFL, flags & ~O_NONBLOCK );