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