OSSP CVS Repository

ossp - ossp-pkg/sio/sio.c 1.1
Not logged in
[Honeypot]  [Browse]  [Directory]  [Home]  [Login
[Reports]  [Search]  [Ticket]  [Timeline
  [Raw

ossp-pkg/sio/sio.c 1.1
/*
**  OSSP sio -- stream I/O
**  Copyright (c) 2002 The OSSP Project <http://www.ossp.org/>
**  Copyright (c) 2002 Cable & Wireless Deutschland <http://www.cw.com/de/>
**  Copyright (c) 2002 Ralf S. Engelschall <rse@engelschall.com>
**  Copyright (c) 2002 Michael van Elst <mlelstv@dev.de.cw.net>
**
**  This file is part of OSSP sio, a library implementing layered I/O 
**
**  Permission to use, copy, modify, and distribute this software for
**  any purpose with or without fee is hereby granted, provided that
**  the above copyright notice and this permission notice appear in all
**  copies.
**
**  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
**  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
**  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
**  IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR
**  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
**  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
**  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
**  USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
**  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
**  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
**  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
**  SUCH DAMAGE.
**
**  sio.c: stream I/O library implementation
*/

#include <stddef.h>
#include <stdlib.h>

#include "al.h"
#include "sio.h"
#include "sio_module.h"
#include "list.h"

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

/* unique library identifier */
const char sio_id[] = "OSSP sio";

/* support for OSSP ex based exception throwing */
#ifdef WITH_EX
#include "ex.h"
#define SIO_RC(rv) \
    (  (rv) != SIO_OK && (ex_catching && !ex_shielding) \
         ? (ex_throw(sio_id, NULL, (rv)), (rv)) : (rv) )
#else
#define SIO_RC(rv) (rv)
#endif /* WITH_EX */


struct sio_halfduplex_st;
typedef struct sio_halfduplex_st sio_halfduplex_t;
struct sio_halfduplex_st {
    NODE(sio_halfduplex_t) hd;
    sio_stage_t *stage;
    sio_rc_t (*func)(sio_t *, al_t *, void *);
};

struct sio_st {
    struct {
        LIST(sio_halfduplex_t) hd;
        al_t                   *al;
    } readers;
    struct {
        LIST(sio_halfduplex_t) hd;
        al_t                   *al;
    } writers;
};

struct sio_stage_st {
    sio_halfduplex_t reader;
    sio_halfduplex_t writer;
    void *userdata;
    sio_module_t *module;
    sio_mode_t rw;
};

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

static
sio_rc_t sio_strategy(sio_t *sio, sio_halfduplex_t *chain, al_t *al)
{
    sio_rc_t rc;
    sio_halfduplex_t *h;

    h = chain;
    while (h != NULL) {
        rc = h->func(sio, al, h->stage->userdata);
        if (rc == SIO_UPSTREAM)
            h = NEXT(h,hd);
        else if (rc == SIO_DOWNSTREAM)
            h = NEXT(h,hd);
        else
            break;
    }

    return SIO_OK;
}

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

sio_rc_t sio_create(sio_t **siop)
{
    sio_t *sio;

    /* argument sanity check(s) */
    if (siop == NULL)
        return SIO_RC(SIO_ERR_ARG);

    sio = (sio_t *)malloc(sizeof(sio_t));
    if (sio == NULL)
        return SIO_RC(SIO_ERR_MEM);

    LISTINIT(&sio->readers,hd);
    LISTINIT(&sio->writers,hd);

    *siop = sio;

    return SIO_OK;
}

sio_rc_t sio_destroy(sio_t *sio)
{
    /* argument sanity check(s) */
    if (sio == NULL)
        return SIO_RC(SIO_ERR_ARG);

    free(sio);

    return SIO_OK;
}

sio_rc_t sio_create_stage(sio_t *sio, sio_module_t *siom, sio_stage_t **siosp)
{
    sio_rc_t rc;
    sio_stage_t *sios;
    void *u;

    /* argument sanity check(s) */
    if (sio == NULL || siom == NULL || siosp == NULL)
        return SIO_RC(SIO_ERR_ARG);

    sios = (sio_stage_t *)malloc(sizeof(sio_stage_t));
    if (sios == NULL)
        return SIO_RC(SIO_ERR_MEM);

    NODEINIT(&sios->reader,hd);
    NODEINIT(&sios->writer,hd);
    sios->module       = siom;
    sios->userdata     = u;
    sios->rw           = SIO_MODE_INVALID;
    sios->reader.func  = siom->input;
    sios->reader.stage = sios;
    sios->writer.func  = siom->output;
    sios->writer.stage = sios;

    rc = sios->module->init(sio, sios->userdata);

    return SIO_RC(rc);
}

sio_rc_t sio_cofigure_stage(sio_t *sio, sio_stage_t *sios, void *obj, void *value)
{
    sio_rc_t rc;

    /* argument sanity check(s) */
    if (sio == NULL || sios == NULL)
        return SIO_RC(SIO_ERR_ARG);

    rc = sios->module->configure(sio, sios->userdata, obj, value);

    return SIO_RC(rc);
}

sio_rc_t sio_destroy_stage(sio_t *sio, sio_stage_t *sios)
{
    sio_rc_t rc;

    /* argument sanity check(s) */
    if (sio == NULL || sios == NULL)
        return SIO_RC(SIO_ERR_ARG);

    rc = sios->module->cleanup(sio, sios->userdata);
    free(sios);

    return SIO_OK;
}

sio_rc_t sio_attach(sio_t *sio, sio_stage_t *sios, sio_mode_t rw)
{
    sio_rc_t rc;

    /* argument sanity check(s) */
    if (sio == NULL || sios == NULL)
        return SIO_RC(SIO_ERR_ARG);

    /* is module already attached ? */
    if (sios->rw != SIO_MODE_INVALID)
        return SIO_RC(SIO_ERR_ARG);

    /* prepare module for being attached */
    rc = sios->module->open(sio, sios->userdata);
    if (rc != SIO_OK) return SIO_RC(rc);

    switch (rw) {
    case SIO_MODE_READ:
        ADDTAIL(&sio->readers,hd,&sios->reader);
        break;
    case SIO_MODE_WRITE:
        ADDTAIL(&sio->writers,hd,&sios->writer);
        break;
    case SIO_MODE_READWRITE:
        ADDTAIL(&sio->readers,hd,&sios->reader);
        ADDTAIL(&sio->writers,hd,&sios->writer);
        break;
    default:
        return SIO_RC(SIO_ERR_ARG);
    }

    /* Remember the lists that sios has been attached to */
    sios->rw = rw;

    return SIO_OK;
}

sio_rc_t sio_detach(sio_t *sio, sio_stage_t *sios)
{
    sio_rc_t rc;

    /* argument sanity check(s) */
    if (sio == NULL || sios == NULL)
        return SIO_RC(SIO_ERR_ARG);

    switch (sios->rw) {
    case SIO_MODE_READ:
        REMOVE(&sio->readers,hd,&sios->reader);
        break;
    case SIO_MODE_WRITE:
        REMOVE(&sio->writers,hd,&sios->writer);
        break;
    case SIO_MODE_READWRITE:
        REMOVE(&sio->readers,hd,&sios->reader);
        REMOVE(&sio->writers,hd,&sios->writer);
        break;
    default:
        return SIO_RC(SIO_ERR_ARG);
        break;
    }

    rc = sios->module->close(sio, sios->userdata);

    return SIO_RC(rc);
}

sio_rc_t sio_input(sio_t *sio, al_t *al, size_t limit)
{
    sio_rc_t rc;
    al_t *src = sio->readers.al;
    size_t n;

    /* argument sanity check(s) */
    if (sio == NULL || al == NULL)
        return SIO_RC(SIO_ERR_ARG);

    n = al_bytes(src);
    if (n == 0) {

        rc = sio_strategy(sio, HEAD(&sio->readers,hd), src);
        if (rc != SIO_OK) return SIO_RC(rc);

        n = al_bytes(src);
        if (n == 0)
            return SIO_RC(SIO_ERR_EOF);

    }

    if (n > limit)
        n = limit;

    (void) al_splice(src, 0, n, NULL, al); /* XXX - error handling ? */

    return SIO_OK;
}

sio_rc_t sio_discard(sio_t *sio)
{
    sio_rc_t rc;
    al_t *src = sio->readers.al;
    size_t n;

    /* argument sanity check(s) */
    if (sio == NULL)
        return SIO_RC(SIO_ERR_ARG);

    while ((n = al_bytes(src)) > 0) {
        rc = sio_strategy(sio, HEAD(&sio->readers,hd), src);
        if (rc != SIO_OK)
            break;
    }

    if (rc == SIO_ERR_EOF)
        return SIO_OK;

    return SIO_RC(rc);
}

sio_rc_t sio_output(sio_t *sio, al_t *al)
{
    sio_rc_t rc;
    al_t *dst = sio->writers.al;
    size_t n;

    /* argument sanity check(s) */
    if (sio == NULL || al == NULL)
        return SIO_RC(SIO_ERR_ARG);

    n = al_bytes(dst);
    al_splice(dst, n, 0, al, NULL);

    rc = sio_strategy(sio, HEAD(&sio->writers,hd), dst);

    return SIO_RC(rc);
}

sio_rc_t sio_flush(sio_t *sio)
{
    sio_rc_t rc;
    al_t *dst = sio->writers.al;
    size_t n;

    /* argument sanity check(s) */
    if (sio == NULL)
        return SIO_RC(SIO_ERR_ARG);

    while ((n = al_bytes(dst)) > 0) {
        rc = sio_strategy(sio, HEAD(&sio->writers,hd), sio->writers.al);
        if (rc != SIO_OK)
            break;
    }

    return SIO_RC(rc);
}

sio_rc_t sio_read(sio_t *sio, char *dst, size_t n, size_t *actualp)
{
    al_rc_t arc;
    sio_rc_t rc;
    al_t *al;

    arc = al_create(&al);
    if (arc != AL_OK) return SIO_RC(SIO_ERR_INT);

    rc = sio_input(sio, al, n);
    if (rc == AL_OK) {
        arc = al_flatten(al, 0, n, dst, actualp);
        if (arc != AL_OK)
            rc = SIO_ERR_INT;
    }

    arc = al_destroy(al);
    if (arc != AL_OK) return SIO_RC(SIO_ERR_INT);

    return SIO_RC(rc);
}

sio_rc_t sio_write(sio_t *sio, char *src, size_t n, size_t *actualp)
{
    al_rc_t arc;
    sio_rc_t rc;
    al_t *al;

    arc = al_create(&al);
    if (arc != AL_OK) return SIO_RC(SIO_ERR_INT);

    arc = al_append_bytes(al, src, n);
    if (arc != AL_OK)
        rc = SIO_ERR_INT;
    else
        rc = sio_output(sio, al);

    arc = al_destroy(al);
    if (arc != AL_OK) return SIO_RC(SIO_ERR_INT);

    return SIO_RC(rc);
}

const char *sio_error(sio_rc_t rc)
{
    const char *mess;

    switch (rc) {
    case SIO_OK:         mess = "Everything Ok"; break;
    case SIO_ERR_ARG:    mess = "Invalid Argument"; break;
    case SIO_ERR_MEM:    mess = "Not Enough Memory"; break;
    case SIO_ERR_EOF:    mess = "End Of Data"; break;
    case SIO_ERR_SYS:    mess = "Operating System Error"; break;
    case SIO_ERR_INT:    mess = "Internal Error"; break;
    case SIO_UPSTREAM:   mess = "Invoke Upstream Stage"; break;
    case SIO_DOWNSTREAM: mess = "Invoke Downstream Stage"; break;
    default:             mess = "Invalid Result Code"; break;
    }

    return mess;
}


CVSTrac 2.0.1