summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/plugins/relay/relay-client.c67
-rw-r--r--src/plugins/relay/relay-client.h2
-rw-r--r--src/plugins/relay/relay-websocket.c85
3 files changed, 121 insertions, 33 deletions
diff --git a/src/plugins/relay/relay-client.c b/src/plugins/relay/relay-client.c
index 29e2cb6ff..58946ab3d 100644
--- a/src/plugins/relay/relay-client.c
+++ b/src/plugins/relay/relay-client.c
@@ -638,8 +638,8 @@ int
relay_client_recv_cb (const void *pointer, void *data, int fd)
{
struct t_relay_client *client;
- static char buffer[4096];
- int i, num_read, rc, num_frames;
+ static char buffer[4096], *buffer2;
+ int i, num_read, rc, num_frames, buffer2_size;
struct t_relay_websocket_frame *frames;
/* make C compiler happy */
@@ -693,15 +693,44 @@ relay_client_recv_cb (const void *pointer, void *data, int fd)
if (client->websocket == RELAY_CLIENT_WEBSOCKET_READY)
{
/* websocket used, decode message */
+ buffer2 = NULL;
+ buffer2_size = 0;
+ if (client->partial_ws_frame)
+ {
+ buffer2_size = num_read + client->partial_ws_frame_size;
+ buffer2 = malloc (buffer2_size);
+ if (!buffer2)
+ {
+ weechat_printf_date_tags (
+ NULL, 0, "relay_client",
+ _("%s%s: not enough memory for received data"),
+ weechat_prefix ("error"), RELAY_PLUGIN_NAME);
+ return WEECHAT_RC_OK;
+ }
+ memcpy (buffer2, client->partial_ws_frame,
+ client->partial_ws_frame_size);
+ memcpy (buffer2 + client->partial_ws_frame_size,
+ buffer, num_read);
+ }
frames = NULL;
num_frames = 0;
- rc = relay_websocket_decode_frame (client,
- (unsigned char *)buffer,
- (unsigned long long)num_read,
- &frames, &num_frames);
+ rc = relay_websocket_decode_frame (
+ client,
+ (buffer2) ? (unsigned char *)buffer2 : (unsigned char *)buffer,
+ (buffer2) ? (unsigned long long)buffer2_size : (unsigned long long)num_read,
+ &frames,
+ &num_frames);
+ if (buffer2)
+ free (buffer2);
if (!rc)
{
- /* error when decoding frame: close connection */
+ /* fatal error when decoding frame: close connection */
+ for (i = 0; i < num_frames; i++)
+ {
+ if (frames[i].payload)
+ free (frames[i].payload);
+ }
+ free (frames);
weechat_printf_date_tags (
NULL, 0, "relay_client",
_("%s%s: error decoding websocket frame for client "
@@ -1420,6 +1449,8 @@ relay_client_new (int sock, const char *address, struct t_relay_server *server)
new_client->send_data_type = RELAY_CLIENT_DATA_TEXT_MULTILINE;
break;
}
+ new_client->partial_ws_frame = NULL;
+ new_client->partial_ws_frame_size = 0;
new_client->partial_message = NULL;
relay_client_set_desc (new_client);
@@ -1586,7 +1617,8 @@ relay_client_new_with_infolist (struct t_infolist *infolist)
struct t_relay_client *new_client;
const char *str;
Bytef *ptr_dict;
- int dict_size;
+ int dict_size, ws_frame_size;
+ void *ptr_ws_frame;
new_client = malloc (sizeof (*new_client));
if (new_client)
@@ -1686,6 +1718,16 @@ relay_client_new_with_infolist (struct t_infolist *infolist)
"%llu", &(new_client->bytes_sent));
new_client->recv_data_type = weechat_infolist_integer (infolist, "recv_data_type");
new_client->send_data_type = weechat_infolist_integer (infolist, "send_data_type");
+ ptr_ws_frame = weechat_infolist_buffer (infolist, "partial_ws_frame", &ws_frame_size);
+ if (ptr_ws_frame && (ws_frame_size > 0))
+ {
+ new_client->partial_ws_frame = malloc (ws_frame_size);
+ if (new_client->partial_ws_frame)
+ {
+ memcpy (new_client->partial_ws_frame, ptr_ws_frame, ws_frame_size);
+ new_client->partial_ws_frame_size = ws_frame_size;
+ }
+ }
str = weechat_infolist_string (infolist, "partial_message");
new_client->partial_message = (str) ? strdup (str) : NULL;
@@ -1891,6 +1933,8 @@ relay_client_free (struct t_relay_client *client)
weechat_unhook (client->hook_fd);
if (client->hook_timer_send)
weechat_unhook (client->hook_timer_send);
+ if (client->partial_ws_frame)
+ free (client->partial_ws_frame);
if (client->partial_message)
free (client->partial_message);
if (client->protocol_data)
@@ -2013,6 +2057,8 @@ relay_client_add_to_infolist (struct t_infolist *infolist,
return 0;
if (!weechat_infolist_new_var_time (ptr_item, "end_time", time (NULL)))
return 0;
+ if (!weechat_infolist_new_var_buffer (ptr_item, "partial_ws_frame", NULL, 0))
+ return 0;
if (!weechat_infolist_new_var_string (ptr_item, "partial_message", NULL))
return 0;
}
@@ -2028,6 +2074,8 @@ relay_client_add_to_infolist (struct t_infolist *infolist,
return 0;
if (!weechat_infolist_new_var_time (ptr_item, "end_time", client->end_time))
return 0;
+ if (!weechat_infolist_new_var_buffer (ptr_item, "partial_ws_frame", client->partial_ws_frame, client->partial_ws_frame_size))
+ return 0;
if (!weechat_infolist_new_var_string (ptr_item, "partial_message", client->partial_message))
return 0;
}
@@ -2194,6 +2242,9 @@ relay_client_print_log ()
weechat_log_printf (" send_data_type. . . . . . : %d (%s)",
ptr_client->send_data_type,
relay_client_data_type_string[ptr_client->send_data_type]);
+ weechat_log_printf (" partial_ws_frame. . . . . : 0x%lx (%d bytes)",
+ ptr_client->partial_ws_frame,
+ ptr_client->partial_ws_frame_size);
weechat_log_printf (" partial_message . . . . . : '%s'", ptr_client->partial_message);
weechat_log_printf (" protocol_data . . . . . . : 0x%lx", ptr_client->protocol_data);
switch (ptr_client->protocol)
diff --git a/src/plugins/relay/relay-client.h b/src/plugins/relay/relay-client.h
index 9d22f629f..e4482037a 100644
--- a/src/plugins/relay/relay-client.h
+++ b/src/plugins/relay/relay-client.h
@@ -129,6 +129,8 @@ struct t_relay_client
unsigned long long bytes_sent; /* bytes sent to client */
enum t_relay_client_data_type recv_data_type; /* type recv from client */
enum t_relay_client_data_type send_data_type; /* type sent to client */
+ char *partial_ws_frame; /* part. binary websocket frame recv */
+ int partial_ws_frame_size; /* size of partial websocket frame */
char *partial_message; /* partial text message received */
void *protocol_data; /* data depending on protocol used */
struct t_relay_client_outqueue *outqueue; /* queue for outgoing msgs */
diff --git a/src/plugins/relay/relay-websocket.c b/src/plugins/relay/relay-websocket.c
index b74fb937e..2d136620b 100644
--- a/src/plugins/relay/relay-websocket.c
+++ b/src/plugins/relay/relay-websocket.c
@@ -547,7 +547,7 @@ error:
* is used).
*
* Returns:
- * 1: frame decoded successfully
+ * 1: frame(s) decoded successfully
* 0: error decoding frame (connection must be closed if it happens)
*/
@@ -558,11 +558,13 @@ relay_websocket_decode_frame (struct t_relay_client *client,
struct t_relay_websocket_frame **frames,
int *num_frames)
{
- unsigned long long i, index_buffer, length_frame_size, length_frame;
+ unsigned long long i, index_buffer, index_buffer_start_frame;
+ unsigned long long length_frame_size, length_frame;
unsigned char opcode;
size_t size_decompressed;
char *payload_decompressed;
struct t_relay_websocket_frame *frames2, *ptr_frame;
+ int size;
if (!buffer || !frames || !num_frames)
return 0;
@@ -571,22 +573,15 @@ relay_websocket_decode_frame (struct t_relay_client *client,
*num_frames = 0;
index_buffer = 0;
+ index_buffer_start_frame = 0;
/* loop to decode all frames in message */
- while (index_buffer + 1 < buffer_length)
+ while (index_buffer < buffer_length)
{
- (*num_frames)++;
-
- frames2 = realloc (*frames, sizeof (**frames) * (*num_frames));
- if (!frames2)
- return 0;
- *frames = frames2;
+ index_buffer_start_frame = index_buffer;
- ptr_frame = &((*frames)[*num_frames - 1]);
-
- ptr_frame->opcode = 0;
- ptr_frame->payload_size = 0;
- ptr_frame->payload = NULL;
+ if (index_buffer + 1 >= buffer_length)
+ goto missing_data;
opcode = buffer[index_buffer] & 15;
@@ -597,16 +592,16 @@ relay_websocket_decode_frame (struct t_relay_client *client,
if (!(buffer[index_buffer + 1] & 128))
return 0;
- /* decode frame */
+ /* decode frame length */
length_frame = buffer[index_buffer + 1] & 127;
index_buffer += 2;
if (index_buffer >= buffer_length)
- return 0;
+ goto missing_data;
if ((length_frame == 126) || (length_frame == 127))
{
length_frame_size = (length_frame == 126) ? 2 : 8;
if (index_buffer + length_frame_size > buffer_length)
- return 0;
+ goto missing_data;
length_frame = 0;
for (i = 0; i < length_frame_size; i++)
{
@@ -617,7 +612,7 @@ relay_websocket_decode_frame (struct t_relay_client *client,
/* read masks (4 bytes) */
if (index_buffer + 4 > buffer_length)
- return 0;
+ goto missing_data;
int masks[4];
for (i = 0; i < 4; i++)
{
@@ -625,6 +620,27 @@ relay_websocket_decode_frame (struct t_relay_client *client,
}
index_buffer += 4;
+ /* check if we have enough data */
+ if ((length_frame > buffer_length)
+ || (index_buffer + length_frame > buffer_length))
+ {
+ goto missing_data;
+ }
+
+ /* add a new frame in array */
+ (*num_frames)++;
+
+ frames2 = realloc (*frames, sizeof (**frames) * (*num_frames));
+ if (!frames2)
+ return 0;
+ *frames = frames2;
+
+ ptr_frame = &((*frames)[*num_frames - 1]);
+
+ ptr_frame->opcode = 0;
+ ptr_frame->payload_size = 0;
+ ptr_frame->payload = NULL;
+
/* save opcode */
switch (opcode)
{
@@ -639,13 +655,7 @@ relay_websocket_decode_frame (struct t_relay_client *client,
break;
}
- /* decode data using masks */
- if ((length_frame > buffer_length)
- || (index_buffer + length_frame > buffer_length))
- {
- return 0;
- }
-
+ /* allocate payload */
ptr_frame->payload = malloc (length_frame + 1);
if (!ptr_frame->payload)
return 0;
@@ -690,6 +700,31 @@ relay_websocket_decode_frame (struct t_relay_client *client,
index_buffer += length_frame;
}
+ if (client->partial_ws_frame)
+ {
+ free (client->partial_ws_frame);
+ client->partial_ws_frame = NULL;
+ client->partial_ws_frame_size = 0;
+ }
+
+ return 1;
+
+missing_data:
+ if (client->partial_ws_frame)
+ {
+ free (client->partial_ws_frame);
+ client->partial_ws_frame = NULL;
+ client->partial_ws_frame_size = 0;
+ }
+ size = buffer_length - index_buffer_start_frame;
+ if (size >= 0)
+ {
+ client->partial_ws_frame = malloc (size);
+ if (!client->partial_ws_frame)
+ return 0;
+ memcpy (client->partial_ws_frame, buffer + index_buffer_start_frame, size);
+ client->partial_ws_frame_size = size;
+ }
return 1;
}