src/Network/Reactor.cc
author terom
Tue, 16 Dec 2008 23:21:26 +0000
changeset 380 d193dd1d8a7e
child 384 6d387796b139
permissions -rw-r--r--
new NetworkReactor, fix everything to actually work

#include "Reactor.hh"


NetworkReactor::NetworkReactor (void) :
    sockets()
{

}

void NetworkReactor::poll (timeval *timeout) {
    // start counting the maximum fd from -1, so that select is given nfds=0 if our list is empty
    int fd_max = 0;

    // zero our fdsets
    fd_set read, write;
    FD_ZERO(&read);
    FD_ZERO(&write);

    // inspect our sockets
    for (std::list<NetworkSocket*>::iterator it = sockets.begin(); it != sockets.end(); it++) {
        NetworkSocket *socket = *it;
    
        // ask socket what events it wants
        NetworkPollMask mask = socket->get_poll();

        // set read/write
        if (mask) {
            // socket file descriptor...
            int fd = socket->get_socket();

            // ignore invalid FDs
            if (fd < 0)
                continue;
            
            // update fd_max?
            if (fd > fd_max)
                fd_max = fd;
            
            // read...
            if (mask & POLL_READ)
                FD_SET(socket->get_socket(), &read);
            
            // write...
            if (mask & POLL_WRITE)
                FD_SET(socket->get_socket(), &write);
        }
    }

    // run select
    int ret;
    
    // we never care about except
    // pass NULL fdsets if they are empty
    if ((ret = select(
            fd_max + 1, 
            fd_max ? &read : NULL, 
            fd_max ? &write : NULL, 
            NULL, 
            timeout
    )) < 0)
        throw NetworkReactorError("select");
    
    // ignore if we just timed out
    if (ret == 0)
        return;

    // notify up to <ret> socket-events
    for (std::list<NetworkSocket*>::iterator it = sockets.begin(); it != sockets.end() && ret > 0; it++) {
        NetworkSocket *socket = *it;

        // socket file descriptor...
        int fd = socket->get_socket();
            
        // ignore invalid FDs
        if (fd < 0)
            continue;
        
        // mask of events detected
        NetworkPollMask mask = 0;
        
        // detect read
        if (FD_ISSET(fd, &read)) {
            mask |= POLL_READ;
            ret--;
        }

        // detect write
        if (FD_ISSET(fd, &write)) {
            mask |= POLL_WRITE;
            ret--;
        }
        
        // notify?
        if (mask)
            socket->notify(mask);
    }
}

// the global reactor
static NetworkReactor g_reactor;
NetworkReactor *NetworkReactor::current = &g_reactor;