00001 #ifndef DV_SOCKET_H 00002 #define DV_SOCKET_H 00003 // $Id: socket.h,v 1.23 2008/03/15 16:55:07 dvermeir Exp $ 00004 00005 #include <iostream> 00006 #include <dvutil/debug.h> 00007 #include <dvutil/shared_ptr.h> 00008 #include <dvutil/fdstreambuf.h> 00009 #include <dvnet/inetaddress.h> 00010 00011 /** @file 00012 * The Dv::Net::Socket class provides a network connection as an iostream. 00013 */ 00014 namespace Dv { 00015 namespace Net { 00016 /** 00017 * Provide a network connection as an iostream. 00018 * 00019 * Example usage: 00020 * @code 00021 * Dv::Net::Socket so("tinf2.vub.ac.be",8000) 00022 * if (so) { 00023 * so << "request" << std::endl; 00024 * std::string line; 00025 * while (std::getline(so,line)) 00026 * process_answer(line); 00027 * if (so.timedout()) 00028 * std::cerr << "Connection timed out" << std::endl; 00029 * } 00030 * else { 00031 * cerr << so.strerror() << endl; 00032 * } 00033 * @endcode 00034 */ 00035 class Socket: public std::iostream, public DebugSlave { 00036 public: 00037 /** Status codes, positive numbers are reserved for copies of the system errno. */ 00038 enum SOCKET_ERRORS { OK = 0, UNKNOWN_HOST = -1, CLOSED = -2, ACCEPT_ERROR = -3, 00039 WRONG_FAMILY = -4, EOFBIT = -5, BADBIT = -6, FAILBIT = -7, LA_ERROR = -8, 00040 MAX_ERRNO = -8 }; 00041 /** 00042 * Set up a client connection to a host:port. 00043 * 00044 * @param host name of host to connect to. 00045 * @param port number of port to connect to. 00046 * @param bufsz size (in bytes) of input and output buffers. 00047 * @param delay (in milliseconds) time allowed for any I/O operation 00048 * to complete, including the present connection to a server. 00049 * A value of 0 means ``wait forever''. Note 00050 * that timedout() makes no sense if delay is 0. 00051 * @param non_blocking if true, the underlying fdstreambuf will be 00052 * non-blocking which prevents some cases of blocking I/O operations. 00053 * @param localaddr local address to bind to. 00054 * @param min_debug_level if a debug_master is connected, logging info 00055 * will only be written if the master's level is at least @a min_debug_level 00056 * @param debug_master from where debug info will be taken 00057 * @see Dv::DebugSlave 00058 * @see Dv::Net::Socket::timedout, Dv::Net::Socket::connected, Dv::Util::fdstreambuf, Dv::Net::Socket::debug 00059 */ 00060 Socket(const std::string& host, int port, size_t bufsz=1024, 00061 time_t delay=0, bool non_blocking=false, const std::string& localaddr = std::string(), 00062 unsigned int min_debug_level = 0, Debugable* debug_master = 0); 00063 /** Copy ctor. This function constructs a new Socket (iostream) and 00064 * associated fdstreambuf, based a new filedescriptor, obtained from 00065 * this Socket's file descriptor This function was introduced to 00066 * allow concurrent reading and writing to a connection (from 00067 * different threads). Experiments to do this failed when using the 00068 * same Socket object. If the writer uses a copy of the original 00069 * (which is used by the reader), the experiment works fine. 00070 * @param so socket whose file descriptor will be used to construct a 00071 * ``copy'' 00072 * @warning Closing a socket also shuts it down using shutdown(2) with 00073 * the SHUT_RDWR option, making all copies of this Socket unusable. However, 00074 * the underlying file descriptors of these copies are not closed. To 00075 * avoid a memory leak, they should be closed as well. 00076 */ 00077 Socket(const Socket& so); 00078 /** 00079 * Duplicate a socket. 00080 * @return reference to copy of this Socket 00081 * @see Dv::Net::Socket::Socket(const Socket& so) 00082 */ 00083 Dv::shared_ptr<Socket> dup(); 00084 /** Destructor. Also closes socket using close(). 00085 * @see Dv::Net::Socket::close 00086 */ 00087 virtual ~Socket(); 00088 /** Close underlying socket. This also does a @a shutdown(2) with the 00089 * @a SHUT_RDWR which prevents any transmissions and should 00090 * make all pending I/O calls return with an error. 00091 * @see Dv::Net::Socket::~Socket 00092 */ 00093 void close(); 00094 /** Try to (re)connect to the same host/port. 00095 * @param delay (in milliseconds) time allowed for the connection to complete. 00096 * A value of 0 means ``wait forever''. 00097 * @return true iff the connect operation succeeded. 00098 * If the constructor failed, it is possible to retry using connect(). 00099 * This may occur e.g. if the client is able to launch the server. 00100 * Note the delay parameter: when launching the server, at least 00101 * Solaris 7 needs a delay (e.g. 3 seems to work find). 00102 */ 00103 bool connect(unsigned int delay=0); 00104 /** Has the connection timed out? 00105 * @return true iff last operation timed out 00106 * @see Dv::Net::Socket::Socket() 00107 */ 00108 bool timedout() const; 00109 /** Set timedout flag. Usually, the argument will be "false", such 00110 * that further I/O on the socket becomes possible. 00111 * @param new_timedout_status: true or (usually) false 00112 * @return true iff status change succeeded. It will fail e.g. if 00113 * the argument is "false" and the socket had not actually timed out, 00114 * or if the argument is "true" and socket status was not Socket::OK. 00115 * @code 00116 * Dv::shared_ptr<Dv::Net::Socket> s; 00117 * size_t tries(0); 00118 * std::string line; 00119 * while ( (! std::getline(*s, line) ) && (++tries <3) ) 00120 * if (s->timedout()) 00121 * s->timedout(false); 00122 * else { 00123 * std::cerr << "I/O error: " << s->strerror() << std::endl; 00124 * break; 00125 * } 00126 * @endcode 00127 * @see Dv::Net::Socket::Socket() Dv::Net::Socket::timedout() 00128 */ 00129 bool timedout(bool new_timedout_status); 00130 /** The port number of the socket. 00131 * @return the port number of the socket. 00132 */ 00133 int port() const { return port_; } 00134 /** @return Dv::Net::InetAddress this socket refers (points) to. 00135 * @invariant inet_address() != 0 00136 */ 00137 Dv::shared_ptr<Dv::Net::InetAddress> inet_address() const { return inet_address_; } 00138 /** @return host name of Socket. If possible, the domain name is returned, 00139 * otherwise, the dot address string is returned. 00140 * @exception std::runtime_error if inet_address() returns 0. 00141 */ 00142 std::string host(bool use_dot_address = false) const throw (std::runtime_error); 00143 /** Make a string representation of the socket. It has 00144 * the form 'host.domain:8000', i.e. 'hostname:portnumber'. 00145 * @see Dv::Net::Socket::host 00146 */ 00147 std::string tostring(bool use_dot_address = false) const throw (); 00148 /** @return true iff last call to connect() was succesful. 00149 * @see connect, Socket::Socket 00150 */ 00151 bool connected() const { return connected_; } 00152 /** 00153 * @return status of Socket, only 0 is ok. 00154 * 00155 * A status of 0 means ok, positive integers correspond to system 00156 * errno values (man 2 errno). Negative numbers correspond to 00157 * ``specific'' errors for the Socket class (or its subclasses). 00158 * 00159 * The values EOFBIT, FAILBIT or BADBIT will be returned if the 00160 * corresponding bit in iostate is turned on and no other specific 00161 * error was detected. 00162 * 00163 * @see Dv::Net::Socket::SOCKET_ERRORS 00164 */ 00165 int error() const; 00166 /** Return string representation of error(). 00167 * This function is virtual because subclasses may want to add 00168 * their own error messages (but the convention of using negative 00169 * numbers for local error codes and positive ones for ::errno 00170 * values should be adhered to). 00171 */ 00172 virtual std::string strerror() const; 00173 /** @return fdstreambuf associated with this socket or 0 if none. */ 00174 Dv::Util::fdstreambuf* rdbuf() const { 00175 return static_cast<Dv::Util::fdstreambuf*>(std::iostream::rdbuf()); 00176 } 00177 /** @return underlying file descriptor (may be <0 if no connection). */ 00178 int sfd() const { return (rdbuf()->fd()); } 00179 /** Create a new socket descriptor. 00180 * @param syserr will contain system errorcode (@a ::errno) if the 00181 * socket could not be created (and the return value is -1). 00182 * @return descriptor of a new socket or -1. 00183 * @see @a socket(2) 00184 */ 00185 static int mksocketfd(int& syserr); 00186 protected: 00187 /** Create a new socket and return associated fd, or -1 upon failure. 00188 * Upon failure, error will be set to the systems's errno. 00189 * @return descriptor of a new socket or -1. 00190 * @see Dv::Net::Socket::mksocketfd, Dv::Net::Socket::error 00191 */ 00192 int mkfd(); 00193 /** Set error status. 00194 * @param e new error status. 00195 * @see error() 00196 */ 00197 void error(int e); 00198 /** Constructor for use by derived classes. 00199 * This constructor can e.g. be used by a Dv::Socket specialization 00200 * that encrypts the data traffic (by means of a class derived from 00201 * fdstreambuf). This function does not attempt to connect to 00202 * the given host/port. 00203 * 00204 * @param host name of host to connect to. 00205 * @param port number of port to connect to. 00206 * @param buffer fdstreambuf to use. This buffer must have been dynamically 00207 * allocated because @a Socket::~Socket() will delete it. 00208 * @param min_debug_level if a debug_master is connected, logging info 00209 * will only be written if the master's level is at least @a min_debug_level 00210 * @param debug_master from where debug info will be taken 00211 * @see Dv::DebugSlave 00212 * @see Dv::Net::Socket::Socket, Dv::Net::Socket::debug 00213 */ 00214 Socket(const std::string& host, int port, Dv::Util::fdstreambuf* buffer, 00215 unsigned int min_debug_level = 0, Debugable* debug_master = 0); 00216 /** Constructor for use by derived classes. 00217 * This constructor can e.g. be used by a Dv::Net::Socket specialization 00218 * that encrypts the data traffic (by means of a class derived from 00219 * fdstreambuf). Dv::Net::Socket::get_peer() will be used to fill in host and port. 00220 * @param buffer Dv::Util::fdstreambuf to use. This buffer must have been dynamically 00221 * allocated because Dv::Net::Socket::~Socket() will delete it. 00222 * @param min_debug_level if a debug_master is connected, logging info 00223 * will only be written if the master's level is at least @a min_debug_level 00224 * @param debug_master from where debug info will be taken 00225 * @see Dv::DebugSlave 00226 * @see Dv::Net::Socket::get_peer, Dv::Net::Socket::debug 00227 */ 00228 Socket(Dv::Util::fdstreambuf* buffer, 00229 unsigned int min_debug_level = 0, Debugable* debug_master = 0); 00230 private: 00231 bool connect_to_host(const std::string& host); 00232 /** InetAddress this socket refers (points) to. */ 00233 Dv::shared_ptr<Dv::Net::InetAddress> inet_address_; 00234 /** Port number this socket refers to. */ 00235 int port_; 00236 /** Error status of socket. 00237 * @see Dv::Net::Socket::error 00238 */ 00239 mutable int errno_; 00240 /** Whether socket is connected. 00241 * @see Dv::Net::Socket::connected() 00242 */ 00243 bool connected_; 00244 /** InetAddress this socket is locally bound to. */ 00245 Dv::shared_ptr<Dv::Net::InetAddress> local_address_; 00246 /** No assignment. */ 00247 Socket& operator=(const Socket&); 00248 /** Set host_ and port_. 00249 * @see getpeername(2). 00250 */ 00251 bool get_peer(); 00252 /** Friend class that can use buf2socket() */ 00253 friend class ServerSocket; 00254 /** Used by ServerSocket. */ 00255 static Dv::shared_ptr<Socket> buf2socket(Dv::Util::fdstreambuf*); 00256 }; 00257 } 00258 } 00259 #endif 00260
dvnet-0.9.24 | [ 5 December, 2009] |