summaryrefslogtreecommitdiff
path: root/src/connection.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/connection.c')
-rw-r--r--src/connection.c114
1 files changed, 113 insertions, 1 deletions
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);
}