remove irc_chan.state, modify irc_chan_callbacks.on_msg to take a irc_nm, improve error handling a bit further (up to irc_net now)
authorTero Marttila <terom@fixme.fi>
Thu, 12 Mar 2009 22:50:08 +0200
changeset 45 71e65564afd2
parent 44 6bd70113e1ed
child 46 0c13bca53ae1
remove irc_chan.state, modify irc_chan_callbacks.on_msg to take a irc_nm, improve error handling a bit further (up to irc_net now)
Makefile
src/irc_chan.c
src/irc_chan.h
src/irc_conn.c
src/irc_conn.h
src/irc_log.c
src/irc_net.c
src/irc_proto.c
src/irc_proto.h
src/line_proto.c
src/line_proto.h
src/test.c
--- a/Makefile	Thu Mar 12 22:06:01 2009 +0200
+++ b/Makefile	Thu Mar 12 22:50:08 2009 +0200
@@ -39,7 +39,7 @@
 SOCK_TEST_OBJS = obj/sock_test.o
 SOCK_GNUTLS_OBJS = obj/sock_gnutls.o
 LINEPROTO_OBJS = obj/line_proto.o
-IRC_OBJS = obj/irc_line.o obj/irc_conn.o obj/irc_net.o obj/irc_chan.o obj/irc_cmd.o obj/irc_nm.o
+IRC_OBJS = obj/irc_line.o obj/irc_conn.o obj/irc_net.o obj/irc_chan.o obj/irc_cmd.o obj/irc_proto.o
 IRC_LOG_OBJS = obj/irc_log.o
 
 # XXX: not yet there
--- a/src/irc_chan.c	Thu Mar 12 22:06:01 2009 +0200
+++ b/src/irc_chan.c	Thu Mar 12 22:50:08 2009 +0200
@@ -20,13 +20,17 @@
     // us?
     if (irc_prefix_cmp_nick(line->prefix, chan->net->conn->nickname) == 0) {
         // twiddle state
-        chan->state.joining = false;
-        chan->state.joined = true;
+        chan->joining = false;
+        chan->joined = true;
 
         log_info("joined channel: %s", chan->info.channel);
         
         // invoke callback
         IRC_CHAN_INVOKE_CALLBACK(chan, on_self_join);
+
+    } else {
+        // XXX: who cares
+        
     }
 }
 
@@ -36,9 +40,23 @@
 static void irc_chan_on_PRIVMSG (const struct irc_line *line, void *arg)
 {
     struct irc_chan *chan = arg;
+    char prefix_buf[IRC_PREFIX_MAX];
+    struct irc_nm *nm;
+    err_t err;
 
-    // invoke callback (prefix, message)
-    IRC_CHAN_INVOKE_CALLBACK(chan, on_msg, line->prefix, line->args[1]);
+    const char *msg = line->args[1];
+
+    // parse nickmask
+    if ((err = irc_nm_parse(nm, prefix_buf, line->prefix))) {
+        log_warn("invalid prefix: %s", line->prefix);
+        
+        // invoke callback with NULL prefix
+        IRC_CHAN_INVOKE_CALLBACK(chan, on_msg, NULL, msg);
+
+    } else {
+        // invoke callback (prefix, message)
+        IRC_CHAN_INVOKE_CALLBACK(chan, on_msg, nm, msg);
+    }
 }
 
 /**
@@ -104,7 +122,8 @@
     err_t err;
 
     // XXX: error instead?
-    assert(!chan->state.joining && !chan->state.joined);
+    assert(!chan->joining && !chan->joined);
+    assert(chan->net->conn);
 
     // send JOIN message on the appropriate connection
     if ((err = irc_conn_JOIN(chan->net->conn, chan->info.channel)))
@@ -112,7 +131,7 @@
         return err;
 
     // ok
-    chan->state.joining = true;
+    chan->joining = true;
 
     return SUCCESS;
 }
--- a/src/irc_chan.h	Thu Mar 12 22:06:01 2009 +0200
+++ b/src/irc_chan.h	Thu Mar 12 22:50:08 2009 +0200
@@ -11,6 +11,7 @@
 
 #include "irc_net.h"
 #include "irc_cmd.h"
+#include "irc_proto.h"
 #include "error.h"
 #include <sys/queue.h>
 
@@ -24,14 +25,16 @@
 };
 
 /**
- * Semantic IRC channel callbacks
+ * Semantic IRC channel callbacks.
+ *
+ * Where callbacks have irc_nm arguments, these are MAY be given as NULL if the prefix could not be parsed.
  */
 struct irc_chan_callbacks {
     /** Joined the channel */
     void (*on_self_join) (struct irc_chan *chan, void *arg);
 
     /** Someone sent a message to the channel */
-    void (*on_msg) (struct irc_chan *chan, const char *prefix, const char *msg, void *arg);
+    void (*on_msg) (struct irc_chan *chan, const struct irc_nm *source, const char *msg, void *arg);
 };
 
 /**
@@ -62,16 +65,15 @@
     /** Our identifying info */
     struct irc_chan_info info;
     
-    /** State flags */
-    struct {
+    /** State flags @{ */
         /** JOIN request sent, waiting for reply */
         bool joining;
 
         /** Currently joined to channel */
         bool joined;
 
-    } state;
-
+    // @}
+    
     /** General command handlers */
     irc_cmd_handlers_t handlers;
 
--- a/src/irc_conn.c	Thu Mar 12 22:06:01 2009 +0200
+++ b/src/irc_conn.c	Thu Mar 12 22:50:08 2009 +0200
@@ -7,14 +7,19 @@
 #include <string.h>
 
 /**
- * @group Forward-declerations
- * @{
+ * Handle an async error on this IRC connection that we could not recover from any other way, the protocol is now dead,
+ * and should be considered as destroyed after this returns.
+ *
+ * For conveniance, this returns the ERROR_CODE
  */
+static err_t irc_conn_set_error (struct irc_conn *conn, struct error_info *err)
+{
+    // notify user callback
+    conn->callbacks.on_error(conn, err, conn->cb_arg);
 
-/**
- * Handle an event-based error on this IRC connection.
- */
-static void irc_conn_handle_error (struct irc_conn *conn, struct error_info *err);
+    return ERROR_CODE(err);
+}
+
 
 /**
  * Update irc_conn.nickname
@@ -28,17 +33,13 @@
         SET_ERROR(&err, ERR_STRDUP);
 
         // notify
-        irc_conn_handle_error(conn, &err);
-
-        return ERROR_CODE(&err);
+        return irc_conn_set_error(conn, &err);
     }
 
     // ok
     return SUCCESS;
 }
 
-// @}
-
 /**
  * 001 <nick> :Welcome to the Internet Relay Network <nick>!<user>@<host>
  */
@@ -138,8 +139,8 @@
     // log
     log_err_info(err, "line_proto error");
     
-    // 'handle'
-    irc_conn_handle_error(conn, err);
+    // trash ourselves
+    irc_conn_set_error(conn, err);
 }
 
 static struct line_proto_callbacks _lp_callbacks = {
@@ -147,11 +148,6 @@
     .on_error       = &irc_conn_on_error,
 };
 
-static void irc_conn_handle_error (struct irc_conn *conn, struct error_info *err)
-{
-    // XXX: notify user callback
-}
-
 err_t irc_conn_create (struct irc_conn **conn_ptr, struct sock_stream *sock, const struct irc_conn_callbacks *callbacks, 
         void *cb_arg, struct error_info *err)
 {
--- a/src/irc_conn.h	Thu Mar 12 22:06:01 2009 +0200
+++ b/src/irc_conn.h	Thu Mar 12 22:50:08 2009 +0200
@@ -40,6 +40,12 @@
      * irc_conn_register has completed.
      */
     void (*on_registered) (struct irc_conn *conn, void *arg);
+
+    /**
+     * The connection has failed in some way, and can not be considered useable anymore. Sending messages won't work,
+     * and no more messages will be received. The connection should be destroyed, probably from this callback.
+     */
+    void (*on_error) (struct irc_conn *conn, struct error_info *err, void *arg);
 };
 
 /*
--- a/src/irc_log.c	Thu Mar 12 22:06:01 2009 +0200
+++ b/src/irc_log.c	Thu Mar 12 22:50:08 2009 +0200
@@ -14,14 +14,14 @@
 
 } _ctx;
 
-static void on_chan_msg (struct irc_chan *chan, const char *prefix, const char *message, void *arg)
+static void on_chan_msg (struct irc_chan *chan, const struct irc_nm *source, const char *message, void *arg)
 {
     struct irc_log_ctx *ctx = arg;
 
     (void) ctx;
 
     // log it! :P
-    log_debug("%s: %s: %s", prefix, irc_chan_name(chan), message);
+    log_debug("%s: %s: %s", source ? source->nickname : "???", irc_chan_name(chan), message);
 }
 
 static struct irc_chan_callbacks _chan_callbacks = {
--- a/src/irc_net.c	Thu Mar 12 22:06:01 2009 +0200
+++ b/src/irc_net.c	Thu Mar 12 22:50:08 2009 +0200
@@ -20,11 +20,26 @@
     }
 }
 
+static void irc_net_conn_error (struct irc_conn *conn, struct error_info *err, void *arg)
+{
+    struct irc_net *net = arg;
+    
+    // log an error
+    log_err_info(err, "irc_conn failed");
+
+    // destroy and set NULL
+    irc_conn_destroy(conn);
+    net->conn = NULL;
+
+    // XXX: reconnect?
+}
+
 /**
  * Our irc_conn_callbacks list
  */
 struct irc_conn_callbacks _conn_callbacks = {
     .on_registered  = &irc_net_conn_registered,
+    .on_error       = &irc_net_conn_error,
 };
 
 /**
--- a/src/irc_proto.c	Thu Mar 12 22:06:01 2009 +0200
+++ b/src/irc_proto.c	Thu Mar 12 22:50:08 2009 +0200
@@ -2,6 +2,31 @@
 
 #include <string.h>
 
+err_t irc_nm_parse (struct irc_nm *nm, char *buf, const char *prefix)
+{
+    // too long?
+    if (strlen(prefix) >= IRC_PREFIX_MAX)
+        return ERR_INVALID_NM;
+
+    // copy to mutable buffer
+    strcpy(buf, prefix);
+
+    // mangle tokens
+    nm->nickname = strsep(&buf, "!");
+    nm->username = strsep(&buf, "@");
+
+    // did we find the ! and @ tokens?
+    if (!buf)
+        // probably a server name instead
+        return ERR_INVALID_NM;
+    
+    // the hostname is then the rest of the prefix
+    nm->hostname = buf;
+
+    // ok
+    return SUCCESS;
+}
+
 /**
  * Compare two nicknames
  */
--- a/src/irc_proto.h	Thu Mar 12 22:06:01 2009 +0200
+++ b/src/irc_proto.h	Thu Mar 12 22:50:08 2009 +0200
@@ -10,11 +10,18 @@
 #include <stddef.h>
 
 /**
- * Maximum length of an IRC nickname including terminating NUL
+ * Maximum length of an IRC nickname including terminating NUL.
  */
 #define IRC_NICK_MAX 31
 
 /**
+ * Maximum length of an IRC prefix/nickmask string, including any termianting NULs.
+ *
+ * XXX: currently this is pretty large, but does it really matter? We have more than 4k stack...
+ */
+#define IRC_PREFIX_MAX 510
+
+/**
  * Parsed nickmask
  */
 struct irc_nm {
@@ -31,9 +38,10 @@
 /**
  * Parse a full nickmask from a prefix. This fails if the prefix is a server name.
  *
- * XXX: not implemented, and memory-management issues
+ * Since we cannot modify the prefix string, the user must provide a buffer of at least IRC_PREFIX_MAX bytes to store
+ * the procesed prefix. The returned nm's fields will point into this buffer.
  */
-err_t irc_nm_parse (struct irc_nm *nm, char *prefix);
+err_t irc_nm_parse (struct irc_nm *nm, char *buf, const char *prefix);
 
 /**
  * Compare two nicknames for equality, with standard strcmp() semantics.
--- a/src/line_proto.c	Thu Mar 12 22:06:01 2009 +0200
+++ b/src/line_proto.c	Thu Mar 12 22:50:08 2009 +0200
@@ -40,16 +40,14 @@
 static err_t line_proto_schedule_events (struct line_proto *lp, short what);
 
 /**
- * Trigger the on_error callback
+ * An error occured which we could not recover from; the line_proto should now be considered corrupt.
  *
- * XXX: take error_info as an arg?
+ * Notify the user callback, which will probably call line_proto_release().
  */
-static void line_proto_handle_error (struct line_proto *lp)
+static void line_proto_set_error (struct line_proto *lp)
 {
     // trigger callback
     lp->callbacks.on_error(&lp->err, lp->cb_arg);
-
-    // XXX: do we handle release()? no
 }
 
 /**
@@ -69,9 +67,7 @@
         // attempt to read a line
         if (line_proto_recv(lp, &line)) {
             // faaail
-            line_proto_handle_error(lp);
-
-            return;
+            return line_proto_set_error(lp);
         }
 
         // got a line?
@@ -82,7 +78,7 @@
 
     // reschedule
     if (line_proto_schedule_events(lp, EV_READ))
-        line_proto_handle_error(lp);
+        line_proto_set_error(lp);
 }
 
 /*
@@ -100,7 +96,7 @@
         // faaaail
         SET_ERROR(&lp->err, -ret);
 
-        line_proto_handle_error(lp);
+        return line_proto_set_error(lp);
     }
 }
 
--- a/src/line_proto.h	Thu Mar 12 22:06:01 2009 +0200
+++ b/src/line_proto.h	Thu Mar 12 22:50:08 2009 +0200
@@ -21,7 +21,7 @@
     /** Handle received line */
     void (*on_line) (char *line, void *arg);
     
-    /** Event-based action failed */
+    /** Transport failed, the line_proto is corrupt, you should call line_proto_release next. */
     void (*on_error) (struct error_info *err, void *arg);
 };
 
--- a/src/test.c	Thu Mar 12 22:06:01 2009 +0200
+++ b/src/test.c	Thu Mar 12 22:50:08 2009 +0200
@@ -379,7 +379,7 @@
 
     // add a channel
     assert((chan = irc_net_add_chan(net, &chan_info)));
-    assert(!chan->state.joining && !chan->state.joined);
+    assert(!chan->joining && !chan->joined);
     assert_success(irc_chan_add_callbacks(chan, &_chan_callbacks, &ctx));
     ctx.chan = chan;
     
@@ -392,12 +392,12 @@
     assert_strcmp(net->conn->nickname, "mynick");
     
     // JOIN request
-    assert(chan->state.joining);
+    assert(chan->joining);
     assert_sock_data(sock, "JOIN #test\r\n");
 
     // JOIN reply
     sock_test_add_recv_str(sock, ":mynick!user@host JOIN #test\r\n");
-    assert(!chan->state.joining && chan->state.joined);
+    assert(!chan->joining && chan->joined);
     assert(ctx.on_chan_self_join);
 }