libassa  3.5.1
Socket.cpp
Go to the documentation of this file.
1 // -*- c++ -*-
2 //------------------------------------------------------------------------------
3 // $Id: Socket.cpp,v 1.13 2006/09/24 17:35:33 vlg Exp $
4 //------------------------------------------------------------------------------
5 // Socket.C
6 //------------------------------------------------------------------------------
7 // Copyright (c) 1999,2005 by Vladislav Grinchenko
8 //
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU Library General Public
11 // License as published by the Free Software Foundation; either
12 // version 2 of the License, or (at your option) any later version.
13 //------------------------------------------------------------------------
14 // Created: 03/22/99
15 //------------------------------------------------------------------------
16 
17 #include <sstream>
18 #if defined (__FreeBSD__) || defined(__FreeBSD_kernel__) || defined (__CYGWIN32__) || defined (__GNU__)
19 # include <sys/ioctl.h>
20 #endif
21 
22 #if defined (__NetBSD__)
23 # include <sys/filio.h>
24 # include <sys/ioctl.h>
25 #endif
26 
27 #if defined (WIN32)
28 # define O_NONBLOCK 04000
29 typedef unsigned int socklen_t;
30 #endif
31 
32 #include "assa/Socket.h"
33 #include "assa/XDRHack.h"
34 
35 using namespace ASSA;
36 
37 const int ASSA::Socket::PGSIZE = 4096;
38 
46 int
48 getBytesAvail (void) const
49 {
50  trace_with_mask("Socket::getBytesAvail",SOCKTRACE);
51 
52  Socket* This = (Socket*) this;
53  u_long ba = 0;
54  int ret = 0;
55 
56 #if defined(WIN32)
57  ret = ioctlsocket (m_fd, FIONREAD, &ba);
58 #else
59  ret = ioctl (m_fd, FIONREAD, &ba);
60 #endif
61 
62  if (ret == -1) {
63  EL((ASSAERR,"ioctl(2) failed with ret: %d\n", ret));
64  return ret;
65  }
66  ba += This->rdbuf ()->in_avail ();
67 
68  DL((SOCKTRACE,"%ld bytes available for reading\n", ba));
69  return (int(ba));
70 }
71 
72 Socket&
74 flush ()
75 {
76  if (good () && rdbuf ()) {
77  if (rdbuf ()->pubsync () == EOF) {
78  setstate (badbit);
79  }
80  }
81  return (*this);
82 }
83 
84 int
86 set_option (int level_, int optname_, int val_)
87 {
88  int ret = setsockopt (m_fd,
89  level_,
90  optname_,
91  (const char*) &val_,
92  sizeof (val_));
93  if (ret < 0) {
95  }
96  return ret;
97 }
98 
102 int
104 set_fd_options (long flags_)
105 {
106  trace_with_mask("Socket::set_fd_options",SOCKTRACE);
107  int val;
108  int ret;
109 
110 #if defined (WIN32)
111 
112  u_long set_nonblock = 1;
113  if ((val = ioctlsocket (m_fd, FIONBIO, &set_nonblock)) == 0) {
114  m_nonblocking = true;
115  return 0;
116  }
117  return -1;
118 
119 #else // POSIX/UNIX
120 
121  if ((val = ::fcntl (m_fd, F_GETFL, 0)) < 0) {
122  return -1;
123  }
124  val |= flags_; // turn flags on
125 
126  DL ((SOCKTRACE,"Set flags fcntl(%d, %s)\n", m_fd,
127  decode_fcntl_flags (val).c_str ()));
128 
129  ret = ::fcntl (m_fd, F_SETFL, val);
130 
131  val = ::fcntl (m_fd, F_GETFL, 0);
132  DL ((SOCKTRACE,"Flags are set to %s via fcntl(25)\n",
133  decode_fcntl_flags (val).c_str ()));
134 
135  return (ret);
136 
137 #endif
138 }
139 
145 int
147 clear_fd_options (long flags_)
148 {
149  trace_with_mask("Socket::clear_fd_options",SOCKTRACE);
150  long oldflags;
151  long newflags;
152  int ret;
153 
154 #if defined (WIN32)
155 
156  u_long set_block = 0;
157  if ((ret = ioctlsocket (m_fd, FIONBIO, &set_block)) == 0) {
158  m_nonblocking = false;
159  return 0;
160  }
161  return -1;
162 
163 #else
164 
165  if ((oldflags = ::fcntl (m_fd, F_GETFL, 0)) < 0) {
166  return -1;
167  }
168  newflags = oldflags & ~flags_; // clear flags
169 
170  DL ((SOCKTRACE,"Set flags fcntl(%d, %s)\n", m_fd,
171  decode_fcntl_flags (newflags).c_str ()));
172 
173  ret = ::fcntl (m_fd, F_SETFL, newflags);
174 
175  newflags = ::fcntl (m_fd, F_GETFL, 0);
176  DL ((SOCKTRACE,"Flags are set to %s via fcntl(%d)\n",
177  decode_fcntl_flags (newflags).c_str ()));
178 
179  return (ret);
180 #endif
181 }
182 
183 bool
185 turnOptionOn (opt_t opt_)
186 {
187  trace_with_mask("Socket::turnOptionOn",SOCKTRACE);
188 
189  if (nonblocking == opt_)
190  return set_fd_options (O_NONBLOCK);
191 
192  int optname;
193  if (reuseaddr == opt_)
194  optname = SO_REUSEADDR;
195  else {
196  EL((ASSAERR,"Invalid socket option\n"));
197  return false;
198  }
199  return set_option (SOL_SOCKET, optname, 1) == 0;
200 }
201 
202 bool
204 turnOptionOff (opt_t opt_)
205 {
206  trace_with_mask("Socket::turnOptionOff",SOCKTRACE);
207 
208  if (nonblocking == opt_)
209  return clear_fd_options (O_NONBLOCK);
210 
211  int optname;
212  if (reuseaddr == opt_)
213  optname = SO_REUSEADDR;
214  else {
215  EL((ASSAERR,"Invalid socket option\n"));
216  return false;
217  }
218  return set_option (SOL_SOCKET, optname, 0) == 0;
219 }
220 
221 bool
223 setOption (opt_t opt_, int arg_)
224 {
225  trace_with_mask("Socket::setOption(,)",SOCKTRACE);
226  int optname;
227 
228  if (nonblocking == opt_) {
229  return (arg_ == 1) ? set_fd_options (O_NONBLOCK)
230  : clear_fd_options (O_NONBLOCK);
231  }
232 
233  if (rcvlowat == opt_) {
234  optname = SO_RCVLOWAT;
235  }
236  else if (sndlowat == opt_) {
237  optname = SO_SNDLOWAT;
238  }
239  else {
240  EL((ASSAERR,"Invalid socket option\n"));
241  return false;
242  }
243  return set_option (SOL_SOCKET, optname, arg_) == 0;
244 }
245 
246 int
248 getOption (opt_t opt_) const
249 {
250  trace_with_mask("Socket::getOption",SOCKTRACE);
251  int optval = 0;
252 
253  if (nonblocking == opt_)
254  {
255 #if defined (WIN32)
256  return (m_nonblocking ? 1 : 0);
257 #else
258  if ((optval = ::fcntl (m_fd, F_GETFL, 0)) < 0) {
259  return -1;
260  }
261  return ((optval & O_NONBLOCK) == O_NONBLOCK ? 1 : 0);
262 #endif
263  }
264 
265  int optname;
266  int level = SOL_SOCKET;
267  bool bin = false;
268 
269  socklen_t len = sizeof (optval);
270  int ret;
271 
272  if (rcvlowat == opt_) {
273  optname = SO_RCVLOWAT;
274  }
275  else if (sndlowat == opt_) {
276  optname = SO_SNDLOWAT;
277  }
278  else if (reuseaddr == opt_) {
279  optname = SO_REUSEADDR;
280  bin = true;
281  }
282  else {
283  EL((ASSAERR,"Invalid socket option\n"));
284  return (-1);
285  }
286 
287 #if defined (__CYGWIN32__) || defined (WIN32)
288 
289  ret = getsockopt (m_fd, level, optname, (char*) &optval, (int*)&len);
290 
291 #else // posix/unix
292 
293  ret = getsockopt (m_fd, level, optname, (char*) &optval, &len);
294 
295 #endif
296 
297  if (ret < 0) {
298  return (-1);
299  }
300  if (bin) {
301  return (ret == 0 ? 0 : 1);
302  }
303  return (ret);
304 }
305 
306 int
308 ignore(int n_, int delim_)
309 {
310  trace_with_mask("Socket::ignore",SOCKTRACE);
311  register int b;
312  register int count = 0;
313  register char c;
314 
315  if (n_ == INT_MAX && delim_ == EOF) {
316  char buf[PGSIZE];
317  while ((b = read (buf, PGSIZE))) {
318  count += b;
319  }
321  return count;
322  }
323  for (; n_; n_--, count++) {
324  if ( (b = read (&c, 1)) == 0 ) {
326  break;
327  }
328  if ( c == delim_ )
329  break;
330  }
331  return count;
332 }
333 
334 //-----------------------------------------------------------------------------
335 // Input operators
336 //-----------------------------------------------------------------------------
337 
357 Socket&
359 operator>>(char& n_)
360 {
361 
362  int c = 0;
363  int len = sizeof (int);
364  XDR xdrs;
365  xdrmem_create (&xdrs, (caddr_t) &c, len, XDR_DECODE);
366 
367  if (read ((char* ) &c, len) == len) {
368  xdr_char (&xdrs, &n_);
369  }
370  else {
372  }
373  xdr_destroy(&xdrs);
374  return *this;
375 }
376 
379 Socket&
381 operator>> (std::string& s_)
382 {
383  char c = 0;
384  size_t n = 0;
385  s_ = "";
386 
387  (*this) >> n;
388 
389  if (n == 0) {
390  return *this;
391  }
392  size_t len = n;
393  while (len-- && read (&c, 1) == 1) {
394  s_ += c;
395  }
396  ignore (4 - n % 4);
397  return *this;
398 }
399 
400 Socket&
402 operator>> (short& n_)
403 {
404  short val;
405  if (read ((char*) &val, sizeof(short)) == sizeof(short)) {
406  n_ = (short) ntohs ((short)val);
407  }
408  else {
410  }
411  return *this;
412 }
413 
414 Socket&
416 operator>> (unsigned short& n_)
417 {
418  u_short val;
419  if (read ((char*) &val, sizeof(u_short)) == sizeof(u_short)) {
420  n_ = (u_short) ntohs ((u_short)val);
421  }
422  else {
424  }
425  return *this;
426 }
427 
428 #define LONGEST long
429 
430 /* On 64-bit platforms, sizeof (long) = 8 bytes.
431  * ntohl()/htonh() operats only on int32_t types which is 4 bytes long
432  * everywhere. So, for 64-bit longs we need to process twice as much
433  * and swapt data accordingly.
434  */
435 
436 #define READ_INT(TYPE) \
437 Socket& Socket::operator>>(TYPE& n_) \
438 {\
439  LONGEST val;\
440  int typesz = sizeof(TYPE);\
441  if (read ( (char* ) &val, typesz) == typesz) {\
442  if (sizeof(int32_t) <= typesz) {\
443  n_ = (TYPE) ntohl (val); \
444  }\
445  else {\
446  if (Socket::is_little_endian ()) {\
447  *((int32_t*)(&n_)+1) = ntohl (*((int32_t*)(&val)) );\
448  *((int32_t*)(&n_) ) = ntohl (*((int32_t*)(&val))+1);\
449  }\
450  else {\
451  *((int32_t*)(&n_) ) = ntohl (*((int32_t*)(&val)) );\
452  *((int32_t*)(&n_)+1) = ntohl (*((int32_t*)(&val))+1);\
453  }\
454  }\
455  }\
456  else {\
457  setstate (Socket::eofbit|Socket::failbit);\
458  }\
459  return *this;\
460 }
461 
462 READ_INT(int);
463 READ_INT(unsigned int);
464 READ_INT(long);
465 READ_INT(unsigned long);
466 
467 Socket&
469 operator>> (float& n_)
470 {
471  float val;
472  XDR xdrs;
473  xdrmem_create (&xdrs, (caddr_t) &val, sizeof(float), XDR_DECODE);
474 
475  if (read ((char*) &val, sizeof(float)) == sizeof(float)) {
476  xdr_float (&xdrs, &n_);
477  }
478  else {
480  }
481  xdr_destroy (&xdrs);
482  return *this;
483 }
484 
485 Socket&
487 operator>> (double& n_)
488 {
489  double val = 0;
490  XDR xdrs;
491  xdrmem_create (&xdrs, (caddr_t) &val, sizeof(double), XDR_DECODE);
492  if (read ((char*) &val, sizeof(double)) == sizeof(double)) {
493  xdr_double (&xdrs, &n_);
494  }
495  else {
497  }
498  xdr_destroy (&xdrs);
499  return *this;
500 }
501 
502 //-----------------------------------------------------------------------------
503 // Output operators
504 //-----------------------------------------------------------------------------
505 
507 Socket::
508 operator<< (char n_)
509 {
510  /* See comment to operator>>(char n_) */
511 
512  int buf = 0;
513  int len = sizeof (int);
514  XDR xdrs;
515 
516  xdrmem_create (&xdrs, (caddr_t) &buf, len, XDR_ENCODE);
517  xdr_char (&xdrs, &n_);
518 
519  if (write ((const char*) &buf, len) != len) {
521  }
522  xdr_destroy (&xdrs);
523  return *this;
524 }
525 
545 Socket::
546 operator<< (const std::string& s_)
547 {
548  static const char pad [4] = { 0, 0, 0, 0 };
549 
550  (*this) << s_.length ();
551  int ret = write (s_.c_str (), s_.length ());
552  if ( ret != s_.length () ) {
554  }
555  size_t r = 4 - s_.length() % 4;
556  if (r) {
557  if (write (pad, r) != r) {
559  }
560  }
561  return *this;
562 }
563 
565 operator<< (short n_)
566 {
567  short val = (short) htons((short)n_);
568 
569  if (write ((const char*) &val, sizeof(short)) != sizeof(short))
570  {
572  }
573  return *this;
574 }
575 
577 operator<< (unsigned short n_)
578 {
579  u_short val = (u_short) htons((u_short)n_);
580 
581  if (write ((const char*) &val, sizeof(u_short)) != sizeof(u_short))
582  {
584  }
585  return *this;
586 }
587 
588 #define WRITE_INT(TYPE) \
589 Socket& Socket::operator<< (TYPE n_) \
590 { \
591  LONGEST val;\
592  int typesz = sizeof(TYPE);\
593  if (sizeof(int32_t) <= typesz) {\
594  val = (TYPE) ntohl (n_); \
595  }\
596  else {\
597  if (Socket::is_little_endian ()) {\
598  *((int32_t*)(&val)+1) = htonl (*((int32_t*)(&n_)) );\
599  *((int32_t*)(&val) ) = htonl (*((int32_t*)(&n_))+1);\
600  }\
601  else {\
602  *((int32_t*)(&val) ) = htonl (*((int32_t*)(&n_)) );\
603  *((int32_t*)(&val)+1) = htonl (*((int32_t*)(&n_))+1);\
604  }\
605  }\
606  if (write ((const char*) &val, typesz) != typesz) {\
607  setstate (Socket::eofbit|Socket::failbit);\
608  }\
609  return *this;\
610 }
611 
613 WRITE_INT(unsigned int);
614 WRITE_INT(long);
615 WRITE_INT(unsigned long);
616 
618 Socket::
619 operator<< (float n_)
620 {
621  float buf, f = n_;
622  XDR xdrs;
623  xdrmem_create (&xdrs, (caddr_t) &buf, sizeof(float), XDR_ENCODE);
624  xdr_float (&xdrs, &f);
625 
626  int ret = write ((const char*) &buf, sizeof(float));
627  xdr_destroy (&xdrs);
628  if ( ret != sizeof(float) ) {
630  }
631  return *this;
632 }
633 
635 Socket::
636 operator<< (double n_)
637 {
638  double buf, f = n_;
639  XDR xdrs;
640  xdrmem_create (&xdrs, (caddr_t) &buf, sizeof(double), XDR_ENCODE);
641  xdr_double (&xdrs, &f);
642 
643  int ret = write ((const char*) &buf, sizeof(double));
644  xdr_destroy (&xdrs);
645  if ( ret != sizeof(double) ) {
647  }
648  return *this;
649 }
650 
651 void
653 dumpState (void) const
654 {
655  trace_with_mask("Socket::dumpState",SOCKTRACE);
656 
657  char state_set[] = "[ set]\n";
658  char state_not_set[] = "[not set]\n";
659 
660  std::ostringstream msg;
661 
662  msg << "\n";
663  msg << "\tTesting good() ....... ";
664 
665  if (this->good ()) msg << state_set;
666  else msg << state_not_set;
667 
668  msg << "\tTesting eof() ........ ";
669  if (this->eof ()) msg << state_set;
670  else msg << state_not_set;
671 
672  msg << "\tTesting fail() ....... ";
673  if (this->fail ()) msg << state_set;
674  else msg << state_not_set;
675 
676  msg << "\tTesting bad() ........ ";
677  if (this->bad ()) msg << state_set;
678  else msg << state_not_set;
679 
680  msg << "\tTesting !() .......... ";
681  if ( !(*this) ) msg << state_set;
682  else msg << state_not_set;
683 
684  msg << "\tTesting void *() ..... ";
685  if ( *this ) msg << state_set;
686  else msg << state_not_set;
687 
688  msg << "\tTesting nonblocking... ";
689  if (getOption (nonblocking) == 1) msg << state_set;
690  else msg << state_not_set;
691 
692  /*--- Terminate stream buffer ---*/
693  msg << std::ends;
694 
695  DL((SOCKTRACE,"%s\n", msg.str ().c_str ()));
696 }
697 
698 bool
701 {
702  union {
703  char c [sizeof (short)];
704  short v;
705  } endian_u;
706 
707  endian_u.v = 256;
708  return (endian_u.c [0] == 0);
709 }
710 
711 string
713 decode_fcntl_flags (long mask_)
714 {
715  string answer;
716 
717 #if !defined (WIN32)
718 
719  if (mask_ & O_RDONLY) {
720  answer = "O_RDONLY|"; // 000000
721  }
722  if (mask_ & O_WRONLY) {
723  answer += "O_WRONLY|"; // 000001
724  }
725  if (mask_ & O_RDWR) {
726  answer += "O_RDWR|"; // 000002
727  }
728  if (mask_ & O_APPEND) {
729  answer += "O_APPEND|"; // 001000
730  }
731  if (mask_ & O_NONBLOCK) {
732  answer += "O_NONBLOCK|";// 004000
733  }
734  if (mask_ & O_SYNC) {
735  answer += "O_SYNC|"; // 010000
736  }
737 
738  if (mask_ & O_ASYNC) { // 020000
739  answer += "O_ASYNC|";
740  }
741 
742  answer.erase (answer.end () - 1);
743 
744 #endif
745 
746  return answer;
747 }
#define EL(X)
A macro for writing error message to the Logger.
Definition: Logger.h:285
#define DL(X)
A macro for writing debug message to the Logger.
Definition: Logger.h:273
#define trace_with_mask(s, m)
trace_with_mask() is used to trace function call chain in C++ program.
Definition: Logger.h:437
unsigned long u_long
Definition: Logger_Impl.h:41
unsigned short u_short
Definition: Logger_Impl.h:39
#define READ_INT(TYPE)
Definition: Socket.cpp:436
#define WRITE_INT(TYPE)
Definition: Socket.cpp:588
Abstraction of socket data type.
XDRHack provides XDR definitions for systems that have them missing.
bool fail() const
Indicates that earlier extraction opeartion has failed to match the required pattern of input.
Definition: Socket.h:328
int clear_fd_options(long flags_)
Gateway method for clearing file descriptor options.
Definition: Socket.cpp:147
Socket & operator>>(char &c)
Input of built-in char type. The value will be XDR-decoded.
Definition: Socket.cpp:359
virtual Streambuf * rdbuf()
Return a pointer to the Streambuf associated with the stream.
Definition: Socket.h:240
void dumpState() const
Write state bits of the socket to the log file.
Definition: Socket.cpp:653
void setstate(iostate flag_)
Set socket state to flag_ by adding flag_ to the existing state.
Definition: Socket.h:577
static string decode_fcntl_flags(long mask_)
Decipher flags packed into mask_ used in fcntl() call.
Definition: Socket.cpp:713
int set_fd_options(long flags_)
Gateway method for setting file descriptor options.
Definition: Socket.cpp:104
bool turnOptionOff(opt_t opt_)
Disable socket option.
Definition: Socket.cpp:204
virtual int read(char *buf_, const u_int size_)
Read expected number of bytes from the socket.
Definition: Socket.h:551
int set_option(int level_, int optname_, int val_)
Gateway method of setting socket options.
Definition: Socket.cpp:86
bool turnOptionOn(opt_t opt_)
Enable socket option.
Definition: Socket.cpp:185
opt_t
Socket options.
Definition: Socket.h:99
@ reuseaddr
Allow local address reuse.
Definition: Socket.h:100
@ sndlowat
The send low-water mark si the amount of available space that must exist in the socket send buffer fo...
Definition: Socket.h:108
@ rcvlowat
The receiver low-water mark is the amount of data that must be in the socket receive buffer for selec...
Definition: Socket.h:102
@ nonblocking
Set Socket to a non-blocking mode (O_RDWR|O_NONBLOCK).
Definition: Socket.h:115
static bool is_little_endian()
Determine the endianess of the platform we are on.
Definition: Socket.cpp:700
bool eof() const
An earlier extraction operation has encountered the end of file of the input stream (peer closed its ...
Definition: Socket.h:321
handler_t m_fd
File descriptor.
Definition: Socket.h:485
bool bad() const
Socket fd == -1 or read/write error occured or some loss of integrity on assosiated stream buffer.
Definition: Socket.h:337
int getOption(opt_t opt_) const
Get current value of a socket option.
Definition: Socket.cpp:248
bool good() const
Indicates no error on the socket.
Definition: Socket.h:315
int ignore(int n_=INT_MAX, int delim_=EOF)
Extracts bytes and discards them.
Definition: Socket.cpp:308
Socket & operator<<(char c)
Output of built-in char type. The value will be XDR-encoded.
Definition: Socket.cpp:508
virtual Socket & flush()
This function simply calls the public "synchronizing" function rdbuf()->pubsync() (assuming the assoc...
Definition: Socket.cpp:74
@ eofbit
indicates that an input operation reached the end of an input sequence
Definition: Socket.h:82
@ badbit
indicates a loss of integrity in an input or output sequence (such as an irrecoverable read error fro...
Definition: Socket.h:87
@ failbit
indicates that an input operation failed to read the expected characters, or that an output operation...
Definition: Socket.h:84
static const int PGSIZE
Size of bytes of a kernel page.
Definition: Socket.h:74
bool setOption(opt_t opt_, int arg_)
Set socket option to value required.
Definition: Socket.cpp:223
virtual int write(const char *buf_, const u_int size_)
Write specified number of bytes to the socket.
Definition: Socket.h:544
int getBytesAvail(void) const
Return number of bytes available in socket receive buffer.
Definition: Socket.cpp:48
int in_avail()
This function returns the number of characters immediately available in the get area.
Definition: Streambuf.h:399
Definition: Acceptor.h:40
@ SOCKTRACE
Extended Socket & friends messages
Definition: LogMask.h:42
@ ASSAERR
ASSA and system errors
Definition: LogMask.h:34
Socket & ends(Socket &os_)
ends manipulator.
Definition: Socket.h:622