From 0db4a80310ecc527cecf55b256b9bd6d71c42b69 Mon Sep 17 00:00:00 2001 From: mdw Date: Wed, 30 Jan 2002 09:27:10 +0000 Subject: [PATCH] Transport configuration overhaul. Configuration string is now a list of `;'-separated `key=value' strings, which can be handled either by the core or the transport module. The newline character(s) are a core parameter now. --- txport.c | 192 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- txport.h | 34 ++++++++++- 2 files changed, 209 insertions(+), 17 deletions(-) diff --git a/txport.c b/txport.c index d6bdcbd..8d68bdd 100644 --- a/txport.c +++ b/txport.c @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: txport.c,v 1.1 2002/01/25 19:34:45 mdw Exp $ + * $Id: txport.c,v 1.2 2002/01/30 09:27:10 mdw Exp $ * * Transport switch glue * @@ -29,6 +29,12 @@ /*----- Revision history --------------------------------------------------* * * $Log: txport.c,v $ + * Revision 1.2 2002/01/30 09:27:10 mdw + * Transport configuration overhaul. Configuration string is now a list of + * `;'-separated `key=value' strings, which can be handled either by the + * core or the transport module. The newline character(s) are a core + * parameter now. + * * Revision 1.1 2002/01/25 19:34:45 mdw * Initial revision * @@ -40,6 +46,7 @@ # include "config.h" #endif +#include #include #include #include @@ -53,10 +60,10 @@ #include #include #include -#include #include #include "err.h" +#include "jog.h" #include "txport.h" /*----- Global variables --------------------------------------------------*/ @@ -90,6 +97,7 @@ static void newline(char *s, size_t len, void *txv) if (!s) return; + T( trace(T_TX, "tx: completed line: `%s'", s); ) l = CREATE(txline); l->s = xmalloc(len + 1); memcpy(l->s, s, len + 1); @@ -104,6 +112,105 @@ static void newline(char *s, size_t len, void *txv) tx->ll_tail = l; } +/* --- @tx_configure@ --- * + * + * Arguments: @txport *tx@ = pointer to transport block + * @const char *config@ = config string + * + * Returns: Zero if OK, nonzero on errors. + * + * Use: Applies a configuration string to a transport. + */ + +int tx_configure(txport *tx, const char *config) +{ + char *c; + char *k, *v; + int rc = -1; + + if (!config) + return (0); + c = xstrdup(config); + for (k = strtok(c, ";"); k; k = strtok(0, ";")) { + if ((v = strchr(k, '=')) != 0) + *v++ = 0; + if (strcmp(k, "nl") == 0 || strcmp(k, "newline") == 0) { + int d; + if (!v) + d = LBUF_CRLF; + else if (strcmp(v, "none") == 0) + d = 0; + else if (strcmp(v, "crlf") == 0) + d = LBUF_CRLF; + else if (strcmp(v, "crlf-strict") == 0 || + strcmp(v, "strict-crlf") == 0) + d = LBUF_STRICTCRLF; + else if (strcmp(v, "cr") == 0) + d = '\r'; + else if (strcmp(v, "lf") == 0) + d = '\n'; + else if (v[0] == '\\') switch (v[1]) { + case 0: d = '\\'; break; + case 'a': d = 0x07; goto d_single; + case 'b': d = 0x08; goto d_single; + case 'f': d = 0x0c; goto d_single; + case 'n': d = 0x0a; goto d_single; + case 'r': d = 0x0d; goto d_single; + case 't': d = 0x09; goto d_single; + case 'v': d = 0x0b; goto d_single; + case 'e': d = 0x1b; goto d_single; + case 'x': + if (!isxdigit((unsigned char)v[2]) || + (d = strtoul(v + 2, &v, 16) || *v)) { + err_report(ERR_TXPORT, ERRTX_CONFIG, 0, + "bad hex escape `%s' in `newline' config", v); + goto err; + } + break; + default: + if (isdigit((unsigned char)v[0])) { + d = strtoul(v + 1, &v, 8); + if (*v) { + err_report(ERR_TXPORT, ERRTX_CONFIG, 0, + "bad octal escape `%s' in `newline' config", v); + goto err; + } + } + d = v[1]; + d_single: + if (v[2]) { + err_report(ERR_TXPORT, ERRTX_CONFIG, 0, + "unknown escape `%s' in `newline' config", v); + goto err; + } + break; + } else if (v[1] == 0) + d = v[0]; + else { + err_report(ERR_TXPORT, ERRTX_CONFIG, 0, + "unknown delimiter `%s' in `newline' config", v); + goto err; + } + tx->lb.delim = d; + } else { + int e = 0; + if (tx->ops->configure) + e = tx->ops->configure(tx, k, v); + if (!e) { + err_report(ERR_TXPORT, ERRTX_CONFIG, 0, + "unrecognized configuration keyword `%s'", k); + } + if (e <= 0) + goto err; + } + } + + rc = 0; +err: + xfree(c); + return (rc); +} + /* --- @tx_create@ --- * * * Arguments: @const char *name@ = name of transport to instantiate @@ -159,10 +266,12 @@ found: } if (!config) config = o->config; - if ((tx = o->create(file, config)) == 0) + if ((tx = o->create(file)) == 0) goto fail_0; tx->ops = o; - DA_CREATE(&tx->buf); + lbuf_init(&tx->lb, newline, tx); + if (tx_configure(tx, config)) + goto fail_1; tx->ll = 0; tx->ll_tail = 0; if ((e = pthread_mutex_init(&tx->mx, 0)) != 0) { @@ -187,8 +296,7 @@ found: goto fail_4; } pthread_attr_destroy(&ta); - lbuf_init(&tx->lb, newline, tx); - tx->lb.delim = '\r'; + DA_CREATE(&tx->buf); tx->s = TX_READY; DDESTROY(&d); return (tx); @@ -202,6 +310,7 @@ fail_3: fail_2: pthread_mutex_destroy(&tx->mx); fail_1: + lbuf_destroy(&tx->lb); tx->ops->destroy(tx); fail_0: DDESTROY(&d); @@ -221,6 +330,7 @@ fail_0: int tx_write(txport *tx, const void *p, size_t sz) { + T( trace_block(T_TX, "tx: outgoing data", p, sz); ) if (tx->ops->write(tx, p, sz) < 0) { err_report(ERR_TXPORT, ERRTX_WRITE, errno, "error writing to transport: %s", strerror(errno)); @@ -262,6 +372,39 @@ int tx_printf(txport *tx, const char *p, ...) return (rc); } +/* --- @tx_newline@ --- * + * + * Arguments: @txport *tx@ = pointer to transport context + * + * Returns: Zero if OK, nonzero on error. + * + * Use: Writes a newline (record boundary) to the output. + */ + +int tx_newline(txport *tx) +{ + static const char crlf[2] = { 0x0d, 0x0a }; + char c; + const char *p; + size_t sz; + + switch (tx->lb.delim) { + case LBUF_CRLF: + case LBUF_STRICTCRLF: + p = crlf; + sz = 2; + break; + case 0: + return (0); + default: + c = tx->lb.delim; + p = &c; + sz = 1; + break; + } + return (tx_write(tx, p, sz)); +} + /* --- @tx_read@, @tx_readx@ --- * * * Arguments: @txport *tx@ = pointer to transport context @@ -294,6 +437,7 @@ txline *tx_readx(txport *tx, unsigned long t, /* --- Get the time to wait until --- */ + T( trace(T_TXSYS, "txsys: tx_readx begin"); ) if (t != FOREVER) { gettimeofday(&now, 0); tv_addl(&tv, &now, t / 1000, (t % 1000) * 1000); @@ -306,8 +450,10 @@ txline *tx_readx(txport *tx, unsigned long t, again: for (; *ll; ll = &l->next) { l = *ll; - if (!filter || filter(l->s, p)) + if (!filter || filter(l->s, p)) { + T( trace(T_TXSYS, "txsys: matched line; done"); ) goto done; + } } l = 0; @@ -324,14 +470,19 @@ again: goto done; } f |= f_lock; + T( trace(T_TXSYS, "txsys: locked buffer"); ) } /* --- Push more stuff through the line buffer --- */ check: if (DA_LEN(&tx->buf)) { - trace_block(1u, "incoming data", DA(&tx->buf), DA_LEN(&tx->buf)); - lbuf_snarf(&tx->lb, DA(&tx->buf), DA_LEN(&tx->buf)); + T( trace_block(T_TX, "tx: incoming data", + DA(&tx->buf), DA_LEN(&tx->buf)); ) + if (tx->lb.delim) + lbuf_snarf(&tx->lb, DA(&tx->buf), DA_LEN(&tx->buf)); + else + newline((char *)DA(&tx->buf), DA_LEN(&tx->buf), tx); DA_SHRINK(&tx->buf, DA_LEN(&tx->buf)); goto again; } @@ -340,33 +491,44 @@ check: if (tx->s == TX_CLOSE) { lbuf_close(&tx->lb); + T( trace(T_TXSYS, "txsys: transport closed; flushing"); ) tx->s = TX_CLOSED; goto again; } - if (!t || tx->s == TX_CLOSED) - goto done; - gettimeofday(&now, 0); - if (TV_CMP(&now, >=, &tv)) + if (!t || tx->s == TX_CLOSED) { + T( trace(T_TX, "tx: transport is closed"); ) goto done; + } /* --- Wait for some more data to arrive --- */ + T( trace(T_TXSYS, "txsys: waiting for data"); ) if (t == FOREVER) e = pthread_cond_wait(&tx->cv, &tx->mx); - else + else { + gettimeofday(&now, 0); + if (TV_CMP(&now, >=, &tv)) { + T( trace(T_TXSYS, "txsys: timed out"); ) + goto done; + } e = pthread_cond_timedwait(&tx->cv, &tx->mx, &ts); + } if (e && e != ETIMEDOUT && e != EINTR) { err_report(ERR_TXPORT, ERRTX_READ, e, "error waiting on condvar: %s", strerror(errno)); goto done; } + T( trace(T_TXSYS, "txsys: woken, checking again"); ) goto check; /* --- Everything is finished --- */ done: - if (f & f_lock) + if (f & f_lock) { pthread_mutex_unlock(&tx->mx); + T( trace(T_TXSYS, "txsys: unlock buffer"); ) + } + T( trace(T_TXSYS, "tx_readx done"); ) return (l); #undef f_lock diff --git a/txport.h b/txport.h index ad4f338..7a2e62b 100644 --- a/txport.h +++ b/txport.h @@ -1,6 +1,6 @@ /* -*-c-*- * - * $Id: txport.h,v 1.1 2002/01/25 19:34:45 mdw Exp $ + * $Id: txport.h,v 1.2 2002/01/30 09:27:10 mdw Exp $ * * Transport switch glue * @@ -29,6 +29,12 @@ /*----- Revision history --------------------------------------------------* * * $Log: txport.h,v $ + * Revision 1.2 2002/01/30 09:27:10 mdw + * Transport configuration overhaul. Configuration string is now a list of + * `;'-separated `key=value' strings, which can be handled either by the + * core or the transport module. The newline character(s) are a core + * parameter now. + * * Revision 1.1 2002/01/25 19:34:45 mdw * Initial revision * @@ -107,7 +113,8 @@ typedef struct txport_ops { const char *name; const struct txfile *fv; const char *config; - txport *(*create)(const char */*file*/, const char */*config*/); + txport *(*create)(const char */*file*/); + int (*configure)(txport */*tx*/, const char */*k*/, const char */*v*/); void *(*fetch)(void */*txv*/); ssize_t (*write)(txport */*tx*/, const void */*p*/, size_t /*sz*/); void (*destroy)(txport */*tx*/); @@ -138,6 +145,18 @@ extern const char *txconf; extern txport *tx_create(const char */*name*/, const char */*file*/, const char */*config*/); +/* --- @tx_configure@ --- * + * + * Arguments: @txport *tx@ = pointer to transport block + * @const char *config@ = config string + * + * Returns: Zero if OK, nonzero on errors. + * + * Use: Applies a configuration string to a transport. + */ + +extern int tx_configure(txport */*tx*/, const char */*config*/); + /* --- @tx_write@ --- * * * Arguments: @txport *tx@ = pointer to transport context @@ -165,6 +184,17 @@ extern int tx_vprintf(txport */*tx*/, const char */*p*/, va_list */*ap*/); extern int tx_printf(txport */*tx*/, const char */*p*/, ...); +/* --- @tx_newline@ --- * + * + * Arguments: @txport *tx@ = pointer to transport context + * + * Returns: Zero if OK, nonzero on error. + * + * Use: Writes a newline (record boundary) to the output. + */ + +int tx_newline(txport */*tx*/); + /* --- @tx_read@, @tx_readx@ --- * * * Arguments: @txport *tx@ = pointer to transport context -- 2.11.0