src/line_proto.c
branchnew-lib-errors
changeset 219 cefec18b8268
parent 218 5229a5d098b2
--- a/src/line_proto.c	Thu May 28 00:35:02 2009 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,336 +0,0 @@
-
-#include "line_proto.h"
-#include "log.h"
-
-#include <string.h>
-#include <stdlib.h>
-#include <assert.h>
-
-/*
- * Our state
- */
-struct line_proto {
-    /* The transport we read/write with */
-    transport_t *transport;
-
-    /* The incoming/outgoing line buffer */
-    char *in_buf, *out_buf;
-
-    /* Buffer size (same for both) */
-    size_t buf_len;
-
-    /* Offset of trailing data in buf */
-    size_t tail_offset;
-
-    /* Length of trailing data in buf, if any */
-    size_t tail_len;
-
-    /* Amount of data in the out buffer */
-    size_t out_offset;
-
-    /* Last error */
-    struct error_info err;
-
-    /* Callback info */
-    struct line_proto_callbacks callbacks;
-    void *cb_arg;
-};
-
-/**
- * An error occured which we could not recover from; the line_proto should now be considered corrupt.
- *
- * Notify the user callback, which will probably call line_proto_release().
- */
-static void line_proto_set_error (struct line_proto *lp)
-{
-    // copy error_info, as it might get free'd
-    struct error_info err = lp->err;
-
-    // trigger callback
-    lp->callbacks.on_error(&err, lp->cb_arg);
-}
-
-/**
- * Our transport_callbacks::on_read handler
- */
-static void line_proto_on_read (transport_t *transport, void *arg)
-{
-    struct line_proto *lp = arg;
-    char *line;
-
-    (void) transport;
-
-    // sanity-check
-    assert(lp->tail_offset < lp->buf_len);
-    
-    do {
-        // attempt to read a line
-        if (line_proto_recv(lp, &line))
-            // faaail
-            return line_proto_set_error(lp);
-
-        // got a line?
-        if (line)
-            lp->callbacks.on_line(line, lp->cb_arg);
-
-    } while (line);
-}
-
-/*
- * Signal for write
- */
-static void line_proto_on_write (transport_t *transport, void *arg)
-{
-    struct line_proto *lp = arg;
-    int ret;
-
-    (void) transport;
-
-    // just flush
-    if ((ret = line_proto_flush(lp)) < 0)
-        // faaail
-        return line_proto_set_error(lp);
-}
-
-// XXX: implement on_error!
-static const struct transport_callbacks line_proto_transport_callbacks = {
-    .on_read    = &line_proto_on_read,
-    .on_write   = &line_proto_on_write,
-};
-
-err_t line_proto_create (struct line_proto **lp_ptr, transport_t *transport, size_t buf_size,
-        const struct line_proto_callbacks *callbacks, void *cb_arg, error_t *err)
-{
-    struct line_proto *lp;
-
-    // alloc
-    if ((lp = calloc(1, sizeof(*lp))) == NULL)
-        return SET_ERROR(err, ERR_CALLOC);
-
-    // store
-    lp->transport = transport;
-    lp->buf_len = buf_size;
-    lp->callbacks = *callbacks;
-    lp->cb_arg = cb_arg;
-
-    // allocate buffers
-    if (
-            (lp->in_buf = malloc(buf_size)) == NULL
-        ||  (lp->out_buf = malloc(buf_size)) == NULL
-    )
-        JUMP_SET_ERROR(err, ERR_CALLOC);
-
-    // setup the transport
-    transport_set_callbacks(transport, &line_proto_transport_callbacks, lp);
-    
-    if ((ERROR_CODE(err) = transport_events(transport, TRANSPORT_READ | TRANSPORT_WRITE)))
-        goto error;
-
-    // return
-    *lp_ptr = lp;
-
-    return SUCCESS;
-
-error:
-    // cleanup the lp
-    line_proto_destroy(lp);
-
-    return ERROR_CODE(err);
-}
-
-/*
- * This looks for a full '\r\n' terminated line at the beginning of the given buffer. If found, the \r\n will be
- * replaced with a '\0', and the offset to the beginning of the next line returned. If not found, zero is returned
- * (which is never a valid next-line offset).
- *
- * The given \a hint is an hint as to the offset at which to start scanning, used for incremental invocations of this
- * on the same buffer.
- *
- */
-int _parse_line (char *buf, size_t len, size_t *hint) {
-    size_t i, next = 0;
-
-    // empty buffer -> nothing
-    if (len == 0)
-        return 0;
-
-    // look for terminating '\r\n' or '\n' sequence
-    for (i = *hint; i < len; i++) {
-        // match this + next char?
-        if (i < len - 1 && buf[i] == '\r' && buf[i + 1] == '\n') {
-            next = i + 2;
-            break;
-
-        } else if (buf[i] == '\n') {
-            next = i + 1;
-            break;
-        }
-    }
-
-    // searched the whole buffer?
-    if (i >= len) {
-        // do continue one char back, to keep any \r
-        *hint = len - 1;
-        return 0;
-    }
-
-    // mangle the newline off
-    buf[i] = '\0';
-
-    // return offset to next line, as set in loop based on delim
-    return next;
-}
-
-err_t line_proto_recv (struct line_proto *lp, char **line_ptr)
-{
-    // offset to recv() new data into, offset to _parse_line hint, offset to next line from _parse_line
-    size_t recv_offset = 0, peek_offset = 0, next_offset = 0;
-    int ret;
-
-    // adjust offset to beyond previous data (as will be moved next)
-    recv_offset = lp->tail_len;
-
-    // move trailing data from previous line to front of buffer
-    if (lp->tail_offset) {
-        // move to front, no-op if tail_len is zero
-        memmove(lp->in_buf, lp->in_buf + lp->tail_offset, lp->tail_len);
-
-        // reset
-        lp->tail_offset = 0;
-        lp->tail_len = 0;
-    }
-
-    // readline loop
-    do {
-        // parse any line at the beginning of the buffer
-        if ((next_offset = _parse_line(lp->in_buf, recv_offset, &peek_offset)) > 0) {
-            // store a valid *line_ptr
-            *line_ptr = lp->in_buf;
-            
-            // exit loop and return
-            break;
-        }
-
-        // ensure there's enough space for the rest of the line
-        if (recv_offset >= lp->buf_len)
-            return ERR_LINE_TOO_LONG;
-        
-        // otherwise, read more data
-        if ((ret = transport_read(lp->transport, lp->in_buf + recv_offset, lp->buf_len - recv_offset, &lp->err)) < 0)
-            return ERROR_CODE(&lp->err);
-
-        // EAGAIN?
-        if (ret == 0) {
-            // return a NULL *line_ptr
-            *line_ptr = NULL;
-            break;
-        }
-        
-        // update recv_offset
-        recv_offset += ret;
-
-    } while (1);
-
-    // update state for next call
-    lp->tail_offset = next_offset;
-    lp->tail_len = recv_offset - next_offset;
-
-    // ok
-    return SUCCESS;
-}
-
-int line_proto_send (struct line_proto *lp, const char *line)
-{
-    int ret;
-    size_t len = strlen(line), ret_len;
-
-    // drop line if we already have output buffered
-    if (lp->out_offset)
-        return -ERR_LINE_TOO_LONG;
-    
-    // try and write the line
-    if ((ret = transport_write(lp->transport, line, len, &lp->err)) < 0)
-        return -ERROR_CODE(&lp->err);
-
-    // length of the sent data
-    ret_len = ret;
-
-    // EAGAIN or partial?
-    if (ret_len < len) {
-        size_t trailing = len - ret_len;
-
-        // ensure it's not waaaay too long
-        if (trailing > lp->buf_len)
-            return -ERR_LINE_TOO_LONG;
-
-        // copy remaining portion to buffer
-        memcpy(lp->out_buf, line + ret_len, trailing);
-
-        // update offset
-        lp->out_offset = trailing;
-        
-        // buffered... transport should invoke on_write itself
-        return 1;
-
-    } else {
-        // ok, no buffering needed
-        return SUCCESS;
-
-    }
-}
-
-int line_proto_flush (struct line_proto *lp)
-{
-    int ret;
-    size_t ret_len;
-
-    assert(lp->out_offset);
-
-    // try and write the line
-    if ((ret = transport_write(lp->transport, lp->out_buf, lp->out_offset, &lp->err)) < 0)
-        return -ERROR_CODE(&lp->err);
-
-    ret_len = ret;
-
-    // empty now?
-    if (ret_len == lp->out_offset) {
-        lp->out_offset = 0;
-
-        return SUCCESS;
-    }
-
-    // partial?
-    if (ret_len > 0) {
-        size_t remaining = lp->out_offset - ret_len;
-
-        // move the rest up
-        memmove(lp->out_buf, lp->out_buf + ret_len, remaining);
-
-        // update offset
-        lp->out_offset = remaining;
-    }
-
-    // ok
-    return 1;
-}
-
-const struct error_info* line_proto_error (struct line_proto *lp)
-{
-    // return pointer
-    return &lp->err;
-}
-
-void line_proto_destroy (struct line_proto *lp)
-{
-    // free buffers
-    free(lp->in_buf);
-    free(lp->out_buf);
-
-    // socket?
-    if (lp->transport)
-        transport_destroy(lp->transport);
-
-    // free the state itself
-    free(lp);
-}
-