1 | 1 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,187 @@ |
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 "../../locking.h" |
|
25 |
+#include "../../tcp_conn.h" |
|
26 |
+#include "../../mem/mem.h" |
|
27 |
+#include "ws_conn.h" |
|
28 |
+ |
|
29 |
+struct ws_connection **wsconn_hash = NULL; |
|
30 |
+gen_lock_t *wsconn_lock = NULL; |
|
31 |
+ |
|
32 |
+char *wsconn_state_str[] = |
|
33 |
+{ |
|
34 |
+ "CONNECTING", |
|
35 |
+ "OPEN", |
|
36 |
+ "CLOSING", |
|
37 |
+ "CLOSED" |
|
38 |
+}; |
|
39 |
+ |
|
40 |
+static inline void _wsconn_rm(ws_connection_t *wsc); |
|
41 |
+ |
|
42 |
+int wsconn_init(void) |
|
43 |
+{ |
|
44 |
+ wsconn_lock = lock_alloc(); |
|
45 |
+ if (wsconn_lock == NULL) |
|
46 |
+ { |
|
47 |
+ LM_ERR("allocating lock\n"); |
|
48 |
+ return -1; |
|
49 |
+ } |
|
50 |
+ if (lock_init(wsconn_lock) == 0) |
|
51 |
+ { |
|
52 |
+ LM_ERR("initialising lock\n"); |
|
53 |
+ lock_dealloc((void *) wsconn_lock); |
|
54 |
+ wsconn_lock = NULL; |
|
55 |
+ return -1; |
|
56 |
+ } |
|
57 |
+ |
|
58 |
+ wsconn_hash = |
|
59 |
+ (ws_connection_t **) shm_malloc(TCP_ID_HASH_SIZE * |
|
60 |
+ sizeof(ws_connection_t)); |
|
61 |
+ if (wsconn_hash == NULL) |
|
62 |
+ { |
|
63 |
+ LM_ERR("allocating WebSocket hash-table\n"); |
|
64 |
+ lock_dealloc((void *) wsconn_lock); |
|
65 |
+ wsconn_lock = NULL; |
|
66 |
+ return -1; |
|
67 |
+ } |
|
68 |
+ memset((void *) wsconn_hash, 0, |
|
69 |
+ TCP_ID_HASH_SIZE * sizeof(ws_connection_t *)); |
|
70 |
+ |
|
71 |
+ return 0; |
|
72 |
+} |
|
73 |
+ |
|
74 |
+void wsconn_destroy(void) |
|
75 |
+{ |
|
76 |
+ int h; |
|
77 |
+ |
|
78 |
+ if (wsconn_hash) |
|
79 |
+ { |
|
80 |
+ WSCONN_UNLOCK; |
|
81 |
+ WSCONN_LOCK; |
|
82 |
+ for (h = 0; h < TCP_ID_HASH_SIZE; h++) |
|
83 |
+ { |
|
84 |
+ ws_connection_t *wsc = wsconn_hash[h]; |
|
85 |
+ while (wsc) |
|
86 |
+ { |
|
87 |
+ ws_connection_t *next = wsc->next; |
|
88 |
+ _wsconn_rm(wsc); |
|
89 |
+ wsc = next; |
|
90 |
+ } |
|
91 |
+ } |
|
92 |
+ WSCONN_UNLOCK; |
|
93 |
+ |
|
94 |
+ shm_free(wsconn_hash); |
|
95 |
+ wsconn_hash = NULL; |
|
96 |
+ } |
|
97 |
+ |
|
98 |
+ if (wsconn_lock) |
|
99 |
+ { |
|
100 |
+ lock_destroy(wsconn_lock); |
|
101 |
+ lock_dealloc((void *) wsconn_lock); |
|
102 |
+ wsconn_lock = NULL; |
|
103 |
+ } |
|
104 |
+} |
|
105 |
+ |
|
106 |
+int wsconn_add(struct tcp_connection *con) |
|
107 |
+{ |
|
108 |
+ ws_connection_t *wsc; |
|
109 |
+ |
|
110 |
+ if (!con) |
|
111 |
+ { |
|
112 |
+ LM_ERR("wsconn_add: null pointer\n"); |
|
113 |
+ return -1; |
|
114 |
+ } |
|
115 |
+ |
|
116 |
+ wsc = shm_malloc(sizeof(ws_connection_t)); |
|
117 |
+ if (wsc == NULL) |
|
118 |
+ { |
|
119 |
+ LM_ERR("allocating shared memory\n"); |
|
120 |
+ return -1; |
|
121 |
+ } |
|
122 |
+ memset(wsc, 0, sizeof(ws_connection_t)); |
|
123 |
+ |
|
124 |
+ wsc->con = con; |
|
125 |
+ wsc->id_hash = con->id_hash; |
|
126 |
+ wsc->last_used = (int)time(NULL); |
|
127 |
+ wsc->state = WS_S_OPEN; |
|
128 |
+ |
|
129 |
+ /* Make sure Kamailio core sends future messages on this connection |
|
130 |
+ directly to this module */ |
|
131 |
+ con->flags |= F_CONN_WS; |
|
132 |
+ |
|
133 |
+ WSCONN_LOCK; |
|
134 |
+ wsc->next = wsconn_hash[wsc->id_hash]; |
|
135 |
+ wsc->prev = NULL; |
|
136 |
+ if (wsconn_hash[wsc->id_hash]) wsconn_hash[wsc->id_hash]->prev = wsc; |
|
137 |
+ wsconn_hash[wsc->id_hash] = wsc; |
|
138 |
+ WSCONN_UNLOCK; |
|
139 |
+ |
|
140 |
+ return 0; |
|
141 |
+} |
|
142 |
+ |
|
143 |
+static inline void _wsconn_rm(ws_connection_t *wsc) |
|
144 |
+{ |
|
145 |
+ if (wsconn_hash[wsc->id_hash] == wsc) |
|
146 |
+ wsconn_hash[wsc->id_hash] = wsc->next; |
|
147 |
+ if (wsc->next) wsc->next->prev = wsc->prev; |
|
148 |
+ if (wsc->prev) wsc->prev->next = wsc->next; |
|
149 |
+ shm_free(wsc); |
|
150 |
+ wsc = NULL; |
|
151 |
+} |
|
152 |
+ |
|
153 |
+int wsconn_rm(ws_connection_t *wsc) |
|
154 |
+{ |
|
155 |
+ if (!wsc) |
|
156 |
+ { |
|
157 |
+ LM_ERR("wsconn_rm: null pointer\n"); |
|
158 |
+ return -1; |
|
159 |
+ } |
|
160 |
+ |
|
161 |
+ WSCONN_LOCK; |
|
162 |
+ _wsconn_rm(wsc); |
|
163 |
+ WSCONN_UNLOCK; |
|
164 |
+ |
|
165 |
+ return 0; |
|
166 |
+} |
|
167 |
+ |
|
168 |
+ws_connection_t *wsconn_find(struct tcp_connection *con) |
|
169 |
+{ |
|
170 |
+ ws_connection_t *wsc; |
|
171 |
+ |
|
172 |
+ if (!con) |
|
173 |
+ { |
|
174 |
+ LM_ERR("wsconn_find: null pointer\n"); |
|
175 |
+ return NULL; |
|
176 |
+ } |
|
177 |
+ |
|
178 |
+ WSCONN_LOCK; |
|
179 |
+ for (wsc = wsconn_hash[con->id_hash]; wsc; wsc = wsc->next) |
|
180 |
+ { |
|
181 |
+ if (wsc->id_hash == con->id_hash) |
|
182 |
+ return wsc; |
|
183 |
+ } |
|
184 |
+ WSCONN_UNLOCK; |
|
185 |
+ |
|
186 |
+ return NULL; |
|
187 |
+} |
0 | 188 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,63 @@ |
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 |
+#ifndef _WS_CONN_H |
|
25 |
+#define _WS_CONN_H |
|
26 |
+ |
|
27 |
+#include "../../locking.h" |
|
28 |
+#include "../../tcp_conn.h" |
|
29 |
+ |
|
30 |
+typedef enum |
|
31 |
+{ |
|
32 |
+ WS_S_CONNECTING = 0, |
|
33 |
+ WS_S_OPEN, |
|
34 |
+ WS_S_CLOSING, |
|
35 |
+ WS_S_CLOSED |
|
36 |
+} ws_conn_state_t; |
|
37 |
+ |
|
38 |
+typedef struct ws_connection |
|
39 |
+{ |
|
40 |
+ struct tcp_connection *con; |
|
41 |
+ |
|
42 |
+ ws_conn_state_t state; |
|
43 |
+ unsigned int id_hash; |
|
44 |
+ unsigned int last_used; |
|
45 |
+ |
|
46 |
+ struct ws_connection *prev; |
|
47 |
+ struct ws_connection *next; |
|
48 |
+} ws_connection_t; |
|
49 |
+ |
|
50 |
+extern ws_connection_t **wsconn_hash; |
|
51 |
+extern gen_lock_t *wsconn_lock; |
|
52 |
+extern char *wsconn_state_str[]; |
|
53 |
+ |
|
54 |
+int wsconn_init(void); |
|
55 |
+void wsconn_destroy(void); |
|
56 |
+int wsconn_add(struct tcp_connection *con); |
|
57 |
+int wsconn_rm(ws_connection_t *wsc); |
|
58 |
+ws_connection_t *wsconn_find(struct tcp_connection *con); |
|
59 |
+ |
|
60 |
+#define WSCONN_LOCK lock_get(wsconn_lock); |
|
61 |
+#define WSCONN_UNLOCK lock_release(wsconn_lock); |
|
62 |
+ |
|
63 |
+#endif /* _WS_CONN_H */ |
... | ... |
@@ -31,9 +31,11 @@ |
31 | 31 |
#include "../../lib/kcore/kstats_wrapper.h" |
32 | 32 |
#include "../../lib/kcore/cmpapi.h" |
33 | 33 |
#include "../../lib/kmi/tree.h" |
34 |
+#include "../../mem/mem.h" |
|
34 | 35 |
#include "../../parser/msg_parser.h" |
35 | 36 |
#include "../sl/sl.h" |
36 | 37 |
#include "../tls/tls_cfg.h" |
38 |
+#include "ws_conn.h" |
|
37 | 39 |
#include "ws_handshake.h" |
38 | 40 |
#include "ws_mod.h" |
39 | 41 |
|
... | ... |
@@ -308,9 +310,8 @@ int ws_handle_handshake(struct sip_msg *msg) |
308 | 310 |
&str_status_switching_protocols, &headers) < 0) |
309 | 311 |
return 0; |
310 | 312 |
|
311 |
- /* Make sure Kamailio core sends future requests on this connection |
|
312 |
- directly to this module */ |
|
313 |
- con->flags |= F_CONN_WS; |
|
313 |
+ /* Add the connection to the WebSocket connection table */ |
|
314 |
+ wsconn_add(con); |
|
314 | 315 |
|
315 | 316 |
return 0; |
316 | 317 |
} |
... | ... |
@@ -30,7 +30,9 @@ |
30 | 30 |
#include "../../lib/kcore/kstats_wrapper.h" |
31 | 31 |
#include "../../lib/kmi/mi.h" |
32 | 32 |
#include "../../lib/kmi/tree.h" |
33 |
+#include "../../mem/mem.h" |
|
33 | 34 |
#include "../../parser/msg_parser.h" |
35 |
+#include "ws_conn.h" |
|
34 | 36 |
#include "ws_handshake.h" |
35 | 37 |
#include "ws_frame.h" |
36 | 38 |
#include "ws_mod.h" |
... | ... |
@@ -121,111 +123,133 @@ static int mod_init(void) |
121 | 123 |
if (sl_load_api(&ws_slb) != 0) |
122 | 124 |
{ |
123 | 125 |
LM_ERR("binding to SL\n"); |
124 |
- return -1; |
|
126 |
+ goto error; |
|
125 | 127 |
} |
126 | 128 |
|
127 | 129 |
if (sr_event_register_cb(SREV_TCP_WS_FRAME, ws_frame_received) != 0) |
128 | 130 |
{ |
129 | 131 |
LM_ERR("registering WebSocket call-back\n"); |
130 |
- return -1; |
|
132 |
+ goto error; |
|
131 | 133 |
} |
132 | 134 |
|
133 | 135 |
if (register_module_stats(exports.name, stats) != 0) |
134 | 136 |
{ |
135 | 137 |
LM_ERR("registering core statistics\n"); |
136 |
- return -1; |
|
138 |
+ goto error; |
|
137 | 139 |
} |
138 | 140 |
|
139 | 141 |
if (register_mi_mod(exports.name, mi_cmds) != 0) |
140 | 142 |
{ |
141 | 143 |
LM_ERR("registering MI commands\n"); |
142 |
- return -1; |
|
144 |
+ goto error; |
|
145 |
+ } |
|
146 |
+ |
|
147 |
+ if (wsconn_init() < 0) |
|
148 |
+ { |
|
149 |
+ LM_ERR("initialising WebSocket connections table\n"); |
|
150 |
+ goto error; |
|
143 | 151 |
} |
144 | 152 |
|
145 | 153 |
if ((ws_enabled = (int *) shm_malloc(sizeof(int))) == NULL) |
146 | 154 |
{ |
147 | 155 |
LM_ERR("allocating shared memory\n"); |
148 |
- return -1; |
|
156 |
+ goto error; |
|
149 | 157 |
} |
150 | 158 |
*ws_enabled = 1; |
151 | 159 |
|
160 |
+ if (wsconn_init() < 0) |
|
161 |
+ { |
|
162 |
+ LM_ERR("initialising WebSocket connections table\n"); |
|
163 |
+ goto error; |
|
164 |
+ } |
|
165 |
+ |
|
152 | 166 |
if ((ws_stats_lock = lock_alloc()) == NULL) |
153 | 167 |
{ |
154 | 168 |
LM_ERR("allocating lock\n"); |
155 |
- return -1; |
|
169 |
+ goto error; |
|
156 | 170 |
} |
157 | 171 |
if (lock_init(ws_stats_lock) == NULL) |
158 | 172 |
{ |
159 | 173 |
LM_ERR("initialising lock\n"); |
160 |
- lock_dealloc(ws_stats_lock); |
|
161 |
- return -1; |
|
174 |
+ goto error; |
|
162 | 175 |
} |
163 | 176 |
|
164 |
- /* TODO: register module with core to receive WS/WSS messages */ |
|
165 |
- |
|
166 | 177 |
return 0; |
178 |
+ |
|
179 |
+error: |
|
180 |
+ wsconn_destroy(); |
|
181 |
+ |
|
182 |
+ if (ws_stats_lock) |
|
183 |
+ lock_dealloc(ws_stats_lock); |
|
184 |
+ |
|
185 |
+ shm_free(ws_enabled); |
|
186 |
+ |
|
187 |
+ return -1; |
|
167 | 188 |
} |
168 | 189 |
|
169 | 190 |
static void destroy(void) |
170 | 191 |
{ |
192 |
+ wsconn_destroy(); |
|
171 | 193 |
shm_free(ws_enabled); |
172 | 194 |
lock_destroy(ws_stats_lock); |
173 | 195 |
lock_dealloc(ws_stats_lock); |
174 |
- |
|
175 |
- /* TODO: close all connections */ |
|
176 | 196 |
} |
177 | 197 |
|
178 | 198 |
static struct mi_root *mi_dump(struct mi_root *cmd, void *param) |
179 | 199 |
{ |
180 |
- int h, connections = 0; |
|
200 |
+ int h, connections = 0, interval; |
|
181 | 201 |
char *src_proto, *dst_proto; |
182 | 202 |
char src_ip[IP6_MAX_STR_SIZE + 1], dst_ip[IP6_MAX_STR_SIZE + 1]; |
183 |
- struct tcp_connection *c; |
|
203 |
+ ws_connection_t *wsc; |
|
184 | 204 |
struct mi_root *rpl_tree = init_mi_tree(200, MI_OK_S, MI_OK_LEN); |
185 | 205 |
|
186 | 206 |
if (!rpl_tree) |
187 | 207 |
return 0; |
188 | 208 |
|
189 |
- TCPCONN_LOCK; |
|
209 |
+ WSCONN_LOCK; |
|
190 | 210 |
for (h = 0; h < TCP_ID_HASH_SIZE; h++) |
191 | 211 |
{ |
192 |
- c = tcpconn_id_hash[h]; |
|
193 |
- while(c) |
|
212 |
+ wsc = wsconn_hash[h]; |
|
213 |
+ while(wsc) |
|
194 | 214 |
{ |
195 |
- if (c->flags & F_CONN_WS) |
|
215 |
+ if (wsc->con) |
|
196 | 216 |
{ |
197 |
- src_proto = (c->rcv.proto== PROTO_TCP) |
|
217 |
+ src_proto = (wsc->con->rcv.proto== PROTO_TCP) |
|
198 | 218 |
? "tcp" : "tls"; |
199 | 219 |
memset(src_ip, 0, IP6_MAX_STR_SIZE + 1); |
200 |
- ip_addr2sbuf(&c->rcv.src_ip, src_ip, |
|
220 |
+ ip_addr2sbuf(&wsc->con->rcv.src_ip, src_ip, |
|
201 | 221 |
IP6_MAX_STR_SIZE); |
202 | 222 |
|
203 |
- dst_proto = (c->rcv.proto == PROTO_TCP) |
|
223 |
+ dst_proto = (wsc->con->rcv.proto == PROTO_TCP) |
|
204 | 224 |
? "tcp" : "tls"; |
205 | 225 |
memset(dst_ip, 0, IP6_MAX_STR_SIZE + 1); |
206 |
- ip_addr2sbuf(&c->rcv.dst_ip, src_ip, |
|
226 |
+ ip_addr2sbuf(&wsc->con->rcv.dst_ip, src_ip, |
|
207 | 227 |
IP6_MAX_STR_SIZE); |
208 | 228 |
|
229 |
+ interval = (int)time(NULL) - wsc->last_used; |
|
230 |
+ |
|
209 | 231 |
if (addf_mi_node_child(&rpl_tree->node, 0, 0, 0, |
210 |
- "id - %d, " |
|
211 |
- "src - %s:%s:%hu, " |
|
212 |
- "dst - %s:%s:%hu", |
|
213 |
- c->id, |
|
232 |
+ "%d: %s:%s:%hu -> %s:%s:%hu " |
|
233 |
+ "(state: %s, " |
|
234 |
+ "last used %ds ago)", |
|
235 |
+ wsc->con->id, |
|
214 | 236 |
src_proto, |
215 | 237 |
strlen(src_ip) ? src_ip : "*", |
216 |
- c->rcv.src_port, |
|
238 |
+ wsc->con->rcv.src_port, |
|
217 | 239 |
dst_proto, |
218 | 240 |
strlen(dst_ip) ? dst_ip : "*", |
219 |
- c->rcv.dst_port) == 0) |
|
241 |
+ wsc->con->rcv.dst_port, |
|
242 |
+ wsconn_state_str[wsc->state], |
|
243 |
+ interval) == 0) |
|
220 | 244 |
return 0; |
221 | 245 |
|
222 | 246 |
connections++; |
223 | 247 |
} |
224 | 248 |
|
225 |
- c = c->id_next; |
|
249 |
+ wsc = wsc->next; |
|
226 | 250 |
} |
227 | 251 |
} |
228 |
- TCPCONN_UNLOCK; |
|
252 |
+ WSCONN_UNLOCK; |
|
229 | 253 |
|
230 | 254 |
if (addf_mi_node_child(&rpl_tree->node, 0, 0, 0, |
231 | 255 |
"%d WebSocket connection%s found", |