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

Generated on Mon Nov 14 10:59:40 2005 for Mango by  doxygen 1.4.0