comparison libpurple/protocols/bonjour/mdns_win32.c @ 21987:71d18f5adbba

Detect the mdnsresponder crashing in the DnsSD implementation and disconnect the account instead of pegging the CPU.
author Daniel Atallah <daniel.atallah@gmail.com>
date Fri, 04 Jan 2008 20:41:08 +0000
parents 26648115261c
children 1be0d49532a1
comparison
equal deleted inserted replaced
21985:035cfd9080a6 21987:71d18f5adbba
28 #include "dnsquery.h" 28 #include "dnsquery.h"
29 #include "mdns_common.h" 29 #include "mdns_common.h"
30 30
31 static GSList *pending_buddies = NULL; 31 static GSList *pending_buddies = NULL;
32 32
33 typedef struct _dnssd_service_ref_handler {
34 DNSServiceRef sdRef;
35 PurpleAccount *account;
36 guint input_handler;
37 } DnsSDServiceRefHandlerData;
38
33 /* data used by win32 bonjour implementation */ 39 /* data used by win32 bonjour implementation */
34 typedef struct _win32_session_impl_data { 40 typedef struct _win32_session_impl_data {
35 DNSServiceRef presence_svc; 41 DnsSDServiceRefHandlerData *presence_query;
36 DNSServiceRef browser_svc; 42 DnsSDServiceRefHandlerData *browser_query;
37 DNSRecordRef buddy_icon_rec; 43 DNSRecordRef buddy_icon_rec;
38
39 guint presence_handler;
40 guint browser_handler;
41 } Win32SessionImplData; 44 } Win32SessionImplData;
42 45
43 typedef struct _win32_buddy_service_resolver_data { 46 typedef struct _win32_buddy_service_resolver_data {
44 DNSServiceRef txt_query; 47 DnsSDServiceRefHandlerData *txt_query;
45 guint txt_query_handler;
46 uint32_t if_idx; 48 uint32_t if_idx;
47 gchar *name; 49 gchar *name;
48 gchar *type; 50 gchar *type;
49 gchar *domain; 51 gchar *domain;
50 /* This is a reference to the entry in BonjourBuddy->ips */ 52 /* This is a reference to the entry in BonjourBuddy->ips */
51 const char *ip; 53 const char *ip;
52 } Win32SvcResolverData; 54 } Win32SvcResolverData;
53 55
54 typedef struct _win32_buddy_impl_data { 56 typedef struct _win32_buddy_impl_data {
55 GSList *resolvers; 57 GSList *resolvers;
56 DNSServiceRef null_query; 58 DnsSDServiceRefHandlerData *null_query;
57 guint null_query_handler;
58 } Win32BuddyImplData; 59 } Win32BuddyImplData;
59 60
60 /* data structure for the resolve callback */ 61 /* data structure for the resolve callback */
61 typedef struct _ResolveCallbackArgs { 62 typedef struct _ResolveCallbackArgs {
62 DNSServiceRef resolver; 63 DnsSDServiceRefHandlerData *resolver_query;
63 guint resolver_handler;
64 PurpleAccount *account; 64 PurpleAccount *account;
65 BonjourBuddy *bb; 65 BonjourBuddy *bb;
66 Win32SvcResolverData *res_data; 66 Win32SvcResolverData *res_data;
67 gchar *full_service_name; 67 gchar *full_service_name;
68 PurpleDnsQueryData *query; 68 PurpleDnsQueryData *dns_query;
69 } ResolveCallbackArgs; 69 } ResolveCallbackArgs;
70
70 71
71 static gint 72 static gint
72 _find_resolver_data(gconstpointer a, gconstpointer b) { 73 _find_resolver_data(gconstpointer a, gconstpointer b) {
73 const Win32SvcResolverData *rd_a = a; 74 const Win32SvcResolverData *rd_a = a;
74 const Win32SvcResolverData *rd_b = b; 75 const Win32SvcResolverData *rd_b = b;
85 } 86 }
86 87
87 static void 88 static void
88 _cleanup_resolver_data(Win32SvcResolverData *rd) { 89 _cleanup_resolver_data(Win32SvcResolverData *rd) {
89 if (rd->txt_query != NULL) { 90 if (rd->txt_query != NULL) {
90 purple_input_remove(rd->txt_query_handler); 91 purple_input_remove(rd->txt_query->input_handler);
91 DNSServiceRefDeallocate(rd->txt_query); 92 DNSServiceRefDeallocate(rd->txt_query->sdRef);
93 g_free(rd->txt_query);
92 } 94 }
93 g_free(rd->name); 95 g_free(rd->name);
94 g_free(rd->type); 96 g_free(rd->type);
95 g_free(rd->domain); 97 g_free(rd->domain);
96 g_free(rd); 98 g_free(rd);
97 } 99 }
98 100
99 static void 101 static void
100 _mdns_handle_event(gpointer data, gint source, PurpleInputCondition condition) { 102 _mdns_handle_event(gpointer data, gint source, PurpleInputCondition condition) {
101 DNSServiceProcessResult((DNSServiceRef) data); 103 DnsSDServiceRefHandlerData *srh = data;
104 DNSServiceErrorType errorCode = DNSServiceProcessResult(srh->sdRef);
105 if (errorCode != kDNSServiceErr_NoError) {
106 purple_debug_error("bonjour", "Error (%d) handling mDNS response.\n", errorCode);
107 /* This happens when the mDNSResponder goes down, I haven't seen it happen any other time (in my limited testing) */
108 if (errorCode == kDNSServiceErr_Unknown) {
109 purple_connection_error_reason(srh->account->gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR,
110 _("Error communicating with local mDNSResponder."));
111 }
112 }
102 } 113 }
103 114
104 static void 115 static void
105 _mdns_parse_text_record(BonjourBuddy *buddy, const char *record, uint16_t record_len) 116 _mdns_parse_text_record(BonjourBuddy *buddy, const char *record, uint16_t record_len)
106 { 117 {
140 g_return_if_fail(idata != NULL); 151 g_return_if_fail(idata != NULL);
141 152
142 bonjour_buddy_got_buddy_icon(bb, rdata, rdlen); 153 bonjour_buddy_got_buddy_icon(bb, rdata, rdlen);
143 154
144 /* We've got what we need; stop listening */ 155 /* We've got what we need; stop listening */
145 purple_input_remove(idata->null_query_handler); 156 purple_input_remove(idata->null_query->input_handler);
146 idata->null_query_handler = 0; 157 DNSServiceRefDeallocate(idata->null_query->sdRef);
147 DNSServiceRefDeallocate(idata->null_query); 158 g_free(idata->null_query);
148 idata->null_query = NULL; 159 idata->null_query = NULL;
149 } 160 }
150 } 161 }
151 } 162 }
152 163
153 static void 164 static void
154 _mdns_resolve_host_callback(GSList *hosts, gpointer data, const char *error_message) 165 _mdns_resolve_host_callback(GSList *hosts, gpointer data, const char *error_message)
155 { 166 {
156 ResolveCallbackArgs* args = (ResolveCallbackArgs*) data; 167 ResolveCallbackArgs *args = (ResolveCallbackArgs*) data;
157 Win32BuddyImplData *idata = args->bb->mdns_impl_data; 168 Win32BuddyImplData *idata = args->bb->mdns_impl_data;
158 gboolean delete_buddy = FALSE; 169 gboolean delete_buddy = FALSE;
159 PurpleBuddy *pb; 170 PurpleBuddy *pb;
160 171
161 if ((pb = purple_find_buddy(args->account, args->bb->name))) 172 if ((pb = purple_find_buddy(args->account, args->bb->name)))
167 purple_debug_error("bonjour", "host resolution - callback error.\n"); 178 purple_debug_error("bonjour", "host resolution - callback error.\n");
168 delete_buddy = TRUE; 179 delete_buddy = TRUE;
169 } else { 180 } else {
170 struct sockaddr_in *addr = g_slist_nth_data(hosts, 1); 181 struct sockaddr_in *addr = g_slist_nth_data(hosts, 1);
171 DNSServiceErrorType errorCode; 182 DNSServiceErrorType errorCode;
183 DNSServiceRef txt_query_sr;
172 184
173 /* finally, set up the continuous txt record watcher, and add the buddy to purple */ 185 /* finally, set up the continuous txt record watcher, and add the buddy to purple */
174 186 errorCode = DNSServiceQueryRecord(&txt_query_sr, kDNSServiceFlagsLongLivedQuery,
175 errorCode = DNSServiceQueryRecord(&args->res_data->txt_query, kDNSServiceFlagsLongLivedQuery,
176 kDNSServiceInterfaceIndexAny, args->full_service_name, kDNSServiceType_TXT, 187 kDNSServiceInterfaceIndexAny, args->full_service_name, kDNSServiceType_TXT,
177 kDNSServiceClass_IN, _mdns_record_query_callback, args->bb); 188 kDNSServiceClass_IN, _mdns_record_query_callback, args->bb);
178 if (errorCode == kDNSServiceErr_NoError) { 189 if (errorCode == kDNSServiceErr_NoError) {
179 const char *ip = inet_ntoa(addr->sin_addr); 190 const char *ip = inet_ntoa(addr->sin_addr);
180 191
181 purple_debug_info("bonjour", "Found buddy %s at %s:%d\n", args->bb->name, ip, args->bb->port_p2pj); 192 purple_debug_info("bonjour", "Found buddy %s at %s:%d\n", args->bb->name, ip, args->bb->port_p2pj);
182 193
183
184 args->bb->ips = g_slist_prepend(args->bb->ips, g_strdup(ip)); 194 args->bb->ips = g_slist_prepend(args->bb->ips, g_strdup(ip));
185 args->res_data->ip = args->bb->ips->data; 195 args->res_data->ip = args->bb->ips->data;
186 196
187 args->res_data->txt_query_handler = purple_input_add(DNSServiceRefSockFD(args->res_data->txt_query), 197 args->res_data->txt_query = g_new(DnsSDServiceRefHandlerData, 1);
198 args->res_data->txt_query->sdRef = txt_query_sr;
199 args->res_data->txt_query->account = args->account;
200
201 args->res_data->txt_query->input_handler = purple_input_add(DNSServiceRefSockFD(txt_query_sr),
188 PURPLE_INPUT_READ, _mdns_handle_event, args->res_data->txt_query); 202 PURPLE_INPUT_READ, _mdns_handle_event, args->res_data->txt_query);
189 203
190 bonjour_buddy_add_to_purple(args->bb, NULL); 204 bonjour_buddy_add_to_purple(args->bb, NULL);
191 } else { 205 } else {
192 purple_debug_error("bonjour", "Unable to set up record watcher for buddy %s (%d)\n", args->bb->name, errorCode); 206 purple_debug_error("bonjour", "Unable to set up record watcher for buddy %s (%d)\n", args->bb->name, errorCode);
229 243
230 static void DNSSD_API 244 static void DNSSD_API
231 _mdns_service_resolve_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, 245 _mdns_service_resolve_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode,
232 const char *fullname, const char *hosttarget, uint16_t port, uint16_t txtLen, const char *txtRecord, void *context) 246 const char *fullname, const char *hosttarget, uint16_t port, uint16_t txtLen, const char *txtRecord, void *context)
233 { 247 {
234 ResolveCallbackArgs *args = (ResolveCallbackArgs*)context; 248 ResolveCallbackArgs *args = (ResolveCallbackArgs*) context;
235 Win32BuddyImplData *idata = args->bb->mdns_impl_data; 249 Win32BuddyImplData *idata = args->bb->mdns_impl_data;
236 250
237 /* remove the input fd and destroy the service ref */ 251 /* remove the input fd and destroy the service ref */
238 purple_input_remove(args->resolver_handler); 252 purple_input_remove(args->resolver_query->input_handler);
239 args->resolver_handler = 0; 253 DNSServiceRefDeallocate(args->resolver_query->sdRef);
240 DNSServiceRefDeallocate(args->resolver); 254 g_free(args->resolver_query);
241 args->resolver = NULL; 255 args->resolver_query = NULL;
242 256
243 if (errorCode != kDNSServiceErr_NoError) 257 if (errorCode != kDNSServiceErr_NoError)
244 purple_debug_error("bonjour", "service resolver - callback error.\n"); 258 purple_debug_error("bonjour", "service resolver - callback error.\n");
245 else { 259 else {
246 /* set more arguments, and start the host resolver */ 260 /* set more arguments, and start the host resolver */
247 261
248 if ((args->query = 262 if ((args->dns_query =
249 purple_dnsquery_a(hosttarget, port, _mdns_resolve_host_callback, args)) != NULL) { 263 purple_dnsquery_a(hosttarget, port, _mdns_resolve_host_callback, args)) != NULL) {
250 264
251 args->full_service_name = g_strdup(fullname); 265 args->full_service_name = g_strdup(fullname);
252 266
253 /* TODO: Should this be per resolver? */ 267 /* TODO: Should this be per resolver? */
305 /* A presence service instance has been discovered... check it isn't us! */ 319 /* A presence service instance has been discovered... check it isn't us! */
306 if (purple_utf8_strcasecmp(serviceName, account->username) != 0) { 320 if (purple_utf8_strcasecmp(serviceName, account->username) != 0) {
307 DNSServiceErrorType resErrorCode; 321 DNSServiceErrorType resErrorCode;
308 /* OK, lets go ahead and resolve it to add to the buddy list */ 322 /* OK, lets go ahead and resolve it to add to the buddy list */
309 ResolveCallbackArgs *args = g_new0(ResolveCallbackArgs, 1); 323 ResolveCallbackArgs *args = g_new0(ResolveCallbackArgs, 1);
324 DNSServiceRef resolver_sr;
310 325
311 purple_debug_info("bonjour", "Received new record for '%s' on iface %u (%s, %s)\n", 326 purple_debug_info("bonjour", "Received new record for '%s' on iface %u (%s, %s)\n",
312 serviceName, interfaceIndex, regtype ? regtype : "", 327 serviceName, interfaceIndex, regtype ? regtype : "",
313 replyDomain ? replyDomain : ""); 328 replyDomain ? replyDomain : "");
314 329
315 resErrorCode = DNSServiceResolve(&args->resolver, 0, 0, serviceName, regtype, 330 resErrorCode = DNSServiceResolve(&resolver_sr, 0, 0, serviceName, regtype,
316 replyDomain, _mdns_service_resolve_callback, args); 331 replyDomain, _mdns_service_resolve_callback, args);
317 if (resErrorCode == kDNSServiceErr_NoError) { 332 if (resErrorCode == kDNSServiceErr_NoError) {
318 GSList *tmp = pending_buddies; 333 GSList *tmp = pending_buddies;
319 PurpleBuddy *pb; 334 PurpleBuddy *pb;
320 BonjourBuddy* bb = NULL; 335 BonjourBuddy* bb = NULL;
321 Win32SvcResolverData *rd; 336 Win32SvcResolverData *rd;
322 Win32BuddyImplData *idata; 337 Win32BuddyImplData *idata;
323 gint fd;
324 338
325 /* Is there an existing buddy? */ 339 /* Is there an existing buddy? */
326 if ((pb = purple_find_buddy(account, serviceName))) 340 if ((pb = purple_find_buddy(account, serviceName)))
327 bb = pb->proto_data; 341 bb = pb->proto_data;
328 /* Is there a pending buddy? */ 342 /* Is there a pending buddy? */
345 pending_buddies = g_slist_prepend(pending_buddies, bb); 359 pending_buddies = g_slist_prepend(pending_buddies, bb);
346 else 360 else
347 pb->proto_data = bb; 361 pb->proto_data = bb;
348 } 362 }
349 363
350
351 rd = g_new0(Win32SvcResolverData, 1); 364 rd = g_new0(Win32SvcResolverData, 1);
352 rd->if_idx = interfaceIndex; 365 rd->if_idx = interfaceIndex;
353 rd->name = g_strdup(serviceName); 366 rd->name = g_strdup(serviceName);
354 rd->type = g_strdup(regtype); 367 rd->type = g_strdup(regtype);
355 rd->domain = g_strdup(replyDomain); 368 rd->domain = g_strdup(replyDomain);
359 372
360 args->bb = bb; 373 args->bb = bb;
361 args->res_data = rd; 374 args->res_data = rd;
362 args->account = account; 375 args->account = account;
363 376
377 args->resolver_query = g_new(DnsSDServiceRefHandlerData, 1);
378 args->resolver_query->sdRef = resolver_sr;
379 args->resolver_query->account = account;
364 /* get a file descriptor for this service ref, and add it to the input list */ 380 /* get a file descriptor for this service ref, and add it to the input list */
365 fd = DNSServiceRefSockFD(args->resolver); 381 args->resolver_query->input_handler = purple_input_add(DNSServiceRefSockFD(resolver_sr),
366 args->resolver_handler = purple_input_add(fd, PURPLE_INPUT_READ, _mdns_handle_event, args->resolver); 382 PURPLE_INPUT_READ, _mdns_handle_event, args->resolver_query);
367 } else { 383 } else {
368 purple_debug_error("bonjour", "service browser - failed to resolve service. (%d)\n", resErrorCode); 384 purple_debug_error("bonjour", "service browser - failed to resolve service. (%d)\n", resErrorCode);
369 g_free(args); 385 g_free(args);
370 } 386 }
371 } 387 }
453 if (errorCode != kDNSServiceErr_NoError) { 469 if (errorCode != kDNSServiceErr_NoError) {
454 purple_debug_error("bonjour", "Unable to allocate memory for text record.(%d)\n", errorCode); 470 purple_debug_error("bonjour", "Unable to allocate memory for text record.(%d)\n", errorCode);
455 ret = FALSE; 471 ret = FALSE;
456 } else { 472 } else {
457 /* OK, we're done constructing the text record, (re)publish the service */ 473 /* OK, we're done constructing the text record, (re)publish the service */
474 DNSServiceRef presence_sr;
458 475
459 switch (type) { 476 switch (type) {
460 case PUBLISH_START: 477 case PUBLISH_START:
461 purple_debug_info("bonjour", "Registering presence on port %d\n", data->port_p2pj); 478 purple_debug_info("bonjour", "Registering presence on port %d\n", data->port_p2pj);
462 errorCode = DNSServiceRegister(&idata->presence_svc, 0, 0, purple_account_get_username(data->account), ICHAT_SERVICE, 479 errorCode = DNSServiceRegister(&presence_sr, 0, 0, purple_account_get_username(data->account), ICHAT_SERVICE,
463 NULL, NULL, htons(data->port_p2pj), TXTRecordGetLength(&dns_data), TXTRecordGetBytesPtr(&dns_data), 480 NULL, NULL, htons(data->port_p2pj), TXTRecordGetLength(&dns_data), TXTRecordGetBytesPtr(&dns_data),
464 _mdns_service_register_callback, NULL); 481 _mdns_service_register_callback, NULL);
465 break; 482 break;
466 483
467 case PUBLISH_UPDATE: 484 case PUBLISH_UPDATE:
468 purple_debug_info("bonjour", "Updating presence.\n"); 485 purple_debug_info("bonjour", "Updating presence.\n");
469 errorCode = DNSServiceUpdateRecord(idata->presence_svc, NULL, 0, TXTRecordGetLength(&dns_data), TXTRecordGetBytesPtr(&dns_data), 0); 486 errorCode = DNSServiceUpdateRecord(idata->presence_query->sdRef, NULL, 0, TXTRecordGetLength(&dns_data), TXTRecordGetBytesPtr(&dns_data), 0);
470 break; 487 break;
471 } 488 }
472 489
473 if (errorCode != kDNSServiceErr_NoError) { 490 if (errorCode != kDNSServiceErr_NoError) {
474 purple_debug_error("bonjour", "Failed to publish presence service.(%d)\n", errorCode); 491 purple_debug_error("bonjour", "Failed to publish presence service.(%d)\n", errorCode);
476 } else if (type == PUBLISH_START) { 493 } else if (type == PUBLISH_START) {
477 /* We need to do this because according to the Apple docs: 494 /* We need to do this because according to the Apple docs:
478 * "the client is responsible for ensuring that DNSServiceProcessResult() is called 495 * "the client is responsible for ensuring that DNSServiceProcessResult() is called
479 * whenever there is a reply from the daemon - the daemon may terminate its connection 496 * whenever there is a reply from the daemon - the daemon may terminate its connection
480 * with a client that does not process the daemon's responses */ 497 * with a client that does not process the daemon's responses */
481 idata->presence_handler = purple_input_add(DNSServiceRefSockFD(idata->presence_svc), 498 idata->presence_query = g_new(DnsSDServiceRefHandlerData, 1);
482 PURPLE_INPUT_READ, _mdns_handle_event, idata->presence_svc); 499 idata->presence_query->sdRef = presence_sr;
500 idata->presence_query->account = data->account;
501 idata->presence_query->input_handler = purple_input_add(DNSServiceRefSockFD(presence_sr),
502 PURPLE_INPUT_READ, _mdns_handle_event, idata->presence_query);
483 } 503 }
484 } 504 }
485 505
486 /* Free the memory used by temp data */ 506 /* Free the memory used by temp data */
487 TXTRecordDeallocate(&dns_data); 507 TXTRecordDeallocate(&dns_data);
489 } 509 }
490 510
491 gboolean _mdns_browse(BonjourDnsSd *data) { 511 gboolean _mdns_browse(BonjourDnsSd *data) {
492 DNSServiceErrorType errorCode; 512 DNSServiceErrorType errorCode;
493 Win32SessionImplData *idata = data->mdns_impl_data; 513 Win32SessionImplData *idata = data->mdns_impl_data;
514 DNSServiceRef browser_sr;
494 515
495 g_return_val_if_fail(idata != NULL, FALSE); 516 g_return_val_if_fail(idata != NULL, FALSE);
496 517
497 errorCode = DNSServiceBrowse(&idata->browser_svc, 0, 0, ICHAT_SERVICE, NULL, 518 errorCode = DNSServiceBrowse(&browser_sr, 0, 0, ICHAT_SERVICE, NULL,
498 _mdns_service_browse_callback, data->account); 519 _mdns_service_browse_callback, data->account);
499 if (errorCode == kDNSServiceErr_NoError) { 520 if (errorCode == kDNSServiceErr_NoError) {
500 idata->browser_handler = purple_input_add(DNSServiceRefSockFD(idata->browser_svc), 521 idata->browser_query = g_new(DnsSDServiceRefHandlerData, 1);
501 PURPLE_INPUT_READ, _mdns_handle_event, idata->browser_svc); 522 idata->browser_query->sdRef = browser_sr;
523 idata->browser_query->account = data->account;
524 idata->browser_query->input_handler = purple_input_add(DNSServiceRefSockFD(browser_sr),
525 PURPLE_INPUT_READ, _mdns_handle_event, idata->browser_query);
502 return TRUE; 526 return TRUE;
503 } else 527 } else
504 purple_debug_error("bonjour", "Error registering Local Link presence browser. (%d)\n", errorCode); 528 purple_debug_error("bonjour", "Error registering Local Link presence browser. (%d)\n", errorCode);
505 529
506 530
511 Win32SessionImplData *idata = data->mdns_impl_data; 535 Win32SessionImplData *idata = data->mdns_impl_data;
512 536
513 if (idata == NULL) 537 if (idata == NULL)
514 return; 538 return;
515 539
516 if (idata->presence_svc != NULL) { 540 if (idata->presence_query != NULL) {
517 purple_input_remove(idata->presence_handler); 541 purple_input_remove(idata->presence_query->input_handler);
518 DNSServiceRefDeallocate(idata->presence_svc); 542 DNSServiceRefDeallocate(idata->presence_query->sdRef);
519 } 543 g_free(idata->presence_query);
520 544 }
521 if (idata->browser_svc != NULL) { 545
522 purple_input_remove(idata->browser_handler); 546 if (idata->browser_query != NULL) {
523 DNSServiceRefDeallocate(idata->browser_svc); 547 purple_input_remove(idata->browser_query->input_handler);
548 DNSServiceRefDeallocate(idata->browser_query->sdRef);
549 g_free(idata->browser_query);
524 } 550 }
525 551
526 g_free(idata); 552 g_free(idata);
527 553
528 data->mdns_impl_data = NULL; 554 data->mdns_impl_data = NULL;
534 560
535 g_return_val_if_fail(idata != NULL, FALSE); 561 g_return_val_if_fail(idata != NULL, FALSE);
536 562
537 if (avatar_data != NULL && idata->buddy_icon_rec == NULL) { 563 if (avatar_data != NULL && idata->buddy_icon_rec == NULL) {
538 purple_debug_info("bonjour", "Setting new buddy icon.\n"); 564 purple_debug_info("bonjour", "Setting new buddy icon.\n");
539 errorCode = DNSServiceAddRecord(idata->presence_svc, &idata->buddy_icon_rec, 565 errorCode = DNSServiceAddRecord(idata->presence_query->sdRef, &idata->buddy_icon_rec,
540 0, kDNSServiceType_NULL, avatar_len, avatar_data, 0); 566 0, kDNSServiceType_NULL, avatar_len, avatar_data, 0);
541 } else if (avatar_data != NULL) { 567 } else if (avatar_data != NULL) {
542 purple_debug_info("bonjour", "Updating existing buddy icon.\n"); 568 purple_debug_info("bonjour", "Updating existing buddy icon.\n");
543 errorCode = DNSServiceUpdateRecord(idata->presence_svc, idata->buddy_icon_rec, 569 errorCode = DNSServiceUpdateRecord(idata->presence_query->sdRef, idata->buddy_icon_rec,
544 0, avatar_len, avatar_data, 0); 570 0, avatar_len, avatar_data, 0);
545 } else if (idata->buddy_icon_rec != NULL) { 571 } else if (idata->buddy_icon_rec != NULL) {
546 purple_debug_info("bonjour", "Removing existing buddy icon.\n"); 572 purple_debug_info("bonjour", "Removing existing buddy icon.\n");
547 errorCode = DNSServiceRemoveRecord(idata->presence_svc, idata->buddy_icon_rec, 0); 573 errorCode = DNSServiceRemoveRecord(idata->presence_query->sdRef, idata->buddy_icon_rec, 0);
548 idata->buddy_icon_rec = NULL; 574 idata->buddy_icon_rec = NULL;
549 } 575 }
550 576
551 if (errorCode != kDNSServiceErr_NoError) { 577 if (errorCode != kDNSServiceErr_NoError) {
552 purple_debug_error("bonjour", "Error (%d) setting buddy icon record.\n", errorCode); 578 purple_debug_error("bonjour", "Error (%d) setting buddy icon record.\n", errorCode);
570 _cleanup_resolver_data(rd); 596 _cleanup_resolver_data(rd);
571 idata->resolvers = g_slist_delete_link(idata->resolvers, idata->resolvers); 597 idata->resolvers = g_slist_delete_link(idata->resolvers, idata->resolvers);
572 } 598 }
573 599
574 if (idata->null_query != NULL) { 600 if (idata->null_query != NULL) {
575 purple_input_remove(idata->null_query_handler); 601 purple_input_remove(idata->null_query->input_handler);
576 DNSServiceRefDeallocate(idata->null_query); 602 DNSServiceRefDeallocate(idata->null_query->sdRef);
603 g_free(idata->null_query);
577 } 604 }
578 605
579 g_free(idata); 606 g_free(idata);
580 607
581 buddy->mdns_impl_data = NULL; 608 buddy->mdns_impl_data = NULL;
587 614
588 g_return_if_fail(idata != NULL); 615 g_return_if_fail(idata != NULL);
589 616
590 /* Cancel any existing query */ 617 /* Cancel any existing query */
591 if (idata->null_query != NULL) { 618 if (idata->null_query != NULL) {
592 purple_input_remove(idata->null_query_handler); 619 purple_input_remove(idata->null_query->input_handler);
593 idata->null_query_handler = 0; 620 DNSServiceRefDeallocate(idata->null_query->sdRef);
594 DNSServiceRefDeallocate(idata->null_query); 621 g_free(idata->null_query);
595 idata->null_query = NULL; 622 idata->null_query = NULL;
596 } 623 }
597 624
598 if (DNSServiceConstructFullName(svc_name, buddy->name, ICHAT_SERVICE, "local") != 0) 625 if (DNSServiceConstructFullName(svc_name, buddy->name, ICHAT_SERVICE, "local") != 0)
599 purple_debug_error("bonjour", "Unable to construct full name to retrieve buddy icon for %s.\n", buddy->name); 626 purple_debug_error("bonjour", "Unable to construct full name to retrieve buddy icon for %s.\n", buddy->name);
600 else { 627 else {
601 DNSServiceErrorType errorCode = DNSServiceQueryRecord(&idata->null_query, 0, kDNSServiceInterfaceIndexAny, 628 DNSServiceRef null_query_sr;
629
630 DNSServiceErrorType errorCode = DNSServiceQueryRecord(&null_query_sr, 0, kDNSServiceInterfaceIndexAny,
602 svc_name, kDNSServiceType_NULL, kDNSServiceClass_IN, _mdns_record_query_callback, buddy); 631 svc_name, kDNSServiceType_NULL, kDNSServiceClass_IN, _mdns_record_query_callback, buddy);
603 if (errorCode == kDNSServiceErr_NoError) 632
604 idata->null_query_handler = purple_input_add(DNSServiceRefSockFD(idata->null_query), 633 if (errorCode == kDNSServiceErr_NoError) {
634 idata->null_query = g_new(DnsSDServiceRefHandlerData, 1);
635
636 idata->null_query->sdRef = null_query_sr;
637 idata->null_query->account = buddy->account;
638
639 idata->null_query->input_handler = purple_input_add(DNSServiceRefSockFD(null_query_sr),
605 PURPLE_INPUT_READ, _mdns_handle_event, idata->null_query); 640 PURPLE_INPUT_READ, _mdns_handle_event, idata->null_query);
606 else 641 } else
607 purple_debug_error("bonjour", "Unable to query buddy icon record for %s. (%d)\n", buddy->name, errorCode); 642 purple_debug_error("bonjour", "Unable to query buddy icon record for %s. (%d)\n", buddy->name, errorCode);
608 } 643 }
609 644
610 } 645 }
611 646