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 */