summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/plugins/relay/relay-client.c280
-rw-r--r--src/plugins/relay/relay-client.h9
2 files changed, 158 insertions, 131 deletions
diff --git a/src/plugins/relay/relay-client.c b/src/plugins/relay/relay-client.c
index d8ebf8d39..84078a577 100644
--- a/src/plugins/relay/relay-client.c
+++ b/src/plugins/relay/relay-client.c
@@ -631,6 +631,113 @@ relay_client_read_websocket_frames (struct t_relay_client *client,
}
/*
+ * Reads a buffer of bytes from a client.
+ */
+
+void
+relay_client_recv_buffer (struct t_relay_client *client,
+ const char *buffer, int buffer_size)
+{
+ struct t_relay_websocket_frame *frames;
+ char *buffer2;
+ int rc, i, buffer2_size, num_frames;
+
+ /*
+ * if we are receiving the first message from client, check if it looks
+ * like a websocket
+ */
+ if (client->bytes_recv == 0)
+ {
+ if (relay_websocket_is_valid_http_get (client->protocol, buffer))
+ {
+ /*
+ * web socket is just initializing for now, it's not accepted
+ * (we will check later with "http_headers" if web socket is
+ * valid or not)
+ */
+ client->websocket = RELAY_CLIENT_WEBSOCKET_INITIALIZING;
+ }
+ }
+
+ client->bytes_recv += buffer_size;
+
+ if (client->websocket == RELAY_CLIENT_WEBSOCKET_READY)
+ {
+ /* websocket used, decode message */
+ buffer2 = NULL;
+ buffer2_size = 0;
+ if (client->partial_ws_frame)
+ {
+ buffer2_size = buffer_size + 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 message"),
+ weechat_prefix ("error"), RELAY_PLUGIN_NAME);
+ return;
+ }
+ memcpy (buffer2, client->partial_ws_frame,
+ client->partial_ws_frame_size);
+ memcpy (buffer2 + client->partial_ws_frame_size,
+ buffer, buffer_size);
+ }
+ frames = NULL;
+ num_frames = 0;
+ rc = relay_websocket_decode_frame (
+ client,
+ (buffer2) ? (unsigned char *)buffer2 : (unsigned char *)buffer,
+ (buffer2) ? (unsigned long long)buffer2_size : (unsigned long long)buffer_size,
+ &frames,
+ &num_frames);
+ if (buffer2)
+ free (buffer2);
+ if (!rc)
+ {
+ /* 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 "
+ "%s%s%s"),
+ weechat_prefix ("error"), RELAY_PLUGIN_NAME,
+ RELAY_COLOR_CHAT_CLIENT,
+ client->desc,
+ RELAY_COLOR_CHAT);
+ relay_client_set_status (client, RELAY_STATUS_DISCONNECTED);
+ return;
+ }
+ relay_client_read_websocket_frames (client, frames, num_frames);
+ for (i = 0; i < num_frames; i++)
+ {
+ if (frames[i].payload)
+ free (frames[i].payload);
+ }
+ free (frames);
+ }
+ else
+ {
+ if ((client->websocket == RELAY_CLIENT_WEBSOCKET_INITIALIZING)
+ || (client->recv_data_type == RELAY_CLIENT_DATA_HTTP))
+ {
+ relay_http_recv (client, buffer);
+ }
+ else if ((client->recv_data_type == RELAY_CLIENT_DATA_TEXT_LINE)
+ || (client->recv_data_type == RELAY_CLIENT_DATA_TEXT_MULTILINE))
+ {
+ relay_client_recv_text (client, buffer);
+ }
+ }
+ relay_buffer_refresh (NULL);
+}
+
+/*
* Reads data from a client.
*/
@@ -638,9 +745,8 @@ int
relay_client_recv_cb (const void *pointer, void *data, int fd)
{
struct t_relay_client *client;
- static char buffer[4096], *buffer2;
- int i, num_read, rc, num_frames, buffer2_size;
- struct t_relay_websocket_frame *frames;
+ static char buffer[4096];
+ int num_read;
/* make C compiler happy */
(void) data;
@@ -670,100 +776,7 @@ relay_client_recv_cb (const void *pointer, void *data, int fd)
if (num_read > 0)
{
buffer[num_read] = '\0';
-
- /*
- * if we are receiving the first message from client, check if it looks
- * like a websocket
- */
- if (client->bytes_recv == 0)
- {
- if (relay_websocket_is_valid_http_get (client->protocol, buffer))
- {
- /*
- * web socket is just initializing for now, it's not accepted
- * (we will check later with "http_headers" if web socket is
- * valid or not)
- */
- client->websocket = RELAY_CLIENT_WEBSOCKET_INITIALIZING;
- }
- }
-
- client->bytes_recv += num_read;
-
- 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 message"),
- 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,
- (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)
- {
- /* 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 "
- "%s%s%s"),
- weechat_prefix ("error"), RELAY_PLUGIN_NAME,
- RELAY_COLOR_CHAT_CLIENT,
- client->desc,
- RELAY_COLOR_CHAT);
- relay_client_set_status (client, RELAY_STATUS_DISCONNECTED);
- return WEECHAT_RC_OK;
- }
- relay_client_read_websocket_frames (client, frames, num_frames);
- for (i = 0; i < num_frames; i++)
- {
- if (frames[i].payload)
- free (frames[i].payload);
- }
- free (frames);
- }
- else
- {
- if ((client->websocket == RELAY_CLIENT_WEBSOCKET_INITIALIZING)
- || (client->recv_data_type == RELAY_CLIENT_DATA_HTTP))
- {
- relay_http_recv (client, buffer);
- }
- else if ((client->recv_data_type == RELAY_CLIENT_DATA_TEXT_LINE)
- || (client->recv_data_type == RELAY_CLIENT_DATA_TEXT_MULTILINE))
- {
- relay_client_recv_text (client, buffer);
- }
- }
- relay_buffer_refresh (NULL);
+ relay_client_recv_buffer (client, buffer, num_read);
}
else
{
@@ -870,6 +883,30 @@ relay_client_outqueue_free_all (struct t_relay_client *client)
}
/*
+ * Sends data to a client.
+ *
+ * Returns the number of bytes send to the client.
+ */
+
+int
+relay_client_send_data (struct t_relay_client *client,
+ const char *data, int data_size)
+{
+ if (client->tls)
+ {
+ return (client->sock >= 0) ?
+ gnutls_record_send (client->gnutls_sess, data, data_size) :
+ data_size;
+ }
+ else
+ {
+ return (client->sock >= 0) ?
+ send (client->sock, data, data_size, 0) :
+ data_size;
+ }
+}
+
+/*
* Sends messages in outqueue for a client.
*/
@@ -881,22 +918,9 @@ relay_client_send_outqueue (struct t_relay_client *client)
while (client->outqueue)
{
- if (client->tls)
- {
- num_sent = (client->sock >= 0) ?
- gnutls_record_send (client->gnutls_sess,
- client->outqueue->data,
- client->outqueue->data_size) :
- client->outqueue->data_size;
- }
- else
- {
- num_sent = (client->sock >= 0) ?
- send (client->sock,
- client->outqueue->data,
- client->outqueue->data_size, 0) :
- client->outqueue->data_size;
- }
+ num_sent = relay_client_send_data (client,
+ client->outqueue->data,
+ client->outqueue->data_size);
if (num_sent >= 0)
{
for (i = 0; i < 2; i++)
@@ -1114,8 +1138,8 @@ relay_client_outqueue_add (struct t_relay_client *client,
int
relay_client_send (struct t_relay_client *client,
enum t_relay_client_msg_type msg_type,
- const char *data,
- int data_size, const char *message_raw_buffer)
+ const char *data, int data_size,
+ const char *message_raw_buffer)
{
int num_sent, raw_size[2], raw_flags[2], opcode, i;
enum t_relay_client_msg_type raw_msg_type[2];
@@ -1123,12 +1147,12 @@ relay_client_send (struct t_relay_client *client,
unsigned long long length_frame;
const char *ptr_data, *raw_msg[2];
- if (client->sock < 0)
- return -1;
-
ptr_data = data;
websocket_frame = NULL;
+ if (client->fake_send_func)
+ (void) (*client->fake_send_func) (client, ptr_data, data_size);
+
/* set raw messages */
for (i = 0; i < 2; i++)
{
@@ -1225,18 +1249,7 @@ relay_client_send (struct t_relay_client *client,
}
else
{
- if (client->tls)
- {
- num_sent = (client->sock >= 0) ?
- gnutls_record_send (client->gnutls_sess, ptr_data, data_size) :
- data_size;
- }
- else
- {
- num_sent = (client->sock >= 0) ?
- send (client->sock, ptr_data, data_size, 0) : data_size;
- }
-
+ num_sent = relay_client_send_data (client, ptr_data, data_size);
if (num_sent >= 0)
{
for (i = 0; i < 2; i++)
@@ -1357,7 +1370,7 @@ relay_client_timer_cb (const void *pointer, void *data, int remaining_calls)
relay_buffer_refresh (NULL);
}
}
- else if (ptr_client->sock >= 0)
+ else
{
/* send messages in outqueue */
relay_client_send_outqueue (ptr_client);
@@ -1403,6 +1416,7 @@ relay_client_new (int sock, const char *address, struct t_relay_server *server)
new_client->server_port = server->port;
new_client->tls = server->tls;
new_client->gnutls_sess = NULL;
+ new_client->fake_send_func = NULL;
new_client->hook_timer_handshake = NULL;
new_client->gnutls_handshake_ok = 0;
new_client->websocket = RELAY_CLIENT_WEBSOCKET_NOT_USED;
@@ -1633,6 +1647,7 @@ relay_client_new_with_infolist (struct t_infolist *infolist)
else
new_client->tls = weechat_infolist_integer (infolist, "ssl");
new_client->gnutls_sess = NULL;
+ new_client->fake_send_func = NULL;
new_client->hook_timer_handshake = NULL;
new_client->gnutls_handshake_ok = 0;
new_client->websocket = weechat_infolist_integer (infolist, "websocket");
@@ -2083,6 +2098,8 @@ relay_client_add_to_infolist (struct t_infolist *infolist,
return 0;
if (!weechat_infolist_new_var_integer (ptr_item, "tls", client->tls))
return 0;
+ if (!weechat_infolist_new_var_pointer (ptr_item, "fake_send_func", client->fake_send_func))
+ return 0;
if (!weechat_infolist_new_var_integer (ptr_item, "websocket", client->websocket))
return 0;
if (!weechat_infolist_new_var_integer (ptr_item, "ws_deflate_enabled", client->ws_deflate->enabled))
@@ -2208,6 +2225,7 @@ relay_client_print_log ()
weechat_log_printf (" server_port . . . . . . . : %d", ptr_client->server_port);
weechat_log_printf (" tls . . . . . . . . . . . : %d", ptr_client->tls);
weechat_log_printf (" gnutls_sess . . . . . . . : 0x%lx", ptr_client->gnutls_sess);
+ weechat_log_printf (" fake_send_func. . . . . . : 0x%lx", ptr_client->fake_send_func);
weechat_log_printf (" hook_timer_handshake. . . : 0x%lx", ptr_client->hook_timer_handshake);
weechat_log_printf (" gnutls_handshake_ok . . . : 0x%lx", ptr_client->gnutls_handshake_ok);
weechat_log_printf (" websocket . . . . . . . . ; %d", ptr_client->websocket);
diff --git a/src/plugins/relay/relay-client.h b/src/plugins/relay/relay-client.h
index e4482037a..5978181fd 100644
--- a/src/plugins/relay/relay-client.h
+++ b/src/plugins/relay/relay-client.h
@@ -81,6 +81,11 @@ enum t_relay_client_msg_type
((client->status == RELAY_STATUS_AUTH_FAILED) || \
(client->status == RELAY_STATUS_DISCONNECTED))
+/* fake send function (for tests) */
+
+typedef void (t_relay_fake_send_func)(void *client,
+ const char *data, int data_size);
+
/* output queue of messages to client */
struct t_relay_client_outqueue
@@ -105,6 +110,8 @@ struct t_relay_client
int server_port; /* port used for connection */
int tls; /* 1 if TLS is enabled */
gnutls_session_t gnutls_sess; /* gnutls session (only if TLS used) */
+ t_relay_fake_send_func *fake_send_func; /* function called for fake send*/
+ /* (used in tests only) */
struct t_hook *hook_timer_handshake; /* timer for doing gnutls handshake*/
int gnutls_handshake_ok; /* 1 if handshake was done and OK */
enum t_relay_client_websocket_status websocket; /* websocket status */
@@ -152,6 +159,8 @@ extern struct t_relay_client *relay_client_search_by_id (int id);
extern int relay_client_status_search (const char *name);
extern int relay_client_count_active_by_port (int server_port);
extern void relay_client_set_desc (struct t_relay_client *client);
+extern void relay_client_recv_buffer (struct t_relay_client *client,
+ const char *buffer, int buffer_size);
extern int relay_client_recv_cb (const void *pointer, void *data, int fd);
extern int relay_client_send (struct t_relay_client *client,
enum t_relay_client_msg_type msg_type,