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