changeset 25497:f38799160cfa

Better support running many Bonjour clients on the same machine by allowing a listening port to be specified and falling back to a system-assigned port if it can't be used. Fixes #8462.
author Daniel Atallah <daniel.atallah@gmail.com>
date Sat, 21 Feb 2009 22:10:27 +0000
parents 7d58d7a3c5c3
children 6eff00e729ac
files libpurple/protocols/bonjour/bonjour.c libpurple/protocols/bonjour/bonjour.h libpurple/protocols/bonjour/jabber.c
diffstat 3 files changed, 21 insertions(+), 32 deletions(-) [+]
line wrap: on
line diff
--- a/libpurple/protocols/bonjour/bonjour.c	Thu Feb 19 22:52:49 2009 +0000
+++ b/libpurple/protocols/bonjour/bonjour.c	Sat Feb 21 22:10:27 2009 +0000
@@ -102,7 +102,7 @@
 
 	/* Start waiting for jabber connections (iChat style) */
 	bd->jabber_data = g_new0(BonjourJabber, 1);
-	bd->jabber_data->port = BONJOUR_DEFAULT_PORT_INT;
+	bd->jabber_data->port = purple_account_get_int(account, "port", BONJOUR_DEFAULT_PORT);
 	bd->jabber_data->account = account;
 
 	if (bonjour_jabber_start(bd->jabber_data) == -1) {
@@ -706,6 +706,9 @@
 	prpl_info.user_splits = g_list_append(prpl_info.user_splits, split);
 
 	/* Creating the options for the protocol */
+	option = purple_account_option_int_new(_("Local Port"), "port", BONJOUR_DEFAULT_PORT);
+	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
+
 	option = purple_account_option_string_new(_("First name"), "first", default_firstname);
 	prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, option);
 
--- a/libpurple/protocols/bonjour/bonjour.h	Thu Feb 19 22:52:49 2009 +0000
+++ b/libpurple/protocols/bonjour/bonjour.h	Sat Feb 21 22:10:27 2009 +0000
@@ -38,7 +38,7 @@
 #define BONJOUR_STATUS_ID_AVAILABLE "available"
 #define BONJOUR_STATUS_ID_AWAY      "away"
 
-#define BONJOUR_DEFAULT_PORT_INT 5298
+#define BONJOUR_DEFAULT_PORT 5298
 
 typedef struct _BonjourData
 {
--- a/libpurple/protocols/bonjour/jabber.c	Thu Feb 19 22:52:49 2009 +0000
+++ b/libpurple/protocols/bonjour/jabber.c	Sat Feb 21 22:10:27 2009 +0000
@@ -672,14 +672,11 @@
 bonjour_jabber_start(BonjourJabber *jdata)
 {
 	struct sockaddr_in my_addr;
-	int i;
-	gboolean bind_successful;
 
 	/* Open a listening socket for incoming conversations */
-	if ((jdata->socket = socket(PF_INET, SOCK_STREAM, 0)) < 0)
-	{
+	if ((jdata->socket = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
 		purple_debug_error("bonjour", "Cannot open socket: %s\n", g_strerror(errno));
-		purple_connection_error_reason (jdata->account->gc,
+		purple_connection_error_reason(jdata->account->gc,
 			PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
 			_("Cannot open socket"));
 		return -1;
@@ -688,36 +685,25 @@
 	memset(&my_addr, 0, sizeof(struct sockaddr_in));
 	my_addr.sin_family = AF_INET;
 
-	/* Attempt to find a free port */
-	bind_successful = FALSE;
-	for (i = 0; i < 10; i++)
-	{
-		my_addr.sin_port = htons(jdata->port);
-		if (bind(jdata->socket, (struct sockaddr*)&my_addr, sizeof(struct sockaddr)) == 0)
-		{
-			bind_successful = TRUE;
-			break;
+	/* Try to use the specified port - if it isn't available, use a random port */
+	my_addr.sin_port = htons(jdata->port);
+	if (bind(jdata->socket, (struct sockaddr*)&my_addr, sizeof(struct sockaddr)) != 0) {
+		purple_debug_info("bonjour", "Unable to bind to specified port %u (%s).\n", jdata->port, g_strerror(errno));
+		my_addr.sin_port = 0;
+		if (bind(jdata->socket, (struct sockaddr*)&my_addr, sizeof(struct sockaddr)) != 0) {
+			purple_debug_error("bonjour", "Unable to bind to system assigned port (%s).\n", g_strerror(errno));
+			purple_connection_error_reason(jdata->account->gc,
+				PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+				_("Could not bind socket to port"));
+			return -1;
 		}
-
-		purple_debug_info("bonjour", "Unable to bind to port %u.(%s)\n", jdata->port, g_strerror(errno));
-		jdata->port++;
-	}
-
-	/* On no!  We tried 10 ports and could not bind to ANY of them */
-	if (!bind_successful)
-	{
-		purple_debug_error("bonjour", "Cannot bind socket: %s\n", g_strerror(errno));
-		purple_connection_error_reason (jdata->account->gc,
-			PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
-			_("Could not bind socket to port"));
-		return -1;
+		jdata->port = purple_network_get_port_from_fd(jdata->socket);
 	}
 
 	/* Attempt to listen on the bound socket */
-	if (listen(jdata->socket, 10) != 0)
-	{
+	if (listen(jdata->socket, 10) != 0) {
 		purple_debug_error("bonjour", "Cannot listen on socket: %s\n", g_strerror(errno));
-		purple_connection_error_reason (jdata->account->gc,
+		purple_connection_error_reason(jdata->account->gc,
 			PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
 			_("Could not listen on socket"));
 		return -1;