Back to index

lightning-sunbird  0.9+nobinonly
GUSISocketMixins.h
Go to the documentation of this file.
00001 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
00002 // % Project  :      GUSI                        -      Grand Unified Socket Interface                    
00003 // % File            :      GUSISocketMixins.nw  -      Useful building blocks                  
00004 // % Author   :      Matthias Neeracher                                           
00005 // % Language :      C++                                                        
00006 // %                                                                       
00007 // % $Log: GUSISocketMixins.h,v $
00008 // % Revision 1.1  2001/03/11 22:38:21  sgehani%netscape.com
00009 // % First Checked In.
00010 // %                                         
00011 // % Revision 1.11  2000/10/16 04:10:12  neeri                             
00012 // % Add GUSISMProcess                                                     
00013 // %                                                                       
00014 // % Revision 1.10  2000/05/23 07:24:58  neeri                             
00015 // % Improve formatting                                                    
00016 // %                                                                       
00017 // % Revision 1.9  1999/08/26 05:45:09  neeri                              
00018 // % Fixes for literate edition of source code                             
00019 // %                                                                       
00020 // % Revision 1.8  1999/08/02 07:02:46  neeri                              
00021 // % Support for asynchronous errors and other socket options              
00022 // %                                                                       
00023 // % Revision 1.7  1999/05/29 06:26:45  neeri                              
00024 // % Fixed header guards                                                   
00025 // %                                                                       
00026 // % Revision 1.6  1999/04/29 05:33:18  neeri                              
00027 // % Fix fcntl prototype                                                   
00028 // %                                                                       
00029 // % Revision 1.5  1999/03/17 09:05:13  neeri                              
00030 // % Added GUSITimer, expanded docs                                        
00031 // %                                                                       
00032 // % Revision 1.4  1998/10/11 16:45:24  neeri                              
00033 // % Ready to release 2.0a2                                                
00034 // %                                                                       
00035 // % Revision 1.3  1998/01/25 20:53:59  neeri                              
00036 // % Engine implemented, except for signals & scheduling                   
00037 // %                                                                       
00038 // % Revision 1.2  1997/11/13 21:12:13  neeri                              
00039 // % Fall 1997                                                             
00040 // %                                                                       
00041 // % Revision 1.1  1996/12/16 02:12:42  neeri                              
00042 // % TCP Sockets sort of work                                              
00043 // %                                                                       
00044 // %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  
00045 //                                                                         
00046 // \chapter{Mixin Classes for Sockets}                                     
00047 //                                                                         
00048 // This section contains some building block classes for sockets:          
00049 //                                                                         
00050 // \begin{itemize}                                                         
00051 // \item [[GUSISMBlocking]] implements the blocking/nonblocking flag.      
00052 // \item [[GUSISMState]] implements a state variable.                      
00053 // \item [[GUSISMInputBuffer]] provides a [[GUSIBuffer]] for input.        
00054 // \item [[GUSISMOutputBuffer]] provides a [[GUSIBuffer]] for output.      
00055 // \item [[GUSISMAsyncError]] provides storage for asynchronous errors.    
00056 // \item [[GUSISMProcess]] maintains a link to the process instance.       
00057 // \end{itemize}                                                           
00058 //                                                                         
00059 //                                                                         
00060 // <GUSISocketMixins.h>=                                                   
00061 #ifndef _GUSISocketMixins_
00062 #define _GUSISocketMixins_
00063 
00064 #ifdef GUSI_INTERNAL
00065 
00066 #include "GUSISocket.h"
00067 #include "GUSIBuffer.h"
00068 
00069 #include <fcntl.h>
00070 #include <sys/ioctl.h>
00071 
00072 // \section{Definition of [[GUSISocketMixins]]}                            
00073 //                                                                         
00074 // [[GUSISMBlocking]] implements the [[fBlocking]] flags and the [[DoIoctl]] and
00075 // [[DoFcntl]] variants to manipulate it. These two functions work like their
00076 // [[GUSISocket]] member function counterparts, but handle the return value 
00077 // differently: The POSIX function result is stored in [[*result]], while the
00078 // return value indicates whether the request was handled.                 
00079 //                                                                         
00080 // <Definition of class [[GUSISMBlocking]]>=                               
00081 class GUSISMBlocking {
00082 public:
00083        GUSISMBlocking();
00084        bool   fBlocking;
00085        bool   DoFcntl(int * result, int cmd, va_list arg);
00086        bool   DoIoctl(int * result, unsigned int request, va_list arg);
00087 };
00088 // [[GUSISMState]] captures the state of a socket over its lifetime. It starts out
00089 // as [[Unbound]]. [[bind]] will put it into [[Unconnected]] state, though few
00090 // socket classes care about this distinction. [[listen]] will put it into 
00091 // [[Listening]] state. [[accept]] starts a [[Connected]] new socket.      
00092 // [[connect]] puts an [[Unconnected]] socket into [[Connecting]] state from
00093 // where it emerges [[Connected]]. [[fReadShutdown]] and [[fWriteShutdown]] record
00094 // shutdown promises.                                                      
00095 //                                                                         
00096 // <Definition of class [[GUSISMState]]>=                                  
00097 class GUSISMState {
00098 public:
00099        enum State {
00100               Unbound,
00101               Unconnected,  
00102               Listening,
00103               Connecting,
00104               Connected,
00105               Closing
00106        };
00107        GUSISMState();
00108        State  fState;
00109        bool   fReadShutdown;
00110        bool   fWriteShutdown;
00111        void   Shutdown(int how);
00112 };
00113 // [[GUSISMInputBuffer]] defines the input buffer and some socket options that go
00114 // with it. [[DoGetSockOpt]] and [[DoSetSockOpt]] work the same way as     
00115 // [[DoFcntl]] and [[DoIoctl]] above.                                      
00116 //                                                                         
00117 // <Definition of class [[GUSISMInputBuffer]]>=                            
00118 class GUSISMInputBuffer {
00119 public:
00120        GUSIRingBuffer       fInputBuffer;
00121        GUSISMInputBuffer();
00122        bool                 DoGetSockOpt(
00123                                           int * result, int level, int optname, 
00124                                           void *optval, socklen_t * optlen);
00125        bool                 DoSetSockOpt(
00126                                           int * result, int level, int optname, 
00127                                           void *optval, socklen_t optlen);   
00128        bool                 DoIoctl(int * result, unsigned int request, va_list arg);
00129 };
00130 // [[GUSISMOutputBuffer]] defines the output buffer and some socket options that go
00131 // with it.                                                                
00132 //                                                                         
00133 // <Definition of class [[GUSISMOutputBuffer]]>=                           
00134 class GUSISMOutputBuffer {
00135 public:
00136        GUSIRingBuffer       fOutputBuffer;
00137        GUSISMOutputBuffer();
00138        bool          DoGetSockOpt(
00139                                           int * result, int level, int optname, 
00140                                           void *optval, socklen_t * optlen);
00141        bool          DoSetSockOpt(
00142                                           int * result, int level, int optname, 
00143                                           void *optval, socklen_t optlen);   
00144 };
00145 // [[GUSISMAsyncError]] stores asynchronous errors and makes them available via
00146 // [[getsockopt]]. [[GetAsyncError]] returns the error and resets the stored value.
00147 //                                                                         
00148 // <Definition of class [[GUSISMAsyncError]]>=                             
00149 class GUSISMAsyncError {
00150 public:
00151        GUSISMAsyncError();
00152        int                  fAsyncError;
00153        int                  SetAsyncPosixError(int error);
00154        int                  SetAsyncMacError(OSErr error);
00155        int                  GetAsyncError();
00156        bool          DoGetSockOpt(
00157                                           int * result, int level, int optname, 
00158                                           void *optval, socklen_t * optlen);
00159 };
00160 // [[GUSISMProcess]] stores a link to the global [[GUSIProcess]] instance, which is useful for completion routines.
00161 //                                                                         
00162 // <Definition of class [[GUSISMProcess]]>=                                
00163 class GUSISMProcess {
00164 public:
00165        GUSISMProcess();
00166        
00167        GUSIProcess * Process(); 
00168 private:
00169        GUSIProcess * fProcess;
00170 };
00171 
00172 // \section{Implementation of [[GUSISocketMixins]]}                        
00173 //                                                                         
00174 // Because all the member functions are simple and called in few places, it
00175 // makes sense to inline them.                                             
00176 //                                                                         
00177 // All sockets start out blocking.                                         
00178 //                                                                         
00179 // <Inline member functions for class [[GUSISMBlocking]]>=                 
00180 inline GUSISMBlocking::GUSISMBlocking() : fBlocking(true)      {}
00181 // For historical reasons, there is both an [[ioctl]] and a [[fcntl]] interface
00182 // to the blocking flag.                                                   
00183 //                                                                         
00184 // <Inline member functions for class [[GUSISMBlocking]]>=                 
00185 inline bool GUSISMBlocking::DoFcntl(int * result, int cmd, va_list arg)
00186 {
00187        switch(cmd) {
00188        case F_GETFL : 
00189               return (*result = fBlocking ? 0: FNDELAY), true;
00190        case F_SETFL : 
00191               fBlocking = !(va_arg(arg, int) & FNDELAY);
00192               
00193               return (*result = 0), true;
00194        }
00195        return false;
00196 }
00197 inline bool GUSISMBlocking::DoIoctl(int * result, unsigned int request, va_list arg)
00198 {
00199        if (request == FIONBIO) {
00200               fBlocking = !*va_arg(arg, int *);
00201               return (*result = 0), true;
00202        }
00203        return false;
00204 }
00205 // Sockets start out as unconnected.                                       
00206 //                                                                         
00207 // <Inline member functions for class [[GUSISMState]]>=                    
00208 inline GUSISMState::GUSISMState() : 
00209        fState(Unbound), fReadShutdown(false), fWriteShutdown(false)          {}
00210 // <Inline member functions for class [[GUSISMState]]>=                    
00211 inline void GUSISMState::Shutdown(int how)
00212 {
00213        if (!(how & 1))
00214               fReadShutdown = true;
00215        if (how > 0)
00216               fWriteShutdown = true;
00217 }
00218 // Buffers initially are 8K.                                               
00219 //                                                                         
00220 // <Inline member functions for class [[GUSISMInputBuffer]]>=              
00221 inline GUSISMInputBuffer::GUSISMInputBuffer() : fInputBuffer(8192)    {}
00222 // [[getsockopt]] is used to obtain the buffer size.                       
00223 //                                                                         
00224 // <Inline member functions for class [[GUSISMInputBuffer]]>=              
00225 inline bool GUSISMInputBuffer::DoGetSockOpt(
00226                                    int * result, int level, int optname, 
00227                                    void *optval, socklen_t *)
00228 {
00229        if (level == SOL_SOCKET && optname == SO_RCVBUF) {
00230               *(int *)optval = (int)fInputBuffer.Size();
00231               
00232               return (*result = 0), true;
00233        }
00234        return false;
00235 }
00236 // [[setsockopt]] modifies the buffer size.                                
00237 //                                                                         
00238 // <Inline member functions for class [[GUSISMInputBuffer]]>=              
00239 inline bool GUSISMInputBuffer::DoSetSockOpt(
00240                                    int * result, int level, int optname, 
00241                                    void *optval, socklen_t)
00242 {
00243        if (level == SOL_SOCKET && optname == SO_RCVBUF) {
00244               fInputBuffer.SwitchBuffer(*(int *)optval);
00245               
00246               return (*result = 0), true;
00247        }
00248        return false;
00249 }
00250 // [[ioctl]] returns the number of available bytes.                        
00251 //                                                                         
00252 // <Inline member functions for class [[GUSISMInputBuffer]]>=              
00253 inline bool GUSISMInputBuffer::DoIoctl(int * result, unsigned int request, va_list arg)
00254 {
00255        if (request == FIONREAD) {
00256               *va_arg(arg, long *) = fInputBuffer.Valid();
00257               return (*result = 0), true;
00258        }
00259        return false;
00260 }
00261 // [[GUSISMOutputBuffer]] works identically to the input buffer.           
00262 //                                                                         
00263 // <Inline member functions for class [[GUSISMOutputBuffer]]>=             
00264 inline GUSISMOutputBuffer::GUSISMOutputBuffer() : fOutputBuffer(8192) {}
00265 // [[getsockopt]] is used to obtain the buffer size.                       
00266 //                                                                         
00267 // <Inline member functions for class [[GUSISMOutputBuffer]]>=             
00268 inline bool GUSISMOutputBuffer::DoGetSockOpt(
00269                                    int * result, int level, int optname, 
00270                                    void *optval, socklen_t *)
00271 {
00272        if (level == SOL_SOCKET && optname == SO_SNDBUF) {
00273               *(int *)optval = (int)fOutputBuffer.Size();
00274               
00275               return (*result = 0), true;
00276        }
00277        return false;
00278 }
00279 // [[setsockopt]] is modifies the buffer size.                             
00280 //                                                                         
00281 // <Inline member functions for class [[GUSISMOutputBuffer]]>=             
00282 inline bool GUSISMOutputBuffer::DoSetSockOpt(
00283                                    int * result, int level, int optname, 
00284                                    void *optval, socklen_t)
00285 {
00286        if (level == SOL_SOCKET && optname == SO_SNDBUF) {
00287               fOutputBuffer.SwitchBuffer(*(int *)optval);
00288               
00289               return (*result = 0), true;
00290        }
00291        return false;
00292 }
00293 // <Inline member functions for class [[GUSISMAsyncError]]>=               
00294 inline GUSISMAsyncError::GUSISMAsyncError()
00295  : fAsyncError(0)
00296 {
00297 }
00298 // The central member functions of [[GUSISMAsyncError]] are [[SetAsyncXXXError]] and
00299 // [[GetAsyncError]].                                                      
00300 //                                                                         
00301 // <Inline member functions for class [[GUSISMAsyncError]]>=               
00302 inline int GUSISMAsyncError::SetAsyncPosixError(int error)
00303 {
00304        if (error) {
00305               fAsyncError = error;
00306               GUSI_MESSAGE(("GUSISMAsyncError::SetAsyncPosixError %d\n", fAsyncError));
00307               
00308               return -1;
00309        }
00310        return 0;
00311 }
00312 inline int GUSISMAsyncError::GetAsyncError()
00313 {
00314        int err = fAsyncError;
00315        fAsyncError = 0;
00316        return err;
00317 }
00318 // For some reason, the CW Pro 4 compilers generated bad code for this in some combination, so
00319 // we make it out of line.                                                 
00320 //                                                                         
00321 // <Inline member functions for class [[GUSISMAsyncError]]>=               
00322 inline int GUSISMAsyncError::SetAsyncMacError(OSErr error)
00323 {
00324        if (error) {
00325               fAsyncError = GUSIMapMacError(error);
00326               GUSI_MESSAGE(("GUSISMAsyncError::SetAsyncMacError %d -> %d\n", error, fAsyncError));
00327               
00328               return -1;
00329        }
00330        return 0;
00331 }
00332 // [[DoGetSockOpt]] only handles [[SO_ERROR]] (hi Philippe!).              
00333 //                                                                         
00334 // <Inline member functions for class [[GUSISMAsyncError]]>=               
00335 inline bool GUSISMAsyncError::DoGetSockOpt(
00336                                           int * result, int level, int optname, 
00337                                           void *optval, socklen_t * optlen)
00338 {
00339        if (level == SOL_SOCKET && optname == SO_ERROR) {
00340               *(int *)optval       = GetAsyncError();
00341               *optlen              = sizeof(int);
00342               
00343               return (*result = 0), true;
00344        }
00345        return false;
00346 }
00347 // <Inline member functions for class [[GUSISMProcess]]>=                  
00348 inline GUSISMProcess::GUSISMProcess()
00349  : fProcess(GUSIProcess::Instance())
00350 {
00351 }
00352 
00353 inline GUSIProcess * GUSISMProcess::Process()
00354 {
00355        return fProcess;
00356 }
00357 
00358 #endif /* GUSI_INTERNAL */
00359 
00360 #endif /* _GUSISocketMixins_ */