diff --git a/src/modules/websocket/config.c b/src/modules/websocket/config.c index faa081c623e..74ea1d72e4b 100644 --- a/src/modules/websocket/config.c +++ b/src/modules/websocket/config.c @@ -34,26 +34,21 @@ #include "ws_frame.h" #include "config.h" -struct cfg_group_websocket default_ws_cfg = -{ - DEFAULT_KEEPALIVE_TIMEOUT, /* keepalive_timeout */ - 1 /* enabled */ +struct cfg_group_websocket default_ws_cfg = { + DEFAULT_KEEPALIVE_TIMEOUT, /* keepalive_timeout */ + 1 /* enabled */ }; void *ws_cfg = &default_ws_cfg; -cfg_def_t ws_cfg_def[] = -{ - /* ws_frame.c */ - { "keepalive_timeout", CFG_VAR_INT | CFG_ATOMIC, - 0, 0, 0, 0, - "Time (in seconds) after which to send a keep-alive on idle" - " WebSocket connections." }, +cfg_def_t ws_cfg_def[] = { + /* ws_frame.c */ + {"keepalive_timeout", CFG_VAR_INT | CFG_ATOMIC, 0, 0, 0, 0, + "Time (in seconds) after which to send a keep-alive on idle" + " WebSocket connections."}, - /* ws_handshake.c */ - { "enabled", CFG_VAR_INT | CFG_ATOMIC, - 0, 0, 0, 0, - "Shows whether WebSockets are enabled or not." }, + /* ws_handshake.c */ + {"enabled", CFG_VAR_INT | CFG_ATOMIC, 0, 0, 0, 0, + "Shows whether WebSockets are enabled or not."}, - { 0, 0, 0, 0, 0, 0 } -}; + {0, 0, 0, 0, 0, 0}}; diff --git a/src/modules/websocket/utf8_decode.h b/src/modules/websocket/utf8_decode.h index 617f8970f8d..33c0ccf55f8 100644 --- a/src/modules/websocket/utf8_decode.h +++ b/src/modules/websocket/utf8_decode.h @@ -37,18 +37,18 @@ static const uint8_t utf8d[] = { // The first part of the table maps bytes to character classes that // to reduce the size of the transition table and create bitmasks. - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, - 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, - 8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 8, 8,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8, // The second part is a transition table that maps a combination // of a state of the automaton and a character class to a state. - 0,12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12, + 0, 12,24,36,60,96,84,12,12,12,48,72, 12,12,12,12,12,12,12,12,12,12,12,12, 12, 0,12,12,12,12,12, 0,12, 0,12,12, 12,24,12,12,12,12,12,24,12,24,12,12, 12,12,12,12,12,12,12,24,12,12,12,12, 12,24,12,12,12,12,12,12,12,24,12,12, 12,12,12,12,12,12,12,36,12,36,12,12, 12,36,12,12,12,12,12,36,12,36,12,12, diff --git a/src/modules/websocket/websocket.c b/src/modules/websocket/websocket.c index 6eaed99ddfa..4a76cac48b5 100644 --- a/src/modules/websocket/websocket.c +++ b/src/modules/websocket/websocket.c @@ -48,30 +48,31 @@ MODULE_VERSION /* Maximum number of connections to display when using the ws.dump command */ -#define MAX_WS_CONNS_DUMP 50 +#define MAX_WS_CONNS_DUMP 50 static int mod_init(void); static int child_init(int rank); static void destroy(void); -static int ws_close_fixup(void** param, int param_no); +static int ws_close_fixup(void **param, int param_no); static int pv_get_ws_conid_f(struct sip_msg *, pv_param_t *, pv_value_t *); static int ws_init_rpc(void); sl_api_t ws_slb; -#define DEFAULT_KEEPALIVE_INTERVAL 1 +#define DEFAULT_KEEPALIVE_INTERVAL 1 static int ws_keepalive_interval = DEFAULT_KEEPALIVE_INTERVAL; static int ws_keepalive_timeout = DEFAULT_KEEPALIVE_TIMEOUT; -#define DEFAULT_KEEPALIVE_PROCESSES 1 +#define DEFAULT_KEEPALIVE_PROCESSES 1 static int ws_keepalive_processes = DEFAULT_KEEPALIVE_PROCESSES; int ws_verbose_list = 0; str ws_event_callback = STR_NULL; +/* clang-format off */ static cmd_export_t cmds[] = { /* ws_frame.c */ { "ws_close", (cmd_function)w_ws_close0, @@ -167,121 +168,104 @@ struct module_exports exports = { destroy, /* destroy function */ child_init /* per-child initialization function */ }; +/* clang-format on */ static int mod_init(void) { - if (sl_load_api(&ws_slb) != 0) - { + if(sl_load_api(&ws_slb) != 0) { LM_ERR("binding to SL\n"); goto error; } - if (sr_event_register_cb(SREV_TCP_WS_FRAME_IN, ws_frame_receive) != 0) - { + if(sr_event_register_cb(SREV_TCP_WS_FRAME_IN, ws_frame_receive) != 0) { LM_ERR("registering WebSocket receive call-back\n"); goto error; } - if (sr_event_register_cb(SREV_TCP_WS_FRAME_OUT, ws_frame_transmit) != 0) - { + if(sr_event_register_cb(SREV_TCP_WS_FRAME_OUT, ws_frame_transmit) != 0) { LM_ERR("registering WebSocket transmit call-back\n"); goto error; } - if (register_module_stats(exports.name, stats) != 0) - { + if(register_module_stats(exports.name, stats) != 0) { LM_ERR("registering core statistics\n"); goto error; } - if(ws_init_rpc()<0) - { + if(ws_init_rpc() < 0) { LM_ERR("failed to register RPC commands\n"); return -1; } - if (wsconn_init() < 0) - { + if(wsconn_init() < 0) { LM_ERR("initialising WebSocket connections table\n"); goto error; } - if (ws_ping_application_data.len < 1 - || ws_ping_application_data.len > 125) - { + if(ws_ping_application_data.len < 1 || ws_ping_application_data.len > 125) { ws_ping_application_data.s = DEFAULT_PING_APPLICATION_DATA + 8; - ws_ping_application_data.len = - DEFAULT_PING_APPLICATION_DATA_LEN - 8; + ws_ping_application_data.len = DEFAULT_PING_APPLICATION_DATA_LEN - 8; } - if (ws_keepalive_mechanism != KEEPALIVE_MECHANISM_NONE) - { - if (ws_keepalive_timeout < 1 || ws_keepalive_timeout > 3600) + if(ws_keepalive_mechanism != KEEPALIVE_MECHANISM_NONE) { + if(ws_keepalive_timeout < 1 || ws_keepalive_timeout > 3600) ws_keepalive_timeout = DEFAULT_KEEPALIVE_TIMEOUT; - switch(ws_keepalive_mechanism) - { - case KEEPALIVE_MECHANISM_PING: - case KEEPALIVE_MECHANISM_PONG: - break; - default: - ws_keepalive_mechanism = DEFAULT_KEEPALIVE_MECHANISM; - break; + switch(ws_keepalive_mechanism) { + case KEEPALIVE_MECHANISM_PING: + case KEEPALIVE_MECHANISM_PONG: + break; + default: + ws_keepalive_mechanism = DEFAULT_KEEPALIVE_MECHANISM; + break; } - if (ws_keepalive_interval < 1 || ws_keepalive_interval > 60) + if(ws_keepalive_interval < 1 || ws_keepalive_interval > 60) ws_keepalive_interval = DEFAULT_KEEPALIVE_INTERVAL; - if (ws_keepalive_processes < 1 || ws_keepalive_processes > 16) + if(ws_keepalive_processes < 1 || ws_keepalive_processes > 16) ws_keepalive_processes = DEFAULT_KEEPALIVE_PROCESSES; /* Add extra process/timer for the keepalive process */ register_sync_timers(ws_keepalive_processes); } - if (ws_sub_protocols & SUB_PROTOCOL_MSRP - && !sr_event_enabled(SREV_TCP_MSRP_FRAME)) + if(ws_sub_protocols & SUB_PROTOCOL_MSRP + && !sr_event_enabled(SREV_TCP_MSRP_FRAME)) ws_sub_protocols &= ~SUB_PROTOCOL_MSRP; - if ((ws_sub_protocols & SUB_PROTOCOL_ALL) == 0) - { + if((ws_sub_protocols & SUB_PROTOCOL_ALL) == 0) { LM_ERR("no sub-protocols enabled\n"); goto error; } - if ((ws_sub_protocols | SUB_PROTOCOL_ALL) != SUB_PROTOCOL_ALL) - { + if((ws_sub_protocols | SUB_PROTOCOL_ALL) != SUB_PROTOCOL_ALL) { LM_ERR("unrecognised sub-protocols enabled\n"); goto error; } - if (ws_cors_mode < 0 || ws_cors_mode > 2) - { + if(ws_cors_mode < 0 || ws_cors_mode > 2) { LM_ERR("bad value for cors_mode\n"); goto error; } - if (cfg_declare("websocket", ws_cfg_def, &default_ws_cfg, - cfg_sizeof(websocket), &ws_cfg)) - { + if(cfg_declare("websocket", ws_cfg_def, &default_ws_cfg, + cfg_sizeof(websocket), &ws_cfg)) { LM_ERR("declaring configuration\n"); return -1; } cfg_get(websocket, ws_cfg, keepalive_timeout) = ws_keepalive_timeout; - if (!module_loaded("xhttp")) - { + if(!module_loaded("xhttp")) { LM_ERR("\"xhttp\" must be loaded to use WebSocket.\n"); return -1; } - if (((ws_sub_protocols & SUB_PROTOCOL_SIP) == SUB_PROTOCOL_SIP) - && !module_loaded("nathelper") - && !module_loaded("outbound")) - { + if(((ws_sub_protocols & SUB_PROTOCOL_SIP) == SUB_PROTOCOL_SIP) + && !module_loaded("nathelper") && !module_loaded("outbound")) { LM_WARN("neither \"nathelper\" nor \"outbound\" modules are" - " loaded. At least one of these is required for correct" - " routing of SIP over WebSocket.\n"); + " loaded. At least one of these is required for correct" + " routing of SIP over WebSocket.\n"); } return 0; @@ -295,23 +279,19 @@ static int child_init(int rank) { int i; - if (rank == PROC_INIT || rank == PROC_TCP_MAIN) + if(rank == PROC_INIT || rank == PROC_TCP_MAIN) return 0; - if (rank == PROC_MAIN - && ws_keepalive_mechanism != KEEPALIVE_MECHANISM_NONE) - { - for (i = 0; i < ws_keepalive_processes; i++) - { - if (fork_sync_timer(PROC_TIMER, "WEBSOCKET KEEPALIVE", - 1, ws_keepalive, NULL, - ws_keepalive_interval) < 0) - { + if(rank == PROC_MAIN + && ws_keepalive_mechanism != KEEPALIVE_MECHANISM_NONE) { + for(i = 0; i < ws_keepalive_processes; i++) { + if(fork_sync_timer(PROC_TIMER, "WEBSOCKET KEEPALIVE", 1, + ws_keepalive, NULL, ws_keepalive_interval) + < 0) { LM_ERR("starting keepalive process\n"); return -1; } } - } return 0; @@ -322,27 +302,29 @@ static void destroy(void) wsconn_destroy(); } -static int ws_close_fixup(void** param, int param_no) +static int ws_close_fixup(void **param, int param_no) { switch(param_no) { - case 1: - case 3: - return fixup_var_int_1(param, 1); - case 2: - return fixup_spve_null(param, 1); - default: - return 0; + case 1: + case 3: + return fixup_var_int_1(param, 1); + case 2: + return fixup_spve_null(param, 1); + default: + return 0; } } -static int pv_get_ws_conid_f(struct sip_msg *msg, pv_param_t *param, - pv_value_t *res) +static int pv_get_ws_conid_f( + struct sip_msg *msg, pv_param_t *param, pv_value_t *res) { - if (msg == NULL) return -1; + if(msg == NULL) + return -1; - return pv_get_sintval(msg, param, res, msg->rcv.proto_reserved1); + return pv_get_sintval(msg, param, res, msg->rcv.proto_reserved1); } +/* clang-format off */ static const char* ws_rpc_dump_doc[2] = { "List websocket connections", 0 @@ -382,14 +364,14 @@ rpc_export_t ws_rpc_cmds[] = { {"ws.disable", ws_rpc_disable, ws_rpc_disable_doc, 0}, {0, 0, 0, 0} }; +/* clang-format on */ /** * register RPC commands */ static int ws_init_rpc(void) { - if (rpc_register_array(ws_rpc_cmds)!=0) - { + if(rpc_register_array(ws_rpc_cmds) != 0) { LM_ERR("failed to register RPC commands\n"); return -1; } diff --git a/src/modules/websocket/websocket.h b/src/modules/websocket/websocket.h index b7cf7e4bdf0..8f8079534f0 100644 --- a/src/modules/websocket/websocket.h +++ b/src/modules/websocket/websocket.h @@ -33,13 +33,13 @@ enum { - SUB_PROTOCOL_SIP = (1 << 0), + SUB_PROTOCOL_SIP = (1 << 0), SUB_PROTOCOL_MSRP = (1 << 1) }; extern sl_api_t ws_slb; extern gen_lock_t *ws_stats_lock; -extern int ws_ping_interval; /* time (in seconds) between sending Pings */ +extern int ws_ping_interval; /* time (in seconds) between sending Pings */ #endif /* _WEBSOCKET_H */ diff --git a/src/modules/websocket/ws_conn.c b/src/modules/websocket/ws_conn.c index 786d87dc502..b3ea15e50e3 100644 --- a/src/modules/websocket/ws_conn.c +++ b/src/modules/websocket/ws_conn.c @@ -35,20 +35,20 @@ #include "websocket.h" /* Maximum number of connections to display when using the ws.dump command */ -#define MAX_WS_CONNS_DUMP 50 +#define MAX_WS_CONNS_DUMP 50 extern int ws_verbose_list; extern str ws_event_callback; ws_connection_t **wsconn_id_hash = NULL; -#define wsconn_listadd tcpconn_listadd -#define wsconn_listrm tcpconn_listrm +#define wsconn_listadd tcpconn_listadd +#define wsconn_listrm tcpconn_listrm gen_lock_t *wsconn_lock = NULL; -#define WSCONN_LOCK lock_get(wsconn_lock) -#define WSCONN_UNLOCK lock_release(wsconn_lock) +#define WSCONN_LOCK lock_get(wsconn_lock) +#define WSCONN_UNLOCK lock_release(wsconn_lock) -#define wsconn_ref(c) atomic_inc(&((c)->refcnt)) +#define wsconn_ref(c) atomic_inc(&((c)->refcnt)) #define wsconn_unref(c) atomic_dec_and_test(&((c)->refcnt)) gen_lock_t *wsstat_lock = NULL; @@ -62,12 +62,11 @@ stat_var *ws_sip_max_concurrent_connections; stat_var *ws_msrp_current_connections; stat_var *ws_msrp_max_concurrent_connections; -char *wsconn_state_str[] = -{ - "CONNECTING", /* WS_S_CONNECTING */ - "OPEN", /* WS_S_OPEN */ - "CLOSING", /* WS_S_CLOSING */ - "CLOSED" /* WS_S_CLOSED */ +char *wsconn_state_str[] = { + "CONNECTING", /* WS_S_CONNECTING */ + "OPEN", /* WS_S_OPEN */ + "CLOSING", /* WS_S_CLOSING */ + "CLOSED" /* WS_S_CLOSED */ }; /* RPC command status text */ @@ -76,58 +75,55 @@ static str str_status_bad_param = str_init("Bad display order parameter"); int wsconn_init(void) { wsconn_lock = lock_alloc(); - if (wsconn_lock == NULL) - { + if(wsconn_lock == NULL) { LM_ERR("allocating lock\n"); goto error; } - if (lock_init(wsconn_lock) == 0) - { + if(lock_init(wsconn_lock) == 0) { LM_ERR("initialising lock\n"); goto error; } wsstat_lock = lock_alloc(); - if (wsstat_lock == NULL) - { + if(wsstat_lock == NULL) { LM_ERR("allocating lock\n"); goto error; } - if (lock_init(wsstat_lock) == NULL) - { + if(lock_init(wsstat_lock) == NULL) { LM_ERR("initialising lock\n"); goto error; } - wsconn_id_hash = - (ws_connection_t **) shm_malloc(TCP_ID_HASH_SIZE * - sizeof(ws_connection_t*)); - if (wsconn_id_hash == NULL) - { + wsconn_id_hash = (ws_connection_t **)shm_malloc( + TCP_ID_HASH_SIZE * sizeof(ws_connection_t *)); + if(wsconn_id_hash == NULL) { LM_ERR("allocating WebSocket hash-table\n"); goto error; } - memset((void *) wsconn_id_hash, 0, - TCP_ID_HASH_SIZE * sizeof(ws_connection_t *)); + memset((void *)wsconn_id_hash, 0, + TCP_ID_HASH_SIZE * sizeof(ws_connection_t *)); - wsconn_used_list = (ws_connection_used_list_t *) shm_malloc( - sizeof(ws_connection_used_list_t)); - if (wsconn_used_list == NULL) - { + wsconn_used_list = (ws_connection_used_list_t *)shm_malloc( + sizeof(ws_connection_used_list_t)); + if(wsconn_used_list == NULL) { LM_ERR("allocating WebSocket used list\n"); goto error; } - memset((void *) wsconn_used_list, 0, sizeof(ws_connection_used_list_t)); + memset((void *)wsconn_used_list, 0, sizeof(ws_connection_used_list_t)); return 0; error: - if (wsconn_lock) lock_dealloc((void *) wsconn_lock); - if (wsstat_lock) lock_dealloc((void *) wsstat_lock); + if(wsconn_lock) + lock_dealloc((void *)wsconn_lock); + if(wsstat_lock) + lock_dealloc((void *)wsstat_lock); wsconn_lock = wsstat_lock = NULL; - if (wsconn_id_hash) shm_free(wsconn_id_hash); - if (wsconn_used_list) shm_free(wsconn_used_list); + if(wsconn_id_hash) + shm_free(wsconn_id_hash); + if(wsconn_used_list) + shm_free(wsconn_used_list); wsconn_id_hash = NULL; wsconn_used_list = NULL; @@ -139,9 +135,9 @@ static inline void _wsconn_rm(ws_connection_t *wsc) wsconn_listrm(wsconn_id_hash[wsc->id_hash], wsc, id_next, id_prev); update_stat(ws_current_connections, -1); - if (wsc->sub_protocol == SUB_PROTOCOL_SIP) + if(wsc->sub_protocol == SUB_PROTOCOL_SIP) update_stat(ws_sip_current_connections, -1); - else if (wsc->sub_protocol == SUB_PROTOCOL_MSRP) + else if(wsc->sub_protocol == SUB_PROTOCOL_MSRP) update_stat(ws_msrp_current_connections, -1); shm_free(wsc); @@ -151,21 +147,17 @@ void wsconn_destroy(void) { int h; - if (wsconn_used_list) - { + if(wsconn_used_list) { shm_free(wsconn_used_list); wsconn_used_list = NULL; } - if (wsconn_id_hash) - { + if(wsconn_id_hash) { WSCONN_UNLOCK; WSCONN_LOCK; - for (h = 0; h < TCP_ID_HASH_SIZE; h++) - { + for(h = 0; h < TCP_ID_HASH_SIZE; h++) { ws_connection_t *wsc = wsconn_id_hash[h]; - while (wsc) - { + while(wsc) { ws_connection_t *next = wsc->id_next; _wsconn_rm(wsc); wsc = next; @@ -177,17 +169,15 @@ void wsconn_destroy(void) wsconn_id_hash = NULL; } - if (wsconn_lock) - { + if(wsconn_lock) { lock_destroy(wsconn_lock); - lock_dealloc((void *) wsconn_lock); + lock_dealloc((void *)wsconn_lock); wsconn_lock = NULL; } - if (wsstat_lock) - { + if(wsstat_lock) { lock_destroy(wsstat_lock); - lock_dealloc((void *) wsstat_lock); + lock_dealloc((void *)wsstat_lock); wsstat_lock = NULL; } } @@ -203,8 +193,7 @@ int wsconn_add(struct receive_info rcv, unsigned int sub_protocol) /* Allocate and fill in new WebSocket connection */ wsc = shm_malloc(sizeof(ws_connection_t) + BUF_SIZE + 1); - if (wsc == NULL) - { + if(wsc == NULL) { LM_ERR("allocating shared memory\n"); return -1; } @@ -215,10 +204,11 @@ int wsconn_add(struct receive_info rcv, unsigned int sub_protocol) wsc->rcv = rcv; wsc->sub_protocol = sub_protocol; wsc->run_event = 0; - wsc->frag_buf.s = ((char*)wsc) + sizeof(ws_connection_t); + wsc->frag_buf.s = ((char *)wsc) + sizeof(ws_connection_t); atomic_set(&wsc->refcnt, 0); - LM_DBG("wsconn_add new wsc => [%p], ref => [%d]\n", wsc, atomic_get(&wsc->refcnt)); + LM_DBG("wsconn_add new wsc => [%p], ref => [%d]\n", wsc, + atomic_get(&wsc->refcnt)); WSCONN_LOCK; /* Add to WebSocket connection table */ @@ -226,10 +216,9 @@ int wsconn_add(struct receive_info rcv, unsigned int sub_protocol) /* Add to the end of the WebSocket used list */ wsc->last_used = (int)time(NULL); - if (wsconn_used_list->head == NULL) + if(wsconn_used_list->head == NULL) wsconn_used_list->head = wsconn_used_list->tail = wsc; - else - { + else { wsc->used_prev = wsconn_used_list->tail; wsconn_used_list->tail->used_next = wsc; wsconn_used_list->tail = wsc; @@ -238,7 +227,8 @@ int wsconn_add(struct receive_info rcv, unsigned int sub_protocol) WSCONN_UNLOCK; - LM_DBG("wsconn_add added to conn_table wsc => [%p], ref => [%d]\n", wsc, atomic_get(&wsc->refcnt)); + LM_DBG("wsconn_add added to conn_table wsc => [%p], ref => [%d]\n", wsc, + atomic_get(&wsc->refcnt)); /* Update connection statistics */ lock_get(wsstat_lock); @@ -246,26 +236,22 @@ int wsconn_add(struct receive_info rcv, unsigned int sub_protocol) update_stat(ws_current_connections, 1); cur_cons = get_stat_val(ws_current_connections); max_cons = get_stat_val(ws_max_concurrent_connections); - if (max_cons < cur_cons) + if(max_cons < cur_cons) update_stat(ws_max_concurrent_connections, cur_cons - max_cons); - if (wsc->sub_protocol == SUB_PROTOCOL_SIP) - { + if(wsc->sub_protocol == SUB_PROTOCOL_SIP) { update_stat(ws_sip_current_connections, 1); cur_cons = get_stat_val(ws_sip_current_connections); max_cons = get_stat_val(ws_sip_max_concurrent_connections); - if (max_cons < cur_cons) - update_stat(ws_sip_max_concurrent_connections, - cur_cons - max_cons); - } - else if (wsc->sub_protocol == SUB_PROTOCOL_MSRP) - { + if(max_cons < cur_cons) + update_stat(ws_sip_max_concurrent_connections, cur_cons - max_cons); + } else if(wsc->sub_protocol == SUB_PROTOCOL_MSRP) { update_stat(ws_msrp_current_connections, 1); cur_cons = get_stat_val(ws_msrp_current_connections); max_cons = get_stat_val(ws_msrp_max_concurrent_connections); - if (max_cons < cur_cons) - update_stat(ws_msrp_max_concurrent_connections, - cur_cons - max_cons); + if(max_cons < cur_cons) + update_stat( + ws_msrp_max_concurrent_connections, cur_cons - max_cons); } lock_release(wsstat_lock); @@ -284,14 +270,13 @@ static void wsconn_run_route(ws_connection_t *wsc) LM_DBG("wsconn_run_route event_route[websocket:closed]\n"); rt = route_lookup(&event_rt, evrtname.s); - if (rt < 0 || event_rt.rlist[rt] == NULL) - { - if(ws_event_callback.len<=0 || ws_event_callback.s==NULL) { + if(rt < 0 || event_rt.rlist[rt] == NULL) { + if(ws_event_callback.len <= 0 || ws_event_callback.s == NULL) { LM_DBG("event route does not exist"); return; } keng = sr_kemi_eng_get(); - if(keng==NULL) { + if(keng == NULL) { LM_DBG("event route callback engine does not exist"); return; } else { @@ -299,8 +284,7 @@ static void wsconn_run_route(ws_connection_t *wsc) } } - if (faked_msg_init() < 0) - { + if(faked_msg_init() < 0) { LM_ERR("faked_msg_init() failed\n"); return; } @@ -312,10 +296,12 @@ static void wsconn_run_route(ws_connection_t *wsc) backup_rt = get_route_type(); set_route_type(EVENT_ROUTE); init_run_actions_ctx(&ctx); - if(rt<0) { + if(rt < 0) { /* kemi script event route callback */ - if(keng && keng->froute(fmsg, EVENT_ROUTE, - &ws_event_callback, &evrtname)<0) { + if(keng + && keng->froute( + fmsg, EVENT_ROUTE, &ws_event_callback, &evrtname) + < 0) { LM_ERR("error running event route kemi callback\n"); } } else { @@ -327,12 +313,12 @@ static void wsconn_run_route(ws_connection_t *wsc) static void wsconn_dtor(ws_connection_t *wsc) { - if (!wsc) + if(!wsc) return; LM_DBG("wsconn_dtor for [%p] refcnt [%d]\n", wsc, atomic_get(&wsc->refcnt)); - if (wsc->run_event) + if(wsc->run_event) wsconn_run_route(wsc); shm_free(wsc); @@ -344,7 +330,7 @@ int wsconn_rm(ws_connection_t *wsc, ws_conn_eventroute_t run_event_route) { LM_DBG("wsconn_rm for [%p] refcnt [%d]\n", wsc, atomic_get(&wsc->refcnt)); - if (run_event_route == WSCONN_EVENTROUTE_YES) + if(run_event_route == WSCONN_EVENTROUTE_YES) wsc->run_event = 1; return wsconn_put(wsc); @@ -352,22 +338,21 @@ int wsconn_rm(ws_connection_t *wsc, ws_conn_eventroute_t run_event_route) int wsconn_update(ws_connection_t *wsc) { - if (!wsc) - { + if(!wsc) { LM_ERR("wsconn_update: null pointer\n"); return -1; } WSCONN_LOCK; - wsc->last_used = (int) time(NULL); - if (wsconn_used_list->tail == wsc) + wsc->last_used = (int)time(NULL); + if(wsconn_used_list->tail == wsc) /* Already at the end of the list */ goto end; - if (wsconn_used_list->head == wsc) + if(wsconn_used_list->head == wsc) wsconn_used_list->head = wsc->used_next; - if (wsc->used_prev) + if(wsc->used_prev) wsc->used_prev->used_next = wsc->used_next; - if (wsc->used_next) + if(wsc->used_next) wsc->used_next->used_prev = wsc->used_prev; wsc->used_prev = wsconn_used_list->tail; wsc->used_next = NULL; @@ -383,11 +368,10 @@ void wsconn_close_now(ws_connection_t *wsc) { struct tcp_connection *con = tcpconn_get(wsc->id, 0, 0, 0, 0); - if (wsconn_rm(wsc, WSCONN_EVENTROUTE_YES) < 0) + if(wsconn_rm(wsc, WSCONN_EVENTROUTE_YES) < 0) LM_ERR("removing WebSocket connection\n"); - if (con == NULL) - { + if(con == NULL) { LM_ERR("getting TCP/TLS connection\n"); return; } @@ -403,23 +387,23 @@ int wsconn_put(ws_connection_t *wsc) { int destroy = 0; - LM_DBG("wsconn_put start for [%p] refcnt [%d]\n", wsc, atomic_get(&wsc->refcnt)); + LM_DBG("wsconn_put start for [%p] refcnt [%d]\n", wsc, + atomic_get(&wsc->refcnt)); - if (!wsc) + if(!wsc) return -1; WSCONN_LOCK; /* refcnt == 0*/ - if (wsconn_unref(wsc)) - { + if(wsconn_unref(wsc)) { /* Remove from the WebSocket used list */ - if (wsconn_used_list->head == wsc) + if(wsconn_used_list->head == wsc) wsconn_used_list->head = wsc->used_next; - if (wsconn_used_list->tail == wsc) + if(wsconn_used_list->tail == wsc) wsconn_used_list->tail = wsc->used_prev; - if (wsc->used_prev) + if(wsc->used_prev) wsc->used_prev->used_next = wsc->used_next; - if (wsc->used_next) + if(wsc->used_next) wsc->used_next->used_prev = wsc->used_prev; /* remove from wsconn_id_hash */ @@ -427,19 +411,20 @@ int wsconn_put(ws_connection_t *wsc) /* stat */ update_stat(ws_current_connections, -1); - if (wsc->sub_protocol == SUB_PROTOCOL_SIP) + if(wsc->sub_protocol == SUB_PROTOCOL_SIP) update_stat(ws_sip_current_connections, -1); - else if (wsc->sub_protocol == SUB_PROTOCOL_MSRP) + else if(wsc->sub_protocol == SUB_PROTOCOL_MSRP) update_stat(ws_msrp_current_connections, -1); destroy = 1; } WSCONN_UNLOCK; - LM_DBG("wsconn_put end for [%p] refcnt [%d]\n", wsc, atomic_get(&wsc->refcnt)); + LM_DBG("wsconn_put end for [%p] refcnt [%d]\n", wsc, + atomic_get(&wsc->refcnt)); /* wsc is removed from all lists and can be destroyed safely */ - if (destroy) + if(destroy) wsconn_dtor(wsc); return 0; @@ -453,12 +438,11 @@ ws_connection_t *wsconn_get(int id) LM_DBG("wsconn_get for id [%d]\n", id); WSCONN_LOCK; - for (wsc = wsconn_id_hash[id_hash]; wsc; wsc = wsc->id_next) - { - if (wsc->id == id) - { + for(wsc = wsconn_id_hash[id_hash]; wsc; wsc = wsc->id_next) { + if(wsc->id == id) { wsconn_ref(wsc); - LM_DBG("wsconn_get returns wsc [%p] refcnt [%d]\n", wsc, atomic_get(&wsc->refcnt)); + LM_DBG("wsconn_get returns wsc [%p] refcnt [%d]\n", wsc, + atomic_get(&wsc->refcnt)); WSCONN_UNLOCK; @@ -473,48 +457,49 @@ ws_connection_t *wsconn_get(int id) ws_connection_t **wsconn_get_list(void) { ws_connection_t **list = NULL; - ws_connection_t *wsc = NULL; + ws_connection_t *wsc = NULL; size_t list_size = 0; - size_t list_len = 0; + size_t list_len = 0; size_t i = 0; - if(ws_verbose_list) LM_DBG("wsconn get list - starting\n"); + if(ws_verbose_list) + LM_DBG("wsconn get list - starting\n"); WSCONN_LOCK; /* get the number of used connections */ wsc = wsconn_used_list->head; - while (wsc) - { - if(ws_verbose_list) LM_DBG("counter wsc [%p] prev => [%p] next => [%p]\n", - wsc, wsc->used_prev, wsc->used_next); + while(wsc) { + if(ws_verbose_list) + LM_DBG("counter wsc [%p] prev => [%p] next => [%p]\n", wsc, + wsc->used_prev, wsc->used_next); list_len++; wsc = wsc->used_next; } - if (!list_len) + if(!list_len) goto end; /* allocate a NULL terminated list of wsconn pointers */ list_size = (list_len + 1) * sizeof(ws_connection_t *); list = pkg_malloc(list_size); - if (!list) + if(!list) goto end; memset(list, 0, list_size); /* copy */ wsc = wsconn_used_list->head; - for(i = 0; i < list_len; i++) - { - if (!wsc) { + for(i = 0; i < list_len; i++) { + if(!wsc) { LM_ERR("Wrong list length\n"); break; } list[i] = wsc; wsconn_ref(wsc); - if(ws_verbose_list) LM_DBG("wsc [%p] id [%d] ref++\n", wsc, wsc->id); + if(ws_verbose_list) + LM_DBG("wsc [%p] id [%d] ref++\n", wsc, wsc->id); wsc = wsc->used_next; } @@ -523,8 +508,10 @@ ws_connection_t **wsconn_get_list(void) end: WSCONN_UNLOCK; - if(ws_verbose_list) LM_DBG("wsconn_get_list returns list [%p]" - " with [%d] members\n", list, (int)list_len); + if(ws_verbose_list) + LM_DBG("wsconn_get_list returns list [%p]" + " with [%d] members\n", + list, (int)list_len); return list; } @@ -532,17 +519,16 @@ ws_connection_t **wsconn_get_list(void) int wsconn_put_list(ws_connection_t **list_head) { ws_connection_t **list = NULL; - ws_connection_t *wsc = NULL; + ws_connection_t *wsc = NULL; LM_DBG("wsconn_put_list [%p]\n", list_head); - if (!list_head) + if(!list_head) return -1; - list = list_head; - wsc = *list_head; - while (wsc) - { + list = list_head; + wsc = *list_head; + while(wsc) { wsconn_put(wsc); wsc = *(++list); } @@ -553,7 +539,8 @@ int wsconn_put_list(ws_connection_t **list_head) } -static int ws_rpc_add_node(rpc_t* rpc, void* ctx, void* ih, ws_connection_t *wsc) +static int ws_rpc_add_node( + rpc_t *rpc, void *ctx, void *ih, ws_connection_t *wsc) { int interval; char *src_proto, *dst_proto, *pong, *sub_protocol; @@ -561,9 +548,8 @@ static int ws_rpc_add_node(rpc_t* rpc, void* ctx, void* ih, ws_connection_t *wsc struct tcp_connection *con = tcpconn_get(wsc->id, 0, 0, 0, 0); char rplbuf[512]; - if (con) - { - src_proto = (con->rcv.proto== PROTO_WS) ? "ws" : "wss"; + if(con) { + src_proto = (con->rcv.proto == PROTO_WS) ? "ws" : "wss"; memset(src_ip, 0, IP6_MAX_STR_SIZE + 1); ip_addr2sbuf(&con->rcv.src_ip, src_ip, IP6_MAX_STR_SIZE); @@ -574,34 +560,26 @@ static int ws_rpc_add_node(rpc_t* rpc, void* ctx, void* ih, ws_connection_t *wsc pong = wsc->awaiting_pong ? "awaiting Pong, " : ""; interval = (int)time(NULL) - wsc->last_used; - if (wsc->sub_protocol == SUB_PROTOCOL_SIP) + if(wsc->sub_protocol == SUB_PROTOCOL_SIP) sub_protocol = "sip"; - else if (wsc->sub_protocol == SUB_PROTOCOL_MSRP) + else if(wsc->sub_protocol == SUB_PROTOCOL_MSRP) sub_protocol = "msrp"; else sub_protocol = "**UNKNOWN**"; - if (snprintf(rplbuf, 512, - "%d: %s:%s:%hu -> %s:%s:%hu (state: %s" - ", %s last used %ds ago" - ", sub-protocol: %s)", - wsc->id, - src_proto, - strlen(src_ip) ? src_ip : "*", - con->rcv.src_port, - dst_proto, - strlen(dst_ip) ? dst_ip : "*", - con->rcv.dst_port, - wsconn_state_str[wsc->state], - pong, - interval, - sub_protocol) < 0) { + if(snprintf(rplbuf, 512, "%d: %s:%s:%hu -> %s:%s:%hu (state: %s" + ", %s last used %ds ago" + ", sub-protocol: %s)", + wsc->id, src_proto, strlen(src_ip) ? src_ip : "*", + con->rcv.src_port, dst_proto, strlen(dst_ip) ? dst_ip : "*", + con->rcv.dst_port, wsconn_state_str[wsc->state], pong, + interval, sub_protocol) + < 0) { tcpconn_put(con); rpc->fault(ctx, 500, "Failed to print connection details"); return -1; } - if (rpc->array_add(ih, "s", rplbuf)<0) - { + if(rpc->array_add(ih, "s", rplbuf) < 0) { tcpconn_put(con); rpc->fault(ctx, 500, "Failed to add to response"); return -1; @@ -609,27 +587,27 @@ static int ws_rpc_add_node(rpc_t* rpc, void* ctx, void* ih, ws_connection_t *wsc tcpconn_put(con); return 1; - } - else + } else return 0; } -void ws_rpc_dump(rpc_t* rpc, void* ctx) +void ws_rpc_dump(rpc_t *rpc, void *ctx) { int h, connections = 0, truncated = 0, order = 0, found = 0; ws_connection_t *wsc; str sorder = {0}; - void* th; - void* ih; - void* dh; + void *th; + void *ih; + void *dh; - if(rpc->scan(ctx, "*S", &sorder)==1) - { - if (sorder.len == 7 && strncasecmp(sorder.s, "id_hash", 7) == 0) { + if(rpc->scan(ctx, "*S", &sorder) == 1) { + if(sorder.len == 7 && strncasecmp(sorder.s, "id_hash", 7) == 0) { order = 0; - } else if (sorder.len == 9 && strncasecmp(sorder.s, "used_desc", 9) == 0) { + } else if(sorder.len == 9 + && strncasecmp(sorder.s, "used_desc", 9) == 0) { order = 1; - } else if (sorder.len == 8 && strncasecmp(sorder.s, "used_asc", 8) == 0) { + } else if(sorder.len == 8 + && strncasecmp(sorder.s, "used_asc", 8) == 0) { order = 2; } else { LM_WARN("bad display order parameter\n"); @@ -639,35 +617,28 @@ void ws_rpc_dump(rpc_t* rpc, void* ctx) } /* add root node */ - if (rpc->add(ctx, "{", &th) < 0) - { + if(rpc->add(ctx, "{", &th) < 0) { rpc->fault(ctx, 500, "Internal error root reply"); return; } - if(rpc->struct_add(th, "[", "connections", &ih)<0) - { + if(rpc->struct_add(th, "[", "connections", &ih) < 0) { rpc->fault(ctx, 500, "Internal error connections structure"); return; } WSCONN_LOCK; - if (order == 0) - { - for (h = 0; h < TCP_ID_HASH_SIZE; h++) - { + if(order == 0) { + for(h = 0; h < TCP_ID_HASH_SIZE; h++) { wsc = wsconn_id_hash[h]; - while(wsc) - { - if ((found = ws_rpc_add_node(rpc, ctx, ih, wsc)) < 0) - { + while(wsc) { + if((found = ws_rpc_add_node(rpc, ctx, ih, wsc)) < 0) { WSCONN_UNLOCK; return; } connections += found; - if (connections >= MAX_WS_CONNS_DUMP) - { + if(connections >= MAX_WS_CONNS_DUMP) { truncated = 1; break; } @@ -675,45 +646,35 @@ void ws_rpc_dump(rpc_t* rpc, void* ctx) wsc = wsc->id_next; } - if (truncated == 1) + if(truncated == 1) break; } - } - else if (order == 1) - { + } else if(order == 1) { wsc = wsconn_used_list->head; - while (wsc) - { - if ((found = ws_rpc_add_node(rpc, ctx, ih, wsc)) < 0) - { + while(wsc) { + if((found = ws_rpc_add_node(rpc, ctx, ih, wsc)) < 0) { WSCONN_UNLOCK; return; } connections += found; - if (connections >= MAX_WS_CONNS_DUMP) - { + if(connections >= MAX_WS_CONNS_DUMP) { truncated = 1; break; } wsc = wsc->used_next; } - } - else - { + } else { wsc = wsconn_used_list->tail; - while (wsc) - { - if ((found = ws_rpc_add_node(rpc, ctx, ih, wsc)) < 0) - { + while(wsc) { + if((found = ws_rpc_add_node(rpc, ctx, ih, wsc)) < 0) { WSCONN_UNLOCK; return; } connections += found; - if (connections >= MAX_WS_CONNS_DUMP) - { + if(connections >= MAX_WS_CONNS_DUMP) { truncated = 1; break; } @@ -723,15 +684,13 @@ void ws_rpc_dump(rpc_t* rpc, void* ctx) } WSCONN_UNLOCK; - if(rpc->struct_add(th, "{", "info", &dh)<0) - { + if(rpc->struct_add(th, "{", "info", &dh) < 0) { rpc->fault(ctx, 500, "Internal error info structure"); return; } - if(rpc->struct_add(dh, "ds", - "wscounter", connections, - "truncated", (truncated==1)?"yes":"no")<0) - { + if(rpc->struct_add(dh, "ds", "wscounter", connections, "truncated", + (truncated == 1) ? "yes" : "no") + < 0) { rpc->fault(ctx, 500, "Internal error adding info structure"); return; } diff --git a/src/modules/websocket/ws_conn.h b/src/modules/websocket/ws_conn.h index 7e413d27d08..74cb40f7c26 100644 --- a/src/modules/websocket/ws_conn.h +++ b/src/modules/websocket/ws_conn.h @@ -32,12 +32,11 @@ #include "../../core/counters.h" #include "../../core/rpc.h" -typedef enum -{ - WS_S_CONNECTING = 0, /* Never used - included for completeness */ +typedef enum { + WS_S_CONNECTING = 0, /* Never used - included for completeness */ WS_S_OPEN, WS_S_CLOSING, - WS_S_CLOSED /* Never used - included for completeness */ + WS_S_CLOSED /* Never used - included for completeness */ } ws_conn_state_t; typedef struct ws_connection @@ -49,8 +48,8 @@ typedef struct ws_connection struct ws_connection *used_prev; struct ws_connection *used_next; - int id; /* id and id_hash are identical to the values */ - unsigned id_hash; /* for the corresponding TCP/TLS connection */ + int id; /* id and id_hash are identical to the values */ + unsigned id_hash; /* for the corresponding TCP/TLS connection */ struct ws_connection *id_prev; struct ws_connection *id_next; @@ -59,7 +58,7 @@ typedef struct ws_connection unsigned int sub_protocol; atomic_t refcnt; - int run_event; + int run_event; str frag_buf; } ws_connection_t; @@ -70,8 +69,7 @@ typedef struct ws_connection_t *tail; } ws_connection_used_list_t; -typedef enum -{ +typedef enum { WSCONN_EVENTROUTE_NO = 0, WSCONN_EVENTROUTE_YES } ws_conn_eventroute_t; @@ -97,5 +95,5 @@ ws_connection_t *wsconn_get(int id); int wsconn_put(ws_connection_t *wsc); ws_connection_t **wsconn_get_list(void); int wsconn_put_list(ws_connection_t **list); -void ws_rpc_dump(rpc_t* rpc, void* ctx); +void ws_rpc_dump(rpc_t *rpc, void *ctx); #endif /* _WS_CONN_H */ diff --git a/src/modules/websocket/ws_frame.c b/src/modules/websocket/ws_frame.c index 5aafe064e9c..aec8a19c8b8 100644 --- a/src/modules/websocket/ws_frame.c +++ b/src/modules/websocket/ws_frame.c @@ -66,7 +66,8 @@ | Payload Data continued ... | +---------------------------------------------------------------+ */ -typedef struct { +typedef struct +{ unsigned int fin; unsigned int rsv1; unsigned int rsv2; @@ -79,27 +80,23 @@ typedef struct { ws_connection_t *wsc; } ws_frame_t; -typedef enum -{ - CONN_CLOSE_DO = 0, - CONN_CLOSE_DONT -} conn_close_t; - -#define BYTE0_MASK_FIN (0x80) -#define BYTE0_MASK_RSV1 (0x40) -#define BYTE0_MASK_RSV2 (0x20) -#define BYTE0_MASK_RSV3 (0x10) -#define BYTE0_MASK_OPCODE (0x0F) -#define BYTE1_MASK_MASK (0x80) -#define BYTE1_MASK_PAYLOAD_LEN (0x7F) - -#define OPCODE_CONTINUATION (0x0) -#define OPCODE_TEXT_FRAME (0x1) -#define OPCODE_BINARY_FRAME (0x2) +typedef enum { CONN_CLOSE_DO = 0, CONN_CLOSE_DONT } conn_close_t; + +#define BYTE0_MASK_FIN (0x80) +#define BYTE0_MASK_RSV1 (0x40) +#define BYTE0_MASK_RSV2 (0x20) +#define BYTE0_MASK_RSV3 (0x10) +#define BYTE0_MASK_OPCODE (0x0F) +#define BYTE1_MASK_MASK (0x80) +#define BYTE1_MASK_PAYLOAD_LEN (0x7F) + +#define OPCODE_CONTINUATION (0x0) +#define OPCODE_TEXT_FRAME (0x1) +#define OPCODE_BINARY_FRAME (0x2) /* 0x3 - 0x7 are reserved for further non-control frames */ -#define OPCODE_CLOSE (0x8) -#define OPCODE_PING (0x9) -#define OPCODE_PONG (0xa) +#define OPCODE_CLOSE (0x8) +#define OPCODE_PING (0x9) +#define OPCODE_PONG (0xa) /* 0xb - 0xf are reserved for further control frames */ int ws_keepalive_mechanism = DEFAULT_KEEPALIVE_MECHANISM; @@ -146,8 +143,7 @@ static int encode_and_send_ws_frame(ws_frame_t *frame, conn_close_t conn_close) LM_DBG("encoding WebSocket frame\n"); - if (frame->wsc->state != WS_S_OPEN) - { + if(frame->wsc->state != WS_S_OPEN) { LM_WARN("sending on closing connection\n"); return -1; } @@ -155,78 +151,71 @@ static int encode_and_send_ws_frame(ws_frame_t *frame, conn_close_t conn_close) wsconn_update(frame->wsc); /* Validate the first byte */ - if (!frame->fin) - { + if(!frame->fin) { LM_ERR("WebSocket fragmentation not supported in the sip " - "sub-protocol\n"); + "sub-protocol\n"); return -1; } - if (frame->rsv1 || frame->rsv2 || frame->rsv3) - { + if(frame->rsv1 || frame->rsv2 || frame->rsv3) { LM_ERR("WebSocket reserved fields with non-zero values\n"); return -1; } sub_proto = frame->wsc->sub_protocol; - switch(frame->opcode) - { - case OPCODE_TEXT_FRAME: - case OPCODE_BINARY_FRAME: - LM_DBG("supported non-control frame: 0x%x\n", - (unsigned char) frame->opcode); - break; - case OPCODE_CLOSE: - case OPCODE_PING: - case OPCODE_PONG: - LM_DBG("supported control frame: 0x%x\n", - (unsigned char) frame->opcode); - break; - default: - LM_ERR("unsupported opcode: 0x%x\n", - (unsigned char) frame->opcode); - return -1; + switch(frame->opcode) { + case OPCODE_TEXT_FRAME: + case OPCODE_BINARY_FRAME: + LM_DBG("supported non-control frame: 0x%x\n", + (unsigned char)frame->opcode); + break; + case OPCODE_CLOSE: + case OPCODE_PING: + case OPCODE_PONG: + LM_DBG("supported control frame: 0x%x\n", + (unsigned char)frame->opcode); + break; + default: + LM_ERR("unsupported opcode: 0x%x\n", (unsigned char)frame->opcode); + return -1; } /* validate the second byte */ - if (frame->mask) - { + if(frame->mask) { LM_ERR("this is a server - all messages sent will be " - "unmasked\n"); + "unmasked\n"); return -1; } - if (frame->payload_len < 126) extended_length = 0; - else if (frame->payload_len <= USHRT_MAX ) extended_length = 2; - else if (frame->payload_len < UINT_MAX) extended_length = 4; - else - { + if(frame->payload_len < 126) + extended_length = 0; + else if(frame->payload_len <= USHRT_MAX) + extended_length = 2; + else if(frame->payload_len < UINT_MAX) + extended_length = 4; + else { LM_ERR(NAME " only supports WebSocket frames with payload " - "< %u\n", UINT_MAX); + "< %u\n", + UINT_MAX); return -1; } /* Allocate send buffer and build frame */ frame_length = frame->payload_len + extended_length + 2; - if ((send_buf = pkg_malloc(sizeof(char) * frame_length)) - == NULL) - { + if((send_buf = pkg_malloc(sizeof(char) * frame_length)) == NULL) { LM_ERR("allocating send buffer from pkg memory\n"); return -1; } memset(send_buf, 0, sizeof(char) * frame_length); send_buf[pos++] = 0x80 | (frame->opcode & 0xff); - if (extended_length == 0) + if(extended_length == 0) send_buf[pos++] = (frame->payload_len & 0xff); - else if (extended_length == 2) - { + else if(extended_length == 2) { send_buf[pos++] = 126; send_buf[pos++] = (frame->payload_len & 0xff00) >> 8; send_buf[pos++] = (frame->payload_len & 0x00ff) >> 0; - } - else - { + } else { send_buf[pos++] = 127; send_buf[pos++] = (frame->payload_len & 0xff000000) >> 24; send_buf[pos++] = (frame->payload_len & 0x00ff0000) >> 16; @@ -235,20 +224,17 @@ static int encode_and_send_ws_frame(ws_frame_t *frame, conn_close_t conn_close) } memcpy(&send_buf[pos], frame->payload_data, frame->payload_len); - if ((con = tcpconn_get(frame->wsc->id, 0, 0, 0, 0)) == NULL) - { + if((con = tcpconn_get(frame->wsc->id, 0, 0, 0, 0)) == NULL) { LM_WARN("TCP/TLS connection get failed\n"); pkg_free(send_buf); - if (wsconn_rm(frame->wsc, WSCONN_EVENTROUTE_YES) < 0) + if(wsconn_rm(frame->wsc, WSCONN_EVENTROUTE_YES) < 0) LM_ERR("removing WebSocket connection\n"); return -1; } init_dst_from_rcv(&dst, &con->rcv); - if (conn_close == CONN_CLOSE_DO) - { + if(conn_close == CONN_CLOSE_DO) { dst.send_flags.f |= SND_F_CON_CLOSE; - if (wsconn_rm(frame->wsc, WSCONN_EVENTROUTE_YES) < 0) - { + if(wsconn_rm(frame->wsc, WSCONN_EVENTROUTE_YES) < 0) { LM_ERR("removing WebSocket connection\n"); tcpconn_put(con); pkg_free(send_buf); @@ -256,34 +242,28 @@ static int encode_and_send_ws_frame(ws_frame_t *frame, conn_close_t conn_close) } } - if (dst.proto == PROTO_WS) - { - if (unlikely(tcp_disable)) - { + if(dst.proto == PROTO_WS) { + if(unlikely(tcp_disable)) { STATS_TX_DROPS; LM_WARN("TCP disabled\n"); pkg_free(send_buf); tcpconn_put(con); return -1; - } + } } #ifdef USE_TLS - else if (dst.proto == PROTO_WSS) - { - if (unlikely(tls_disable)) - { + else if(dst.proto == PROTO_WSS) { + if(unlikely(tls_disable)) { STATS_TX_DROPS; LM_WARN("TLS disabled\n"); pkg_free(send_buf); tcpconn_put(con); return -1; - } + } } #endif /* USE_TLS */ - if (unlikely((dst.send_flags.f & SND_F_FORCE_SOCKET) - && dst.send_sock)) - { + if(unlikely((dst.send_flags.f & SND_F_FORCE_SOCKET) && dst.send_sock)) { local_addr = dst.send_sock->su; su_setport(&local_addr, 0); from = &local_addr; @@ -294,57 +274,52 @@ static int encode_and_send_ws_frame(ws_frame_t *frame, conn_close_t conn_close) server (which Kamailio is) CANNOT create connections. */ dst.send_flags.f |= SND_F_FORCE_CON_REUSE; - if (tcp_send(&dst, from, send_buf, frame_length) < 0) - { + if(tcp_send(&dst, from, send_buf, frame_length) < 0) { STATS_TX_DROPS; LM_ERR("sending WebSocket frame\n"); pkg_free(send_buf); update_stat(ws_failed_connections, 1); - if (sub_proto == SUB_PROTOCOL_SIP) + if(sub_proto == SUB_PROTOCOL_SIP) update_stat(ws_sip_failed_connections, 1); - else if (sub_proto == SUB_PROTOCOL_MSRP) + else if(sub_proto == SUB_PROTOCOL_MSRP) update_stat(ws_msrp_failed_connections, 1); - if (wsconn_rm(frame->wsc, WSCONN_EVENTROUTE_YES) < 0) + if(wsconn_rm(frame->wsc, WSCONN_EVENTROUTE_YES) < 0) LM_ERR("removing WebSocket connection\n"); tcpconn_put(con); return -1; } update_stat(ws_transmitted_frames, 1); - switch (frame->opcode) - { - case OPCODE_TEXT_FRAME: - case OPCODE_BINARY_FRAME: - if (frame->wsc->sub_protocol == SUB_PROTOCOL_SIP) - update_stat(ws_sip_transmitted_frames, 1); - else if (frame->wsc->sub_protocol == SUB_PROTOCOL_MSRP) - update_stat(ws_msrp_transmitted_frames, 1); + switch(frame->opcode) { + case OPCODE_TEXT_FRAME: + case OPCODE_BINARY_FRAME: + if(frame->wsc->sub_protocol == SUB_PROTOCOL_SIP) + update_stat(ws_sip_transmitted_frames, 1); + else if(frame->wsc->sub_protocol == SUB_PROTOCOL_MSRP) + update_stat(ws_msrp_transmitted_frames, 1); } - + pkg_free(send_buf); tcpconn_put(con); return 0; } static int close_connection(ws_connection_t **p_wsc, ws_close_type_t type, - short int status, str reason) + short int status, str reason) { char *data; ws_frame_t frame; - ws_connection_t * wsc = NULL; + ws_connection_t *wsc = NULL; int sub_proto = -1; - if (!p_wsc || !(*p_wsc)) - { + if(!p_wsc || !(*p_wsc)) { LM_ERR("Invalid parameters\n"); return -1; } wsc = *p_wsc; - if (wsc->state == WS_S_OPEN) - { + if(wsc->state == WS_S_OPEN) { data = pkg_malloc(sizeof(char) * (reason.len + 2)); - if (data == NULL) - { + if(data == NULL) { LM_ERR("allocating pkg memory\n"); return -1; } @@ -361,10 +336,9 @@ static int close_connection(ws_connection_t **p_wsc, ws_close_type_t type, frame.wsc = wsc; sub_proto = wsc->sub_protocol; - if (encode_and_send_ws_frame(&frame, - type == - REMOTE_CLOSE ? CONN_CLOSE_DO : CONN_CLOSE_DONT) < 0) - { + if(encode_and_send_ws_frame(&frame, + type == REMOTE_CLOSE ? CONN_CLOSE_DO : CONN_CLOSE_DONT) + < 0) { LM_ERR("sending WebSocket close\n"); pkg_free(data); return -1; @@ -372,28 +346,21 @@ static int close_connection(ws_connection_t **p_wsc, ws_close_type_t type, pkg_free(data); - if (type == LOCAL_CLOSE) - { + if(type == LOCAL_CLOSE) { frame.wsc->state = WS_S_CLOSING; update_stat(ws_local_closed_connections, 1); - if (frame.wsc->sub_protocol == SUB_PROTOCOL_SIP) + if(frame.wsc->sub_protocol == SUB_PROTOCOL_SIP) update_stat(ws_sip_local_closed_connections, 1); - else if (frame.wsc->sub_protocol == SUB_PROTOCOL_MSRP) - update_stat(ws_msrp_local_closed_connections, - 1); - } - else - { + else if(frame.wsc->sub_protocol == SUB_PROTOCOL_MSRP) + update_stat(ws_msrp_local_closed_connections, 1); + } else { update_stat(ws_remote_closed_connections, 1); - if (sub_proto == SUB_PROTOCOL_SIP) - update_stat(ws_sip_remote_closed_connections, - 1); - else if (sub_proto == SUB_PROTOCOL_MSRP) - update_stat(ws_msrp_remote_closed_connections, - 1); + if(sub_proto == SUB_PROTOCOL_SIP) + update_stat(ws_sip_remote_closed_connections, 1); + else if(sub_proto == SUB_PROTOCOL_MSRP) + update_stat(ws_msrp_remote_closed_connections, 1); } - } - else /* if (frame->wsc->state == WS_S_CLOSING) */ + } else /* if (frame->wsc->state == WS_S_CLOSING) */ { wsconn_close_now(wsc); } @@ -402,8 +369,7 @@ static int close_connection(ws_connection_t **p_wsc, ws_close_type_t type, } static int decode_and_validate_ws_frame(ws_frame_t *frame, - tcp_event_info_t *tcpinfo, - short *err_code, str *err_text) + tcp_event_info_t *tcpinfo, short *err_code, str *err_text) { unsigned int i, len = tcpinfo->len; unsigned int mask_start, j; @@ -414,8 +380,7 @@ static int decode_and_validate_ws_frame(ws_frame_t *frame, wsconn_update(frame->wsc); /* Decode and validate first 9 bits */ - if (len < 2) - { + if(len < 2) { LM_WARN("message is too short\n"); *err_code = 1002; *err_text = str_status_protocol_error; @@ -427,46 +392,42 @@ static int decode_and_validate_ws_frame(ws_frame_t *frame, frame->rsv3 = (buf[0] & 0xff) & BYTE0_MASK_RSV3; frame->opcode = (buf[0] & 0xff) & BYTE0_MASK_OPCODE; frame->mask = (buf[1] & 0xff) & BYTE1_MASK_MASK; - - if (frame->rsv1 || frame->rsv2 || frame->rsv3) - { + + if(frame->rsv1 || frame->rsv2 || frame->rsv3) { LM_WARN("WebSocket reserved fields with non-zero values\n"); *err_code = 1002; *err_text = str_status_protocol_error; return -1; } - switch(frame->opcode) - { - case OPCODE_CONTINUATION: - LM_DBG("supported continuation frame: 0x%x\n", - (unsigned char) frame->opcode); - break; - case OPCODE_TEXT_FRAME: - case OPCODE_BINARY_FRAME: - LM_DBG("supported non-control frame: 0x%x\n", - (unsigned char) frame->opcode); - break; - - case OPCODE_CLOSE: - case OPCODE_PING: - case OPCODE_PONG: - LM_DBG("supported control frame: 0x%x\n", - (unsigned char) frame->opcode); - break; - - default: - LM_WARN("unsupported opcode: 0x%x\n", - (unsigned char) frame->opcode); - *err_code = 1008; - *err_text = str_status_unsupported_opcode; - return -1; + switch(frame->opcode) { + case OPCODE_CONTINUATION: + LM_DBG("supported continuation frame: 0x%x\n", + (unsigned char)frame->opcode); + break; + case OPCODE_TEXT_FRAME: + case OPCODE_BINARY_FRAME: + LM_DBG("supported non-control frame: 0x%x\n", + (unsigned char)frame->opcode); + break; + + case OPCODE_CLOSE: + case OPCODE_PING: + case OPCODE_PONG: + LM_DBG("supported control frame: 0x%x\n", + (unsigned char)frame->opcode); + break; + + default: + LM_WARN("unsupported opcode: 0x%x\n", (unsigned char)frame->opcode); + *err_code = 1008; + *err_text = str_status_unsupported_opcode; + return -1; } - if (!frame->mask) - { + if(!frame->mask) { LM_WARN("this is a server - all received messages must be " - "masked\n"); + "masked\n"); *err_code = 1002; *err_text = str_status_protocol_error; return -1; @@ -474,10 +435,8 @@ static int decode_and_validate_ws_frame(ws_frame_t *frame, /* Decode and validate length */ frame->payload_len = (buf[1] & 0xff) & BYTE1_MASK_PAYLOAD_LEN; - if (frame->payload_len == 126) - { - if (len < 4) - { + if(frame->payload_len == 126) { + if(len < 4) { LM_WARN("message is too short\n"); *err_code = 1002; *err_text = str_status_protocol_error; @@ -485,13 +444,9 @@ static int decode_and_validate_ws_frame(ws_frame_t *frame, } mask_start = 4; - frame->payload_len = ((buf[2] & 0xff) << 8) - | ((buf[3] & 0xff) << 0); - } - else if (frame->payload_len == 127) - { - if (len < 10) - { + frame->payload_len = ((buf[2] & 0xff) << 8) | ((buf[3] & 0xff) << 0); + } else if(frame->payload_len == 127) { + if(len < 10) { LM_WARN("message is too short\n"); *err_code = 1002; *err_text = str_status_protocol_error; @@ -499,9 +454,8 @@ static int decode_and_validate_ws_frame(ws_frame_t *frame, } mask_start = 10; - if ((buf[2] & 0xff) != 0 || (buf[3] & 0xff) != 0 - || (buf[4] & 0xff) != 0 || (buf[5] & 0xff) != 0) - { + if((buf[2] & 0xff) != 0 || (buf[3] & 0xff) != 0 || (buf[4] & 0xff) != 0 + || (buf[5] & 0xff) != 0) { LM_WARN("message is too long\n"); *err_code = 1009; *err_text = str_status_message_too_big; @@ -511,12 +465,9 @@ static int decode_and_validate_ws_frame(ws_frame_t *frame, /* Only decoding the last four bytes of the length... This limits the size of WebSocket messages that can be handled to 2^32 = which should be plenty for SIP! */ - frame->payload_len = ((buf[6] & 0xff) << 24) - | ((buf[7] & 0xff) << 16) - | ((buf[8] & 0xff) << 8) - | ((buf[9] & 0xff) << 0); - } - else + frame->payload_len = ((buf[6] & 0xff) << 24) | ((buf[7] & 0xff) << 16) + | ((buf[8] & 0xff) << 8) | ((buf[9] & 0xff) << 0); + } else mask_start = 2; /* Decode mask */ @@ -526,32 +477,29 @@ static int decode_and_validate_ws_frame(ws_frame_t *frame, frame->masking_key[3] = (buf[mask_start + 3] & 0xff); /* Decode and unmask payload */ - if ((unsigned long long)len != (unsigned long long)frame->payload_len - + mask_start + 4) - { + if((unsigned long long)len + != (unsigned long long)frame->payload_len + mask_start + 4) { LM_WARN("message not complete frame size %u but received %u\n", - frame->payload_len + mask_start + 4, len); + frame->payload_len + mask_start + 4, len); *err_code = 1002; *err_text = str_status_protocol_error; return -1; } if(frame->payload_len >= BUF_SIZE) { - LM_WARN("message is too long for our buffer size (%d / %d)\n", - BUF_SIZE, frame->payload_len); + LM_WARN("message is too long for our buffer size (%d / %d)\n", BUF_SIZE, + frame->payload_len); *err_code = 1009; *err_text = str_status_message_too_big; return -1; } frame->payload_data = &buf[mask_start + 4]; - for (i = 0; i < frame->payload_len; i++) - { + for(i = 0; i < frame->payload_len; i++) { j = i % 4; - frame->payload_data[i] - = frame->payload_data[i] ^ frame->masking_key[j]; + frame->payload_data[i] = frame->payload_data[i] ^ frame->masking_key[j]; } - LM_DBG("Rx (decoded): %.*s\n", - (int) frame->payload_len, frame->payload_data); + LM_DBG("Rx (decoded): %.*s\n", (int)frame->payload_len, + frame->payload_data); return frame->opcode; } @@ -561,26 +509,25 @@ static int handle_close(ws_frame_t *frame) unsigned short code = 0; str reason = {0, 0}; - if (frame->payload_len >= 2) - code = ((frame->payload_data[0] & 0xff) << 8) - | ((frame->payload_data[1] & 0xff) << 0); + if(frame->payload_len >= 2) + code = ((frame->payload_data[0] & 0xff) << 8) + | ((frame->payload_data[1] & 0xff) << 0); - if (frame->payload_len > 2) - { + if(frame->payload_len > 2) { reason.s = &frame->payload_data[2]; reason.len = frame->payload_len - 2; } LM_DBG("Rx Close: %hu %.*s\n", code, reason.len, reason.s); - if (close_connection(&frame->wsc, - frame->wsc->state == WS_S_OPEN ? REMOTE_CLOSE : LOCAL_CLOSE, - 1000, str_status_normal_closure) < 0) - { + if(close_connection(&frame->wsc, + frame->wsc->state == WS_S_OPEN ? REMOTE_CLOSE : LOCAL_CLOSE, + 1000, str_status_normal_closure) + < 0) { LM_ERR("closing connection\n"); return -1; } - + return 0; } @@ -591,8 +538,7 @@ static int handle_ping(ws_frame_t *frame) frame->opcode = OPCODE_PONG; frame->mask = 0; - if (encode_and_send_ws_frame(frame, CONN_CLOSE_DONT) < 0) - { + if(encode_and_send_ws_frame(frame, CONN_CLOSE_DONT) < 0) { LM_ERR("sending Pong\n"); return -1; } @@ -604,8 +550,9 @@ static int handle_pong(ws_frame_t *frame) { LM_DBG("Rx Pong: %.*s\n", frame->payload_len, frame->payload_data); - if (strncmp(frame->payload_data, ws_ping_application_data.s, - ws_ping_application_data.len) == 0) + if(strncmp(frame->payload_data, ws_ping_application_data.s, + ws_ping_application_data.len) + == 0) frame->wsc->awaiting_pong = 0; return 0; @@ -617,31 +564,29 @@ int ws_frame_receive(sr_event_param_t *evp) tcp_event_info_t *tcpinfo = (tcp_event_info_t *)evp->data; sr_event_param_t levp = {0}; - int opcode = -1; - int ret = 0; - short err_code = 0; - str err_text = {NULL, 0}; + int opcode = -1; + int ret = 0; + short err_code = 0; + str err_text = {NULL, 0}; update_stat(ws_received_frames, 1); - if (tcpinfo == NULL || tcpinfo->buf == NULL || tcpinfo->len <= 0) - { + if(tcpinfo == NULL || tcpinfo->buf == NULL || tcpinfo->len <= 0) { LM_WARN("received bad frame\n"); return -1; } /* wsc refcnt++ */ frame.wsc = wsconn_get(tcpinfo->con->id); - if (frame.wsc == NULL) - { + if(frame.wsc == NULL) { LM_ERR("WebSocket connection not found\n"); return -1; } - opcode = decode_and_validate_ws_frame(&frame, tcpinfo, &err_code, &err_text); - if (opcode < 0) - { - if (close_connection(&frame.wsc, LOCAL_CLOSE, err_code, err_text) < 0) + opcode = + decode_and_validate_ws_frame(&frame, tcpinfo, &err_code, &err_text); + if(opcode < 0) { + if(close_connection(&frame.wsc, LOCAL_CLOSE, err_code, err_text) < 0) LM_ERR("closing connection\n"); wsconn_put(frame.wsc); @@ -649,122 +594,114 @@ int ws_frame_receive(sr_event_param_t *evp) return -1; } - switch(opcode) - { - case OPCODE_CONTINUATION: - if (likely(frame.wsc->sub_protocol == SUB_PROTOCOL_SIP)) - { - if (frame.wsc->frag_buf.len + frame.payload_len >= BUF_SIZE) - { - LM_ERR("Buffer overflow assembling websocket fragments %d + %d = %d\n", frame.wsc->frag_buf.len, frame.payload_len, frame.wsc->frag_buf.len + frame.payload_len); - wsconn_put(frame.wsc); - return -1; - } - memcpy(frame.wsc->frag_buf.s + frame.wsc->frag_buf.len, frame.payload_data, frame.payload_len); - frame.wsc->frag_buf.len += frame.payload_len; - frame.wsc->frag_buf.s[frame.wsc->frag_buf.len] = '\0'; - - if (frame.fin) - { - ret = receive_msg(frame.wsc->frag_buf.s, - frame.wsc->frag_buf.len, - tcpinfo->rcv); - wsconn_put(frame.wsc); - return ret; - } - wsconn_put(frame.wsc); - return 0; - } - else - { - LM_ERR("Unsupported fragmented sub-protocol"); - wsconn_put(frame.wsc); - return -1; - } - case OPCODE_TEXT_FRAME: - case OPCODE_BINARY_FRAME: - if (likely(frame.wsc->sub_protocol == SUB_PROTOCOL_SIP)) - { - LM_DBG("Rx SIP (or text) message:\n%.*s\n", frame.payload_len, - frame.payload_data); - update_stat(ws_sip_received_frames, 1); - - if((frame.payload_len==CRLF_LEN - && strncmp(frame.payload_data, CRLF, CRLF_LEN)==0) - || (frame.payload_len==CRLFCRLF_LEN - && strncmp(frame.payload_data, CRLFCRLF, CRLFCRLF_LEN)==0)) - { - ws_send_crlf(frame.wsc, opcode); + switch(opcode) { + case OPCODE_CONTINUATION: + if(likely(frame.wsc->sub_protocol == SUB_PROTOCOL_SIP)) { + if(frame.wsc->frag_buf.len + frame.payload_len >= BUF_SIZE) { + LM_ERR("Buffer overflow assembling websocket fragments %d " + "+ %d = %d\n", + frame.wsc->frag_buf.len, frame.payload_len, + frame.wsc->frag_buf.len + frame.payload_len); + wsconn_put(frame.wsc); + return -1; + } + memcpy(frame.wsc->frag_buf.s + frame.wsc->frag_buf.len, + frame.payload_data, frame.payload_len); + frame.wsc->frag_buf.len += frame.payload_len; + frame.wsc->frag_buf.s[frame.wsc->frag_buf.len] = '\0'; + + if(frame.fin) { + ret = receive_msg(frame.wsc->frag_buf.s, + frame.wsc->frag_buf.len, tcpinfo->rcv); + wsconn_put(frame.wsc); + return ret; + } wsconn_put(frame.wsc); return 0; - } - if (frame.fin) - { - + } else { + LM_ERR("Unsupported fragmented sub-protocol"); wsconn_put(frame.wsc); - - return receive_msg(frame.payload_data, - frame.payload_len, - tcpinfo->rcv); + return -1; } - else - { - memcpy(frame.wsc->frag_buf.s, frame.payload_data, frame.payload_len); - frame.wsc->frag_buf.len = frame.payload_len; - frame.wsc->frag_buf.s[frame.wsc->frag_buf.len] = '\0'; - wsconn_put(frame.wsc); - return 0; + case OPCODE_TEXT_FRAME: + case OPCODE_BINARY_FRAME: + if(likely(frame.wsc->sub_protocol == SUB_PROTOCOL_SIP)) { + LM_DBG("Rx SIP (or text) message:\n%.*s\n", frame.payload_len, + frame.payload_data); + update_stat(ws_sip_received_frames, 1); + + if((frame.payload_len == CRLF_LEN + && strncmp(frame.payload_data, CRLF, CRLF_LEN) == 0) + || (frame.payload_len == CRLFCRLF_LEN + && strncmp(frame.payload_data, CRLFCRLF, + CRLFCRLF_LEN) + == 0)) { + ws_send_crlf(frame.wsc, opcode); + wsconn_put(frame.wsc); + return 0; + } + if(frame.fin) { + + wsconn_put(frame.wsc); + + return receive_msg(frame.payload_data, frame.payload_len, + tcpinfo->rcv); + } else { + memcpy(frame.wsc->frag_buf.s, frame.payload_data, + frame.payload_len); + frame.wsc->frag_buf.len = frame.payload_len; + frame.wsc->frag_buf.s[frame.wsc->frag_buf.len] = '\0'; + wsconn_put(frame.wsc); + return 0; + } + } else if(frame.wsc->sub_protocol == SUB_PROTOCOL_MSRP) { + LM_DBG("Rx MSRP frame:\n%.*s\n", frame.payload_len, + frame.payload_data); + update_stat(ws_msrp_received_frames, 1); + if(likely(sr_event_enabled(SREV_TCP_MSRP_FRAME))) { + tcp_event_info_t tev; + memset(&tev, 0, sizeof(tcp_event_info_t)); + tev.type = SREV_TCP_MSRP_FRAME; + tev.buf = frame.payload_data; + tev.len = frame.payload_len; + tev.rcv = tcpinfo->rcv; + tev.con = tcpinfo->con; + + wsconn_put(frame.wsc); + + levp.data = (void *)&tev; + return sr_event_exec(SREV_TCP_MSRP_FRAME, &levp); + } else { + LM_ERR("no callback registered for MSRP\n"); + + wsconn_put(frame.wsc); + + return -1; + } } - } - else if (frame.wsc->sub_protocol == SUB_PROTOCOL_MSRP) - { - LM_DBG("Rx MSRP frame:\n%.*s\n", frame.payload_len, - frame.payload_data); - update_stat(ws_msrp_received_frames, 1); - if (likely(sr_event_enabled(SREV_TCP_MSRP_FRAME))) - { - tcp_event_info_t tev; - memset(&tev, 0, sizeof(tcp_event_info_t)); - tev.type = SREV_TCP_MSRP_FRAME; - tev.buf = frame.payload_data; - tev.len = frame.payload_len; - tev.rcv = tcpinfo->rcv; - tev.con = tcpinfo->con; + case OPCODE_CLOSE: + ret = handle_close(&frame); + if(frame.wsc) wsconn_put(frame.wsc); + return ret; - levp.data = (void *) &tev; - return sr_event_exec(SREV_TCP_MSRP_FRAME, &levp); - } - else - { - LM_ERR("no callback registered for MSRP\n"); - + case OPCODE_PING: + ret = handle_ping(&frame); + if(frame.wsc) wsconn_put(frame.wsc); + return ret; - return -1; - } - } - - case OPCODE_CLOSE: - ret = handle_close(&frame); - if (frame.wsc) wsconn_put(frame.wsc); - return ret; - - case OPCODE_PING: - ret = handle_ping(&frame); - if (frame.wsc) wsconn_put(frame.wsc); - return ret; - - case OPCODE_PONG: - ret = handle_pong(&frame); - if (frame.wsc) wsconn_put(frame.wsc); - return ret; + case OPCODE_PONG: + ret = handle_pong(&frame); + if(frame.wsc) + wsconn_put(frame.wsc); + return ret; - default: - LM_WARN("received bad frame\n"); - wsconn_put(frame.wsc); - return -1; + default: + LM_WARN("received bad frame\n"); + wsconn_put(frame.wsc); + return -1; } } @@ -775,29 +712,28 @@ int ws_frame_transmit(sr_event_param_t *evp) memset(&frame, 0, sizeof(frame)); frame.fin = 1; - /* Can't be sure whether this message is UTF-8 or not so check to see +/* Can't be sure whether this message is UTF-8 or not so check to see if it "might" be UTF-8 and send as binary if it definitely isn't */ #ifdef EMBEDDED_UTF8_DECODE - frame.opcode = IsUTF8((uint8_t *) wsev->buf, wsev->len) ? - OPCODE_TEXT_FRAME : OPCODE_BINARY_FRAME; + frame.opcode = IsUTF8((uint8_t *)wsev->buf, wsev->len) + ? OPCODE_TEXT_FRAME + : OPCODE_BINARY_FRAME; #else - frame.opcode = (u8_check((uint8_t *) wsev->buf, wsev->len) == NULL) ? - OPCODE_TEXT_FRAME : OPCODE_BINARY_FRAME; + frame.opcode = (u8_check((uint8_t *)wsev->buf, wsev->len) == NULL) + ? OPCODE_TEXT_FRAME + : OPCODE_BINARY_FRAME; #endif frame.payload_len = wsev->len; frame.payload_data = wsev->buf; frame.wsc = wsconn_get(wsev->id); - if (frame.wsc == NULL) - { + if(frame.wsc == NULL) { LM_ERR("WebSocket outbound connection not found\n"); return -1; } - LM_DBG("Tx message:\n%.*s\n", frame.payload_len, - frame.payload_data); + LM_DBG("Tx message:\n%.*s\n", frame.payload_len, frame.payload_data); - if (encode_and_send_ws_frame(&frame, CONN_CLOSE_DONT) < 0) - { + if(encode_and_send_ws_frame(&frame, CONN_CLOSE_DONT) < 0) { LM_ERR("sending message\n"); wsconn_put(frame.wsc); @@ -821,13 +757,12 @@ static int ping_pong(ws_connection_t *wsc, int opcode) frame.payload_data = ws_ping_application_data.s; frame.wsc = wsc; - if (encode_and_send_ws_frame(&frame, CONN_CLOSE_DONT) < 0) - { + if(encode_and_send_ws_frame(&frame, CONN_CLOSE_DONT) < 0) { LM_ERR("sending keepalive\n"); return -1; } - if (opcode == OPCODE_PING) + if(opcode == OPCODE_PING) wsc->awaiting_pong = 1; return 0; @@ -844,7 +779,7 @@ static int ws_send_crlf(ws_connection_t *wsc, int opcode) frame.payload_data = CRLF; frame.wsc = wsc; - if (encode_and_send_ws_frame(&frame, CONN_CLOSE_DONT) < 0) { + if(encode_and_send_ws_frame(&frame, CONN_CLOSE_DONT) < 0) { LM_ERR("failed sending CRLF\n"); return -1; } @@ -854,32 +789,27 @@ static int ws_send_crlf(ws_connection_t *wsc, int opcode) void ws_keepalive(unsigned int ticks, void *param) { - int check_time = (int) time(NULL) - - cfg_get(websocket, ws_cfg, keepalive_timeout); + int check_time = + (int)time(NULL) - cfg_get(websocket, ws_cfg, keepalive_timeout); - ws_connection_t **list = NULL, - **list_head = NULL; - ws_connection_t *wsc = NULL; + ws_connection_t **list = NULL, **list_head = NULL; + ws_connection_t *wsc = NULL; /* get an array of pointer to all ws connection */ list_head = wsconn_get_list(); - if (!list_head) + if(!list_head) return; - list = list_head; - wsc = *list_head; - while (wsc && wsc->last_used < check_time) - { - if (wsc->state == WS_S_CLOSING || wsc->awaiting_pong) - { + list = list_head; + wsc = *list_head; + while(wsc && wsc->last_used < check_time) { + if(wsc->state == WS_S_CLOSING || wsc->awaiting_pong) { LM_WARN("forcibly closing connection\n"); wsconn_close_now(wsc); - } - else - { + } else { int opcode = (ws_keepalive_mechanism == KEEPALIVE_MECHANISM_PING) - ? OPCODE_PING - : OPCODE_PONG; + ? OPCODE_PING + : OPCODE_PONG; ping_pong(wsc, opcode); } @@ -894,13 +824,15 @@ int ws_close(sip_msg_t *msg) ws_connection_t *wsc; int ret; - if ((wsc = wsconn_get(msg->rcv.proto_reserved1)) == NULL) { + if((wsc = wsconn_get(msg->rcv.proto_reserved1)) == NULL) { LM_ERR("failed to retrieve WebSocket connection\n"); return -1; } - ret = (close_connection(&wsc, LOCAL_CLOSE, 1000, - str_status_normal_closure) == 0) ? 1: 0; + ret = (close_connection(&wsc, LOCAL_CLOSE, 1000, str_status_normal_closure) + == 0) + ? 1 + : 0; wsconn_put(wsc); @@ -917,12 +849,12 @@ int ws_close2(sip_msg_t *msg, int status, str *reason) ws_connection_t *wsc; int ret; - if ((wsc = wsconn_get(msg->rcv.proto_reserved1)) == NULL) { + if((wsc = wsconn_get(msg->rcv.proto_reserved1)) == NULL) { LM_ERR("failed to retrieve WebSocket connection\n"); return -1; } - ret = (close_connection(&wsc, LOCAL_CLOSE, status, *reason) == 0) ? 1: 0; + ret = (close_connection(&wsc, LOCAL_CLOSE, status, *reason) == 0) ? 1 : 0; wsconn_put(wsc); @@ -934,12 +866,12 @@ int w_ws_close2(sip_msg_t *msg, char *_status, char *_reason) int status; str reason; - if (get_int_fparam(&status, msg, (fparam_t *) _status) < 0) { + if(get_int_fparam(&status, msg, (fparam_t *)_status) < 0) { LM_ERR("failed to get status code\n"); return -1; } - if (get_str_fparam(&reason, msg, (fparam_t *) _reason) < 0) { + if(get_str_fparam(&reason, msg, (fparam_t *)_reason) < 0) { LM_ERR("failed to get reason string\n"); return -1; } @@ -951,12 +883,12 @@ int ws_close3(sip_msg_t *msg, int status, str *reason, int con) ws_connection_t *wsc; int ret; - if ((wsc = wsconn_get(con)) == NULL) { + if((wsc = wsconn_get(con)) == NULL) { LM_ERR("failed to retrieve WebSocket connection\n"); return -1; } - ret = (close_connection(&wsc, LOCAL_CLOSE, status, *reason) == 0) ? 1: 0; + ret = (close_connection(&wsc, LOCAL_CLOSE, status, *reason) == 0) ? 1 : 0; wsconn_put(wsc); @@ -969,17 +901,17 @@ int w_ws_close3(sip_msg_t *msg, char *_status, char *_reason, char *_con) str reason; int con; - if (get_int_fparam(&status, msg, (fparam_t *) _status) < 0) { + if(get_int_fparam(&status, msg, (fparam_t *)_status) < 0) { LM_ERR("failed to get status code\n"); return -1; } - if (get_str_fparam(&reason, msg, (fparam_t *) _reason) < 0) { + if(get_str_fparam(&reason, msg, (fparam_t *)_reason) < 0) { LM_ERR("failed to get reason string\n"); return -1; } - if (get_int_fparam(&con, msg, (fparam_t *) _con) < 0) { + if(get_int_fparam(&con, msg, (fparam_t *)_con) < 0) { LM_ERR("failed to get connection ID\n"); return -1; } @@ -990,21 +922,19 @@ int w_ws_close3(sip_msg_t *msg, char *_status, char *_reason, char *_con) /* * RPC command to set the state of a destination address */ -void ws_rpc_close(rpc_t* rpc, void* ctx) +void ws_rpc_close(rpc_t *rpc, void *ctx) { unsigned int id; int ret; ws_connection_t *wsc; - if(rpc->scan(ctx, "d", (int*)(&id))<1) - { + if(rpc->scan(ctx, "d", (int *)(&id)) < 1) { LM_WARN("no connection ID parameter\n"); rpc->fault(ctx, 500, "Invalid Parameters"); return; } - if ((wsc = wsconn_get(id)) == NULL) - { + if((wsc = wsconn_get(id)) == NULL) { LM_WARN("bad connection ID parameter\n"); rpc->fault(ctx, 500, "Unknown connection ID"); return; @@ -1014,29 +944,26 @@ void ws_rpc_close(rpc_t* rpc, void* ctx) wsconn_put(wsc); - if (ret < 0) - { + if(ret < 0) { LM_WARN("closing connection\n"); rpc->fault(ctx, 500, str_status_error_closing.s); return; } } -void ws_rpc_ping_pong(rpc_t* rpc, void* ctx, int opcode) +void ws_rpc_ping_pong(rpc_t *rpc, void *ctx, int opcode) { unsigned int id; ws_connection_t *wsc; int ret = 0; - if(rpc->scan(ctx, "d", (int*)(&id))<1) - { + if(rpc->scan(ctx, "d", (int *)(&id)) < 1) { LM_WARN("no connection ID parameter\n"); rpc->fault(ctx, 500, "Invalid Parameters"); return; } - if ((wsc = wsconn_get(id)) == NULL) - { + if((wsc = wsconn_get(id)) == NULL) { LM_WARN("bad connection ID parameter\n"); rpc->fault(ctx, 500, "Unknown connection ID"); return; @@ -1046,20 +973,19 @@ void ws_rpc_ping_pong(rpc_t* rpc, void* ctx, int opcode) wsconn_put(wsc); - if (ret < 0) - { + if(ret < 0) { LM_WARN("sending %s\n", OPCODE_PING ? "Ping" : "Pong"); rpc->fault(ctx, 500, str_status_error_sending.s); return; } } -void ws_rpc_ping(rpc_t* rpc, void* ctx) +void ws_rpc_ping(rpc_t *rpc, void *ctx) { ws_rpc_ping_pong(rpc, ctx, OPCODE_PING); } -void ws_rpc_pong(rpc_t* rpc, void* ctx) +void ws_rpc_pong(rpc_t *rpc, void *ctx) { ws_rpc_ping_pong(rpc, ctx, OPCODE_PONG); } diff --git a/src/modules/websocket/ws_frame.h b/src/modules/websocket/ws_frame.h index 83a4eb5300f..d2cfe3a577a 100644 --- a/src/modules/websocket/ws_frame.h +++ b/src/modules/websocket/ws_frame.h @@ -34,11 +34,7 @@ #include "../../core/rpc.h" #include "ws_conn.h" -typedef enum -{ - LOCAL_CLOSE = 0, - REMOTE_CLOSE -} ws_close_type_t; +typedef enum { LOCAL_CLOSE = 0, REMOTE_CLOSE } ws_close_type_t; enum { @@ -46,14 +42,14 @@ enum KEEPALIVE_MECHANISM_PING = 1, KEEPALIVE_MECHANISM_PONG = 2 }; -#define DEFAULT_KEEPALIVE_MECHANISM KEEPALIVE_MECHANISM_PING +#define DEFAULT_KEEPALIVE_MECHANISM KEEPALIVE_MECHANISM_PING extern int ws_keepalive_mechanism; -#define DEFAULT_KEEPALIVE_TIMEOUT 180 /* seconds */ +#define DEFAULT_KEEPALIVE_TIMEOUT 180 /* seconds */ extern str ws_ping_application_data; -#define DEFAULT_PING_APPLICATION_DATA SERVER_HDR -#define DEFAULT_PING_APPLICATION_DATA_LEN SERVER_HDR_LEN +#define DEFAULT_PING_APPLICATION_DATA SERVER_HDR +#define DEFAULT_PING_APPLICATION_DATA_LEN SERVER_HDR_LEN extern stat_var *ws_failed_connections; extern stat_var *ws_local_closed_connections; @@ -82,8 +78,8 @@ int w_ws_close2(sip_msg_t *msg, char *_status, char *_reason); int ws_close3(sip_msg_t *msg, int status, str *reason, int con); int w_ws_close3(sip_msg_t *msg, char *_status, char *_reason, char *_con); -void ws_rpc_close(rpc_t* rpc, void* ctx); -void ws_rpc_ping(rpc_t* rpc, void* ctx); -void ws_rpc_pong(rpc_t* rpc, void* ctx); +void ws_rpc_close(rpc_t *rpc, void *ctx); +void ws_rpc_ping(rpc_t *rpc, void *ctx); +void ws_rpc_pong(rpc_t *rpc, void *ctx); #endif /* _WS_FRAME_H */ diff --git a/src/modules/websocket/ws_handshake.c b/src/modules/websocket/ws_handshake.c index 1010991e26f..58e6077bb58 100644 --- a/src/modules/websocket/ws_handshake.c +++ b/src/modules/websocket/ws_handshake.c @@ -43,7 +43,7 @@ #include "websocket.h" #include "config.h" -#define WS_VERSION (13) +#define WS_VERSION (13) int ws_sub_protocols = DEFAULT_SUB_PROTOCOLS; int ws_cors_mode = CORS_MODE_NONE; @@ -67,19 +67,19 @@ static str str_hdr_sec_websocket_key = str_init("Sec-WebSocket-Key"); static str str_hdr_sec_websocket_protocol = str_init("Sec-WebSocket-Protocol"); static str str_hdr_sec_websocket_version = str_init("Sec-WebSocket-Version"); static str str_hdr_origin = str_init("Origin"); -static str str_hdr_access_control_allow_origin - = str_init("Access-Control-Allow-Origin"); -#define CONNECTION (1<<0) -#define UPGRADE (1<<1) -#define SEC_WEBSOCKET_ACCEPT (1<<2) -#define SEC_WEBSOCKET_KEY (1<<3) -#define SEC_WEBSOCKET_PROTOCOL (1<<4) -#define SEC_WEBSOCKET_VERSION (1<<5) -#define ORIGIN (1<<6) - -#define REQUIRED_HEADERS (CONNECTION | UPGRADE | SEC_WEBSOCKET_KEY\ - | SEC_WEBSOCKET_PROTOCOL\ - | SEC_WEBSOCKET_VERSION) +static str str_hdr_access_control_allow_origin = + str_init("Access-Control-Allow-Origin"); +#define CONNECTION (1 << 0) +#define UPGRADE (1 << 1) +#define SEC_WEBSOCKET_ACCEPT (1 << 2) +#define SEC_WEBSOCKET_KEY (1 << 3) +#define SEC_WEBSOCKET_PROTOCOL (1 << 4) +#define SEC_WEBSOCKET_VERSION (1 << 5) +#define ORIGIN (1 << 6) + +#define REQUIRED_HEADERS \ + (CONNECTION | UPGRADE | SEC_WEBSOCKET_KEY | SEC_WEBSOCKET_PROTOCOL \ + | SEC_WEBSOCKET_VERSION) /* HTTP status text */ static str str_status_switching_protocols = str_init("Switching Protocols"); @@ -88,33 +88,29 @@ static str str_status_upgrade_required = str_init("Upgrade Required"); static str str_status_internal_server_error = str_init("Internal Server Error"); static str str_status_service_unavailable = str_init("Service Unavailable"); -#define HDR_BUF_LEN (512) +#define HDR_BUF_LEN (512) static char headers_buf[HDR_BUF_LEN]; static char key_buf[base64_enc_len(SHA_DIGEST_LENGTH)]; static int ws_send_reply(sip_msg_t *msg, int code, str *reason, str *hdrs) { - if (hdrs && hdrs->len > 0) - { - if (add_lump_rpl(msg, hdrs->s, hdrs->len, LUMP_RPL_HDR) == 0) - { + if(hdrs && hdrs->len > 0) { + if(add_lump_rpl(msg, hdrs->s, hdrs->len, LUMP_RPL_HDR) == 0) { LM_ERR("inserting extra-headers lump\n"); update_stat(ws_failed_handshakes, 1); return -1; } } - if (ws_slb.freply(msg, code, reason) < 0) - { + if(ws_slb.freply(msg, code, reason) < 0) { LM_ERR("sending reply\n"); update_stat(ws_failed_handshakes, 1); return -1; } update_stat( - code == 101 ? ws_successful_handshakes : ws_failed_handshakes, - 1); + code == 101 ? ws_successful_handshakes : ws_failed_handshakes, 1); return 0; } @@ -136,169 +132,130 @@ int ws_handle_handshake(struct sip_msg *msg) msg->rpl_send_flags.f |= SND_F_CON_CLOSE; msg->rpl_send_flags.f |= SND_F_FORCE_CON_REUSE; - if (cfg_get(websocket, ws_cfg, enabled) == 0) - { + if(cfg_get(websocket, ws_cfg, enabled) == 0) { LM_INFO("disabled: bouncing handshake\n"); - ws_send_reply(msg, 503, &str_status_service_unavailable, - NULL); + ws_send_reply(msg, 503, &str_status_service_unavailable, NULL); return 0; } /* Retrieve TCP/TLS connection */ - if ((con = tcpconn_get(msg->rcv.proto_reserved1, 0, 0, 0, 0)) == NULL) - { + if((con = tcpconn_get(msg->rcv.proto_reserved1, 0, 0, 0, 0)) == NULL) { LM_ERR("retrieving connection\n"); - ws_send_reply(msg, 500, &str_status_internal_server_error, - NULL); + ws_send_reply(msg, 500, &str_status_internal_server_error, NULL); return 0; } - if (con->type != PROTO_TCP && con->type != PROTO_TLS) - { + if(con->type != PROTO_TCP && con->type != PROTO_TLS) { LM_ERR("unsupported transport: %d", con->type); goto end; } - if (parse_headers(msg, HDR_EOH_F, 0) < 0) - { + if(parse_headers(msg, HDR_EOH_F, 0) < 0) { LM_ERR("error parsing headers\n"); - ws_send_reply(msg, 500, &str_status_internal_server_error, - NULL); + ws_send_reply(msg, 500, &str_status_internal_server_error, NULL); goto end; } /* Process HTTP headers */ - while (hdr != NULL) - { + while(hdr != NULL) { /* Decode and validate Connection */ - if (cmp_hdrname_strzn(&hdr->name, - str_hdr_connection.s, - str_hdr_connection.len) == 0) - { + if(cmp_hdrname_strzn( + &hdr->name, str_hdr_connection.s, str_hdr_connection.len) + == 0) { strlower(&hdr->body); - if (str_search(&hdr->body, &str_upgrade) != NULL) - { + if(str_search(&hdr->body, &str_upgrade) != NULL) { LM_DBG("found %.*s: %.*s\n", - hdr->name.len, hdr->name.s, - hdr->body.len, hdr->body.s); + hdr->name.len, hdr->name.s, hdr->body.len, hdr->body.s); hdr_flags |= CONNECTION; } } /* Decode and validate Upgrade */ - else if (cmp_hdrname_strzn(&hdr->name, - str_hdr_upgrade.s, - str_hdr_upgrade.len) == 0) - { + else if(cmp_hdrname_strzn( + &hdr->name, str_hdr_upgrade.s, str_hdr_upgrade.len) + == 0) { strlower(&hdr->body); - if (str_search(&hdr->body, &str_websocket) != NULL) - { - LM_DBG("found %.*s: %.*s\n", - hdr->name.len, hdr->name.s, - hdr->body.len, hdr->body.s); + if(str_search(&hdr->body, &str_websocket) != NULL) { + LM_DBG("found %.*s: %.*s\n", hdr->name.len, hdr->name.s, + hdr->body.len, hdr->body.s); hdr_flags |= UPGRADE; } } /* Decode and validate Sec-WebSocket-Key */ - else if (cmp_hdrname_strzn(&hdr->name, - str_hdr_sec_websocket_key.s, - str_hdr_sec_websocket_key.len) == 0) - { - if (hdr_flags & SEC_WEBSOCKET_KEY) - { - LM_WARN("%.*s found multiple times\n", - hdr->name.len, hdr->name.s); - ws_send_reply(msg, 400, - &str_status_bad_request, - NULL); + else if(cmp_hdrname_strzn(&hdr->name, str_hdr_sec_websocket_key.s, + str_hdr_sec_websocket_key.len) + == 0) { + if(hdr_flags & SEC_WEBSOCKET_KEY) { + LM_WARN("%.*s found multiple times\n", hdr->name.len, + hdr->name.s); + ws_send_reply(msg, 400, &str_status_bad_request, NULL); goto end; } - LM_DBG("found %.*s: %.*s\n", - hdr->name.len, hdr->name.s, - hdr->body.len, hdr->body.s); + LM_DBG("found %.*s: %.*s\n", hdr->name.len, hdr->name.s, + hdr->body.len, hdr->body.s); key = hdr->body; hdr_flags |= SEC_WEBSOCKET_KEY; } /* Decode and validate Sec-WebSocket-Protocol */ - else if (cmp_hdrname_strzn(&hdr->name, - str_hdr_sec_websocket_protocol.s, - str_hdr_sec_websocket_protocol.len) == 0) - { + else if(cmp_hdrname_strzn(&hdr->name, str_hdr_sec_websocket_protocol.s, + str_hdr_sec_websocket_protocol.len) + == 0) { strlower(&hdr->body); - if (str_search(&hdr->body, &str_sip) != NULL) - { - LM_DBG("found %.*s: %.*s\n", - hdr->name.len, hdr->name.s, - hdr->body.len, hdr->body.s); + if(str_search(&hdr->body, &str_sip) != NULL) { + LM_DBG("found %.*s: %.*s\n", hdr->name.len, hdr->name.s, + hdr->body.len, hdr->body.s); hdr_flags |= SEC_WEBSOCKET_PROTOCOL; sub_protocol |= SUB_PROTOCOL_SIP; } - if (str_search(&hdr->body, &str_msrp) != NULL) - { - LM_DBG("found %.*s: %.*s\n", - hdr->name.len, hdr->name.s, - hdr->body.len, hdr->body.s); + if(str_search(&hdr->body, &str_msrp) != NULL) { + LM_DBG("found %.*s: %.*s\n", hdr->name.len, hdr->name.s, + hdr->body.len, hdr->body.s); hdr_flags |= SEC_WEBSOCKET_PROTOCOL; sub_protocol |= SUB_PROTOCOL_MSRP; } } /* Decode and validate Sec-WebSocket-Version */ - else if (cmp_hdrname_strzn(&hdr->name, - str_hdr_sec_websocket_version.s, - str_hdr_sec_websocket_version.len) == 0) - { - if (hdr_flags & SEC_WEBSOCKET_VERSION) - { - LM_WARN("%.*s found multiple times\n", - hdr->name.len, hdr->name.s); - ws_send_reply(msg, 400, - &str_status_bad_request, - NULL); + else if(cmp_hdrname_strzn(&hdr->name, str_hdr_sec_websocket_version.s, + str_hdr_sec_websocket_version.len) + == 0) { + if(hdr_flags & SEC_WEBSOCKET_VERSION) { + LM_WARN("%.*s found multiple times\n", hdr->name.len, + hdr->name.s); + ws_send_reply(msg, 400, &str_status_bad_request, NULL); goto end; } str2sint(&hdr->body, &version); - if (version != WS_VERSION) - { - LM_WARN("Unsupported protocol version %.*s\n", - hdr->body.len, hdr->body.s); + if(version != WS_VERSION) { + LM_WARN("Unsupported protocol version %.*s\n", hdr->body.len, + hdr->body.s); headers.s = headers_buf; - headers.len = snprintf(headers.s, HDR_BUF_LEN, - "%.*s: %d\r\n", - str_hdr_sec_websocket_version.len, - str_hdr_sec_websocket_version.s, - WS_VERSION); - ws_send_reply(msg, 426, - &str_status_upgrade_required, - &headers); + headers.len = snprintf(headers.s, HDR_BUF_LEN, "%.*s: %d\r\n", + str_hdr_sec_websocket_version.len, + str_hdr_sec_websocket_version.s, WS_VERSION); + ws_send_reply(msg, 426, &str_status_upgrade_required, &headers); goto end; } - LM_DBG("found %.*s: %.*s\n", - hdr->name.len, hdr->name.s, - hdr->body.len, hdr->body.s); + LM_DBG("found %.*s: %.*s\n", hdr->name.len, hdr->name.s, + hdr->body.len, hdr->body.s); hdr_flags |= SEC_WEBSOCKET_VERSION; } /* Decode Origin */ - else if (cmp_hdrname_strzn(&hdr->name, - str_hdr_origin.s, - str_hdr_origin.len) == 0) - { - if (hdr_flags & ORIGIN) - { - LM_WARN("%.*s found multiple times\n", - hdr->name.len, hdr->name.s); - ws_send_reply(msg, 400, - &str_status_bad_request, - NULL); + else if(cmp_hdrname_strzn( + &hdr->name, str_hdr_origin.s, str_hdr_origin.len) + == 0) { + if(hdr_flags & ORIGIN) { + LM_WARN("%.*s found multiple times\n", hdr->name.len, + hdr->name.s); + ws_send_reply(msg, 400, &str_status_bad_request, NULL); goto end; } - LM_DBG("found %.*s: %.*s\n", - hdr->name.len, hdr->name.s, - hdr->body.len, hdr->body.s); + LM_DBG("found %.*s: %.*s\n", hdr->name.len, hdr->name.s, + hdr->body.len, hdr->body.s); origin = hdr->body; hdr_flags |= ORIGIN; } @@ -308,66 +265,56 @@ int ws_handle_handshake(struct sip_msg *msg) /* Final check that all required headers/values were found */ sub_protocol &= ws_sub_protocols; - if ((hdr_flags & REQUIRED_HEADERS) != REQUIRED_HEADERS - || sub_protocol == 0) - { + if((hdr_flags & REQUIRED_HEADERS) != REQUIRED_HEADERS + || sub_protocol == 0) { LM_WARN("required headers not present\n"); headers.s = headers_buf; headers.len = 0; - if (ws_sub_protocols & SUB_PROTOCOL_SIP) + if(ws_sub_protocols & SUB_PROTOCOL_SIP) headers.len += snprintf(headers.s + headers.len, - HDR_BUF_LEN - headers.len, - "%.*s: %.*s\r\n", + HDR_BUF_LEN - headers.len, "%.*s: %.*s\r\n", str_hdr_sec_websocket_protocol.len, - str_hdr_sec_websocket_protocol.s, - str_sip.len, str_sip.s); + str_hdr_sec_websocket_protocol.s, str_sip.len, str_sip.s); - if (ws_sub_protocols & SUB_PROTOCOL_MSRP) + if(ws_sub_protocols & SUB_PROTOCOL_MSRP) headers.len += snprintf(headers.s + headers.len, - HDR_BUF_LEN - headers.len, - "%.*s: %.*s\r\n", + HDR_BUF_LEN - headers.len, "%.*s: %.*s\r\n", str_hdr_sec_websocket_protocol.len, - str_hdr_sec_websocket_protocol.s, - str_msrp.len, str_msrp.s); + str_hdr_sec_websocket_protocol.s, str_msrp.len, str_msrp.s); - headers.len += snprintf(headers.s + headers.len, - HDR_BUF_LEN - headers.len, - "%.*s: %d\r\n", - str_hdr_sec_websocket_version.len, - str_hdr_sec_websocket_version.s, - WS_VERSION); + headers.len += + snprintf(headers.s + headers.len, HDR_BUF_LEN - headers.len, + "%.*s: %d\r\n", str_hdr_sec_websocket_version.len, + str_hdr_sec_websocket_version.s, WS_VERSION); ws_send_reply(msg, 400, &str_status_bad_request, &headers); goto end; } /* Construct reply_key */ - reply_key.s = (char *) pkg_malloc( - (key.len + str_ws_guid.len) * sizeof(char)); - if (reply_key.s == NULL) - { + reply_key.s = + (char *)pkg_malloc((key.len + str_ws_guid.len) * sizeof(char)); + if(reply_key.s == NULL) { LM_ERR("allocating pkg memory\n"); - ws_send_reply(msg, 500, &str_status_internal_server_error, - NULL); + ws_send_reply(msg, 500, &str_status_internal_server_error, NULL); goto end; } memcpy(reply_key.s, key.s, key.len); memcpy(reply_key.s + key.len, str_ws_guid.s, str_ws_guid.len); reply_key.len = key.len + str_ws_guid.len; - SHA1((const unsigned char *) reply_key.s, reply_key.len, sha1); + SHA1((const unsigned char *)reply_key.s, reply_key.len, sha1); pkg_free(reply_key.s); reply_key.s = key_buf; reply_key.len = base64_enc(sha1, SHA_DIGEST_LENGTH, - (unsigned char *) reply_key.s, - base64_enc_len(SHA_DIGEST_LENGTH)); + (unsigned char *)reply_key.s, base64_enc_len(SHA_DIGEST_LENGTH)); /* Add the connection to the WebSocket connection table */ wsconn_add(msg->rcv, sub_protocol); /* Make sure Kamailio core sends future messages on this connection directly to this module */ - if (con->type == PROTO_TLS) + if(con->type == PROTO_TLS) con->type = con->rcv.proto = PROTO_WSS; else con->type = con->rcv.proto = PROTO_WS; @@ -377,71 +324,54 @@ int ws_handle_handshake(struct sip_msg *msg) headers.s = headers_buf; headers.len = 0; - if (ws_cors_mode == CORS_MODE_ANY) + if(ws_cors_mode == CORS_MODE_ANY) + headers.len += + snprintf(headers.s + headers.len, HDR_BUF_LEN - headers.len, + "%.*s: *\r\n", str_hdr_access_control_allow_origin.len, + str_hdr_access_control_allow_origin.s); + else if(ws_cors_mode == CORS_MODE_ORIGIN && origin.len > 0) headers.len += snprintf(headers.s + headers.len, - HDR_BUF_LEN - headers.len, - "%.*s: *\r\n", - str_hdr_access_control_allow_origin.len, - str_hdr_access_control_allow_origin.s); - else if (ws_cors_mode == CORS_MODE_ORIGIN && origin.len > 0) + HDR_BUF_LEN - headers.len, "%.*s: %.*s\r\n", + str_hdr_access_control_allow_origin.len, + str_hdr_access_control_allow_origin.s, origin.len, origin.s); + + if(sub_protocol & SUB_PROTOCOL_SIP) headers.len += snprintf(headers.s + headers.len, - HDR_BUF_LEN - headers.len, - "%.*s: %.*s\r\n", - str_hdr_access_control_allow_origin.len, - str_hdr_access_control_allow_origin.s, - origin.len, - origin.s); - - if (sub_protocol & SUB_PROTOCOL_SIP) + HDR_BUF_LEN - headers.len, "%.*s: %.*s\r\n", + str_hdr_sec_websocket_protocol.len, + str_hdr_sec_websocket_protocol.s, str_sip.len, str_sip.s); + else if(sub_protocol & SUB_PROTOCOL_MSRP) headers.len += snprintf(headers.s + headers.len, - HDR_BUF_LEN - headers.len, - "%.*s: %.*s\r\n", - str_hdr_sec_websocket_protocol.len, - str_hdr_sec_websocket_protocol.s, - str_sip.len, str_sip.s); - else if (sub_protocol & SUB_PROTOCOL_MSRP) - headers.len += snprintf(headers.s + headers.len, - HDR_BUF_LEN - headers.len, - "%.*s: %.*s\r\n", - str_hdr_sec_websocket_protocol.len, - str_hdr_sec_websocket_protocol.s, - str_msrp.len, str_msrp.s); - - headers.len += snprintf(headers.s + headers.len, - HDR_BUF_LEN - headers.len, - "%.*s: %.*s\r\n" - "%.*s: %.*s\r\n" - "%.*s: %.*s\r\n", - str_hdr_upgrade.len, str_hdr_upgrade.s, - str_websocket.len, str_websocket.s, - str_hdr_connection.len, str_hdr_connection.s, - str_upgrade.len, str_upgrade.s, - str_hdr_sec_websocket_accept.len, - str_hdr_sec_websocket_accept.s, reply_key.len, - reply_key.s); + HDR_BUF_LEN - headers.len, "%.*s: %.*s\r\n", + str_hdr_sec_websocket_protocol.len, + str_hdr_sec_websocket_protocol.s, str_msrp.len, str_msrp.s); + + headers.len += snprintf(headers.s + headers.len, HDR_BUF_LEN - headers.len, + "%.*s: %.*s\r\n" + "%.*s: %.*s\r\n" + "%.*s: %.*s\r\n", + str_hdr_upgrade.len, str_hdr_upgrade.s, str_websocket.len, + str_websocket.s, str_hdr_connection.len, str_hdr_connection.s, + str_upgrade.len, str_upgrade.s, str_hdr_sec_websocket_accept.len, + str_hdr_sec_websocket_accept.s, reply_key.len, reply_key.s); 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) - { + 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_EVENTROUTE_NO); wsconn_put(wsc); } goto end; - } - else - { - if (sub_protocol & SUB_PROTOCOL_SIP) + } else { + if(sub_protocol & SUB_PROTOCOL_SIP) update_stat(ws_sip_successful_handshakes, 1); - else if (sub_protocol & SUB_PROTOCOL_MSRP) + else if(sub_protocol & SUB_PROTOCOL_MSRP) update_stat(ws_msrp_successful_handshakes, 1); } tcpconn_put(con); return 1; end: - if (con) + if(con) tcpconn_put(con); return 0; } @@ -451,14 +381,14 @@ int w_ws_handle_handshake(sip_msg_t *msg, char *p1, char *p2) return ws_handle_handshake(msg); } -void ws_rpc_disable(rpc_t* rpc, void* ctx) +void ws_rpc_disable(rpc_t *rpc, void *ctx) { cfg_get(websocket, ws_cfg, enabled) = 0; LM_WARN("disabling websockets - new connections will be dropped\n"); return; } -void ws_rpc_enable(rpc_t* rpc, void* ctx) +void ws_rpc_enable(rpc_t *rpc, void *ctx) { cfg_get(websocket, ws_cfg, enabled) = 1; LM_WARN("enabling websockets\n"); diff --git a/src/modules/websocket/ws_handshake.h b/src/modules/websocket/ws_handshake.h index eba13938da5..888dc34c92d 100644 --- a/src/modules/websocket/ws_handshake.h +++ b/src/modules/websocket/ws_handshake.h @@ -32,13 +32,13 @@ #include "../../core/parser/msg_parser.h" #include "websocket.h" -#define DEFAULT_SUB_PROTOCOLS (SUB_PROTOCOL_SIP | SUB_PROTOCOL_MSRP) -#define SUB_PROTOCOL_ALL (SUB_PROTOCOL_SIP | SUB_PROTOCOL_MSRP) +#define DEFAULT_SUB_PROTOCOLS (SUB_PROTOCOL_SIP | SUB_PROTOCOL_MSRP) +#define SUB_PROTOCOL_ALL (SUB_PROTOCOL_SIP | SUB_PROTOCOL_MSRP) extern int ws_sub_protocols; -#define CORS_MODE_NONE 0 -#define CORS_MODE_ANY 1 -#define CORS_MODE_ORIGIN 2 +#define CORS_MODE_NONE 0 +#define CORS_MODE_ANY 1 +#define CORS_MODE_ORIGIN 2 extern int ws_cors_mode; extern stat_var *ws_failed_handshakes; @@ -49,7 +49,7 @@ extern stat_var *ws_msrp_successful_handshakes; int ws_handle_handshake(struct sip_msg *msg); int w_ws_handle_handshake(sip_msg_t *msg, char *p1, char *p2); -void ws_rpc_disable(rpc_t* rpc, void* ctx); -void ws_rpc_enable(rpc_t* rpc, void* ctx); +void ws_rpc_disable(rpc_t *rpc, void *ctx); +void ws_rpc_enable(rpc_t *rpc, void *ctx); #endif /* _WS_HANDSHAKE_H */