Hogwarts Wand Docs: ../server/ac_fdio.c

Wand Sourcecode: ../server/ac_fdio.c

//
// ac_fdio.c - file descriptor io functions
//
// Copyright (C) 2006  Nathan (Acorn) Pooley
// 
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// version 2 as published by the Free Software Foundation.
// 
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License (gpl.txt) for more details. 
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
// 
// You can contact the author, Nathan (Acorn) Pooley, by writing
// to Nathan (Acorn) Pooley, 949 Buckeye Drive, Sunnyvale, CA  94086, USA
// or through the form at http://www.rawbw.com/~acorn/wand/feedback.html
//
//
// Thanks to Gary Frerking for writing the Serial Programming HOWTO at
//    http://www.tldp.org/HOWTO/Serial-Programming-HOWTO
// Much of this is based on his descriptions and examples.
//

//#@DOC@ file descriptor io functions

//###########################################################################
//############################### INCLUDES ##################################
//###########################################################################

#include "ac_fdio.h"

#include <stdio.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

//###########################################################################
//############################### TYPEDEFS ##################################
//###########################################################################

//===========================================================================
// AcFdInfo - info about 1 file descriptor
//===========================================================================
typedef struct AcFdInfoRec {
    int fd;
    
    AcFdFunc    func;
    void        *data;

    struct AcFdInfoRec  *next;
    struct AcFdInfoRec  *prev;
} AcFdInfo;

//===========================================================================
// AcFdGroup - Group of file descriptors
//===========================================================================
struct AcFdGroupRec {
    int         fdmax;
    fd_set      fds;
    AcFdInfo    head;
    struct timeval *timeout;
};

//###########################################################################
//############################### GLOBALS ###################################
//###########################################################################

//###########################################################################
//############################### CODE ######################################
//###########################################################################

//===========================================================================
// AcFdGroupCreate()
//===========================================================================
AcFdGroup *AcFdGroupCreate(void)
{
    AcFdGroup *grp = calloc(1,sizeof(AcFdGroup));

    if (!grp) return 0;

    FD_ZERO(&grp->fds);
    grp->fdmax     = -1;
    grp->head.next = &grp->head;
    grp->head.prev = &grp->head;

    return grp;
}

//===========================================================================
// AcFdGroupDestroy()
//===========================================================================
void AcFdGroupDestroy(AcFdGroup *grp)
{
    //
    // remove all file descriptors
    //
    AcFdGroupRemove(grp,-1,0,0);

    AcFdGroupClearTimeout(grp);

    free(grp);
}

//===========================================================================
// AcFdGroupAdd() - add fd to group
//===========================================================================
int AcFdGroupAdd(AcFdGroup *grp, int fd, AcFdFunc func, void *data)
{
    AcFdInfo *i = calloc(1,sizeof(AcFdInfo));

    if (!i) return -1;

    i->fd = fd;
    i->func = func;
    i->data = data;

    i->next = grp->head.prev;
    i->prev = &grp->head;
    i->next->prev = i;
    i->prev->next = i;

    return 0;
}

//===========================================================================
// AcFdGroupRemove() - remove fd from group
//===========================================================================
int AcFdGroupRemove(AcFdGroup *grp, int fd, AcFdFunc func, void *data)
{
    AcFdInfo *i = grp->head.next;
    for(; i != &grp->head; i=i->next) {
        AcFdInfo *prev, *next;
        if (fd >= 0 && i->fd   != fd)   continue;
        if (func    && i->func != func) continue;
        if (data    && i->data != data) continue;
        prev = i->prev;
        next = i->next;
        next->prev = prev;
        prev->next = next;
        free(i);
        i = prev;
    }
    return 0;
}

//===========================================================================
// AcFdGroupCalcSet() - calc fds & fdmax
//===========================================================================
static void AcFdGroupCalcSet(AcFdGroup *grp)
{
    AcFdInfo *i = grp->head.next;

    FD_ZERO(&grp->fds);
    grp->fdmax = -1;
    
    for(; i != &grp->head; i=i->next) {
        FD_SET(i->fd, &grp->fds);
        grp->fdmax = (i->fd+1 > grp->fdmax) ? i->fd+1 : grp->fdmax;
    }
}

//===========================================================================
// AcFdGroupSetTimeout() - set te timeout period for select calls
//===========================================================================
void AcFdGroupSetTimeout(AcFdGroup *grp, long sec, long usec)
{
    grp->timeout = malloc(sizeof(struct timeval));
    grp->timeout->tv_sec = sec;
    grp->timeout->tv_usec = usec;
}

//===========================================================================
// AcFdGroupClearTimeout() - turn off the timeout (wait forever - default)
//===========================================================================
void AcFdGroupClearTimeout(AcFdGroup *grp)
{
    if (grp->timeout) {
        free(grp->timeout);
        grp->timeout = 0;
    }
}

//===========================================================================
// AcFdGroupDoWait() - wait for input & call handlers
//===========================================================================
//  If a fd becomes readable, one of the handler functions is called and its
//  return value is returned.
//  If a timeout occurs -2 is returned.
//  If an error occurs -1 is returned.
//
static int AcFdGroupDoWait(AcFdGroup *grp, struct timeval *tmo)
{
    AcFdInfo *i;
    int cnt;

    //
    // are there any fd to wait on?
    //
    AcFdGroupCalcSet(grp);
    if (grp->fdmax <= 0) {
        if (tmo) {
            grp->fdmax = 0;
        } else {
            return -1;
        }
    }

    //
    // wait until one of the fd has data to read
    //
    cnt = select(grp->fdmax, &grp->fds, 0, 0, tmo);
    if (cnt <= 0) {
        return (cnt==0)? -2 : -1;
    }

    //
    // call associated function
    //
    i = &grp->head;
    while(1) {
        i = i->next;
        if (i == &grp->head) return 0;
        if (FD_ISSET(i->fd, &grp->fds)) {
            if (i->func) {
                return i->func(i->fd, i->data);
            } else {
                return -1;
            }
        }
    }
}

//===========================================================================
// AcFdGroupWaitTimeout() - wait for & process input with timeout
//===========================================================================
//
// returns -2 on timeout
//
int AcFdGroupWaitTimeout(AcFdGroup *grp, unsigned long usecTimeout)
{
    struct timeval timeout;

    if (usecTimeout > 1000000) {
        timeout.tv_sec  = usecTimeout/1000000;
        timeout.tv_usec = usecTimeout % 1000000;
    } else {
        timeout.tv_sec = 0;
        timeout.tv_usec = usecTimeout;
    }

    return AcFdGroupDoWait(grp, &timeout);
}

//===========================================================================
// AcFdGroupWait() - wait for & process input
//===========================================================================
int AcFdGroupWait(AcFdGroup *grp)
{
    struct timeval timeout, *tmo = 0;

    if (grp->timeout) {
        memcpy(&timeout, grp->timeout, sizeof(timeout));
        tmo = &timeout;
    }
    return AcFdGroupDoWait(grp, tmo);
}

//===========================================================================
// AcFdGroupLoop() - loop waiting for & processing input
//===========================================================================
int AcFdGroupLoop(AcFdGroup *grp)
{
    for(;;) {
        int result = AcFdGroupWait(grp);
        if (result) return result;
    }
}

This file Copyright (C) 2006 by Nathan (Acorn) Pooley
Go to TOP Wand page
Go to Acorn's personal webpage
Go to Hogwarts website: www.gotohogwarts.com
Snout: www.snout.org/game
Gadgets of Justice Unlimited
Snout GC (Wiki)
Snout Wiki
File created by do_doc at Wed May 30 03:24:47 PDT 2007