/home/vlg/develop/libASSA/libassa/assa/Socket.cpp

Go to the documentation of this file.
00001 // -*- c++ -*-
00002 //------------------------------------------------------------------------------
00003 // $Id: Socket.cpp,v 1.12 2006/07/26 00:27:32 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 #if defined (__NetBSD__)
00023 #  include <sys/filio.h>
00024 #  include <sys/ioctl.h>
00025 #endif
00026 
00027 #if defined (WIN32)
00028 #  define O_NONBLOCK    04000
00029 typedef unsigned int socklen_t;
00030 #endif
00031 
00032 #include "assa/Socket.h"
00033 #include "assa/XDRHack.h"
00034 
00035 using namespace ASSA;
00036 
00037 const int ASSA::Socket::PGSIZE = 4096;
00038 
00046 int 
00047 Socket::
00048 getBytesAvail (void) const
00049 {
00050     trace_with_mask("Socket::getBytesAvail",SOCKTRACE);
00051       
00052     Socket* This = (Socket*) this;
00053     u_long ba    = 0;
00054     int ret      = 0;
00055 
00056 #if defined(WIN32)
00057     ret = ioctlsocket (m_fd, FIONREAD, &ba);
00058 #else 
00059     ret = ioctl (m_fd, FIONREAD, &ba);
00060 #endif
00061 
00062     if (ret == -1) {
00063         EL((ASSAERR,"ioctl(2) failed with ret: %d\n", ret));
00064         return ret;
00065     }
00066     ba += This->rdbuf ()->in_avail ();
00067 
00068     DL((SOCKTRACE,"%ld bytes available for reading\n", ba));
00069     return (int(ba));
00070 }
00071 
00072 Socket&
00073 Socket::
00074 flush ()
00075 {
00076     if (good () && rdbuf ()) {
00077         if (rdbuf ()->pubsync () == EOF) {
00078             setstate (badbit);
00079         }
00080     }
00081     return (*this);
00082 }
00083 
00084 int 
00085 Socket::
00086 set_option (int level_, int optname_, int val_)
00087 {
00088     int ret = setsockopt (m_fd, 
00089                           level_, 
00090                           optname_, 
00091                           (const char*) &val_, 
00092                           sizeof (val_));
00093     if (ret < 0) {
00094         setstate (Socket::failbit);
00095     }
00096     return ret;
00097 }
00098 
00102 int
00103 Socket::
00104 set_fd_options (long flags_)
00105 {
00106     trace_with_mask("Socket::set_fd_options",SOCKTRACE);
00107     int val;
00108     int ret;
00109 
00110 #if defined (WIN32)
00111 
00112     u_long set_nonblock = 1;
00113     if ((val = ioctlsocket (m_fd, FIONBIO, &set_nonblock)) == 0) {
00114         m_nonblocking = true;
00115         return 0;
00116     }
00117     return -1;
00118 
00119 #else  // POSIX/UNIX
00120 
00121     if ((val = ::fcntl (m_fd, F_GETFL, 0)) < 0) {
00122         return -1;
00123     }
00124     val |= flags_;      // turn flags on
00125 
00126     DL ((SOCKTRACE,"Set flags fcntl(%d, %s)\n", m_fd, 
00127          decode_fcntl_flags (val).c_str ()));
00128 
00129     ret = ::fcntl (m_fd, F_SETFL, val);
00130 
00131     val = ::fcntl (m_fd, F_GETFL, 0);
00132     DL ((SOCKTRACE,"Flags are set to %s via fcntl(25)\n",
00133          decode_fcntl_flags (val).c_str ()));
00134 
00135     return (ret);
00136 
00137 #endif
00138 }
00139 
00145 int
00146 Socket::
00147 clear_fd_options (long flags_)
00148 {
00149     trace_with_mask("Socket::clear_fd_options",SOCKTRACE);
00150     long oldflags;
00151     long newflags;
00152     int ret;
00153 
00154 #if defined (WIN32)
00155 
00156     u_long set_block = 0;
00157     if ((ret = ioctlsocket (m_fd, FIONBIO, &set_block)) == 0) {
00158         m_nonblocking = false;
00159         return 0;
00160     }
00161     return -1;
00162 
00163 #else
00164 
00165     if ((oldflags = ::fcntl (m_fd, F_GETFL, 0)) < 0) {
00166         return -1;
00167     }
00168     newflags = oldflags & ~flags_;  // clear flags
00169 
00170     DL ((SOCKTRACE,"Set flags fcntl(%d, %s)\n", m_fd, 
00171          decode_fcntl_flags (newflags).c_str ()));
00172 
00173     ret = ::fcntl (m_fd, F_SETFL, newflags);
00174 
00175     newflags = ::fcntl (m_fd, F_GETFL, 0);
00176     DL ((SOCKTRACE,"Flags are set to %s via fcntl(%d)\n",
00177          decode_fcntl_flags (newflags).c_str ()));
00178 
00179     return (ret);
00180 #endif
00181 }
00182 
00183 bool
00184 Socket::
00185 turnOptionOn (opt_t opt_)
00186 {
00187     trace_with_mask("Socket::turnOptionOn",SOCKTRACE);
00188 
00189     if (nonblocking == opt_) 
00190         return set_fd_options (O_NONBLOCK);
00191 
00192     int optname;
00193     if (reuseaddr == opt_) 
00194         optname = SO_REUSEADDR;
00195     else {
00196         EL((ASSAERR,"Invalid socket option\n"));
00197         return false;
00198     }
00199     return set_option (SOL_SOCKET, optname, 1) == 0;
00200 }
00201 
00202 bool
00203 Socket::
00204 turnOptionOff (opt_t opt_)
00205 {
00206     trace_with_mask("Socket::turnOptionOff",SOCKTRACE);
00207 
00208     if (nonblocking == opt_) 
00209         return clear_fd_options (O_NONBLOCK);
00210 
00211     int optname;
00212     if (reuseaddr == opt_) 
00213         optname = SO_REUSEADDR;
00214     else {
00215         EL((ASSAERR,"Invalid socket option\n"));
00216         return false;
00217     }
00218     return set_option (SOL_SOCKET, optname, 0) == 0;
00219 }
00220 
00221 bool
00222 Socket::
00223 setOption (opt_t opt_, int arg_)
00224 {
00225     trace_with_mask("Socket::setOption(,)",SOCKTRACE);
00226     int optname;
00227 
00228     if (nonblocking == opt_) {
00229         return (arg_ == 1) ? set_fd_options (O_NONBLOCK)
00230             : clear_fd_options (O_NONBLOCK);
00231     }
00232 
00233     if (rcvlowat == opt_) {
00234         optname = SO_RCVLOWAT;
00235     }
00236     else if (sndlowat == opt_) {
00237         optname = SO_SNDLOWAT;
00238     }
00239     else {
00240         EL((ASSAERR,"Invalid socket option\n"));
00241         return false;
00242     }
00243     return set_option (SOL_SOCKET, optname, arg_) == 0;
00244 }
00245 
00246 int
00247 Socket::
00248 getOption (opt_t opt_) const
00249 {
00250     trace_with_mask("Socket::getOption",SOCKTRACE);
00251     int optval = 0;
00252 
00253     if (nonblocking == opt_) 
00254     {
00255 #if defined (WIN32)
00256         return (m_nonblocking ? 1 : 0);
00257 #else
00258         if ((optval = ::fcntl (m_fd, F_GETFL, 0)) < 0) {
00259             return -1;
00260         }
00261         return ((optval & O_NONBLOCK) == O_NONBLOCK ? 1 : 0);
00262 #endif
00263     }
00264 
00265     int optname;
00266     int level = SOL_SOCKET;
00267     bool bin = false;
00268 
00269     socklen_t len = sizeof (optval);
00270     int ret;
00271 
00272     if (rcvlowat == opt_) {
00273         optname = SO_RCVLOWAT;
00274     }
00275     else if (sndlowat == opt_) {
00276         optname = SO_SNDLOWAT;
00277     }
00278     else if (reuseaddr == opt_) {
00279         optname = SO_REUSEADDR;
00280         bin = true;
00281     }
00282     else {
00283         EL((ASSAERR,"Invalid socket option\n"));
00284         return (-1);
00285     }
00286 
00287 #if defined (__CYGWIN32__) || defined (WIN32)
00288 
00289     ret = getsockopt (m_fd, level, optname, (char*) &optval, (int*)&len);
00290 
00291 #else  // posix/unix
00292 
00293     ret = getsockopt (m_fd, level, optname, (char*) &optval, &len);
00294 
00295 #endif
00296 
00297     if (ret < 0) {
00298         return (-1);
00299     }
00300     if (bin) {
00301         return (ret == 0 ? 0 : 1);
00302     }
00303     return (ret);
00304 }
00305 
00306 int
00307 Socket::
00308 ignore(int n_, int delim_)
00309 {
00310     trace_with_mask("Socket::ignore",SOCKTRACE);
00311     register int b;
00312     register int count = 0;
00313     register char c;
00314 
00315     if (n_ == INT_MAX && delim_ == EOF) {
00316         char buf[PGSIZE];
00317         while ((b = read (buf, PGSIZE))) {
00318             count += b;
00319         }
00320         setstate (Socket::eofbit|Socket::failbit);
00321         return count;
00322     }
00323     for (; n_; n_--, count++) {
00324         if ( (b = read (&c, 1)) == 0 ) {
00325             setstate (Socket::eofbit|Socket::failbit);
00326             break;
00327         }
00328         if ( c == delim_ )
00329             break;
00330     }
00331     return count;
00332 }
00333 
00334 //-----------------------------------------------------------------------------
00335 //                         Input operators
00336 //-----------------------------------------------------------------------------
00337 
00357 Socket& 
00358 Socket::
00359 operator>>(char& n_) 
00360 {
00361 
00362     int c = 0;
00363     int len = sizeof (int);
00364     XDR xdrs; 
00365     xdrmem_create (&xdrs, (caddr_t) &c, len, XDR_DECODE); 
00366 
00367     if (read ((char* ) &c, len) == len) { 
00368         xdr_char (&xdrs, &n_); 
00369     } 
00370     else { 
00371         setstate (Socket::eofbit|Socket::failbit); 
00372     } 
00373     xdr_destroy(&xdrs); 
00374     return *this; 
00375 }
00376 
00379 Socket& 
00380 Socket::
00381 operator>> (std::string& s_) 
00382 {
00383     char c = 0;
00384     size_t n = 0;
00385     s_ = "";
00386 
00387     (*this) >> n;
00388 
00389     if (n == 0) {
00390         return *this;
00391     }
00392     size_t len = n;
00393     while (len-- && read (&c, 1) == 1) {
00394         s_ += c;
00395     }
00396     ignore (4 - n % 4);
00397     return *this; 
00398 }
00399 
00400 Socket& 
00401 Socket::
00402 operator>> (short& n_)
00403 {
00404     short val;
00405     if (read ((char*) &val, sizeof(short)) == sizeof(short)) {
00406         n_ = (short) ntohs ((short)val);
00407     }
00408     else {
00409         setstate (Socket::eofbit|Socket::failbit);
00410     }
00411     return *this;
00412 }
00413 
00414 Socket& 
00415 Socket::
00416 operator>> (unsigned short& n_) 
00417 {
00418     u_short val;
00419     if (read ((char*) &val, sizeof(u_short)) == sizeof(u_short)) {
00420         n_ = (u_short) ntohs ((u_short)val);
00421     }
00422     else {
00423         setstate (Socket::eofbit|Socket::failbit);
00424     }
00425     return *this;
00426 }
00427 
00428 #define LONGEST long
00429 
00430 /* On 64-bit platforms, sizeof (long) = 8 bytes. 
00431  * ntohl()/htonh() operats only on int32_t types which is 4 bytes long
00432  * everywhere. So, for 64-bit longs we need to process twice as much
00433  * and swapt data accordingly.
00434  */
00435 
00436 #define READ_INT(TYPE) \
00437 Socket& Socket::operator>>(TYPE& n_) \
00438 {\
00439     LONGEST val;\
00440     int typesz = sizeof(TYPE);\
00441     if (read ( (char* ) &val, typesz) == typesz) {\
00442         if (sizeof(int32_t) <= typesz) {\
00443             n_ = (TYPE) ntohl (val);   \
00444         }\
00445         else {\
00446             if (Socket::is_little_endian ()) {\
00447                 *((int32_t*)(&n_)+1) = ntohl (*((int32_t*)(&val))  );\
00448                 *((int32_t*)(&n_)  ) = ntohl (*((int32_t*)(&val))+1);\
00449             }\
00450             else {\
00451                 *((int32_t*)(&n_)  ) = ntohl (*((int32_t*)(&val))  );\
00452                 *((int32_t*)(&n_)+1) = ntohl (*((int32_t*)(&val))+1);\
00453             }\
00454         }\
00455     }\
00456     else {\
00457         setstate (Socket::eofbit|Socket::failbit);\
00458     }\
00459     return *this;\
00460 }
00461 
00462 READ_INT(int);
00463 READ_INT(unsigned int);
00464 READ_INT(long);
00465 READ_INT(unsigned long);
00466 
00467 Socket& 
00468 Socket::
00469 operator>> (float& n_) 
00470 {
00471     float val; 
00472     XDR xdrs; 
00473     xdrmem_create (&xdrs, (caddr_t) &val, sizeof(float), XDR_DECODE); 
00474 
00475     if (read ((char*) &val, sizeof(float)) == sizeof(float)) { 
00476         xdr_float (&xdrs, &n_); 
00477     } 
00478     else { 
00479         setstate (Socket::eofbit|Socket::failbit); 
00480     } 
00481     xdr_destroy (&xdrs); 
00482     return *this; 
00483 }
00484 
00485 Socket& 
00486 Socket::
00487 operator>> (double& n_) 
00488 {
00489     double val = 0; 
00490     XDR xdrs; 
00491     xdrmem_create (&xdrs, (caddr_t) &val, sizeof(double), XDR_DECODE); 
00492     if (read ((char*) &val, sizeof(double)) == sizeof(double)) { 
00493         xdr_double (&xdrs, &n_); 
00494     } 
00495     else { 
00496         setstate (Socket::eofbit|Socket::failbit); 
00497     } 
00498     xdr_destroy (&xdrs); 
00499     return *this; 
00500 }
00501 
00502 //-----------------------------------------------------------------------------
00503 //                          Output operators
00504 //-----------------------------------------------------------------------------
00505 
00506 Socket& 
00507 Socket::
00508 operator<< (char n_) 
00509 { 
00510     /* See comment to operator>>(char n_) */
00511 
00512     int buf = 0;
00513     int len = sizeof (int);
00514     XDR xdrs; 
00515 
00516     xdrmem_create (&xdrs, (caddr_t) &buf, len, XDR_ENCODE); 
00517     xdr_char (&xdrs, &n_); 
00518 
00519     if (write ((const char*) &buf, len) != len) {
00520         (Socket::eofbit|Socket::failbit); 
00521     }
00522     xdr_destroy (&xdrs); 
00523     return *this; 
00524 }
00525 
00544 Socket& 
00545 Socket::
00546 operator<< (const std::string& s_) 
00547 { 
00548     static const char pad [4] = { 0, 0, 0, 0 };
00549 
00550     (*this) << s_.length ();
00551     int ret = write (s_.c_str (), s_.length ());
00552     if ( ret != s_.length () ) { 
00553         setstate (Socket::eofbit|Socket::failbit); 
00554     } 
00555     size_t r = 4 - s_.length() % 4;
00556     if (r) {
00557         if (write (pad, r) != r) {
00558             setstate (Socket::eofbit|Socket::failbit); 
00559         }
00560     }
00561     return *this;
00562 }
00563 
00564 Socket& Socket::
00565 operator<< (short n_) 
00566 { 
00567     short val = (short) htons((short)n_);
00568 
00569     if (write ((const char*) &val, sizeof(short)) != sizeof(short)) 
00570     {
00571         setstate (Socket::eofbit|Socket::failbit);
00572     }
00573     return *this;
00574 }
00575 
00576 Socket& Socket::
00577 operator<< (unsigned short n_) 
00578 { 
00579     u_short val = (u_short) htons((u_short)n_);
00580 
00581     if (write ((const char*) &val, sizeof(u_short)) != sizeof(u_short)) 
00582     {
00583         setstate (Socket::eofbit|Socket::failbit);
00584     }
00585     return *this;
00586 }
00587 
00588 #define WRITE_INT(TYPE) \
00589 Socket& Socket::operator<< (TYPE n_) \
00590 { \
00591     LONGEST val;\
00592     int typesz = sizeof(TYPE);\
00593     if (sizeof(int32_t) <= typesz) {\
00594         val = (TYPE) ntohl (n_);   \
00595     }\
00596     else {\
00597         if (Socket::is_little_endian ()) {\
00598             *((int32_t*)(&val)+1) = htonl (*((int32_t*)(&n_))  );\
00599             *((int32_t*)(&val)  ) = htonl (*((int32_t*)(&n_))+1);\
00600         }\
00601         else {\
00602             *((int32_t*)(&val)  ) = htonl (*((int32_t*)(&n_))  );\
00603             *((int32_t*)(&val)+1) = htonl (*((int32_t*)(&n_))+1);\
00604         }\
00605     }\
00606     if (write ((const char*) &val, typesz) != typesz) {\
00607         setstate (Socket::eofbit|Socket::failbit);\
00608     }\
00609     return *this;\
00610 }
00611 
00612 WRITE_INT(int);
00613 WRITE_INT(unsigned int);
00614 WRITE_INT(long);
00615 WRITE_INT(unsigned long);
00616 
00617 Socket& 
00618 Socket::
00619 operator<< (float n_) 
00620 { 
00621     float buf, f = n_; 
00622     XDR xdrs; 
00623     xdrmem_create (&xdrs, (caddr_t) &buf, sizeof(float), XDR_ENCODE); 
00624     xdr_float (&xdrs, &f); 
00625 
00626     int ret = write ((const char*) &buf, sizeof(float)); 
00627     xdr_destroy (&xdrs); 
00628     if ( ret != sizeof(float) ) { 
00629         setstate (Socket::eofbit|Socket::failbit); 
00630     } 
00631     return *this; 
00632 }
00633 
00634 Socket& 
00635 Socket::
00636 operator<< (double n_) 
00637 { 
00638     double buf, f = n_; 
00639     XDR xdrs; 
00640     xdrmem_create (&xdrs, (caddr_t) &buf, sizeof(double), XDR_ENCODE); 
00641     xdr_double (&xdrs, &f); 
00642 
00643     int ret = write ((const char*) &buf, sizeof(double)); 
00644     xdr_destroy (&xdrs); 
00645     if ( ret != sizeof(double) ) { 
00646         setstate (Socket::eofbit|Socket::failbit); 
00647     } 
00648     return *this; 
00649 }
00650 
00651 void 
00652 Socket::
00653 dumpState (void) const
00654 {
00655     trace_with_mask("Socket::dumpState",SOCKTRACE);
00656 
00657     char state_set[]    = "[    set]\n";
00658     char state_not_set[] = "[not set]\n";
00659 
00660     std::ostringstream msg;
00661 
00662     msg << "\n";
00663     msg << "\tTesting good() ....... ";
00664 
00665     if (this->good ()) msg << state_set;
00666     else msg << state_not_set;
00667 
00668     msg << "\tTesting eof() ........ ";
00669     if (this->eof ()) msg << state_set;
00670     else msg << state_not_set;
00671 
00672     msg << "\tTesting fail() ....... ";
00673     if (this->fail ()) msg << state_set;
00674     else msg << state_not_set;
00675 
00676     msg << "\tTesting bad() ........ ";
00677     if (this->bad ()) msg << state_set;
00678     else msg << state_not_set;
00679 
00680     msg << "\tTesting !() .......... ";
00681     if ( !(*this) ) msg << state_set;
00682     else msg << state_not_set;
00683 
00684     msg << "\tTesting void *() ..... ";
00685     if ( *this ) msg << state_set;
00686     else msg << state_not_set;
00687 
00688     msg << "\tTesting nonblocking... ";
00689     if (getOption (nonblocking) == 1) msg << state_set;
00690     else msg << state_not_set;
00691 
00692     /*--- Terminate stream buffer ---*/
00693     msg << std::ends;
00694 
00695     DL((SOCKTRACE,"%s\n", msg.str ().c_str ()));
00696 }
00697 
00698 bool
00699 Socket::
00700 is_little_endian ()
00701 {
00702     union {
00703         char  c [sizeof (short)];
00704         short v;
00705     } endian_u;
00706 
00707     endian_u.v = 256;
00708     return (endian_u.c [0] == 0);
00709 }
00710 
00711 string
00712 Socket::
00713 decode_fcntl_flags (long mask_)
00714 {
00715     string answer;
00716 
00717     if (mask_ & O_RDONLY) {
00718         answer = "O_RDONLY|";   // 000000
00719     }
00720     if (mask_ & O_WRONLY) {
00721         answer += "O_WRONLY|";  // 000001
00722     }
00723     if (mask_ & O_RDWR) {
00724         answer += "O_RDWR|";    // 000002
00725     }
00726     if (mask_ & O_APPEND) {
00727         answer += "O_APPEND|";  // 001000
00728     }
00729     if (mask_ & O_NONBLOCK) {
00730         answer += "O_NONBLOCK|";// 004000
00731     }
00732     if (mask_ & O_SYNC) {
00733         answer += "O_SYNC|";    // 010000
00734     }
00735 
00736     if (mask_ & O_ASYNC) {      // 020000
00737         answer += "O_ASYNC|";
00738     }
00739 
00740     answer.erase (answer.end () - 1);
00741 
00742     return answer;
00743 }

Generated on Sun Aug 13 15:08:00 2006 for libassa by  doxygen 1.4.6