1
0
mirror of https://github.com/weechat/weechat.git synced 2026-07-05 01:03:14 +02:00

relay: add experimental websocket server support (RFC 6455) for irc and weechat protocols, new option relay.network.websocket_allowed_origins

It is a partial implementation of RFC 6455: fragmentation and control frames are
not yet supported.
Text and binary frames are supported.
This commit is contained in:
Sebastien Helleu
2013-02-10 20:22:13 +01:00
parent eb11921f16
commit c2aeb69c46
42 changed files with 1385 additions and 199 deletions
+2 -1
View File
@@ -32,7 +32,8 @@ relay-info.c relay-info.h
relay-network.c relay-network.h
relay-raw.c relay-raw.h
relay-server.c relay-server.h
relay-upgrade.c relay-upgrade.h)
relay-upgrade.c relay-upgrade.h
relay-websocket.c relay-websocket.h)
SET_TARGET_PROPERTIES(relay PROPERTIES PREFIX "")
SET (LINK_LIBS)
+3 -1
View File
@@ -52,7 +52,9 @@ relay_la_SOURCES = relay.c \
relay-server.c \
relay-server.h \
relay-upgrade.c \
relay-upgrade.h
relay-upgrade.h \
relay-websocket.c \
relay-websocket.h
relay_la_LDFLAGS = -module
relay_la_LIBADD = $(RELAY_LFLAGS) $(ZLIB_LFLAGS) $(GNUTLS_LFLAGS)
+3 -33
View File
@@ -231,13 +231,12 @@ relay_irc_sendf (struct t_relay_client *client, const char *format, ...)
str_message = weechat_hashtable_get (hashtable_out, hash_key);
if (!str_message)
break;
relay_raw_print (client, RELAY_RAW_FLAG_SEND, "%s", str_message);
length = strlen (str_message) + 16 + 1;
message = malloc (length);
if (message)
{
snprintf (message, length, "%s\r\n", str_message);
relay_client_send (client, message, strlen (message));
relay_client_send (client, message, strlen (message), NULL);
free (message);
}
number++;
@@ -1290,9 +1289,9 @@ relay_irc_recv_command_capab (struct t_relay_client *client,
*/
void
relay_irc_recv_one_msg (struct t_relay_client *client, char *data)
relay_irc_recv (struct t_relay_client *client, const char *data)
{
char *pos, str_time[128], str_signal[128], str_server_channel[256];
char str_time[128], str_signal[128], str_server_channel[256];
char str_command[128], *target, **irc_argv;
const char *irc_command, *irc_channel, *irc_args, *irc_args2;
int irc_argc, redirect_msg;
@@ -1304,11 +1303,6 @@ relay_irc_recv_one_msg (struct t_relay_client *client, char *data)
irc_argv = NULL;
irc_argc = 0;
/* remove \r at the end of message */
pos = strchr (data, '\r');
if (pos)
pos[0] = '\0';
/* display debug message */
if (weechat_relay_plugin->debug >= 2)
{
@@ -1320,9 +1314,6 @@ relay_irc_recv_one_msg (struct t_relay_client *client, char *data)
data);
}
/* display message in raw buffer */
relay_raw_print (client, RELAY_RAW_FLAG_RECV, "%s", data);
/* parse IRC message */
hash_parsed = relay_irc_message_parse (data);
if (!hash_parsed)
@@ -1707,27 +1698,6 @@ end:
weechat_string_free_split (irc_argv);
}
/*
* Reads data from a client.
*/
void
relay_irc_recv (struct t_relay_client *client, const char *data)
{
char **items;
int items_count, i;
items = weechat_string_split (data, "\n", 0, 0, &items_count);
if (items)
{
for (i = 0; i < items_count; i++)
{
relay_irc_recv_one_msg (client, items[i]);
}
weechat_string_free_split (items);
}
}
/*
* Closes connection with client.
*/
+1 -1
View File
@@ -63,7 +63,7 @@ enum t_relay_irc_server_capab
};
extern void relay_irc_recv (struct t_relay_client *client,
const char *data);
const char *data);
extern void relay_irc_close_connection (struct t_relay_client *client);
extern void relay_irc_alloc (struct t_relay_client *client);
extern void relay_irc_alloc_with_infolist (struct t_relay_client *client,
+412 -23
View File
@@ -41,7 +41,9 @@
#include "relay-config.h"
#include "relay-buffer.h"
#include "relay-network.h"
#include "relay-raw.h"
#include "relay-server.h"
#include "relay-websocket.h"
char *relay_client_status_string[] = /* strings for status */
@@ -49,6 +51,9 @@ char *relay_client_status_string[] = /* strings for status */
N_("connected"), N_("auth failed"), N_("disconnected")
};
char *relay_client_data_type_string[] = /* strings for data types */
{ "text", "binary" };
struct t_relay_client *relay_clients = NULL;
struct t_relay_client *last_relay_client = NULL;
int relay_client_count = 0; /* number of clients */
@@ -216,6 +221,168 @@ relay_client_handshake_timer_cb (void *data, int remaining_calls)
}
#endif
/*
* Reads text data from a client: splits data on '\n' and keep a partial message
* if date does not end with '\n'.
*/
void
relay_client_recv_text (struct t_relay_client *client, const char *data)
{
char *new_partial, *raw_msg, **lines, *pos, *tmp, *handshake;
int i, num_lines, length, rc;
if (client->partial_message)
{
new_partial = realloc (client->partial_message,
strlen (client->partial_message) +
strlen (data) + 1);
if (!new_partial)
return;
client->partial_message = new_partial;
strcat (client->partial_message, data);
}
else
client->partial_message = strdup (data);
pos = strrchr (client->partial_message, '\n');
if (pos)
{
/* print message in raw buffer */
raw_msg = weechat_strndup (client->partial_message,
pos - client->partial_message + 1);
if (raw_msg)
{
relay_raw_print (client, RELAY_RAW_FLAG_RECV,
raw_msg, strlen (raw_msg) + 1);
free (raw_msg);
}
pos[0] = '\0';
lines = weechat_string_split (client->partial_message, "\n",
0, 0, &num_lines);
if (lines)
{
for (i = 0; i < num_lines; i++)
{
/* remove final '\r' */
length = strlen (lines[i]);
if ((length > 0) && (lines[i][length - 1] == '\r'))
lines[i][length - 1] = '\0';
/* if websocket is initializing */
if (client->websocket == 1)
{
if (lines[i][0])
{
/* web socket is initializing, read HTTP headers */
relay_websocket_save_header (client, lines[i]);
}
else
{
/*
* empty line means that we have received all HTTP
* headers: then we check the validity of websocket, and
* if it is OK, we'll do the handshake and answer to the
* client
*/
rc = relay_websocket_client_handshake_valid (client);
if (rc == 0)
{
/* handshake from client is valid */
handshake = relay_websocket_build_handshake (client);
if (handshake)
{
relay_client_send (client, handshake,
strlen (handshake), NULL);
free (handshake);
client->websocket = 2;
}
}
else
{
switch (rc)
{
case -1:
relay_websocket_send_http (client,
"400 Bad Request");
if (weechat_relay_plugin->debug >= 1)
{
weechat_printf_tags (NULL, "relay_client",
_("%s%s: invalid websocket "
"handshake received for "
"client %s%s%s"),
weechat_prefix ("error"),
RELAY_PLUGIN_NAME,
RELAY_COLOR_CHAT_CLIENT,
client->desc,
RELAY_COLOR_CHAT);
}
break;
case -2:
relay_websocket_send_http (client,
"403 Forbidden");
if (weechat_relay_plugin->debug >= 1)
{
weechat_printf_tags (NULL, "relay_client",
_("%s%s: origin \"%s\" "
"not allowed for websocket"),
weechat_prefix ("error"),
RELAY_PLUGIN_NAME,
weechat_hashtable_get (client->http_headers,
"Origin"));
}
break;
}
relay_client_set_status (client, RELAY_STATUS_DISCONNECTED);
}
/* remove HTTP headers */
weechat_hashtable_free (client->http_headers);
client->http_headers = NULL;
/*
* discard all received data after the handshake
* received from client, and return immediately
*/
free (client->partial_message);
client->partial_message = NULL;
return;
}
}
else
{
/* receive text from client */
switch (client->protocol)
{
case RELAY_PROTOCOL_WEECHAT:
relay_weechat_recv (client, lines[i]);
break;
case RELAY_PROTOCOL_IRC:
relay_irc_recv (client, lines[i]);
break;
case RELAY_NUM_PROTOCOLS:
break;
}
}
}
weechat_string_free_split (lines);
}
if (pos[1])
{
tmp = strdup (pos + 1);
free (client->partial_message);
client->partial_message = tmp;
}
else
{
free (client->partial_message);
client->partial_message = NULL;
}
}
}
/*
* Reads data from a client.
*/
@@ -224,7 +391,8 @@ int
relay_client_recv_cb (void *arg_client, int fd)
{
struct t_relay_client *client;
static char buffer[4096 + 2];
static char buffer[4096], decoded[4096];
const char *ptr_buffer;
int num_read;
/* make C compiler happy */
@@ -245,18 +413,63 @@ relay_client_recv_cb (void *arg_client, int fd)
if (num_read > 0)
{
client->bytes_recv += num_read;
buffer[num_read] = '\0';
switch (client->protocol)
ptr_buffer = buffer;
/*
* if we are receiving the first message from client, check if it looks
* like a websocket
*/
if (client->bytes_recv == 0)
{
case RELAY_PROTOCOL_WEECHAT:
relay_weechat_recv (client, buffer);
break;
case RELAY_PROTOCOL_IRC:
relay_irc_recv (client, buffer);
break;
case RELAY_NUM_PROTOCOLS:
break;
if (relay_websocket_is_http_get_weechat (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 = 1;
client->http_headers = weechat_hashtable_new (32,
WEECHAT_HASHTABLE_STRING,
WEECHAT_HASHTABLE_STRING,
NULL,
NULL);
}
}
client->bytes_recv += num_read;
if (client->websocket == 2)
{
/* websocket used, decode message */
if (!relay_websocket_decode_frame ((unsigned char *)buffer, num_read,
(unsigned char *)decoded))
{
/* error when decoding frame: close connection */
weechat_printf_tags (NULL, "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;
}
ptr_buffer = decoded;
}
if ((client->websocket == 1)
|| (client->recv_data_type == RELAY_CLIENT_DATA_TEXT))
{
/* websocket initializing or text data for this client */
relay_client_recv_text (client, ptr_buffer);
}
else
{
/* receive buffer as-is (binary data) */
/* currently, all supported protocols receive only text, no binary */
}
relay_buffer_refresh (NULL);
}
@@ -310,10 +523,13 @@ relay_client_recv_cb (void *arg_client, int fd)
*/
void
relay_client_outqueue_add (struct t_relay_client *client, const char *data,
int data_size)
relay_client_outqueue_add (struct t_relay_client *client,
const char *data, int data_size,
int raw_flags[2], const char *raw_message[2],
int raw_size[2])
{
struct t_relay_client_outqueue *new_outqueue;
int i;
if (!client || !data || (data_size <= 0))
return;
@@ -329,6 +545,23 @@ relay_client_outqueue_add (struct t_relay_client *client, const char *data,
}
memcpy (new_outqueue->data, data, data_size);
new_outqueue->data_size = data_size;
for (i = 0; i < 2; i++)
{
new_outqueue->raw_flags[i] = 0;
new_outqueue->raw_message[i] = NULL;
new_outqueue->raw_size[i] = 0;
if (raw_message && raw_message[i] && (raw_size[i] > 0))
{
new_outqueue->raw_message[i] = malloc (raw_size[i]);
if (new_outqueue->raw_message[i])
{
new_outqueue->raw_flags[i] = raw_flags[i];
memcpy (new_outqueue->raw_message[i], raw_message[i],
raw_size[i]);
new_outqueue->raw_size[i] = raw_size[i];
}
}
}
new_outqueue->prev_outqueue = client->last_outqueue;
new_outqueue->next_outqueue = NULL;
@@ -367,6 +600,10 @@ relay_client_outqueue_free (struct t_relay_client *client,
/* free data */
if (outqueue->data)
free (outqueue->data);
if (outqueue->raw_message[0])
free (outqueue->raw_message[0]);
if (outqueue->raw_message[1])
free (outqueue->raw_message[1]);
free (outqueue);
/* set new head */
@@ -389,18 +626,88 @@ relay_client_outqueue_free_all (struct t_relay_client *client)
/*
* Sends data to client (adds in out queue if it's impossible to send now).
*
* If "message_raw_buffer" is not NULL, it is used for display in raw buffer
* and replaces display of data, which is default.
*
* Returns number of bytes sent to client, -1 if error.
*/
int
relay_client_send (struct t_relay_client *client, const char *data,
int data_size)
int data_size, const char *message_raw_buffer)
{
int num_sent;
int num_sent, raw_size[2], raw_flags[2], i;
char *websocket_frame;
unsigned long long length_frame;
const char *ptr_data, *raw_msg[2];
if (client->sock < 0)
return -1;
ptr_data = data;
websocket_frame = NULL;
/* set raw messages */
for (i = 0; i < 2; i++)
{
raw_flags[i] = RELAY_RAW_FLAG_SEND;
raw_msg[i] = NULL;
raw_size[i] = 0;
}
if (message_raw_buffer)
{
if (weechat_relay_plugin->debug >= 2)
{
raw_msg[0] = message_raw_buffer;
raw_size[0] = strlen (message_raw_buffer) + 1;
raw_msg[1] = data;
raw_size[1] = data_size;
raw_flags[1] |= RELAY_RAW_FLAG_BINARY;
if ((client->websocket == 1)
|| (client->send_data_type == RELAY_CLIENT_DATA_TEXT))
{
raw_size[1]--;
}
}
else
{
raw_msg[0] = message_raw_buffer;
raw_size[0] = strlen (message_raw_buffer) + 1;
}
}
else
{
raw_msg[0] = data;
raw_size[0] = data_size;
if ((client->websocket != 1)
&& (client->send_data_type == RELAY_CLIENT_DATA_BINARY))
{
/*
* set binary flag if we send binary to client
* (except if websocket == 1, which means that websocket is
* initializing, and then we are sending HTTP data, as text)
*/
raw_flags[0] |= RELAY_RAW_FLAG_BINARY;
}
else
{
/* count the final '\0' in size */
raw_size[0]++;
}
}
/* if websocket is initialized, encode data in a websocket frame */
if (client->websocket == 2)
{
websocket_frame = relay_websocket_encode_frame (client, data, data_size,
&length_frame);
if (websocket_frame)
{
ptr_data = websocket_frame;
data_size = length_frame;
}
}
num_sent = -1;
/*
@@ -409,19 +716,28 @@ relay_client_send (struct t_relay_client *client, const char *data,
*/
if (client->outqueue)
{
relay_client_outqueue_add (client, data, data_size);
relay_client_outqueue_add (client, ptr_data, data_size,
raw_flags, raw_msg, raw_size);
}
else
{
#ifdef HAVE_GNUTLS
if (client->ssl)
num_sent = gnutls_record_send (client->gnutls_sess, data, data_size);
num_sent = gnutls_record_send (client->gnutls_sess, ptr_data, data_size);
else
#endif
num_sent = send (client->sock, data, data_size, 0);
num_sent = send (client->sock, ptr_data, data_size, 0);
if (num_sent >= 0)
{
for (i = 0; i < 2; i++)
{
if (raw_msg[i])
{
relay_raw_print (client,
raw_flags[i], raw_msg[i], raw_size[i]);
}
}
if (num_sent > 0)
{
client->bytes_sent += num_sent;
@@ -430,8 +746,9 @@ relay_client_send (struct t_relay_client *client, const char *data,
if (num_sent < data_size)
{
/* some data was not sent, add it to outqueue */
relay_client_outqueue_add (client, data + num_sent,
data_size - num_sent);
relay_client_outqueue_add (client, ptr_data + num_sent,
data_size - num_sent,
NULL, NULL, NULL);
}
}
else if (num_sent < 0)
@@ -443,7 +760,8 @@ relay_client_send (struct t_relay_client *client, const char *data,
|| (num_sent == GNUTLS_E_INTERRUPTED))
{
/* add message to queue (will be sent later) */
relay_client_outqueue_add (client, data, data_size);
relay_client_outqueue_add (client, ptr_data, data_size,
raw_flags, raw_msg, raw_size);
}
else
{
@@ -466,7 +784,8 @@ relay_client_send (struct t_relay_client *client, const char *data,
if ((errno == EAGAIN) || (errno == EWOULDBLOCK))
{
/* add message to queue (will be sent later) */
relay_client_outqueue_add (client, data, data_size);
relay_client_outqueue_add (client, ptr_data, data_size,
raw_flags, raw_msg, raw_size);
}
else
{
@@ -486,6 +805,9 @@ relay_client_send (struct t_relay_client *client, const char *data,
}
}
if (websocket_frame)
free (websocket_frame);
return num_sent;
}
@@ -497,7 +819,7 @@ int
relay_client_timer_cb (void *data, int remaining_calls)
{
struct t_relay_client *ptr_client;
int num_sent;
int num_sent, i;
char *buf;
/* make C compiler happy */
@@ -527,6 +849,26 @@ relay_client_timer_cb (void *data, int remaining_calls)
}
if (num_sent >= 0)
{
for (i = 0; i < 2; i++)
{
if (ptr_client->outqueue->raw_message
&& ptr_client->outqueue->raw_message[i])
{
/*
* print raw message and remove it from outqueue
* (so that it is displayed only one time, even if
* message is sent in many chunks)
*/
relay_raw_print (ptr_client,
ptr_client->outqueue->raw_flags[i],
ptr_client->outqueue->raw_message[i],
ptr_client->outqueue->raw_size[i]);
ptr_client->outqueue->raw_flags[i] = 0;
free (ptr_client->outqueue->raw_message[i]);
ptr_client->outqueue->raw_message[i] = NULL;
ptr_client->outqueue->raw_size[i] = 0;
}
}
if (num_sent > 0)
{
ptr_client->bytes_sent += num_sent;
@@ -644,6 +986,8 @@ relay_client_new (int sock, const char *address, struct t_relay_server *server)
#ifdef HAVE_GNUTLS
new_client->hook_timer_handshake = NULL;
#endif
new_client->websocket = 0;
new_client->http_headers = NULL;
new_client->address = strdup ((address) ? address : "?");
new_client->status = RELAY_STATUS_CONNECTED;
new_client->protocol = server->protocol;
@@ -656,6 +1000,22 @@ relay_client_new (int sock, const char *address, struct t_relay_server *server)
new_client->last_activity = new_client->start_time;
new_client->bytes_recv = 0;
new_client->bytes_sent = 0;
switch (new_client->protocol)
{
case RELAY_PROTOCOL_WEECHAT:
new_client->recv_data_type = RELAY_CLIENT_DATA_TEXT;
new_client->send_data_type = RELAY_CLIENT_DATA_BINARY;
break;
case RELAY_PROTOCOL_IRC:
new_client->recv_data_type = RELAY_CLIENT_DATA_TEXT;
new_client->send_data_type = RELAY_CLIENT_DATA_TEXT;
break;
default:
new_client->recv_data_type = RELAY_CLIENT_DATA_TEXT;
new_client->send_data_type = RELAY_CLIENT_DATA_TEXT;
break;
}
new_client->partial_message = NULL;
relay_client_set_desc (new_client);
@@ -792,6 +1152,8 @@ relay_client_new_with_infolist (struct t_infolist *infolist)
new_client->gnutls_sess = NULL;
new_client->hook_timer_handshake = NULL;
#endif
new_client->websocket = weechat_infolist_integer (infolist, "websocket");
new_client->http_headers = NULL;
new_client->address = strdup (weechat_infolist_string (infolist, "address"));
new_client->status = weechat_infolist_integer (infolist, "status");
new_client->protocol = weechat_infolist_integer (infolist, "protocol");
@@ -816,6 +1178,10 @@ relay_client_new_with_infolist (struct t_infolist *infolist)
"%lu", &(new_client->bytes_recv));
sscanf (weechat_infolist_string (infolist, "bytes_sent"),
"%lu", &(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");
str = weechat_infolist_string (infolist, "partial_message");
new_client->partial_message = (str) ? strdup (str) : NULL;
str = weechat_infolist_string (infolist, "desc");
if (str)
@@ -972,8 +1338,12 @@ relay_client_free (struct t_relay_client *client)
if (client->hook_timer_handshake)
weechat_unhook (client->hook_timer_handshake);
#endif
if (client->http_headers)
weechat_hashtable_free (client->http_headers);
if (client->hook_fd)
weechat_unhook (client->hook_fd);
if (client->partial_message)
free (client->partial_message);
if (client->protocol_data)
{
switch (client->protocol)
@@ -1078,6 +1448,8 @@ relay_client_add_to_infolist (struct t_infolist *infolist,
if (!weechat_infolist_new_var_pointer (ptr_item, "hook_timer_handshake", client->hook_timer_handshake))
return 0;
#endif
if (!weechat_infolist_new_var_integer (ptr_item, "websocket", client->websocket))
return 0;
if (!weechat_infolist_new_var_string (ptr_item, "address", client->address))
return 0;
if (!weechat_infolist_new_var_integer (ptr_item, "status", client->status))
@@ -1108,6 +1480,12 @@ relay_client_add_to_infolist (struct t_infolist *infolist,
snprintf (value, sizeof (value), "%lu", client->bytes_sent);
if (!weechat_infolist_new_var_string (ptr_item, "bytes_sent", value))
return 0;
if (!weechat_infolist_new_var_integer (ptr_item, "recv_data_type", client->recv_data_type))
return 0;
if (!weechat_infolist_new_var_integer (ptr_item, "send_data_type", client->send_data_type))
return 0;
if (!weechat_infolist_new_var_string (ptr_item, "partial_message", client->partial_message))
return 0;
switch (client->protocol)
{
@@ -1146,6 +1524,10 @@ relay_client_print_log ()
weechat_log_printf (" gnutls_sess . . . . . : 0x%lx", ptr_client->gnutls_sess);
weechat_log_printf (" hook_timer_handshake. : 0x%lx", ptr_client->hook_timer_handshake);
#endif
weechat_log_printf (" websocket . . . . . . : %d", ptr_client->websocket);
weechat_log_printf (" http_headers. . . . . : 0x%lx (hashtable: '%s')",
ptr_client->http_headers,
weechat_hashtable_get_string (ptr_client->http_headers, "keys_values"));
weechat_log_printf (" address . . . . . . . : '%s'", ptr_client->address);
weechat_log_printf (" status. . . . . . . . : %d (%s)",
ptr_client->status,
@@ -1162,6 +1544,13 @@ relay_client_print_log ()
weechat_log_printf (" last_activity . . . . : %ld", ptr_client->last_activity);
weechat_log_printf (" bytes_recv. . . . . . : %lu", ptr_client->bytes_recv);
weechat_log_printf (" bytes_sent. . . . . . : %lu", ptr_client->bytes_sent);
weechat_log_printf (" recv_data_type. . . . : %d (%s)",
ptr_client->recv_data_type,
relay_client_data_type_string[ptr_client->recv_data_type]);
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_message . . . : '%s'", ptr_client->partial_message);
weechat_log_printf (" protocol_data . . . . : 0x%lx", ptr_client->protocol_data);
switch (ptr_client->protocol)
{
+19 -1
View File
@@ -39,6 +39,16 @@ enum t_relay_status
RELAY_NUM_STATUS,
};
/* type of data exchanged with client */
enum t_relay_client_data_type
{
RELAY_CLIENT_DATA_TEXT = 0, /* text messages */
RELAY_CLIENT_DATA_BINARY, /* binary messages */
/* number of data types */
RELAY_NUM_CLIENT_DATA_TYPES,
};
/* macros for status */
#define RELAY_CLIENT_HAS_ENDED(client) \
@@ -51,6 +61,9 @@ struct t_relay_client_outqueue
{
char *data; /* data to send */
int data_size; /* number of bytes */
int raw_flags[2]; /* flags for raw messages */
char *raw_message[2]; /* msgs for raw buffer (can be NULL)*/
int raw_size[2]; /* size (in bytes) of raw messages */
struct t_relay_client_outqueue *next_outqueue; /* next msg in queue */
struct t_relay_client_outqueue *prev_outqueue; /* prev msg in queue */
};
@@ -67,6 +80,8 @@ struct t_relay_client
gnutls_session_t gnutls_sess; /* gnutls session (only if SSL used) */
struct t_hook *hook_timer_handshake; /* timer for doing gnutls handshake*/
#endif
int websocket; /* 0=not a ws, 1=init ws, 2=ws ready */
struct t_hashtable *http_headers; /* HTTP headers for websocket */
char *address; /* string with IP address */
enum t_relay_status status; /* status (connecting, active,..) */
enum t_relay_protocol protocol; /* protocol (irc,..) */
@@ -80,6 +95,9 @@ struct t_relay_client
time_t last_activity; /* time of last byte received/sent */
unsigned long bytes_recv; /* bytes received from client */
unsigned 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_message; /* partial text message received */
void *protocol_data; /* data depending on protocol used */
struct t_relay_client_outqueue *outqueue; /* queue for outgoing msgs */
struct t_relay_client_outqueue *last_outqueue; /* last outgoing msg */
@@ -97,7 +115,7 @@ extern struct t_relay_client *relay_client_search_by_number (int number);
extern struct t_relay_client *relay_client_search_by_id (int id);
extern int relay_client_recv_cb (void *arg_client, int fd);
extern int relay_client_send (struct t_relay_client *client, const char *data,
int data_size);
int data_size, const char *message_raw_buffer);
extern int relay_client_timer_cb (void *data, int remaining_calls);
extern struct t_relay_client *relay_client_new (int sock, const char *address,
struct t_relay_server *server);
+48
View File
@@ -57,6 +57,7 @@ struct t_config_option *relay_config_network_ipv6;
struct t_config_option *relay_config_network_max_clients;
struct t_config_option *relay_config_network_password;
struct t_config_option *relay_config_network_ssl_cert_key;
struct t_config_option *relay_config_network_websocket_allowed_origins;
/* relay config, irc section */
@@ -69,6 +70,7 @@ struct t_config_option *relay_config_irc_backlog_time_format;
/* other */
regex_t *relay_config_regex_allowed_ips = NULL;
regex_t *relay_config_regex_websocket_allowed_origins = NULL;
struct t_hashtable *relay_config_hashtable_irc_backlog_tags = NULL;
@@ -187,6 +189,44 @@ relay_config_change_network_ssl_cert_key (void *data,
relay_network_set_ssl_cert_key (1);
}
/*
* Callback for changes on option "relay.network.websocker_allowed_origins".
*/
void
relay_config_change_network_websocket_allowed_origins (void *data,
struct t_config_option *option)
{
const char *allowed_origins;
/* make C compiler happy */
(void) data;
(void) option;
if (relay_config_regex_websocket_allowed_origins)
{
regfree (relay_config_regex_websocket_allowed_origins);
free (relay_config_regex_websocket_allowed_origins);
relay_config_regex_websocket_allowed_origins = NULL;
}
allowed_origins = weechat_config_string (relay_config_network_websocket_allowed_origins);
if (allowed_origins && allowed_origins[0])
{
relay_config_regex_websocket_allowed_origins = malloc (sizeof (*relay_config_regex_websocket_allowed_origins));
if (relay_config_regex_websocket_allowed_origins)
{
if (weechat_string_regcomp (relay_config_regex_websocket_allowed_origins,
allowed_origins,
REG_EXTENDED | REG_ICASE) != 0)
{
free (relay_config_regex_websocket_allowed_origins);
relay_config_regex_websocket_allowed_origins = NULL;
}
}
}
}
/*
* Callback for changes on option "relay.irc.backlog_tags".
*/
@@ -606,6 +646,14 @@ relay_config_init ()
"with SSL)"),
NULL, 0, 0, "%h/ssl/relay.pem", NULL, 0, NULL, NULL,
&relay_config_change_network_ssl_cert_key, NULL, NULL, NULL);
relay_config_network_websocket_allowed_origins = weechat_config_new_option (
relay_config_file, ptr_section,
"websocket_allowed_origins", "string",
N_("regular expression with origins allowed in websockets (case "
"insensitive, use \"(?-i)\" at beginning to make it case sensitive), "
"example: \"^http://(www\\.)?example\\.(com|org)\""),
NULL, 0, 0, "", NULL, 0, NULL, NULL,
&relay_config_change_network_websocket_allowed_origins, NULL, NULL, NULL);
/* section irc */
ptr_section = weechat_config_new_section (relay_config_file, "irc",
+1
View File
@@ -51,6 +51,7 @@ extern struct t_config_option *relay_config_irc_backlog_tags;
extern struct t_config_option *relay_config_irc_backlog_time_format;
extern regex_t *relay_config_regex_allowed_ips;
extern regex_t *relay_config_regex_websocket_allowed_origins;
extern struct t_hashtable *relay_config_hashtable_irc_backlog_tags;
extern int relay_config_create_option_port (void *data,
+97 -53
View File
@@ -215,46 +215,99 @@ relay_raw_message_add_to_list (time_t date, const char *prefix,
/*
* Adds a new raw message to list.
*
* Returns pointer to new raw message, NULL if error.
*/
struct t_relay_raw_message *
void
relay_raw_message_add (struct t_relay_client *client, int flags,
const char *message)
const char *data, int data_size)
{
char *buf, *buf2, prefix[256], prefix_arrow[16];
char str_hexa[(16 * 3) + 1], str_ascii[(16 * 2) + 1], str_line[256];
const unsigned char *ptr_buf;
const char *hexa = "0123456789ABCDEF";
int pos_buf, pos_buf2, char_size, i;
int pos_buf, pos_buf2, char_size, i, hexa_pos, ascii_pos;
struct t_relay_raw_message *new_raw_message;
buf = weechat_iconv_to_internal (NULL, message);
buf2 = malloc ((strlen (buf) * 3) + 1);
if (buf2)
buf = NULL;
buf2 = NULL;
if (flags & RELAY_RAW_FLAG_BINARY)
{
ptr_buf = (buf) ? (unsigned char *)buf : (unsigned char *)message;
pos_buf = 0;
pos_buf2 = 0;
while (ptr_buf[pos_buf])
/* binary message */
buf = malloc ((data_size * 6) + 128 + 1);
if (buf)
{
if (ptr_buf[pos_buf] < 32)
buf[0] = '\0';
hexa_pos = 0;
ascii_pos = 0;
for (i = 0; i < data_size; i++)
{
buf2[pos_buf2++] = '\\';
buf2[pos_buf2++] = hexa[ptr_buf[pos_buf] / 16];
buf2[pos_buf2++] = hexa[ptr_buf[pos_buf] % 16];
pos_buf++;
}
else
{
char_size = weechat_utf8_char_size ((const char *)(ptr_buf + pos_buf));
for (i = 0; i < char_size; i++)
snprintf (str_hexa + hexa_pos, 4,
"%02X ", (unsigned char)(data[i]));
hexa_pos += 3;
snprintf (str_ascii + ascii_pos, 3, "%c ",
((((unsigned char)data[i]) < 32)
|| (((unsigned char)data[i]) > 127)) ?
'.' : (unsigned char)(data[i]));
ascii_pos += 2;
if (ascii_pos == 32)
{
buf2[pos_buf2++] = ptr_buf[pos_buf++];
if (buf[0])
strcat (buf, "\n");
snprintf (str_line, sizeof (str_line),
"%-48s %s", str_hexa, str_ascii);
strcat (buf, str_line);
hexa_pos = 0;
ascii_pos = 0;
}
}
if (ascii_pos > 0)
{
if (buf[0])
strcat (buf, "\n");
snprintf (str_line, sizeof (str_line),
"%-48s %s", str_hexa, str_ascii);
strcat (buf, str_line);
}
}
}
else
{
/* text message */
buf = weechat_iconv_to_internal (NULL, data);
buf2 = weechat_string_replace (buf, "\r", "");
if (buf2)
{
free (buf);
buf = buf2;
buf2 = NULL;
}
buf2 = malloc ((strlen (buf) * 3) + 1);
if (buf2)
{
ptr_buf = (buf) ? (unsigned char *)buf : (unsigned char *)data;
pos_buf = 0;
pos_buf2 = 0;
while (ptr_buf[pos_buf])
{
if ((ptr_buf[pos_buf] < 32) && (ptr_buf[pos_buf] != '\n'))
{
buf2[pos_buf2++] = '\\';
buf2[pos_buf2++] = hexa[ptr_buf[pos_buf] / 16];
buf2[pos_buf2++] = hexa[ptr_buf[pos_buf] % 16];
pos_buf++;
}
else
{
char_size = weechat_utf8_char_size ((const char *)(ptr_buf + pos_buf));
for (i = 0; i < char_size; i++)
{
buf2[pos_buf2++] = ptr_buf[pos_buf++];
}
}
}
buf2[pos_buf2] = '\0';
}
buf2[pos_buf2] = '\0';
}
/* build prefix with arrow */
@@ -302,35 +355,8 @@ relay_raw_message_add (struct t_relay_client *client, int flags,
new_raw_message = relay_raw_message_add_to_list (time (NULL),
prefix,
(buf2) ? buf2 : ((buf) ? buf : message));
(buf2) ? buf2 : ((buf) ? buf : data));
if (buf)
free (buf);
if (buf2)
free (buf2);
return new_raw_message;
}
/*
* Prints a message on relay raw buffer.
*/
void
relay_raw_print (struct t_relay_client *client, int flags,
const char *format, ...)
{
struct t_relay_raw_message *new_raw_message;
weechat_va_format (format);
if (!vbuffer)
return;
/* auto-open Relay raw buffer if debug for irc plugin is >= 1 */
if (!relay_raw_buffer && (weechat_relay_plugin->debug >= 1))
relay_raw_open (0);
new_raw_message = relay_raw_message_add (client, flags, vbuffer);
if (new_raw_message)
{
if (relay_raw_buffer)
@@ -339,7 +365,25 @@ relay_raw_print (struct t_relay_client *client, int flags,
relay_raw_message_free (new_raw_message);
}
free (vbuffer);
if (buf)
free (buf);
if (buf2)
free (buf2);
}
/*
* Prints a message on relay raw buffer.
*/
void
relay_raw_print (struct t_relay_client *client, int flags,
const char *data, int data_size)
{
/* auto-open Relay raw buffer if debug for irc plugin is >= 1 */
if (!relay_raw_buffer && (weechat_relay_plugin->debug >= 1))
relay_raw_open (0);
relay_raw_message_add (client, flags, data, data_size);
}
/*
+2 -1
View File
@@ -26,6 +26,7 @@
#define RELAY_RAW_FLAG_RECV 1
#define RELAY_RAW_FLAG_SEND 2
#define RELAY_RAW_FLAG_BINARY 4
struct t_relay_raw_message
{
@@ -47,7 +48,7 @@ extern struct t_relay_raw_message *relay_raw_message_add_to_list (time_t date,
const char *prefix,
const char *message);
extern void relay_raw_print (struct t_relay_client *client, int flags,
const char *format, ...);
const char *data, int data_size);
extern void relay_raw_message_free_all ();
extern int relay_raw_add_to_infolist (struct t_infolist *infolist,
struct t_relay_raw_message *raw_message);
+1 -1
View File
@@ -286,7 +286,7 @@ relay_server_sock_cb (void *data, int fd)
if (relay_config_regex_allowed_ips
&& (regexec (relay_config_regex_allowed_ips, ptr_ip_address, 0, NULL, 0) != 0))
{
if (weechat_relay_plugin->debug >= 2)
if (weechat_relay_plugin->debug >= 1)
{
weechat_printf (NULL,
_("%s%s: IP address \"%s\" not allowed for relay"),
+379
View File
@@ -0,0 +1,379 @@
/*
* relay-websocket.c - websocket server functions for relay plugin (RFC 6455)
*
* Copyright (C) 2013 Sebastien Helleu <flashcode@flashtux.org>
*
* This file is part of WeeChat, the extensible chat client.
*
* WeeChat is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* WeeChat is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <gcrypt.h>
#include "../weechat-plugin.h"
#include "relay.h"
#include "relay-client.h"
#include "relay-config.h"
/*
* globally unique identifier that is concatenated to HTTP header
* "Sec-WebSocket-Key"
*/
#define WEBSOCKET_GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
/*
* Checks if a message is a HTTP GET with resource "/weechat".
*
* Returns:
* 1: message is a HTTP GET with resource "/weechat"
* 0: message is NOT a HTTP GET with resource "/weechat"
*/
int
relay_websocket_is_http_get_weechat (const char *message)
{
/* the message must start with "GET /weechat" */
if (strncmp (message, "GET /weechat", 12) != 0)
return 0;
/* after "GET /weechat", only a new line or " HTTP" is allowed */
if ((message[12] != '\r') && (message[12] != '\n')
&& (strncmp (message + 12, " HTTP", 5) != 0))
{
return 0;
}
/* valid HTTP GET for resource "/weechat" */
return 1;
}
/*
* Saves a HTTP header in hashtable "http_header" of client.
*/
void
relay_websocket_save_header (struct t_relay_client *client,
const char *message)
{
char *pos, *name;
const char *ptr_value;
/* ignore the "GET" request */
if (strncmp (message, "GET ", 4) == 0)
return;
pos = strchr (message, ':');
/* not a valid header */
if (!pos || (pos == message))
return;
/* get header name */
name = weechat_strndup (message, pos - message);
if (!name)
return;
/* get pointer on header value */
ptr_value = pos + 1;
while (ptr_value[0] == ' ')
{
ptr_value++;
}
/* add header in the hashtable */
weechat_hashtable_set (client->http_headers, name, ptr_value);
free (name);
}
/*
* Checks if a client handshake is valid.
*
* A websocket query looks like:
* GET /weechat HTTP/1.1
* Upgrade: websocket
* Connection: Upgrade
* Host: myhost:5000
* Origin: http://example.org.org
* Pragma: no-cache
* Cache-Control: no-cache
* Sec-WebSocket-Key: fo1J9uHSsrfDP3BkwUylzQ==
* Sec-WebSocket-Version: 13
* Sec-WebSocket-Extensions: x-webkit-deflate-frame
* Cookie: csrftoken=acb65377798f32dc377ebb50316a12b5
*
* Expected HTTP headers with values are:
*
* header | value
* --------------------+----------------
* "Upgrade" | "websocket"
* "Sec-WebSocket-Key" | non-empty value
*
* If option relay.network.websocket_allowed_origins is set, the HTTP header
* "Origin" is checked against this regex. If header "Origin" is not set or does
* not match regex, the handshake is considered as invalid.
*
* Returns:
* 0: handshake is valid
* -1: handshake is invalid (headers missing or with bad value)
* -2: origin is not allowed (option relay.network.websocket_allowed_origins)
*/
int
relay_websocket_client_handshake_valid (struct t_relay_client *client)
{
const char *value;
/* check if we have header "Upgrade" with value "websocket" */
value = weechat_hashtable_get (client->http_headers, "Upgrade");
if (!value)
return -1;
if (strcmp (value, "websocket") != 0)
return -1;
/* check if we have header "Sec-WebSocket-Key" with non-empty value */
value = weechat_hashtable_get (client->http_headers, "Sec-WebSocket-Key");
if (!value || !value[0])
return -1;
if (relay_config_regex_websocket_allowed_origins)
{
value = weechat_hashtable_get (client->http_headers, "Origin");
if (!value || !value[0])
return -2;
if (regexec (relay_config_regex_websocket_allowed_origins, value, 0,
NULL, 0) != 0)
{
return -2;
}
}
/* client handshake is valid */
return 0;
}
/*
* Builds the handshake that will be returned to client, to initialize and use
* the websocket.
*
* Returns a string with content of handshake to send to client, it looks like:
* HTTP/1.1 101 Switching Protocols
* Upgrade: websocket
* Connection: Upgrade
* Sec-WebSocket-Accept: 73OzoF/IyV9znm7Tsb4EtlEEmn4=
*
* Note: result must be freed after use.
*/
char *
relay_websocket_build_handshake (struct t_relay_client *client)
{
const char *sec_websocket_key;
char *key, sec_websocket_accept[128], handshake[1024];
unsigned char *result;
gcry_md_hd_t hd;
int length;
sec_websocket_key = weechat_hashtable_get (client->http_headers,
"Sec-WebSocket-Key");
if (!sec_websocket_key || !sec_websocket_key[0])
return NULL;
length = strlen (sec_websocket_key) + strlen (WEBSOCKET_GUID) + 1;
key = malloc (length);
if (!key)
return NULL;
/*
* concatenate header "Sec-WebSocket-Key" with the GUID
* (globally unique identifier)
*/
snprintf (key, length, "%s%s", sec_websocket_key, WEBSOCKET_GUID);
/* compute 160-bit SHA1 on the key and encode it with base64 */
gcry_md_open (&hd, GCRY_MD_SHA1, 0);
length = gcry_md_get_algo_dlen (GCRY_MD_SHA1);
gcry_md_write (hd, key, strlen (key));
result = gcry_md_read (hd, GCRY_MD_SHA1);
weechat_string_encode_base64 ((char *)result, length, sec_websocket_accept);
gcry_md_close (hd);
/* build the handshake (it will be sent as-is to client) */
snprintf (handshake, sizeof (handshake),
"HTTP/1.1 101 Switching Protocols\r\n"
"Upgrade: websocket\r\n"
"Connection: Upgrade\r\n"
//"Sec-WebSocket-Protocol: chat\r\n"
"Sec-WebSocket-Accept: %s\r\n"
"\r\n",
sec_websocket_accept);
return strdup (handshake);
}
/*
* Sends a HTTP message to client.
*
* Argument "http" is a HTTP code + message, for example:
* "403 Forbidden".
*/
void
relay_websocket_send_http (struct t_relay_client *client,
const char *http)
{
char *message;
int length;
length = 32 + strlen (http) + 1;
message = malloc (length);
if (message)
{
snprintf (message, length, "HTTP/1.1 %s\r\n\r\n", http);
relay_client_send (client, message, strlen (message), NULL);
free (message);
}
}
/*
* Decodes a websocket frame.
*
* Returns:
* 1: frame decoded successfully
* 0: error decoding frame (connection must be closed if it happens)
*/
int
relay_websocket_decode_frame (const unsigned char *buffer,
unsigned long long length,
unsigned char *decoded)
{
unsigned long long i, index, length_frame_size, length_frame;
if (length < 2)
return 0;
/*
* check if frame is masked: client MUST send a masked frame; if frame is
* not masked, we MUST reject it and close the connection (see RFC 6455)
*/
if (!(buffer[1] & 128))
return 0;
/* decode frame */
index = 2;
length_frame_size = 1;
length_frame = buffer[1] & 127;
if ((length_frame == 126) || (length_frame == 127))
{
length_frame_size = (length_frame == 126) ? 2 : 8;
if (length < 1 + length_frame_size)
return 0;
length_frame = 0;
for (i = 0; i < length_frame_size; i++)
{
length_frame += (unsigned long long)buffer[index + i] << ((length_frame_size - i - 1) * 8);
}
index += length_frame_size;
}
if (length < 1 + length_frame_size + 4 + length_frame)
return 0;
/* read masks (4 bytes) */
int masks[4];
for (i = 0; i < 4; i++)
{
masks[i] = (int)((unsigned char)buffer[index + i]);
}
index += 4;
/* decode data using masks */
for (i = 0; i < length_frame; i++)
{
decoded[i] = (int)((unsigned char)buffer[index + i]) ^ masks[i % 4];
}
decoded[length_frame] = '\0';
return 1;
}
/*
* Encodes data in a websocket frame.
*
* Returns websocket frame, NULL if error.
* Argument "length_frame" is set with the length of frame built.
*
* Note: result must be freed after use.
*/
char *
relay_websocket_encode_frame (struct t_relay_client *client,
const char *buffer,
unsigned long long length,
unsigned long long *length_frame)
{
unsigned char *frame;
unsigned long long index;
*length_frame = 0;
frame = malloc (length + 10);
if (!frame)
return NULL;
frame[0] = (client->send_data_type == RELAY_CLIENT_DATA_TEXT) ? 0x81 : 0x82;
if (length <= 125)
{
/* length on one byte */
frame[1] = length;
index = 2;
}
else if ((length >= 126) && (length <= 65535))
{
/* length on 2 bytes */
frame[1] = 126;
frame[2] = (length >> 8) & 0xFF;
frame[3] = length & 0xFF;
index = 4;
}
else
{
/* length on 8 bytes */
frame[1] = 127;
frame[2] = (length >> 56) & 0xFF;
frame[3] = (length >> 48) & 0xFF;
frame[4] = (length >> 40) & 0xFF;
frame[5] = (length >> 32) & 0xFF;
frame[6] = (length >> 24) & 0xFF;
frame[7] = (length >> 16) & 0xFF;
frame[8] = (length >> 8) & 0xFF;
frame[9] = length & 0xFF;
index = 10;
}
/* copy buffer after length */
memcpy (frame + index, buffer, length);
*length_frame = index + length;
return (char *)frame;
}
+38
View File
@@ -0,0 +1,38 @@
/*
* Copyright (C) 2013 Sebastien Helleu <flashcode@flashtux.org>
*
* This file is part of WeeChat, the extensible chat client.
*
* WeeChat is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* WeeChat is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with WeeChat. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __WEECHAT_RELAY_WEBSOCKET_H
#define __WEECHAT_RELAY_WEBSOCKET_H 1
extern int relay_websocket_is_http_get_weechat (const char *message);
extern void relay_websocket_save_header (struct t_relay_client *client,
const char *message);
extern int relay_websocket_client_handshake_valid (struct t_relay_client *client);
extern char *relay_websocket_build_handshake (struct t_relay_client *client);
extern void relay_websocket_send_http (struct t_relay_client *client,
const char *http);
extern int relay_websocket_decode_frame (const unsigned char *buffer,
int length,
unsigned char *decoded);
extern char *relay_websocket_encode_frame (struct t_relay_client *client,
const char *buffer,
unsigned long long length,
unsigned long long *length_frame);
#endif /* __WEECHAT_RELAY_WEBSOCKET_H */
+13 -14
View File
@@ -958,7 +958,7 @@ relay_weechat_msg_send (struct t_relay_client *client,
struct t_relay_weechat_msg *msg)
{
uint32_t size32;
char compression;
char compression, raw_message[1024];
int rc;
Bytef *dest;
uLongf dest_size;
@@ -986,16 +986,17 @@ relay_weechat_msg_send (struct t_relay_client *client,
dest[4] = 1;
/* display message in raw buffer */
relay_raw_print (client, RELAY_RAW_FLAG_SEND,
"obj: %d/%d bytes (%d%%, %ldms), id: %s",
(int)dest_size + 5,
msg->data_size,
100 - ((((int)dest_size + 5) * 100) / msg->data_size),
time_diff,
msg->id);
snprintf (raw_message, sizeof (raw_message),
"obj: %d/%d bytes (%d%%, %ldms), id: %s",
(int)dest_size + 5,
msg->data_size,
100 - ((((int)dest_size + 5) * 100) / msg->data_size),
time_diff,
msg->id);
/* send compressed data */
relay_client_send (client, (const char *)dest, dest_size + 5);
relay_client_send (client, (const char *)dest, dest_size + 5,
raw_message);
free (dest);
return;
@@ -1012,12 +1013,10 @@ relay_weechat_msg_send (struct t_relay_client *client,
compression = 0;
relay_weechat_msg_set_bytes (msg, 4, &compression, 1);
/* display message in raw buffer */
relay_raw_print (client, RELAY_RAW_FLAG_SEND,
"obj: %d bytes", msg->data_size);
/* send uncompressed data */
relay_client_send (client, msg->data, msg->data_size);
snprintf (raw_message, sizeof (raw_message),
"obj: %d bytes", msg->data_size);
relay_client_send (client, msg->data, msg->data_size, raw_message);
}
/*
@@ -1053,7 +1053,7 @@ RELAY_WEECHAT_PROTOCOL_CALLBACK(quit)
*/
void
relay_weechat_protocol_recv (struct t_relay_client *client, char *data)
relay_weechat_protocol_recv (struct t_relay_client *client, const char *data)
{
char *pos, *id, *command, **argv, **argv_eol;
int i, argc, return_code;
@@ -1074,11 +1074,6 @@ relay_weechat_protocol_recv (struct t_relay_client *client, char *data)
if (!data || !data[0] || RELAY_CLIENT_HAS_ENDED(client))
return;
/* remove \r at the end of message */
pos = strchr (data, '\r');
if (pos)
pos[0] = '\0';
/* display debug message */
if (weechat_relay_plugin->debug >= 2)
{
@@ -1090,9 +1085,6 @@ relay_weechat_protocol_recv (struct t_relay_client *client, char *data)
data);
}
/* display message in raw buffer */
relay_raw_print (client, RELAY_RAW_FLAG_RECV, "cmd: %s", data);
/* extract id */
id = NULL;
if (data[0] == '(')
@@ -96,6 +96,6 @@ extern int relay_weechat_protocol_signal_upgrade_cb (void *data,
extern int relay_weechat_protocol_timer_nicklist_cb (void *data,
int remaining_calls);
extern void relay_weechat_protocol_recv (struct t_relay_client *client,
char *data);
const char *data);
#endif /* __WEECHAT_RELAY_WEECHAT_PROTOCOL_H */
+1 -44
View File
@@ -42,8 +42,6 @@
char *relay_weechat_compression_string[] = /* strings for compressions */
{ "off", "gzip" };
char *relay_weechat_partial_message = NULL;
/*
* Searches for a compression.
@@ -132,48 +130,7 @@ relay_weechat_hook_timer_nicklist (struct t_relay_client *client)
void
relay_weechat_recv (struct t_relay_client *client, const char *data)
{
char *new_partial, *pos, *tmp, **commands;
int num_commands, i;
if (relay_weechat_partial_message)
{
new_partial = realloc (relay_weechat_partial_message,
strlen (relay_weechat_partial_message) +
strlen (data) + 1);
if (!new_partial)
return;
relay_weechat_partial_message = new_partial;
strcat (relay_weechat_partial_message, data);
}
else
relay_weechat_partial_message = strdup (data);
pos = strrchr (relay_weechat_partial_message, '\n');
if (pos)
{
pos[0] = '\0';
commands = weechat_string_split (relay_weechat_partial_message, "\n",
0, 0, &num_commands);
if (commands)
{
for (i = 0; i < num_commands; i++)
{
relay_weechat_protocol_recv (client, commands[i]);
}
weechat_string_free_split (commands);
}
if (pos[1])
{
tmp = strdup (pos + 1);
free (relay_weechat_partial_message);
relay_weechat_partial_message = tmp;
}
else
{
free (relay_weechat_partial_message);
relay_weechat_partial_message = NULL;
}
}
relay_weechat_protocol_recv (client, data);
}
/*