a fancy socket abstraction layer, with TCP, next, SSL. Also, .hgignore
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/.hgignore Sun Feb 22 03:57:44 2009 +0200
@@ -0,0 +1,6 @@
+syntax: regexp
+
+\.[^/]+\.sw[op]$
+^bin/
+^obj/
+^build/
--- a/Makefile Sun Feb 22 02:00:34 2009 +0200
+++ b/Makefile Sun Feb 22 03:57:44 2009 +0200
@@ -26,6 +26,8 @@
# modules
module_objs = $(patsubst src/%.c,obj/%.o,$(wildcard src/$(1)/*.c))
+SOCK_OBJS = obj/sock.o obj/sock_tcp.o
+
# XXX: not yet there
#CORE_OBJS = obj/lib/log.o obj/lib/signals.o
@@ -33,7 +35,7 @@
all: ${BIN_PATHS}
# binaries
-bin/nexus:
+bin/nexus: ${SOCK_OBJS}
# computed
LDFLAGS = ${LIBRARY_PATHS}
--- a/src/nexus.c Sun Feb 22 02:00:34 2009 +0200
+++ b/src/nexus.c Sun Feb 22 03:57:44 2009 +0200
@@ -1,56 +1,19 @@
#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>
+#include "sock.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;
@@ -95,7 +58,7 @@
/*
* 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) {
+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;
@@ -122,7 +85,7 @@
assert(recv_offset < len);
// otherwise, read more data
- if ((ret = read(sock, buf + recv_offset, len - recv_offset)) < 0)
+ if ((ret = sock_stream_read(sock, buf + recv_offset, len - recv_offset)) < 0)
err(1, "read");
// EOF?
@@ -142,7 +105,7 @@
}
int main (int argc, char **argv) {
- int sock;
+ struct sock_stream *sock;
char line_buf[LINE_LENGTH + 1];
struct recvline_state recvline_ctx;
@@ -150,7 +113,7 @@
memset(&recvline_ctx, 0, sizeof(recvline_ctx));
// over-simplified connect
- sock = sock_connect(CONNECT_HOST, CONNECT_SERV);
+ sock = sock_tcp_connect(CONNECT_HOST, CONNECT_SERV);
// read lines and dump them out
do {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/sock.c Sun Feb 22 03:57:44 2009 +0200
@@ -0,0 +1,15 @@
+
+#include "sock_internal.h"
+
+int sock_stream_read (struct sock_stream *sock, void *buf, size_t len)
+{
+ // proxy off to method handler
+ return sock->type->methods.read(sock, buf, len);
+}
+
+int sock_stream_write (struct sock_stream *sock, const void *buf, size_t len)
+{
+ // proxy off to method handler
+ return sock->type->methods.write(sock, buf, len);
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/sock.h Sun Feb 22 03:57:44 2009 +0200
@@ -0,0 +1,41 @@
+#ifndef SOCK_H
+#define SOCK_H
+
+/*
+ * Low-level socket-related functions
+ */
+#include <sys/types.h>
+
+/*
+ * The generic socket handle
+ */
+struct sock_stream;
+
+/*
+ * A simple blocking TCP connect to the given host/service, using getaddrinfo.
+ *
+ * XXX: blocking
+ * XXX: exits on error
+ *
+ * Returns the socket handle.
+ */
+struct sock_stream *sock_tcp_connect (const char *host, const char *service);
+
+/*
+ * A simple blocking SSL connect to the given host/service.
+ *
+ * XXX: blocking
+ * XXX: doesn't do any certificate verification.
+ * XXX: exits on error
+ *
+ * Returns the socket handle.
+ */
+struct sock_stream *sock_ssl_connect (const char *host, const char *service);
+
+/*
+ * The generic read/write API for stream sockets.
+ */
+int sock_stream_read (struct sock_stream *sock, void *buf, size_t len);
+int sock_stream_write (struct sock_stream *sock, const void *buf, size_t len);
+
+#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/sock_internal.h Sun Feb 22 03:57:44 2009 +0200
@@ -0,0 +1,33 @@
+#ifndef SOCK_INTERNAL_H
+#define SOCK_INTERNAL_H
+
+#include "sock.h"
+
+/*
+ * The base type struct, which defines the method table.
+ */
+struct sock_stream_type {
+ /* method table */
+ struct sock_stream_methods {
+ /* Normal read(2) */
+ int (*read) (struct sock_stream *sock, void *buf, size_t len);
+
+ /* Normal write(2) */
+ int (*write) (struct sock_stream *sock, const void *buf, size_t len);
+
+ } methods;
+};
+
+/*
+ * The base sock_stream type, as used by the sock_stream_* functions.
+ *
+ * The specific implementations should embed this at the start of their type-specific struct, and then cast around
+ * as appropriate.
+ */
+struct sock_stream {
+ struct sock_stream_type *type;
+};
+
+#define SOCK_FROM_BASE(sock, type) ((type*) sock)
+
+#endif /* SOCK_INTERNAL_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/sock_tcp.c Sun Feb 22 03:57:44 2009 +0200
@@ -0,0 +1,89 @@
+
+#include "sock_tcp.h"
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <string.h>
+#include <err.h>
+
+/*
+ * Our sock_stream_type.methods.read implementation
+ */
+static int sock_tcp_read (struct sock_stream *base_sock, void *buf, size_t len)
+{
+ struct sock_tcp *sock = SOCK_FROM_BASE(base_sock, struct sock_tcp);
+
+ return read(sock->fd, buf, len);
+}
+
+/*
+ * Our sock_stream_type.methods.write implementation
+ */
+static int sock_tcp_write (struct sock_stream *base_sock, const void *buf, size_t len)
+{
+ struct sock_tcp *sock = SOCK_FROM_BASE(base_sock, struct sock_tcp);
+
+ return write(sock->fd, buf, len);
+}
+
+/*
+ * Define our sock_stream_Type
+ */
+struct sock_stream_type sock_tcp_type = {
+ .methods.read = &sock_tcp_read,
+ .methods.write = &sock_tcp_write,
+};
+
+struct sock_stream* sock_tcp_new (int fd)
+{
+ struct sock_tcp *sock;
+
+ // alloc
+ if ((sock = calloc(1, sizeof(*sock))) == NULL)
+ errx(1, "calloc");
+
+ // initialize
+ sock->base.type = &sock_tcp_type;
+ sock->fd = fd;
+
+ // done
+ return SOCK_TCP_BASE(sock);
+}
+
+struct sock_stream* sock_tcp_connect (const char *host, const char *service)
+{
+ struct addrinfo hints, *res, *r;
+ int _err, fd = -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 ((fd = socket(r->ai_family, r->ai_socktype, r->ai_protocol)) < 0)
+ err(1, "socket");
+
+ if (connect(fd, r->ai_addr, r->ai_addrlen))
+ err(1, "connect");
+
+ break;
+ }
+
+ // ensure we got some valid socket
+ if (fd < 0)
+ errx(1, "no valid socket");
+
+ // ok, return sock_stream
+ return sock_tcp_new(fd);
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/sock_tcp.h Sun Feb 22 03:57:44 2009 +0200
@@ -0,0 +1,27 @@
+#ifndef SOCK_TCP_H
+#define SOCK_TCP_H
+
+/*
+ * TCP implementation of sock_stream interface.
+ */
+#include "sock_internal.h"
+
+/*
+ * Contains the base sock_stream struct, and the file descriptor
+ */
+struct sock_tcp {
+ /* The base struct for sock_stream_* functions */
+ struct sock_stream base;
+
+ /* The OS file descriptor */
+ int fd;
+};
+
+#define SOCK_TCP_BASE(sock_ptr) (&(sock_ptr)->base)
+
+/*
+ * Create a new sock_tcp from the given fd, returning it as a sock_stream
+ */
+struct sock_stream* sock_tcp_new (int fd);
+
+#endif /* SOCK_TCP_H */