Back to index

lightning-sunbird  0.9+nobinonly
GUSISocket.h
Go to the documentation of this file.
00001 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
00002 // % Project  :      GUSI                        -      Grand Unified Socket Interface                    
00003 // % File            :      GUSISocket.nw        -      The socket class                             
00004 // % Author   :      Matthias Neeracher                                           
00005 // % Language :      C++                                                        
00006 // %                                                                       
00007 // % $Log: GUSISocket.h,v $
00008 // % Revision 1.1  2001/03/11 22:38:15  sgehani%netscape.com
00009 // % First Checked In.
00010 // %                                               
00011 // % Revision 1.18  2000/10/16 04:34:23  neeri                             
00012 // % Releasing 2.1.2                                                       
00013 // %                                                                       
00014 // % Revision 1.17  2000/05/23 07:19:34  neeri                             
00015 // % Improve formatting, add close queue                                   
00016 // %                                                                       
00017 // % Revision 1.16  2000/03/15 07:20:53  neeri                             
00018 // % Add GUSISocket::AddContextInScope                                     
00019 // %                                                                       
00020 // % Revision 1.15  1999/10/15 02:48:51  neeri                             
00021 // % Make disconnects orderly                                              
00022 // %                                                                       
00023 // % Revision 1.14  1999/09/26 03:59:26  neeri                             
00024 // % Releasing 2.0fc1                                                      
00025 // %                                                                       
00026 // % Revision 1.13  1999/08/26 05:45:09  neeri                             
00027 // % Fixes for literate edition of source code                             
00028 // %                                                                       
00029 // % Revision 1.12  1999/06/08 04:31:31  neeri                             
00030 // % Getting ready for 2.0b2                                               
00031 // %                                                                       
00032 // % Revision 1.11  1999/05/29 06:26:45  neeri                             
00033 // % Fixed header guards                                                   
00034 // %                                                                       
00035 // % Revision 1.10  1999/04/29 05:33:18  neeri                             
00036 // % Fix fcntl prototype                                                   
00037 // %                                                                       
00038 // % Revision 1.9  1999/03/17 09:05:13  neeri                              
00039 // % Added GUSITimer, expanded docs                                        
00040 // %                                                                       
00041 // % Revision 1.8  1998/11/22 23:07:01  neeri                              
00042 // % Releasing 2.0a4 in a hurry                                            
00043 // %                                                                       
00044 // % Revision 1.7  1998/10/11 16:45:23  neeri                              
00045 // % Ready to release 2.0a2                                                
00046 // %                                                                       
00047 // % Revision 1.6  1998/08/01 21:29:53  neeri                              
00048 // % Use context queues                                                    
00049 // %                                                                       
00050 // % Revision 1.5  1998/01/25 20:53:58  neeri                              
00051 // % Engine implemented, except for signals & scheduling                   
00052 // %                                                                       
00053 // % Revision 1.4  1997/11/13 21:12:12  neeri                              
00054 // % Fall 1997                                                             
00055 // %                                                                       
00056 // % Revision 1.3  1996/11/24  13:00:28  neeri                             
00057 // % Fix comment leaders                                                   
00058 // %                                                                       
00059 // % Revision 1.2  1996/11/24  12:52:09  neeri                             
00060 // % Added GUSIPipeSockets                                                 
00061 // %                                                                       
00062 // % Revision 1.1.1.1  1996/11/03  02:43:32  neeri                         
00063 // % Imported into CVS                                                     
00064 // %                                                                       
00065 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
00066 //                                                                         
00067 // \chapter{The GUSI Socket Class}                                         
00068 //                                                                         
00069 // GUSI is constructed around the [[GUSISocket]] class. This class is      
00070 // mostly an abstract superclass, but all virtual procedures are implemented
00071 // to return sensible error codes.                                         
00072 //                                                                         
00073 // <GUSISocket.h>=                                                         
00074 #ifndef _GUSISocket_
00075 #define _GUSISocket_
00076 
00077 #ifdef GUSI_SOURCE
00078 
00079 #include "GUSIBasics.h"
00080 #include "GUSIContext.h"
00081 #include "GUSIContextQueue.h"
00082 #include "GUSIBuffer.h"
00083 
00084 #include <sys/types.h>
00085 #include <sys/socket.h>
00086 #include <stdarg.h>
00087 
00088 #include <ConditionalMacros.h>
00089 #include <LowMem.h>
00090 
00091 #if PRAGMA_STRUCT_ALIGN
00092 #pragma options align=native
00093 #endif
00094 
00095 // \section{Definition of [[GUSISocket]]}                                  
00096 //                                                                         
00097 // [[GUSISocket]] consists of a few maintenance functions and the socket operations.
00098 // Each operation consists to a POSIX/BSD function with the file descriptor operand
00099 // left out.                                                               
00100 //                                                                         
00101 // <Definition of class [[GUSISocket]]>=                                   
00102 class GUSISocket {
00103        // Since a single [[GUSISocket]] may (through [[dup]]) be installed multiply
00104  // in a descriptor table or even in multiple descriptor tables, [[GUSISocket]]s
00105  // are not destroyed directly, but by manipulating a reference count. As soon
00106  // as the reference count hits zero, the destructor (which, of course, should 
00107  // probably be overridden) is called.                                      
00108  //                                                                         
00109  // Since destructors cannot call virtual functions, we call [[close]] which 
00110  // eventually calls the destructor. Some socket types can take quite long to close
00111  // under unfavorable circumstances. To speed up the process, we have the option of
00112  // queueing the socket up and regularly having [[Close]] called on it.     
00113  //                                                                         
00114  // <Reference counting for [[GUSISocket]]>=                                
00115  public:
00116        void                 AddReference();
00117        void                 RemoveReference();
00118        
00119        virtual void  close();
00120        void                 CheckClose(UInt32 now = LMGetTicks());
00121  protected:
00122        GUSISocket();
00123        virtual                     ~GUSISocket();
00124        virtual       bool   Close(UInt32 now = LMGetTicks());
00125  private:
00126        u_long fRefCount;
00127        // [[GUSIContext]]s are defined in {\tt GUSIBasics}. A context references all 
00128  // information you need in a completion procedure: The contents of [[A5]], 
00129  // the process ID, and thread information. [[Wakeup]] wakes up the threads 
00130  // and/or processes associated with the socket and is guaranteed to work even
00131  // at interrupt level. [[AddContext]] adds another context. [[RemoveContext]] 
00132  // indicates that this context no longer should be woken up when something happens.
00133  // To keep a context added inside a scope, declare an automatic object of class
00134  // [[AddContextInScope]].                                                  
00135  //                                                                         
00136  // <Context links for [[GUSISocket]]>=                                     
00137  public:
00138        void                        Wakeup();
00139        void                        AddContext(GUSIContext * context = nil);
00140        void                        RemoveContext(GUSIContext * context = nil);
00141        
00142        class AddContextInScope {
00143        public:
00144               AddContextInScope(GUSISocket * sock, GUSIContext *      context = nil) 
00145                      : fSocket(sock), fContext(context) 
00146                                                         { fSocket->AddContext(fContext);   }
00147               ~AddContextInScope() { fSocket->RemoveContext(fContext);       }
00148        private:
00149               GUSISocket *  fSocket;
00150               GUSIContext * fContext;
00151        };
00152  private:
00153        GUSIContextQueue     fContexts;
00154        // There may be various reasons to keep sockets in queue. Currently the    
00155  // only reason is to queue up dying sockets.                               
00156  //                                                                         
00157  // <Queue management for [[GUSISocket]]>=                                  
00158  public:
00159        void Enqueue(GUSISocket ** queue);
00160        void Dequeue();
00161  private:
00162        GUSISocket ** fQueue;
00163        GUSISocket *  fNextSocket;
00164        GUSISocket *  fPrevSocket;
00165        // Both read and write calls on sockets come in five different variants:   
00166  //                                                                         
00167  // \begin{enumerate}                                                       
00168  // \item [[read]] and [[write]]                                            
00169  // \item [[recv]] and [[send]]                                             
00170  // \item [[readv]] and [[writev]]                                          
00171  // \item [[recvfrom]] and [[sendto]]                                       
00172  // \item [[recvmsg]] and [[sendmsg]]                                       
00173  // \end{enumerate}                                                         
00174  //                                                                         
00175  // GUSI initially maps variants 3 and 5 of these calls to the [[recvmsg]] and 
00176  // [[sendmsg]] member functions, variants 2 and 4 to the [[recvfrom]] and  
00177  // [[sendto]] member functions, and variant 1 to the [[read]] and          
00178  // [[write]] member functions.                                             
00179  //                                                                         
00180  // The simpler member functions can always be translated into the complex member
00181  // functions, and under some circumstances, the opposite is also possible. 
00182  // To avoid translation loops, the translation routines (i.e., the default 
00183  // implementation of [[GUSISocket::read]] and [[GUSISocket::recvmsg]]      
00184  // check for the availablility of the other function by calling [[Supports]].
00185  // This member function must be overridden for any reasonable socket class.
00186  //                                                                         
00187  // <Configuration options for [[GUSISocket]]>=                             
00188  protected:
00189        enum ConfigOption {
00190               kSimpleCalls,        // [[read]], [[write]]
00191               kSocketCalls,        // [[recvfrom]], [[sendto]]
00192               kMsgCalls                   // [[recvmsg]], [[sendmsg]]
00193        };
00194        virtual bool  Supports(ConfigOption config);
00195 public:
00196        // Most sockets have names, which to [[GUSISocket]] are just opaque blocks of
00197  // memory. A name for a socket is established (before the socket is actually
00198  // used, of course) through [[bind]]. The name may be queried with         
00199  // [[getsockname]] and once the socket is connected, the name of the peer  
00200  // endpoint may be queried with [[getpeername]].                           
00201  //                                                                         
00202  // <Socket name management for [[GUSISocket]]>=                            
00203  virtual int  bind(void * name, socklen_t namelen);
00204  virtual int getsockname(void * name, socklen_t * namelen);
00205  virtual int getpeername(void * name, socklen_t * namelen);
00206        // Sockets follow either a virtual circuit model where all data is exchanged
00207  // with the same peer throughout the lifetime of the connection, or a datagram
00208  // model where potentially every message is exchanged with a different peer.
00209  //                                                                         
00210  // The vast majority of protocols follow the virtual circuit model. The server
00211  // end, typically after calling [[bind]] to attach the socket to a well known
00212  // address, calls [[listen]] to establish its willingness to accept connections.
00213  // [[listen]] takes a queue length parameter, which however is ignored for many
00214  // types of sockets.                                                       
00215  //                                                                         
00216  // Incoming connections are then accepted by calling [[accept]]. When [[accept]]
00217  // is successful, it always returns a new [[GUSISocket]], while the original socket 
00218  // remains available for further connections. To avoid blocking on [[accept]], you may poll for connections with an 
00219  // [[accept()] call in nonblocking mode or query the result of [[select]] whether 
00220  // the socket is ready for reading.                                        
00221  //                                                                         
00222  // The client end in the virtual circuit model connects itself to the well known
00223  // address by calling [[connect]]. To avoid blocking on [[connect]], you may
00224  // call it in nonblocking mode and then query the result of [[select]] whether 
00225  // the socket is ready for writing.                                        
00226  //                                                                         
00227  // In the datagram model, you don't need to establish connections. You may call
00228  // [[connect]] anyway to temporarily establish a virtual circuit.          
00229  //                                                                         
00230  // <Connection establishment for [[GUSISocket]]>=                          
00231  virtual int listen(int qlen);
00232  virtual GUSISocket * accept(void * address, socklen_t * addrlen);
00233  virtual int connect(void * address, socklen_t addrlen);
00234        // As mentioned before, there are three variants each for reading and writing. 
00235  // The socket variants provide a means to pass a peer address for the datagram 
00236  // model, while the msg variants also provides fields for passing access rights, 
00237  // which is, however not currently supported in GUSI. As syntactic sugar, the more
00238  // traditional flavors with [[buffer]]/[[length]] buffers are also supported.
00239  //                                                                         
00240  // <Sending and receiving data for [[GUSISocket]]>=                        
00241  virtual ssize_t     read(const GUSIScatterer & buffer);
00242  virtual ssize_t write(const GUSIGatherer & buffer);
00243  virtual ssize_t recvfrom(
00244                      const GUSIScatterer & buffer, int flags, void * from, socklen_t * fromlen);
00245  virtual ssize_t sendto(
00246                      const GUSIGatherer & buffer, int flags, const void * to, socklen_t tolen);
00247  virtual ssize_t     recvmsg(msghdr * msg, int flags);
00248  virtual ssize_t sendmsg(const msghdr * msg, int flags);
00249 
00250  ssize_t      read(void * buffer, size_t length);
00251  ssize_t write(const void * buffer, size_t length);
00252  ssize_t recvfrom(
00253                      void * buffer, size_t length, int flags, void * from, socklen_t * fromlen);
00254  ssize_t sendto(
00255                      const void * buffer, size_t length, int flags, const void * to, socklen_t tolen);
00256        // A multitude of parameters can be manipulated for a [[GUSISocket]] through
00257  // the socket oriented calls [[getsockopt]], [[setsockopt]], the file oriented 
00258  // call [[fcntl]], and the device oriented call [[ioctl]].                 
00259  //                                                                         
00260  // [[isatty]] returns whether the socket should be considered an interactive 
00261  // console.                                                                
00262  //                                                                         
00263  // <Maintaining properties for [[GUSISocket]]>=                            
00264  virtual int getsockopt(int level, int optname, void *optval, socklen_t * optlen);
00265  virtual int setsockopt(int level, int optname, void *optval, socklen_t optlen);
00266  virtual int  fcntl(int cmd, va_list arg);
00267  virtual int  ioctl(unsigned int request, va_list arg);
00268  virtual int  isatty();
00269        // Three of the operations make sense primarily for files, and most other socket
00270  // types accept the default implementations. [[fstat]] returns information about
00271  // an open file, [[lseek]] repositions the read/write pointer, and [[ftruncate]]
00272  // cuts off an open file at a certain point.                               
00273  //                                                                         
00274  // <File oriented operations for [[GUSISocket]]>=                          
00275  virtual int  fstat(struct stat * buf);
00276  virtual off_t lseek(off_t offset, int whence);
00277  virtual int ftruncate(off_t offset);
00278        // [[select]] polls or waits for one of a group of [[GUSISocket]] to become
00279  // ready for reading, writing, or for an exceptional condition to occur.   
00280  // First, [[pre_select]] is called once for all [[GUSISocket]]s in the group.
00281  // It returns [[true]] is the socket will wake up as soon as one of the events
00282  // occurs and [[false]] if GUSI needs to poll.                             
00283  // Next, [[select]] is called for all [[GUSISocket]]s once or multiple times,
00284  // until a condition becomes true or the call times out. Finally, [[post_select]]
00285  // is called for all members of the group.                                 
00286  //                                                                         
00287  // <Multiplexing for [[GUSISocket]]>=                                      
00288  virtual bool pre_select(bool wantRead, bool wantWrite, bool wantExcept);
00289  virtual bool select(bool * canRead, bool * canWrite, bool * exception);
00290  virtual void post_select(bool wantRead, bool wantWrite, bool wantExcept);
00291        // A socket connection is usually full duplex. By calling [[shutdown(1)]], you 
00292  // indicate that you won't write any more data on this socket. The values 0 (no
00293  // more reads) and 2 (no more read/write) are used less frequently.        
00294  //                                                                         
00295  // <Miscellaneous operations for [[GUSISocket]]>=                          
00296  virtual int shutdown(int how);
00297  // Some socket types do not write out data immediately. Calling [[fsync]] guarantees
00298  // that all data is written.                                               
00299  //                                                                         
00300  // <Miscellaneous operations for [[GUSISocket]]>=                          
00301  virtual int fsync();
00302 };
00303 
00304 #if PRAGMA_STRUCT_ALIGN
00305 #pragma options align=reset
00306 #endif
00307 
00308 // \section{Implementation of [[GUSISocket]]}                              
00309 //                                                                         
00310 // \subsection{General socket management}                                  
00311 //                                                                         
00312 //                                                                         
00313 // <Inline member functions for class [[GUSISocket]]>=                     
00314 inline void GUSISocket::AddReference() 
00315 {
00316        ++fRefCount;
00317 }
00318 
00319 inline void GUSISocket::RemoveReference()
00320 {
00321        if (!--fRefCount)
00322               close();
00323 }
00324 
00325 // \subsection{Context management}                                         
00326 //                                                                         
00327 //                                                                         
00328 // <Inline member functions for class [[GUSISocket]]>=                     
00329 inline void GUSISocket::Wakeup()
00330 {
00331        fContexts.Wakeup();
00332 }
00333 
00334 // The traditional flavors of the I/O calls are translated to the scatterer/gatherer
00335 // variants.                                                               
00336 //                                                                         
00337 // <Inline member functions for class [[GUSISocket]]>=                     
00338 inline ssize_t       GUSISocket::read(void * buffer, size_t length)
00339 {      
00340        return read(GUSIScatterer(buffer, length));      
00341 }
00342 
00343 inline ssize_t GUSISocket::write(const void * buffer, size_t length)
00344 {      
00345        return write(GUSIGatherer(buffer, length));      
00346 }
00347 
00348 inline ssize_t GUSISocket::recvfrom(
00349        void * buffer, size_t length, int flags, void * from, socklen_t * fromlen)
00350 {      
00351        return recvfrom(GUSIScatterer(buffer, length), flags, from, fromlen); 
00352 }
00353 
00354 inline ssize_t GUSISocket::sendto(
00355        const void * buffer, size_t length, int flags, const void * to, socklen_t tolen)
00356 {      
00357        return sendto(GUSIGatherer(buffer, length), flags, to, tolen); 
00358 }
00359 
00360 #endif /* GUSI_SOURCE */
00361 
00362 #endif /* _GUSISocket_ */