Socket.cpp

Go to the documentation of this file.
00001 // -*- c++ -*-
00002 //------------------------------------------------------------------------------
00003 // $Id: Socket.cpp,v 1.8 2005/10/21 02:57:06 vlg Exp $
00004 //------------------------------------------------------------------------------
00005 //                              Socket.C
00006 //------------------------------------------------------------------------------
00007 //  Copyright (c) 1999,2005 by Vladislav Grinchenko
00008 //
00009 //  This library is free software; you can redistribute it and/or
00010 //  modify it under the terms of the GNU Library General Public
00011 //  License as published by the Free Software Foundation; either
00012 //  version 2 of the License, or (at your option) any later version.
00013 //------------------------------------------------------------------------
00014 //  Created: 03/22/99
00015 //------------------------------------------------------------------------
00016 
00017 #include <sstream>
00018 #if defined (__FreeBSD__) || defined (__FreeBSD_kernel__) || defined (__CYGWIN32__)
00019 #  include <sys/ioctl.h>
00020 #endif
00021 
00022 #include "assa/Socket.h"
00023 #include "assa/XDRHack.h"
00024 
00025 using namespace ASSA;
00026 
00027 const int ASSA::Socket::PGSIZE = 4096;
00028 
00036 int 
00037 Socket::
00038 getBytesAvail (void) const
00039 {
00040     trace_with_mask("Socket::getBytesAvail",SOCKTRACE);
00041       
00042     Socket* This = (Socket*) this;
00043     int ba = 0;
00044     int ret = ioctl (m_fd, FIONREAD, &ba);
00045 
00046     if (ret == -1) {
00047         EL((ERROR,"ioctl(2) failed with ret: %d\n", ret));
00048         return ret;
00049     }
00050     ba += This->rdbuf ()->in_avail ();
00051 
00052     DL((SOCKTRACE,"%d bytes available for reading\n", ba));
00053     return ba;
00054 }
00055 
00056 Socket&
00057 Socket::
00058 flush ()
00059 {
00060     if (good () && rdbuf ()) {
00061         if (rdbuf ()->pubsync () == EOF) {
00062             setstate (badbit);
00063         }
00064     }
00065     return (*this);
00066 }
00067 
00068 int 
00069 Socket::
00070 set_option (int level_, int optname_, int val_)
00071 {
00072     int ret = setsockopt (m_fd, level_, optname_, (const char*) &val_, 
00073                   sizeof (val_));
00074     if (ret < 0)
00075         setstate (Socket::failbit);
00076     return ret;
00077 }
00078 
00079 int
00080 Socket::
00081 set_fd_options (int flags_)
00082 {
00083     int val;
00084     if ((val = fcntl (m_fd, F_GETFL, 0)) < 0) {
00085         return -1;
00086     }
00087     val |= flags_;      // turn flags on
00088 
00089     return (fcntl (m_fd, F_SETFL, val) < 0) ? -1 : 0;
00090 }
00091 
00092 int
00093 Socket::
00094 clear_fd_options (int flags_)
00095 {
00096     int val;
00097     if ((val = fcntl (m_fd, F_GETFL, 0)) < 0) {
00098         return -1;
00099     }
00100     val &= ~flags_; // turn flags off
00101 
00102     return (fcntl (m_fd, F_SETFL, val) < 0) ? -1 : 0;
00103 }
00104 
00105 bool
00106 Socket::
00107 turnOptionOn (opt_t opt_)
00108 {
00109     trace_with_mask("Socket::turnOptionOn",SOCKTRACE);
00110 
00111     if (blocking == opt_) 
00112         return clear_fd_options (O_NONBLOCK);
00113 
00114     if (nonblocking == opt_) 
00115         return set_fd_options (O_NONBLOCK);
00116 
00117     int optname;
00118     if (reuseaddr == opt_) 
00119         optname = SO_REUSEADDR;
00120     else {
00121         EL((ERROR,"Invalid socket option\n"));
00122         return false;
00123     }
00124     return set_option (SOL_SOCKET, optname, 1) == 0;
00125 }
00126 
00127 bool
00128 Socket::
00129 turnOptionOff (opt_t opt_)
00130 {
00131     trace_with_mask("Socket::turnOptionOff",SOCKTRACE);
00132 
00133     if (blocking == opt_) 
00134         return set_fd_options (O_NONBLOCK);
00135 
00136     if (nonblocking == opt_) 
00137         return clear_fd_options (O_NONBLOCK);
00138 
00139     int optname;
00140     if (reuseaddr == opt_) 
00141         optname = SO_REUSEADDR;
00142     else {
00143         EL((ERROR,"Invalid socket option\n"));
00144         return false;
00145     }
00146     return set_option (SOL_SOCKET, optname, 0) == 0;
00147 }
00148 
00149 bool
00150 Socket::
00151 setOption (opt_t opt_, int arg_)
00152 {
00153     trace_with_mask("Socket::setOption(,)",SOCKTRACE);
00154     int optname;
00155 
00156     if (nonblocking == opt_) 
00157         return (arg_ == 1) ? set_fd_options (O_NONBLOCK)
00158             : clear_fd_options (O_NONBLOCK);
00159 
00160     if (blocking == opt_) 
00161         return (arg_ == 1) ? clear_fd_options (O_NONBLOCK)
00162             : set_fd_options (O_NONBLOCK);
00163 
00164     if (rcvlowat == opt_)      optname = SO_RCVLOWAT;
00165     else if (sndlowat == opt_) optname = SO_SNDLOWAT;
00166     else {
00167         EL((ERROR,"Invalid socket option\n"));
00168         return false;
00169     }
00170     return set_option (SOL_SOCKET, optname, arg_) == 0;
00171 }
00172 
00173 int
00174 Socket::
00175 getOption (opt_t opt_) const
00176 {
00177     trace_with_mask("Socket::getOption",SOCKTRACE);
00178     int optval = 0;
00179 
00180     if (nonblocking == opt_) {
00181         if ((optval = fcntl (m_fd, F_GETFL, 0)) < 0) {
00182             return -1;
00183         }
00184         return ((optval & O_NONBLOCK) == O_NONBLOCK ? 1 : 0);
00185     }
00186 
00187     if (blocking == opt_) {
00188         if ((optval = fcntl (m_fd, F_GETFL, 0)) < 0) {
00189             return -1;
00190         }
00191         return ((optval & O_NONBLOCK) == O_NONBLOCK ? 0 : 1);
00192     }
00193     
00194     int optname;
00195     int level = SOL_SOCKET;
00196     bool bin = false;
00197 
00198     socklen_t len = sizeof (optval);
00199     int ret;
00200 
00201     if (rcvlowat == opt_) {
00202         optname = SO_RCVLOWAT;
00203     }
00204     else if (sndlowat == opt_) {
00205         optname = SO_SNDLOWAT;
00206     }
00207     else if (reuseaddr == opt_) {
00208         optname = SO_REUSEADDR;
00209         bin = true;
00210     }
00211     else {
00212         EL((ERROR,"Invalid socket option\n"));
00213         return (-1);
00214     }
00215 
00216 #ifndef __CYGWIN32__
00217     ret = getsockopt (m_fd, level, optname, (char*) &optval, &len);
00218 #else
00219     ret = getsockopt (m_fd, level, optname, (char*) &optval, (int*)&len);
00220 #endif
00221 
00222     if (ret < 0) {
00223         return (-1);
00224     }
00225     if (bin) {
00226         return (ret == 0 ? 0 : 1);
00227     }
00228     return (ret);
00229 }
00230 
00231 int
00232 Socket::
00233 ignore(int n_, int delim_)
00234 {
00235     trace_with_mask("Socket::ignore",SOCKTRACE);
00236     register int b;
00237     register int count = 0;
00238     register char c;
00239 
00240     if (n_ == INT_MAX && delim_ == EOF) {
00241         char buf[PGSIZE];
00242         while ((b = read (buf, PGSIZE))) {
00243             count += b;
00244         }
00245         setstate (Socket::eofbit|Socket::failbit);
00246         return count;
00247     }
00248     for (; n_; n_--, count++) {
00249         if ( (b = read (&c, 1)) == 0 ) {
00250             setstate (Socket::eofbit|Socket::failbit);
00251             break;
00252         }
00253         if ( c == delim_ )
00254             break;
00255     }
00256     return count;
00257 }
00258 
00259 //-----------------------------------------------------------------------------
00260 //                         Input operators
00261 //-----------------------------------------------------------------------------
00262 
00282 Socket& 
00283 Socket::
00284 operator>>(char& n_) 
00285 {
00286 
00287     int c = 0;
00288     int len = sizeof (int);
00289     XDR xdrs; 
00290     xdrmem_create (&xdrs, (caddr_t) &c, len, XDR_DECODE); 
00291 
00292     if (read ((char* ) &c, len) == len) { 
00293         xdr_char (&xdrs, &n_); 
00294     } 
00295     else { 
00296         setstate (Socket::eofbit|Socket::failbit); 
00297     } 
00298     xdr_destroy(&xdrs); 
00299     return *this; 
00300 }
00301 
00304 Socket& 
00305 Socket::
00306 operator>> (std::string& s_) 
00307 {
00308     char c = 0;
00309     size_t n = 0;
00310     s_ = "";
00311 
00312     (*this) >> n;
00313 
00314     if (n == 0) {
00315         return *this;
00316     }
00317     size_t len = n;
00318     while (len-- && read (&c, 1) == 1) {
00319         s_ += c;
00320     }
00321     ignore (4 - n % 4);
00322     return *this; 
00323 }
00324 
00325 Socket& 
00326 Socket::
00327 operator>> (short& n_)
00328 {
00329     short val;
00330     if (read ((char*) &val, sizeof(short)) == sizeof(short)) {
00331         n_ = (short) ntohs ((short)val);
00332     }
00333     else {
00334         setstate (Socket::eofbit|Socket::failbit);
00335     }
00336     return *this;
00337 }
00338 
00339 Socket& 
00340 Socket::
00341 operator>> (unsigned short& n_) 
00342 {
00343     u_short val;
00344     if (read ((char*) &val, sizeof(u_short)) == sizeof(u_short)) {
00345         n_ = (u_short) ntohs ((u_short)val);
00346     }
00347     else {
00348         setstate (Socket::eofbit|Socket::failbit);
00349     }
00350     return *this;
00351 }
00352 
00353 #define LONGEST long
00354 
00355 /* On 64-bit platforms, sizeof (long) = 8 bytes. 
00356  * ntohl()/htonh() operats only on int32_t types which is 4 bytes long
00357  * everywhere. So, for 64-bit longs we need to process twice as much
00358  * and swapt data accordingly.
00359  */
00360 
00361 #define READ_INT(TYPE) \
00362 Socket& Socket::operator>>(TYPE& n_) \
00363 {\
00364     LONGEST val;\
00365     int typesz = sizeof(TYPE);\
00366     if (read ( (char* ) &val, typesz) == typesz) {\
00367         if (sizeof(int32_t) <= typesz) {\
00368             n_ = (TYPE) ntohl (val);   \
00369         }\
00370         else {\
00371             if (Socket::is_little_endian ()) {\
00372                 *((int32_t*)(&n_)+1) = ntohl (*((int32_t*)(&val))  );\
00373                 *((int32_t*)(&n_)  ) = ntohl (*((int32_t*)(&val))+1);\
00374             }\
00375             else {\
00376                 *((int32_t*)(&n_)  ) = ntohl (*((int32_t*)(&val))  );\
00377                 *((int32_t*)(&n_)+1) = ntohl (*((int32_t*)(&val))+1);\
00378             }\
00379         }\
00380     }\
00381     else {\
00382         setstate (Socket::eofbit|Socket::failbit);\
00383     }\
00384     return *this;\
00385 }
00386 
00387 READ_INT(int);
00388 READ_INT(unsigned int);
00389 READ_INT(long);
00390 READ_INT(unsigned long);
00391 
00392 Socket& 
00393 Socket::
00394 operator>> (float& n_) 
00395 {
00396     float val; 
00397     XDR xdrs; 
00398     xdrmem_create (&xdrs, (caddr_t) &val, sizeof(float), XDR_DECODE); 
00399 
00400     if (read ((char*) &val, sizeof(float)) == sizeof(float)) { 
00401         xdr_float (&xdrs, &n_); 
00402     } 
00403     else { 
00404         setstate (Socket::eofbit|Socket::failbit); 
00405     } 
00406     xdr_destroy (&xdrs); 
00407     return *this; 
00408 }
00409 
00410 Socket& 
00411 Socket::
00412 operator>> (double& n_) 
00413 {
00414     double val = 0; 
00415     XDR xdrs; 
00416     xdrmem_create (&xdrs, (caddr_t) &val, sizeof(double), XDR_DECODE); 
00417     if (read ((char*) &val, sizeof(double)) == sizeof(double)) { 
00418         xdr_double (&xdrs, &n_); 
00419     } 
00420     else { 
00421         setstate (Socket::eofbit|Socket::failbit); 
00422     } 
00423     xdr_destroy (&xdrs); 
00424     return *this; 
00425 }
00426 
00427 //-----------------------------------------------------------------------------
00428 //                          Output operators
00429 //-----------------------------------------------------------------------------
00430 
00431 Socket& 
00432 Socket::
00433 operator<< (char n_) 
00434 { 
00435     /* See comment to operator>>(char n_) */
00436 
00437     int buf = 0;
00438     int len = sizeof (int);
00439     XDR xdrs; 
00440 
00441     xdrmem_create (&xdrs, (caddr_t) &buf, len, XDR_ENCODE); 
00442     xdr_char (&xdrs, &n_); 
00443 
00444     if (write ((const char*) &buf, len) != len) {
00445         (Socket::eofbit|Socket::failbit); 
00446     }
00447     xdr_destroy (&xdrs); 
00448     return *this; 
00449 }
00450 
00469 Socket& 
00470 Socket::
00471 operator<< (const std::string& s_) 
00472 { 
00473     static const char pad [4] = { 0, 0, 0, 0 };
00474 
00475     (*this) << s_.length ();
00476     int ret = write (s_.c_str (), s_.length ());
00477     if ( ret != s_.length () ) { 
00478         setstate (Socket::eofbit|Socket::failbit); 
00479     } 
00480     size_t r = 4 - s_.length() % 4;
00481     if (r) {
00482         if (write (pad, r) != r) {
00483             setstate (Socket::eofbit|Socket::failbit); 
00484         }
00485     }
00486     return *this;
00487 }
00488 
00489 Socket& Socket::
00490 operator<< (short n_) 
00491 { 
00492     short val = (short) htons((short)n_);
00493 
00494     if (write ((const char*) &val, sizeof(short)) != sizeof(short)) 
00495     {
00496         setstate (Socket::eofbit|Socket::failbit);
00497     }
00498     return *this;
00499 }
00500 
00501 Socket& Socket::
00502 operator<< (unsigned short n_) 
00503 { 
00504     u_short val = (u_short) htons((u_short)n_);
00505 
00506     if (write ((const char*) &val, sizeof(u_short)) != sizeof(u_short)) 
00507     {
00508         setstate (Socket::eofbit|Socket::failbit);
00509     }
00510     return *this;
00511 }
00512 
00513 #define WRITE_INT(TYPE) \
00514 Socket& Socket::operator<< (TYPE n_) \
00515 { \
00516     LONGEST val;\
00517     int typesz = sizeof(TYPE);\
00518     if (sizeof(int32_t) <= typesz) {\
00519         val = (TYPE) ntohl (n_);   \
00520     }\
00521     else {\
00522         if (Socket::is_little_endian ()) {\
00523             *((int32_t*)(&val)+1) = htonl (*((int32_t*)(&n_))  );\
00524             *((int32_t*)(&val)  ) = htonl (*((int32_t*)(&n_))+1);\
00525         }\
00526         else {\
00527             *((int32_t*)(&val)  ) = htonl (*((int32_t*)(&n_))  );\
00528             *((int32_t*)(&val)+1) = htonl (*((int32_t*)(&n_))+1);\
00529         }\
00530     }\
00531     if (write ((const char*) &val, typesz) != typesz) {\
00532         setstate (Socket::eofbit|Socket::failbit);\
00533     }\
00534     return *this;\
00535 }
00536 
00537 WRITE_INT(int);
00538 WRITE_INT(unsigned int);
00539 WRITE_INT(long);
00540 WRITE_INT(unsigned long);
00541 
00542 Socket& 
00543 Socket::
00544 operator<< (float n_) 
00545 { 
00546     float buf, f = n_; 
00547     XDR xdrs; 
00548     xdrmem_create (&xdrs, (caddr_t) &buf, sizeof(float), XDR_ENCODE); 
00549     xdr_float (&xdrs, &f); 
00550 
00551     int ret = write ((const char*) &buf, sizeof(float)); 
00552     xdr_destroy (&xdrs); 
00553     if ( ret != sizeof(float) ) { 
00554         setstate (Socket::eofbit|Socket::failbit); 
00555     } 
00556     return *this; 
00557 }
00558 
00559 Socket& 
00560 Socket::
00561 operator<< (double n_) 
00562 { 
00563     double buf, f = n_; 
00564     XDR xdrs; 
00565     xdrmem_create (&xdrs, (caddr_t) &buf, sizeof(double), XDR_ENCODE); 
00566     xdr_double (&xdrs, &f); 
00567 
00568     int ret = write ((const char*) &buf, sizeof(double)); 
00569     xdr_destroy (&xdrs); 
00570     if ( ret != sizeof(double) ) { 
00571         setstate (Socket::eofbit|Socket::failbit); 
00572     } 
00573     return *this; 
00574 }
00575 
00576 void 
00577 Socket::
00578 dumpState (void) const
00579 {
00580     trace_with_mask("Socket::dumpState",SOCKTRACE);
00581 
00582     char state_set[]    = "[    set]\n";
00583     char state_not_set[] = "[not set]\n";
00584 
00585     std::ostringstream msg;
00586 
00587     msg << "\n";
00588     msg << "\tTesting good() ....... ";
00589 
00590     if (this->good ()) msg << state_set;
00591     else msg << state_not_set;
00592 
00593     msg << "\tTesting eof() ........ ";
00594     if (this->eof ()) msg << state_set;
00595     else msg << state_not_set;
00596 
00597     msg << "\tTesting fail() ....... ";
00598     if (this->fail ()) msg << state_set;
00599     else msg << state_not_set;
00600 
00601     msg << "\tTesting bad() ........ ";
00602     if (this->bad ()) msg << state_set;
00603     else msg << state_not_set;
00604 
00605     msg << "\tTesting !() .......... ";
00606     if ( !(*this) ) msg << state_set;
00607     else msg << state_not_set;
00608 
00609     msg << "\tTesting void *() ..... ";
00610     if ( *this ) msg << state_set;
00611     else msg << state_not_set;
00612 
00613     msg << "\tTesting nonblocking... ";
00614     if (getOption (nonblocking) == 1) msg << state_set;
00615     else msg << state_not_set;
00616 
00617     /*--- Terminate stream buffer ---*/
00618     msg << std::ends;
00619 
00620     DL((SOCKTRACE,"%s\n", msg.str ().c_str ()));
00621 }
00622 
00623 bool
00624 Socket::
00625 is_little_endian ()
00626 {
00627     union {
00628         char  c [sizeof (short)];
00629         short v;
00630     } endian_u;
00631 
00632     endian_u.v = 256;
00633     return (endian_u.c [0] == 0);
00634 }

Generated on Mon Dec 19 16:37:15 2005 for libassa by  doxygen 1.4.5