modules/websocket: Added new event_route[websocket:closed] which is run when a WebSoc...
authorPeter Dunkley <peter.dunkley@crocodile-rcs.com>
Tue, 7 Aug 2012 22:38:18 +0000 (23:38 +0100)
committerPeter Dunkley <peter.dunkley@crocodile-rcs.com>
Tue, 7 Aug 2012 22:38:18 +0000 (23:38 +0100)
- Also changed ws_handle_handshake() to return 1 on success (still 0 on all
  errors as they are handled - and the correct responses sent - within the
  function).

modules/websocket/README
modules/websocket/doc/websocket_admin.xml
modules/websocket/example/kamailio.cfg
modules/websocket/ws_conn.c
modules/websocket/ws_conn.h
modules/websocket/ws_frame.c
modules/websocket/ws_handshake.c

index 72f7757..5a34e3a 100644 (file)
@@ -43,6 +43,10 @@ Peter Dunkley
               6.5. ws.disable
               6.6. ws.enable
 
+        7. Event routes
+
+              7.1. websocket:closed
+
    List of Examples
 
    1.1. event_route[xhttp:request]
@@ -90,6 +94,10 @@ Chapter 1. Admin Guide
         6.5. ws.disable
         6.6. ws.enable
 
+   7. Event routes
+
+        7.1. websocket:closed
+
 1. Overview
 
    This module implements a WebSocket (RFC 6455) server and provides
@@ -153,7 +161,12 @@ event_route[xhttp:request] {
 
                 # ws_handle_handshake() exits (no further configuration file
                 # processing of the request) when complete.
-                ws_handle_handshake();
+                if (ws_handle_handshake())
+                {
+                        # Optional... cache some information about the
+                        # successful connection
+                        exit;
+                }
         }
 
         xhttp_reply("404", "Not found", "", "");
@@ -356,8 +369,8 @@ modparam("websocket", "ping_application_data", "WebSockets rock")
 
 Note
 
-   This function always returns 0, stopping all further processing of the
-   request.
+   This function returns 0, stopping all further processing of the
+   request, when there is a problem.
 
    Example 1.8. ws_handle_handshake usage
 ...
@@ -460,3 +473,18 @@ Note
    MI FIFO Command Format:
                         :ws.enable:fifo_reply
                         _empty_line_
+
+7. Event routes
+
+   7.1. websocket:closed
+
+7.1.  websocket:closed
+
+   When defined, the module calls event_route[websocket:closed] when a
+   connection closes. The connection may be identified using the the $si
+   and $sp pseudo-variables.
+...
+event_route[websocket:closed] {
+        xlog("L_INFO", "WebSocket connection from $si:$sp has closed\n");
+}
+...
index 0ec82f2..6609275 100644 (file)
@@ -77,7 +77,12 @@ event_route[xhttp:request] {
 
                 # ws_handle_handshake() exits (no further configuration file
                 # processing of the request) when complete.
-                ws_handle_handshake();
+                if (ws_handle_handshake())
+               {
+                       # Optional... cache some information about the
+                       # successful connection
+                       exit;
+               }
         }
 
         xhttp_reply("404", "Not found", "", "");
@@ -343,8 +348,8 @@ modparam("websocket", "ping_application_data", "WebSockets rock")
                from HTTP to WebSocket.</para>
                <para>This function can be used from ANY_ROUTE (but will only
                work in <emphasis>event_route[xhttp:request]</emphasis>).</para>
-               <note><para>This function always returns 0, stopping all further
-               processing of the request.</para></note>
+               <note><para>This function returns 0, stopping all further
+               processing of the request, when there is a problem.</para></note>
                <example>
                <title><function>ws_handle_handshake</function> usage</title>
                <programlisting format="linespecific">
@@ -466,7 +471,29 @@ ws_handle_handshake();
 </programlisting>
        </section>
 
+       </section>
 
+       <section>
+       <title>Event routes</title>
+       <section>
+               <title>
+               <function moreinfo="none">websocket:closed</function>
+               </title>
+               <para>
+                       When defined, the module calls
+                       event_route[websocket:closed] when a connection
+                       closes.  The connection may be identified using the
+                       the $si and $sp pseudo-variables.
+               </para>
+               <programlisting format="linespecific">
+...
+event_route[websocket:closed] {
+       xlog("L_INFO", "WebSocket connection from $si:$sp has closed\n");
+}
+...
+               </programlisting>
        </section>
+
+       </section>      
 </chapter>
 
index 28a016c..5cc76ab 100644 (file)
@@ -333,9 +333,18 @@ event_route[xhttp:request] {
 
                # ws_handle_handshake() exits (no further configuration file
                # processing of the request) when complete.
-               ws_handle_handshake();
+               if (ws_handle_handshake())
+               {
+                       # Optional... cache some information abou the
+                       # successful connection
+                       exit;
+               }
        }
 
        xhttp_reply("404", "Not found", "", "");
 }
+
+event_route[websocket:closed] {
+       xlog("L_INFO", "WebSocket connection from $si:$sp has closed\n");
+}
 #!endif
index fdaba36..5afeaa6 100644 (file)
@@ -24,6 +24,7 @@
 #include "../../locking.h"
 #include "../../str.h"
 #include "../../tcp_conn.h"
+#include "../../lib/kcore/faked_msg.h"
 #include "../../lib/kcore/kstats_wrapper.h"
 #include "../../lib/kmi/tree.h"
 #include "../../mem/mem.h"
@@ -175,9 +176,10 @@ void wsconn_destroy(void)
        }
 }
 
-int wsconn_add(int id)
+int wsconn_add(struct receive_info rcv)
 {
        int cur_cons, max_cons;
+       int id = rcv.proto_reserved1;
        int id_hash = tcp_id_hash(id);
        ws_connection_t *wsc;
 
@@ -192,6 +194,7 @@ int wsconn_add(int id)
        wsc->id = id;
        wsc->id_hash = id_hash;
        wsc->state = WS_S_OPEN;
+       wsc->rcv = rcv;
 
        WSCONN_LOCK;
        /* Add to WebSocket connection table */
@@ -221,7 +224,37 @@ int wsconn_add(int id)
        return 0;
 }
 
-int wsconn_rm(ws_connection_t *wsc)
+static void wsconn_run_route(ws_connection_t *wsc)
+{
+       int rt, backup_rt;
+       struct run_act_ctx ctx;
+       sip_msg_t *fmsg;
+
+       LM_DBG("wsconn_run_route event_route[websocket:closed]\n");
+
+       rt = route_get(&event_rt, "websocket:closed");
+       if (rt < 0 || event_rt.rlist[rt] == NULL)
+       {
+               LM_DBG("route does not exist");
+               return;
+       }
+
+       if (faked_msg_init() < 0)
+       {
+               LM_ERR("faked_msg_init() failed\n");
+               return;
+       }
+       fmsg = faked_msg_next();
+       fmsg->rcv = wsc->rcv;
+
+       backup_rt = get_route_type();
+       set_route_type(REQUEST_ROUTE);
+       init_run_actions_ctx(&ctx);
+       run_top_route(event_rt.rlist[rt], fmsg, 0);
+       set_route_type(backup_rt);
+}
+
+int wsconn_rm(ws_connection_t *wsc, ws_conn_eventroute_t run_event_route)
 {
        if (!wsc)
        {
@@ -229,6 +262,9 @@ int wsconn_rm(ws_connection_t *wsc)
                return -1;
        }
 
+       if (run_event_route == WSCONN_EVENTROUTE_YES)
+               wsconn_run_route(wsc);
+
        WSCONN_LOCK;
        /* Remove from the WebSocket used list */
        if (wsconn_used_list->head == wsc)
@@ -289,7 +325,7 @@ void wsconn_close_now(ws_connection_t *wsc)
        con->state = S_CONN_BAD;
        con->timeout = get_ticks_raw();
 
-       if (wsconn_rm(wsc) < 0)
+       if (wsconn_rm(wsc, WSCONN_EVENTROUTE_YES) < 0)
                LM_ERR("removing WebSocket connection\n");
 }
 
index c90af5a..5485458 100644 (file)
@@ -48,6 +48,8 @@ typedef struct ws_connection
        unsigned id_hash;       /* for the corresponding TCP/TLS connection */
        struct ws_connection *id_prev;
        struct ws_connection *id_next;
+
+       struct receive_info rcv;
 } ws_connection_t;
 
 typedef struct
@@ -56,6 +58,12 @@ typedef struct
        ws_connection_t *tail;
 } ws_connection_used_list_t;
 
+typedef enum
+{
+       WSCONN_EVENTROUTE_NO = 0,
+       WSCONN_EVENTROUTE_YES
+} ws_conn_eventroute_t;
+
 extern ws_connection_used_list_t *wsconn_used_list;
 
 extern char *wsconn_state_str[];
@@ -65,8 +73,8 @@ extern stat_var *ws_max_concurrent_connections;
 
 int wsconn_init(void);
 void wsconn_destroy(void);
-int wsconn_add(int id);
-int wsconn_rm(ws_connection_t *wsc);
+int wsconn_add(struct receive_info rcv);
+int wsconn_rm(ws_connection_t *wsc, ws_conn_eventroute_t run_event_route);
 int wsconn_update(ws_connection_t *wsc);
 void wsconn_close_now(ws_connection_t *wsc);
 ws_connection_t *wsconn_get(int id);
index a9b10f6..eded7a4 100644 (file)
@@ -216,7 +216,7 @@ static int encode_and_send_ws_frame(ws_frame_t *frame, conn_close_t conn_close)
        if ((con = tcpconn_get(frame->wsc->id, 0, 0, 0, 0)) == NULL)
        {
                LM_WARN("TCP/TLS connection get failed\n");
-               if (wsconn_rm(frame->wsc) < 0)
+               if (wsconn_rm(frame->wsc, WSCONN_EVENTROUTE_YES) < 0)
                        LM_ERR("removing WebSocket connection\n");
                return -1;
        }
@@ -224,7 +224,7 @@ static int encode_and_send_ws_frame(ws_frame_t *frame, conn_close_t conn_close)
        if (conn_close == CONN_CLOSE_DO)
        {
                dst.send_flags.f |= SND_F_CON_CLOSE;
-               if (wsconn_rm(frame->wsc) < 0)
+               if (wsconn_rm(frame->wsc, WSCONN_EVENTROUTE_YES) < 0)
                {
                        LM_ERR("removing WebSocket connection\n");
                        return -1;
@@ -271,7 +271,7 @@ static int encode_and_send_ws_frame(ws_frame_t *frame, conn_close_t conn_close)
                LM_ERR("sending WebSocket frame\n");
                pkg_free(send_buf);
                update_stat(ws_failed_connections, 1);
-               if (wsconn_rm(frame->wsc) < 0)
+               if (wsconn_rm(frame->wsc, WSCONN_EVENTROUTE_YES) < 0)
                        LM_ERR("removing WebSocket connection\n");
                return -1;
        }
index bb53ef7..d8e34f8 100644 (file)
@@ -292,7 +292,7 @@ int ws_handle_handshake(struct sip_msg *msg)
                                (unsigned char *) reply_key.s, KEY_BUF_LEN);
 
        /* Add the connection to the WebSocket connection table */
-       wsconn_add(msg->rcv.proto_reserved1);
+       wsconn_add(msg->rcv);
 
        /* Make sure Kamailio core sends future messages on this connection
           directly to this module */
@@ -321,10 +321,14 @@ int ws_handle_handshake(struct sip_msg *msg)
        msg->rpl_send_flags.f &= ~SND_F_CON_CLOSE;
        if (ws_send_reply(msg, 101,
                                &str_status_switching_protocols, &headers) < 0)
+       {
                if ((wsc = wsconn_get(msg->rcv.proto_reserved1)) != NULL)
-                       wsconn_rm(wsc);
+                       wsconn_rm(wsc, WSCONN_EVENTROUTE_NO);
 
-       return 0;
+               return 0;
+       }
+
+       return 1;
 }
 
 struct mi_root *ws_mi_disable(struct mi_root *cmd, void *param)