im.pidgin.pidgin: 3531b34b0f7b83dfa1705ca1d133ea83293d79b2

datallah at pidgin.im datallah at pidgin.im
Fri Jan 4 15:45:48 EST 2008


-----------------------------------------------------------------
Revision: 3531b34b0f7b83dfa1705ca1d133ea83293d79b2
Ancestor: 79d3af412f1d67bac1a2a9614ace068e7dc753db
Author: datallah at pidgin.im
Date: 2008-01-04T20:41:08
Branch: im.pidgin.pidgin

Modified files:
        libpurple/protocols/bonjour/mdns_win32.c

ChangeLog: 

Detect the mdnsresponder crashing in the DnsSD implementation and disconnect the account instead of pegging the CPU.

-------------- next part --------------
============================================================
--- libpurple/protocols/bonjour/mdns_win32.c	fc40611da25da58c5de43c1663d496070021755a
+++ libpurple/protocols/bonjour/mdns_win32.c	38ceb904cf4ad04b7a57106ac9887db1c8708f09
@@ -30,19 +30,21 @@ static GSList *pending_buddies = NULL;
 
 static GSList *pending_buddies = NULL;
 
+typedef struct _dnssd_service_ref_handler {
+	DNSServiceRef sdRef;
+	PurpleAccount *account;
+	guint input_handler;
+} DnsSDServiceRefHandlerData;
+
 /* data used by win32 bonjour implementation */
 typedef struct _win32_session_impl_data {
-	DNSServiceRef presence_svc;
-	DNSServiceRef browser_svc;
+	DnsSDServiceRefHandlerData *presence_query;
+	DnsSDServiceRefHandlerData *browser_query;
 	DNSRecordRef buddy_icon_rec;
-
-	guint presence_handler;
-	guint browser_handler;
 } Win32SessionImplData;
 
 typedef struct _win32_buddy_service_resolver_data {
-	DNSServiceRef txt_query;
-	guint txt_query_handler;
+	DnsSDServiceRefHandlerData *txt_query;
 	uint32_t if_idx;
 	gchar *name;
 	gchar *type;
@@ -53,21 +55,20 @@ typedef struct _win32_buddy_impl_data {
 
 typedef struct _win32_buddy_impl_data {
 	GSList *resolvers;
-	DNSServiceRef null_query;
-	guint null_query_handler;
+	DnsSDServiceRefHandlerData *null_query;
 } Win32BuddyImplData;
 
 /* data structure for the resolve callback */
 typedef struct _ResolveCallbackArgs {
-	DNSServiceRef resolver;
-	guint resolver_handler;
+	DnsSDServiceRefHandlerData *resolver_query;
 	PurpleAccount *account;
 	BonjourBuddy *bb;
 	Win32SvcResolverData *res_data;
 	gchar *full_service_name;
-	PurpleDnsQueryData *query;
+	PurpleDnsQueryData *dns_query;
 } ResolveCallbackArgs;
 
+
 static gint
 _find_resolver_data(gconstpointer a, gconstpointer b) {
 	const Win32SvcResolverData *rd_a = a;
@@ -87,8 +88,9 @@ _cleanup_resolver_data(Win32SvcResolverD
 static void
 _cleanup_resolver_data(Win32SvcResolverData *rd) {
 	if (rd->txt_query != NULL) {
-		purple_input_remove(rd->txt_query_handler);
-		DNSServiceRefDeallocate(rd->txt_query);
+		purple_input_remove(rd->txt_query->input_handler);
+		DNSServiceRefDeallocate(rd->txt_query->sdRef);
+		g_free(rd->txt_query);
 	}
 	g_free(rd->name);
 	g_free(rd->type);
@@ -98,7 +100,16 @@ _mdns_handle_event(gpointer data, gint s
 
 static void
 _mdns_handle_event(gpointer data, gint source, PurpleInputCondition condition) {
-	DNSServiceProcessResult((DNSServiceRef) data);
+	DnsSDServiceRefHandlerData *srh = data;
+	DNSServiceErrorType errorCode = DNSServiceProcessResult(srh->sdRef);
+	if (errorCode != kDNSServiceErr_NoError) {
+		purple_debug_error("bonjour", "Error (%d) handling mDNS response.\n", errorCode);
+		/* This happens when the mDNSResponder goes down, I haven't seen it happen any other time (in my limited testing) */
+		if (errorCode == kDNSServiceErr_Unknown) {
+			purple_connection_error_reason(srh->account->gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
+				_("Error communicating with local mDNSResponder."));
+		}
+	}
 }
 
 static void
@@ -142,9 +153,9 @@ _mdns_record_query_callback(DNSServiceRe
 			bonjour_buddy_got_buddy_icon(bb, rdata, rdlen);
 
 			/* We've got what we need; stop listening */
-			purple_input_remove(idata->null_query_handler);
-			idata->null_query_handler = 0;
-			DNSServiceRefDeallocate(idata->null_query);
+			purple_input_remove(idata->null_query->input_handler);
+			DNSServiceRefDeallocate(idata->null_query->sdRef);
+			g_free(idata->null_query);
 			idata->null_query = NULL;
 		}
 	}
@@ -153,7 +164,7 @@ _mdns_resolve_host_callback(GSList *host
 static void
 _mdns_resolve_host_callback(GSList *hosts, gpointer data, const char *error_message)
 {
-	ResolveCallbackArgs* args = (ResolveCallbackArgs*) data;
+	ResolveCallbackArgs *args = (ResolveCallbackArgs*) data;
 	Win32BuddyImplData *idata = args->bb->mdns_impl_data;
 	gboolean delete_buddy = FALSE;
 	PurpleBuddy *pb;
@@ -169,10 +180,10 @@ _mdns_resolve_host_callback(GSList *host
 	} else {
 		struct sockaddr_in *addr = g_slist_nth_data(hosts, 1);
 		DNSServiceErrorType errorCode;
+		DNSServiceRef txt_query_sr;
 
 		/* finally, set up the continuous txt record watcher, and add the buddy to purple */
-
-		errorCode = DNSServiceQueryRecord(&args->res_data->txt_query, kDNSServiceFlagsLongLivedQuery,
+		errorCode = DNSServiceQueryRecord(&txt_query_sr, kDNSServiceFlagsLongLivedQuery,
 				kDNSServiceInterfaceIndexAny, args->full_service_name, kDNSServiceType_TXT,
 				kDNSServiceClass_IN, _mdns_record_query_callback, args->bb);
 		if (errorCode == kDNSServiceErr_NoError) {
@@ -180,11 +191,14 @@ _mdns_resolve_host_callback(GSList *host
 
 			purple_debug_info("bonjour", "Found buddy %s at %s:%d\n", args->bb->name, ip, args->bb->port_p2pj);
 
-
 			args->bb->ips = g_slist_prepend(args->bb->ips, g_strdup(ip));
 			args->res_data->ip = args->bb->ips->data;
 
-			args->res_data->txt_query_handler = purple_input_add(DNSServiceRefSockFD(args->res_data->txt_query),
+			args->res_data->txt_query = g_new(DnsSDServiceRefHandlerData, 1);
+			args->res_data->txt_query->sdRef = txt_query_sr;
+			args->res_data->txt_query->account = args->account;
+
+			args->res_data->txt_query->input_handler = purple_input_add(DNSServiceRefSockFD(txt_query_sr),
 				PURPLE_INPUT_READ, _mdns_handle_event, args->res_data->txt_query);
 
 			bonjour_buddy_add_to_purple(args->bb, NULL);
@@ -231,21 +245,21 @@ _mdns_service_resolve_callback(DNSServic
 _mdns_service_resolve_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode,
     const char *fullname, const char *hosttarget, uint16_t port, uint16_t txtLen, const char *txtRecord, void *context)
 {
-	ResolveCallbackArgs *args = (ResolveCallbackArgs*)context;
+	ResolveCallbackArgs *args = (ResolveCallbackArgs*) context;
 	Win32BuddyImplData *idata = args->bb->mdns_impl_data;
 
 	/* remove the input fd and destroy the service ref */
-	purple_input_remove(args->resolver_handler);
-	args->resolver_handler = 0;
-	DNSServiceRefDeallocate(args->resolver);
-	args->resolver = NULL;
+	purple_input_remove(args->resolver_query->input_handler);
+	DNSServiceRefDeallocate(args->resolver_query->sdRef);
+	g_free(args->resolver_query);
+	args->resolver_query = NULL;
 
 	if (errorCode != kDNSServiceErr_NoError)
 		purple_debug_error("bonjour", "service resolver - callback error.\n");
 	else {
 		/* set more arguments, and start the host resolver */
 
-		if ((args->query =
+		if ((args->dns_query =
 				purple_dnsquery_a(hosttarget, port, _mdns_resolve_host_callback, args)) != NULL) {
 
 			args->full_service_name = g_strdup(fullname);
@@ -307,12 +321,13 @@ _mdns_service_browse_callback(DNSService
 			DNSServiceErrorType resErrorCode;
 			/* OK, lets go ahead and resolve it to add to the buddy list */
 			ResolveCallbackArgs *args = g_new0(ResolveCallbackArgs, 1);
+			DNSServiceRef resolver_sr;
 
 			purple_debug_info("bonjour", "Received new record for '%s' on iface %u (%s, %s)\n",
 							  serviceName, interfaceIndex, regtype ? regtype : "",
 							  replyDomain ? replyDomain : "");
 
-			resErrorCode = DNSServiceResolve(&args->resolver, 0, 0, serviceName, regtype,
+			resErrorCode = DNSServiceResolve(&resolver_sr, 0, 0, serviceName, regtype,
 					replyDomain, _mdns_service_resolve_callback, args);
 			if (resErrorCode == kDNSServiceErr_NoError) {
 				GSList *tmp = pending_buddies;
@@ -320,7 +335,6 @@ _mdns_service_browse_callback(DNSService
 				BonjourBuddy* bb = NULL;
 				Win32SvcResolverData *rd;
 				Win32BuddyImplData *idata;
-				gint fd;
 
 				/* Is there an existing buddy? */
 				if ((pb = purple_find_buddy(account, serviceName)))
@@ -347,7 +361,6 @@ _mdns_service_browse_callback(DNSService
 						pb->proto_data = bb;
 				}
 
-
 				rd = g_new0(Win32SvcResolverData, 1);
 				rd->if_idx = interfaceIndex;
 				rd->name = g_strdup(serviceName);
@@ -361,9 +374,12 @@ _mdns_service_browse_callback(DNSService
 				args->res_data = rd;
 				args->account = account;
 
+				args->resolver_query = g_new(DnsSDServiceRefHandlerData, 1);
+				args->resolver_query->sdRef = resolver_sr;
+				args->resolver_query->account = account;
 				/* get a file descriptor for this service ref, and add it to the input list */
-				fd = DNSServiceRefSockFD(args->resolver);
-				args->resolver_handler = purple_input_add(fd, PURPLE_INPUT_READ, _mdns_handle_event, args->resolver);
+				args->resolver_query->input_handler = purple_input_add(DNSServiceRefSockFD(resolver_sr),
+					PURPLE_INPUT_READ, _mdns_handle_event, args->resolver_query);
 			} else {
 				purple_debug_error("bonjour", "service browser - failed to resolve service. (%d)\n", resErrorCode);
 				g_free(args);
@@ -455,18 +471,19 @@ gboolean _mdns_publish(BonjourDnsSd *dat
 		ret = FALSE;
 	} else {
 		/* OK, we're done constructing the text record, (re)publish the service */
+		DNSServiceRef presence_sr;
 
 		switch (type) {
 			case PUBLISH_START:
 				purple_debug_info("bonjour", "Registering presence on port %d\n", data->port_p2pj);
-				errorCode = DNSServiceRegister(&idata->presence_svc, 0, 0, purple_account_get_username(data->account), ICHAT_SERVICE,
+				errorCode = DNSServiceRegister(&presence_sr, 0, 0, purple_account_get_username(data->account), ICHAT_SERVICE,
 					NULL, NULL, htons(data->port_p2pj), TXTRecordGetLength(&dns_data), TXTRecordGetBytesPtr(&dns_data),
 					_mdns_service_register_callback, NULL);
 				break;
 
 			case PUBLISH_UPDATE:
 				purple_debug_info("bonjour", "Updating presence.\n");
-				errorCode = DNSServiceUpdateRecord(idata->presence_svc, NULL, 0, TXTRecordGetLength(&dns_data), TXTRecordGetBytesPtr(&dns_data), 0);
+				errorCode = DNSServiceUpdateRecord(idata->presence_query->sdRef, NULL, 0, TXTRecordGetLength(&dns_data), TXTRecordGetBytesPtr(&dns_data), 0);
 				break;
 		}
 
@@ -478,8 +495,11 @@ gboolean _mdns_publish(BonjourDnsSd *dat
 			 * "the client is responsible for ensuring that DNSServiceProcessResult() is called
 			 * whenever there is a reply from the daemon - the daemon may terminate its connection
 			 * with a client that does not process the daemon's responses */
-			idata->presence_handler = purple_input_add(DNSServiceRefSockFD(idata->presence_svc),
-				PURPLE_INPUT_READ, _mdns_handle_event, idata->presence_svc);
+			idata->presence_query = g_new(DnsSDServiceRefHandlerData, 1);
+			idata->presence_query->sdRef = presence_sr;
+			idata->presence_query->account = data->account;
+			idata->presence_query->input_handler = purple_input_add(DNSServiceRefSockFD(presence_sr),
+				PURPLE_INPUT_READ, _mdns_handle_event, idata->presence_query);
 		}
 	}
 
@@ -491,14 +511,18 @@ gboolean _mdns_browse(BonjourDnsSd *data
 gboolean _mdns_browse(BonjourDnsSd *data) {
 	DNSServiceErrorType errorCode;
 	Win32SessionImplData *idata = data->mdns_impl_data;
+	DNSServiceRef browser_sr;
 
 	g_return_val_if_fail(idata != NULL, FALSE);
 
-	errorCode = DNSServiceBrowse(&idata->browser_svc, 0, 0, ICHAT_SERVICE, NULL,
-						   _mdns_service_browse_callback, data->account);
+	errorCode = DNSServiceBrowse(&browser_sr, 0, 0, ICHAT_SERVICE, NULL,
+		_mdns_service_browse_callback, data->account);
 	if (errorCode == kDNSServiceErr_NoError) {
-		idata->browser_handler = purple_input_add(DNSServiceRefSockFD(idata->browser_svc),
-			PURPLE_INPUT_READ, _mdns_handle_event, idata->browser_svc);
+		idata->browser_query = g_new(DnsSDServiceRefHandlerData, 1);
+		idata->browser_query->sdRef = browser_sr;
+		idata->browser_query->account = data->account;
+		idata->browser_query->input_handler = purple_input_add(DNSServiceRefSockFD(browser_sr),
+			PURPLE_INPUT_READ, _mdns_handle_event, idata->browser_query);
 		return TRUE;
 	} else
 		purple_debug_error("bonjour", "Error registering Local Link presence browser. (%d)\n", errorCode);
@@ -513,14 +537,16 @@ void _mdns_stop(BonjourDnsSd *data) {
 	if (idata == NULL)
 		return;
 
-	if (idata->presence_svc != NULL) {
-		purple_input_remove(idata->presence_handler);
-		DNSServiceRefDeallocate(idata->presence_svc);
+	if (idata->presence_query != NULL) {
+		purple_input_remove(idata->presence_query->input_handler);
+		DNSServiceRefDeallocate(idata->presence_query->sdRef);
+		g_free(idata->presence_query);
 	}
 
-	if (idata->browser_svc != NULL) {
-		purple_input_remove(idata->browser_handler);
-		DNSServiceRefDeallocate(idata->browser_svc);
+	if (idata->browser_query != NULL) {
+		purple_input_remove(idata->browser_query->input_handler);
+		DNSServiceRefDeallocate(idata->browser_query->sdRef);
+		g_free(idata->browser_query);
 	}
 
 	g_free(idata);
@@ -536,15 +562,15 @@ gboolean _mdns_set_buddy_icon_data(Bonjo
 
 	if (avatar_data != NULL && idata->buddy_icon_rec == NULL) {
 		purple_debug_info("bonjour", "Setting new buddy icon.\n");
-		errorCode = DNSServiceAddRecord(idata->presence_svc, &idata->buddy_icon_rec,
+		errorCode = DNSServiceAddRecord(idata->presence_query->sdRef, &idata->buddy_icon_rec,
 			0, kDNSServiceType_NULL, avatar_len, avatar_data, 0);
 	} else if (avatar_data != NULL) {
 		purple_debug_info("bonjour", "Updating existing buddy icon.\n");
-		errorCode = DNSServiceUpdateRecord(idata->presence_svc, idata->buddy_icon_rec,
+		errorCode = DNSServiceUpdateRecord(idata->presence_query->sdRef, idata->buddy_icon_rec,
 			0, avatar_len, avatar_data, 0);
 	} else if (idata->buddy_icon_rec != NULL) {
 		purple_debug_info("bonjour", "Removing existing buddy icon.\n");
-		errorCode = DNSServiceRemoveRecord(idata->presence_svc, idata->buddy_icon_rec, 0);
+		errorCode = DNSServiceRemoveRecord(idata->presence_query->sdRef, idata->buddy_icon_rec, 0);
 		idata->buddy_icon_rec = NULL;
 	}
 
@@ -572,8 +598,9 @@ void _mdns_delete_buddy(BonjourBuddy *bu
 	}
 
 	if (idata->null_query != NULL) {
-		purple_input_remove(idata->null_query_handler);
-		DNSServiceRefDeallocate(idata->null_query);
+		purple_input_remove(idata->null_query->input_handler);
+		DNSServiceRefDeallocate(idata->null_query->sdRef);
+		g_free(idata->null_query);
 	}
 
 	g_free(idata);
@@ -589,21 +616,29 @@ void _mdns_retrieve_buddy_icon(BonjourBu
 
 	/* Cancel any existing query */
 	if (idata->null_query != NULL) {
-		purple_input_remove(idata->null_query_handler);
-		idata->null_query_handler = 0;
-		DNSServiceRefDeallocate(idata->null_query);
+		purple_input_remove(idata->null_query->input_handler);
+		DNSServiceRefDeallocate(idata->null_query->sdRef);
+		g_free(idata->null_query);
 		idata->null_query = NULL;
 	}
 
 	if (DNSServiceConstructFullName(svc_name, buddy->name, ICHAT_SERVICE, "local") != 0)
 		purple_debug_error("bonjour", "Unable to construct full name to retrieve buddy icon for %s.\n", buddy->name);
 	else {
-		DNSServiceErrorType errorCode = DNSServiceQueryRecord(&idata->null_query, 0, kDNSServiceInterfaceIndexAny,
+		DNSServiceRef null_query_sr;
+
+		DNSServiceErrorType errorCode = DNSServiceQueryRecord(&null_query_sr, 0, kDNSServiceInterfaceIndexAny,
 			svc_name, kDNSServiceType_NULL, kDNSServiceClass_IN, _mdns_record_query_callback, buddy);
-		if (errorCode == kDNSServiceErr_NoError)
-			idata->null_query_handler = purple_input_add(DNSServiceRefSockFD(idata->null_query),
+
+		if (errorCode == kDNSServiceErr_NoError) {
+			idata->null_query = g_new(DnsSDServiceRefHandlerData, 1);
+
+			idata->null_query->sdRef = null_query_sr;
+			idata->null_query->account = buddy->account;
+
+			idata->null_query->input_handler = purple_input_add(DNSServiceRefSockFD(null_query_sr),
 				PURPLE_INPUT_READ, _mdns_handle_event, idata->null_query);
-		else
+		} else
 			purple_debug_error("bonjour", "Unable to query buddy icon record for %s. (%d)\n", buddy->name, errorCode);
 	}
 


More information about the Commits mailing list