view dreactor/transport/AsyncSocketConduit.d @ 0:7a315154bf5e

Initial commit
author rick@minifunk
date Sun, 08 Jun 2008 01:45:38 -0400
parents
children d3374d553986
line wrap: on
line source

/*******************************************************************************

        copyright:      Copyright (c) 2004 Kris Bell. All rights reserved

        license:        BSD style: $(LICENSE)

        version:        Mar 2004 : Initial release
        version:        Jan 2005 : RedShodan patch for timeout query
        version:        Dec 2006 : Outback release
        
        author:         Kris, modified by Rick Richardson (May 2008)

*******************************************************************************/

module dreactor.transport.AsyncSocketConduit;

private import  tango.time.Time;

public  import  tango.io.Conduit;

private import  tango.net.Socket;

/*******************************************************************************

        A wrapper around the bare Socket to implement the IConduit abstraction
        and add socket-specific functionality specifically for multiplexing via 
        poll and the ilk.

        AsyncSocketConduit data-transfer is typically performed in conjunction with
        an IBuffer, but can happily be handled directly using void array where
        preferred
        
*******************************************************************************/

class AsyncSocketConduit : Conduit
{
        package Socket                  socket_;

        /***********************************************************************
        
                Create a streaming Internet Socket

        ***********************************************************************/
        /* overriding the enum from the IConduit interface */
        enum : uint 
        {
                Eof = uint.max, /// the End-of-Flow identifer
                Err = uint.max -1 // some error ocurred, Should disconnect
        }

        this ()
        {
                this (SocketType.STREAM, ProtocolType.TCP);
        }

        /***********************************************************************
        
                Create an Internet Socket. Used by subclasses and by
                ServerSocket; the latter via method allocate() below

        ***********************************************************************/

        protected this (SocketType type, ProtocolType protocol, bool create=true)
        {
                socket_ = new Socket (AddressFamily.INET, type, protocol, create);
        }

        /***********************************************************************

                Return the name of this device

        ***********************************************************************/

        override char[] toString()
        {
                return socket.toString;
        }

        /***********************************************************************

                Return the socket wrapper
                
        ***********************************************************************/

        Socket socket ()
        {
                return socket_;
        }

        /***********************************************************************

                Return a preferred size for buffering conduit I/O

        ***********************************************************************/

        override uint bufferSize ()
        {
                return 1024 * 8;
        }

        /***********************************************************************

                Models a handle-oriented device.

                TODO: figure out how to avoid exposing this in the general
                case

        ***********************************************************************/

        override Handle fileHandle ()
        {
                return cast(Handle) socket_.fileHandle;
        }

        /***********************************************************************

                Is this socket still alive?

        ***********************************************************************/

        override bool isAlive ()
        {
                return socket_.isAlive;
        }

        /***********************************************************************

                Connect to the provided endpoint
        
        ***********************************************************************/

        AsyncSocketConduit connect (Address addr)
        {
                socket_.connect (addr);
                return this;
        }

        /***********************************************************************

                Bind the socket. This is typically used to configure a
                listening socket (such as a server or multicast socket).
                The address given should describe a local adapter, or
                specify the port alone (ADDR_ANY) to have the OS assign
                a local adapter address.
        
        ***********************************************************************/

        AsyncSocketConduit bind (Address address)
        {
                socket_.bind (address);
                return this;
        }

        /***********************************************************************

                Inform other end of a connected socket that we're no longer
                available. In general, this should be invoked before close()
                is invoked
        
                The shutdown function shuts down the connection of the socket: 

                    -   stops receiving data for this socket. If further data 
                        arrives, it is rejected.

                    -   stops trying to transmit data from this socket. Also
                        discards any data waiting to be sent. Stop looking for 
                        acknowledgement of data already sent; don't retransmit 
                        if any data is lost.

        ***********************************************************************/

        AsyncSocketConduit shutdown ()
        {
                socket_.shutdown (SocketShutdown.BOTH);
                return this;
        }

        /***********************************************************************

                Release this AsyncSocketConduit

                Note that one should always disconnect a AsyncSocketConduit 
                under normal conditions, and generally invoke shutdown 
                on all connected sockets beforehand

        ***********************************************************************/

        override void detach ()
        {
                socket_.detach;

                // deallocate if this came from the free-list,
                // otherwise just wait for the GC to handle it
                if (fromList)
                    deallocate (this);
        }

       /***********************************************************************
                
                Read content from the socket. 

                Returns the number of bytes read from the socket, or
                IConduit.Eof where there's no more content available

                Note that a timeout is equivalent to Eof. Isolating
                a timeout condition can be achieved via hadTimeout()

                Note also that a zero return value is not legitimate;
                such a value indicates Eof

        ***********************************************************************/

        override uint read (void[] dst)
        {
                return read (dst, (void[] dst){return socket_.receive(dst);});
        }
        
        /***********************************************************************

                Callback routine to write the provided content to the
                socket. This will stall until the socket responds in
                some manner. Returns the number of bytes sent to the
                output, or IConduit.Eof if the socket cannot write.

        ***********************************************************************/

        override uint write (void[] src)
        {
                int count = socket_.send (src);
                if (count == 0)
                    count = Eof;
                else if (count < 0)
                    count = Err;
                return count;
        }

        /***********************************************************************
 
                Internal routine to handle socket read under a timeout.
                Note that this is synchronized, in order to serialize
                socket access

        ***********************************************************************/

        package final uint read (void[] dst, int delegate(void[]) dg)
        {
                // invoke the actual read op
                int count = dg (dst);
                if (count == 0)
                    return Eof;
                else if (count < 0)
                    return Err;
              
                return count;
        }
        
}