From d24a3f265ec4344b5502ec57df3cf8358f6f1499 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 5 Jan 2004 22:24:10 +0000 Subject: many changes git-svn-id: file:///home/lennart/svn/public/ivam2/trunk@14 dbf6933d-3bce-0310-9bcc-ed052ba35b35 --- conf/msntab | 10 +- doc/TODO | 11 ++- src/Makefile | 2 +- src/buffio.c | 276 ++++++++++++++++++++++++++++------------------------- src/buffio.h | 26 +++-- src/exec.c | 10 +- src/main.c | 41 +++++++- src/modem.c | 213 ++++++++++++++++++++++++++++++++--------- src/modem.h | 6 +- src/msntab.c | 303 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 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$ diff --git a/doc/TODO b/doc/TODO index 18fe2b1..8686af0 100644 --- a/doc/TODO +++ b/doc/TODO @@ -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 diff --git a/src/exec.c b/src/exec.c index d9195c6..fabe757 100644 --- a/src/exec.c +++ b/src/exec.c @@ -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); } } diff --git a/src/main.c b/src/main.c index 9710be9..4f5a273 100644 --- a/src/main.c +++ b/src/main.c @@ -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 #include #include +#include #include @@ -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 #include +#include +#include +#include +#include +#include + +#include + #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 -- cgit