Main Page | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | File Members | Related Pages

SocketConduit.d

Go to the documentation of this file.
00001 /*******************************************************************************
00002 
00003         @file SocketConduit.d
00004         
00005         Copyright (C) 2004 Kris Bell
00006         
00007         This software is provided 'as-is', without any express or implied
00008         warranty. In no event will the authors be held liable for damages
00009         of any kind arising from the use of this software.
00010         
00011         Permission is hereby granted to anyone to use this software for any 
00012         purpose, including commercial applications, and to alter it and/or 
00013         redistribute it freely, subject to the following restrictions:
00014         
00015         1. The origin of this software must not be misrepresented; you must 
00016            not claim that you wrote the original software. If you use this 
00017            software in a product, an acknowledgment within documentation of 
00018            said product would be appreciated but is not required.
00019 
00020         2. Altered source versions must be plainly marked as such, and must 
00021            not be misrepresented as being the original software.
00022 
00023         3. This notice may not be removed or altered from any distribution
00024            of the source.
00025 
00026 
00027                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00028 
00029 
00030         @version        Initial version, March 2004      
00031         @author         Kris
00032 
00033 
00034 *******************************************************************************/
00035 
00036 module mango.io.SocketConduit;
00037 
00038 version = UseFreeList;
00039 
00040 public  import  mango.io.Socket;
00041 
00042 private import  mango.io.Buffer,
00043                 mango.io.Exception,
00044                 mango.io.ConduitStyle;
00045 
00046 private import  mango.io.model.IConduit;
00047 
00048 /*******************************************************************************
00049 
00050         A wrapper around the bare Socket to implement the IConduit abstraction
00051         and add further functionality.
00052 
00053 *******************************************************************************/
00054 
00055 class SocketConduit : Socket, IConduit, ISocketReader
00056 {       
00057         private timeval         tv;
00058         private SocketSet       ss;
00059         private IConduitSource  input;
00060         private IConduitSink    output;
00061 
00062         version (UseFreeList)
00063         {
00064                 /***************************************************************
00065 
00066                         Instance variables for free-list support
00067 
00068                 ***************************************************************/
00069 
00070                 private SocketConduit           next;   
00071                 private bool                    fromList;
00072                 private static SocketConduit    freelist;
00073 
00074                 /***************************************************************
00075 
00076                         Allocate a SocketConduit from a list rather than 
00077                         creating a new one
00078 
00079                 ***************************************************************/
00080 
00081                 private static synchronized SocketConduit allocate (socket_t sock)
00082                 {       
00083                         SocketConduit s;
00084 
00085                         if (freelist)
00086                            {
00087                            s = freelist;
00088                            freelist = s.next;
00089                            s.set (sock);
00090                            }
00091                         else
00092                            {
00093                            s = new SocketConduit (sock);
00094                            s.fromList = true;
00095                            }
00096                         return s;
00097                 }
00098 
00099                 /***************************************************************
00100 
00101                         Return this SocketConduit to the free-list
00102 
00103                 ***************************************************************/
00104 
00105                 private static synchronized void deallocate (SocketConduit s)
00106                 {
00107                         // socket handle is no longer valid
00108                         s.reset ();
00109                         s.next = freelist;
00110                         freelist = s;
00111                 }
00112 
00113                 /***************************************************************
00114 
00115                         Override closure() to deallocate this SocketConduit 
00116                         when it has been closed. Note that one should *not* 
00117                         delete a SocketConduit when FreeList is enabled ...
00118 
00119                 ***************************************************************/
00120 
00121                 protected override void closure ()
00122                 {       
00123                         input.unbind ();
00124                         output.unbind ();
00125                         fixup ();
00126 
00127                         // be a nice client, and tell the server?
00128                         //super.shutdown();
00129 
00130                         // do this first cos' we're gonna' reset the
00131                         // socket handle during deallocate()
00132                         super.closure ();
00133 
00134                         // deallocate if this came from the free-list,
00135                         // otherwise just wait for the GC to handle it
00136                         if (fromList)
00137                             deallocate (this);
00138                 }
00139         }
00140         else
00141         {
00142                 /***************************************************************
00143         
00144                         Method to close the filters. This is invoked from the 
00145                         Resource base-class when the resource is being closed.
00146                         You should ensure that a subclass invokes this as part
00147                         of its closure mechanics.
00148 
00149                 ***************************************************************/
00150 
00151                 protected override void closure ()
00152                 {       
00153                         input.unbind ();
00154                         output.unbind ();
00155                 }    
00156         }
00157 
00158         /***********************************************************************
00159         
00160         ***********************************************************************/
00161 
00162         private void fixup ()
00163         {
00164                 input = this;
00165                 output = this;
00166         }
00167                         
00168         /***********************************************************************
00169         
00170                 Construct this SocketConduit with the given socket handle;
00171                 this is for FreeList and ServerSocket support.
00172 
00173         ***********************************************************************/
00174 
00175         static SocketConduit create (socket_t handle)
00176         {
00177                 version (UseFreeList)
00178                         {
00179                         // allocate one from the free-list
00180                         return allocate (handle);
00181                         }
00182                      else
00183                         {
00184                         // create a new SocketConduit instance
00185                         return new SocketConduit (handle);
00186                         }
00187         }
00188 
00189         /***********************************************************************
00190         
00191                 Create a streaming Internet Socket
00192 
00193         ***********************************************************************/
00194 
00195         this ()
00196         {
00197                 super (Socket.AddressFamily.INET, Socket.Type.STREAM, Socket.Protocol.IP);                
00198                 fixup ();
00199         }
00200 
00201         /***********************************************************************
00202         
00203                 Construct this SocketConduit with the given socket handle;
00204                 this is for FreeList and ServerSocket support.
00205 
00206         ***********************************************************************/
00207 
00208         private this (socket_t handle)
00209         {
00210                 super (handle);                
00211                 fixup ();
00212         }
00213 
00214         /***********************************************************************
00215         
00216                 Create a Buffer of a conduit-specific size. I think 8K bytes
00217                 is the common standard for socket buffering?
00218 
00219         ***********************************************************************/
00220 
00221         IBuffer createBuffer ()
00222         {
00223                 Buffer buffer = new Buffer (1024 * 8);
00224                 buffer.setConduit (this);
00225                 return buffer;
00226         }
00227 
00228         /***********************************************************************
00229         
00230                 Set the read timeout to the specified microseconds. Set a 
00231                 value of zero to disable timeout support.
00232 
00233         ***********************************************************************/
00234 
00235         void setTimeout (uint us)
00236         {
00237                 tv.tv_sec = 0;
00238                 tv.tv_usec = us;
00239         }
00240                          
00241         /***********************************************************************
00242         
00243                 Please refer to IConduit.attach for details
00244 
00245         ***********************************************************************/
00246 
00247         void attach (IConduitSource input)
00248         {
00249                 input.bind (this.input);
00250                 this.input = input;
00251         }
00252 
00253         /***********************************************************************
00254                 
00255                 Please refer to IConduit.attach for details
00256 
00257         ***********************************************************************/
00258 
00259         void attach (IConduitSink output)
00260         {
00261                 output.bind (this.output);
00262                 this.output = output;
00263         }
00264 
00265         /***********************************************************************
00266         
00267         ***********************************************************************/
00268 
00269         protected void bind (IConduitSink sink)
00270         {
00271         }
00272                               
00273         /***********************************************************************
00274         
00275         ***********************************************************************/
00276 
00277         protected void bind (IConduitSource source)
00278         {
00279         }                            
00280                               
00281         /***********************************************************************
00282         
00283         ***********************************************************************/
00284 
00285         protected void unbind ()
00286         {
00287         }
00288 
00289         /***********************************************************************
00290         
00291                 Callback routine to read content from the socket. Note 
00292                 that the operation may timeout if method setTimeout()
00293                 has been invoked with a non-zero value.         
00294 
00295                 Returns the number of bytes read from the socket, or
00296                 IConduit.Eof where there's no more content available
00297 
00298         ***********************************************************************/
00299 
00300         protected int reader (void[] src)
00301         {
00302                 // ensure just one read at a time 
00303                 synchronized (_lock)
00304                 {
00305                 // did user disable timeout checks?
00306                 if (tv.tv_usec)
00307                    {
00308                    // nope: ensure we have a SocketSet
00309                    if (ss is null)
00310                        ss = new SocketSet(1);
00311 
00312                    ss.reset();
00313                    ss.add(this);
00314 
00315                    // wait until data is available
00316                    if (select (ss, null, null, &tv) <= 0)
00317                        return Eof;
00318                    }
00319 
00320                 int count = receive (src);
00321                 if (count <= 0)
00322                     count = Eof;
00323                 return count;
00324                 }
00325         }
00326 
00327         /***********************************************************************
00328         
00329                 Callback routine to write the provided content to the 
00330                 socket. This will stall until the socket responds in
00331                 some manner. Returns the number of bytes sent to the
00332                 output, or IConduit.Eof if the socket cannot write.
00333 
00334         ***********************************************************************/
00335 
00336         protected int writer (void[] src)
00337         {
00338                 int count = send (src);
00339                 if (count <= 0)
00340                     count = Eof;
00341                 return count;
00342         }
00343 
00344         /***********************************************************************
00345         
00346                 Read from conduit into a target buffer. Note that this 
00347                 uses SocketSet to handle timeouts, such that the socket
00348                 does not stall forever.
00349 
00350         ***********************************************************************/
00351 
00352         int read (IBuffer target)
00353         in {
00354            assert (target);
00355            }
00356         body
00357         {
00358                 return target.write (&input.reader);
00359         }
00360 
00361         /***********************************************************************
00362         
00363                 Write to conduit from a source buffer.
00364 
00365         ***********************************************************************/
00366 
00367         int write (IBuffer source)
00368         in {
00369            assert (source);
00370            }
00371         body
00372         {
00373                 int count = source.read (&output.writer);
00374 
00375                 // if we didn't write everything, move remaining content
00376                 // to front of buffer for a subsequent write
00377                 source.compress();
00378                 return count;
00379         }
00380 
00381         /***********************************************************************
00382         
00383                 This conduit is not seekable
00384 
00385         ***********************************************************************/
00386 
00387         bool isSeekable ()
00388         {
00389                 return false;
00390         }               
00391 
00392         /***********************************************************************
00393         
00394                 This conduit is readable
00395 
00396         ***********************************************************************/
00397 
00398         bool isReadable ()
00399         {
00400                 return true;
00401         }               
00402 
00403         /***********************************************************************
00404         
00405                 This conduit is writable
00406 
00407         ***********************************************************************/
00408 
00409         bool isWritable ()
00410         {
00411                 return true;
00412         }               
00413 
00414         /***********************************************************************
00415 
00416                 Transfer the content of this conduit to another one. 
00417                 Returns true if all content was successfully copied.
00418         
00419         ***********************************************************************/
00420 
00421         IConduit copy (IConduit source)
00422         in {
00423            assert (source);
00424            }
00425         body
00426         {
00427                 IBuffer buffer = createBuffer ();
00428 
00429                 while (source.read (buffer) != Eof)
00430                        if (write (buffer) == Eof)
00431                            throw new IOException ("Eof while copying to Socket");
00432 
00433                 // flush any remains into the target
00434                 return flush (buffer);
00435         }               
00436 
00437         /***********************************************************************
00438         
00439                 Flush buffer content out to this conduit.
00440 
00441                 Returns true if all content is flushed; false if writing 
00442                 results in an Eof condition.
00443                         
00444         ***********************************************************************/
00445 
00446         IConduit flush (IBuffer source)
00447         {
00448                 while (source.readable())
00449                        if (write (source) == Eof)
00450                            throw new IOException ("Eof while flushing Socket");
00451                 return this;
00452         }               
00453 
00454         /***********************************************************************
00455         
00456                 Return the style used to open the conduit
00457 
00458         ***********************************************************************/
00459 
00460         ConduitStyle getStyle ()
00461         {
00462                 return ConduitStyle.ReadWrite;
00463         }    
00464 }
00465 
00466 
00467 

Generated on Sun Nov 7 19:06:53 2004 for Mango by doxygen 1.3.6