diff --git a/src/kiss.c b/src/kiss.c index c405144..c180f65 100644 --- a/src/kiss.c +++ b/src/kiss.c @@ -24,8 +24,13 @@ struct _patty_kiss_tnc { *frame; size_t bufsz, - buflen, + offset, dropped; + + ssize_t readlen, + left; + + int eof; }; patty_kiss_tnc *patty_kiss_tnc_open_fd(int fd) { @@ -41,8 +46,11 @@ patty_kiss_tnc *patty_kiss_tnc_open_fd(int fd) { tnc->fd = fd; tnc->bufsz = PATTY_KISS_BUFSZ; - tnc->buflen = 0; + tnc->offset = 0; tnc->dropped = 0; + tnc->readlen = 0; + tnc->left = 0; + tnc->eof = 0; return tnc; @@ -84,36 +92,11 @@ void patty_kiss_tnc_close(patty_kiss_tnc *tnc) { free(tnc); } -static ssize_t tnc_buffer(patty_kiss_tnc *tnc) { - ssize_t readlen; - - if (tnc->buflen == tnc->bufsz) { - goto full; - } - - if ((readlen = read(tnc->fd, tnc->buf, tnc->bufsz - tnc->buflen)) < 0) { - goto error_read; - } - - tnc->buflen += readlen; - - return readlen; - -full: - return 0; - -error_read: - return -1; -} - -static void tnc_flush(patty_kiss_tnc *tnc, size_t len) { - memmove(tnc->buf, ((uint8_t *)tnc->buf) + len, tnc->buflen - len); - - tnc->buflen -= len; -} - static void tnc_drop(patty_kiss_tnc *tnc) { - tnc->buflen = 0; + tnc->offset = 0; + tnc->readlen = 0; + tnc->left = 0; + tnc->eof = 0; tnc->dropped++; } @@ -125,17 +108,46 @@ ssize_t patty_kiss_tnc_recv(patty_kiss_tnc *tnc, void *buf, size_t len, int *port) { - size_t i = 0, - b = 0; + size_t r = 0, /* Number of bytes read */ + w = 0; /* Number of bytes written to buf */ enum kiss_flags flags = KISS_NONE; - if (tnc_buffer(tnc) < 0) { - goto error_io; + if (tnc->eof) { + return 0; } - while (i < tnc->buflen && b < len) { - uint8_t c = ((uint8_t *)tnc->buf)[i++]; + while (1) { + uint8_t c; + + r++; + + if (w == len) { + tnc_drop(tnc); + + flags &= ~KISS_FRAME; + w = 0; + } + + if (tnc->offset == 0) { + if ((tnc->readlen = read(tnc->fd, tnc->buf, tnc->bufsz)) < 0) { + goto error_io; + } else if (tnc->readlen == 0) { + if (errno) { + goto error_io; + } + + goto done; + } + + tnc->left = tnc->readlen; + } + + c = ((uint8_t *)tnc->buf)[tnc->offset++]; + + if (tnc->offset == tnc->bufsz) { + tnc->offset = 0; + } if (!(flags & KISS_FRAME)) { if (c == PATTY_KISS_FEND) { @@ -149,7 +161,7 @@ ssize_t patty_kiss_tnc_recv(patty_kiss_tnc *tnc, } } else { if (c == PATTY_KISS_FEND) { - if (b > 0) { + if (w > 0) { flags &= ~KISS_FRAME; goto done; @@ -182,12 +194,12 @@ ssize_t patty_kiss_tnc_recv(patty_kiss_tnc *tnc, } else { switch (c) { case PATTY_KISS_TFEND: - ((uint8_t *)buf)[b++] = PATTY_KISS_FEND; + ((uint8_t *)buf)[w++] = PATTY_KISS_FEND; flags &= ~KISS_ESCAPE; continue; case PATTY_KISS_TFESC: - ((uint8_t *)buf)[b++] = PATTY_KISS_FESC; + ((uint8_t *)buf)[w++] = PATTY_KISS_FESC; flags &= ~KISS_ESCAPE; continue; @@ -198,17 +210,23 @@ ssize_t patty_kiss_tnc_recv(patty_kiss_tnc *tnc, } } - ((uint8_t *)buf)[b++] = c; + ((uint8_t *)buf)[w++] = c; } done: if (flags & KISS_FRAME) { tnc_drop(tnc); - } else { - tnc_flush(tnc, i); + + return 0; } - return (ssize_t)b; + tnc->left -= r; + + if (tnc->readlen < tnc->bufsz && tnc->left == 0) { + tnc->eof = 1; + } + + return (ssize_t)w; error_io: return -1;