Skip to content
Snippets Groups Projects
Commit 82bac6ba authored by Andy Green's avatar Andy Green
Browse files

defer PONG send until no partial send buffer


Reported-by: Andrew Canaday
Signed-off-by: default avatarAndy Green <andy.green@linaro.org>
parent af8db350
No related branches found
No related tags found
No related merge requests found
...@@ -224,6 +224,12 @@ just_kill_connection: ...@@ -224,6 +224,12 @@ just_kill_connection:
wsi->truncated_send_malloc = NULL; wsi->truncated_send_malloc = NULL;
wsi->truncated_send_len = 0; wsi->truncated_send_len = 0;
} }
if (wsi->u.ws.ping_payload_buf) {
free(wsi->u.ws.ping_payload_buf);
wsi->u.ws.ping_payload_buf = NULL;
wsi->u.ws.ping_payload_alloc = 0;
wsi->u.ws.ping_payload_len = 0;
}
} }
/* tell the user it's all over for this guy */ /* tell the user it's all over for this guy */
......
...@@ -898,16 +898,45 @@ spill: ...@@ -898,16 +898,45 @@ spill:
case LWS_WS_OPCODE_07__PING: case LWS_WS_OPCODE_07__PING:
lwsl_info("received %d byte ping, sending pong\n", lwsl_info("received %d byte ping, sending pong\n",
wsi->u.ws.rx_user_buffer_head); wsi->u.ws.rx_user_buffer_head);
lwsl_hexdump(&wsi->u.ws.rx_user_buffer[
LWS_SEND_BUFFER_PRE_PADDING], if (wsi->u.ws.ping_payload_len) {
wsi->u.ws.rx_user_buffer_head); /*
/* parrot the ping packet payload back as a pong */ * there is already a pending ping payload
n = libwebsocket_write(wsi, (unsigned char *) * we should just log and drop
&wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING], */
wsi->u.ws.rx_user_buffer_head, LWS_WRITE_PONG); lwsl_parser("DROP PING since one pending\n");
if (n < 0) goto ping_drop;
return -1; }
/* ... then just drop it */
/* control packets can only be < 128 bytes long */
if (wsi->u.ws.ping_payload_len > 128 - 4) {
lwsl_parser("DROP PING payload too large\n");
goto ping_drop;
}
/* if existing buffer is too small, drop it */
if (wsi->u.ws.ping_payload_buf &&
wsi->u.ws.ping_payload_alloc < wsi->u.ws.rx_user_buffer_head) {
free(wsi->u.ws.ping_payload_buf);
wsi->u.ws.ping_payload_buf = NULL;
}
/* if no buffer, allocate it */
if (!wsi->u.ws.ping_payload_buf) {
wsi->u.ws.ping_payload_buf = malloc(wsi->u.ws.rx_user_buffer_head + LWS_SEND_BUFFER_PRE_PADDING);
wsi->u.ws.ping_payload_alloc = wsi->u.ws.rx_user_buffer_head;
}
/* stash the pong payload */
memcpy(wsi->u.ws.ping_payload_buf + LWS_SEND_BUFFER_PRE_PADDING,
&wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING],
wsi->u.ws.rx_user_buffer_head);
wsi->u.ws.ping_payload_len = wsi->u.ws.rx_user_buffer_head;
/* get it sent as soon as possible */
libwebsocket_callback_on_writable(wsi->protocol->owning_server, wsi);
ping_drop:
wsi->u.ws.rx_user_buffer_head = 0; wsi->u.ws.rx_user_buffer_head = 0;
return 0; return 0;
......
...@@ -565,6 +565,10 @@ struct _lws_websocket_related { ...@@ -565,6 +565,10 @@ struct _lws_websocket_related {
unsigned int this_frame_masked:1; unsigned int this_frame_masked:1;
unsigned int inside_frame:1; /* next write will be more of frame */ unsigned int inside_frame:1; /* next write will be more of frame */
unsigned int clean_buffer:1; /* buffer not rewritten by extension */ unsigned int clean_buffer:1; /* buffer not rewritten by extension */
unsigned char *ping_payload_buf; /* non-NULL if malloc'd */
unsigned int ping_payload_alloc; /* length malloc'd */
unsigned int ping_payload_len; /* nonzero if PONG pending */
}; };
struct libwebsocket { struct libwebsocket {
......
...@@ -48,7 +48,24 @@ lws_handle_POLLOUT_event(struct libwebsocket_context *context, ...@@ -48,7 +48,24 @@ lws_handle_POLLOUT_event(struct libwebsocket_context *context,
return -1; /* retry closing now */ return -1; /* retry closing now */
} }
/* pending control packets have next priority */
if (wsi->u.ws.ping_payload_len) {
n = libwebsocket_write(wsi,
&wsi->u.ws.ping_payload_buf[
LWS_SEND_BUFFER_PRE_PADDING],
wsi->u.ws.ping_payload_len,
LWS_WRITE_PONG);
if (n < 0)
return -1;
/* well he is sent, mark him done */
wsi->u.ws.ping_payload_len = 0;
/* leave POLLOUT active either way */
return 0;
}
/* if nothing critical, user can get the callback */
m = lws_ext_callback_for_each_active(wsi, LWS_EXT_CALLBACK_IS_WRITEABLE, m = lws_ext_callback_for_each_active(wsi, LWS_EXT_CALLBACK_IS_WRITEABLE,
NULL, 0); NULL, 0);
if (handled == 1) if (handled == 1)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment