00001 #ifndef SPOCKET_CLASS 00002 #define SPOCKET_CLASS 00003 00004 /*****************************************************************************\ 00005 * * 00006 * Name : spocket * 00007 * Author : Chris Koeritz * 00008 * * 00009 * Purpose: * 00010 * * 00011 * Abstraction for a BSD socket that is platform independent, as least as * 00012 * far as working on Win32 or Unix operating systems. This class is named * 00013 * after the venerable Vulcan Spock to avoid name conflicts with the OS's * 00014 * socket() function. * 00015 * * 00016 ******************************************************************************* 00017 * Copyright (c) 1989-$now By Author. This program is free software; you can * 00018 * redistribute it and/or modify it under the terms of the GNU General Public * 00019 * License as published by the Free Software Foundation; either version 2 of * 00020 * the License or (at your option) any later version. This is online at: * 00021 * http://www.fsf.org/copyleft/gpl.html * 00022 * Please send any updates to: fred@gruntose.com * 00023 \*****************************************************************************/ 00024 00025 #include "definitions_sockets.h" 00026 00027 #include <basis/object_base.h> 00028 00029 // forward. 00030 class internet_address; 00031 class raw_socket; 00032 class tcpip_stack; 00033 class time_stamp; 00034 00035 class SOCKETS_CLASS_STYLE spocket : public virtual object_base 00036 { 00037 public: 00038 enum sock_types { 00039 CONNECTED, // connected socket over TCP. 00040 BROADCAST, // broadcasting socket over UDP. 00041 UNICAST, // single-address targeted socket over UDP. 00042 BOGUS_SOCK // special type that goes nowhere and provides no data. 00043 }; 00044 00045 spocket(const internet_address &where, sock_types type = CONNECTED); 00046 // constructs the spocket object. "where" provides the network location 00047 // for either this side (for a server) or the other side (for a client). 00048 // the decision about this socket's orientation (client or server) will not 00049 // be made until either connect() or accept() are invoked. note however 00050 // that BROADCAST sockets are only appropriate for use as a client; they 00051 // can receive and send broadcasts that way without needing a server role. 00052 00053 ~spocket(); 00054 // drops any connection that was made and destroys the spocket object. 00055 00056 IMPLEMENT_CLASS_NAME("spocket"); 00057 00058 bool healthy(); 00059 // returns true if the spocket seems to be okay. 00060 00061 const internet_address &where() const; 00062 // returns the location where this socket exists. 00063 00064 const internet_address &remote() const; 00065 // returns the location that we have accepted from. 00066 00067 enum outcomes { 00068 OKAY = common::OKAY, 00069 TIMED_OUT = common::TIMED_OUT, 00070 ACCESS_DENIED = common::ACCESS_DENIED, 00071 BAD_INPUT = common::BAD_INPUT, 00072 NONE_READY = common::NONE_READY, 00073 PARTIAL = common::PARTIAL, 00074 00075 NO_CONNECTION = communication_commons::NO_CONNECTION, 00076 NO_ANSWER = communication_commons::NO_ANSWER, 00077 00078 DEFINE_OUTCOME(NOT_SERVER, -39, "Accept was tried on a spocket that is " 00079 "not a root server") 00080 }; 00081 00082 static const char *outcome_name(const outcome &to_name); 00083 // returns the text for "to_name" if it's a member of spocket outcomes. 00084 00085 // informative functions... 00086 00087 istring text_form(); 00088 // returns a readable version of the contents of the spocket. 00089 00090 inline bool was_connected() const { return _was_connected; } 00091 // a simple check of whether a connection has been made on this object. 00092 // if this is not true, then the object is not usable yet. this state 00093 // will also get set to false when the spocket gets disconnected. 00094 00095 bool connected(); 00096 // returns true if the spocket is "currently" connected. this causes an 00097 // interrogation of the operating system and may take a short while. 00098 00099 // these report what type of spocket this is. 00100 bool is_client() const { return _client; } 00101 bool is_server() const { return !_client; } 00102 bool is_root_server() const { return is_server() && !!_server_socket; } 00103 00104 u_int OS_socket() { return _socket; } 00105 // returns the low-level operating system form of our normal action socket. 00106 // this is zero for a root server. note: this will still record what the 00107 // socket was after it is closed out, just for record keeping; do not 00108 // control the returned socket outside of this class. 00109 u_int OS_root_socket() { return _server_socket; } 00110 // returns the OS form of our server socket, but only if this is a root 00111 // server type of socket. 00112 00113 void bind_client(const internet_address &source); 00115 00119 // major operations for connected mode sockets... 00120 00121 outcome connect(int communication_wait = 20 * SECOND_ms); 00122 // acts as a client and connects to a destination. the timeout is 00123 // specified in milliseconds by "communication_wait". this can be as low 00124 // as zero if you don't want to wait. TIMED_OUT is returned if the 00125 // connection hasn't finished within the connection_wait. OKAY is returned 00126 // if the connection succeeded. other outcomes denote failures. 00127 00128 outcome accept(spocket * &sock, bool wait); 00129 // makes this spocket act as a root server and accepts a connection from a 00130 // client if possible. a root server is a spocket object that manages a 00131 // server spocket but which does not allow any normal sending or receiving. 00132 // only root servers can have accept called on them. the "sock" will be 00133 // a normal server spocket which can be used to send and receive if it 00134 // got connected. for "sock" to be valid, it must not be returned as NIL 00135 // and the returned outcome must be OKAY. if no new connections are 00136 // available, then NO_CONNECTION is returned. if the "wait" flag is true, 00137 // then the accept on the root server will block until a connection is 00138 // accepted and the returned spocket will be made non-blocking. if "wait" 00139 // is false, then no blocking will occur at all. note that multiple 00140 // threads can invoke this without tripping over the protective locking; 00141 // once the root socket is initialized, accept will not lock the spocket. 00142 00143 outcome disconnect(); 00144 // closes the connection. the state is returned to the post-construction 00145 // state, i.e. it will appear that this object had never connected yet. 00146 00147 // these report which side of the connection this is functioning as. 00148 bool client() const { return _client; } 00149 bool server() const { return !_client; } 00150 00151 // send and receive functions... 00152 // 00153 // if the outcome from one of these is NO_CONNECTION, then somehow the 00154 // connection has dropped or never succeeded. 00155 00156 outcome send(const byte *buffer, int size, int &len_sent); 00157 // sends "size" bytes from the "buffer". the number actually sent is 00158 // stored in "len_sent". this can only be used for CONNECTED type sockets. 00159 00160 outcome send(const byte_array &to_send, int &len_sent); 00161 // this version takes a byte_array. 00162 00163 outcome send_to(const internet_address &where_to, const byte *buffer, 00164 int size, int &len_sent); 00165 // this version is used for sending when the socket type is BROADCAST 00166 // or UNICAST. 00167 00168 outcome send_to(const internet_address &where_to, const byte_array &to_send, 00169 int &len_sent); 00170 // clone of above, using byte_array. 00171 00172 outcome receive(byte *buffer, int &size); 00173 // attempts to retrieve data from the spocket and place it in the "buffer". 00174 // the "size" specifies how much space is available. if successful, the 00175 // buffer will be filled with data and "size" will report how much there 00176 // actually is. 00177 00178 outcome receive(byte_array &buffer, int &size); 00179 // this version uses a byte_array for the "buffer". the "size" expected 00180 // must still be set and "size" will still report the bytes read. 00181 //hmmm: could remove the size parameter for byte array type. 00182 00183 // these methods are used for BROADCAST and other non-connected types of 00184 // spockets. they report the data as the above receive methods do, but they 00185 // also report the sender. 00186 outcome receive_from(byte *buffer, int &size, 00187 internet_address &where_from); 00188 outcome receive_from(byte_array &buffer, int &size, 00189 internet_address &where_from); 00190 00191 outcome await_readable(int timeout); 00192 // pauses this caller until data arrives. this is a blocking call that 00193 // could potentially not return until the "timeout" elapses (measured in 00194 // milliseconds). if "timeout" is zero, then this really doesn't do 00195 // anything. if data is available, then OKAY is returned. 00196 00197 outcome await_writable(int timeout); 00198 // pauses this caller until the socket can be written to again. could 00199 // potentially not return until the "timeout" elapses (measured in 00200 // milliseconds). if "timeout" is zero, then this really doesn't do 00201 // anything. if the socket is able to send again, then OKAY is returned. 00202 // otherwise NONE_READY is returned. 00203 00204 tcpip_stack &stack() const; 00205 // provides access to the spocket's tcpip stack to derivative objects. 00206 00207 bool is_bogus() const { return _type == BOGUS_SOCK; } 00209 00215 private: 00216 sock_types _type; // records what kind of socket we'll create. 00217 u_int _socket; // our socket that we communicate on. 00218 u_int _server_socket; // our serving socket, if we're a root server. 00219 bool _was_connected; // did we ever successfully connect? 00220 bool _client; // true if we are acting as a client. 00221 internet_address *_where; // our addressing info. 00222 internet_address *_remote; // our addressing info. 00223 raw_socket *_socks; // provides low-level socket functionality. 00224 tcpip_stack *_stack; // provides access to socket facilities. 00225 mutex *_select_lock; // protects concurrent access to socket. 00226 time_stamp *_last_resolve; 00227 // tracks when we last tried a resolve on our address. if they try to 00228 // reconnect and we haven't done this in a while, we'll re-resolve the 00229 // socket. 00230 bool _client_bind; 00231 internet_address *_cli_bind; 00232 00233 // not allowed. 00234 spocket(const spocket &); 00235 spocket &operator =(const spocket &); 00236 }; 00237 00238 #endif 00239
1.5.1