Pol  Revision:cb584c9
wnsckt.cpp
Go to the documentation of this file.
1 
7 #include "wnsckt.h"
8 
9 #include <cstdio>
10 #include <cstring>
11 
12 #include "esignal.h"
13 #include "logfacility.h"
14 #include "passert.h"
15 #include "strutil.h"
16 
17 #if defined( WINDOWS )
18 #define SOCKET_ERRNO( x ) WSA##x
19 #define socket_errno WSAGetLastError()
20 typedef int socklen_t;
21 
22 #else
23 
24 #include <arpa/inet.h>
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <netinet/in.h>
28 #include <netinet/tcp.h>
29 #include <sys/socket.h>
30 #include <sys/time.h>
31 #include <unistd.h>
32 
33 #define SOCKET_ERRNO( x ) x
34 #define socket_errno errno
35 
36 #endif
37 
38 #ifndef SCK_WATCH
39 #define SCK_WATCH 0
40 #endif
41 namespace Pol
42 {
43 namespace Clib
44 {
45 Socket::Socket() : _sck( INVALID_SOCKET ), _options( none )
46 {
47  memset( &_peer, 0, sizeof( _peer ) );
48 #ifdef _WIN32
49  static bool init;
50  if ( !init )
51  {
52  init = true;
53  WSADATA dummy;
54  WSAStartup( MAKEWORD( 1, 0 ), &dummy );
55  }
56 #endif
57 }
58 
59 Socket::Socket( SOCKET sock ) : _sck( sock ), _options( none )
60 {
61  memset( &_peer, 0, sizeof( _peer ) );
62 }
63 
64 Socket::Socket( Socket& sock ) : _sck( sock._sck ), _options( none )
65 {
66  memset( &_peer, 0, sizeof( _peer ) );
67  sock._sck = INVALID_SOCKET;
68 }
69 
70 
72 {
73  close();
74 }
75 
77 {
78  close();
79  _sck = sock;
80 }
81 
83 {
84  _options = opt;
85 }
86 
87 void Socket::setpeer( struct sockaddr peer )
88 {
89  _peer = peer;
90 }
91 
92 std::string Socket::getpeername() const
93 {
94  struct sockaddr client_addr; // inet_addr
95  socklen_t addrlen = sizeof client_addr;
96  if (::getpeername( _sck, &client_addr, &addrlen ) == 0 )
97  {
98  struct sockaddr_in* in_addr = (struct sockaddr_in*)&client_addr;
99  if ( client_addr.sa_family == AF_INET )
100  return inet_ntoa( in_addr->sin_addr );
101  else
102  return "(display error)";
103  }
104  else
105  return "Error retrieving peer name";
106 }
107 struct sockaddr Socket::peer_address() const
108 {
109  return _peer;
110 }
111 
113 {
114  return _sck;
115 }
116 
118 {
119  SOCKET s = _sck;
121  return s;
122 }
123 
124 
125 bool Socket::open( const char* ipaddr, unsigned short port )
126 {
127  close();
128  _sck = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
129  if ( _sck == INVALID_SOCKET
130 #ifndef WINDOWS
131  || _sck < 0
132 #endif
133  )
134  {
135  INFO_PRINT << "Unable to open socket in Socket::open()\n";
136  return false;
137  }
138 
139  struct sockaddr_in sin;
140  memset( &sin, 0, sizeof sin );
141  sin.sin_family = AF_INET;
142  sin.sin_addr.s_addr = inet_addr( ipaddr );
143  sin.sin_port = htons( port );
144 
145 
146  int res = connect( _sck, (struct sockaddr*)&sin, sizeof sin );
147 
148  if ( res == 0 )
149  {
150  return true;
151  }
152  else
153  {
154 #ifdef _WIN32
155  closesocket( _sck );
156 #else
157  ::close( _sck );
158 #endif
160  return false;
161  }
162 }
163 
165 {
166  if ( _sck == INVALID_SOCKET )
167  return;
168 
169  int tcp_nodelay = 1;
170  int res = setsockopt( _sck, IPPROTO_TCP, TCP_NODELAY, (const char*)&tcp_nodelay,
171  sizeof( tcp_nodelay ) );
172  if ( res < 0 )
173  {
174  throw std::runtime_error( "Unable to setsockopt (TCP_NODELAY) on socket, res=" +
175  Clib::decint( res ) );
176  }
177 }
178 
180 {
181  if ( _options & nonblocking )
182  {
183 #ifdef _WIN32
184  u_long nonblocking = 1;
185  int res = ioctlsocket( sck, FIONBIO, &nonblocking );
186 #else
187  int flags = fcntl( sck, F_GETFL );
188  flags |= O_NONBLOCK;
189  int res = fcntl( sck, F_SETFL, O_NONBLOCK );
190 #endif
191  if ( res < 0 )
192  {
193  throw std::runtime_error( "Unable to set listening socket to nonblocking mode, res=" +
194  decint( res ) );
195  }
196  }
197 }
198 
200 {
201  if ( sck != INVALID_SOCKET && _options & reuseaddr )
202  {
203 #ifndef WIN32
204  int reuse_opt = 1;
205  int res =
206  setsockopt( sck, SOL_SOCKET, SO_REUSEADDR, (const char*)&reuse_opt, sizeof( reuse_opt ) );
207  if ( res < 0 )
208  {
209  throw std::runtime_error( "Unable to setsockopt (SO_REUSEADDR) on listening socket, res = " +
210  decint( res ) );
211  }
212 #endif
213  }
214 }
215 
216 bool Socket::listen( unsigned short port )
217 {
218  struct sockaddr_in local;
219 
220  close();
221  local.sin_family = AF_INET;
222  local.sin_addr.s_addr = INADDR_ANY;
223  /* Port MUST be in Network Byte Order */
224  local.sin_port = htons( port );
225  memset( local.sin_zero, 0, sizeof( local.sin_zero ) ); // not needed, but for completeness
226 
227  _sck = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
228  if ( _sck == INVALID_SOCKET )
229  {
230  close();
231  return false;
232  }
233 
236 
237  if ( bind( _sck, (struct sockaddr*)&local, sizeof( local ) ) == -1 )
238  {
239  HandleError();
240  return false;
241  }
242  if (::listen( _sck, SOMAXCONN ) == -1 )
243  {
244  HandleError();
245  return false;
246  }
247  return true;
248 }
249 
250 bool Socket::select( unsigned int seconds, unsigned int useconds )
251 {
252  fd_set fd;
253  struct timeval timeout = {0, 0};
254  int nfds = 0;
255  FD_ZERO( &fd );
256  FD_SET( _sck, &fd );
257 #ifndef _WIN32
258  passert_r( _sck < FD_SETSIZE,
259  "Select() implementation in Linux cant handle this many sockets at the same time." )
260  nfds = _sck + 1;
261 #endif
262 
263  int res;
264 
265  do
266  {
267  timeout.tv_sec = seconds;
268  timeout.tv_usec = useconds;
269  res = ::select( nfds, &fd, NULL, NULL, &timeout );
270  } while ( res < 0 && !exit_signalled && socket_errno == SOCKET_ERRNO( EINTR ) );
271 
272  return ( res > 0 && FD_ISSET( _sck, &fd ) );
273 }
274 
275 bool Socket::accept( SOCKET* s, unsigned int /*mstimeout*/ )
276 {
277  *s = ::accept( _sck, NULL, NULL );
278  if ( *s != INVALID_SOCKET )
279  {
280  apply_socket_options( *s );
281  return true;
282  }
283  else
284  {
285  *s = INVALID_SOCKET;
286  return false;
287  }
288 }
289 
290 bool Socket::accept( Socket& newsocket )
291 {
292  struct sockaddr client_addr;
293  socklen_t addrlen = sizeof client_addr;
294  SOCKET s = ::accept( _sck, &client_addr, &addrlen );
295  if ( s != INVALID_SOCKET )
296  {
298  newsocket.setsocket( s );
299  newsocket.setpeer( client_addr );
300  return true;
301  }
302  else
303  {
304  return false;
305  }
306 }
307 
308 bool Socket::connected() const
309 {
310  return ( _sck != INVALID_SOCKET );
311 }
312 
313 /* Read and clear the error value */
315 {
316 #ifdef _WIN32
317  int ErrVal;
318  static char ErrorBuffer[80];
319 
320  ErrVal = WSAGetLastError();
321  WSASetLastError( 0 );
322 
323  switch ( ErrVal )
324  {
325  case WSAENOTSOCK: /* Software caused connection to abort */
326  case WSAECONNRESET: /* Arg list too long */
327  close();
328  break;
329 
330  default:
331  close(); /*
332  gee, we'll close here,too.
333  if you want to _not_ close for _specific_ error codes,
334  feel more than free to make exceptions; but the general
335  rule should be, close on error.
336  */
337  break;
338  }
339 
340 #if SCK_WATCH
341  if ( FormatMessage( FORMAT_MESSAGE_FROM_HMODULE, GetModuleHandle( TEXT( "wsock32" ) ), ErrVal,
342  MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), ErrorBuffer, sizeof ErrorBuffer,
343  NULL ) == 0 )
344  {
345  sprintf( ErrorBuffer, "Unknown error code 0x%08x", ErrVal );
346  }
347  INFO_PRINT << ErrorBuffer << "\n";
348 #endif
349 #else
350  close();
351 #endif
352 }
353 
354 bool Socket::recvbyte( unsigned char* ch, unsigned int waitms )
355 {
356  fd_set fd;
357 
358  if ( !connected() )
359  return false;
360 
361 #if SCK_WATCH
362  INFO_PRINT << "{L;1}\n";
363 #endif
364  FD_ZERO( &fd );
365  FD_SET( _sck, &fd );
366  int nfds = 0;
367 #ifndef _WIN32
368  nfds = _sck + 1;
369 #endif
370  struct timeval tv;
371  int res;
372 
373  do
374  {
375  tv.tv_sec = 0;
376  tv.tv_usec = waitms * 1000;
377  res = ::select( nfds, &fd, NULL, NULL, &tv );
378  } while ( res < 0 && exit_signalled && socket_errno == SOCKET_ERRNO( EINTR ) );
379 
380  if ( res == 0 )
381  {
382 #if SCK_WATCH
383  INFO_PRINT << "{TO}\n";
384 #endif
385  return false;
386  }
387  else if ( res == -1 )
388  {
389  HandleError();
390  close(); /* FIXME: very likely unrecoverable */
391  }
392 
393  res = recv( _sck, (char*)ch, 1, 0 );
394  if ( res == 1 )
395  {
396 #if SCK_WATCH
397  INFO_PRINT.Format( "\{{:#X}\}\n" ) << ch;
398 #endif
399  return true;
400  }
401  else if ( res == 0 )
402  {
403 #if SCK_WATCH
404  INFO_PRINT << "{CLOSE}\n";
405 #endif
406  close();
407  return false;
408  }
409  else
410  {
411  /* Can't time out here this is an ERROR! */
412  HandleError();
413  return false;
414  }
415 }
416 
417 bool Socket::recvdata( void* vdest, unsigned len, unsigned int waitms )
418 {
419  fd_set fd;
420  char* pdest = (char*)vdest;
421  int nfds = 0;
422 
423  while ( len )
424  {
425  if ( !connected() )
426  return false;
427 
428 #if SCK_WATCH
429  INFO_PRINT << "{L:" << len << "}\n";
430 #endif
431  FD_ZERO( &fd );
432  FD_SET( _sck, &fd );
433 #ifndef _WIN32
434  nfds = _sck + 1;
435 #endif
436 
437  struct timeval tv;
438  int res;
439  do
440  {
441  tv.tv_sec = 0;
442  tv.tv_usec = waitms * 1000;
443  res = ::select( nfds, &fd, NULL, NULL, &tv );
444  } while ( res < 0 && exit_signalled && socket_errno == SOCKET_ERRNO( EINTR ) );
445 
446  if ( res == 0 )
447  {
448 #if SCK_WATCH
449  INFO_PRINT << "{TO}\n";
450 #endif
451  return false;
452  }
453  else if ( res == -1 )
454  {
455  HandleError();
456  close(); /* FIXME: very likely unrecoverable */
457  }
458 
459 
460  res = ::recv( _sck, pdest, len, 0 );
461  if ( res > 0 )
462  {
463 #if SCK_WATCH
464  char* tmp = pdest;
465  INFO_PRINT.Format( "\{R:{}[{}]\}\n" ) << res << len;
466 #endif
467  len -= res;
468  pdest += res;
469 
470 #if SCK_WATCH
471  while ( res-- )
472  INFO_PRINT.Format( "\{{:#X}\}\n" ) << (unsigned char)( *tmp++ );
473 #endif
474  }
475  else if ( res == 0 )
476  {
477 #if SCK_WATCH
478  INFO_PRINT << "{CLOSE}\n";
479 #endif
480  close();
481  return false;
482  }
483  else
484  {
485  /* Can't time out here this is an ERROR! */
486  HandleError();
487  return false;
488  }
489  }
490  return true;
491 }
492 
493 unsigned Socket::peek( void* vdest, unsigned len, unsigned int wait_sec )
494 {
495  fd_set fd;
496  char* pdest = (char*)vdest;
497  int nfds = 0;
498 
499 #if SCK_WATCH
500  INFO_PRINT << "{L:" << len << "}\n";
501 #endif
502  FD_ZERO( &fd );
503  FD_SET( _sck, &fd );
504 #ifndef _WIN32
505  nfds = _sck + 1;
506 #endif
507  struct timeval tv;
508  int res;
509 
510  do
511  {
512  tv.tv_sec = wait_sec;
513  tv.tv_usec = 0;
514  res = ::select( nfds, &fd, NULL, NULL, &tv );
515  } while ( res < 0 && exit_signalled && socket_errno == SOCKET_ERRNO( EINTR ) );
516 
517  if ( res == 0 )
518  {
519 #if SCK_WATCH
520  INFO_PRINT << "{TO}\n";
521 #endif
522  return 0;
523  }
524  else if ( res == -1 )
525  {
526  HandleError();
527  close(); /* FIXME: very likely unrecoverable */
528  return 0;
529  }
530 
531 
532  res = ::recv( _sck, pdest, len, MSG_PEEK );
533  if ( res > 0 )
534  {
535  return res;
536  }
537  else if ( res == 0 )
538  {
539 #if SCK_WATCH
540  INFO_PRINT << "{CLOSE}\n";
541 #endif
542  close();
543  return 0;
544  }
545  else
546  {
547  /* Can't time out here this is an ERROR! */
548  HandleError();
549  return 0;
550  }
551 }
552 
553 void Socket::send( const void* vdata, unsigned datalen )
554 {
555  const char* cdata = static_cast<const char*>( vdata );
556 
557  while ( datalen )
558  {
559  int res = ::send( _sck, cdata, datalen, 0 );
560  if ( res < 0 )
561  {
562  int sckerr = socket_errno;
563  if ( sckerr == SOCKET_ERRNO( EWOULDBLOCK ) )
564  {
565  // FIXME sleep
566  continue;
567  }
568  else
569  {
570  INFO_PRINT << "Socket::send() error: " << sckerr << "\n";
571  HandleError();
572  return;
573  }
574  }
575  else
576  {
577  datalen -= res;
578  cdata += res;
579  }
580  }
581 }
582 
583 bool Socket::send_nowait( const void* vdata, unsigned datalen, unsigned* nsent )
584 {
585  const char* cdata = static_cast<const char*>( vdata );
586 
587  *nsent = 0;
588 
589  while ( datalen )
590  {
591  int res = ::send( _sck, cdata, datalen, 0 );
592  if ( res < 0 )
593  {
594  int sckerr = socket_errno;
595  if ( sckerr == SOCKET_ERRNO( EWOULDBLOCK ) )
596  {
597  // FIXME sleep
598  return false;
599  }
600  else
601  {
602  INFO_PRINT << "Socket::send_nowait() error: " << sckerr << "\n";
603  HandleError();
604  return true;
605  }
606  }
607  else
608  {
609  datalen -= res;
610  cdata += res;
611  *nsent += res;
612  }
613  }
614  return true;
615 }
616 
617 void Socket::write( const std::string& s )
618 {
619  send( (void*)s.c_str(), static_cast<unsigned int>( s.length() ) );
620 }
621 
622 
624 {
625  if ( _sck != INVALID_SOCKET )
626  {
627 #ifdef _WIN32
628  shutdown( _sck, 2 ); // 2 is both sides. defined in winsock2.h ...
629  closesocket( _sck );
630 #else
631  shutdown( _sck, SHUT_RDWR );
632  ::close( _sck );
633 #endif
635  }
636 }
637 
638 bool Socket::is_local() const
639 {
640  std::string s = getpeername();
641  return ( s == "127.0.0.1" );
642 }
643 }
644 }
void write(const std::string &str)
Definition: wnsckt.cpp:617
virtual ~Socket()
Definition: wnsckt.cpp:71
bool recvdata(void *vdest, unsigned len, unsigned int waitms)
Definition: wnsckt.cpp:417
#define INVALID_SOCKET
Definition: wnsckt.h:12
int SOCKET
Definition: wnsckt.h:10
bool connected() const
Definition: wnsckt.cpp:308
SOCKET handle() const
Definition: wnsckt.cpp:112
void apply_prebind_socket_options(SOCKET sck)
Definition: wnsckt.cpp:199
std::string decint(unsigned short v)
Definition: strutil.cpp:64
void disable_nagle()
Definition: wnsckt.cpp:164
bool listen(unsigned short port)
Definition: wnsckt.cpp:216
std::string getpeername() const
Definition: wnsckt.cpp:92
bool open(const char *ipaddr, unsigned short port)
Definition: wnsckt.cpp:125
bool recvbyte(unsigned char *byte, unsigned int waitms)
Definition: wnsckt.cpp:354
#define passert_r(exp, reason)
Definition: passert.h:66
void HandleError()
Definition: wnsckt.cpp:314
SOCKET _sck
Definition: wnsckt.h:73
unsigned peek(void *vdest, unsigned len, unsigned int waitms)
Definition: wnsckt.cpp:493
bool send_nowait(const void *vdata, unsigned datalen, unsigned *nsent)
Definition: wnsckt.cpp:583
bool accept(SOCKET *s, unsigned int mstimeout)
Definition: wnsckt.cpp:275
#define socket_errno
Definition: wnsckt.cpp:34
#define SOCKET_ERRNO(x)
Definition: wnsckt.cpp:33
void dummy()
Definition: testmisc.cpp:23
void setsocket(SOCKET sck)
Definition: wnsckt.cpp:76
bool is_local() const
Definition: wnsckt.cpp:638
struct sockaddr peer_address() const
Definition: wnsckt.cpp:107
struct sockaddr _peer
Definition: wnsckt.h:76
SOCKET release_handle()
Definition: wnsckt.cpp:117
void setpeer(struct sockaddr peer)
Definition: wnsckt.cpp:87
bool select(unsigned int seconds, unsigned int useconds)
Definition: wnsckt.cpp:250
void apply_socket_options(SOCKET sck)
Definition: wnsckt.cpp:179
#define INFO_PRINT
Definition: logfacility.h:223
void set_options(option opt)
Definition: wnsckt.cpp:82
Definition: berror.cpp:12
void send(const void *data, unsigned length)
Definition: wnsckt.cpp:553
std::atomic< bool > exit_signalled