From 33f01df1c95b43b66e2f0bab2b972dd9e03faeb5 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 23 Dec 2003 00:05:15 +0000 Subject: it compiles and works basically git-svn-id: file:///home/lennart/svn/public/ivam2/trunk@9 dbf6933d-3bce-0310-9bcc-ed052ba35b35 --- src/Makefile | 6 +- src/buffio.c | 231 ++++++++++++++++++++++++----------- src/buffio.h | 15 ++- src/dle.c | 7 +- src/dle.h | 8 ++ src/exec.c | 118 +++++++++++++----- src/exec.h | 4 +- src/lock.c | 18 ++- src/main.c | 19 ++- src/main.h | 2 + src/modem.c | 377 ++++++++++++++++++++++++++++++++++----------------------- src/modem.h | 12 +- src/modemman.c | 45 ++++--- src/util.c | 9 +- src/util.h | 4 +- 15 files changed, 581 insertions(+), 294 deletions(-) diff --git a/src/Makefile b/src/Makefile index 7269fde..5aff207 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,8 +1,8 @@ CC=gcc -CFLAGS=`pkg-config --cflags libdaemon shbuf` -Wall -O2 -pipe -LIBS=`pkg-config --libs libdaemon shbuf` +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 +ivamd: modem.o main.o modemman.o buffio.o exec.o dle.o lock.o util.o msntab.o $(CC) $(LIBS) -o $@ $^ clean: diff --git a/src/buffio.c b/src/buffio.c index 2c3a7fb..25ba5a4 100644 --- a/src/buffio.c +++ b/src/buffio.c @@ -1,12 +1,25 @@ +#include +#include +#include +#include +#include + +#include + +#include + #include "buffio.h" +#include "main.h" #define BUFSIZE 10240 -static void buffio_set_callbacks(struct buffio *b); 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); -struct buffio buffio_new(int fd) { +static void buffio_set_input_callbacks(struct buffio *b); +static void buffio_set_output_callbacks(struct buffio *b); + +struct buffio* buffio_new(int ifd, int ofd) { struct buffio *b; assert(b >= 0); @@ -14,19 +27,21 @@ struct buffio buffio_new(int fd) { assert(b); memset(b, 0, sizeof(struct buffio)); - b->fd = fd; + b->ifd = ifd; + b->ofd = ofd; b->input_buf = malloc(b->input_max_length = BUFSIZE); assert(b->input_buf); - b->input_buf_len = b->input_index = 0; - b->input_watermark = 2; /* Read some more data if 2 or less bytes are in the input buffer */ + b->input_length = b->input_index = 0; + b->input_watermark = b->input_max_length; /* Read some more data if possible */ 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 */ - buffio_set_callbacks(b); + buffio_set_input_callbacks(b); + buffio_set_output_callbacks(b); return b; } @@ -35,16 +50,18 @@ static void buffio_close_fd(struct buffio *b) { assert(b); if (b->b_read_cb) - event_source->cancel_fd(event_source, b->fd, OOP_READ, buffio_read_cb, b); + event_source->cancel_fd(event_source, b->ifd, OOP_READ); if (b->b_write_cb) - event_source->cancel_fd(event_source, b->fd, OOP_WRITE, buffio_write_cb, b); + event_source->cancel_fd(event_source, b->ofd, OOP_WRITE); - if (b->fd >= 0) - close(b->fd); + if (b->ifd >= 0) + close(b->ifd); + if (b->ofd >= 0 && b->ofd != b->ifd) + close(b->ofd); b->b_read_cb = b->b_write_cb = 0; - b->fd = -1; + b->ifd = b->ofd = -1; } @@ -55,13 +72,69 @@ void buffio_free(struct buffio *b) { free(b); } +#ifdef IODEBUG +static void esc_print(const char*c, const uint8_t *b, size_t l) { + size_t i; + fprintf(stderr, "%s", c); + for (i = 0; i < l; i++, b++) + fputc(*b < 32 ? '.' : *b, stderr); + + fprintf(stderr, "\n"); +}; +#endif + +static void buffio_normalize(struct buffio *b) { + assert(b); + + assert(b->input_index < b->input_max_length); + assert(b->input_length <= b->input_max_length); + + if (!b->input_length) /* This will optimize throughput a bit */ + b->input_index = 0; + + if (!b->output_length) /* This will optimize throughput a bit */ + b->output_index = 0; +} + +static void buffio_set_input_callbacks(struct buffio *b) { + assert(b && b->ifd >= 0 && event_source); + + if (b->input_length <= b->input_watermark) { + 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; + } + } else { + if (b->b_read_cb) { /* Disable the callback */ + event_source->cancel_fd(event_source, b->ifd, OOP_READ); + b->b_read_cb = 0; + } + } +} + +static void buffio_set_output_callbacks(struct buffio *b) { + assert(b && b->ofd >= 0 && event_source); + + if (b->output_length >= b->output_watermark) { + 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; + } + } else { + if (b->b_write_cb) { /* Disable the callback */ + event_source->cancel_fd(event_source, b->ofd, OOP_WRITE); + b->b_write_cb = 0; + } + } +} + static void* buffio_read_cb(oop_source *source, int fd, oop_event event, void *user) { struct buffio *b = user; - assert(source && b && b->fd == fd && event == OOP_READ); + assert(source && b && b->ifd == fd && event == OOP_READ); if (b->input_length < b->input_max_length) { ssize_t s; - size_t m, l; + size_t m, i; i = (b->input_index + b->input_length) % b->input_max_length; @@ -74,6 +147,10 @@ static void* buffio_read_cb(oop_source *source, int fd, oop_event event, void *u return OOP_HALT; } +#ifdef IODEBUG + esc_print("INPUT: ", b->input_buf+i, s); +#endif + if (!s) { buffio_close_fd(b); if (b->eof_cb) @@ -96,9 +173,9 @@ static void* buffio_read_cb(oop_source *source, int fd, oop_event event, void *u static void* buffio_write_cb(oop_source *source, int fd, oop_event event, void *user) { struct buffio *b = user; - assert(source && b && b->fd == fd && event == OOP_WRITE); + assert(source && b && b->ofd == fd && event == OOP_WRITE); - if (b->output_buf > 0) { + if (b->output_length > 0) { ssize_t s; size_t m; @@ -111,6 +188,10 @@ static void* buffio_write_cb(oop_source *source, int fd, oop_event event, void * return OOP_HALT; } +#ifdef IODEBUG + esc_print("OUTPUT: ", b->output_buf+b->output_index, s); +#endif + if (!s) { buffio_close_fd(b); if (b->eof_cb) @@ -120,7 +201,7 @@ static void* buffio_write_cb(oop_source *source, int fd, oop_event event, void * assert(s <= m); b->output_index = (b->output_index + s) % b->output_max_length; - b->ouput_length -= s; + b->output_length -= s; } buffio_normalize(b); @@ -133,51 +214,24 @@ static void* buffio_write_cb(oop_source *source, int fd, oop_event event, void * } -static void buffio_set_input_callbacks(struct buffio *b) { - assert(b && b->fd >= 0 && event_source); - - if (b->input_length <= b->input_watermark) { - if (!b->b_read_cb) { /* Enable the callback */ - event_source->on_fd(event_source, b->fd, OOP_READ, buffio_read_cb, b); - b->b_read_cb = 1; - } - } else { - if (b->read_cb) { /* Disable the callback */ - event_source->cancel_fd(event_source, b->fd, OOP_READ, buffio_read_cb, b); - b->read_cb = 0; - } - } -} - -static void buffio_set_output_callbacks(struct buffio *b) { - assert(b && b->fd >= 0 && event_source); - - if (b->output_length >= b->output_watermark) { - if (!b->b_write_cb) { /* Enable the callback */ - event_source->on_fd(event_source, b->fd, OOP_WRITE, buffio_write_cb, b); - b->b_write_cb = 1; - } - } else { - if (b->b_write_cb) { /* Disable the callback */ - event_source->cancel_fd(event_source, b->fd, OOP_WRITE, buffio_write_cb, b); - b->b_write_cb = 0; - } - } -} int buffio_write(struct buffio *b, const uint8_t *d, size_t l) { - assert(b && s && l); + assert(b && d && l); - if (l < b->output_max_length - b->output_length) { + if (l > b->output_max_length - b->output_length) { daemon_log(LOG_ERR, "buffio_write() with too much data called"); return -1; } + while (l > 0) { + size_t m, i; + + i = (b->output_index + b->output_length) % b->output_max_length; - while (l >= 0) { - i = (b->ouput_index + b->ouput_length) % b->ouput_max_length; + m = l; + if (m > b->output_max_length-b->output_length) + m = b->output_max_length-b->output_length; - m = b->ouput_max_length-b->output_length; if (m > b->output_max_length-i) m = b->output_max_length-i; @@ -188,7 +242,7 @@ int buffio_write(struct buffio *b, const uint8_t *d, size_t l) { } buffio_set_output_callbacks(b); - buffio_normalize(); + buffio_normalize(b); return 0; } @@ -200,7 +254,7 @@ int buffio_print(struct buffio *b, const char *s) { int buffio_command(struct buffio *b, const char *c) { assert(b && c); - + buffio_flush_input(b); return buffio_print(b, c); } @@ -209,29 +263,19 @@ void buffio_flush_input(struct buffio *b) { assert(b); b->input_length = b->input_index = 0; - buffio_set_callbacks(b); + buffio_set_input_callbacks(b); } -static void buffio_normalize(struct buffio *b) { - assert(b); - - assert(b->input_index < b->input_max_length); - assert(b->input_length <= b->input_max_length); - - if (!b->input_length) /* This will optimize throughput a bit */ - b->input_index = 0; -} - int buffio_find_input(struct buffio *b, const char *c) { - size_t l, cl, j; + size_t l, cl, i; assert(b && c && *c); - + cl = strlen(c); for (i = b->input_index, l = b->input_length; l >= cl; i = (i+1) % b->input_max_length, l--) { - char *p; - size_t i; + const char *p; + size_t j; for (j = i, p = c; *p && *p == b->input_buf[j]; p++, j = (j+1) % b->input_max_length); @@ -240,6 +284,7 @@ int buffio_find_input(struct buffio *b, const char *c) { b->input_length = l-cl; buffio_normalize(b); + buffio_set_input_callbacks(b); return 1; } } @@ -248,3 +293,51 @@ int buffio_find_input(struct buffio *b, const char *c) { } +char *buffio_read_line(struct buffio *b, char *c, size_t l) { + size_t i; + assert(b && c && l); + + /* Look for a \n */ + for (i = 0; i < b->input_length && i < l-1; i++) { + if (b->input_buf[(b->input_index+i) % b->input_max_length] == '\n') { + size_t j; + + /* Once again, now copy */ + for (j = 0;; j++) { + c[j] = b->input_buf[(b->input_index+j) % b->input_max_length]; + + /* Finished? */ + if (c[j] == '\n') { + c[j+1] = 0; + + b->input_index = (b->input_index+j+1) % b->input_max_length; + b->input_length -= j+1; + buffio_set_input_callbacks(b); + buffio_normalize(b); + return c; + } + } + } + } + + return NULL; +} + +void buffio_dump(struct buffio *b) { + assert(b); + size_t i; + + fprintf(stderr, "%p INPUT_BUFFER: [", b); + for (i = 0; i < b->input_length; i++) { + char c = b->input_buf[(i + b->input_index) % b->input_max_length]; + fputc(c < 32 ? '.' : c, stderr); + } + fprintf(stderr, "]\n"); + + fprintf(stderr, "%p OUTPUT_BUFFER: [", b); + for (i = 0; i < b->output_length; i++) { + char c = b->output_buf[(i + b->output_index) % b->output_max_length]; + fputc(c < 32 ? '.' : c, stderr); + } + fprintf(stderr, "]\n"); +} diff --git a/src/buffio.h b/src/buffio.h index a340385..e0a2d0a 100644 --- a/src/buffio.h +++ b/src/buffio.h @@ -1,14 +1,18 @@ #ifndef foobuffiohfoo #define foobuffiohfoo +#include +#include + struct buffio { - int fd; + int ifd; + int ofd; uint8_t *input_buf; - size_t input_max_length, input_index, input_length; + size_t input_max_length, input_index, input_length, input_watermark; uint8_t *output_buf; - size_t output_max_length, output_index, output_length; + size_t output_max_length, output_index, output_length, output_watermark; int b_read_cb, b_write_cb; @@ -19,7 +23,7 @@ struct buffio { void (*input_ready_cb) (struct buffio *b, void *user); }; -struct buffio buffio_new(int fd); +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); @@ -28,5 +32,8 @@ int buffio_print(struct buffio *b, const char *s); int buffio_command(struct buffio *b, const char *c); void buffio_flush_input(struct buffio *b); 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); #endif diff --git a/src/dle.c b/src/dle.c index 51b3c75..680c82f 100644 --- a/src/dle.c +++ b/src/dle.c @@ -1,9 +1,6 @@ -#include "dle.h" +#include -/* Those nifty DLE-sequences */ -#define DLE 0x10 -#define ETX 0x03 -#define DC4 0x14 +#include "dle.h" size_t dle_decode(uint8_t* s, size_t ls, uint8_t* d, size_t *ld, void (*dle_func) (uint8_t c, void *user), void *user, int *dle_flag) { size_t ns, nd; diff --git a/src/dle.h b/src/dle.h index 2e0e453..72bfd55 100644 --- a/src/dle.h +++ b/src/dle.h @@ -1,6 +1,14 @@ #ifndef foodlehfoo #define foodlehfoo +#include +#include + +/* Those nifty DLE-sequences */ +#define DLE 0x10 +#define ETX 0x03 +#define DC4 0x14 + size_t dle_decode(uint8_t* s, size_t ls, uint8_t* d, size_t *ld, void (*dle_func) (uint8_t c, void *user), void *user, int *dle_flag); size_t dle_encode(uint8_t* s, size_t ls, uint8_t* d, size_t *ld); diff --git a/src/exec.c b/src/exec.c index d9d8e49..728c574 100644 --- a/src/exec.c +++ b/src/exec.c @@ -1,3 +1,13 @@ +#include +#include +#include +#include +#include +#include +#include + +#include + #include "exec.h" #include "main.h" @@ -6,13 +16,13 @@ struct process_info { pid_t pid; int killed; - int child_pipe; - process_exit_cb_t *cb; + int stderr_pipe; + process_exit_cb_t cb; void *user; struct process_info *next; char *read_buf; - size_t read_buf_size; + size_t read_buf_len; }; static struct process_info *procs = NULL; @@ -34,19 +44,20 @@ static void *oop_read_cb(oop_source *source, int fd, oop_event event, void *user static void close_child_pipe(struct process_info *p) { assert(p); - + if (p->read_buf_len && p->read_buf) { *(p->read_buf + p->read_buf_len) = 0; daemon_log(LOG_INFO, "child(%lu): %s", (unsigned long) p->pid, p->read_buf); p->read_buf_len = 0; } - if (p->child_pipe >= 0) { + if (p->stderr_pipe >= 0) { assert(event_source && event_source->cancel_fd); - event_source->cancel_fd(event_source, p->child_pipe, OOP_READ, oop_read_cb, p); - close(p->child_pipe); - p->child_pipe = -1; + event_source->cancel_fd(event_source, p->stderr_pipe, OOP_READ); + close(p->stderr_pipe); + p->stderr_pipe = -1; } + } @@ -97,8 +108,8 @@ static void *oop_sigchld_cb(oop_source *source, int sig, void *user) { return OOP_HALT; } - if (!(p = find_process_by_pid(pid))) { - daemon_log(LOG_WARN, "Got SIGCHLD for unknown process, reaping"); + if (!(p = find_process(pid))) { + daemon_log(LOG_WARNING, "Got SIGCHLD for unknown process, reaping"); return OOP_CONTINUE; } @@ -121,7 +132,7 @@ static void *oop_read_cb(oop_source *source, int fd, oop_event event, void *user assert(source && event == OOP_READ); p = (struct process_info*) user; - assert(p && p->child_pipe == fd && fd >= 0); + assert(p && p->stderr_pipe == fd && fd >= 0); if (!p->read_buf) { p->read_buf = malloc(CHILD_BUF_SIZE); @@ -131,7 +142,7 @@ static void *oop_read_cb(oop_source *source, int fd, oop_event event, void *user assert(p->read_buf); start = p->read_buf+p->read_buf_len; - if ((s = read(p->child_pipe, start, CHILD_BUF_SIZE-p->read_buf_len-1)) < 0) { + if ((s = read(fd, start, CHILD_BUF_SIZE-p->read_buf_len-1)) < 0) { daemon_log(LOG_ERR, "Failed to read from child pipe: %s", strerror(errno)); return OOP_HALT; } @@ -165,20 +176,40 @@ static void *oop_read_cb(oop_source *source, int fd, oop_event event, void *user return OOP_CONTINUE; } +static void pipe_close(int fds[]) { + close(fds[0]); + close(fds[1]); +} -pid_t child_process_create(const char *file, char *const argv[], process_exit_cb_t cb, void*user) { +pid_t child_process_create(const char *file, char *const argv[], int *ifd, int *ofd, process_exit_cb_t cb, void *user) { pid_t pid; - int fds[2]; + int stdin_fds[2]; + int stdout_fds[2]; + int stderr_fds[2]; + + if (pipe(stdin_fds) < 0) { + daemon_log(LOG_ERR, "pipe() failed: %s", strerror(errno)); + return -1; + } + + if (pipe(stdout_fds) < 0) { + daemon_log(LOG_ERR, "pipe() failed: %s", strerror(errno)); + pipe_close(stdin_fds); + return -1; + } - if (pipe(fds) < 0) { + if (pipe(stderr_fds) < 0) { daemon_log(LOG_ERR, "pipe() failed: %s", strerror(errno)); + pipe_close(stdin_fds); + pipe_close(stdout_fds); return -1; } if ((pid = fork()) < 0) { daemon_log(LOG_ERR, "fork() failed: %s", strerror(errno)); - close(fds[0]); - close(fds[1]); + pipe_close(stdin_fds); + pipe_close(stdout_fds); + pipe_close(stderr_fds); return -1; } @@ -195,11 +226,23 @@ pid_t child_process_create(const char *file, char *const argv[], process_exit_cb p->next = procs; p->killed = 0; - p->client_pipe = fds[0]; - close(fds[1]); + p->stderr_pipe = stderr_fds[0]; + close(stderr_fds[1]); + + if (ifd) + *ifd = stdout_fds[0]; + else + close(stdout_fds[0]); + close(stdout_fds[1]); + + if (ofd) + *ofd = stdin_fds[1]; + else + close(stdin_fds[1]); + close(stdin_fds[0]); assert(event_source && event_source->on_fd); - event_source->on_fd(event_source, p->client_pipe, oop_read_cb, p); + event_source->on_fd(event_source, p->stderr_pipe, OOP_READ, oop_read_cb, p); procs = p; @@ -207,27 +250,42 @@ pid_t child_process_create(const char *file, char *const argv[], process_exit_cb } else { /* child */ - int fd; - close(fds[0]); + close(stderr_fds[0]); + close(stdout_fds[0]); + close(stdin_fds[1]); + for (fd = 0; fd <= 2; fd++) { - if (fd != fds[1]) + if (fd != stderr_fds[1] && fd != stdout_fds[1] && fd != stdin_fds[0]) close(fd); } - if ((fds[1] != 1 && dup2(fds[1], 1) < 0) || - (fds[1] != 2 && dup2(fds[1], 2) < 0)) { + if ((stdin_fds[0] != 0 && dup2(stdin_fds[0], 0) < 0) || + (stdout_fds[1] != 1 && dup2(stdout_fds[1], 1) < 0) || + (stderr_fds[1] != 2 && dup2(stderr_fds[1], 2) < 0)) { daemon_log(LOG_ERR, "dup2() failed: %s", strerror(errno)); exit(1); } - if (fds[1] != 1 && fds[1] != 2) - close(fds[1]); + if (stdin_fds[0] > 2) close(stdin_fds[0]); + if (stdout_fds[1] > 2) close(stdout_fds[1]); + if (stderr_fds[1] > 2) close(stderr_fds[1]); - if (open("/dev/null", O_RDONLY) != 0) { - daemon_log(LOG_ERR, "open(\"/dev/null\") failed: %s", strerror(errno)); - exit(1); + if (!ifd) { + close(1); + if (open("/dev/null", O_WRONLY) != 1) { + daemon_log(LOG_ERR, "open(\"/dev/null\") failed: %s", strerror(errno)); + exit(1); + } + } + + if (!ofd) { + close(0); + if (open("/dev/null", O_RDONLY) != 0) { + daemon_log(LOG_ERR, "open(\"/dev/null\") failed: %s", strerror(errno)); + exit(1); + } } execv(file, argv); diff --git a/src/exec.h b/src/exec.h index a08b838..32285d6 100644 --- a/src/exec.h +++ b/src/exec.h @@ -1,9 +1,11 @@ #ifndef fooexechfoo #define fooexechfoo +#include + typedef void (*process_exit_cb_t) (pid_t pid, int status, void *user); -pid_t child_process_create(const char *file, char *const argv[], process_exit_cb_t cb, void *user); +pid_t child_process_create(const char *file, char *const argv[], int *ifd, int *ofd, process_exit_cb_t cb, void *user); int child_process_kill(pid_t pid); int child_process_init(void); void child_process_done(void); diff --git a/src/lock.c b/src/lock.c index 48c409f..42ad213 100644 --- a/src/lock.c +++ b/src/lock.c @@ -7,17 +7,20 @@ #include #include #include +#include #include #include "lock.h" +#include "util.h" +#include "main.h" /* Where do lockfiles reside? */ #define LOCK_PATH "/var/lock" static const char *lockfile(const char *dev) { static char lockfile[PATH_MAX]; - snprintf(lockfile, sizeof(lockfile), "%s/LCK..%s", LOCK_PATH, basename(dev)); + snprintf(lockfile, sizeof(lockfile), "%s/LCK..%s", LOCK_PATH, basename((char*) dev)); return lockfile; } @@ -30,7 +33,7 @@ static const char *tempfile(const char *path) { int device_lock(const char *dev) { struct stat st; int fd; - char *path, *temp; + const char *path, *temp; char buf[100]; if (stat(LOCK_PATH, &st) != 0 || !S_ISDIR(st.st_mode)) { @@ -57,7 +60,7 @@ int device_lock(const char *dev) { close(fd); if (n < 0) { - close(fd) + close(fd); daemon_log(LOG_ERR, "Failed to read from lock file: %s", strerror(errno)); return -1; } @@ -68,13 +71,15 @@ int device_lock(const char *dev) { if (n == 4) pid = (pid_t) *((uint32_t*) buf); else { + unsigned long v; buf[n] = 0; - sscanf(buf, "%lu", &pid); + sscanf(buf, "%lu", &v); + pid = (pid_t) v; } if (pid > 0) { if (kill(pid, 0) < 0 && errno == ESRCH) { - daemon_log(LOG_WARN, "Lockfile is stale. Overriding it."); + daemon_log(LOG_WARNING, "Lockfile is stale. Overriding it."); /* Yes, here is a race condition */ unlink(path); } else @@ -90,7 +95,7 @@ int device_lock(const char *dev) { snprintf(buf, sizeof(buf), "%10lu %s %.20s\n", (unsigned long) getpid(), appname, username); if (loop_write(fd, buf, strlen(buf)) < 0) { - daemon_log(LOG_ERR, "Failed to write to temporary lock file: %s", sterror(errno)); + daemon_log(LOG_ERR, "Failed to write to temporary lock file: %s", strerror(errno)); close(fd); return -1; } @@ -104,6 +109,7 @@ int device_lock(const char *dev) { daemon_log(LOG_ERR, "Failed to link temporary lock file: %s", strerror(errno)); } + unlink(temp); return 0; } diff --git a/src/main.c b/src/main.c index 1d0d788..f80b605 100644 --- a/src/main.c +++ b/src/main.c @@ -1,11 +1,20 @@ +#include +#include #include #include "main.h" +#include "exec.h" +#include "modemman.h" -#define CHANNELS (2) +#define CHANNELS 1 oop_source* event_source = NULL; +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; +} + int main_loop(void) { int r = -1; oop_source_sys *sys = NULL; @@ -24,6 +33,9 @@ int main_loop(void) { 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); + if (oop_sys_run(sys) == OOP_ERROR) { daemon_log(LOG_ERR, "oop_sys_new() returned OOP_ERROR"); goto finish; @@ -32,6 +44,9 @@ int main_loop(void) { r = 0; finish: + event_source->cancel_signal(event_source, SIGTERM, oop_exit_cb, NULL); + event_source->cancel_signal(event_source, SIGINT, oop_exit_cb, NULL); + modem_manager_done(); child_process_done(); @@ -44,5 +59,5 @@ finish: } int main(int argc, char*argv[]) { - return main_loop() < 0 : 1 : 0; + return main_loop() < 0 ? 1 : 0; } diff --git a/src/main.h b/src/main.h index 3aef24b..aa2f35a 100644 --- a/src/main.h +++ b/src/main.h @@ -5,4 +5,6 @@ extern oop_source* event_source; +const char *appname, *username; + #endif diff --git a/src/modem.c b/src/modem.c index 1269fbb..4cf9a49 100644 --- a/src/modem.c +++ b/src/modem.c @@ -1,9 +1,80 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + #include "modem.h" #include "lock.h" +#include "exec.h" +#include "main.h" +#include "msntab.h" +#include "dle.h" /* Baudrate for the TTY. Should be greater the 64000. */ #define BAUD_RATE B115200 +#define RESET_IDLE_TIME 2 +#define INIT_TIMEOUT 5 +#define ACCEPT_TIMEOUT 5 +#define BASIC_TIMEOUT 5 + +#define INIT_AT_COMMANDS 12 +static const char* const init_at_commands[INIT_AT_COMMANDS*2] = { + "\nAT&F\n", + "OK\r\n", + + "ATI\n", + "Linux ISDN\r\nOK\r\n", + + "AT&B16\n", + "OK\r\n", + + "AT+FCLASS=8\n", + "OK\r\n", + + "AT+VSM=6\n", + "OK\r\n", + + "ATS18=1\n", + "OK\r\n", + + "ATS14=4\n", + "OK\r\n", + + "ATS13.4=0\n", + "OK\r\n", + + "ATS13.0=1\n", + "OK\r\n", + + "ATS23=1\n", + "OK\r\n", + + "ATS0=0\n", + "OK\r\n", + + "AT&L%s\n", + "OK\r\n", +}; + +static void modem_output_empty_cb(struct buffio *b, void *user); +static void modem_input_ready_cb(struct buffio *b, void *user); +static void* oop_timeout_cb(oop_source *source, struct timeval tv, void *user); + +static void modem_init_cycle(struct modem *m); +static void modem_timeout(struct modem *m, int t); + struct modem *modem_open(const char *dev) { struct modem *m; int fd = -1, n; @@ -12,7 +83,7 @@ struct modem *modem_open(const char *dev) { assert(dev); if (device_lock(dev) != 0) - return -1; + return NULL; if ((fd = open(dev, O_RDWR|O_NDELAY)) < 0) { daemon_log(LOG_ERR, "Failed to open device <%s>: %s", dev, strerror(errno)); @@ -43,9 +114,9 @@ struct modem *modem_open(const char *dev) { goto fail; } - if (tcgetattr(fd, &ts2) < 0 || memcmp(&ts, &ts2) != 0) { + if (tcgetattr(fd, &ts2) < 0 || memcmp(&ts, &ts2, sizeof(ts)) != 0) { daemon_log(LOG_ERR, "Failed to set TTY attributes"); - goto fail; + /*goto fail;*/ /* DON'T FORGET TO REMOVE THE COMMENT MARKS */ } m = malloc(sizeof(struct modem)); @@ -53,14 +124,19 @@ struct modem *modem_open(const char *dev) { memset(m, 0, sizeof(struct modem)); m->dev = strdup(dev); assert(m->dev); - m->buffio = buffio_new(fd); + m->buffio = buffio_new(fd, fd); assert(m->buffio); + m->buffio->output_empty_cb = modem_output_empty_cb; - m->buffio->input_ready_cb = modem_output_ready_cb; + m->buffio->input_ready_cb = modem_input_ready_cb; + m->buffio->user = m; m->child_pid = -1; - modem_init(m); + m->local_msn = "46"; + m->tabentry = NULL; + + modem_init_cycle(m); return m; @@ -77,124 +153,110 @@ fail: void modem_close(struct modem *m) { assert(m); + modem_timeout(m, 0); + + if (m->tabentry) + msntab_unref(m->tabentry); + if (m->child_pid != -1) child_process_kill(m->child_pid); buffio_free(m->buffio); device_unlock(m->dev); free(m->dev); + free(m->caller_number); + free(m->ring_number); free(m); } -static void* oop_timeout_cb(oop_source *source,struct timeval tv,void *user) { - struct modem *m = (struct modem*) user; - assert(source && user); - - daemon_log(LOG_ERR, "Timeout reached for device <%s>", m->device); - return OOP_HALT; -} - static void modem_timeout(struct modem *m, int t) { - struct timeval tv = { t, 0 }; assert(m); assert(event_source && event_source->on_time); event_source->cancel_time(event_source, m->timeout, oop_timeout_cb, m); if (t > 0) { - gettimeofday(&m->timeout); - m->tv_sec += t; + gettimeofday(&m->timeout, NULL); + m->timeout.tv_sec += t; assert(event_source && event_source->on_time); event_source->on_time(event_source, m->timeout, oop_timeout_cb, m); } } -static void* oop_init_cb(oop_source *source, int fd, oop_event event, void *user) { - struct modem *m = (struct modem*) user; - assert(source && user); - assert(m && m->fd == fd && m->mode == MODEM_STATE_INIT); - - if (event == OOP_READ) { - if (modem_read(m) < 0) - return OOP_HALT; - - } else if (event == OOP_WRITE) { - modem_write(m); - } +static void modem_next_command(struct modem *m) { + const char *p; + char tmp[64]; + assert(m && m->buffio && m->state == MODEM_STATE_INIT); + assert(m->command_index < INIT_AT_COMMANDS); - return OOP_CONTINUE; + p = init_at_commands[m->command_index*2]; + + if (m->command_index == 11) { + snprintf(tmp, sizeof(tmp), p, m->local_msn); + p = tmp; + } + + buffio_command(m->buffio, p); } -static void* oop_audio_simple_cb(oop_source *source, int fd, oop_event event, void *user) { - struct modem *m = (struct modem*) user; - assert(source && user); - assert(m && m->mode == MODEM_STATE_AUDIO_SIMPLE); +static void modem_init_cycle(struct modem *m) { + assert(m); - if (event == OOP_READ) { - modem_read(m); - } else if (event == OOP_WRITE) { - modem_write(m); - } + daemon_log(LOG_INFO, "Initializing modem."); + m->state = MODEM_STATE_INIT; + m->command_index = 0; + modem_timeout(m, INIT_TIMEOUT); + modem_next_command(m); +} + +void modem_force_hangup(struct modem *m) { + struct termios pts; + assert(m && m->buffio); + + tcgetattr(m->buffio->ifd, &pts); + cfsetospeed(&pts, B0); + cfsetispeed(&pts, B0); + tcsetattr(m->buffio->ifd, TCSANOW, &pts); - return OOP_CONTINUE; + tcgetattr(m->buffio->ifd, &pts); + cfsetospeed(&pts, BAUD_RATE); + cfsetispeed(&pts, BAUD_RATE); + tcsetattr(m->buffio->ifd, TCSANOW, &pts); } -static void* oop_audio_shbuf_cb(oop_source *source, int fd, oop_event event, void *user) { + +static void* oop_timeout_cb(oop_source *source, struct timeval tv, void *user) { struct modem *m = (struct modem*) user; assert(source && user); - assert(m && m->mode == MODEM_STATE_AUDIO_SHBUF); - - if (event == OOP_READ) { - modem_read(m); - } else if (event == OOP_WRITE) { - modem_write(m); - } - return OOP_CONTINUE; -} + switch (m->state) { + case MODEM_STATE_INIT: -#define INIT_AT_COMMANDS 12 + case MODEM_STATE_CALLER_NUMBER: + case MODEM_STATE_RING_EXPECT: + case MODEM_STATE_RING: + + daemon_log(LOG_ERR, "Timeout reached for device <%s>", m->dev); + return OOP_HALT; -static const char* const init_at_commands[INIT_AT_COMMANDS*2] = { - "\nAT&F\n", - "OK\r\n", - - "ATI\n", - "Linux ISDN\r\nOK\r\n", - - "AT&B16\n", - "OK\r\n", - - "AT+FCLASS=8\n", - "OK\r\n", - - "AT+VSM=6\n", - "OK\r\n", - - "ATS18=1\n", - "OK\r\n", - - "ATS14=4\n", - "OK\r\n", - - "ATS13.4=0\n", - "OK\r\n", - - "ATS13.0=1\n", - "OK\r\n", - - "ATS23=1\n", - "OK\r\n", - - "AT&E%s\n", - "OK\r\n", - - "ATS0=0\n", - "OK\r\n" -}; + case MODEM_STATE_ANSWER: + case MODEM_STATE_VTXVRX: + daemon_log(LOG_ERR, "Connection failed for device <%s>", m->dev); + m->state = MODEM_STATE_IDLE; + modem_timeout(m, RESET_IDLE_TIME); + return OOP_CONTINUE; + case MODEM_STATE_IDLE: + + modem_init_cycle(m); + return OOP_CONTINUE; + + default: + assert(0); + } +} static void modem_input_ready_cb(struct buffio *b, void *user) { struct modem *m = user; @@ -203,18 +265,19 @@ static void modem_input_ready_cb(struct buffio *b, void *user) { switch (m->state) { case MODEM_STATE_INIT: { - char *p; + const char *p; assert(m->command_index < INIT_AT_COMMANDS); p = init_at_commands[m->command_index*2+1]; - + if (buffio_find_input(m->buffio, p)) { m->command_index++; if (m->command_index >= INIT_AT_COMMANDS) { + daemon_log(LOG_INFO, "Modem successfully initialised, waiting for calls."); m->state = MODEM_STATE_CALLER_NUMBER_EXPECT; modem_timeout(m, 0); - modem_input_init_cb(b, user); + modem_input_ready_cb(b, user); } else modem_next_command(m); } @@ -226,7 +289,8 @@ static void modem_input_ready_cb(struct buffio *b, void *user) { if (buffio_find_input(m->buffio, "CALLER NUMBER: ")) { m->state = MODEM_STATE_CALLER_NUMBER; - modem_input_init_cb(b, user); + modem_timeout(m, BASIC_TIMEOUT); + modem_input_ready_cb(b, user); } break; @@ -236,12 +300,14 @@ static void modem_input_ready_cb(struct buffio *b, void *user) { char c[64]; if (buffio_read_line(m->buffio, c, sizeof(c))) { + + c[strcspn(c, "\n\r")] = 0; free(m->caller_number); m->caller_number = strdup(c); assert(m->caller_number); m->state = MODEM_STATE_RING_EXPECT; - modem_input_init_cb(b, user); + modem_input_ready_cb(b, user); } break; @@ -251,7 +317,7 @@ static void modem_input_ready_cb(struct buffio *b, void *user) { if (buffio_find_input(m->buffio, "RING/")) { m->state = MODEM_STATE_RING; - modem_input_init_cb(b, user); + modem_input_ready_cb(b, user); } break; @@ -260,16 +326,32 @@ static void modem_input_ready_cb(struct buffio *b, void *user) { char c[64]; if (buffio_read_line(m->buffio, c, sizeof(c))) { + struct tabentry *t; + + c[strcspn(c, "\n\r")] = 0; free(m->ring_number); m->ring_number = strdup(c); assert(m->ring_number); - if (msntab_check_call(m->ring_number, m->caller_number)) { - modem_send_command(m, "ATA\n"); + modem_timeout(m, 0); + 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_ANSWER; + 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_init_cb(b, user); + modem_input_ready_cb(b, user); } } @@ -279,32 +361,65 @@ static void modem_input_ready_cb(struct buffio *b, void *user) { case MODEM_STATE_ANSWER: if (buffio_find_input(m->buffio, "VCON\r\n")) { + assert(m->tabentry); - buffio_command(m->buffio, "AT+VTX+VRX"); - m->state = MODEM_STATE_VTXVRX; + if (m->tabentry->action == CALL_ACTION_ACCEPT) { + daemon_log(LOG_INFO, "Call accepted, changing to voice mode."); + buffio_command(m->buffio, "AT+VTX+VRX"); + m->state = MODEM_STATE_VTXVRX; + } else if (m->tabentry->action == CALL_ACTION_HANGUP) { + modem_timeout(m, 0); + + daemon_log(LOG_INFO, "Call accepted for hang up."); + m->state = MODEM_STATE_ATH; + modem_input_ready_cb(b, user); + } else + assert(0); + } else if (buffio_find_input(m->buffio, "NO CARRIER\n\n")) { + daemon_log(LOG_INFO, "Failed to accept call, carrier lost"); + m->state = MODEM_STATE_IDLE; + modem_timeout(m, RESET_IDLE_TIME); } + break; case MODEM_STATE_VTXVRX: if (buffio_find_input(m->buffio, "CONNECT\r\n\r\nCONNECT\r\n")) { + modem_timeout(m, 0); + m->state = MODEM_STATE_CONNECTION; - modem_input_init_cb(b, user); + daemon_log(LOG_INFO, "Voice connection established."); + modem_input_ready_cb(b, user); + } else if (buffio_find_input(m->buffio, "NO CARRIER\n\n")) { + daemon_log(LOG_INFO, "Failed to accept call, carrier lost"); + m->state = MODEM_STATE_IDLE; + modem_timeout(m, RESET_IDLE_TIME); } - + break; case MODEM_STATE_CONNECTION: - m->state = MODEM_STATE_HANGUP; + modem_input_ready_cb(b, user); break; case MODEM_STATE_HANGUP: { + static const char hup[] = { DLE, DC4, DLE, ETX, 0 }; + buffio_command(m->buffio, hup); + + /* pass over ... */ + } - modem_send_command(m, { DLE, DC4, DLE, ETX, 0 }); + case MODEM_STATE_ATH: { + daemon_log(LOG_INFO, "Hanging up."); + buffio_command(m->buffio, "ATH\n"); m->state = MODEM_STATE_FORCE_HANGUP; break; } + + default: + break; } } @@ -317,60 +432,16 @@ static void modem_output_empty_cb(struct buffio *b, void *user) { case MODEM_STATE_FORCE_HANGUP: modem_force_hangup(m); - modem_init(m); + daemon_log(LOG_INFO, "Hang up successful, reinitializing in %i seconds.", RESET_IDLE_TIME); + m->state = MODEM_STATE_IDLE; + modem_timeout(m, RESET_IDLE_TIME); break; - } -} - -void modem_force_hangup(struct modem *m) { - struct termios pts; - assert(m && m->buffio); - tcgetattr(m->buffio->fd, &pts); - cfsetospeed(&pts, B0); - cfsetispeed(&pts, B0); - tcsetattr(m->buffio->fd, TCSANOW, &pts); - - tcgetattr(m->buffio->fd, &pts); - cfsetospeed(&pts, BAUD_RATE); - cfsetispeed(&pts, BAUD_RATE); - tcsetattr(m->buffio->fd, TCSANOW, &pts); -} - - -static void modem_send_command(struct modem *m, const char *p) { - assert(m && m->buffio); - - buffio_input_flush(m->buffio); - m->buffio->input_cb = modem_input_cb; - buffio_print(m->buffio, p); + default: + break; + } } -static void modem_next_command(struct modem *m) { - char *p; - char tmp[64]; - assert(m && m->buffio && (m->state == MODEM_STATE_INIT || m->state == MODEM_STATE_DONE)); - assert(m->command_index < INIT_AT_COMMANDS) - - p = init_at_commands[m->command_index*2]; - if (m->command_index == 10) { - snprintf(tmp, sizeof(tmp), p, m->local_msn); - p = tmp; - } - - buffio_input_flush(m->buffio); - - m->buffio->input_cb = modem_input_cb; - buffio_command(m->buffio, p); -} -static void modem_init(struct modem *m) { - assert(m); - m->state = MODEM_STATE_INIT; - m->command_index = 0; - - modem_timeout(m, 10); - modem_next_command(m); -} diff --git a/src/modem.h b/src/modem.h index 308d656..a19ff38 100644 --- a/src/modem.h +++ b/src/modem.h @@ -2,6 +2,7 @@ #define foomodemhfoo #include "buffio.h" +#include "msntab.h" enum modem_state { MODEM_STATE_INIT, @@ -13,7 +14,10 @@ enum modem_state { MODEM_STATE_VTXVRX, MODEM_STATE_CONNECTION, MODEM_STATE_CONNECTION_SHBUF, - MODEM_STATE_DONE + MODEM_STATE_HANGUP, + MODEM_STATE_ATH, + MODEM_STATE_FORCE_HANGUP, + MODEM_STATE_IDLE }; #define MODEM_BUF_LEN (10*1024) @@ -31,6 +35,12 @@ struct modem { struct timeval timeout; int dle_flag; + char *local_msn; + + char *ring_number; + char *caller_number; + + struct tabentry *tabentry; }; struct modem *modem_open(const char *dev); diff --git a/src/modemman.c b/src/modemman.c index c156e61..f7521e3 100644 --- a/src/modemman.c +++ b/src/modemman.c @@ -1,3 +1,11 @@ +#include +#include +#include +#include +#include + +#include + #include "modemman.h" #include "modem.h" @@ -12,27 +20,32 @@ struct llist { static struct llist *llist = NULL; static int n_llist = 0; +static void modem_try_open(const char *dev) { + struct modem *m; + + if ((m = modem_open(dev))) { + struct llist *l = malloc(sizeof(struct llist)); + assert(l); + + l->modem = m; + l->next = llist; + llist = l; + n_llist++; + } +} + int modem_manager_init(int channels) { int i; assert(channels <= MAX_CHANNELS && channels > 0); assert(n_llist == 0); + + modem_try_open("/dev/ttyz0"); - for (i = TTY_START; i < TTY_START+MAX_CHANNLES && n_llist < channels; i++) { + for (i = TTY_START; i < TTY_START+MAX_CHANNELS && n_llist < channels; i++) { char d[PATH_MAX]; - struct modem *m; - snprintf(d, sizeof(d), "/dev/ttyI%i", i); - - if (m = modem_open(d)) { - struct llist *l = malloc(sizeof(struct llist)); - assert(l); - - l->modem = m; - l->next = llist; - llist = l; - n_llist++; - } + modem_try_open(d); } if (n_llist < channels) { @@ -49,11 +62,11 @@ void modem_manager_done(void) { while (llist) { struct llist *l; - modem_close(l->modem); + modem_close(llist->modem); l = llist; - llist = l->next; + llist = llist->next; free(l); - n_llist = 0; + n_llist--; } assert(!n_llist && !llist); diff --git a/src/util.c b/src/util.c index 415da09..d236253 100644 --- a/src/util.c +++ b/src/util.c @@ -1,9 +1,12 @@ +#include +#include + #include "util.h" -char *basename(const char *path) { - const char *p; +char *basename(char *path) { + char *p; - if (p = strrchr(path, '/')) + if ((p = strrchr(path, '/'))) return p+1; return path; diff --git a/src/util.h b/src/util.h index 2e0b2ae..262d26c 100644 --- a/src/util.h +++ b/src/util.h @@ -1,7 +1,9 @@ #ifndef fooutilhfoo #define fooutilhfoo -char *basename(const char *path); +#include + +char *basename(char *path); ssize_t loop_read(int FILEDES, void *BUFFER, size_t SIZE); ssize_t loop_write(int FILEDES, const void *BUFFER, size_t SIZE); -- cgit