a fancy socket abstraction layer, with TCP, next, SSL. Also, .hgignore
authorTero Marttila <terom@fixme.fi>
Sun, 22 Feb 2009 03:57:44 +0200
changeset 1 cf0e1bb6bcab
parent 0 317e5bc59627
child 2 a834f0559939
a fancy socket abstraction layer, with TCP, next, SSL. Also, .hgignore
.hgignore
Makefile
src/nexus.c
src/sock.c
src/sock.h
src/sock_internal.h
src/sock_tcp.c
src/sock_tcp.h
--- /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 */