Browse code

modules/websocket: Added ws_close() exported function

- Enables immediate closure of a WebSocket connection from the configuration
file.

Peter Dunkley authored on 10/05/2013 19:04:02
Showing 5 changed files
... ...
@@ -36,6 +36,7 @@ Peter Dunkley
36 36
         5. Functions
37 37
 
38 38
               5.1. ws_handle_handshake()
39
+              5.2. ws_close([status, reason[, connection_id]])
39 40
 
40 41
         6. MI Commands
41 42
 
... ...
@@ -62,7 +63,8 @@ Peter Dunkley
62 63
    1.8. Set sub_protocols parameter
63 64
    1.9. Set cors_mode parameter
64 65
    1.10. ws_handle_handshake usage
65
-   1.11. event_route[websocket:closed] usage
66
+   1.11. ws_close usage
67
+   1.12. event_route[websocket:closed] usage
66 68
 
67 69
 Chapter 1. Admin Guide
68 70
 
... ...
@@ -93,6 +95,7 @@ Chapter 1. Admin Guide
93 95
    5. Functions
94 96
 
95 97
         5.1. ws_handle_handshake()
98
+        5.2. ws_close([status, reason[, connection_id]])
96 99
 
97 100
    6. MI Commands
98 101
 
... ...
@@ -239,8 +242,7 @@ request_route {
239 242
                         fix_nated_register();
240 243
                 else {
241 244
                         if (!add_contact_alias()) {
242
-                                xlog("L_ERR", "Error aliasing contact <$ct>\n")
243
-;
245
+                                xlog("L_ERR", "Error aliasing contact <$ct>\n");
244 246
                                 sl_send_reply("400", "Bad Request");
245 247
                                 exit;
246 248
                         }
... ...
@@ -433,6 +435,7 @@ modparam("websocket", "cors_mode", 2)
433 435
 5. Functions
434 436
 
435 437
    5.1. ws_handle_handshake()
438
+   5.2. ws_close([status, reason[, connection_id]])
436 439
 
437 440
 5.1.  ws_handle_handshake()
438 441
 
... ...
@@ -453,6 +456,31 @@ Note
453 456
 ws_handle_handshake();
454 457
 ...
455 458
 
459
+5.2.  ws_close([status, reason[, connection_id]])
460
+
461
+   This function closes a WebSocket connection.
462
+
463
+   The function returns -1 if there is an error and 1 if it succeeds.
464
+
465
+   The meaning of the parameters is as follows:
466
+     * status - an integer indicating the reason for closure.
467
+     * reason - a string describing the reason for closure.
468
+     * connection_id - the connection to close. If not specified the
469
+       connection the current message arrived on will be closed.
470
+
471
+Note
472
+
473
+   status and reason values SHOULD correspond to the definitions in
474
+   section 7.4 of RFC 6455. If these parameters are not used the defaults
475
+   of "1000" and "Normal closure" will be used.
476
+
477
+   This function can be used from ANY_ROUTE.
478
+
479
+   Example 1.11. ws_close usage
480
+...
481
+ws_close(4000, "Because I say so");
482
+...
483
+
456 484
 6. MI Commands
457 485
 
458 486
    6.1. ws.dump
... ...
@@ -560,7 +588,7 @@ Note
560 588
    connection closes. The connection may be identified using the the $si
561 589
    and $sp pseudo-variables.
562 590
 
563
-   Example 1.11. event_route[websocket:closed] usage
591
+   Example 1.12. event_route[websocket:closed] usage
564 592
 ...
565 593
 event_route[websocket:closed] {
566 594
         xlog("L_INFO", "WebSocket connection from $si:$sp has closed\n");
... ...
@@ -454,6 +454,42 @@ modparam("websocket", "cors_mode", 2)
454 454
 ...
455 455
 ws_handle_handshake();
456 456
 ...
457
+</programlisting>
458
+		</example>
459
+	</section>
460
+	<section id="websocket.f.ws_close">
461
+		<title>
462
+		<function moreinfo="none">ws_close([status,
463
+			reason[, connection_id]])</function>
464
+		</title>
465
+		<para>This function closes a WebSocket connection.</para>
466
+		<para>The function returns -1 if there is an error and 1 if
467
+		it succeeds.</para>
468
+		<para>The meaning of the parameters is as follows:</para>
469
+		<itemizedlist>
470
+			<listitem><para><emphasis>status</emphasis> - an
471
+			integer indicating the reason for closure.</para>
472
+			</listitem>
473
+			<listitem><para><emphasis>reason</emphasis> - a
474
+			string describing the reason for closure.</para>
475
+			</listitem>
476
+			<listitem><para><emphasis>connection_id</emphasis> - the
477
+			connection to close. If not specified the connection the
478
+			current message arrived on will be closed.</para>
479
+			</listitem>
480
+		</itemizedlist>
481
+		<note><para><emphasis>status</emphasis> and
482
+		<emphasis>reason</emphasis> values SHOULD correspond to the
483
+		definitions in section 7.4 of RFC 6455. If these parameters are
484
+		not used the defaults of &quot;1000&quot; and &quot;Normal
485
+		closure&quot; will be used.</para></note>
486
+		<para>This function can be used from ANY_ROUTE.</para>
487
+		<example>
488
+		<title><function>ws_close</function> usage</title>
489
+		<programlisting format="linespecific">
490
+...
491
+ws_close(4000, "Because I say so");
492
+...
457 493
 </programlisting>
458 494
 		</example>
459 495
 	</section>
... ...
@@ -831,3 +831,70 @@ void ws_keepalive(unsigned int ticks, void *param)
831 831
 	}
832 832
 	
833 833
 }
834
+
835
+int ws_close(sip_msg_t *msg)
836
+{
837
+	ws_connection_t *wsc;
838
+
839
+	if ((wsc = wsconn_get(msg->rcv.proto_reserved1)) == NULL) {
840
+		LM_ERR("failed to retrieve WebSocket connection\n");
841
+		return -1;
842
+	}
843
+
844
+	return (close_connection(wsc, LOCAL_CLOSE, 1000,
845
+				 str_status_normal_closure) == 0) ? 1: 0;
846
+}
847
+
848
+int ws_close2(sip_msg_t *msg, char *_status, char *_reason)
849
+{
850
+	int status;
851
+	str reason;
852
+	ws_connection_t *wsc;
853
+
854
+	if (get_int_fparam(&status, msg, (fparam_t *) _status) < 0) {
855
+		LM_ERR("failed to get status code\n");
856
+		return -1;
857
+	}
858
+
859
+	if (get_str_fparam(&reason, msg, (fparam_t *) _reason) < 0) {
860
+		LM_ERR("failed to get reason string\n");
861
+		return -1;
862
+	}
863
+
864
+	if ((wsc = wsconn_get(msg->rcv.proto_reserved1)) == NULL) {
865
+		LM_ERR("failed to retrieve WebSocket connection\n");
866
+		return -1;
867
+	}
868
+
869
+	return (close_connection(wsc, LOCAL_CLOSE, status, reason) == 0) ? 1: 0;
870
+}
871
+
872
+int ws_close3(sip_msg_t *msg, char *_status, char *_reason, char *_con)
873
+{
874
+	int status;
875
+	str reason;
876
+	int con;
877
+	ws_connection_t *wsc;
878
+
879
+	if (get_int_fparam(&status, msg, (fparam_t *) _status) < 0) {
880
+		LM_ERR("failed to get status code\n");
881
+		return -1;
882
+	}
883
+
884
+	if (get_str_fparam(&reason, msg, (fparam_t *) _reason) < 0) {
885
+		LM_ERR("failed to get reason string\n");
886
+		return -1;
887
+	}
888
+
889
+	if (get_int_fparam(&con, msg, (fparam_t *) _con) < 0) {
890
+		LM_ERR("failed to get connection ID\n");
891
+		return -1;
892
+	}
893
+
894
+	if ((wsc = wsconn_get(con)) == NULL) {
895
+		LM_ERR("failed to retrieve WebSocket connection\n");
896
+		return -1;
897
+	}
898
+
899
+	return (close_connection(wsc, LOCAL_CLOSE, status, reason) == 0) ? 1: 0;
900
+}
... ...
@@ -73,5 +73,8 @@ struct mi_root *ws_mi_close(struct mi_root *cmd, void *param);
73 73
 struct mi_root *ws_mi_ping(struct mi_root *cmd, void *param);
74 74
 struct mi_root *ws_mi_pong(struct mi_root *cmd, void *param);
75 75
 void ws_keepalive(unsigned int ticks, void *param);
76
+int ws_close(sip_msg_t *msg);
77
+int ws_close2(sip_msg_t *msg, char *_status, char *_reason);
78
+int ws_close3(sip_msg_t *msg, char *_status, char *_reason, char *_con);
76 79
 
77 80
 #endif /* _WS_FRAME_H */
... ...
@@ -32,6 +32,7 @@
32 32
 #include "../../lib/kcore/kstats_wrapper.h"
33 33
 #include "../../lib/kmi/mi.h"
34 34
 #include "../../mem/mem.h"
35
+#include "../../mod_fix.h"
35 36
 #include "../../parser/msg_parser.h"
36 37
 #include "ws_conn.h"
37 38
 #include "ws_handshake.h"
... ...
@@ -47,6 +48,7 @@ MODULE_VERSION
47 48
 static int mod_init(void);
48 49
 static int child_init(int rank);
49 50
 static void destroy(void);
51
+static int ws_close_fixup(void** param, int param_no);
50 52
 
51 53
 sl_api_t ws_slb;
52 54
 
... ...
@@ -60,6 +62,17 @@ static int ws_keepalive_processes = DEFAULT_KEEPALIVE_PROCESSES;
60 62
 
61 63
 static cmd_export_t cmds[]= 
62 64
 {
65
+	/* ws_frame.c */
66
+	{ "ws_close", (cmd_function) ws_close,
67
+	  0, 0, 0,
68
+	  ANY_ROUTE },
69
+	{ "ws_close", (cmd_function) ws_close2,
70
+	  2, ws_close_fixup, 0,
71
+	  ANY_ROUTE },
72
+	{ "ws_close", (cmd_function) ws_close3,
73
+	  3, ws_close_fixup, 0,
74
+	  ANY_ROUTE },
75
+
63 76
 	/* ws_handshake.c */
64 77
 	{ "ws_handle_handshake", (cmd_function) ws_handle_handshake,
65 78
 	  0, 0, 0,
... ...
@@ -295,3 +308,16 @@ static void destroy(void)
295 308
 {
296 309
 	wsconn_destroy();
297 310
 }
311
+
312
+static int ws_close_fixup(void** param, int param_no)
313
+{
314
+	switch(param_no) {
315
+	case 1:
316
+	case 3:
317
+		return fixup_var_int_1(param, 1);
318
+	case 2:
319
+		return fixup_spve_null(param, 1);
320
+	default:
321
+		return 0;
322
+	}
323
+}