diff options
| author | Lennart Poettering <lennart@poettering.net> | 2004-01-05 22:24:10 +0000 | 
|---|---|---|
| committer | Lennart Poettering <lennart@poettering.net> | 2004-01-05 22:24:10 +0000 | 
| commit | d24a3f265ec4344b5502ec57df3cf8358f6f1499 (patch) | |
| tree | b869285f72044966ceaa4f6d2d7ab2cb998c03f3 | |
| parent | e44bcf6a233173911c2a52f314025abd28281485 (diff) | |
many changes
git-svn-id: file:///home/lennart/svn/public/ivam2/trunk@14 dbf6933d-3bce-0310-9bcc-ed052ba35b35
| -rw-r--r-- | conf/msntab | 10 | ||||
| -rw-r--r-- | doc/TODO | 11 | ||||
| -rw-r--r-- | src/Makefile | 2 | ||||
| -rw-r--r-- | src/buffio.c | 276 | ||||
| -rw-r--r-- | src/buffio.h | 26 | ||||
| -rw-r--r-- | src/exec.c | 10 | ||||
| -rw-r--r-- | src/main.c | 41 | ||||
| -rw-r--r-- | src/modem.c | 213 | ||||
| -rw-r--r-- | src/modem.h | 6 | ||||
| -rw-r--r-- | src/msntab.c | 303 | ||||
| -rw-r--r-- | src/msntab.h | 17 | 
11 files changed, 712 insertions, 203 deletions
| diff --git a/conf/msntab b/conf/msntab index ca16ef7..239eae4 100644 --- a/conf/msntab +++ b/conf/msntab @@ -1,8 +1,12 @@ -  # local MSN     remote MSN      options         action -41264179        41264179        rings=0         ivam-say /var/spool/ivam/hello.ulaw +41264179        41264179        rings=0         ivam-play /var/spool/ivam/welcome.ulaw  41264179        41264177        rings=0         ivam-dialup --pin=4711 ppp0  *               41264179        rings=0         @hangup  41264179        *               rings=2,shbuf   ivam-voicebox --pin=4711 -*               *               defaults        @ignore + +#46              36              defaults        @hangup +46              36              rings=0         ivam-play /var/spool/ivam/welcome.ulaw +46              *               defaults        ivam-echo + +# $Id$ @@ -1,7 +1,12 @@ -* implement msntab.c -* implement shbuf support  * python part -* dtmf fifo +* implement shbuf support  * uid switching support +* clean hangup on shutdown  + +* implement msntab.c (DONE) +* dtmf fifo (DONE) +* env var passing (DONE) +* msntab @include (DONE) +* ring counter (DONE)  $Id$ diff --git a/src/Makefile b/src/Makefile index 65ee382..c689956 100644 --- a/src/Makefile +++ b/src/Makefile @@ -2,7 +2,7 @@ CC=gcc  CFLAGS=`pkg-config --cflags libdaemon shbuf liboop` -Wall -O0 -pipe -g  LIBS=`pkg-config --libs libdaemon shbuf liboop` -Wall -O0 -pipe -g -ivamd: modem.o main.o modemman.o buffio.o exec.o dle.o lock.o util.o msntab.o timevalarith.o +ivamd: modem.o main.o modemman.o buffio.o exec.o dle.o lock.o util.o msntab.o timevalarith.o dtmffifo.o  	$(CC) $(LIBS) -o $@ $^  clean: diff --git a/src/buffio.c b/src/buffio.c index 727821d..95db681 100644 --- a/src/buffio.c +++ b/src/buffio.c @@ -21,8 +21,8 @@ static void* buffio_timeout_cb(oop_source *source, struct timeval tv, void *user  static void* buffio_read_cb(oop_source *source, int fd, oop_event event, void *user);  static void* buffio_write_cb(oop_source *source, int fd, oop_event event, void *user); -static void buffio_set_input_callbacks(struct buffio *b); -static void buffio_set_output_callbacks(struct buffio *b); +static void buffio_set_writable(struct buffio *b, int v); +static void buffio_set_readable(struct buffio *b, int v);  struct buffio* buffio_new(int ifd, int ofd) {      struct buffio *b; @@ -32,24 +32,21 @@ struct buffio* buffio_new(int ifd, int ofd) {      assert(b);      memset(b, 0, sizeof(struct buffio)); -    b->ifd = ifd; -    b->ofd = ofd; - -    daemon_nonblock(b->ifd, 1); -    daemon_nonblock(b->ofd, 1); +    daemon_nonblock(b->ifd = ifd, 1); +    daemon_nonblock(b->ofd = ofd, 1);      b->input_buf = malloc(b->input_max_length = BUFSIZE);      assert(b->input_buf);      b->input_length = b->input_index = 0; -    b->input_watermark = b->input_max_length; /* Read some more data if possible */ +    b->input_range = b->input_max_length;      b->output_buf = malloc(b->output_max_length = BUFSIZE);      assert(b->output_buf);      b->output_length = b->output_index = 0; -    b->output_watermark = 1; /* Write some data if 1 or more bytes are in the output buffer */ +    b->output_range = b->output_max_length; -    buffio_set_input_callbacks(b); -    buffio_set_output_callbacks(b); +    buffio_set_readable(b, 0); +    buffio_set_writable(b, 0);      return b;     } @@ -114,6 +111,8 @@ static void* buffio_user_cb(oop_source *source, struct timeval tv, void *user) {          r |= b->input_ready_cb(b, b->user);      if (s & BUFFIO_SCHED_CB_OUTPUT_EMPTY && b->output_empty_cb && !b->output_length)          r |= b->output_empty_cb(b, b->user); +    if (s & BUFFIO_SCHED_CB_OUTPUT_REQUEST && b->output_request_cb && b->output_length < b->output_range) +        r |= b->output_request_cb(b, b->user);      if (s & BUFFIO_SCHED_CB_EOF && b->eof_cb)          r |= b->eof_cb(b, b->user);      if (s & BUFFIO_SCHED_CB_EPIPE && b->epipe_cb) @@ -124,9 +123,9 @@ static void* buffio_user_cb(oop_source *source, struct timeval tv, void *user) {      return r == 0 ? OOP_CONTINUE : OOP_HALT;  } -  static void buffio_sched_cb(struct buffio *b, enum buffio_sched_cb s) {      if (s & BUFFIO_SCHED_CB_INPUT_READY && !b->input_ready_cb) s &= ~BUFFIO_SCHED_CB_INPUT_READY; +    if (s & BUFFIO_SCHED_CB_OUTPUT_REQUEST && !b->output_request_cb) s &= ~BUFFIO_SCHED_CB_OUTPUT_REQUEST;      if (s & BUFFIO_SCHED_CB_OUTPUT_EMPTY && !b->output_empty_cb) s &= ~BUFFIO_SCHED_CB_OUTPUT_EMPTY;      if (s & BUFFIO_SCHED_CB_EOF && !b->eof_cb) s &= ~BUFFIO_SCHED_CB_EOF;      if (s & BUFFIO_SCHED_CB_EPIPE && !b->epipe_cb) s = ~BUFFIO_SCHED_CB_EPIPE; @@ -170,13 +169,13 @@ inline static void buffio_normalize(struct buffio *b) {          b->output_index = 0;  } -static void buffio_set_input_callbacks(struct buffio *b) { +static void buffio_set_readable(struct buffio *b, int v) {      assert(b && event_source);      if (b->ifd == -1)          return; -    if (!b->readable && b->input_length < b->input_watermark) { +    if (!(b->readable = v)) {          if (!b->b_read_cb) { /* Enable the callback */              event_source->on_fd(event_source, b->ifd, OOP_READ, buffio_read_cb, b);              b->b_read_cb = 1; @@ -189,13 +188,13 @@ static void buffio_set_input_callbacks(struct buffio *b) {      }  } -static void buffio_set_output_callbacks(struct buffio *b) { +static void buffio_set_writable(struct buffio *b, int v) {      assert(b && event_source);      if (b->ofd == -1)          return; -    if (!b->writable && b->output_length >= b->output_watermark) { +    if (!(b->writable = v)) {          if (!b->b_write_cb) { /* Enable the callback */              event_source->on_fd(event_source, b->ofd, OOP_WRITE, buffio_write_cb, b);              b->b_write_cb = 1; @@ -243,108 +242,109 @@ void buffio_set_delay_usec(struct buffio *b, unsigned long delay, unsigned long  }  static void do_read(struct buffio *b) { +    ssize_t s; +    size_t m, i; +              assert(b); -    if (b->readable && b->input_length < b->input_watermark) { -        ssize_t s; -        size_t m, i; -         -        i = (b->input_index + b->input_length) % b->input_max_length; - -        m = b->input_max_length-b->input_length; -        if (m > b->input_max_length-i) -            m = b->input_max_length-i; - -        s = read(b->ifd, b->input_buf+i, m); -        b->readable = 0; - -        //daemon_log(LOG_INFO, "%p: Read %u (%u) bytes.", b, s, m); - -        if (s < 0) { -            daemon_log(LOG_ERR, "Failed to read from file descriptor: %s", strerror(errno)); -            buffio_close_input_fd(b); -            buffio_sched_cb(b, BUFFIO_SCHED_CB_ERROR); -            return; - -        } else if (!s) { -            buffio_close_input_fd(b); -            buffio_sched_cb(b, BUFFIO_SCHED_CB_EOF); -            return; - -        } else { +    if (!b->readable || b->input_length >= b->input_range || b->ifd == -1) +        return; +     +    i = (b->input_index + b->input_length) % b->input_max_length; +    m = b->input_range-b->input_length; +    if (m > b->input_max_length-i) +        m = b->input_max_length-i; +     +    s = read(b->ifd, b->input_buf+i, m); +    //daemon_log(LOG_INFO, "%p: Read %u (%u) bytes.", b, s, m); +     +    if (s < 0) { +        daemon_log(LOG_ERR, "Failed to read from file descriptor: %s", strerror(errno)); +        buffio_close_input_fd(b); +        buffio_sched_cb(b, BUFFIO_SCHED_CB_ERROR); +        return; +         +    } else if (!s) { +        buffio_close_input_fd(b); +        buffio_sched_cb(b, BUFFIO_SCHED_CB_EOF); +        return; +         +    } +      #ifdef IODEBUG -            esc_print(b, "INPUT:  ", b->input_buf+i, s); +    esc_print(b, "INPUT:  ", b->input_buf+i, s);  #endif -             -            assert(s <= m); -            b->input_length += s; -            buffio_normalize(b); -        } -    } -    buffio_set_input_callbacks(b); +    assert(s <= m); +    b->input_length += s; +    buffio_normalize(b); +     +    buffio_set_readable(b, 0); -    if (b->input_length) +    if (b->input_length)           buffio_sched_cb(b, BUFFIO_SCHED_CB_INPUT_READY); - -    return;  }  static void do_write(struct buffio *b) { -    assert(b); +    ssize_t s; +    size_t m; -    if (!b->delaying && b->writable && b->output_length >= b->output_watermark) { -        ssize_t s; -        size_t m; +    assert(b); -        m = b->output_length; -        if (m > b->output_max_length-b->output_index) -            m = b->output_max_length-b->output_index; +    if (b->delaying || !b->writable || !b->output_length || b->ofd == -1) +        return; -        s = write(b->ofd, b->output_buf+b->output_index, m); -        b->writable = 0; +    if (b->prebuf && b->output_length >= b->output_range) +        b->prebuf = 0; -        //daemon_log(LOG_INFO, "%p: Wrote %u (%u) bytes.", b, s, m); +    if (b->prebuf) +        return; +     +    m = b->output_length; +    if (m > b->output_max_length-b->output_index) +        m = b->output_max_length-b->output_index; +     +    s = write(b->ofd, b->output_buf+b->output_index, m); +    //daemon_log(LOG_INFO, "%p: Wrote %u (%u) bytes.", b, s, m); +     +    if (s < 0) { +        buffio_close_output_fd(b); -        if (s < 0) { -            buffio_close_output_fd(b); +        if (errno == EPIPE) { +            buffio_sched_cb(b, BUFFIO_SCHED_CB_EPIPE); +            return; -            if (errno == EPIPE) { -                buffio_sched_cb(b, BUFFIO_SCHED_CB_EPIPE); -                return; -                 -            } else { -                daemon_log(LOG_ERR, "Failed to write to file descriptor: %s", strerror(errno)); -                buffio_sched_cb(b, BUFFIO_SCHED_CB_ERROR); -                return; -            } +        } else { +            daemon_log(LOG_ERR, "Failed to write to file descriptor: %s", strerror(errno)); +            buffio_sched_cb(b, BUFFIO_SCHED_CB_ERROR); +            return;          } -         +    } +  #ifdef IODEBUG -        esc_print(b, "OUTPUT: ", b->output_buf+b->output_index, s); +    esc_print(b, "OUTPUT: ", b->output_buf+b->output_index, s);  #endif +     +    assert(s > 0 && s <= m); +    b->output_index = (b->output_index + s) % b->output_max_length; +    b->output_length -= s; +    buffio_normalize(b); +     +    buffio_set_writable(b, 0); +    buffio_delay(b, s); -        assert(s > 0 && s <= m); -        b->output_index = (b->output_index + s) % b->output_max_length; -        b->output_length -= s; - -        buffio_normalize(b); -        buffio_delay(b, s); - -        if (!b->output_length) -            buffio_sched_cb(b, BUFFIO_SCHED_CB_OUTPUT_EMPTY); -    } else -        buffio_set_output_callbacks(b); - -    return; +    if (b->output_length < b->output_range) +        buffio_sched_cb(b, BUFFIO_SCHED_CB_OUTPUT_REQUEST); +    if (!b->output_length) +        buffio_sched_cb(b, BUFFIO_SCHED_CB_OUTPUT_EMPTY);  }  static void* buffio_read_cb(oop_source *source, int fd, oop_event event, void *user) {      struct buffio *b = user;      assert(source && b && b->ifd == fd && event == OOP_READ); -    b->readable = 1; +    buffio_set_readable(b, 1);      do_read(b);      return OOP_CONTINUE; @@ -354,7 +354,7 @@ static void* buffio_write_cb(oop_source *source, int fd, oop_event event, void *      struct buffio *b = user;      assert(source && b && b->ofd == fd && event == OOP_WRITE); -    b->writable = 1; +    buffio_set_writable(b, 1);      do_write(b);      return OOP_CONTINUE; @@ -370,12 +370,12 @@ static void* buffio_timeout_cb(oop_source *source, struct timeval tv, void *user      return OOP_CONTINUE;  } -int buffio_write(struct buffio *b, const uint8_t *d, size_t l) { +void buffio_write(struct buffio *b, const uint8_t *d, size_t l) {      assert(b && d && l); -    if (l > b->output_max_length - b->output_length) { +    if (b->output_length > b->output_range || l > b->output_range - b->output_length) {          daemon_log(LOG_ERR, "buffio_write() with too much data called"); -        return -1; +        return;      }      while (l > 0) { @@ -394,38 +394,34 @@ int buffio_write(struct buffio *b, const uint8_t *d, size_t l) {      }      buffio_normalize(b); -      do_write(b); -    return 0;  } -int buffio_print(struct buffio *b, const char *s) { +void buffio_print(struct buffio *b, const char *s) {      assert(b && s); -    return buffio_write(b, (uint8_t*) s, strlen(s)); +    buffio_write(b, (uint8_t*) s, strlen(s));  } -int buffio_command(struct buffio *b, const char *c) { +void buffio_command(struct buffio *b, const char *c) {      assert(b && c);      buffio_flush_input(b); -    return buffio_print(b, c); +    buffio_print(b, c);  }  void buffio_flush_input(struct buffio *b) {      assert(b);      b->input_length = b->input_index = 0; -    buffio_set_input_callbacks(b); +    do_read(b);  }  void buffio_flush_output(struct buffio *b) {      assert(b);      b->output_length = b->output_index = 0; -    buffio_set_output_callbacks(b);  } -  int buffio_find_input(struct buffio *b, const char *c) {      size_t l, cl, i;      assert(b && c && *c); @@ -441,7 +437,6 @@ int buffio_find_input(struct buffio *b, const char *c) {          if (!*p) { /* Found! */              b->input_index = j;              b->input_length = l-cl; -              buffio_normalize(b);              do_read(b); @@ -472,7 +467,6 @@ char* buffio_read_line(struct buffio *b, char *c, size_t l) {                      b->input_index = (b->input_index+j+1) % b->input_max_length;                      b->input_length -= j+1; -                      buffio_normalize(b);                      do_read(b); @@ -504,34 +498,39 @@ void buffio_dump(struct buffio *b) {      fprintf(stderr, "]\n");  } -void buffio_set_input_watermark(struct buffio *b, ssize_t w) { +void buffio_set_input_range(struct buffio *b, ssize_t w) {      assert(b);      if (w < 0) -        b->input_watermark = b->input_max_length; +        b->input_range = b->input_max_length;      else -        b->input_watermark = w; +        b->input_range = w; + +    assert(b->input_range > 0 && b->input_range <= b->input_max_length); -    assert(b->input_watermark > 0 && b->input_watermark <= b->input_max_length); -    buffio_set_input_callbacks(b); +    do_read(b);  } -void buffio_set_output_watermark(struct buffio *b, ssize_t w) { +void buffio_set_output_range(struct buffio *b, ssize_t w) {      assert(b);      if (w < 0) -        b->output_watermark = b->output_max_length; +        b->output_range = b->output_max_length;      else -        b->output_watermark = w; +        b->output_range = w; -    assert(b->output_watermark > 0 && b->output_watermark <= b->output_max_length); -    buffio_set_output_callbacks(b); +    assert(b->output_range > 0 && b->output_range <= b->output_max_length); + +    do_write(b);  }  const uint8_t* buffio_read_ptr(struct buffio *b, size_t *l) {      assert(b && l); +    if (!b->input_length) +        return NULL; +          *l = b->input_length;      if (*l > b->input_max_length - b->input_index) @@ -553,7 +552,6 @@ void buffio_read_ptr_inc(struct buffio *b, size_t l) {          b->input_index -= b->input_max_length;      b->input_length -= l; -          buffio_normalize(b);          do_read(b); @@ -563,9 +561,12 @@ uint8_t* buffio_write_ptr(struct buffio *b, size_t *l) {      size_t j;      assert(b && l); +    if (b->output_length >= b->output_range) +        return NULL; +          j = (b->output_index + b->output_length) % b->output_max_length; -    *l = b->output_max_length - b->output_length; +    *l = b->output_range - b->output_length;      if (*l > b->output_max_length - j)          *l = b->output_max_length - j; @@ -583,7 +584,6 @@ void buffio_write_ptr_inc(struct buffio *b, size_t l) {      assert(l <= b->output_max_length - b->output_length && l <= b->output_max_length - j);      b->output_length += l; -          buffio_normalize(b);      do_write(b); @@ -595,6 +595,12 @@ int buffio_output_is_empty(struct buffio *b) {      return b->output_length == 0;  } +int buffio_input_is_full(struct buffio *b) { +    assert(b); + +    return b->input_length >= b->input_range; +} +  void buffio_dump_lines(struct buffio *b) {      int r, i;      assert(b); @@ -608,9 +614,8 @@ void buffio_dump_lines(struct buffio *b) {      if (r > 0) {          b->input_index = (b->input_index+r) % b->input_max_length;          b->input_length -= r; -                  buffio_normalize(b); - +                  do_read(b);      }  } @@ -618,20 +623,31 @@ void buffio_dump_lines(struct buffio *b) {  void buffio_set_fds(struct buffio *b, int ifd, int ofd) {      assert(b && b->ifd == -1 && b->ofd == -1); -    b->ifd = ifd; -    b->ofd = ofd; +    daemon_nonblock(b->ifd = ifd, 1); +    daemon_nonblock(b->ofd = ofd, 1); -    daemon_nonblock(b->ifd, 1); -    daemon_nonblock(b->ofd, 1); +    buffio_set_readable(b, 0); +    buffio_set_writable(b, 0); +} -    b->readable = b->writable = 0; +int buffio_can_write(struct buffio *b, size_t l) { +    assert(b); + +    if (b->output_length >= b->output_range) +        return 0; -    buffio_set_input_callbacks(b); -    buffio_set_output_callbacks(b); +    return l <= b->output_range - b->output_length;  } -int buffio_can_write(struct buffio *b, size_t l) { +int buffio_write_req(struct buffio *b) {      assert(b); -    return l <= b->output_max_length - b->output_length; +    return b->output_length < b->output_range; +} + +void buffio_set_prebuf(struct buffio *b, int p) { +    assert(b); + +    b->prebuf = p; +    do_write(b);  } diff --git a/src/buffio.h b/src/buffio.h index a41ec76..fff2514 100644 --- a/src/buffio.h +++ b/src/buffio.h @@ -7,7 +7,8 @@  enum buffio_sched_cb {      BUFFIO_SCHED_CB_IDLE = 0,      BUFFIO_SCHED_CB_INPUT_READY = 1, -    BUFFIO_SCHED_CB_OUTPUT_EMPTY = 2, +    BUFFIO_SCHED_CB_OUTPUT_REQUEST = 2, +    BUFFIO_SCHED_CB_OUTPUT_EMPTY = 32,      BUFFIO_SCHED_CB_EOF = 4,      BUFFIO_SCHED_CB_EPIPE = 8,      BUFFIO_SCHED_CB_ERROR = 16 @@ -18,19 +19,20 @@ struct buffio {      int ofd;      uint8_t *input_buf; -    size_t input_max_length, input_index, input_length, input_watermark; +    size_t input_max_length, input_index, input_length, input_range;      uint8_t *output_buf; -    size_t output_max_length, output_index, output_length, output_watermark; +    size_t output_max_length, output_index, output_length, output_range;      int b_read_cb, b_write_cb;      void *user; -    int readable; -    int writable; +    int readable, writable; +    int prebuf;      int (*input_ready_cb) (struct buffio *b, void *user); +    int (*output_request_cb) (struct buffio *b, void *user);      int (*output_empty_cb) (struct buffio *b, void *user);      int (*eof_cb) (struct buffio *b, void *user);      int (*epipe_cb) (struct buffio *b, void *user); @@ -47,20 +49,20 @@ struct buffio {  struct buffio* buffio_new(int ifd, int ofd);  void buffio_free(struct buffio *b); -int buffio_write(struct buffio *b, const uint8_t *d, size_t l); -int buffio_print(struct buffio *b, const char *s); +void buffio_write(struct buffio *b, const uint8_t *d, size_t l); +void buffio_print(struct buffio *b, const char *s);  void buffio_flush_input(struct buffio *b);  void buffio_flush_output(struct buffio *b); -int buffio_command(struct buffio *b, const char *c); +void buffio_command(struct buffio *b, const char *c);  int buffio_find_input(struct buffio *b, const char *c);  char *buffio_read_line(struct buffio *b, char *c, size_t l);  void buffio_dump(struct buffio *b); -void buffio_set_input_watermark(struct buffio *b, ssize_t w); -void buffio_set_output_watermark(struct buffio *b, ssize_t w); +void buffio_set_input_range(struct buffio *b, ssize_t w); +void buffio_set_output_range(struct buffio *b, ssize_t w);  const uint8_t* buffio_read_ptr(struct buffio *b, size_t *l);  void buffio_read_ptr_inc(struct buffio *b, size_t l); @@ -72,6 +74,8 @@ void buffio_close_input_fd(struct buffio *b);  void buffio_close_output_fd(struct buffio *b);  int buffio_output_is_empty(struct buffio *b); +int buffio_input_is_full(struct buffio *b); +  void buffio_dump_lines(struct buffio *b);  void buffio_set_fds(struct buffio *b, int ifd, int ofd); @@ -80,4 +84,6 @@ void buffio_set_delay_usec(struct buffio *b, unsigned long usec, unsigned long l  int buffio_can_write(struct buffio *b, size_t l); +void buffio_set_prebuf(struct buffio *b, int p); +  #endif @@ -164,7 +164,7 @@ static void *oop_read_cb(oop_source *source, int fd, oop_event event, void *user      /* Escape */      for (c = start, i = 0; i < s; i++, c++) -        if (*c < 32 || *c == 127) +        if (*c != '\r' && *c != '\n' && (*c < 32 || *c == 127))              *c = '.'; @@ -197,6 +197,8 @@ pid_t child_process_create(const char *file, char *const argv[], int *ifd, int *      int stdout_fds[2];      int stderr_fds[2]; +    daemon_log(LOG_INFO, "Executing child process '%s'.", file); +          if (pipe(stdin_fds) < 0) {          daemon_log(LOG_ERR, "pipe() failed: %s", strerror(errno));          return -1; @@ -296,9 +298,9 @@ pid_t child_process_create(const char *file, char *const argv[], int *ifd, int *                  exit(1);              }          } -             -        execv(file, argv); -        daemon_log(LOG_ERR, "exec() failed: %s", strerror(errno)); + +        execvp(file, argv); +        daemon_log(LOG_ERR, "exec('%s', ...) failed: %s", file, strerror(errno));          exit(1);      }  } @@ -5,22 +5,45 @@  #include "main.h"  #include "exec.h"  #include "modemman.h" +#include "msntab.h"  #define CHANNELS 1  oop_source* event_source = NULL; +#define MSNTABLE "../conf/msntab" +  static void *oop_exit_cb(oop_source *source, int sig, void *user) {      daemon_log(LOG_ERR, "Recieved signal %s", sig == SIGINT ? "SIGINT" : (sig == SIGTERM ? "SIGTERM" : "UNKNWON"));      return OOP_HALT;  } +static void *oop_reload_cb(oop_source *source, int sig, void *user) { +    daemon_log(LOG_ERR, "Reloading MSN table."); +    msntab_flush(); + +    if (msntab_load(MSNTABLE) < 0) { +        daemon_log(LOG_ERR, "Ignoring all calls."); +        msntab_flush(); +    } + +    return OOP_CONTINUE; +} + +static void *oop_dump_cb(oop_source *source, int sig, void *user) { +    msntab_dump(); +    return OOP_CONTINUE; +} + +  int main_loop(void) {      int r = -1;      oop_source_sys *sys = NULL; +    daemon_log(LOG_INFO, "Starting up."); +          if (!(sys = oop_sys_new())) { -        daemon_log(LOG_ERR, "Failed to create system source"); +        daemon_log(LOG_ERR, "Failed to create system source.");          goto finish;      } @@ -30,12 +53,19 @@ int main_loop(void) {      if (child_process_init() < 0)          goto finish; +    if (msntab_load(MSNTABLE) < 0) +        goto finish; +      if (modem_manager_init(CHANNELS) < 0)          goto finish;      event_source->on_signal(event_source, SIGINT, oop_exit_cb, NULL);      event_source->on_signal(event_source, SIGTERM, oop_exit_cb, NULL); +    event_source->on_signal(event_source, SIGHUP, oop_reload_cb, NULL); +    event_source->on_signal(event_source, SIGUSR1, oop_dump_cb, NULL);      signal(SIGPIPE, SIG_IGN); + +    daemon_log(LOG_INFO, "Start up complete.");      if (oop_sys_run(sys) == OOP_ERROR) {          daemon_log(LOG_ERR, "oop_sys_new() returned OOP_ERROR"); @@ -45,8 +75,15 @@ int main_loop(void) {      r = 0;  finish: + +    daemon_log(LOG_INFO, "Shutting down."); +      event_source->cancel_signal(event_source, SIGTERM, oop_exit_cb, NULL);      event_source->cancel_signal(event_source, SIGINT, oop_exit_cb, NULL); +    event_source->cancel_signal(event_source, SIGHUP, oop_reload_cb, NULL); +    event_source->cancel_signal(event_source, SIGUSR1, oop_dump_cb, NULL); + +    msntab_flush();      modem_manager_done();      child_process_done(); @@ -55,6 +92,8 @@ finish:          event_source = NULL;          oop_sys_delete(sys);      } + +    daemon_log(LOG_INFO, "Shut down complete.");      return r;  } diff --git a/src/modem.c b/src/modem.c index 71a8eb4..ef79b20 100644 --- a/src/modem.c +++ b/src/modem.c @@ -10,6 +10,7 @@  #include <time.h>  #include <stdio.h>  #include <sys/wait.h> +#include <stdlib.h>  #include <oop.h> @@ -21,22 +22,31 @@  #include "main.h"  #include "msntab.h"  #include "dle.h" +#include "dtmffifo.h"  /* Baudrate for the TTY. Should be greater the 64000. */  #define BAUD_RATE B115200 -#define RESET_IDLE_TIME 10 +#define RESET_IDLE_TIME 2 +#define RING_TIME 5 +  #define INIT_TIMEOUT 5  #define ACCEPT_TIMEOUT 5  #define BASIC_TIMEOUT 5  #define CHILD_TIMEOUT 10  #define HANGUP_TIMEOUT 10 -#define ISDN_DELAY_USEC 125L -#define ISDN_LATENCY_USEC 25000L -#define INPUT_WATERMARK_DEFAULT -1 -#define INPUT_WATERMARK_CONNECTION 2 -#define INPUT_WATERMARK_CHILD 1 +#define ISDN_DELAY_USEC 125L  /* The time a single byte written to the ISDN takes to be played */ +#define ISDN_LATENCY_USEC 50000L /* Request the next byte to be written to the ISDN this many usecs before the last one is finished playing */ + +#define INPUT_RANGE_DEFAULT -1 +#define OUTPUT_RANGE_DEFAULT -1 + +#define INPUT_RANGE_CONNECTION 96 +#define OUTPUT_RANGE_CONNECTION 1024 + +#define INPUT_RANGE_CHILD 64 +#define OUTPUT_RANGE_CHILD 1024  #define INIT_AT_COMMANDS 16  static const char* const init_at_commands[INIT_AT_COMMANDS*2] = { @@ -67,7 +77,7 @@ static const char* const init_at_commands[INIT_AT_COMMANDS*2] = {      "ATS13.0=1\n", /* direct tty send */      "OK\r\n", -    "AT\n", //S13.2=0\n", /* Don't hangup on DTR low */ +    "ATS13.6=1\n", /* Get special RUNG messages */      "OK\r\n",      "ATS23=1\n", @@ -92,6 +102,7 @@ static const char* const init_at_commands[INIT_AT_COMMANDS*2] = {  static const char hup_sequence[] = { DLE, DC4, DLE, ETX, 0 };  static const char ath_sequence[] = "\nATH\n"; +static int modem_output_request_cb(struct buffio *b, void *user);  static int modem_output_empty_cb(struct buffio *b, void *user);  static int modem_input_ready_cb(struct buffio *b, void *user);  static void* oop_timeout_cb(oop_source *source, struct timeval tv, void *user); @@ -105,12 +116,12 @@ static int modem_reopen(struct modem *m);  void modem_close(struct modem *m);  struct modem *modem_open(const char *dev) { -    struct modem *m; +    struct modem *m = NULL;      assert(dev);      if (device_lock(dev) != 0) -        return NULL; +        goto fail;      m = malloc(sizeof(struct modem));      assert(m); @@ -121,7 +132,7 @@ struct modem *modem_open(const char *dev) {      m->child_pid = -1;      m->child_buffio = NULL; -    m->local_msn = "46"; +    m->listen_msn = "46";      m->tabentry = NULL;      if (modem_reopen(m) < 0) @@ -132,7 +143,9 @@ struct modem *modem_open(const char *dev) {      return m;  fail: -    modem_close(m); +    if (m) +        modem_close(m); +          return NULL;  } @@ -140,8 +153,13 @@ fail:  void modem_close(struct modem *m) {      assert(m); +    daemon_log(LOG_INFO, "Closing modem on TTY device '%s'", m->dev); +      modem_timeout(m, 0); +    if (m->dtmf_fifo) +        dtmf_fifo_free(m->dtmf_fifo); +          if (m->tabentry)          msntab_unref(m->tabentry); @@ -196,7 +214,7 @@ static void modem_next_command(struct modem *m) {      if (m->command_index == 0)          buffio_command(m->buffio, hup_sequence);      else if (m->command_index == 15) { -        snprintf(tmp, sizeof(tmp), p, m->local_msn); +        snprintf(tmp, sizeof(tmp), p, m->listen_msn);          p = tmp;      }    @@ -277,8 +295,10 @@ static void modem_hangup(struct modem *m, int b) {      assert(m);      daemon_log(LOG_INFO, "Hanging up."); -    buffio_set_input_watermark(m->buffio, INPUT_WATERMARK_DEFAULT); +    buffio_set_input_range(m->buffio, INPUT_RANGE_DEFAULT); +    buffio_set_output_range(m->buffio, OUTPUT_RANGE_DEFAULT);      buffio_set_delay_usec(m->buffio, 0, 0); +    buffio_set_prebuf(m->buffio, 0);      l = strlen(ath_sequence) + (b ? strlen(hup_sequence) : 0); @@ -295,6 +315,17 @@ static void modem_hangup(struct modem *m, int b) {      modem_timeout(m, HANGUP_TIMEOUT);  } +static void modem_accept(struct modem *m) { +    assert(m); +     +    daemon_log(LOG_INFO, "Accepting call."); +                     +    m->state = MODEM_STATE_ATA; +    modem_timeout(m, ACCEPT_TIMEOUT); +     +    buffio_command(m->buffio, "ATA\n"); +} +  static void child_exit_cb(pid_t t, int status, void *user) {      struct modem *m = user;      assert(m && m->child_pid == t); @@ -307,6 +338,10 @@ static void child_exit_cb(pid_t t, int status, void *user) {          daemon_log(LOG_ERR, "Child exited due to unknown cause.");      m->child_pid = (pid_t) -1; +    if (m->dtmf_fifo) { +        dtmf_fifo_free(m->dtmf_fifo); +        m->dtmf_fifo = NULL; +    }      switch (m->state) { @@ -323,9 +358,10 @@ static int child_input_ready_cb(struct buffio *b, void *user) {      struct modem *m = (struct modem*) user;      assert(m && m->child_buffio == b); -    if (m->state == MODEM_STATE_CONNECTION) +    if (m->state == MODEM_STATE_CONNECTION) { +        //daemon_log(LOG_INFO, "child_input_ready");          copy_child_to_modem(m); -    else +    } else          buffio_flush_input(m->child_buffio);      return 0; @@ -380,7 +416,7 @@ static int child_epipe_cb(struct buffio *b, void *user) {      return 0;  } -static int child_output_empty_cb(struct buffio *b, void *user) { +static int child_output_request_cb(struct buffio *b, void *user) {      struct modem *m = user;      assert(m && m->child_buffio == b); @@ -405,18 +441,34 @@ static int modem_start_child(struct modem *m) {      int ifd, ofd;      assert(m && m->child_pid == (pid_t) -1 && m->tabentry && m->state == MODEM_STATE_CONNECTION); +    assert(!m->dtmf_fifo); +    if (!(m->dtmf_fifo = dtmf_fifo_new())) +        return -1; + +    setenv("RINGMSN", m->ring_number ? m->ring_number : "", 1); +    setenv("CALLERMSN", m->caller_number ? m->caller_number : "", 1); +    assert(m->dtmf_fifo->fname); +    setenv("DTMFFIFO", m->dtmf_fifo->fname, 1); +    if (m->listen_msn)  +        setenv("LISTENMSN", m->listen_msn, 1); +    else +        unsetenv("LISTENMSN"); +          assert(m->tabentry->args && m->tabentry->args[0]); -    if ((m->child_pid = child_process_create(m->tabentry->args[0], m->tabentry->args, &ifd, &ofd, child_exit_cb, m)) < 0) +    if ((m->child_pid = child_process_create(m->tabentry->args[0], m->tabentry->args, &ifd, &ofd, child_exit_cb, m)) < 0) { +        dtmf_fifo_free(m->dtmf_fifo);          return -1; +    }      assert(ifd >= 0 && ofd >= 0 && !m->child_buffio);      m->child_buffio = buffio_new(ifd, ofd); -    buffio_set_input_watermark(m->child_buffio, INPUT_WATERMARK_CHILD); +    buffio_set_input_range(m->child_buffio, INPUT_RANGE_CHILD); +    buffio_set_output_range(m->child_buffio, OUTPUT_RANGE_CHILD);      m->child_buffio->user = m;      m->child_buffio->eof_cb = child_eof_cb;      m->child_buffio->epipe_cb = child_epipe_cb;      m->child_buffio->input_ready_cb = child_input_ready_cb; -    m->child_buffio->output_empty_cb = child_output_empty_cb; +    m->child_buffio->output_request_cb = child_output_request_cb;      m->child_buffio->error_cb = error_cb;      return 0; @@ -439,6 +491,10 @@ static void* oop_timeout_cb(oop_source *source, struct timeval tv, void *user) {              daemon_log(LOG_ERR, "Timeout reached for device <%s>", m->dev);              return OOP_HALT; +        case MODEM_STATE_RINGING: +            modem_accept(m); +            return OOP_CONTINUE; +                      case MODEM_STATE_ATA:          case MODEM_STATE_VTXVRX: @@ -555,6 +611,7 @@ static int modem_input_ready_cb(struct buffio *b, void *user) {                  struct tabentry *t;                  c[strcspn(c, "\n\r")] = 0; +                  free(m->ring_number);                  m->ring_number = strdup(c);                  assert(m->ring_number); @@ -563,27 +620,46 @@ static int modem_input_ready_cb(struct buffio *b, void *user) {                  daemon_log(LOG_INFO, "Incoming call from [%s] to [%s]", m->caller_number, m->ring_number);                  if ((t = msntab_check_call(m->ring_number, m->caller_number)) && (t->action == CALL_ACTION_ACCEPT || t->action == CALL_ACTION_HANGUP)) { +                      if (m->tabentry)                          msntab_unref(m->tabentry);                      m->tabentry = t; -                    daemon_log(LOG_INFO, "Accepting call."); - -                    m->state = MODEM_STATE_ATA; -                    modem_timeout(m, ACCEPT_TIMEOUT); -                    buffio_command(m->buffio, "ATA\n"); -                } else { -                    if (t) -                        msntab_unref(t); -                    daemon_log(LOG_INFO, "Ignoring call."); -                    m->state = MODEM_STATE_CALLER_NUMBER_EXPECT; -                    modem_input_ready_cb(b, user); +                    if (t->rings <= 0) +                        modem_accept(m); +                    else { +                        daemon_log(LOG_INFO, "Will accept call after %u rings (%u seconds).", t->rings, t->rings*RING_TIME); +                        m->state = MODEM_STATE_RINGING; +                        modem_timeout(m, RING_TIME*t->rings); +                    } +                     +                    break;                  } + +                daemon_log(LOG_INFO, "Ignoring call."); + +                if (t) +                    msntab_unref(t); +                 +                m->state = MODEM_STATE_CALLER_NUMBER_EXPECT; +                modem_input_ready_cb(b, user);              }              break;          } +        case MODEM_STATE_RINGING: + +            if (buffio_find_input(m->buffio, "RUNG\r\n")) { +                daemon_log(LOG_INFO, "Peer hung up prematurely."); +                m->state = MODEM_STATE_CALLER_NUMBER_EXPECT; +                modem_timeout(m, 0); +                modem_input_ready_cb(b, user); +            } else +                buffio_dump_lines(m->buffio); + +            break; +          case MODEM_STATE_ATA:              if (buffio_find_input(m->buffio, "VCON\r\n")) { @@ -621,8 +697,13 @@ static int modem_input_ready_cb(struct buffio *b, void *user) {                      modem_hangup(m, 1);                  } else {                      m->dle_flag = 0; -                    buffio_set_input_watermark(m->buffio, INPUT_WATERMARK_CONNECTION); +                    buffio_set_input_range(m->buffio, INPUT_RANGE_CONNECTION); +                    buffio_set_output_range(m->buffio, OUTPUT_RANGE_CONNECTION);                      buffio_set_delay_usec(m->buffio, ISDN_DELAY_USEC, ISDN_LATENCY_USEC); +                    buffio_set_prebuf(m->buffio, 1); + +                    m->flush_msg = 0; +                                          modem_input_ready_cb(b, user);                  } @@ -650,10 +731,6 @@ static int modem_output_empty_cb(struct buffio *b, void *user) {      switch (m->state) { -        case MODEM_STATE_CONNECTION: -            copy_child_to_modem(m); -            break; -          case MODEM_STATE_PRE_HANGUP_HUPSEQ:              if (b)                  buffio_command(m->buffio, hup_sequence); @@ -663,8 +740,6 @@ static int modem_output_empty_cb(struct buffio *b, void *user) {              buffio_command(m->buffio, ath_sequence);              m->state = MODEM_STATE_HANGUP; -            daemon_log(LOG_INFO, "Delayed HANGUP sequence"); -              /* Don't restart timeout here */              break; @@ -680,6 +755,25 @@ static int modem_output_empty_cb(struct buffio *b, void *user) {      return 0;  } +static int modem_output_request_cb(struct buffio *b, void *user) { +    struct modem *m = user; +    assert(b && m && m->buffio == b); + +    switch (m->state) { + +        case MODEM_STATE_CONNECTION: +            //daemon_log(LOG_INFO, "modem_output_request"); +            copy_child_to_modem(m); +            break; + +        default: +            break; +    } + +    return 0; +} + +  static int modem_dle_cb(uint8_t c, void *user) {      struct modem *m = user;      assert(m); @@ -696,10 +790,10 @@ static int modem_dle_cb(uint8_t c, void *user) {              return -1;          default: -            daemon_log(LOG_INFO, "Recieved DTMF character '%c'", c); +            assert(m->dtmf_fifo);  +            dtmf_fifo_pass(m->dtmf_fifo, c); +            return 0;      } - -    return 0;  }  static void copy_modem_to_child(struct modem *m) { @@ -708,10 +802,27 @@ static void copy_modem_to_child(struct modem *m) {      size_t sl, dl;      assert(m->buffio && m->child_buffio); -    sp = buffio_read_ptr(m->buffio, &sl); -    dp = buffio_write_ptr(m->child_buffio, &dl); + +    for (;;) { +        sp = buffio_read_ptr(m->buffio, &sl); +        dp = buffio_write_ptr(m->child_buffio, &dl); + +        if (sp && sl && (!dp || !dl)) { +            if (!m->flush_msg) { +                daemon_log(LOG_INFO, "Child too slow, output buffer overflow, flushing."); +                m->flush_msg = 1; +            } +             +            buffio_flush_output(m->child_buffio); +            continue; +        } + +        break; +    }      if (sp && sl && dp && dl) { +        //daemon_log(LOG_INFO, "copy modem->child (%lu->%lu)", (unsigned long) m->buffio->input_length, (unsigned long) (m->child_buffio->output_range - m->child_buffio->output_length)); +          sl = dle_decode(sp, sl, dp, &dl, modem_dle_cb, m, &m->dle_flag);          /* It may be the case that dle_decode recieved a @@ -728,11 +839,15 @@ static void copy_child_to_modem(struct modem *m) {      const uint8_t *sp;      uint8_t *dp; -    assert(m->child_buffio && m->buffio); +    assert(m && m->child_buffio && m->buffio); +      sp = buffio_read_ptr(m->child_buffio, &sl);      dp = buffio_write_ptr(m->buffio, &dl); -     +      if (sp && dp && sl && dl) { +     +        //daemon_log(LOG_INFO, "copy child->modem (%lu->%lu)", (unsigned long) m->child_buffio->input_length, (unsigned long) (m->buffio->output_range - m->buffio->output_length)); +                  sl = dle_encode(sp, sl, dp, &dl);          buffio_read_ptr_inc(m->child_buffio, sl);          buffio_write_ptr_inc(m->buffio, dl); @@ -750,7 +865,7 @@ static int modem_reopen(struct modem *m) {          buffio_close_input_fd(m->buffio);      } -    daemon_log(LOG_INFO, "Trying to open TTY device '%s' ...", m->dev); +    daemon_log(LOG_INFO, "Trying to open modem on TTY device '%s' ...", m->dev);      if ((fd = open(m->dev, O_RDWR|O_NDELAY)) < 0) {          daemon_log(LOG_ERR, "Failed to open device '%s': %s", m->dev, strerror(errno)); @@ -786,11 +901,17 @@ static int modem_reopen(struct modem *m) {          m->buffio = buffio_new(fd, fd);          assert(m->buffio); +        m->buffio->output_request_cb = modem_output_request_cb;          m->buffio->output_empty_cb = modem_output_empty_cb;          m->buffio->input_ready_cb = modem_input_ready_cb;          m->buffio->error_cb = error_cb; -             +          m->buffio->user = m; +         +        buffio_set_input_range(m->buffio, INPUT_RANGE_DEFAULT); +        buffio_set_output_range(m->buffio, OUTPUT_RANGE_DEFAULT); +        buffio_set_delay_usec(m->buffio, 0, 0); +      } else          buffio_set_fds(m->buffio, fd, fd); diff --git a/src/modem.h b/src/modem.h index 320467a..8fed726 100644 --- a/src/modem.h +++ b/src/modem.h @@ -10,6 +10,7 @@ enum modem_state {      MODEM_STATE_CALLER_NUMBER,      MODEM_STATE_RING_EXPECT,      MODEM_STATE_RING, +    MODEM_STATE_RINGING,      MODEM_STATE_ATA,      MODEM_STATE_VTXVRX,      MODEM_STATE_CONNECTION, @@ -36,9 +37,11 @@ struct modem {      struct buffio *child_buffio;      pid_t child_pid; +    struct dtmf_fifo *dtmf_fifo; +      struct timeval timeout; -    char *local_msn; +    char *listen_msn;      char *ring_number;      char *caller_number; @@ -46,6 +49,7 @@ struct modem {      struct tabentry *tabentry;      int dle_flag; +    int flush_msg;  };  struct modem *modem_open(const char *dev); diff --git a/src/msntab.c b/src/msntab.c index bcd3030..09709cc 100644 --- a/src/msntab.c +++ b/src/msntab.c @@ -1,12 +1,39 @@  #include <stddef.h>  #include <assert.h> +#include <stdlib.h> +#include <string.h> +#include <fnmatch.h> +#include <stdio.h> +#include <unistd.h> + +#include <libdaemon/dlog.h> +  #include "msntab.h" +#define MAX_ENTRIES 100 +#define MAX_INCLUDES 10 + +static struct tabentry *first = NULL; +static struct tabentry *last = NULL; +static int n_entries = 0; + +static int n_includes = 0; +  struct tabentry* msntab_check_call(const char *callee, const char *caller) { -    static char *args[] = { "/bin/cat", NULL }; -    static struct tabentry ca = { CALL_ACTION_ACCEPT, 1, args }; +    struct tabentry *l = first; -    return msntab_ref(&ca); +    while (l) { +        assert(l->local && l->remote); +         +        if (!fnmatch(l->local, callee, 0) &&  !fnmatch(l->remote, caller, 0)) { +            daemon_log(LOG_INFO, "MSN table entry from '%s:%u' matched.", l->filename, l->line); +            return msntab_ref(l); +        } +         +        l = l->next; +    } + +    return NULL;  } @@ -19,5 +46,275 @@ struct tabentry* msntab_ref(struct tabentry *t) {  void msntab_unref(struct tabentry *t) {      assert(t && t->ref_counter >= 1);      t->ref_counter--; + +    if (t->ref_counter == 0) { +         +        if (t->args) { +            char **a = t->args; +            while (*a) { +                free(*a); +                a++; +            } +            free(t->args); +        } + +        free(t->local); +        free(t->remote); +        free(t->filename); +         +        free(t); +    } +} + +void msntab_flush(void) { +    while (first) { +        struct tabentry *l = first; +        first = first->next; + +        if (first) +            first->prev = NULL; + +        if (last == l) +            last = NULL; +         +        msntab_unref(l); +    } + +    n_entries = 0; +    n_includes++; +} + +#define MAX_ARGS 16 + +static char** parse_args(const char *s) { +    char *o, **a; +    char *c = (char*) s; +    int i = 0; + +    a = malloc(sizeof(char *)*MAX_ARGS); +    memset(a, 0, sizeof(char *)*MAX_ARGS); + +    while ((o = strsep(&c, " \t"))) { +        a[i++] = strdup(o); + +        if (i >= MAX_ARGS-1) +            break; +    } + +    return a; +} + + +static int parse_options(const char *s, struct tabentry *t) { +    char *o; +    char *c = (char*) s; + +    assert(s && t); +     +    while ((o = strsep(&c, ","))) { + +        if (!strcmp(o, "defaults")) +            continue; +        else if (!strcmp(o, "shbuf")) { +            t->shbuf = 1; +            continue; +        } else if (!strncmp(o, "rings=", 6)) { +            t->rings = atoi(o+6); +            continue; +        } + +        daemon_log(LOG_INFO, "Unknown option '%s'", o); +        return -1; +    } + +    return 0;  } + +int msntab_load(const char *fn) { +    int n; +    struct tabentry *t = NULL; +    FILE *f = NULL; + +    daemon_log(LOG_INFO, "Loading MSN table '%s'.", fn); +    if (!(f = fopen(fn, "r"))) { +        daemon_log(LOG_ERR, "Failed to open MSN table '%s'.", fn); +        goto fail; +    } + +    n = 0; +    while (!feof(f)) { +        char l[256], *c, *e, *local, *remote, *options, *action; + +        n++; + +        if (!fgets(l, sizeof(l), f)) +            break; + +        c = l+strspn(l, " \t"); +        if ((e = strchr(c, '\r'))) +            *e = 0; +        if ((e = strchr(c, '\n'))) +            *e = 0; +        e = strchr(c, 0); + +        if (*c == '#' || *c == 0) +            continue; + +        if (!(local = strsep(&c, " \t"))) { +            daemon_log(LOG_ERR, "Parse failure on local MSN field in '%s:%i'.", fn, n); +            goto fail; +        } + +        if (c) +            c+=strspn(c, " \t"); + +        if (!strcmp(local, "@include")) { +            char *include; +             +            if (n_includes ++ >= MAX_INCLUDES) { +                daemon_log(LOG_ERR, "Recursive include directive detected."); +                goto fail; +            }             + +            if (!(include = strsep(&c, ""))) { +                daemon_log(LOG_ERR, "Parse failure on include field in '%s:%i'.", fn, n); +                goto fail; +            } + +            if (msntab_load(include) < 0) +                goto fail; +             +            continue; +        } +         +        if (!(remote = strsep(&c, " \t"))) { +            daemon_log(LOG_ERR, "Parse failure on remote MSN field in '%s:%i'.", fn, n); +            goto fail; +        } + +        if (c) +            c+=strspn(c, " \t"); + +        if (!(options = strsep(&c, " \t"))) { +            daemon_log(LOG_ERR, "Parse failure on options field in '%s:%i'.", fn, n); +            goto fail; +        } + +        if (c) +            c+=strspn(c, " \t"); + +        if (!(action = strsep(&c, ""))) { +            daemon_log(LOG_ERR, "Parse failure on action field in '%s:%i'.", fn, n); +            goto fail; +        } + +        t = malloc(sizeof(struct tabentry)); +        assert(t); +        memset(t, 0, sizeof(struct tabentry)); + +        t->line = n; +        t->filename = strdup(fn); +         +        t->ref_counter = 1; +         +        t->local = strdup(local); +        assert(t->local); + +        t->remote = strdup(remote); +        assert(t->remote); + +        if (action[0] == '@') { +            if (!strcmp(action, "@hangup")) +                t->action = CALL_ACTION_HANGUP; +            else if (!strcmp(action, "@ignore")) +                t->action = CALL_ACTION_IGNORE; +            else { +                daemon_log(LOG_ERR, "Unknown action command '%s' in '%s:%i'.", action, fn, n); +                goto fail; +            } +        } else { +            t->action = CALL_ACTION_ACCEPT; +            t->args = parse_args(action); +        } + +        if (parse_options(options, t) < 0) { +            daemon_log(LOG_ERR, "Parse failure on options field in '%s:%i'.", fn, n); +            goto fail; +        } + +        if (last) { +            t->prev = last; +            last->next = t; +            last = t; +        } else +            last = first = t; + +        n_entries ++; + +        t = NULL; + +        if (n_entries > MAX_ENTRIES) { +            daemon_log(LOG_INFO, "Too many MSN table entries"); +            goto fail; +        } +    } + +    fclose(f); +    daemon_log(LOG_INFO, "MSN table '%s' successfully read.", fn); +     +    return 0; +     +fail: + +    if (t) +        msntab_unref(t); +     +    if (f) +        fclose(f); +     +    return -1; +} + + +static void dump_entry(struct tabentry *t) { +    char s[256]; +    assert(t); + +    s[0] = 0; +     +    if (t->args) { +        char **a = t->args; +         +        while (*a) { +            char *p = strchr(s, 0); +            snprintf(p, sizeof(s)-(p-s), a == t->args ? "%s" : " %s", *a); +            a++; +        } +    } else +        strncpy(s, "NOARGS", sizeof(s)); +     +    daemon_log(LOG_INFO, "[%s:%02u] %-12s -> %-12s; shbuf=%-3s; rings=%u; action=%s; args=<%s>", +               t->filename, +               t->line, +               t->local, +               t->remote, +               t->shbuf ? "yes" : "no", +               t->rings, +               t->action == CALL_ACTION_ACCEPT ? "ACCEPT" : (t->action == CALL_ACTION_HANGUP ? "HANGUP" : "IGNORE"), +               s); +} + +void msntab_dump(void) { +    struct tabentry *l; + +    daemon_log(LOG_INFO, "=== Dumping MSN table ==="); + +    l = first; +    while (l) { +        dump_entry(l); +        l = l->next; +    } + +    daemon_log(LOG_INFO, "=== MSN table dump complete ==="); +} diff --git a/src/msntab.h b/src/msntab.h index 28de484..9c473e3 100644 --- a/src/msntab.h +++ b/src/msntab.h @@ -5,13 +5,28 @@ enum call_action { CALL_ACTION_IGNORE, CALL_ACTION_ACCEPT, CALL_ACTION_HANGUP };  struct tabentry {      enum call_action action; -    int ref_counter; +    unsigned ref_counter;      char **args; +    char *local; +    char *remote; + +    struct tabentry *next; +    struct tabentry *prev; + +    int shbuf; +    unsigned rings; + +    char *filename; /* filename of the msntab where this entry originates from */ +    unsigned line;  };  struct tabentry* msntab_check_call(const char *callee, const char *caller);  struct tabentry* msntab_ref(struct tabentry *t);  void msntab_unref(struct tabentry *t); +void msntab_flush(void); +int msntab_load(const char *fn); +void msntab_dump(void); +  #endif | 
