working event-based operation for sock_tcp
authorTero Marttila <terom@fixme.fi>
Sat, 28 Feb 2009 17:39:37 +0200
changeset 11 14e79683c48c
parent 10 9fe218576d13
child 12 4147fae232d9
working event-based operation for sock_tcp
src/error.h
src/line_proto.c
src/line_proto.h
src/nexus.c
src/sock.c
src/sock_tcp.c
src/sock_tcp.h
--- a/src/error.h	Sun Feb 22 10:16:28 2009 +0200
+++ b/src/error.h	Sat Feb 28 17:39:37 2009 +0200
@@ -64,6 +64,7 @@
 
     /* Libevent errors */
     _ERROR_CODE( ERR_EVENT_NEW,                     0x010201,   NONE    ),
+    _ERROR_CODE( ERR_EVENT_ADD,                     0x010202,   NONE    ),
     
     // mask of bits used for the error_code value
     _ERROR_CODE_MASK    = 0xffffff,
--- a/src/line_proto.c	Sun Feb 22 10:16:28 2009 +0200
+++ b/src/line_proto.c	Sat Feb 28 17:39:37 2009 +0200
@@ -56,7 +56,7 @@
         
         // got a line?
         if (line)
-            lp->cb_read(lp, line, lp->cb_arg);
+            lp->cb_read(line, lp->cb_arg);
 
     } while (line);
 
@@ -104,6 +104,7 @@
 
     // initialize event-based stuff
     sock_stream_event_init(sock, &line_proto_sock_stream_callbacks, lp);
+    line_proto_schedule_events(lp, EV_READ);
 
     // return
     *lp_ptr = lp;
--- a/src/line_proto.h	Sun Feb 22 10:16:28 2009 +0200
+++ b/src/line_proto.h	Sat Feb 28 17:39:37 2009 +0200
@@ -15,7 +15,7 @@
 /*
  * The callback for receiving lines
  */
-typedef void (*line_proto_read_cb)(struct line_proto *lp, const char *line, void *arg);
+typedef void (*line_proto_read_cb)(const char *line, void *arg);
 
 /*
  * Create a new line_proto off the the given sock_stream. The newly allocated line_proto will be returned via *lp_ptr.
@@ -28,10 +28,9 @@
         line_proto_read_cb cb_func, void *cb_arg, struct error_info *err);
 
 /*
- * Receive one line into the given buffer. The line will be terminated with '\r\n', and said terminator will be
- * NUL'd out, so the buffer is safe for use as a C-string after succesfull return.
- *
- * Note: currently this uses the buffer to store intermediate state, so always pass the same buffer (for now).
+ * Runs the socket recv() into our internal buffer. If a full line was received, a pointer to our internal bufffer is
+ * returned via *line_ptr, and we return SUCCESS. If we don't yet have a full line, and receiving more would block,
+ * NULL is returned via *line_ptr instead. Otherwise, nonzero error return code.
  */
 err_t line_proto_read (struct line_proto *lp, const char **line_ptr);
 
--- a/src/nexus.c	Sun Feb 22 10:16:28 2009 +0200
+++ b/src/nexus.c	Sat Feb 28 17:39:37 2009 +0200
@@ -13,14 +13,17 @@
 #include "line_proto.h"
 
 #define CONNECT_HOST "irc.fixme.fi"
-#define CONNECT_SERV "6697"
+#define CONNECT_SERV "6667"
 #define LINE_LENGTH 512
 
+void on_line (const char *line, void *arg) {
+    printf("<<< %s\n", line);
+}
+
 int main (int argc, char **argv) {
     struct event_base *ev_base;
     struct sock_stream *sock;
     struct line_proto *lp;
-    char *line;
     struct error_info _err;
 
     // initialize libevent
@@ -32,25 +35,18 @@
         errx(1, "sock_init: %s", error_msg(&_err));
 
     // over-simplified connect
-    if (sock_gnutls_connect(&sock, CONNECT_HOST, CONNECT_SERV, &_err))
+    if (sock_tcp_connect(&sock, CONNECT_HOST, CONNECT_SERV, &_err))
         errx(1, "sock_gnutls_connect: %s", error_msg(&_err));
 
     // line protocol
-    if (line_proto_create(&lp, sock, LINE_LENGTH, NULL, NULL, &_err))
+    if (line_proto_create(&lp, sock, LINE_LENGTH, on_line, NULL, &_err))
         errx(1, "line_proto_create: %s", error_msg(&_err));
 
-    // read lines and dump them out
-    do {
-        // recv
-        if (line_proto_read(lp, &line))
-            errx(1, "line_proto_read: %s", error_msg(line_proto_error(lp)));
-
-        // printf
-        printf("<<< %s\n", line);
-
-    } while (1);
+    // run event loop
+    if (event_base_dispatch(ev_base))
+        errx(1, "event_base_dispatch");
     
-    // ok
+    // ok, no cleanup
     return 0;
 }
 
--- a/src/sock.c	Sun Feb 22 10:16:28 2009 +0200
+++ b/src/sock.c	Sat Feb 28 17:39:37 2009 +0200
@@ -35,7 +35,7 @@
 
     // proxy off to method handler
     if ((err = sock->type->methods.read(sock, buf, &len)))
-        return err;
+        return -err;
     
     // return updated bytes-read len
     return len;
@@ -47,7 +47,7 @@
 
     // proxy off to method handler
     if ((err = sock->type->methods.write(sock, buf, &len)))
-        return err;
+        return -err;
 
     // return updated bytes-written len
     return len;
--- a/src/sock_tcp.c	Sun Feb 22 10:16:28 2009 +0200
+++ b/src/sock_tcp.c	Sat Feb 28 17:39:37 2009 +0200
@@ -11,6 +11,21 @@
 #include <assert.h>
 
 /*
+ * Our basic socket event handler for driving our callbacks
+ */
+static void sock_tcp_event_handler (evutil_socket_t fd, short what, void *arg) 
+{
+    struct sock_tcp *sock = arg;
+
+    // invoke appropriate callback
+    if (what & EV_READ && SOCK_TCP_BASE(sock)->cb_info->on_read)
+        SOCK_TCP_BASE(sock)->cb_info->on_read(SOCK_TCP_BASE(sock), SOCK_TCP_BASE(sock)->cb_arg);
+
+    if (what & EV_WRITE && SOCK_TCP_BASE(sock)->cb_info->on_write)
+        SOCK_TCP_BASE(sock)->cb_info->on_read(SOCK_TCP_BASE(sock), SOCK_TCP_BASE(sock)->cb_arg);
+}
+
+/*
  * Our sock_stream_methods.read method
  */
 static err_t sock_tcp_read (struct sock_stream *base_sock, void *buf, size_t *len)
@@ -51,14 +66,32 @@
 static err_t sock_tcp_event_init (struct sock_stream *base_sock)
 {
     struct sock_tcp *sock = SOCK_FROM_BASE(base_sock, struct sock_tcp);
+    err_t err;
+
+    // set nonblocking
+    if ((err = sock_tcp_set_nonblock(sock, 1)))
+        return err;
+
+    // add ourselves as the event handler
+    if ((err = sock_tcp_init_ev(sock, &sock_tcp_event_handler, sock)))
+        return err;
     
+    // done
     return SUCCESS;
 }
 
 static err_t sock_tcp_event_enable (struct sock_stream *base_sock, short mask)
 {
     struct sock_tcp *sock = SOCK_FROM_BASE(base_sock, struct sock_tcp);
+
+    // just add the appropraite events
+    if (mask & EV_READ && event_add(sock->ev_read, NULL))
+        return SET_ERROR(SOCK_TCP_ERR(sock), ERR_EVENT_ADD);
+ 
+    if (mask & EV_WRITE && event_add(sock->ev_write, NULL))
+        return SET_ERROR(SOCK_TCP_ERR(sock), ERR_EVENT_ADD);
     
+    // done
     return SUCCESS;
 }
 
@@ -72,21 +105,6 @@
     .methods.event_enable   = &sock_tcp_event_enable,
 };
 
-/*
- * Our basic socket event handler for driving our callbacks
- */
-static void sock_tcp_event (evutil_socket_t fd, short what, void *arg) 
-{
-    struct sock_tcp *sock = arg;
-
-    // invoke appropriate callback
-    if (what & EV_READ && SOCK_TCP_BASE(sock)->cb_info->on_read)
-        SOCK_TCP_BASE(sock)->cb_info->on_read(SOCK_TCP_BASE(sock), SOCK_TCP_BASE(sock)->cb_arg);
-
-    if (what & EV_WRITE && SOCK_TCP_BASE(sock)->cb_info->on_write)
-        SOCK_TCP_BASE(sock)->cb_info->on_read(SOCK_TCP_BASE(sock), SOCK_TCP_BASE(sock)->cb_arg);
-}
-
 err_t sock_tcp_alloc (struct sock_tcp **sock_ptr)
 {
     // alloc
@@ -116,9 +134,15 @@
 {
     // require valid fd
     assert(sock->fd >= 0);
+
+    // this is initialization
+    assert(sock->ev_read == NULL && sock->ev_write == NULL);
     
     // create new event
-    if ((sock->ev = event_new(_sock_stream_ctx.ev_base, sock->fd, EV_READ, ev_cb, cb_arg)) == NULL)
+    if ((sock->ev_read = event_new(_sock_stream_ctx.ev_base, sock->fd, EV_READ, ev_cb, cb_arg)) == NULL)
+        return SET_ERROR(SOCK_TCP_ERR(sock), ERR_EVENT_NEW);
+
+    if ((sock->ev_write = event_new(_sock_stream_ctx.ev_base, sock->fd, EV_WRITE, ev_cb, cb_arg)) == NULL)
         return SET_ERROR(SOCK_TCP_ERR(sock), ERR_EVENT_NEW);
 
     // ok
--- a/src/sock_tcp.h	Sun Feb 22 10:16:28 2009 +0200
+++ b/src/sock_tcp.h	Sat Feb 28 17:39:37 2009 +0200
@@ -16,8 +16,8 @@
     /* The OS file descriptor */
     int fd;
 
-    /* The libevent struct */
-    struct event *ev;
+    /* The IO events */
+    struct event *ev_read, *ev_write;
 };
 
 #define SOCK_TCP_BASE(sock_ptr) (&(sock_ptr)->base)
@@ -34,8 +34,7 @@
 err_t sock_tcp_init_fd (struct sock_tcp *sock, int fd);
 
 /*
- * Initialize sock_tcp.ev to use the socket's fd with the given callback. By default, this is created with EV_READ
- * flags, but is not added.
+ * Initialize sock_tcp.ev_* to use the socket's fd with the given callback. The ev's are not activated yet.
  */
 err_t sock_tcp_init_ev (struct sock_tcp *sock, void (*ev_cb) (evutil_socket_t, short, void *), void *arg);