Skip to content

Commit

Permalink
websocket: use the list with ids for ws connections to do ping-pong
Browse files Browse the repository at this point in the history
- avoid using pointers to ws connections, they can get closed
  • Loading branch information
miconda committed Dec 18, 2018
1 parent 8467ef0 commit b5253b6
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 17 deletions.
125 changes: 121 additions & 4 deletions src/modules/websocket/ws_conn.c
Expand Up @@ -382,8 +382,8 @@ void wsconn_close_now(ws_connection_t *wsc)
con->timeout = get_ticks_raw();
}

/* must be called with unlocked WSCONN_LOCK */
int wsconn_put(ws_connection_t *wsc)
/* mode controls if lock needs to be aquired */
int wsconn_put_mode(ws_connection_t *wsc, int mode)
{
int destroy = 0;

Expand All @@ -393,7 +393,9 @@ int wsconn_put(ws_connection_t *wsc)
if(!wsc)
return -1;

WSCONN_LOCK;
if(mode) {
WSCONN_LOCK;
}
/* refcnt == 0*/
if(wsconn_unref(wsc)) {
/* Remove from the WebSocket used list */
Expand All @@ -418,7 +420,9 @@ int wsconn_put(ws_connection_t *wsc)

destroy = 1;
}
WSCONN_UNLOCK;
if(mode) {
WSCONN_UNLOCK;
}

LM_DBG("wsconn_put end for [%p] refcnt [%d]\n", wsc,
atomic_get(&wsc->refcnt));
Expand All @@ -430,6 +434,12 @@ int wsconn_put(ws_connection_t *wsc)
return 0;
}

/* must be called with unlocked WSCONN_LOCK */
int wsconn_put(ws_connection_t *wsc)
{
return wsconn_put_mode(wsc, 1);
}

ws_connection_t *wsconn_get(int id)
{
int id_hash = tcp_id_hash(id);
Expand All @@ -454,6 +464,30 @@ ws_connection_t *wsconn_get(int id)
return NULL;
}

int wsconn_put_id(int id)
{
int id_hash = tcp_id_hash(id);
ws_connection_t *wsc;

LM_DBG("wsconn put id [%d]\n", id);

WSCONN_LOCK;
for(wsc = wsconn_id_hash[id_hash]; wsc; wsc = wsc->id_next) {
if(wsc->id == id) {
LM_DBG("wsc [%p] refcnt [%d]\n", wsc,
atomic_get(&wsc->refcnt));
wsconn_put_mode(wsc, 0);

WSCONN_UNLOCK;

return 1;
}
}
WSCONN_UNLOCK;

return 0;
}

ws_connection_t **wsconn_get_list(void)
{
ws_connection_t **list = NULL;
Expand Down Expand Up @@ -539,6 +573,89 @@ int wsconn_put_list(ws_connection_t **list_head)
}


ws_connection_id_t *wsconn_get_list_ids(void)
{
ws_connection_id_t *list = NULL;
ws_connection_t *wsc = NULL;
size_t list_size = 0;
size_t list_len = 0;
size_t i = 0;

if(ws_verbose_list)
LM_DBG("wsconn get list ids - 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);
list_len++;
wsc = wsc->used_next;
}

if(!list_len)
goto end;

/* allocate a NULL terminated list of wsconn pointers */
list_size = (list_len + 1) * sizeof(ws_connection_id_t);
list = pkg_malloc(list_size);
if(!list)
goto end;

memset(list, 0, list_size);

/* copy */
wsc = wsconn_used_list->head;
for(i = 0; i < list_len; i++) {
if(!wsc) {
LM_ERR("Wrong list length\n");
break;
}

list[i].id = wsc->id;
wsconn_ref(wsc);
if(ws_verbose_list)
LM_DBG("wsc [%p] id [%d] ref++\n", wsc, wsc->id);

wsc = wsc->used_next;
}
list[i].id = -1; /* explicit -1 termination */

end:
WSCONN_UNLOCK;

if(ws_verbose_list)
LM_DBG("wsconn get list id returns list [%p]"
" with [%d] members\n",
list, (int)list_len);

return list;
}

int wsconn_put_list_ids(ws_connection_id_t *list_head)
{
ws_connection_id_t *list = NULL;
int i;

LM_DBG("wsconn put list id [%p]\n", list_head);

if(!list_head)
return -1;

list = list_head;
for(i=0; list[i].id!=-1; i++) {
wsconn_put_id(list[i].id);
}

pkg_free(list_head);

return 0;
}


static int ws_rpc_add_node(
rpc_t *rpc, void *ctx, void *ih, ws_connection_t *wsc)
{
Expand Down
8 changes: 8 additions & 0 deletions src/modules/websocket/ws_conn.h
Expand Up @@ -63,6 +63,11 @@ typedef struct ws_connection
str frag_buf;
} ws_connection_t;

typedef struct ws_connection_id
{
int id;
} ws_connection_id_t;

typedef struct
{
ws_connection_t *head;
Expand Down Expand Up @@ -95,5 +100,8 @@ 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);
ws_connection_id_t *wsconn_get_list_ids(void);
int wsconn_put_list_ids(ws_connection_id_t *list);
int wsconn_put_id(int id);
void ws_rpc_dump(rpc_t *rpc, void *ctx);
#endif /* _WS_CONN_H */
31 changes: 18 additions & 13 deletions src/modules/websocket/ws_frame.c
Expand Up @@ -796,31 +796,36 @@ void ws_keepalive(unsigned int ticks, void *param)
int check_time =
(int)time(NULL) - cfg_get(websocket, ws_cfg, keepalive_timeout);

ws_connection_t **list = NULL, **list_head = NULL;
ws_connection_id_t *list_head = NULL;
ws_connection_t *wsc = NULL;
int i = 0;

/* get an array of pointer to all ws connection */
list_head = wsconn_get_list();
list_head = wsconn_get_list_ids();
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) {
LM_WARN("forcibly closing connection\n");
wsconn_close_now(wsc);
} else {
int opcode = (ws_keepalive_mechanism == KEEPALIVE_MECHANISM_PING)
while(list_head[i].id!=-1) {
wsc = wsconn_get(list_head[i].id);
if(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 {
int opcode = (ws_keepalive_mechanism == KEEPALIVE_MECHANISM_PING)
? OPCODE_PING
: OPCODE_PONG;
ping_pong(wsc, opcode);
ping_pong(wsc, opcode);
}
}
if(wsc) {
wsconn_get(list_head[i].id);
}
i++;

wsc = *(++list);
}

wsconn_put_list(list_head);
wsconn_put_list_ids(list_head);
}

int ws_close(sip_msg_t *msg)
Expand Down

0 comments on commit b5253b6

Please sign in to comment.