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; @