# HG changeset patch # User Tero Marttila # Date 1235260834 -7200 # Node ID 317e5bc5962786441b6898449e8709a38fdc7448 initial code... diff -r 000000000000 -r 317e5bc59627 Makefile --- /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} + diff -r 000000000000 -r 317e5bc59627 src/nexus.c --- /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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#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; +} +