Transport configuration overhaul. Configuration string is now a list of
authormdw <mdw>
Wed, 30 Jan 2002 09:27:10 +0000 (09:27 +0000)
committermdw <mdw>
Wed, 30 Jan 2002 09:27:10 +0000 (09:27 +0000)
`;'-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
txport.h

index d6bdcbd..8d68bdd 100644 (file)
--- 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
  *
 /*----- 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 <ctype.h>
 #include <errno.h>
 #include <stdio.h>
 #include <stdarg.h>
 #include <mLib/dstr.h>
 #include <mLib/lbuf.h>
 #include <mLib/sub.h>
-#include <mLib/trace.h>
 #include <mLib/tv.h>
 
 #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
index ad4f338..7a2e62b 100644 (file)
--- 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
  *
 /*----- 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