head 1.14;
access;
symbols
SIO_0_9_3:1.14
SIO_0_9_2:1.13
SIO_0_9_1:1.13
SIO_0_9_0:1.13;
locks; strict;
comment @ * @;
1.14
date 2005.10.03.09.06.11; author rse; state Exp;
branches;
next 1.13;
1.13
date 2003.01.06.19.04.56; author rse; state Exp;
branches;
next 1.12;
1.12
date 2002.11.29.14.27.44; author mlelstv; state Exp;
branches;
next 1.11;
1.11
date 2002.11.29.13.00.18; author mlelstv; state Exp;
branches;
next 1.10;
1.10
date 2002.11.27.15.50.29; author mlelstv; state Exp;
branches;
next 1.9;
1.9
date 2002.11.24.19.36.48; author mlelstv; state Exp;
branches;
next 1.8;
1.8
date 2002.11.19.22.20.52; author mlelstv; state Exp;
branches;
next 1.7;
1.7
date 2002.11.14.15.56.10; author mlelstv; state Exp;
branches;
next 1.6;
1.6
date 2002.11.08.11.12.28; author mlelstv; state Exp;
branches;
next 1.5;
1.5
date 2002.11.08.11.10.41; author mlelstv; state Exp;
branches;
next 1.4;
1.4
date 2002.11.08.10.34.24; author mlelstv; state Exp;
branches;
next 1.3;
1.3
date 2002.11.05.17.20.22; author mlelstv; state Exp;
branches;
next 1.2;
1.2
date 2002.11.05.15.52.21; author mlelstv; state Exp;
branches;
next 1.1;
1.1
date 2002.11.05.13.23.36; author mlelstv; state Exp;
branches;
next ;
desc
@@
1.14
log
@adjust copyright messages
@
text
@/*
** OSSP sio - Stream I/O
** Copyright (c) 2002-2005 Cable & Wireless
** Copyright (c) 2002-2005 The OSSP Project
** Copyright (c) 2002-2005 Ralf S. Engelschall
**
** This file is part of OSSP sio, a layered stream I/O library
** which can be found at http://www.ossp.org/pkg/lib/sio/.
**
** 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_hello.c: hello world stage
*/
#include
#include
#include
#include "al.h"
#include "sio.h"
#define PROMPT "Login: "
#define NPROMPT (sizeof(PROMPT)-1)
#define PASSWD "Geheim\r\n"
#define NPASS (sizeof(PASSWD)-1)
/*
* protocol states
*/
typedef enum {
INIT, /* setting up protocol, save output or switch to writer */
PROMPTING, /* sending prompt string as writer */
PROMPTED, /* continue sending, switch to reader when done */
WAIT, /* gather password as reader, flush buffer if good */
GOOD, /* default null operation */
BAD /* drop output, return eof on input */
} state_t;
typedef struct {
al_t *al_in, *al_out; /* cache input and output stream */
state_t state;
char passwd[NPASS]; /* input buffer */
int npass; /* characters in input buffer */
al_t *pre_in; /* saved during protocol */
al_t *pre_out; /* saved during protocol */
int isoutput; /* remember originator of protocol */
al_label_t data_label; /* al labels used by SIO */
al_label_t eof_label;
char eof; /* eof label buffer */
} private_t;
/***********************************************************************/
/*
* create stage
*
* allocate private instance data
*/
static
sio_rc_t hello_init(sio_t *sio, void **up)
{
private_t *my;
my = (private_t *)malloc(sizeof(private_t));
if (my == NULL)
return SIO_ERR_MEM;
sio_label(sio, SIO_LN_DATA, &my->data_label);
sio_label(sio, SIO_LN_EOF, &my->eof_label);
my->eof = '\0';
my->pre_in = NULL;
my->pre_out = NULL;
*up = my;
return SIO_OK;
}
/*
* configure stage
*
* pass two void pointers
*/
static
sio_rc_t hello_configure(sio_t *sio, void *u, void *obj, void *val)
{
return SIO_ERR_ARG;
}
/*
* destroy stage
*/
static
sio_rc_t hello_cleanup(sio_t *sio, void *u)
{
private_t *my = (private_t *)u;
free(my);
return SIO_OK;
}
static
void hello_setup(sio_t *sio, private_t *my)
{
my->state = INIT;
my->npass = 0;
}
static
sio_rc_t hello_openr(sio_t *sio, al_t *al, void *u)
{
private_t *my = (private_t *)u;
hello_setup(sio,my);
if (al_create(&my->pre_in) != AL_OK)
return SIO_ERR_INT;
my->al_in = al;
return SIO_OK;
}
static
sio_rc_t hello_closer(sio_t *sio, al_t *al, void *u)
{
private_t *my = (private_t *)u;
al_destroy(my->pre_in);
my->pre_in = NULL;
return SIO_OK;
}
static
sio_rc_t hello_openw(sio_t *sio, al_t *al, void *u)
{
private_t *my = (private_t *)u;
hello_setup(sio,my);
if (al_create(&my->pre_out) != AL_OK)
return SIO_ERR_INT;
my->al_out = al;
return SIO_OK;
}
static
sio_rc_t hello_closew(sio_t *sio, al_t *al, void *u)
{
private_t *my = (private_t *)u;
al_destroy(my->pre_out);
my->pre_out = NULL;
return SIO_OK;
}
/************************************************************************/
static
void hello_clearinput(private_t *my)
{
al_splice(my->al_in, 0, al_bytes(my->al_in), NULL, NULL);
}
static
void hello_clearoutput(private_t *my)
{
al_splice(my->al_out, 0, al_bytes(my->al_out), NULL, NULL);
}
/*
* gather input in password buffer
* return true if enough bytes or if no more data follows
*/
static
int hello_readpasswd(private_t *my)
{
size_t actual;
al_flatten(my->al_in, 0, NPASS - my->npass, AL_FORWARD_SPAN, my->data_label,
my->passwd, &actual);
al_splice(my->al_in, 0, actual, NULL, NULL);
my->npass += actual;
/* flush input when buffer full or labels are switching */
return my->npass == NPASS || al_bytes(my->al_in) > 0;
}
/*
* write eof token to input stream
*/
static
void hello_writeeof(private_t *my)
{
hello_clearinput(my);
al_append_bytes(my->al_in, &my->eof, sizeof(my->eof), my->eof_label);
}
/*
* defer initial data until protocol is done
*/
static
void hello_save(private_t *my)
{
al_splice(my->pre_in, al_bytes(my->pre_in), 0, my->al_in, NULL);
al_splice(my->pre_out, al_bytes(my->pre_out), 0, my->al_out, NULL);
}
/*
* restore saved output after handshake completed successfully
*/
static
void hello_restore(private_t *my)
{
al_splice(my->al_in, 0, 0, my->pre_in, NULL);
al_splice(my->al_out, 0, 0, my->pre_out, NULL);
}
/*
* kill saved data
*/
static
void hello_dropsaved(private_t *my)
{
al_splice(my->pre_in, 0, al_bytes(my->pre_in), NULL, NULL);
al_splice(my->pre_out, 0, al_bytes(my->pre_out), NULL, NULL);
}
/*
* write prompt string to output
*/
static
void hello_sendprompt(private_t *my)
{
al_prepend_bytes(my->al_out, PROMPT, NPROMPT, my->data_label);
}
/************************************************************************/
/*
*
* simple protocol
*
* send prompt to socket
* wait for password from socket
* if password correct -> normal communication
* else -> drop output, eof on input
*
*/
/* jump to next state */
#define GOTO(s, c) do { my->state = (s); rc = (c); } while(0)
static
sio_rc_t hello_protocol(sio_t *sio, private_t *my, int isoutput, sio_rc_t orc)
{
sio_rc_t rc = SIO_ERR_INT;
int good;
switch (my->state) {
case INIT:
assert(orc == SIO_SCHED_UP);
/*
* save origin (input, output) so that
* we can complete correctly after handshake
* is done
*
* save global assembly lines
*
* if caller starts with write, stay
*
* if caller starts with read, switch to writer
*
*/
hello_save(my);
my->isoutput = isoutput;
if (isoutput) {
GOTO(PROMPTING, SIO_SCHED_LOOP);
} else {
GOTO(PROMPTING, SIO_SCHED_CROSS);
}
break;
case PROMPTING:
assert(orc == SIO_SCHED_CROSS || orc == SIO_SCHED_LOOP);
assert(isoutput == 1);
/*
* only called on output stream
*
* either fall through from INIT as writer
* or scheduled via SIO_SCHED_CROSS from reader
* maybe there should be a SIO_STAY ?
*
* send prompt string, schedule upstream
*/
hello_sendprompt(my);
GOTO(PROMPTED, SIO_SCHED_UP);
break;
case PROMPTED:
assert(orc == SIO_SCHED_DOWN);
assert(isoutput == 1);
/*
* only called on output stream
*
* switch back to reader when output is flushed
* otherwise retry upstream
*
*/
if (al_bytes(my->al_out) > 0)
GOTO(PROMPTED, SIO_SCHED_UP);
else
GOTO(WAIT, SIO_SCHED_CROSS);
break;
case WAIT:
assert(orc == SIO_SCHED_CROSS || orc == SIO_SCHED_DOWN);
assert(isoutput == 0);
/*
* only called on input stream
*
* if not enough data and no signalling chunks,
* schedule upstream to deliver more
*
* check password
* if password bad (incomplete or wrong)
* state will be BAD
* -> if origin was writer, drop saved initial write
* schedule writer
* -> if origin was reader, signal EOF, send downstream
* else
* state will be GOOD
* -> if origin was writer, push saved initial write
* schedule writer
* -> if origin was reader, default action for reading
*
*/
if (!hello_readpasswd(my))
GOTO(WAIT, SIO_SCHED_UP);
else {
good = my->npass == NPASS &&
memcmp(my->passwd, PASSWD, NPASS) == 0;
if (!good) {
hello_dropsaved(my);
if (isoutput != my->isoutput) {
GOTO(BAD, SIO_SCHED_CROSS);
} else {
GOTO(BAD, SIO_SCHED_LOOP);
}
} else {
hello_restore(my);
if (isoutput != my->isoutput) {
GOTO(GOOD, SIO_SCHED_CROSS);
} else
GOTO(GOOD, SIO_SCHED_LOOP);
}
}
break;
case GOOD:
/*
* default action
*
* on input -> deliver data downstream, gather data upstream
* on output -> deliver data upstream, gather data downstream
*
*/
GOTO(GOOD, SIO_OK); /* default action */
break;
case BAD:
/*
* black hole
*
* on input -> signal EOF, send downstream
* on output -> drop data, return downstream
*
*/
if (isoutput)
hello_clearoutput(my);
else
hello_writeeof(my);
GOTO(BAD, SIO_SCHED_DOWN);
break;
}
return rc;
}
/************************************************************************/
static
sio_rc_t hello_input(sio_t *sio, al_t *al, void *u, sio_rc_t orc)
{
return hello_protocol(sio, (private_t *)u, 0, orc);
}
static
sio_rc_t hello_output(sio_t *sio, al_t *al, void *u, sio_rc_t orc)
{
return hello_protocol(sio, (private_t *)u, 1, orc);
}
sio_module_t sio_module_hello = {
"hello",
hello_init,
hello_configure,
hello_cleanup,
hello_openr,
hello_closer,
hello_openw,
hello_closew,
hello_input,
hello_output,
NULL
};
@
1.13
log
@- consistently use standard OSSP copyright message everywhere
- strip trailing whitespaces
@
text
@d3 3
a5 3
** Copyright (c) 2002-2003 Cable & Wireless Deutschland
** Copyright (c) 2002-2003 The OSSP Project
** Copyright (c) 2002-2003 Ralf S. Engelschall
@
1.12
log
@add assertions to check internal state with scheduler direction
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d1 30
d80 1
a80 1
@
1.11
log
@input/output now gets another parameter where scheduler tells
them from where they methods called by passing the return value
of the previously called stage.
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d249 1
a249 1
sio_rc_t hello_protocol(sio_t *sio, private_t *my, int isoutput)
d258 2
d285 2
d304 2
d322 2
d404 1
a404 1
return hello_protocol(sio, (private_t *)u, 0);
d410 1
a410 1
return hello_protocol(sio, (private_t *)u, 1);
@
1.10
log
@code cleanup
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d394 1
a394 1
sio_rc_t hello_input(sio_t *sio, al_t *al, void *u)
d400 1
a400 1
sio_rc_t hello_output(sio_t *sio, al_t *al, void *u)
@
1.9
log
@add optional shutdown function to modules. On detach, it is called
and if returning SIO_OK another round through output and input
is done.
modules are now pushed at pipe head instead of appended so that
a module can do upstream I/O while being wound up.
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d47 1
a47 1
sio_rc_t hello_init(sio_t *sio, void **u)
d62 1
a62 1
*u = my;
@
1.8
log
@remove extra empty line
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d415 2
a416 1
hello_output
@
1.7
log
@merged sio_module.h into sio.h
renamed scheduler codes to SIO_SCHED_*
added comments to sio.c
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@a0 1
@
1.6
log
@more alignments, code cleanup
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@a7 1
#include "sio_module.h"
d276 1
a276 1
GOTO(PROMPTING, SIO_LOOP);
d278 1
a278 1
GOTO(PROMPTING, SIO_XSTREAM);
d289 1
a289 1
* or scheduled via SIO_XSTREAM from reader
d295 1
a295 1
GOTO(PROMPTED, SIO_UPSTREAM);
d310 1
a310 1
GOTO(PROMPTED, SIO_UPSTREAM);
d312 1
a312 1
GOTO(WAIT, SIO_XSTREAM);
d338 1
a338 1
GOTO(WAIT, SIO_UPSTREAM);
d345 1
a345 1
GOTO(BAD, SIO_XSTREAM);
d347 1
a347 1
GOTO(BAD, SIO_LOOP);
d352 1
a352 1
GOTO(GOOD, SIO_XSTREAM);
d354 1
a354 1
GOTO(GOOD, SIO_LOOP);
d385 1
a385 1
GOTO(BAD, SIO_DOWNSTREAM);
@
1.5
log
@align example protocol module with documentation
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d345 1
a345 1
if (my->isoutput) {
d348 1
a348 2
hello_writeeof(my);
GOTO(BAD, SIO_DOWNSTREAM);
@
1.4
log
@add SIO_LOOP status to simplify protocol state machine
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d33 2
a34 1
al_t *pre; /* saved output during protocol */
d60 3
a62 1
my->eof = '\0';
a87 2
al_destroy(my->pre);
d106 4
d118 5
d132 4
a135 1
al_create(&my->pre);
d146 2
a147 2
al_destroy(my->pre);
my->pre = NULL;
d195 1
a195 1
* defer initial output until protocol is done
d198 1
a198 1
void hello_saveoutput(private_t *my)
d200 2
a201 1
al_splice(my->pre, al_bytes(my->pre), 0, my->al_out, NULL);
d208 1
a208 1
void hello_restoreoutput(private_t *my)
d210 2
a211 1
al_splice(my->al_out, 0, 0, my->pre, NULL);
d215 1
a215 1
* kill saved output
d220 2
a221 1
al_splice(my->pre, 0, al_bytes(my->pre), NULL, NULL);
d230 1
a230 1
al_prepend_bytes(my->al_out, PROMPT, NPROMPT, my->data_label);
d265 3
a267 1
* if caller starts with write, preserve data
d272 4
a276 2
my->isoutput = 1;
hello_saveoutput(my);
a278 1
my->isoutput = 0;
d344 1
a345 1
hello_dropsaved(my);
d351 7
a357 5
} else if (my->isoutput) {
hello_restoreoutput(my);
GOTO(GOOD, SIO_XSTREAM);
} else
GOTO(GOOD, SIO_OK);
@
1.3
log
@comments
code cleanup
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d257 1
a257 10
GOTO(PROMPTING, SIO_UPSTREAM);
/*
* FALL THROUGH to next state
*
* XXX = fall through is ugly
* XXX + efficient, no extra pass through scheduler
* XXX - scheduler doesn't support loops yet, we
* could simulate this with extra states that
* ping-pong back to the "right" side (ugh!)
*/
a260 1
break;
d262 1
a262 1
/* FALL THROUGH */
@
1.2
log
@code cleanup
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d200 9
d219 13
d241 1
d243 11
d258 9
d270 1
d272 2
a273 1
break;
d275 1
d277 9
d289 2
d292 1
d294 11
a304 1
GOTO(WAIT, SIO_XSTREAM);
d306 1
d308 1
d310 19
d335 2
a336 1
if (my->isoutput)
d338 1
a338 1
else {
d348 1
a349 1
break;
d351 8
d361 1
d363 8
@
1.1
log
@snapshot
- sio_strategy now has a default direction triggered by SIO_OK result
- added structure tag to aid debugging
- sio_hole eats all data and returns downstream (correct ?)
- sio_null now uses default directio
- sio_sa puts wrapper on sa objects
- sio_hello.c implements a trivial protocol handler
PR:
Submitted by:
Reviewed by:
Approved by:
Obtained from:
@
text
@d35 2
a36 2
void *data_label; /* al labels used by SIO */
void *eof_label;
@