--- /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;
+}
+