Back to index

lightning-sunbird  0.9+nobinonly
GUSIOpenTransport.h
Go to the documentation of this file.
00001 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
00002 // % Project  :      GUSI                        -      Grand Unified Socket Interface                    
00003 // % File            :      GUSIOpenTransport.nw-       OpenTransport sockets                   
00004 // % Author   :      Matthias Neeracher                                           
00005 // % Language :      C++                                                        
00006 // %                                                                       
00007 // % $Log: GUSIOpenTransport.h,v $
00008 // % Revision 1.1  2001/03/11 22:37:24  sgehani%netscape.com
00009 // % First Checked In.
00010 // %                                        
00011 // % Revision 1.18  2001/01/17 08:58:06  neeri                             
00012 // % Releasing 2.1.4                                                       
00013 // %                                                                       
00014 // % Revision 1.17  2000/10/16 04:07:23  neeri                             
00015 // % Fix accept code                                                       
00016 // %                                                                       
00017 // % Revision 1.16  2000/06/01 06:31:10  neeri                             
00018 // % Reset shutdown flags on connect, refine test for data available, fix memory leak in UDP sendto
00019 // %                                                                       
00020 // % Revision 1.15  2000/05/23 07:13:19  neeri                             
00021 // % Improve formatting, implement immediate close and sorrect linger handling
00022 // %                                                                       
00023 // % Revision 1.14  2000/03/15 07:19:53  neeri                             
00024 // % Fix numerous race conditions                                          
00025 // %                                                                       
00026 // % Revision 1.13  2000/03/06 06:10:01  neeri                             
00027 // % Reorganize Yield()                                                    
00028 // %                                                                       
00029 // % Revision 1.12  1999/12/14 06:28:29  neeri                             
00030 // % Read pending data while closing                                       
00031 // %                                                                       
00032 // % Revision 1.11  1999/12/13 02:44:19  neeri                             
00033 // % Fix SO_LINGER, read results for disconnected sockets                  
00034 // %                                                                       
00035 // % Revision 1.10  1999/10/15 02:48:50  neeri                             
00036 // % Make disconnects orderly                                              
00037 // %                                                                       
00038 // % Revision 1.9  1999/09/09 07:20:29  neeri                              
00039 // % Fix numerous bugs, add support for interface ioctls                   
00040 // %                                                                       
00041 // % Revision 1.8  1999/09/03 06:31:36  neeri                              
00042 // % Needed more mopups                                                    
00043 // %                                                                       
00044 // % Revision 1.7  1999/08/26 05:43:09  neeri                              
00045 // % Supply missing Unbind                                                 
00046 // %                                                                       
00047 // % Revision 1.6  1999/08/02 07:02:45  neeri                              
00048 // % Support for asynchronous errors and other socket options              
00049 // %                                                                       
00050 // % Revision 1.5  1999/07/19 06:17:44  neeri                              
00051 // % Fix nonblocking connect                                               
00052 // %                                                                       
00053 // % Revision 1.4  1999/06/28 06:04:59  neeri                              
00054 // % Support interrupted calls                                             
00055 // %                                                                       
00056 // % Revision 1.3  1999/05/30 03:06:41  neeri                              
00057 // % MPW compiler compatibility, fix select for datagram sockets           
00058 // %                                                                       
00059 // % Revision 1.2  1999/04/29 05:33:19  neeri                              
00060 // % Fix fcntl prototype                                                   
00061 // %                                                                       
00062 // % Revision 1.1  1999/03/17 09:05:11  neeri                              
00063 // % Added GUSITimer, expanded docs                                        
00064 // %                                                                       
00065 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
00066 //                                                                         
00067 // \chapter{Open Transport socket infrastructure}                          
00068 //                                                                         
00069 // A [[GUSIOTSocket]] defines a class of Open Transport sockets. Since most 
00070 // families differ only in a few details, like address representation, we  
00071 // abstract the typical differences in a strategy class [[GUSIOTStrategy]].
00072 //                                                                         
00073 // <GUSIOpenTransport.h>=                                                  
00074 #ifndef _GUSIOpenTransport_
00075 #define _GUSIOpenTransport_
00076 
00077 #ifdef GUSI_INTERNAL
00078 
00079 #include "GUSISocket.h"
00080 #include "GUSISocketMixins.h"
00081 #include "GUSIFactory.h"
00082 
00083 #include <netinet/in.h>
00084 #include <netinet/tcp.h>
00085 
00086 #undef O_ASYNC
00087 #undef O_NDELAY
00088 #undef O_NONBLOCK
00089 #undef SIGHUP
00090 #undef SIGURG
00091 #undef AF_INET
00092 #undef TCP_KEEPALIVE
00093 #undef TCP_NODELAY
00094 #undef TCP_MAXSEG
00095 
00096 #include <OpenTransport.h>
00097 #include <OpenTptInternet.h>
00098 
00099 // \section{Definition of [[GUSIOTStrategy]]}                              
00100 //                                                                         
00101 // A [[GUSIOTStrategy]] contains all the tricky parts of each Open Transport
00102 // family.                                                                 
00103 //                                                                         
00104 // <Definition of class [[GUSIOTStrategy]]>=                               
00105 class GUSIOTStrategy {
00106 public:
00107        // [[CreateConfiguration]] creates an appropriate [[OTConfiguration]]. This 
00108  // method is not virtual, as it relies on the strategy method              
00109  // [[ConfigPath]].                                                         
00110  //                                                                         
00111  // <Strategic interfaces for [[GUSIOTStrategy]]>=                          
00112  OTConfiguration *          CreateConfiguration();
00113  // [[PackAddress]] converts a socket address into an OT address, and       
00114  // [[UnpackAddress]] performs the reverse step. [[CopyAddress]] copies an address.
00115  //                                                                         
00116  // <Strategic interfaces for [[GUSIOTStrategy]]>=                          
00117  virtual      int    PackAddress(
00118        const void * address, socklen_t len, TNetbuf & addr, bool non_null = false) = 0;
00119  virtual      int    UnpackAddress(const TNetbuf & addr, void * address, socklen_t * len) = 0;
00120  virtual int CopyAddress(const TNetbuf & from, TNetbuf & to);
00121  // [[EndpointInfo]] returns a data structure storing endpoint parameters. We only
00122  // need one copy per socket type.                                          
00123  //                                                                         
00124  // <Strategic interfaces for [[GUSIOTStrategy]]>=                          
00125  TEndpointInfo *     EndpointInfo()       { return &fEndpointInfo; }
00126 protected:
00127        // <Privatissima of [[GUSIOTStrategy]]>=                                   
00128  virtual const char *       ConfigPath() = 0;
00129  // <Privatissima of [[GUSIOTStrategy]]>=                                   
00130  TEndpointInfo       fEndpointInfo;
00131  // \section{Implementation of [[GUSIOTStrategy]]}                          
00132  //                                                                         
00133  // [[GUSIOTStrategy]] is mostly abstract, except for the [[CreateConfiguration]]
00134  // and [[CopyAddress]] methods.                                            
00135  //                                                                         
00136  // <Privatissima of [[GUSIOTStrategy]]>=                                   
00137  OTConfiguration *   fConfig;
00138  GUSIOTStrategy()                                : fConfig(nil) {}
00139  virtual ~GUSIOTStrategy();
00140 };
00141 // \section{Definition of [[GUSIOTFactory]] and descendants}               
00142 //                                                                         
00143 // A [[GUSIOTFactory]] is an abstract class combining a socket creation    
00144 // mechanism with a strategy instance. To clarify our intent, we isolate   
00145 // the latter in [[GUSIOTStrategy]].                                       
00146 //                                                                         
00147 // <Definition of class [[GUSIOTFactory]]>=                                
00148 class GUSIOTFactory : public GUSISocketFactory {
00149 public:
00150        static bool                 Initialize();
00151 protected:
00152        virtual GUSIOTStrategy *Strategy(int domain, int type, int protocol) = 0;
00153 private:
00154        // \section{Implementation of [[GUSIOTFactory]] and descendants}           
00155  //                                                                         
00156  //                                                                         
00157  // <Privatissima of [[GUSIOTFactory]]>=                                    
00158  static bool  sOK;
00159 };
00160 // <Definition of class [[GUSIOTStreamFactory]]>=                          
00161 class GUSIOTStreamFactory : public GUSIOTFactory {
00162 public:
00163        GUSISocket * socket(int domain, int type, int protocol);
00164 };
00165 // <Definition of class [[GUSIOTDatagramFactory]]>=                        
00166 class GUSIOTDatagramFactory : public GUSIOTFactory {
00167 public:
00168        GUSISocket * socket(int domain, int type, int protocol);
00169 };
00170 // \section{Definition of [[GUSIOT]]}                                      
00171 //                                                                         
00172 // Open Transport allocates and deallocates many data structures, which we 
00173 // simplify with a smart template. Allocation works via class allocation   
00174 // operators, which is a bit weird admittedly.                             
00175 //                                                                         
00176 // <Definition of template [[GUSIOT]]>=                                    
00177 template <class T, int tag> class GUSIOT : public T {
00178 public:
00179        void * operator new(size_t, EndpointRef ref)     
00180               {      OSStatus err; return OTAlloc(ref, tag, T_ALL, &err);    }
00181        void * operator new(size_t, EndpointRef ref, int fields)       
00182               {      OSStatus err; return OTAlloc(ref, tag, fields, &err);   }
00183        void operator delete(void * o)
00184               {      if (o) OTFree(o, tag);                                                              }
00185 };     
00186 template <class T, int tag> class GUSIOTAddr : public GUSIOT<T, tag> {
00187 public:
00188        int    Pack(GUSIOTStrategy * strategy, const void * address, socklen_t len, bool non_null=false)
00189               {      return strategy->PackAddress(address, len, addr, non_null);    }
00190        int    Unpack(GUSIOTStrategy * strategy, void * address, socklen_t * len)
00191               {      return strategy->UnpackAddress(addr, address, len);                   }
00192        int Copy(GUSIOTStrategy * strategy, GUSIOTAddr<T, tag> * to)
00193               {      return strategy->CopyAddress(addr, to->addr);                         }
00194 };
00195 
00196 typedef GUSIOTAddr<TBind,          T_BIND>              GUSIOTTBind;
00197 typedef GUSIOTAddr<TCall,          T_CALL>              GUSIOTTCall;
00198 typedef GUSIOTAddr<TUnitData,      T_UNITDATA>   GUSIOTTUnitData;
00199 typedef GUSIOTAddr<TUDErr,         T_UDERROR>    GUSIOTTUDErr;
00200 typedef GUSIOT<TDiscon,            T_DIS>        GUSIOTTDiscon;
00201 typedef GUSIOT<TOptMgmt,           T_OPTMGMT>    GUSIOTTOptMgmt;
00202 // \section{Definition of [[GUSIOTSocket]] and descendants}                
00203 //                                                                         
00204 // Open Transport sockets are rather lightweight, since OT is rather similar 
00205 // to sockets already.                                                     
00206 //                                                                         
00207 // <Definition of class [[GUSIOTSocket]]>=                                 
00208 class GUSIOTSocket  : 
00209        public               GUSISocket, 
00210        protected     GUSISMBlocking, 
00211        protected     GUSISMState,
00212        protected     GUSISMAsyncError
00213 {
00214 public:
00215        // <Overridden member functions for [[GUSIOTSocket]]>=                     
00216  virtual int  bind(void * name, socklen_t namelen);
00217  // [[getsockname]] and [[getpeername]] unpack the stored addresses.        
00218  // Note that the reaction to [[nil]] addresses is a bit different.         
00219  //                                                                         
00220  // <Overridden member functions for [[GUSIOTSocket]]>=                     
00221  virtual int getsockname(void * name, socklen_t * namelen);
00222  // [[shutdown]] just delegates to [[GUSISMState]].                         
00223  //                                                                         
00224  // <Overridden member functions for [[GUSIOTSocket]]>=                     
00225  virtual int shutdown(int how);
00226  // [[fcntl]] handles the blocking support.                                 
00227  //                                                                         
00228  // <Overridden member functions for [[GUSIOTSocket]]>=                     
00229  virtual int fcntl(int cmd, va_list arg);
00230  // [[ioctl]] deals with blocking support and with [[FIONREAD]].            
00231  //                                                                         
00232  // <Overridden member functions for [[GUSIOTSocket]]>=                     
00233  virtual int ioctl(unsigned int request, va_list arg);
00234  // [[getsockopt]] and [[setsockopt]] are available for a variety of options.
00235  //                                                                         
00236  // <Overridden member functions for [[GUSIOTSocket]]>=                     
00237  virtual int getsockopt(int level, int optname, void *optval, socklen_t * optlen);
00238  // <Overridden member functions for [[GUSIOTSocket]]>=                     
00239  virtual int setsockopt(int level, int optname, void *optval, socklen_t optlen);
00240  // Open Transport sockets implement socket style calls.                    
00241  //                                                                         
00242  // <Overridden member functions for [[GUSIOTSocket]]>=                     
00243  virtual bool Supports(ConfigOption config);
00244 protected:
00245        GUSIOTSocket(GUSIOTStrategy * strategy);
00246 
00247        // \section{Implementation of [[GUSIOTSocket]]}                            
00248  //                                                                         
00249  // Open Transport may call this routine for dozens and dozens of different 
00250  // reasons. Pretty much every call results in a wakeup of the threads attached
00251  // to the socket. We save some of the more interesting events in bitsets.  
00252  // in [[MopupEvents]].                                                     
00253  //                                                                         
00254  // <Privatissima of [[GUSIOTSocket]]>=                                     
00255  uint16_t            fNewEvent;
00256  uint16_t            fCurEvent;
00257  uint16_t            fEvent;
00258  uint32_t            fNewCompletion;
00259  uint32_t            fCurCompletion;
00260  uint32_t            fCompletion;
00261  friend pascal void GUSIOTNotify(GUSIOTSocket *, OTEventCode, OTResult, void *);
00262  // To avoid race conditions with the notifier, we sometimes need a lock.   
00263  //                                                                         
00264  // <Privatissima of [[GUSIOTSocket]]>=                                     
00265  class Lock {
00266  public:
00267        Lock(EndpointRef end)       : fEndpoint(end)     { OTEnterNotifier(fEndpoint);      } 
00268        ~Lock()                                                                      { OTLeaveNotifier(fEndpoint);      } 
00269  private:
00270        EndpointRef   fEndpoint;
00271  };
00272  // For some events, we have to take a followup action at a more convenient time.
00273  //                                                                         
00274  // <Privatissima of [[GUSIOTSocket]]>=                                     
00275  virtual void MopupEvents();
00276  // [[GUSIOTSocket]] creates an asynchronous endpoint for the appropriate   
00277  // provider.                                                               
00278  //                                                                         
00279  // <Privatissima of [[GUSIOTSocket]]>=                                     
00280  GUSIOTStrategy *    fStrategy;
00281  EndpointRef                fEndpoint;
00282  linger                            fLinger;
00283  UInt32                            fDeadline;
00284  // The destructor tears down the connection as gracefully as possible. It also respects
00285  // the linger settings.                                                    
00286  //                                                                         
00287  // <Privatissima of [[GUSIOTSocket]]>=                                     
00288  virtual void close();
00289  virtual ~GUSIOTSocket();
00290  // [[Clone]] creates another socket of the same class.                     
00291  //                                                                         
00292  // <Privatissima of [[GUSIOTSocket]]>=                                     
00293  virtual GUSIOTSocket * Clone() = 0;
00294  // At the time the socket function [[bind]] is called, we are not really ready
00295  // yet to call [[OTBind]], but if we don't call it, we can't report whether the
00296  // address was free.                                                       
00297  //                                                                         
00298  // <Privatissima of [[GUSIOTSocket]]>=                                     
00299  GUSIOTTBind *       fSockName;
00300  int BindToAddress(GUSIOTTBind * addr);
00301  // Open Transport takes unbinding a lot more serious than MacTCP.          
00302  //                                                                         
00303  // <Privatissima of [[GUSIOTSocket]]>=                                     
00304  void Unbind();
00305        
00306        friend class GUSIOTStreamSocket;
00307        friend class GUSIOTDatagramSocket;
00308 };
00309 // <Definition of class [[GUSIOTStreamSocket]]>=                           
00310 class GUSIOTStreamSocket  : public GUSIOTSocket {
00311 public:
00312        // [[Clone]] creates another socket of the same class.                     
00313  //                                                                         
00314  // <Overridden member functions for [[GUSIOTStreamSocket]]>=               
00315  virtual GUSIOTSocket * Clone();
00316  // <Overridden member functions for [[GUSIOTStreamSocket]]>=               
00317  virtual void close();
00318  virtual bool Close(UInt32 now);
00319  ~GUSIOTStreamSocket();
00320  // Stream sockets include a mopup action for connect and disconnect.       
00321  //                                                                         
00322  // <Overridden member functions for [[GUSIOTStreamSocket]]>=               
00323  virtual void MopupEvents();
00324  // [[listen]] is a bit embarassing, because we already committed ourselves 
00325  // to a queue length of [[0]], so we have to unbind and rebind ourselves.  
00326  //                                                                         
00327  // <Overridden member functions for [[GUSIOTStreamSocket]]>=               
00328  virtual int listen(int qlen);
00329  // <Overridden member functions for [[GUSIOTStreamSocket]]>=               
00330  virtual int getpeername(void * name, socklen_t * namelen);
00331  // [[accept]] may become quite complex, because connections could nest. The
00332  // listening socket calls [[OTListen]], queues candidates by their         
00333  // [[fNextListener]] field, and then trys calling [[OTAccept]] on the first
00334  // candidate.                                                              
00335  //                                                                         
00336  // <Overridden member functions for [[GUSIOTStreamSocket]]>=               
00337  virtual GUSISocket * accept(void * address, socklen_t * addrlen);
00338  // [[connect]] is comparatively simple.                                    
00339  //                                                                         
00340  // <Overridden member functions for [[GUSIOTStreamSocket]]>=               
00341  virtual int connect(void * address, socklen_t addrlen);
00342  // Data transfer is simple as well. Here is the version for stream protocols.
00343  //                                                                         
00344  // <Overridden member functions for [[GUSIOTStreamSocket]]>=               
00345  virtual ssize_t recvfrom(const GUSIScatterer & buffer, int flags, void * from, socklen_t * fromlen);
00346  // <Overridden member functions for [[GUSIOTStreamSocket]]>=               
00347  virtual ssize_t sendto(const GUSIGatherer & buffer, int flags, const void * to, socklen_t tolen);
00348  // [[select]] for stream sockets intermingles data information and connection
00349  // information as usual.                                                   
00350  //                                                                         
00351  // <Overridden member functions for [[GUSIOTStreamSocket]]>=               
00352  virtual bool select(bool * canRead, bool * canWrite, bool * except);
00353  // [[shutdown]] for stream sockets has to send an orderly disconnect.      
00354  //                                                                         
00355  // <Overridden member functions for [[GUSIOTStreamSocket]]>=               
00356  virtual int shutdown(int how);
00357 protected:
00358        GUSIOTStreamSocket(GUSIOTStrategy * strategy);
00359 
00360        // Since all we need to know is in the [[GUSIOTStrategy]], it often suffices 
00361  // simply to create a [[GUSIOTSocket]]. Stream and datagram sockets differ 
00362  // merely in the descendant they create.                                   
00363  //                                                                         
00364  // <Privatissima of [[GUSIOTStreamSocket]]>=                               
00365  friend class GUSIOTStreamFactory;
00366  // <Privatissima of [[GUSIOTStreamSocket]]>=                               
00367  friend pascal void GUSIOTNotify(GUSIOTSocket *, OTEventCode, OTResult, void *);
00368  // The peer address for a [[GUSIOTStreamSocket]] is stored in a [[GUSIOTTCall]]
00369  // structure.                                                              
00370  //                                                                         
00371  // <Privatissima of [[GUSIOTStreamSocket]]>=                               
00372  GUSIOTTCall *       fPeerName;
00373  // <Privatissima of [[GUSIOTStreamSocket]]>=                               
00374  GUSIOTStreamSocket *       fNextListener;
00375 };
00376 // <Definition of class [[GUSIOTDatagramSocket]]>=                         
00377 class GUSIOTDatagramSocket  : public GUSIOTSocket {
00378 public:
00379        // [[Clone]] creates another socket of the same class.                     
00380  //                                                                         
00381  // <Overridden member functions for [[GUSIOTDatagramSocket]]>=             
00382  virtual GUSIOTSocket * Clone();
00383  // <Overridden member functions for [[GUSIOTDatagramSocket]]>=             
00384  ~GUSIOTDatagramSocket();
00385  // <Overridden member functions for [[GUSIOTDatagramSocket]]>=             
00386  virtual int getpeername(void * name, socklen_t * namelen);
00387  // A datagram socket can [[connect]] as many times as it wants.            
00388  //                                                                         
00389  // <Overridden member functions for [[GUSIOTDatagramSocket]]>=             
00390  virtual int connect(void * address, socklen_t addrlen);
00391  // Datagram protocols use slightly different calls for data transfers.     
00392  //                                                                         
00393  // <Overridden member functions for [[GUSIOTDatagramSocket]]>=             
00394  virtual ssize_t recvfrom(const GUSIScatterer & buffer, int flags, void * from, socklen_t * fromlen);
00395  // [[sendto]] needs either a valid [[to]] address or a stored peer address set by
00396  // [[connect]].                                                            
00397  //                                                                         
00398  // <Overridden member functions for [[GUSIOTDatagramSocket]]>=             
00399  virtual ssize_t sendto(const GUSIGatherer & buffer, int flags, const void * to, socklen_t tolen);
00400  // [[select]] for datagram sockets returns data information only.          
00401  //                                                                         
00402  // <Overridden member functions for [[GUSIOTDatagramSocket]]>=             
00403  virtual bool select(bool * canRead, bool * canWrite, bool * except);
00404 protected:
00405        GUSIOTDatagramSocket(GUSIOTStrategy * strategy);
00406 
00407        // <Privatissima of [[GUSIOTDatagramSocket]]>=                             
00408  friend class GUSIOTDatagramFactory;
00409  // Datagram sockets might be bound at rather arbitrary times.              
00410  //                                                                         
00411  // <Privatissima of [[GUSIOTDatagramSocket]]>=                             
00412  int BindIfUnbound();
00413  // The peer address for a [[GUSIOTDatagramSocket]] is stored in a [[GUSIOTTBind]]
00414  // structure.                                                              
00415  //                                                                         
00416  // <Privatissima of [[GUSIOTDatagramSocket]]>=                             
00417  GUSIOTTBind *       fPeerName;
00418 };
00419 
00420 #endif /* GUSI_INTERNAL */
00421 
00422 #endif /* _GUSIOpenTransport_ */