--- 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}
--- 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];
--- 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)
--- /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 <string.h>
+#include <stdlib.h>
+#include <assert.h>
+
+/*
+ * 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;
+}
--- /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 */
--- 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 <err.h>
#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);
--- 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);
}
--- 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
--- 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);