*** /dev/null Sat Nov 23 01:03:56 2024
--- - Sat Nov 23 01:03:56 2024
***************
*** 0 ****
--- 1,302 ----
+
+ #include <stdlib.h>
+ #include <string.h>
+ #include <assert.h>
+
+ #include "al.h"
+ #include "sio.h"
+ #include "sio_module.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; /* saved output during protocol */
+ int isoutput; /* remember originator of protocol */
+ void *data_label; /* al labels used by SIO */
+ void *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 **u)
+ {
+ 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';
+
+ *u = 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;
+
+ al_destroy(my->pre);
+
+ 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);
+ my->al_in = al;
+
+ return SIO_OK;
+ }
+
+ static
+ sio_rc_t hello_closer(sio_t *sio, al_t *al, void *u)
+ {
+ 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);
+ al_create(&my->pre);
+ 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);
+ my->pre = 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 output until protocol is done
+ */
+ static
+ void hello_saveoutput(private_t *my)
+ {
+ al_splice(my->pre, al_bytes(my->pre), 0, my->al_out, NULL);
+ }
+
+ /*
+ * restore saved output after handshake completed successfully
+ */
+ static
+ void hello_restoreoutput(private_t *my)
+ {
+ al_splice(my->al_out, 0, 0, my->pre, NULL);
+ }
+
+ /*
+ * write prompt string to output
+ */
+ static
+ void hello_sendprompt(private_t *my)
+ {
+ al_prepend_bytes(my->al_out, PROMPT, NPROMPT, my->data_label);
+ }
+
+ /************************************************************************/
+
+ #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 rc = SIO_ERR_INT;
+ int good;
+
+ switch (my->state) {
+ case INIT:
+ if (isoutput) {
+ my->isoutput = 1;
+ hello_saveoutput(my);
+ GOTO(PROMPTING, SIO_UPSTREAM);
+ } else {
+ my->isoutput = 0;
+ GOTO(PROMPTING, SIO_XSTREAM);
+ }
+ break;
+ case PROMPTING:
+ assert(isoutput == 1);
+ hello_sendprompt(my);
+ GOTO(PROMPTED, SIO_UPSTREAM);
+ break;
+ case PROMPTED:
+ assert(isoutput == 1);
+ GOTO(WAIT, SIO_XSTREAM);
+ break;
+ case WAIT:
+ assert(isoutput == 0);
+ if (!hello_readpasswd(my))
+ GOTO(WAIT, SIO_UPSTREAM);
+ else {
+ good = my->npass == NPASS &&
+ memcmp(my->passwd, PASSWD, NPASS) == 0;
+ if (!good) {
+ if (my->isoutput)
+ GOTO(BAD, SIO_XSTREAM);
+ else {
+ hello_writeeof(my);
+ GOTO(BAD, SIO_DOWNSTREAM);
+ }
+ } else if (my->isoutput) {
+ hello_restoreoutput(my);
+ GOTO(GOOD, SIO_XSTREAM);
+ } else
+ GOTO(GOOD, SIO_OK);
+ }
+
+ break;
+ case GOOD:
+ GOTO(GOOD, SIO_OK); /* default action */
+ break;
+ case BAD:
+ if (isoutput)
+ hello_clearoutput(my);
+ else
+ hello_writeeof(my);
+
+ GOTO(BAD, SIO_DOWNSTREAM);
+ break;
+ }
+
+ return rc;
+ }
+
+ /************************************************************************/
+
+ static
+ sio_rc_t hello_input(sio_t *sio, al_t *al, void *u)
+ {
+ return hello_protocol(sio, (private_t *)u, 0);
+ }
+
+ static
+ sio_rc_t hello_output(sio_t *sio, al_t *al, void *u)
+ {
+ return hello_protocol(sio, (private_t *)u, 1);
+ }
+
+ 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
+ };
+
|