src/nexus.c
changeset 0 317e5bc59627
child 1 cf0e1bb6bcab
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/nexus.c	Sun Feb 22 02:00:34 2009 +0200
@@ -0,0 +1,168 @@
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <event.h>
+#include <assert.h>
+
+#include <err.h>
+
+#define CONNECT_HOST "irc.fixme.fi"
+#define CONNECT_SERV "6667"
+#define LINE_LENGTH 512
+
+/*
+ * Simple getaddrinfo() connect
+ */
+int sock_connect (const char *host, const char *service) {
+    struct addrinfo hints, *res, *r;
+    int _err, sock = -1;
+    
+    // hints
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_family = AF_UNSPEC;
+    hints.ai_socktype = SOCK_STREAM;
+
+    // resolve
+    if ((_err = getaddrinfo(host, service, &hints, &res)))
+        errx(1, "getaddrinfo: %s", gai_strerror(_err));
+
+    // use
+    for (r = res; r; r = r->ai_next) {
+        // XXX: wrong
+        if ((sock = socket(r->ai_family, r->ai_socktype, r->ai_protocol)) < 0)
+            err(1, "socket");
+
+        if (connect(sock, r->ai_addr, r->ai_addrlen))
+            err(1, "connect");
+
+        break;
+    }
+    
+    // ensure we got some valid socket
+    if (sock < 0)
+        errx(1, "no valid socket");
+    
+    // ok
+    return sock;
+}
+
+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 (int 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 = 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) {
+    int sock;
+    char line_buf[LINE_LENGTH + 1];
+    struct recvline_state recvline_ctx;
+
+    // initialize
+    memset(&recvline_ctx, 0, sizeof(recvline_ctx));
+    
+    // over-simplified connect
+    sock = sock_connect(CONNECT_HOST, CONNECT_SERV);
+
+    // read lines and dump them out
+    do {
+        // recv
+        recvline(sock, line_buf, sizeof(line_buf), &recvline_ctx);
+
+        // printf
+        printf("<<< %s\n", line_buf);
+
+    } while (1);
+    
+    // ok
+    return 0;
+}
+