1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 | #ifndef STLPLUS_TCP_SOCKET #define STLPLUS_TCP_SOCKET //////////////////////////////////////////////////////////////////////////////// // Author: Andy Rushton // Copyright: (c) Southampton University 1999-2004 // (c) Andy Rushton 2004 onwards // License: BSD License, see ../docs/license.html // A platform-independent (Unix and Windows anyway) interface to TCP sockets //////////////////////////////////////////////////////////////////////////////// #include "portability_fixes.hpp" #include "ip_sockets.hpp" #include <string> namespace stlplus { ////////////////////////////////////////////////////////////////////////////// // Server Classes: A server creates a listening port which waits for incoming // connections. This is placed on the port number appropriate for the service // - for example, a Telnet server would typically use port 23. For a new // service you should of course use any port not allocated to a standard // service. I believe that RFC 1700 defines the standard service port numbers. // When an incoming connection is made, the server accepts it and in the // process creates a new connection on a different port. This leaves the // standard port listening for further connections. In effect, the server // farms out the handling of the connections themselves and only takes // responsibility for accepting the connection. This is reflected in the class // structure. A TCP_server performs the listening and accepting roles, but // creates a TCP_connection to handle the accepted connection. ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// // connection class created by TCP_server when a connection is accepted // this is then used to perform any communications with the remote client class TCP_connection : protected IP_socket { private : // constructor to actually initialise the class - can only be constructed by TCP_server friend class TCP_server; TCP_connection( const IP_socket& socket); public : //////////////////////////////////////////////////////////////////////////// // constructors/destructors // create an uninitialised connection TCP_connection( void ); //////////////////////////////////////////////////////////////////////////// // initialisation, connection control // Note: TCP connections can only be initialised by a TCP server // test whether this is an initialised socket // - returns whether this is initialised // bool initialised(void) const; using IP_socket::initialised; // close, i.e. disconnect the socket // - returns a success flag // bool close(void); using IP_socket::close; //////////////////////////////////////////////////////////////////////////// // sending/receiving // test whether a socket is connected and ready to send data, returns if ready or on timeout // - timeout: how long to wait in microseconds if not connected yet (blocking) // - returns status // bool send_ready(unsigned timeout = 0); using IP_socket::send_ready; // send data through the socket - if the data is long only part of it may // be sent. The sent part is removed from the data, so the same string can // be sent again and again until it is empty. // - data: string containing data to be sent - any data successfully sent is removed // - returns success flag // bool send (std::string& data); using IP_socket::send; // test whether a socket is connected and ready to receive data, returns if ready or on timeout // - timeout: how long to wait in microseconds if not connected yet (blocking) // - returns status // bool receive_ready(unsigned timeout = 0); using IP_socket::receive_ready; // receive data through the socket - if the data is long only part of it // may be received. The received data is appended to the string, building // it up in stages, so the same string can be received again and again // until all information has been received. // - data: string receiving data from socket - any data successfully received is appended // - returns success flag // bool receive (std::string& data); using IP_socket::receive; //////////////////////////////////////////////////////////////////////////// // informational // the local port number of the connection // - returns the port number, 0 if not bound to a port // unsigned short local_port(void) const; using IP_socket::local_port; // the remote address of the connection // - returns the address, 0 if not connected // unsigned long remote_address(void) const; using IP_socket::remote_address; // the remote port number of the connection // - returns the port number, 0 if not connected to a port // unsigned short remote_port(void) const; using IP_socket::remote_port; //////////////////////////////////////////////////////////////////////////// // error handling // errors are set internally // an error code of 0 is the test for no error, don't rely on the message being an empty string // an error code != 0 means an error, then there will be a message explaining the error // if an error is set it stays set - so you must clear it before further operations // void clear_error(void) const; using IP_socket::clear_error; // get the error code of the last error // int error(void) const; using IP_socket::error; // get the explanatory message of the last error // std::string message(void) const; using IP_socket::message; //////////////////////////////////////////////////////////////////////////// // deprecated version of remote_port unsigned short port( void ) const ; //////////////////////////////////////////////////////////////////////////// }; ////////////////////////////////////////////////////////////////////////////// // server class that does the listening on the designated port // incoming connections can be queued up to a maximum queue length specified // in the constructor/initialise class TCP_server : protected IP_socket { public : // create an uninitialised server TCP_server( void ); // initialise a socket and set it up to be a listening port // - port: port to listen on // - queue: length of backlog queue to manage - may be zero // - returns success status TCP_server( unsigned short port, unsigned short queue = 0); //////////////////////////////////////////////////////////////////////////// // initialisation // initialise a socket and set it up to be a listening port // - port: port to listen on // - queue: length of backlog queue to manage - may be zero // - returns success status bool initialise( unsigned short port, unsigned short queue = 0); // test whether this is an initialised socket // - returns whether this is initialised // bool initialised(void) const; using IP_socket::initialised; // close, i.e. disconnect the socket // - returns a success flag // bool close(void); using IP_socket::close; ////////////////////////////////////////////////////////////////////////////// // server operation - accepting a connection // test for a connection on the object's socket - only applicable if it has been set up as a listening port // - timeout: how long to wait in microseconds if not connected yet // - returns true if a connection is ready to be accepted // bool accept_ready(unsigned timeout = 0); using IP_socket::accept_ready; // accept a connection on the object's socket - only applicable if it has been set up as a listening port // - returns the connection as a new socket TCP_connection accept( void ); //////////////////////////////////////////////////////////////////////////// // error handling // errors are set internally // an error code of 0 is the test for no error, don't rely on the message being an empty string // an error code != 0 means an error, then there will be a message explaining the error // if an error is set it stays set - so you must clear it before further operations // void clear_error (void) const; using IP_socket::clear_error; // get the error code of the last error // int error(void) const; using IP_socket::error; // get the explanatory message of the last error // std::string message(void) const; using IP_socket::message; ////////////////////////////////////////////////////////////////////////////// // deprecated versions of accept_ready and accept bool connection_ready( unsigned timeout = 0); TCP_connection connection( void ); ////////////////////////////////////////////////////////////////////////////// }; //////////////////////////////////////////////////////////////////////////////// // Client Class: a client is simpler in that there is no listening port - you // just create a connection and get on with it. Thus the client class does the // whole job - create the connection and handle communications to/from it. // // Blocking mode: To use the client in blocking mode, use non-zero timeout for // the initialisation method. In this mode, the connection operation must // complete before the call will return or an error is indicated if the // timeout is reached without completion. This usage was designed for // applications which either just to TCP and nothing else or which do TCP // operations in a separate thread. // // Non-blocking mode: To use the client in non-blocking mode, use a zero // timeout for the initialisation method. Instead, you can ask it if it has // connected once you've initialised it. It is not an error for it to be // initialised but not connected. This usage was designed so that you can poll // the connection periodically to implement a timeout for as long as you like for // the connection to occur without blocking the thread that uses the client. // // In both modes, the send_ready/receive_ready methods can be called with any // timeout including zero. class TCP_client : protected IP_socket { public : // create an uninitialised client TCP_client( void ); // client connect to a server // - remote_address: IP name (stlplus.sourceforge.net) or dotted number (216.34.181.96) // - remote_port: port number of remote host // - timeout: if 0, don't wait; if >0 wait for that microseconds for connection to be confirmed TCP_client( const std:: string & remote_address, unsigned short remote_port, unsigned timeout = 0); // client connect to a server // - remote_address: IP address as a long integer - generated by stlplus::ip_lookup // - remote_port: port number of remote host // - timeout: if 0, don't wait; if >0 wait for that microseconds for connection to be confirmed TCP_client( unsigned long remote_address, unsigned short remote_port, unsigned timeout = 0); //////////////////////////////////////////////////////////////////////////// // initialisation, connection // function for performing IP lookup (i.e. gethostbyname) // could be standalone but making it a member means that it can use the socket's error handler // i.e. if this fails, the sockets error code will be set - clear it to use the socket again // - remote_address: IP name (stlplus.sourceforge.net) or dotted number (216.34.181.96) // - returns the IP address as a long integer - zero if there's an error // unsigned long ip_lookup(const std::string& remote_address); using IP_socket::ip_lookup; // client connect to a server // - remote_address: IP name (stlplus.sourceforge.net) or dotted number (216.34.181.96) // - remote_port: port number of remote host // - timeout: if 0, don't wait; if >0 wait for that microseconds for connection to be confirmed // - returns a success flag bool initialise( const std:: string & remote_address, unsigned short remote_port, unsigned timeout = 0); // client connect to a server // - remote_address: IP address as a long integer - generated by stlplus::ip_lookup // - remote_port: port number of remote host // - timeout: if 0, don't wait; if >0 wait for that microseconds for connection to be confirmed // - returns a success flag bool initialise( unsigned long remote_address, unsigned short remote_port, unsigned timeout = 0); // test whether this is an initialised socket // - returns whether this is initialised // bool initialised(void) const; using IP_socket::initialised; // test whether a socket is connected and ready to communicate, returns on successful connect or timeout // - timeout: how long to wait in microseconds if not connected yet // - returns success flag // bool connected(unsigned timeout = 0); using IP_socket::connected; // close, i.e. disconnect the socket // - returns a success flag // bool close(void); using IP_socket::close; //////////////////////////////////////////////////////////////////////////// // sending/receiving // test whether a socket is connected and ready to send data, returns if ready or on timeout // - timeout: how long to wait in microseconds if not connected yet (blocking) // - returns status // bool send_ready(unsigned timeout = 0); using IP_socket::send_ready; // send data through the socket - if the data is long only part of it may // be sent. The sent part is removed from the data, so the same string can // be sent again and again until it is empty. // - data: string containing data to be sent - any data successfully sent is removed // - returns success flag // bool send (std::string& data); using IP_socket::send; // test whether a socket is connected and ready to receive data, returns if ready or on timeout // - timeout: how long to wait in microseconds if not connected yet (blocking) // - returns status // bool receive_ready(unsigned timeout = 0); using IP_socket::receive_ready; // receive data through the socket - if the data is long only part of it // may be received. The received data is appended to the string, building // it up in stages, so the same string can be received again and again // until all information has been received. // - data: string receiving data from socket - any data successfully received is appended // - returns success flag // bool receive (std::string& data); using IP_socket::receive; //////////////////////////////////////////////////////////////////////////// // informational // the local port number of the connection // - returns the port number, 0 if not bound to a port // unsigned short local_port(void) const; using IP_socket::local_port; // the remote address of the connection // - returns the address, 0 if not connected // unsigned long remote_address(void) const; using IP_socket::remote_address; // the remote port number of the connection // - returns the port number, 0 if not connected to a port // unsigned short remote_port(void) const; using IP_socket::remote_port; //////////////////////////////////////////////////////////////////////////// // error handling // errors are set internally // an error code of 0 is the test for no error, don't rely on the message being an empty string // an error code != 0 means an error, then there will be a message explaining the error // if an error is set it stays set - so you must clear it before further operations // void clear_error (void) const; using IP_socket::clear_error; // get the error code of the last error // int error(void) const; using IP_socket::error; // get the explanatory message of the last error // std::string message(void) const; using IP_socket::message; ////////////////////////////////////////////////////////////////////////////// // deprecated versions unsigned long address( void ) const ; unsigned short port( void ) const ; ////////////////////////////////////////////////////////////////////////////// }; //////////////////////////////////////////////////////////////////////////////// } // end namespace stlplus #endif |