initial code...
authorTero Marttila <terom@fixme.fi>
Sun, 22 Feb 2009 02:00:34 +0200
changeset 0 317e5bc59627
child 1 cf0e1bb6bcab
initial code...
Makefile
bin/.empty_dir
build/deps/.empty_dir
obj/.empty_dir
src/nexus.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Makefile	Sun Feb 22 02:00:34 2009 +0200
@@ -0,0 +1,81 @@
+#LIBEVENT_PATH = ~/opt
+#LIBRARY_PATHS = -L${LIBEVENT_PATH}/lib
+#INCLUDE_PATHS = -I${LIBEVENT_PATH}/include
+LDLIBS = -levent
+
+# default is test
+ifndef MODE
+MODE = test
+endif
+
+ifeq ($(MODE), debug)
+MODE_CFLAGS = -g -DDEBUG_ENABLED
+else ifeq ($(MODE), dev)
+MODE_CFLAGS = -g
+else ifeq ($(MODE), test)
+MODE_CFLAGS = -g -DINFO_DISABLED
+else ifeq ($(MODE), release)
+MODE_CFLAGS = -DINFO_DISABLED -O2
+endif
+
+FIXED_CFLAGS = -Wall -std=gnu99
+
+BIN_NAMES = nexus
+BIN_PATHS = $(addprefix bin/,$(BIN_NAMES))
+
+# modules
+module_objs = $(patsubst src/%.c,obj/%.o,$(wildcard src/$(1)/*.c))
+
+# XXX: not yet there
+#CORE_OBJS = obj/lib/log.o obj/lib/signals.o
+
+# first target
+all: ${BIN_PATHS}
+
+# binaries
+bin/nexus: 
+
+# computed
+LDFLAGS = ${LIBRARY_PATHS}
+CPPFLAGS = ${INCLUDE_PATHS} ${DEFINES}
+CFLAGS = ${MODE_CFLAGS} ${FIXED_CFLAGS}
+
+SRC_PATHS = $(wildcard src/*.c) $(wildcard src/*/*.c)
+SRC_NAMES = $(patsubst src/%,%,$(SRC_PATHS))
+SRC_DIRS = $(dir $(SRC_NAMES))
+
+# other targets
+clean :
+	-rm obj/*.o obj/*/*.o
+	-rm bin/* 
+	-rm build/deps/*.d build/deps/*/*.d
+
+clean-deps:
+	-rm build/deps/*/*.d 
+	-rm build/deps/*.d
+
+#obj-dirs: 
+#	python build/make_obj_dirs.py $(BIN_PATHS)
+
+build/deps/%.d : src/%.c
+	@set -e; rm -f $@; \
+	 $(CC) -MM -MT __ $(CPPFLAGS) $< > $@.$$$$; \
+	 sed 's,__[ :]*,obj/$*.o $@ : ,g' < $@.$$$$ > $@; \
+	 rm -f $@.$$$$
+
+include $(SRC_NAMES:%.c=build/deps/%.d)
+
+obj/%.o : src/%.c
+	$(CC) -c $(CPPFLAGS) $(CFLAGS) $< -o $@
+
+bin/% : obj/%.o
+	$(CC) $(LDFLAGS) $+ $(LOADLIBES) $(LDLIBS) -o $@
+
+# documentation
+DOXYGEN_PATH = /usr/bin/doxygen
+DOXYGEN_CONF_PATH = doc/doxygen.conf
+DOXYGEN_OUTPUT_FILE = doc/html/index.html
+
+docs :
+	${DOXYGEN_PATH} ${DOXYGEN_CONF_PATH}
+
--- /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;
+}
+