spocket.h

Go to the documentation of this file.
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 
Generated on Sat Jan 28 04:22:44 2012 for hoople2 project by  doxygen 1.6.3