view dreactor/core/ConnectionHandler.d @ 2:d3374d553986

updates
author rick@minifunk
date Thu, 12 Jun 2008 23:12:17 -0400
parents 7a315154bf5e
children e3dbc9208822
line wrap: on
line source

module dreactor.core.ConnectionHandler;

import tango.io.selector.model.ISelector;
import tango.net.Socket.Address;
import tango.util.collection.CircularSeq;

import dreactor.transport.AsyncSocketConduit;

alias bool delegate(ConnectionHandler) RegisterD;

alias bool delegate(ConnectionHandler, RegisterD)   IncomingHandlerD;
alias bool delegate(ConnectionHandler, RegisterD)   OutgoingHandlerD;
alias int delegate(ConnectionHandler, RegisterD)    ErrorHandlerD;
alias bool delegate(ConnectionHandler, RegisterD)   DisconnectHandlerD;
alias int delegate(Conduit, RegisterD)              ConnectHandlerD;

alias bool function(ConnectionHandler, RegisterD)   IncomingHandlerF;
alias bool function(ConnectionHandler, RegisterD)   OutgoingHandlerF;
alias int function(ConnectionHandler, RegisterD)    ErrorHandlerF;
alias bool function(ConnectionHandler, RegisterD)   DisconnectHandlerF;
alias int function(Conduit, RegisterD)              ConnectHandlerF;


/******************************************************************************
    ConnectionHandler object. To be used by the SelectLoop to manage callbacks 
    for events. It may also be used to buffer data inbetween requests.
    These can be populated passed to a SelectLoop directly by the end user, 
    or may be managed by a chosen Protocol. 
******************************************************************************/
class ConnectionHandler()
{
 public 
    enum { init, connected, listening, idle,  closing };
  
    /**************************************************************************

        Standard Ctor, takes a transport

    **************************************************************************/ 
    this (Conduit trans, bool listener = false)
    {
        transport = trans;
        ibuf_len = 0;
        obuf_len = 0;
        i_offset = 0;
        o_offset = 0;
    }
      
    /**********************************************************************
    
        Setters for the handlers. These are set by the Protocols as well 
    
    **********************************************************************/
    
    void setIncomingHandler(IncomingHandlerD hand)
    {
        inD = hand;
        inF = null;
    }

    void setIncomingHandler(IncomingHandlerF hand)
    {
        inF = hand;
        inD = null;
    }

    void setOutgoingHandler(OutgoingHandlerD hand)
    {
        outD = hand;
        outF = null;
    }

    void setOutgoingHandler(OutgoingHandlerF hand)
    {
        outF = hand;
        outD = null;
    }

    void setErrorHandler(ErrorHandlerD hand)
    {
        errD = hand;
        errF = null;
    }

    void setErrorHandler(ErrorHandlerF hand)
    {
        errF = hand;
        errD = null;
    }

    void setDisconnectHandler(DisconnectHandlerD hand)
    {
        disD = hand;
        disF = null;
    }

    void setDisconnectHandler(DisconnectHandlerF hand)
    {
        disF = hand;
        disD = null;
    }

    void setConnectHandler(ConnectHandlerD hand)
    {
        conD = hand;
        conF = null;
    }

    void setConnectHandler(ConnectHandlerF hand)
    {
        conF = hand;
        conD = null;
    }

    /**********************************************************************
        
        Handlers to be called by the SelectLoop when events occur
    
    **********************************************************************/
    void handleIncoming(Conduit cond)
    {
        if (!inD is null)
            return inD(cond);
        else if (!inF is null)
            return inF(cond);
    }

    void handleOutgoing(Conduit cond)
    {
        if (!outD is null)
            return outD(cond);
        else if (!outF is null)
            return outF(cond);
    }

    int handleError(Conduit cond)
    {
        if (!errD is null)
            return errD(cond);
        else if (!errF is null)
            return errF(cond);
    }

    int handleDisconnect(Conduit cond)
    {
        if (!disD is null)
            return disD(addr);
        else if (!disF is null)
            return disF(addr);
    }

    int handleConnection(Address addr)
    {
        if (!conD is null)
        {
            return conD(addr);
        }
        else if (!conF is null)
        {
            return conF(addr);
        }
    }

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

        Sending / Receiving helpers

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

    /**************************************************************************
    
        appendOutBuffer

        Adds an outgoing buffer to the list. This returns true if the list
        was empty, indicating that the handler should be registered with the
        SelectLoop. If it returns false, it was probably already registered.
        
    **************************************************************************/
    synchronized void appendOutBuffer(char[] outbuf)
    {
        out_buffers.append(outbuf);
        out_buffers_len++;
        if (out_buffers_len == 1)
            return true;
        else
            return false;
    }
   
    /**************************************************************************

        addOffset 
        Use this function to update the offset position after a successful data
        send. This not only manages the current offset, but will update the 
        out buffer chain if necessary. 

        Returns: false if there is nothing left to send, true if there is.

    **************************************************************************/ 
    synchronized bool addOffset(int off)
    in
    {
        assert(out_buffers_len > 0);
    }
    body
    {
        char[] hd = out_buffers.head();
        if ((off + o_offset) >= hd.length)
        {
            out_buffers.removeHead();
            o_offset = 0;
            out_buffers_len--;
            return (out_buffers_len > 0);
        }
        else
            o_offset += off;
        return true;
    }

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

        char[] nextBuffer

        Returns a slice of the current outbound buffer, returns a char[] pointing
        to null if there is no current outbound buffer

    **************************************************************************/
    synchronized char[] nextBuffer()
    {
        if (out_buffers_len < 1)
        {
            return null; 
        }

        return out_buffers.head()[o_offset .. $];
    }

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

        listen
        Enable listening on the socket attached to this connectionhandler

    **************************************************************************/
    int listen(IPv4Address addr)
    {
        transport.bind().listen();
        state = listening;
        setConnectionHandler()
    }


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

        Configuration functions

    **************************************************************************/
    Event events()
    {
        return events_;
    }
    void events(Event e)
    {
        events_ = e;
    }
    void addEvent(Event e)
    {
        events_ |= e;
    }
    void remEvent(Event e)
    {
        events_ ^= e;
    }

    State getState() {return state;}
    
    /*
       connection handlers are left out of this because 
       this method is used by the listener socket to pass 
       on its handlers to the accepted socket. An accepted
       socket will generally do different things onConnection
    */
    void setHandlers(ConnectionHandler other)
    {
        inD  = other.inD; 
        outD = other.outD;
        errD = other.errD;
        disD = other.disD;
        inF  = other.inF;
        outF = other.outF;
        errF = other.errF;
        disF = other.disF;
    }

    /**************************************************************************
    
        Freelist allocators and deallocators

    **************************************************************************/
    static synchronized ConnectionHandler New(Conduit tran, ConnectionHandler other = null)
    {
        ConnectionHandler hand;
	    if (freelist)
	    {   
            hand = freelist;
	        freelist = hand.next;
            hand.transport = tran;
	    }
	    else
	        hand = new ConnectionHandler(tran);

        if (!other is null)
        {
            hand.setHandlers(other);
        }
	    return hand;
    }

    static synchronized void Delete(ConnectionHandler hand)
    {   
        hand.next = freelist;
        freelist = hand.init();
    } 

private
    
    char[SZ] in_buffer;
    CircularSeq!(char[]) out_buffers;
    int ibuf_len;
    int i_offset;
    int o_offset;

    package Conduit transport;
    State state;
    Event events; 
    IncomingHandlerD    inD;
    OutgoingHandlerD    outD;
    ErrorHandlerD       errD;
    DisconnectHandlerD  disD;
    ConnectHandlerD     conD;

    IncomingHandlerF    inF;
    OutgoingHandlerF    outF;
    ErrorHandlerF       errF;
    DisconnectHandlerF  disF;
    ConnectHandlerF     conF;
    
    static ConnectionHandler freelist;
    ConnectionHandler next;

    /**************************************************************************
        Copy ctor, creates a new ConnectionHandler using the settings
        of an existing handler. 
    **************************************************************************/ 
    void init()
    {
        transport = null;
        state = State.init;
        ibuf_len = 0;
        obuf_len = 0;
        i_offset = 0;
        o_offset = 0;
        out_buffer = null;
        inD  = null;
        outD = null;
        errD = null;
        disD = null;
        conD = null;
        inF  = null;
        outF = null;
        errF = null;
        disF = null;
        conF = null;
    }
}