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

Generated on Sat Apr 9 20:11:28 2005 for Mango by doxygen 1.3.6