# HG changeset patch # User Tero Marttila # Date 1235283682 -7200 # Node ID be88e543c8ff9f23cb54820eacffb004b6421cfa # Parent 844f014409ff01983bdef256bb9b755ada1ba419 split off line_proto, and make sock_stream_error return a const error_info diff -r 844f014409ff -r be88e543c8ff Makefile --- a/Makefile Sun Feb 22 07:53:34 2009 +0200 +++ b/Makefile Sun Feb 22 08:21:22 2009 +0200 @@ -33,6 +33,7 @@ CORE_OBJS = obj/error.o SOCK_OBJS = obj/sock.o obj/sock_tcp.o SOCK_GNUTLS_OBJS = obj/sock_gnutls.o +LINEPROTO_OBJS = obj/line_proto.o # XXX: not yet there #CORE_OBJS = obj/lib/log.o obj/lib/signals.o @@ -41,7 +42,7 @@ all: ${BIN_PATHS} # binaries -bin/nexus: ${CORE_OBJS} ${SOCK_OBJS} ${SOCK_GNUTLS_OBJS} +bin/nexus: ${CORE_OBJS} ${SOCK_OBJS} ${SOCK_GNUTLS_OBJS} ${LINEPROTO_OBJS} # computed CFLAGS = ${MODE_CFLAGS} ${FIXED_CFLAGS} ${LIBEVENT_CFLAGS} ${GNUTLS_CFLAGS} diff -r 844f014409ff -r be88e543c8ff src/error.c --- a/src/error.c Sun Feb 22 07:53:34 2009 +0200 +++ b/src/error.c Sun Feb 22 08:21:22 2009 +0200 @@ -17,10 +17,11 @@ switch (code) { ERROR_NAME( ERR_CALLOC, "calloc" ); ERROR_NAME( ERR_GETADDRINFO, "getaddrinfo" ); - ERROR_NAME( ERR_GETADDRINFO_EMPTY, "getaddrinfo" ); + ERROR_NAME( ERR_GETADDRINFO_EMPTY, "getaddrinfo: no results" ); ERROR_NAME( ERR_SOCKET, "socket" ); ERROR_NAME( ERR_CONNECT, "connect" ); ERROR_NAME( ERR_READ, "read" ); + ERROR_NAME( ERR_READ_EOF, "read: EOF" ); ERROR_NAME( ERR_WRITE, "write" ); ERROR_NAME( ERR_GNUTLS_CERT_ALLOC_CRED, "gnutls_certificate_allocate_credentials" ); ERROR_NAME( ERR_GNUTLS_GLOBAL_INIT, "gnutls_global_init" ); @@ -32,7 +33,7 @@ } } -const char *error_msg (struct error_info *err) +const char *error_msg (const struct error_info *err) { static char msg[ERROR_MSG_MAXLEN]; diff -r 844f014409ff -r be88e543c8ff src/error.h --- a/src/error.h Sun Feb 22 07:53:34 2009 +0200 +++ b/src/error.h Sun Feb 22 08:21:22 2009 +0200 @@ -48,7 +48,8 @@ /* Low-level IO errors */ _ERROR_CODE( ERR_READ, 0x000401, ERRNO ), - _ERROR_CODE( ERR_WRITE, 0x000402, ERRNO ), + _ERROR_CODE( ERR_READ_EOF, 0x000402, NONE ), + _ERROR_CODE( ERR_WRITE, 0x000403, ERRNO ), /* GnuTLS errors */ _ERROR_CODE( ERR_GNUTLS_CERT_ALLOC_CRED, 0x010101, GNUTLS ), @@ -88,7 +89,7 @@ * * This is returned as a pointer into a statically allocated buffer. It is not re-entrant. */ -const char *error_msg (struct error_info *err); +const char *error_msg (const struct error_info *err); /** No error, evaulates as logical false */ #define SUCCESS (0) @@ -123,6 +124,7 @@ #define RETURN_SET_ERROR(err_info_ptr, err_code) do { SET_ERROR(err_info_ptr, err_code); return (err_code); } while (0) #define RETURN_SET_ERROR_EXTRA(err_info_ptr, err_code, err_extra) do { _SET_ERROR_EXTRA(err_info_ptr, err_code, err_extra); return (err_code); } while (0) #define RETURN_SET_ERROR_ERRNO(err_info_ptr, err_code) do { _SET_ERROR_ERRNO(err_info_ptr, err_code); return (err_code); } while (0) +#define RETURN_SET_ERROR_INFO(err_info_ptr, from_ptr) do { SET_ERROR_INFO(err_info_ptr, from_ptr); return (from_ptr->code); } while (0) /* Same as above, but also do a 'goto error' */ #define JUMP_SET_ERROR(err_info_ptr, err_code) do { SET_ERROR(err_info_ptr, err_code); goto error; } while (0) diff -r 844f014409ff -r be88e543c8ff src/line_proto.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/line_proto.c Sun Feb 22 08:21:22 2009 +0200 @@ -0,0 +1,131 @@ + +#include "line_proto.h" + +#include +#include +#include + +/* + * Our state + */ +struct line_proto { + /* The sock_stream we read/write with */ + struct sock_stream *sock; + + /* Offset of trailing data in buf */ + size_t tail_offset; + + /* Length of trailing data in buf, if any */ + size_t tail_len; + + /* Last error */ + struct error_info err; +}; + +err_t line_proto_create (struct line_proto **lp_ptr, struct sock_stream *sock, struct error_info *err) +{ + struct line_proto *lp; + + // allocate + if ((lp = calloc(1, sizeof(*lp))) == NULL) + return SET_ERROR(err, ERR_CALLOC); + + // store + lp->sock = sock; + + // return + *lp_ptr = lp; + + return SUCCESS; +} + +/* + * 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) { + int i; + + // empty buffer -> nothing + if (len == 0) + return 0; + + // look for terminating '\r\n' sequence + for (i = *hint; i < len - 1; i++) { + // match this + next char + if (buf[i] == '\r' && buf[i + 1] == '\n') + break; + } + + // incomplete? + if (i >= len - 1) { + *hint = len - 1; + return 0; + } + + // mangle the newline off + buf[i] = '\0'; + + // return offset to next line + return i + 2; +} + +err_t line_proto_read (struct line_proto *lp, char *buf, size_t len) +{ + // 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 from previous data + recv_offset = lp->tail_len; + + // move trailing data from previous line to front of buffer + if (lp->tail_offset) { + // move to front + memmove(buf, 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(buf, recv_offset, &peek_offset)) > 0) + break; + + // ensure there's enough space for it + assert(recv_offset < len); + + // otherwise, read more data + if ((ret = sock_stream_read(lp->sock, buf + recv_offset, len - recv_offset)) < 0) + RETURN_SET_ERROR_INFO(&lp->err, sock_stream_error(lp->sock)); + + // EOF? + if (ret == 0) + return SET_ERROR(&lp->err, ERR_READ_EOF); + + // 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; +} + +const struct error_info* line_proto_error (struct line_proto *lp) +{ + // return pointer + return &lp->err; +} diff -r 844f014409ff -r be88e543c8ff src/line_proto.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/line_proto.h Sun Feb 22 08:21:22 2009 +0200 @@ -0,0 +1,33 @@ +#ifndef LINE_PROTO_H +#define LINE_PROTO_H + +/* + * Support for protocols that send/receive lines + */ +#include "sock.h" +#include "error.h" + +/* + * The state handle + */ +struct line_proto; + +/* + * Create a new line_proto off the the given sock_stream. The newly allocated line_proto will be returned via *lp_ptr. + */ +err_t line_proto_create (struct line_proto **lp_ptr, struct sock_stream *sock, struct error_info *err); + +/* + * Receive one line into the given buffer. The line will be terminated with '\r\n', and said terminator will be + * NUL'd out, so the buffer is safe for use as a C-string after succesfull return. + * + * Note: currently this uses the buffer to store intermediate state, so always pass the same buffer (for now). + */ +err_t line_proto_read (struct line_proto *lp, char *buf, size_t len); + +/* + * Get current error_info* + */ +const struct error_info* line_proto_error (struct line_proto *lp); + +#endif /* LINE_PROTO_H */ diff -r 844f014409ff -r be88e543c8ff src/nexus.c --- a/src/nexus.c Sun Feb 22 07:53:34 2009 +0200 +++ b/src/nexus.c Sun Feb 22 08:21:22 2009 +0200 @@ -9,121 +9,35 @@ #include #include "sock.h" +#include "line_proto.h" #define CONNECT_HOST "irc.fixme.fi" -#define CONNECT_SERV "66976" +#define CONNECT_SERV "6697" #define LINE_LENGTH 512 -struct recvline_state { - size_t tail_offset; - size_t tail_len; -}; - -/* - * 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) { - int i; - - // empty buffer -> nothing - if (len == 0) - return 0; - - // look for terminating '\r\n' sequence - for (i = *hint; i < len - 1; i++) { - // match this + next char - if (buf[i] == '\r' && buf[i + 1] == '\n') - break; - } - - // incomplete? - if (i >= len - 1) { - *hint = len - 1; - return 0; - } - - // mangle the newline off - buf[i] = '\0'; - - // return offset to next line - return i + 2; -} - -/* - * Receive one line of data into the buffer of the given length - */ -int recvline (struct sock_stream *sock, char *buf, size_t len, struct recvline_state *ctx) { - size_t recv_offset = 0, peek_offset = 0, next_offset = 0; - int ret; - - // adjust offset from previous data - recv_offset = ctx->tail_len; - - // move trailing data from previous line to front of buffer - if (ctx->tail_offset) { - // move to front - memmove(buf, buf + ctx->tail_offset, ctx->tail_len); - - // reset - ctx->tail_offset = 0; - ctx->tail_len = 0; - } - - // readline loop - do { - // parse any line at the beginning of the buffer - if ((next_offset = _parse_line(buf, recv_offset, &peek_offset)) > 0) - break; - - // ensure there's enough space for it - assert(recv_offset < len); - - // otherwise, read more data - if ((ret = sock_stream_read(sock, buf + recv_offset, len - recv_offset)) < 0) - err(1, "read"); - - // EOF? - if (ret == 0) - errx(1, "read: EOF"); - - // update recv_offset - recv_offset += ret; - } while (1); - - // update state for next call - ctx->tail_offset = next_offset; - ctx->tail_len = recv_offset - next_offset; - - // ok - return 0; -} - int main (int argc, char **argv) { struct sock_stream *sock; + struct line_proto *lp; char line_buf[LINE_LENGTH + 1]; - struct recvline_state recvline_ctx; struct error_info err; // initialize if (sock_init(&err)) errx(1, "sock_init: %s", error_msg(&err)); - memset(&recvline_ctx, 0, sizeof(recvline_ctx)); - // over-simplified connect if (sock_gnutls_connect(&sock, CONNECT_HOST, CONNECT_SERV, &err)) errx(1, "sock_gnutls_connect: %s", error_msg(&err)); + // line protocol + if (line_proto_create(&lp, sock, &err)) + errx(1, "line_proto_create: %s", error_msg(&err)); + // read lines and dump them out do { // recv - recvline(sock, line_buf, sizeof(line_buf), &recvline_ctx); + if (line_proto_read(lp, line_buf, sizeof(line_buf))) + errx(1, "line_proto_read: %s", error_msg(line_proto_error(lp))); // printf printf("<<< %s\n", line_buf); diff -r 844f014409ff -r be88e543c8ff src/sock.c --- a/src/sock.c Sun Feb 22 07:53:34 2009 +0200 +++ b/src/sock.c Sun Feb 22 08:21:22 2009 +0200 @@ -35,8 +35,8 @@ return sock->type->methods.write(sock, buf, len); } -void sock_stream_error (struct sock_stream *sock, struct error_info *err) +const struct error_info* sock_stream_error (struct sock_stream *sock) { - // copy from SOCK_ER - *err = *SOCK_ERR(sock); + // return pointer + return SOCK_ERR(sock); } diff -r 844f014409ff -r be88e543c8ff src/sock.h --- a/src/sock.h Sun Feb 22 07:53:34 2009 +0200 +++ b/src/sock.h Sun Feb 22 08:21:22 2009 +0200 @@ -43,8 +43,8 @@ err_t sock_stream_write (struct sock_stream *sock, const void *buf, size_t len); /** - * Get last err_info for \a sock, returned via \a *err. + * Get current error_info for \a sock. */ -void sock_stream_error (struct sock_stream *sock, struct error_info *err); +const struct error_info* sock_stream_error (struct sock_stream *sock); #endif diff -r 844f014409ff -r be88e543c8ff src/sock_tcp.c --- a/src/sock_tcp.c Sun Feb 22 07:53:34 2009 +0200 +++ b/src/sock_tcp.c Sun Feb 22 08:21:22 2009 +0200 @@ -148,8 +148,8 @@ // connect if ((err = sock_tcp_init_connect(sock, host, service))) { - // set *err_info - sock_stream_error(SOCK_TCP_BASE(sock), err_info); + // copy error_info + SET_ERROR_INFO(err_info, sock_stream_error(SOCK_TCP_BASE(sock))); // cleanup sock_tcp_release(sock);