view dreactor/protocol/RawTcp.d @ 5:f875a1f278b8

housekeeping
author rick@minifunk
date Tue, 08 Jul 2008 12:16:07 -0400
parents f8b01c9f7114
children 287ba7de97c4
line wrap: on
line source

module dreactor.protocol.RawTcp;

import tango.io.Conduit;
import tango.io.selector.model.ISelector;
import tango.net.Socket;
import tango.util.collection.CircularSeq;
import tango.util.log.Log;
import tango.util.log.Config;

import dreactor.transport.AsyncSocketConduit;
import dreactor.core.Vat;
import dreactor.core.ConnectionHandler;

/******************************************************************************
    
    Basic TCP server or client routines for sending raw data.

******************************************************************************/
class RawTCPListener
{
public
    Logger log; 
    this(ConnectionHandler mgr, Vat sel, IPv4Address addr)
    {
        manager = mgr;
        mgr.events(Event.Read);
        mgr.setOutgoingHandler(&Handlers.onSend);
        mgr.setIncomingHandler(&Handlers.onReceive);
        mgr.setConnectHandler(&accept);
        mgr.listen(addr);
        
        sel.addConnection(mgr);
        vat = sel;
        log = Log.lookup("dreactor.protocol.RawTcpServer");
        log.info("log initialized");
        children = new CircularSeq!(ConnectionHandler);
    }
 
    int accept(Conduit cond, RegisterD reg)
    {
        AsyncSocketConduit newcond = new AsyncSocketConduit;
        (cast(AsyncSocketConduit)cond).socket().accept(newcond.socket);
        ConnectionHandler h = ConnectionHandler.New(newcond, manager);
        h.events(Event.Read);
        vat.addConnection(h);
        children.append(h);
        log.info("accepted new connection");
        return 0;
    }

    int broadcast(char[] outbuf)
    {
        foreach(ConnectionHandler h; children)
        {
            if (h.appendOutBuffer(outbuf))
            {
                h.addEvent(Event.Write);
                vat.addConnection(h);
            }
        }
        return 0;
    }
 
    void close()
    {
        
    }

private
    ConnectionHandler manager;
    Vat vat;
    CircularSeq!(ConnectionHandler) children;
}

class RawTCPClient
{
public
    Logger log;
    this(ConnectionHandler mgr, Vat sel, Event evts = Event.Read)
    {
        manager = mgr;
        manager.events(evts);
        connected = false;
        mgr.setOutgoingHandler(&Handlers.onSend);
        mgr.setIncomingHandler(&Handlers.onReceive);
        vat = sel;
        log = Log.lookup("dreactor.protocol.RawTcpClient");
    }

    int connect(IPv4Address addr)
    {
        (cast(AsyncSocketConduit) manager.transport()).connect(addr);
        vat.addConnection(manager);
        connected = true;
        log.info("connected to {}", addr);
        return 0;
    } 

    /**************************************************************************
    
        send
        User-called function to send data to the counterpart at the other
        end of the connection. This sets up the connection manager to send
        data as the socket becomes free. 

    **************************************************************************/
    int send(char[] outbuf, IPv4Address addr = null)
    {
        if (!connected)
        {
            log.info("send: not connected, connecting");
            if (addr !is null)
            {
                if (0 > connect(addr))
                {
                    log.error("send: unable to connect");
                    return -1;
                }
            }
        }
        if (manager.appendOutBuffer(outbuf))
        {
            manager.addEvent(Event.Write);
            if (!vat.addConnection(manager))
            {
                log.error("unable to register mgr");
            }
        }
        return 0;
    }
    
private
    ConnectionHandler manager;
    Vat vat;
    bool connected;
}


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

    Default Event handlers common to both listener/clients

******************************************************************************/
class Handlers
{
/**************************************************************************

    onSend
    OutgoingHandlerD 
    To be registered as the response to socket writable event. 
    Sends data, returns amount sent. Unregisters Handler for sending
    if there is no more data left to send. 

***************************************************************************/
public static int onSend(ConnectionHandler h)
{
    Logger log = Log.lookup("Handlers.onSend");
 
    log.info("top of onSend");
    char[] outbuf = h.nextBuffer();
    if (outbuf !is null)
    {
        int sent = h.transport.write(outbuf);
        if (sent > 0)
        {
            if (! h.addOffset(sent))
            {
                h.remEvent(Event.Write);
                return REREGISTER;
            }
        }
        else if (sent == AsyncSocketConduit.Eof)
        {
            log.error("Select said socket was writable, but sent 0 bytes");
        }
        else
        {
           log.error("Socket send return ERR");
        }
        return REMAIN;
    }
    else
    {
        h.remEvent(Event.Write);
        return REREGISTER;
    }
}
/**************************************************************************

    receive
    IncomingHandlerD
    Default incoming data handler. Should be replaced with something useful.

**************************************************************************/ 
public static int onReceive(ConnectionHandler h)
{
    Logger log = Log.lookup("Handlers.onReceive");

    char inbuf[8192];
    int amt;
    if((amt = h.transport.read(inbuf)) > 0)
        log.info("Received {} byte Buffer: {}", amt, inbuf[0 .. amt]);
    else 
        log.error("Received no data, err = {}", amt);

    return REMAIN;
}
}