--- a/Makefile Sun Feb 22 03:57:44 2009 +0200
+++ b/Makefile Sun Feb 22 05:27:29 2009 +0200
@@ -1,8 +1,3 @@
-#LIBEVENT_PATH = ~/opt
-#LIBRARY_PATHS = -L${LIBEVENT_PATH}/lib
-#INCLUDE_PATHS = -I${LIBEVENT_PATH}/include
-LDLIBS = -levent
-
# default is test
ifndef MODE
MODE = test
@@ -20,6 +15,15 @@
FIXED_CFLAGS = -Wall -std=gnu99
+# libevent
+LIBEVENT_CFLAGS =
+LIBEVENT_LDFLAGS = -levent
+
+# GnuTLS stuff
+GNUTLS_NAME = "gnutls"
+GNUTLS_CFLAGS = $(shell pkg-config ${GNUTLS_NAME} --cflags)
+GNUTLS_LDFLAGS = $(shell pkg-config ${GNUTLS_NAME} --libs)
+
BIN_NAMES = nexus
BIN_PATHS = $(addprefix bin/,$(BIN_NAMES))
@@ -27,6 +31,7 @@
module_objs = $(patsubst src/%.c,obj/%.o,$(wildcard src/$(1)/*.c))
SOCK_OBJS = obj/sock.o obj/sock_tcp.o
+SOCK_GNUTLS_OBJS = obj/sock_gnutls.o
# XXX: not yet there
#CORE_OBJS = obj/lib/log.o obj/lib/signals.o
@@ -35,13 +40,16 @@
all: ${BIN_PATHS}
# binaries
-bin/nexus: ${SOCK_OBJS}
+bin/nexus: ${SOCK_OBJS} ${SOCK_GNUTLS_OBJS}
# computed
-LDFLAGS = ${LIBRARY_PATHS}
-CPPFLAGS = ${INCLUDE_PATHS} ${DEFINES}
-CFLAGS = ${MODE_CFLAGS} ${FIXED_CFLAGS}
+CFLAGS = ${MODE_CFLAGS} ${FIXED_CFLAGS} ${LIBEVENT_CFLAGS} ${GNUTLS_CFLAGS}
+LDFLAGS = ${LIBEVENT_LDFLAGS} ${GNUTLS_LDFLAGS}
+# XXX: is this valid?
+CPPFLAGS = ${CFLAGS}
+
+# names for src/
SRC_PATHS = $(wildcard src/*.c) $(wildcard src/*/*.c)
SRC_NAMES = $(patsubst src/%,%,$(SRC_PATHS))
SRC_DIRS = $(dir $(SRC_NAMES))
--- a/src/nexus.c Sun Feb 22 03:57:44 2009 +0200
+++ b/src/nexus.c Sun Feb 22 05:27:29 2009 +0200
@@ -11,7 +11,7 @@
#include "sock.h"
#define CONNECT_HOST "irc.fixme.fi"
-#define CONNECT_SERV "6667"
+#define CONNECT_SERV "6697"
#define LINE_LENGTH 512
struct recvline_state {
@@ -110,10 +110,11 @@
struct recvline_state recvline_ctx;
// initialize
+ sock_init();
memset(&recvline_ctx, 0, sizeof(recvline_ctx));
// over-simplified connect
- sock = sock_tcp_connect(CONNECT_HOST, CONNECT_SERV);
+ sock = sock_ssl_connect(CONNECT_HOST, CONNECT_SERV);
// read lines and dump them out
do {
--- a/src/sock.c Sun Feb 22 03:57:44 2009 +0200
+++ b/src/sock.c Sun Feb 22 05:27:29 2009 +0200
@@ -1,5 +1,12 @@
#include "sock_internal.h"
+#include "sock_gnutls.h"
+
+void sock_init (void)
+{
+ // XXX: just call directly for now
+ sock_gnutls_init();
+}
int sock_stream_read (struct sock_stream *sock, void *buf, size_t len)
{
--- a/src/sock.h Sun Feb 22 03:57:44 2009 +0200
+++ b/src/sock.h Sun Feb 22 05:27:29 2009 +0200
@@ -33,6 +33,11 @@
struct sock_stream *sock_ssl_connect (const char *host, const char *service);
/*
+ * Initialize the socket module's global state
+ */
+void sock_init (void);
+
+/*
* The generic read/write API for stream sockets.
*/
int sock_stream_read (struct sock_stream *sock, void *buf, size_t len);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/sock_gnutls.c Sun Feb 22 05:27:29 2009 +0200
@@ -0,0 +1,105 @@
+
+#include "sock_gnutls.h"
+
+#include <stdlib.h>
+#include <err.h>
+
+static void _sock_gnutls_error (struct sock_gnutls *sock, const char *func, int _err) {
+ if (_err == GNUTLS_E_FATAL_ALERT_RECEIVED)
+ errx(1, "%s: %s: %s", func, gnutls_strerror(_err), gnutls_alert_get_name(gnutls_alert_get(sock->session)));
+
+ else
+ errx(1, "%s: %s", func, gnutls_strerror(_err));
+}
+
+static int sock_gnutls_read (struct sock_stream *base_sock, void *buf, size_t len)
+{
+ struct sock_gnutls *sock = SOCK_FROM_BASE(base_sock, struct sock_gnutls);
+
+ // just map to gnutls_record_recv
+ return gnutls_record_recv(sock->session, buf, len);
+}
+
+static int sock_gnutls_write (struct sock_stream *base_sock, const void *buf, size_t len)
+{
+ struct sock_gnutls *sock = SOCK_FROM_BASE(base_sock, struct sock_gnutls);
+
+ // just map to gnutls_record_send
+ return gnutls_record_send(sock->session, buf, len);
+}
+
+/*
+ * Our sock_stream_Type
+ */
+struct sock_stream_type sock_gnutls_type = {
+ .methods.read = &sock_gnutls_read,
+ .methods.write = &sock_gnutls_write,
+};
+
+/*
+ * XXX: global shared sock_gnutls_ctx
+ */
+struct sock_gnutls_client_ctx _sock_gnutls_client_ctx;
+
+/*
+ * Configure the given gnutls socket context to use simple anonymous client credentials
+ *
+ * XXX: errors
+ */
+void sock_gnutls_client_ctx_anon (struct sock_gnutls_client_ctx *ctx)
+{
+ gnutls_certificate_allocate_credentials(&ctx->xcred);
+}
+
+// XXX: errors
+void sock_gnutls_init (void)
+{
+ int _err;
+
+ // global init
+ if ((_err = gnutls_global_init()) < 0)
+ errx(1, "gnutls_global_init: %s", gnutls_strerror(_err));
+
+ // init _sock_gnutls_ctx
+ sock_gnutls_client_ctx_anon(&_sock_gnutls_client_ctx);
+}
+
+
+// XXX: errors
+struct sock_stream *sock_ssl_connect (const char *host, const char *service)
+{
+ int _err;
+ struct sock_gnutls *sock;
+ struct sock_gnutls_client_ctx *ctx = &_sock_gnutls_client_ctx;
+
+ // alloc
+ if ((sock = calloc(1, sizeof(*sock))) == NULL)
+ errx(1, "calloc");
+
+ // initialize
+ sock->base_tcp.base.type = &sock_gnutls_type;
+
+ // initialize client session
+ if ((_err = gnutls_init(&sock->session, GNUTLS_CLIENT)) < 0)
+ errx(1, "gnutls_init: %s", gnutls_strerror(_err));
+
+ // ...default priority stuff
+ gnutls_set_default_priority(sock->session);
+
+ // bind anon credentials
+ gnutls_credentials_set(sock->session, GNUTLS_CRD_CERTIFICATE, ctx->xcred);
+
+ // TCP connect
+ sock_tcp_init_connect(SOCK_GNUTLS_TCP(sock), host, service);
+
+ // bind default transport functions (recv/send) to use the TCP fd
+ gnutls_transport_set_ptr(sock->session, (gnutls_transport_ptr_t) sock->base_tcp.fd);
+
+ // perform the handshake
+ if ((_err = gnutls_handshake(sock->session)) < 0)
+ _sock_gnutls_error(sock, "gnutls_handshake", _err);
+
+ // done
+ return SOCK_GNUTLS_BASE(sock);
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/sock_gnutls.h Sun Feb 22 05:27:29 2009 +0200
@@ -0,0 +1,44 @@
+#ifndef SOCK_GNUTLS_H
+#define SOCK_GNUTLS_H
+
+/*
+ * A sock_stream implementation using GnuTLS
+ */
+
+#include "sock_internal.h"
+#include "sock_tcp.h"
+
+#include <gnutls/gnutls.h>
+
+/*
+ * Additional gnutls configuration for client sockets.
+ *
+ * XXX: currently, we just have one global instance, set up by sock_gnutls_init, used for all sockets
+ */
+struct sock_gnutls_client_ctx {
+ gnutls_certificate_credentials_t xcred;
+};
+
+/*
+ * Per-sock state, this includes the sock_tcp connection
+ */
+struct sock_gnutls {
+ /* SSL connections use TCP connections */
+ struct sock_tcp base_tcp;
+
+ /* Additional SSL info XXX: do we need to keep a ref to this? */
+ struct sock_gnutls_ctx *ctx;
+
+ /* The GnuTLS session for this connection */
+ gnutls_session_t session;
+};
+
+#define SOCK_GNUTLS_BASE(sock_ptr) (&(sock_ptr)->base_tcp.base)
+#define SOCK_GNUTLS_TCP(sock_ptr) (&(sock_ptr)->base_tcp)
+
+/*
+ * Initialize the global gnutls state
+ */
+void sock_gnutls_init (void);
+
+#endif /* SOCK_GNUTLS_H */
--- a/src/sock_tcp.c Sun Feb 22 03:57:44 2009 +0200
+++ b/src/sock_tcp.c Sun Feb 22 05:27:29 2009 +0200
@@ -30,33 +30,43 @@
}
/*
- * Define our sock_stream_Type
+ * Our sock_stream_type
+ *
+ * XXX: move to sock_tcp.h
*/
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_tcp_alloc (void)
{
struct sock_tcp *sock;
// alloc
if ((sock = calloc(1, sizeof(*sock))) == NULL)
errx(1, "calloc");
+
+ // initialize base
+ sock->base.type = &sock_tcp_type;
+ // done
+ return sock;
+}
+
+int sock_tcp_init_fd (struct sock_tcp *sock, int fd)
+{
// initialize
- sock->base.type = &sock_tcp_type;
sock->fd = fd;
// done
- return SOCK_TCP_BASE(sock);
+ return 0;
}
-struct sock_stream* sock_tcp_connect (const char *host, const char *service)
+int sock_tcp_init_connect (struct sock_tcp *sock, const char *hostname, const char *service)
{
struct addrinfo hints, *res, *r;
- int _err, fd = -1;
+ int _err;
// hints
memset(&hints, 0, sizeof(hints));
@@ -64,26 +74,40 @@
hints.ai_socktype = SOCK_STREAM;
// resolve
- if ((_err = getaddrinfo(host, service, &hints, &res)))
+ if ((_err = getaddrinfo(hostname, 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)
+ if ((sock->fd = socket(r->ai_family, r->ai_socktype, r->ai_protocol)) < 0)
err(1, "socket");
- if (connect(fd, r->ai_addr, r->ai_addrlen))
+ if (connect(sock->fd, r->ai_addr, r->ai_addrlen))
err(1, "connect");
break;
}
// ensure we got some valid socket
- if (fd < 0)
+ if (sock->fd < 0)
errx(1, "no valid socket");
- // ok, return sock_stream
- return sock_tcp_new(fd);
+ // ok, done
+ return 0;
}
+// XXX: error handling
+struct sock_stream* sock_tcp_connect (const char *host, const char *service)
+{
+ struct sock_tcp *sock;
+
+ // allocate
+ sock = sock_tcp_alloc();
+
+ // connect
+ sock_tcp_init_connect(sock, host, service);
+
+ // done
+ return SOCK_TCP_BASE(sock);
+}
--- a/src/sock_tcp.h Sun Feb 22 03:57:44 2009 +0200
+++ b/src/sock_tcp.h Sun Feb 22 05:27:29 2009 +0200
@@ -20,8 +20,18 @@
#define SOCK_TCP_BASE(sock_ptr) (&(sock_ptr)->base)
/*
- * Create a new sock_tcp from the given fd, returning it as a sock_stream
+ * Allocate a new blank sock_tcp with a correctly initialized base
*/
-struct sock_stream* sock_tcp_new (int fd);
+struct sock_tcp* sock_tcp_alloc (void);
+
+/*
+ * Initialize a blank sock_tcp with a given already-existing fd
+ */
+int sock_tcp_init_fd (struct sock_tcp *sock, int fd);
+
+/*
+ * Initialize a blank sock_tcp by connecting
+ */
+int sock_tcp_init_connect (struct sock_tcp *sock, const char *hostname, const char *service);
#endif /* SOCK_TCP_H */