From 81e0d7d65a55be7df908567da622e1e2f249ceec Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Sun, 25 Sep 2011 11:18:03 +0200 Subject: Add support for transporting audio data using udp With crypt.c importet from umurmur, changed encrypt key to use raw_key instead of decrypt_iv. --- src/connection.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 113 insertions(+), 1 deletion(-) (limited to 'src/connection.c') diff --git a/src/connection.c b/src/connection.c index 7fefdb3..e7f74bd 100644 --- a/src/connection.c +++ b/src/connection.c @@ -3,6 +3,7 @@ #include "connection.h" #include "cmumble.h" +#include "varint.h" static gboolean read_cb(GObject *pollable_stream, gpointer data) @@ -18,6 +19,118 @@ read_cb(GObject *pollable_stream, gpointer data) return TRUE; } +static gboolean +read_udp_socket(GSocket *socket, GIOCondition condition, gpointer user_data) +{ + struct cmumlbe *cm = user_data; + GError *error = NULL; + guchar data[1024]; + guchar plain[1020]; + gssize size; + + size = g_socket_receive(socket, (gchar *) data, sizeof(data), + NULL, &error); + if (size <= 4) + return TRUE; + + if (!CryptState_decrypt(&cm->crypt, data, plain, size)) + return TRUE; + + cm->con.udp.connected = TRUE; + + cmumble_read_udp_data(cm, plain, size - 4); + + return TRUE; +} + +static void +send_udp_tcptunnel(struct cmumlbe *cm, guint8 *data, gsize len) +{ + MumbleProto__UDPTunnel tunnel; + + mumble_proto__udptunnel__init(&tunnel); + tunnel.packet.data = data; + tunnel.packet.len = len; + cmumble_send_msg(cm, &tunnel.base); +} + +static void +send_udp(struct cmumlbe *cm, guint8 *data, gsize len) +{ + guint8 encrypted[1024]; + GError *error = NULL; + + g_assert(len <= (sizeof(encrypted) - 4)); + + CryptState_encrypt(&cm->crypt, data, encrypted, len); + g_socket_send(cm->con.udp.sock, (gchar *) encrypted, len + 4, + NULL, &error); +} + +void +cmumble_connection_send_udp_data(struct cmumlbe *cm, guint8 *data, gsize len) +{ + if (cm->con.udp.connected) + send_udp(cm, data, len); + else + send_udp_tcptunnel(cm, data, len); +} + +static void +do_udp_ping(struct cmumlbe *cm) +{ + uint8_t data[16]; + uint32_t written = 0, pos = 0; + GTimeVal tv; + + g_get_current_time(&tv); + + data[pos++] = (udp_ping << 5); + encode_varint(&data[pos], &written, tv.tv_sec, sizeof(data)-pos); + pos += written; + + send_udp(cm, data, pos); + + g_print("udp ping sent: timestamp: %ld\n", tv.tv_sec); +} + +void +cmumble_connection_udp_init(struct cmumlbe *cm) +{ + GError *error = NULL; + GSocketAddress *saddr; + + cm->con.udp.connected = FALSE; + cm->con.udp.sock = g_socket_new(G_SOCKET_FAMILY_IPV4, + G_SOCKET_TYPE_DATAGRAM, + G_SOCKET_PROTOCOL_UDP, + &error); + g_assert(error == NULL); + + saddr = g_socket_connection_get_remote_address(cm->con.conn, &error); + if (saddr == NULL) { + g_printerr("Failed to get remote address for udp setup: %s\n", + error->message); + return; + } + + if (!g_socket_connect(cm->con.udp.sock, saddr, NULL, &error)) { + g_object_unref(saddr); + g_object_unref(cm->con.udp.sock); + cm->con.udp.sock = NULL; + return; + } + g_object_unref(saddr); + + cm->con.udp.source = g_socket_create_source(cm->con.udp.sock, + G_IO_IN, NULL); + g_source_set_callback(cm->con.udp.source, + (GSourceFunc) read_udp_socket, cm, NULL); + g_source_attach(cm->con.udp.source, NULL); + + do_udp_ping(cm); +} + static void connection_ready(GObject *source_object, GAsyncResult *res, gpointer user_data) { @@ -48,7 +161,6 @@ connection_ready(GObject *source_object, GAsyncResult *res, gpointer user_data) con->source = g_pollable_input_stream_create_source(con->input, NULL); g_source_set_callback(con->source, (GSourceFunc) read_cb, cm, NULL); g_source_attach(con->source, NULL); - g_source_unref(con->source); cmumble_protocol_init(cm); } -- cgit