Index: ossp-pkg/sio/sio_hello.c RCS File: /v/ossp/cvs/ossp-pkg/sio/sio_hello.c,v rcsdiff -q -kk '-r1.2' '-r1.3' -u '/v/ossp/cvs/ossp-pkg/sio/sio_hello.c,v' 2>/dev/null --- sio_hello.c 2002/11/05 15:52:21 1.2 +++ sio_hello.c 2002/11/05 17:20:22 1.3 @@ -197,6 +197,15 @@ } /* + * kill saved output + */ +static +void hello_dropsaved(private_t *my) +{ + al_splice(my->pre, 0, al_bytes(my->pre), NULL, NULL); +} + +/* * write prompt string to output */ static @@ -207,6 +216,19 @@ /************************************************************************/ +/* + * + * 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 @@ -216,36 +238,104 @@ int good; switch (my->state) { + case INIT: + + /* + * save origin (input, output) so that + * we can complete correctly after handshake + * is done + * + * if caller starts with write, preserve data + * + * if caller starts with read, switch to writer + * + */ if (isoutput) { my->isoutput = 1; hello_saveoutput(my); 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!) + */ } else { my->isoutput = 0; GOTO(PROMPTING, SIO_XSTREAM); + break; } - break; + /* FALL THROUGH */ + case PROMPTING: + assert(isoutput == 1); + /* + * only called on output stream + * + * either fall through from INIT as writer + * or scheduled via SIO_XSTREAM from reader + * maybe there should be a SIO_STAY ? + * + * send prompt string, schedule upstream + */ hello_sendprompt(my); GOTO(PROMPTED, SIO_UPSTREAM); break; + + case PROMPTED: + assert(isoutput == 1); - GOTO(WAIT, SIO_XSTREAM); + /* + * 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_UPSTREAM); + else + GOTO(WAIT, SIO_XSTREAM); break; + case WAIT: + 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_UPSTREAM); else { good = my->npass == NPASS && memcmp(my->passwd, PASSWD, NPASS) == 0; if (!good) { - if (my->isoutput) + if (my->isoutput) { + hello_dropsaved(my); GOTO(BAD, SIO_XSTREAM); - else { + } else { hello_writeeof(my); GOTO(BAD, SIO_DOWNSTREAM); } @@ -255,12 +345,29 @@ } else GOTO(GOOD, SIO_OK); } - 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