Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

TCP_sock.H

Go to the documentation of this file.
00001 // Copyright (C) 2001, Compaq Computer Corporation
00002 // 
00003 // This file is part of Vesta.
00004 // 
00005 // Vesta is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU Lesser General Public
00007 // License as published by the Free Software Foundation; either
00008 // version 2.1 of the License, or (at your option) any later version.
00009 // 
00010 // Vesta is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 // Lesser General Public License for more details.
00014 // 
00015 // You should have received a copy of the GNU Lesser General Public
00016 // License along with Vesta; if not, write to the Free Software
00017 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 
00019 // Last modified on Sun May 22 22:52:41 EDT 2005 by ken@xorian.net  
00020 //      modified on Wed Sep  6 17:53:32 PDT 2000 by mann  
00021 //      modified on Fri Aug 22 00:37:26 PDT 1997 by heydon
00022 //      modified on Fri Sep 27 13:35:55 PDT 1996 by sirer
00023 //      modified on Tue Jul  2 15:37:22 PDT 1996 by levin
00024 
00025 //  *******************************
00026 //  *  TCP sockets for pseudo RPC *
00027 //  *******************************
00028 
00029 // See end of this file for an overview.
00030 
00031 #ifndef _TCP_sock
00032 #define _TCP_sock
00033 
00034 #include <netdb.h>  // network host database access
00035 #include <Basics.H>
00036 #include <OS.H>
00037 
00038 extern "C" void TCP_sock_init();
00039 
00040 class TCP_sock {
00041 public:
00042 
00043   // Error reporting
00044   enum {
00045     wrong_state          =  -1,   // inappropriate time to attempt function
00046     internal_trouble     =  -2,   // probable bug in TCP_sock implementation
00047     environment_problem  =  -3,   // unexpected external environment state
00048     unknown_host         =  -4,
00049     unknown_port         =  -5,
00050     invalid_parameter    =  -6,
00051     partner_went_away    =  -7,
00052     read_timeout         =  -8,    // no data from peer for too long
00053     end_of_file =         partner_went_away
00054     };
00055   struct failure {
00056     int reason;
00057     int err_no;
00058     Text msg;
00059     inline failure(int r, const Text &msg, int err_no = 0) {
00060       this->reason = r; this->msg = msg; this->err_no = err_no; };
00061     inline failure(const failure &f) {
00062       this->reason = f.reason; this->msg = f.msg; this->err_no = f.err_no; };
00063     inline failure& operator=(const failure &f) {
00064       this->reason = f.reason; this->msg = f.msg; this->err_no = f.err_no;
00065       return *this; };
00066   };
00067 
00068   struct alerted { };
00069     // optionally thrown by wait_for_connect and recv_data
00070 
00071   //
00072   // Construction
00073   //
00074 
00075   TCP_sock(u_short port = 0) throw (failure);
00076 
00077   ~TCP_sock() throw (failure);
00078 
00079   //
00080   // Optional configuration
00081   //
00082 
00083   enum {default_sndbuffer_size = 8192, default_rcvbuffer_size = 8192};
00084 
00085   void set_output_buffer_size(int bytes = default_sndbuffer_size)
00086     throw (failure);
00087     // By default, a buffer size of "default_sndbuffer_size" is used for
00088     // output.  However, this number can be adjusted by calling this 
00089     // procedure before the first "send_data" operation.
00090 
00091   void set_input_buffer_size(int bytes = default_rcvbuffer_size)
00092     throw (failure);
00093     // By default, a buffer size of "default_buffer_size" is used for
00094     // output.  However, this number can be adjusted by calling this 
00095     // procedure before the first "recv_data" operation.
00096 
00097   void enable_alerts() throw (failure);
00098   void disable_alerts() throw (failure);
00099     // These operations enable/disable the alert mechanism, which is
00100     // used to terminate an otherwise unbounded wait in recv_data and
00101     // wait_for_connect.
00102 
00103   void alert() throw (failure);
00104     // If alerts have not been enabled (see "enable_alerts", above), this
00105     // operation throws failure.  Otherwise, it sets the alert flag in the
00106     // TCP_sock.  Additionally, if another thread is presently waiting in
00107     // recv_data or wait_for_connect, the wait is terminated and "alerted"
00108     // is thrown by the operation.
00109 
00110   bool test_alert() throw (failure);
00111     // If alerts have not been enabled (see "enable_alerts", above), this
00112     // operation throws failure.  Otherwise, it returns the present value
00113     // of the alert flag and sets the flag to false.
00114 
00115   void set_keepalive(bool state)  throw (failure);
00116   inline void enable_keepalive() throw (failure)
00117     { set_keepalive(true); }
00118   void disable_keepalive() throw (failure)
00119     { set_keepalive(false); }
00120   bool get_keepalive() throw (failure);
00121     // Enable, disable, or check for the use of the TCP keep-alive
00122     // timer (set by the SO_KEEPALIVE socket option).  This provides
00123     // for detection of a peer whose system has crashed, rebooted, or
00124     // which is no longer reachable.  (See the setsockopt(2) and/or
00125     // socket(7) man pages for more information.)
00126 
00127   void enable_read_timeout(unsigned int seconds) throw (failure);
00128   void disable_read_timeout() throw (failure);
00129   inline bool get_read_timeout(/*OUT*/ unsigned int &seconds) throw()
00130     {
00131       if(read_timeout_enabled)
00132         seconds = read_timeout_secs;
00133       return read_timeout_enabled;
00134     }
00135     // Enable, disable, or check the setting of the read timeout
00136     // feature.  This makes it possible to set an upper limit on the
00137     // amount of time spent waiting for data from a peer.  This
00138     // feature can be used by servers to prevent holding a resource
00139     // for an indefinite amount of time due to suspended or
00140     // misbehaving clients.
00141   
00142   //
00143   // Interrogation
00144   //
00145 
00146   static Text this_host() throw (failure);
00147     // returns a/the name of this host.
00148 
00149   void get_local_addr(/*OUT*/ sockaddr_in &addr) throw (failure);
00150     // 'addr' is filled in with the local socket address (in network byte
00151     // order) of this socket.
00152 
00153   void get_remote_addr(/*OUT*/ sockaddr_in &addr) throw (failure);
00154     // 'addr' is filled in with the remote (i.e., connected) socket address
00155     // (in network byte order), if any.  If the socket is not connected,
00156     // failure is thrown.
00157 
00158   bool alive() throw (failure);
00159     // This function should be used only for a connected socket (i.e.,
00160     // a socket returned by 'wait_for_connect' or one on which 'connect_to'
00161     // has been successfully executed.)  It attempts to determine if the
00162     // connection is intact.  A 'false' result means the connection is
00163     // definitely broken; a 'true' return strongly suggests, but does not
00164     // guarantee, that a subsequent 'recv_data' or 'send_data' will
00165     // succeed.
00166 
00167   static u_short parse_port(const Text &port) throw (failure);
00168     // This is a utility routine that translates parses a text string
00169     // specifying a port.  If it can be parsed as a decimal number, it
00170     // is taken to be an explicit port number.  Otherwise, 'port' is
00171     // looked up as a service in the network database; if it can't be
00172     // found there, 'failure' is thrown.  Note that the port number is
00173     // returned in host byte order, not network byte order.
00174 
00175   static in_addr host_to_addr(const Text &hostname) throw (failure);
00176     // This is a utility routine that translates a hostname to an IPv4
00177     // Internet address.  If 'hostname' can be parsed as four decimal
00178     // numbers separated by periods, it is taken to be an explicit
00179     // (numeric) IP address.  Otherwise, 'hostname' is looked up in
00180     // the network naming database; if it can't be found there,
00181     // 'failure' is thrown.  If 'hostname' resolves to a non-IPv4
00182     // address, failure is thrown.  (IPv6 is not yet supported by
00183     // TCP_sock.)
00184 
00185   static void name_to_sockaddr(const Text &hostname,
00186     const Text &port, /*OUT*/ sockaddr_in &s) throw (failure);
00187     // This is a utility routine that translates a hostname and port
00188     // to a socket address.  If the translation is successful, the
00189     // socket address 's' is returned in network byte order.
00190     // If 'hostname' is empty, the local host's name is used.  If 'hostname'
00191     // can be parsed as four decimal numbers separated by periods, it is
00192     // taken to be an explicit (numeric) IP address.  Otherwise, 'hostname'
00193     // is looked up in the network naming database; if it can't be found
00194     // there, 'failure' is thrown.
00195     // 'port' is interpreted as follows.  If it can be parsed as a
00196     // decimal number, it is taken to be an explicit port number.
00197     // Otherwise, 'port' is looked up as a service in the network
00198     // database; if it can't be found there, 'failure' is thrown.
00199 
00200   static void name_to_sockaddr(const Text &host_and_port,
00201     /*OUT*/ sockaddr_in &s) throw (failure);
00202     // This is an alternative form of the preceding procedure.  It is
00203     // semantically equivalent to:
00204     //   int i = host_and_port.FindCharR(':');
00205     //   if (i < 1) throw (failure(...));
00206     //   name_to_sockaddr(host_and_port.Sub(0, i), host_and_port.Sub(i+1), s);
00207 
00208   fd_t get_fd() throw () { return fd; };
00209     // returns the Unix file descriptor associated with the socket
00210 
00211   //
00212   // Client
00213   //
00214 
00215   void connect_to(const Text &hostname, const Text &port) throw (failure);
00216     // "hostname" may be "abc" or "w.x.y.z".  "port" may be either
00217     // a service name or a decimal number.
00218 
00219   void connect_to(const Text &host_and_port) throw (failure);
00220     // Semantically equivalent to:
00221     //   int i = host_and_port.FindCharR(':');
00222     //   if (i < 1) throw (failure(...));
00223     //   connect_to(host_and_port.Sub(0, i), host_and_port.Sub(i+1));
00224 
00225   void connect_to(sockaddr_in &addr) throw (failure);
00226     // 'addr' contains a socket address in network byte order.
00227 
00228   //
00229   // Listener
00230   //
00231 
00232   void set_waiters(int waiters = 1) throw (failure);
00233     // See description under overview, below.
00234 
00235   TCP_sock *wait_for_connect() throw (alerted, failure);
00236     // See description under overview, below.
00237 
00238   //
00239   // Data transmission
00240   //
00241 
00242   void send_data(const char *buffer, int len, bool flush = false)
00243     throw (failure);
00244 
00245   inline void flush() throw (failure) { send_data(NULL, 0, true); };
00246 
00247   int recv_data(char *buffer, int len) throw (alerted, failure);
00248     // Waits until at least one byte of data is available, then places
00249     // at most "len" bytes in the buffer defined by "buffer".  The number
00250     // of bytes stored is returned as the result, which will never be zero.
00251     // Note that "end of file" is reported as a specific failure reason.
00252     // If the alert flag associated with the TCP_sock is set either at
00253     // entry or while recv_data is blocked, "alerted" is raised.  See
00254     // description of "alert".
00255 
00256 private:
00257 
00258   // A TCP_sock should neither be copied nor assigned.
00259 
00260   TCP_sock(TCP_sock&);
00261 
00262   void operator=(TCP_sock&);
00263 
00264   // Constructor for creating a TCP_sock without an underlying socket
00265   // (used when accepting connections).  We use an otherwise unused
00266   // non-integer type to disambiguate calls of this constructor from
00267   // the default (declared above).
00268   struct empty_sock_marker { empty_sock_marker() { } };
00269   TCP_sock(const empty_sock_marker &) throw (TCP_sock::failure);
00270 
00271   // data fields
00272   Basics::mutex m;              // protects most of the following fields
00273 
00274   enum sock_state { fresh, listening, connected, dead };
00275   sock_state state;
00276                                 // These are in network byte order:
00277   sockaddr_in me;               // local IP address/port
00278   sockaddr_in him;              // remote IP address/port, if connected
00279   fd_t fd;                      // file descriptor
00280   char *sndbuff;                // output buffer
00281   int sndbuff_len;              // current number of bytes
00282   int sndbuff_size;             // allocated size
00283   char *rcvbuff;                // input buffer
00284   char *rcvcurp;                // current read location
00285   char *rcvend;                 // end of valid data in the read buffer
00286   int rcvbuff_size;             // input buffer size
00287 
00288   bool non_blocking;
00289 
00290   bool alerts_enabled;
00291   bool alert_flag;
00292   fd_t pipe_wr;                 // pipe fd's used to implement alert channel
00293   fd_t pipe_rd;
00294   int bytes_in_pipe;
00295 
00296   // Optional timeout on reading data from the peer.
00297   bool read_timeout_enabled;
00298   unsigned int read_timeout_secs;
00299 
00300   // member functions
00301 
00302   static void init() throw (failure);
00303   friend void TCP_sock_init();
00304   static void ensure_init() throw (failure);
00305   static void set_no_delay(int fd) throw (failure);
00306 
00307   void new_socket(u_short port) throw (failure);
00308   void instance_init() throw();
00309   void ensure_state(sock_state should_be) throw (failure);
00310   void ensure_sndbuffer() throw ();
00311   void ensure_rcvbuffer() throw ();
00312   void configure_blocking() throw (failure);
00313   void controlled_wait() throw (alerted, failure);
00314   int  fill_rcvbuffer() throw (alerted, failure);
00315 
00316   // static data; filled in by "init"
00317   static pthread_once_t init_block;
00318   static Text my_hostname;
00319   static sockaddr_in defaultsock;  // default values for sockect creation
00320   static in_addr self_addr;        // address of our hostname
00321   static int tcp_protolevel;
00322 
00323 #if defined(__linux__)
00324   // glibc 2.1... and 2.2... have a problem with gethostbyname_r and
00325   // perhaps getservbyname_r  -- they aren't really all that re-entrant.
00326   // so we mutex them for linux. 
00327   static Basics::mutex ndb_mutex;
00328 #endif
00329 };
00330 
00331 /*
00332 Overview of TCP_sock
00333 --------------------
00334 
00335 This class provides TCP-based sockets intended specifically to support
00336 simple RPC's (SRPC).  It makes no attempt to provide comprehensive
00337 TCP functionality.
00338 
00339 A TCP_sock is constructed by optionally supplying an IP address and/or
00340 port number.  If the IP address is omitted, the primary address of the
00341 local host machine is used.  If the port is 0, the implementation
00342 chooses a suitable value.  In either case, the resulting object is
00343 assigned a file descriptor (used internally) which is bound, in the
00344 sense of bind(2), to the specified IP address and port.
00345 
00346 A newly-created TCP_sock may be either used to connect to a specified
00347 address or to listen for connection requests.  For the former purpose,
00348 the client calls connect_to, specifying the socket address (IP address and
00349 port) to which the connection is to be made.
00350 
00351 To listen on a TCP_sock, a client optionally invokes set_waiters,
00352 specifying the number of incoming requests that will be buffered
00353 (rather than rejected) while the client is busy with other things.  To
00354 receive an incoming request, the client calls wait_for_connect, which
00355 waits for a request to arrive (if necessary), creates a new TCP_sock
00356 object, and connects it to the IP address/port provided by the
00357 requestor.  This object is returned by wait_for_connect.
00358 
00359 Data transmission is buffered.  To send data, the client invokes send_data,
00360 specifying an address and byte count.  The data is taken from the specified
00361 location and buffered.  The buffer is flushed when it becomes full or when
00362 send_data is called with its third parameter set to true.
00363 
00364 By default, data reception is synchronous; that is the recv_data function
00365 blocks until data arrives.  However, the client may optionally enable either
00366 or both of two mechanisms to prevent recv_data from blocking indefinitely.
00367 First, a TCP_sock may be marked as alertable, using the enable_alerts
00368 function.  On such a socket recv_data blocks until either data arrives or
00369 until another thread invokes the alert function.  In the latter case, recv_data
00370 throws 'alerted'.
00371 
00372 Wherever socket addresses are visible through this interface, their fields
00373 are maintained in network byte-order.  This follows the conventions used
00374 by the network database routines, but can lead to surprises if clients
00375 construct socket addresses piecemeal.
00376 
00377 A TCP_sock is inherently a sequentially-used object.  Multi-threaded access
00378 to a TCP_sock by a  client must be synchronized by the client.
00379 
00380 
00381 */
00382 
00383 #endif  /* _TCP_sock */

Generated on Mon May 8 00:48:57 2006 for Vesta by  doxygen 1.4.2