changeset 26137:c56e8826fed0

Added support to generate relayed candidates (TURN). Added prefs setting for relay server in Pidgin
author Marcus Lundblad <ml@update.uu.se>
date Thu, 22 Jan 2009 23:04:52 +0000
parents d68924f1265f
children 4f0aec6d4ad7
files libpurple/media.c libpurple/network.c libpurple/network.h pidgin/gtkprefs.c pidgin/gtkprefs.h
diffstat 5 files changed, 201 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/media.c	Mon Jan 19 10:47:12 2009 +0000
+++ b/libpurple/media.c	Thu Jan 22 23:04:52 2009 +0000
@@ -1622,23 +1622,70 @@
 		GError *err = NULL;
 		FsStream *fsstream = NULL;
 		const gchar *stun_ip = purple_network_get_stun_ip();
-		
+		const gchar *turn_ip = purple_network_get_turn_ip();
 		
-		if (stun_ip) {
-			GParameter *param = g_new0(GParameter, num_params+1);
+		if (stun_ip || turn_ip) {
+			guint new_num_params = 
+				stun_ip && turn_ip ? num_params + 2 : num_params + 1;
+			guint next_param_index = num_params;
+			GParameter *param = g_new0(GParameter, new_num_params);
 			memcpy(param, params, sizeof(GParameter) * num_params);
 
-			purple_debug_info("media", 
-				"setting property stun-ip on new stream: %s\n", stun_ip);
+			if (stun_ip) {
+				purple_debug_info("media", 
+					"setting property stun-ip on new stream: %s\n", stun_ip);
+			
+				param[next_param_index].name = "stun-ip";
+				g_value_init(&param[next_param_index].value, G_TYPE_STRING);
+				g_value_set_string(&param[next_param_index].value, stun_ip);
+				next_param_index++;
+			}
 			
-			param[num_params].name = "stun-ip";
-			g_value_init(&param[num_params].value, G_TYPE_STRING);
-			g_value_set_string(&param[num_params].value, stun_ip);
+			if (turn_ip) {
+				GValueArray *relay_info = g_value_array_new(0);
+				GValue value = {0};
+				gint turn_port = 
+					purple_prefs_get_int("/purple/network/turn_port");
+				const gchar *username =
+					purple_prefs_get_string("/purple/network/turn_username");
+				const gchar *password =
+					purple_prefs_get_string("/purple/network/turn_password");
+				GstStructure *turn_setup = gst_structure_new("relay-info",
+					"ip", G_TYPE_STRING, turn_ip, 
+					"port", G_TYPE_UINT, turn_port,
+					"username", G_TYPE_STRING, username,
+					"password", G_TYPE_STRING, password,
+					NULL);
 
+				if (turn_setup) {
+					g_value_init(&value, GST_TYPE_STRUCTURE);
+					gst_value_set_structure(&value, turn_setup);
+					relay_info = g_value_array_append(relay_info, &value);
+					gst_structure_free(turn_setup);
+					
+					purple_debug_info("media",
+						"setting property relay-info on new stream\n");
+					param[next_param_index].name = "relay-info";
+					g_value_init(&param[next_param_index].value, 
+						G_TYPE_VALUE_ARRAY);
+					g_value_set_boxed(&param[next_param_index].value,
+						relay_info);
+					g_value_array_free(relay_info);
+				} else {
+					purple_debug_error("media", "Error relay info");
+					g_object_unref(participant);
+					g_hash_table_remove(media->priv->participants, who);
+					purple_media_remove_session(media, session);
+					g_free(session);
+					return FALSE;
+				}
+				
+			}
+				
 			fsstream = fs_session_new_stream(session->session,
 					participant, type_direction &
 					FS_DIRECTION_RECV, transmitter,
-					num_params+1, param, &err);
+					new_num_params, param, &err);
 			g_free(param);
 		} else {
 			fsstream = fs_session_new_stream(session->session,
--- a/libpurple/network.c	Mon Jan 19 10:47:12 2009 +0000
+++ b/libpurple/network.c	Thu Jan 22 23:04:52 2009 +0000
@@ -93,8 +93,9 @@
 static NMState nm_get_network_state(void);
 #endif
 
-/* Cached IP address for STUN server */
+/* Cached IP addresses for STUN and TURN servers (set globally in prefs) */
 static gchar *stun_ip = NULL;
+static gchar *turn_ip = NULL;
 
 const unsigned char *
 purple_network_ip_atoi(const char *ip)
@@ -694,6 +695,8 @@
 			   offline */
 			purple_network_set_stun_server(
 				purple_prefs_get_string("/purple/network/stun_server"));
+			purple_network_set_turn_server(
+				purple_prefs_get_string("/purple/network/turn_server"));
 			
 			if (ui_ops != NULL && ui_ops->network_connected != NULL)
 				ui_ops->network_connected();
@@ -757,11 +760,13 @@
 #endif
 
 static void
-purple_network_stun_lookup_cb(GSList *hosts, gpointer data, 
+purple_network_ip_lookup_cb(GSList *hosts, gpointer data, 
 	const char *error_message)
 {
+	const gchar **ip = (const gchar **) data; 
+	
 	if (error_message) {
-		purple_debug_error("network", "lookup of STUN server IP failed: %s\n",
+		purple_debug_error("network", "lookup of IP address failed: %s\n",
 			error_message);
 		g_slist_free(hosts);
 		return;
@@ -780,8 +785,8 @@
 				dst, sizeof(dst));
 		}
 			
-		stun_ip = g_strdup(dst);
-		purple_debug_info("network", "set STUN IP: %s\n", stun_ip);
+		*ip = g_strdup(dst);
+		purple_debug_info("network", "set IP address: %s\n", *ip);
 	}
 	
 	g_slist_free(hosts);
@@ -793,8 +798,8 @@
 	if (stun_server && stun_server[0] != '\0') {
 		if (purple_network_is_available()) {
 			purple_debug_info("network", "running DNS query for STUN server\n");
-			purple_dnsquery_a(stun_server, 3478, purple_network_stun_lookup_cb,
-				NULL);
+			purple_dnsquery_a(stun_server, 3478, purple_network_ip_lookup_cb,
+				&stun_ip);
 		} else {
 			purple_debug_info("network", 
 				"network is unavailable, don't try to update STUN IP");
@@ -805,12 +810,38 @@
 	}
 }
 
+void
+purple_network_set_turn_server(const gchar *turn_server)
+{
+	if (turn_server && turn_server[0] != '\0') {
+		if (purple_network_is_available()) {
+			purple_debug_info("network", "running DNS query for TURN server\n");
+			purple_dnsquery_a(turn_server, 
+				purple_prefs_get_int("/purple/network/turn_port"), 
+				purple_network_ip_lookup_cb, &turn_ip);
+		} else {
+			purple_debug_info("network", 
+				"network is unavailable, don't try to update TURN IP");
+		}
+	} else if (turn_ip) {
+		g_free(turn_ip);
+		turn_ip = NULL;
+	}
+}
+
+
 const gchar *
 purple_network_get_stun_ip(void)
 {
 	return stun_ip;
 }
 
+const gchar *
+purple_network_get_turn_ip(void)
+{
+	return turn_ip;
+}
+
 void *
 purple_network_get_handle(void)
 {
@@ -843,6 +874,10 @@
 
 	purple_prefs_add_none  ("/purple/network");
 	purple_prefs_add_string("/purple/network/stun_server", "");
+	purple_prefs_add_string("/purple/network/turn_server", "");
+	purple_prefs_add_int   ("/purple/network/turn_port", 3478);
+	purple_prefs_add_string("/purple/network/turn_username", "");
+	purple_prefs_add_string("/purple/network/turn_password", "");
 	purple_prefs_add_bool  ("/purple/network/auto_ip", TRUE);
 	purple_prefs_add_string("/purple/network/public_ip", "");
 	purple_prefs_add_bool  ("/purple/network/map_ports", TRUE);
@@ -884,6 +919,8 @@
 	
 	purple_network_set_stun_server(
 		purple_prefs_get_string("/purple/network/stun_server"));
+	purple_network_set_turn_server(
+		purple_prefs_get_string("/purple/network/turn_server"));
 }
 
 void
--- a/libpurple/network.h	Mon Jan 19 10:47:12 2009 +0000
+++ b/libpurple/network.h	Thu Jan 22 23:04:52 2009 +0000
@@ -215,7 +215,7 @@
 void *purple_network_get_handle(void);
 
 /**	
- * Update the STUN server name
+ * Update the STUN server IP given the host name
  * Will result in a DNS query being executed asynchronous
  * 
  * @param stun_server The host name of the STUN server to set
@@ -229,6 +229,22 @@
  */
 const gchar *purple_network_get_stun_ip(void);
 	
+/**	
+ * Update the TURN server IP given the host name
+ * Will result in a DNS query being executed asynchronous
+ * 
+ * @param stun_server The host name of the STUN server to set
+ */
+void purple_network_set_turn_server(const gchar *stun_server);
+	
+/**
+ * Get the IP address of the STUN server as a string representation
+ *
+ * @return the IP address
+ */
+const gchar *purple_network_get_turn_ip(void);
+		
+	
 /**
  * Initializes the network subsystem.
  */
--- a/pidgin/gtkprefs.c	Mon Jan 19 10:47:12 2009 +0000
+++ b/pidgin/gtkprefs.c	Thu Jan 22 23:04:52 2009 +0000
@@ -137,6 +137,26 @@
 	return pidgin_add_widget_to_vbox(GTK_BOX(page), title, sg, entry, TRUE, NULL);
 }
 
+GtkWidget *
+pidgin_prefs_labeled_password(GtkWidget *page, const gchar *title,
+							 const char *key, GtkSizeGroup *sg)
+{
+	GtkWidget *entry;
+	const gchar *value;
+
+	value = purple_prefs_get_string(key);
+
+	entry = gtk_entry_new();
+	gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE);
+	gtk_entry_set_text(GTK_ENTRY(entry), value);
+	g_signal_connect(G_OBJECT(entry), "changed",
+					 G_CALLBACK(entry_set), (char*)key);
+	gtk_widget_show(entry);
+
+	return pidgin_add_widget_to_vbox(GTK_BOX(page), title, sg, entry, TRUE, NULL);
+}
+
+
 static void
 dropdown_set(GObject *w, const char *key)
 {
@@ -1153,6 +1173,17 @@
 	return FALSE;
 }
 
+static gboolean network_turn_server_changed_cb(GtkWidget *widget, 
+	GdkEventFocus *event, gpointer data)
+{
+	GtkEntry *entry = GTK_ENTRY(widget);
+	purple_prefs_set_string("/purple/network/turn_server",
+		gtk_entry_get_text(entry));
+	purple_network_set_turn_server(gtk_entry_get_text(entry));
+	
+	return FALSE;
+}
+
 static void
 proxy_changed_cb(const char *name, PurplePrefType type,
 				 gconstpointer value, gpointer data)
@@ -1314,6 +1345,43 @@
 	g_signal_connect(G_OBJECT(ports_checkbox), "clicked",
 					 G_CALLBACK(pidgin_toggle_sensitive), spin_button);
 
+	vbox = pidgin_make_frame(ret, _("Relay Server (TURN)"));
+
+	/* TURN server */
+	hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
+	sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
+	label = gtk_label_new_with_mnemonic(_("_Server:"));
+	gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
+	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
+	
+	entry = gtk_entry_new();
+	gtk_label_set_mnemonic_widget(GTK_LABEL(label), entry);
+	g_signal_connect(G_OBJECT(entry), "focus-out-event",
+					 G_CALLBACK(network_turn_server_changed_cb), NULL);
+	gtk_entry_set_text(GTK_ENTRY(entry), 
+		purple_prefs_get_string("/purple/network/turn_server"));
+	gtk_misc_set_alignment(GTK_MISC(entry), 0, 0.5);
+	gtk_box_pack_start(GTK_BOX(hbox), entry, FALSE, FALSE, 0);
+	
+	gtk_size_group_add_widget(GTK_SIZE_GROUP(sg), label);
+	gtk_size_group_add_widget(GTK_SIZE_GROUP(sg), entry);
+	
+	sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
+	spin_button = pidgin_prefs_labeled_spin_button(hbox, _("_Port:"),
+		"/purple/network/turn_port", 0, 65535, sg);
+	gtk_container_add(GTK_CONTAINER(vbox), hbox);
+	
+	hbox = gtk_hbox_new(FALSE, PIDGIN_HIG_BOX_SPACE);
+	sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
+	entry = pidgin_prefs_labeled_entry(hbox, "_User name:", 
+		"/purple/network/turn_username", sg);
+
+	sg = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
+	entry = pidgin_prefs_labeled_password(hbox, "_Password:",
+		"/purple/network/turn_password", sg);
+	gtk_container_add(GTK_CONTAINER(vbox), hbox);
+	
+	
 	if (purple_running_gnome()) {
 		vbox = pidgin_make_frame(ret, _("Proxy Server &amp; Browser"));
 		prefs_proxy_frame = gtk_vbox_new(FALSE, 0);
--- a/pidgin/gtkprefs.h	Mon Jan 19 10:47:12 2009 +0000
+++ b/pidgin/gtkprefs.h	Thu Jan 22 23:04:52 2009 +0000
@@ -82,6 +82,22 @@
 										const char *key, GtkSizeGroup *sg);
 
 /**
+ * Add a new entry representing a password (string) preference
+ * The entry will use a password-style text entry (the text is substituded)
+ *
+ * @param page  The page to which the entry will be added
+ * @param title The text to be displayed as the entry label
+ * @param key   The key of the string pref that will be represented by the entry
+ * @param sg    If not NULL, the size group to which the entry will be added
+ *
+ * @return      An hbox containing both the label and the entry.  Can be used to set
+ *               the widgets to sensitive or insensitive based on the value of a
+ *               checkbox.
+ */
+GtkWidget *pidgin_prefs_labeled_password(GtkWidget *page, const gchar *title,
+										const char *key, GtkSizeGroup *sg);
+
+/**
  * Add a new dropdown representing a preference of the specified type
  *
  * @param page  The page to which the dropdown will be added