modules/websocket: more work on module boiler-plate and handshake
[sip-router] / modules / websocket / ws_mod.c
1 /*
2  * $Id$
3  *
4  * Copyright (C) 2012 Crocodile RCS Ltd
5  *
6  * This file is part of Kamailio, a free SIP server.
7  *
8  * Kamailio is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version
12  *
13  * Kamailio is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License 
19  * along with this program; if not, write to the Free Software 
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23
24 #include "../../dprint.h"
25 #include "../../locking.h"
26 #include "../../sr_module.h"
27 #include "../../lib/kcore/kstats_wrapper.h"
28 #include "../../lib/kmi/mi.h"
29 #include "../../lib/kmi/tree.h"
30 #include "../../parser/msg_parser.h"
31 #include "ws_handshake.h"
32 #include "ws_frame.h"
33 #include "ws_mod.h"
34
35 MODULE_VERSION
36
37 static int mod_init(void);
38 static void destroy(void);
39
40 sl_api_t ws_slb;
41 int *ws_enabled;
42 gen_lock_t *ws_stats_lock;
43
44 int ws_ping_interval = 30;      /* time (in seconds) between sending Pings */
45
46 stat_var *ws_current_connections;
47 stat_var *ws_failed_connections;
48 stat_var *ws_failed_handshakes;
49 stat_var *ws_local_closed_connections;
50 stat_var *ws_max_concurrent_connections;
51 stat_var *ws_received_frames;
52 stat_var *ws_remote_closed_connections;
53 stat_var *ws_successful_handshakes;
54 stat_var *ws_transmitted_frames;
55
56 static struct mi_root *mi_dump(struct mi_root *cmd, void *param);
57
58 static cmd_export_t cmds[]= 
59 {
60     {"ws_handle_handshake", (cmd_function)ws_handle_handshake, 0,
61         0, 0,
62         ANY_ROUTE},
63     {0, 0, 0, 0, 0, 0}
64 };
65
66 static param_export_t params[]=
67 {
68         {"ping_interval",       INT_PARAM, &ws_ping_interval},
69         {0, 0}
70 };
71
72 static stat_export_t stats[] =
73 {
74         {"ws_current_connections",       0, &ws_current_connections },
75         {"ws_failed_connections",        0, &ws_failed_connections },
76         {"ws_failed_handshakes",         0, &ws_failed_handshakes },
77         {"ws_local_closed_connections",  0, &ws_local_closed_connections },
78         {"ws_max_concurrent_connections",0, &ws_max_concurrent_connections },
79         {"ws_received_frames",           0, &ws_received_frames },
80         {"ws_remote_closed_connections", 0, &ws_remote_closed_connections },
81         {"ws_successful_handshakes",     0, &ws_successful_handshakes },
82         {"ws_transmitted_frames",        0, &ws_transmitted_frames },
83         {0, 0, 0}
84 };
85
86 static mi_export_t mi_cmds[] =
87 {
88         { "ws_close",   ws_mi_close,   0, 0, 0},
89         { "ws_disable", ws_mi_disable, 0, 0, 0},
90         { "ws_dump",    mi_dump,       0, 0, 0},
91         { "ws_enable",  ws_mi_enable,  0, 0, 0},
92         { "ws_ping",    ws_mi_ping,    0, 0, 0},
93         { 0, 0, 0, 0, 0}
94 };
95
96 struct module_exports exports= 
97 {
98         "websocket",
99         DEFAULT_DLFLAGS,        /* dlopen flags */
100         cmds,                   /* Exported functions */
101         params,                 /* Exported parameters */
102         stats,                  /* exported statistics */
103         mi_cmds,                /* exported MI functions */
104         0,                      /* exported pseudo-variables */
105         0,                      /* extra processes */
106         mod_init,               /* module initialization function */
107         0,                      /* response function */
108         destroy,                /* destroy function */
109         0                       /* per-child initialization function */
110 };
111
112 static int mod_init(void)
113 {
114         if (sl_load_api(&ws_slb) != 0)
115         {
116                 LM_ERR("binding to SL\n");
117                 return -1;
118         }
119
120         if (register_module_stats(exports.name, stats) != 0)
121         {
122                 LM_ERR("registering core statistics\n");
123                 return -1;
124         }
125
126         if (register_mi_mod(exports.name, mi_cmds) != 0)
127         {
128                 LM_ERR("registering MI commands\n");
129                 return -1;
130         }
131
132         if ((ws_enabled = (int *) shm_malloc(sizeof(int))) == NULL)
133         {
134                 LM_ERR("allocating shared memory\n");
135                 return -1;
136         }
137         *ws_enabled = 1;
138
139         if ((ws_stats_lock = lock_alloc()) == NULL)
140         {
141                 LM_ERR("allocating lock\n");
142                 return -1;
143         }
144         if (lock_init(ws_stats_lock) == NULL)
145         {
146                 LM_ERR("initialising lock\n");
147                 lock_dealloc(ws_stats_lock);
148                 return -1;
149         }
150
151         /* TODO: register module with core to receive WS/WSS messages */
152
153         return 0;
154 }
155
156 static void destroy(void)
157 {
158         shm_free(ws_enabled);
159         lock_destroy(ws_stats_lock);
160         lock_dealloc(ws_stats_lock);
161
162         /* TODO: close all connections */
163 }
164
165 static struct mi_root *mi_dump(struct mi_root *cmd, void *param)
166 {
167         /* TODO: output all open websocket connections */
168         return init_mi_tree(200, MI_OK_S, MI_OK_LEN);
169 }