diff --git a/include/patty/ax25/if.h b/include/patty/ax25/if.h index 5c82a20..8497bbf 100644 --- a/include/patty/ax25/if.h +++ b/include/patty/ax25/if.h @@ -35,7 +35,13 @@ typedef int (patty_ax25_if_driver_fd)(void *); typedef int (patty_ax25_if_driver_pending)(void *); -typedef ssize_t (patty_ax25_if_driver_recv)(void *, void *, size_t); +typedef ssize_t (patty_ax25_if_driver_fill)(void *); + +typedef ssize_t (patty_ax25_if_driver_drain)(void *, void *, size_t); + +typedef int (patty_ax25_if_driver_ready)(void *); + +typedef ssize_t (patty_ax25_if_driver_flush)(void *); typedef ssize_t (patty_ax25_if_driver_send)(void *, const void *, size_t); @@ -44,7 +50,10 @@ typedef struct _patty_ax25_if_driver { patty_ax25_if_driver_destroy *destroy; patty_ax25_if_driver_fd *fd; patty_ax25_if_driver_pending *pending; - patty_ax25_if_driver_recv *recv; + patty_ax25_if_driver_fill *fill; + patty_ax25_if_driver_drain *drain; + patty_ax25_if_driver_ready *ready; + patty_ax25_if_driver_flush *flush; patty_ax25_if_driver_send *send; } patty_ax25_if_driver; @@ -100,10 +109,15 @@ int patty_ax25_if_promisc_delete(patty_ax25_if *iface, int patty_ax25_if_fd(patty_ax25_if *iface); -ssize_t patty_ax25_if_pending(patty_ax25_if *iface); +int patty_ax25_if_pending(patty_ax25_if *iface); -ssize_t patty_ax25_if_recv(patty_ax25_if *iface, - void **buf); +ssize_t patty_ax25_if_fill(patty_ax25_if *iface); + +ssize_t patty_ax25_if_drain(patty_ax25_if *iface, void *buf, size_t len); + +int patty_ax25_if_ready(patty_ax25_if *iface); + +ssize_t patty_ax25_if_flush(patty_ax25_if *iface); ssize_t patty_ax25_if_send(patty_ax25_if *iface, const void *buf, diff --git a/include/patty/kiss/tnc.h b/include/patty/kiss/tnc.h index 6296da5..5c4c715 100644 --- a/include/patty/kiss/tnc.h +++ b/include/patty/kiss/tnc.h @@ -39,11 +39,17 @@ void patty_kiss_tnc_destroy(patty_kiss_tnc *tnc); size_t patty_kiss_tnc_dropped(patty_kiss_tnc *tnc); -ssize_t patty_kiss_tnc_pending(patty_kiss_tnc *tnc); +int patty_kiss_tnc_pending(patty_kiss_tnc *tnc); -ssize_t patty_kiss_tnc_recv(patty_kiss_tnc *tnc, - void *buf, - size_t len); +ssize_t patty_kiss_tnc_fill(patty_kiss_tnc *tnc); + +ssize_t patty_kiss_tnc_drain(patty_kiss_tnc *tnc, void *buf, size_t len); + +int patty_kiss_tnc_ready(patty_kiss_tnc *tnc); + +ssize_t patty_kiss_tnc_flush(patty_kiss_tnc *tnc); + +ssize_t patty_kiss_tnc_recv(patty_kiss_tnc *tnc, void *buf, size_t len); ssize_t patty_kiss_tnc_send(patty_kiss_tnc *tnc, const void *buf, diff --git a/src/if.c b/src/if.c index ff36df0..75ed7c0 100644 --- a/src/if.c +++ b/src/if.c @@ -275,43 +275,45 @@ int patty_ax25_if_fd(patty_ax25_if *iface) { return iface->driver->fd(iface->phy); } -ssize_t patty_ax25_if_pending(patty_ax25_if *iface) { +int patty_ax25_if_pending(patty_ax25_if *iface) { return iface->driver->pending(iface->phy); } -ssize_t patty_ax25_if_recv(patty_ax25_if *iface, - void **buf) { - ssize_t readlen; - struct promisc_frame frame; +ssize_t patty_ax25_if_fill(patty_ax25_if *iface) { + return iface->driver->fill(iface->phy); +} - if ((readlen = iface->driver->recv(iface->phy, - iface->rx_buf, - iface->mru)) < 0) { - goto error_driver_recv; - } else if (readlen == 0) { - goto done; +ssize_t patty_ax25_if_drain(patty_ax25_if *iface, void *buf, size_t len) { + return iface->driver->drain(iface->phy, buf, len); +} + +int patty_ax25_if_ready(patty_ax25_if *iface) { + return iface->driver->ready(iface->phy); +} + +ssize_t patty_ax25_if_flush(patty_ax25_if *iface) { + ssize_t len = iface->driver->flush(iface->phy); + + if (len > 0) { + struct promisc_frame frame = { + .buf = iface->rx_buf, + .len = len, + .iface = iface + }; + + iface->stats.rx_frames++; + iface->stats.rx_bytes += len; + + if (patty_dict_each(iface->promisc_fds, + handle_promisc_frame, + &frame) < 0) { + goto error_handle_promisc_frame; + } } - *buf = iface->rx_buf; - - iface->stats.rx_frames++; - iface->stats.rx_bytes += readlen; - - frame.buf = iface->rx_buf; - frame.len = readlen; - frame.iface = iface; - - if (patty_dict_each(iface->promisc_fds, - handle_promisc_frame, - &frame) < 0) { - goto error_handle_promisc_frame; - } - -done: - return readlen; + return len; error_handle_promisc_frame: -error_driver_recv: return -1; } diff --git a/src/server.c b/src/server.c index 3ddd9a5..e54039f 100644 --- a/src/server.c +++ b/src/server.c @@ -2007,33 +2007,46 @@ error_decode: static int handle_iface(patty_ax25_server *server, patty_ax25_if *iface) { int fd = patty_ax25_if_fd(iface); + ssize_t len; if (!FD_ISSET(fd, &server->fds_r)) { goto done; } - do { - void *buf; - ssize_t readlen; + if ((len = patty_ax25_if_fill(iface)) < 0) { + goto error_io; + } else if (len == 0) { + close(fd); - if ((readlen = patty_ax25_if_recv(iface, &buf)) < 0) { - goto error_io; - } else if (readlen == 0) { - close(fd); + fd_clear(server, fd); - fd_clear(server, fd); + goto done; + } - goto done; - } + while (1) { + ssize_t len; - if (handle_frame(server, iface, buf, readlen) < 0) { + if ((len = patty_ax25_if_drain(iface, iface->rx_buf, iface->mru)) < 0) { goto error_io; } - } while (patty_ax25_if_pending(iface)); + + if (!patty_ax25_if_ready(iface)) { + break; + } + + if ((len = patty_ax25_if_flush(iface)) < 0) { + goto error_io; + } + + if (handle_frame(server, iface, iface->rx_buf, len) < 0) { + goto error_handle_frame; + } + } done: return 0; +error_handle_frame: error_io: return -1; } diff --git a/src/tnc.c b/src/tnc.c index 3ca4349..a121602 100644 --- a/src/tnc.c +++ b/src/tnc.c @@ -16,18 +16,18 @@ #include "config.h" -enum state_flags { - STATE_NONE = 0, - STATE_FRAME = 1 << 0, - STATE_COMMAND = 1 << 1, - STATE_ESCAPE = 1 << 2 -}; - enum tnc_opts { TNC_NONE = 0, TNC_CLOSE_ON_DESTROY = 1 << 0 }; +enum state { + KISS_NONE, + KISS_FRAME, + KISS_FRAME_BODY, + KISS_FRAME_ESCAPE +}; + struct _patty_kiss_tnc { struct termios attrs, attrs_old; @@ -35,14 +35,15 @@ struct _patty_kiss_tnc { int fd, opts; - void *buf, - *frame; + void *buf; + + enum state state; size_t bufsz, - offset, + readlen, + offset_i, + offset_o, dropped; - - ssize_t readlen; }; patty_kiss_tnc *patty_kiss_tnc_new(patty_kiss_tnc_info *info) { @@ -143,11 +144,13 @@ patty_kiss_tnc *patty_kiss_tnc_new(patty_kiss_tnc_info *info) { errno = 0; } - tnc->opts = TNC_NONE; - tnc->bufsz = PATTY_KISS_TNC_BUFSZ; - tnc->offset = 0; - tnc->dropped = 0; - tnc->readlen = -1; + tnc->opts = TNC_NONE; + tnc->state = KISS_NONE; + tnc->bufsz = PATTY_KISS_TNC_BUFSZ; + tnc->offset_i = 0; + tnc->offset_o = 0; + tnc->dropped = 0; + tnc->readlen = 0; return tnc; @@ -191,8 +194,10 @@ int patty_kiss_tnc_fd(patty_kiss_tnc *tnc) { } static void tnc_drop(patty_kiss_tnc *tnc) { - tnc->offset = 0; - tnc->readlen = -1; + tnc->state = KISS_NONE; + tnc->offset_i = 0; + tnc->offset_o = 0; + tnc->readlen = 0; tnc->dropped++; } @@ -200,132 +205,132 @@ size_t patty_kiss_tnc_dropped(patty_kiss_tnc *tnc) { return tnc->dropped; } -ssize_t patty_kiss_tnc_pending(patty_kiss_tnc *tnc) { - if (tnc->readlen < 0) { - return -1; - } - - if (tnc->offset == 0) { - return 0; - } - - return tnc->readlen - tnc->offset; +int patty_kiss_tnc_pending(patty_kiss_tnc *tnc) { + return tnc->offset_i < tnc->readlen? 1: 0; } -ssize_t patty_kiss_tnc_recv(patty_kiss_tnc *tnc, - void *buf, - size_t len) { - size_t o = 0; /* Number of bytes written to buf */ - - int flags = STATE_NONE; - - if (tnc->offset == tnc->readlen) { - errno = 0; - - return 0; +ssize_t patty_kiss_tnc_fill(patty_kiss_tnc *tnc) { + if ((tnc->readlen = read(tnc->fd, tnc->buf, tnc->bufsz)) < 0) { + goto error_read; } - while (1) { + tnc->offset_i = 0; + + return tnc->readlen; + +error_read: + return -1; +} + +ssize_t patty_kiss_tnc_drain(patty_kiss_tnc *tnc, void *buf, size_t len) { + size_t offset_start = tnc->offset_i; + + while (tnc->offset_i < tnc->readlen) { uint8_t c; - if (o == len) { + if (tnc->offset_o == len) { tnc_drop(tnc); - - flags &= ~STATE_FRAME; - o = 0; } - if (tnc->offset == 0) { - if ((tnc->readlen = read(tnc->fd, tnc->buf, tnc->bufsz)) < 0) { - goto error_io; - } else if (tnc->readlen == 0) { - goto done; - } - } + c = ((uint8_t *)tnc->buf)[tnc->offset_i++]; - c = ((uint8_t *)tnc->buf)[tnc->offset++]; - - if (tnc->offset == tnc->readlen) { - tnc->offset = 0; - } - - if (!(flags & STATE_FRAME)) { - if (c == PATTY_KISS_FEND) { - flags = STATE_FRAME; - - continue; - } else { - errno = EIO; - - goto error_io; - } - } else { - if (c == PATTY_KISS_FEND) { - flags = STATE_NONE; - - if (o > 0) { - goto done; + switch (tnc->state) { + case KISS_NONE: + if (c == PATTY_KISS_FEND) { + tnc->state = KISS_FRAME; } - continue; - } - } + break; - if (!(flags & STATE_COMMAND)) { - if (PATTY_KISS_COMMAND(c) != PATTY_KISS_DATA) { - errno = EIO; - - goto error_io; - } - - flags |= STATE_COMMAND; - - continue; - } - - if (!(flags & STATE_ESCAPE)) { - if (c == PATTY_KISS_FESC) { - flags |= STATE_ESCAPE; - - continue; - } - } else { - switch (c) { - case PATTY_KISS_TFEND: - ((uint8_t *)buf)[o++] = PATTY_KISS_FEND; - flags &= ~STATE_ESCAPE; - continue; - - case PATTY_KISS_TFESC: - ((uint8_t *)buf)[o++] = PATTY_KISS_FESC; - flags &= ~STATE_ESCAPE; - continue; - - default: + case KISS_FRAME: + if (c == PATTY_KISS_FEND) { + break; + } else if (PATTY_KISS_COMMAND(c) != PATTY_KISS_DATA) { errno = EIO; goto error_io; - } - } + } - ((uint8_t *)buf)[o++] = c; + tnc->state = KISS_FRAME_BODY; + + break; + + case KISS_FRAME_BODY: + if (c == PATTY_KISS_FESC) { + tnc->state = KISS_FRAME_ESCAPE; + } else if (c == PATTY_KISS_FEND) { + tnc->state = KISS_FRAME; + + goto done; + } else { + ((uint8_t *)buf)[tnc->offset_o++] = c; + } + + break; + + case KISS_FRAME_ESCAPE: + if (c == PATTY_KISS_TFEND) { + ((uint8_t *)buf)[tnc->offset_o++] = PATTY_KISS_FEND; + } else if (c == PATTY_KISS_TFESC) { + ((uint8_t *)buf)[tnc->offset_o++] = PATTY_KISS_FESC; + } else { + errno = EIO; + + goto error_io; + } + + tnc->state = KISS_FRAME_BODY; + } } done: - if (flags & STATE_FRAME) { - tnc_drop(tnc); - - errno = 0; - - return 0; - } - - return (ssize_t)o; + return tnc->offset_i - offset_start; error_io: return -1; } +int patty_kiss_tnc_ready(patty_kiss_tnc *tnc) { + return tnc->state == KISS_FRAME && tnc->offset_o > 0? 1: 0; +} + +ssize_t patty_kiss_tnc_flush(patty_kiss_tnc *tnc) { + if (patty_kiss_tnc_ready(tnc)) { + ssize_t ret = (ssize_t)tnc->offset_o; + + tnc->state = KISS_NONE; + tnc->offset_o = 0; + + return ret; + } + + return 0; +} + +ssize_t patty_kiss_tnc_recv(patty_kiss_tnc *tnc, void *buf, size_t len) { + while (!patty_kiss_tnc_ready(tnc)) { + ssize_t drained; + + if ((drained = patty_kiss_tnc_drain(tnc, buf, len)) < 0) { + goto error_drain; + } else if (drained == 0) { + ssize_t filled; + + if ((filled = patty_kiss_tnc_fill(tnc)) < 0) { + goto error_fill; + } else if (filled == 0) { + return 0; + } + } + } + + return patty_kiss_tnc_flush(tnc); + +error_drain: +error_fill: + return -1; +} + ssize_t patty_kiss_tnc_send(patty_kiss_tnc *tnc, const void *buf, size_t len) { @@ -338,7 +343,10 @@ patty_ax25_if_driver *patty_kiss_tnc_driver() { .destroy = (patty_ax25_if_driver_destroy *)patty_kiss_tnc_destroy, .fd = (patty_ax25_if_driver_fd *)patty_kiss_tnc_fd, .pending = (patty_ax25_if_driver_pending *)patty_kiss_tnc_pending, - .recv = (patty_ax25_if_driver_recv *)patty_kiss_tnc_recv, + .fill = (patty_ax25_if_driver_fill *)patty_kiss_tnc_fill, + .drain = (patty_ax25_if_driver_drain *)patty_kiss_tnc_drain, + .ready = (patty_ax25_if_driver_ready *)patty_kiss_tnc_ready, + .flush = (patty_ax25_if_driver_flush *)patty_kiss_tnc_flush, .send = (patty_ax25_if_driver_send *)patty_kiss_tnc_send };