Mercurial > pidgin
comparison libpurple/protocols/bonjour/mdns_win32.c @ 18843:7bf6b9a70b41
Some more minor mdns implementation abstraction tweaks and implementation of setting buddy icons for the win32 bonjour implementation.
author | Daniel Atallah <daniel.atallah@gmail.com> |
---|---|
date | Wed, 08 Aug 2007 01:50:01 +0000 |
parents | b839f427cbb2 |
children | 09f52521ff5b |
comparison
equal
deleted
inserted
replaced
18841:03a0054954bb | 18843:7bf6b9a70b41 |
---|---|
19 | 19 |
20 #include "buddy.h" | 20 #include "buddy.h" |
21 #include "mdns_interface.h" | 21 #include "mdns_interface.h" |
22 #include "dns_sd_proxy.h" | 22 #include "dns_sd_proxy.h" |
23 #include "dnsquery.h" | 23 #include "dnsquery.h" |
24 #include "mdns_common.h" | |
24 | 25 |
25 | 26 |
26 /* data structure for the resolve callback */ | 27 /* data structure for the resolve callback */ |
27 typedef struct _ResolveCallbackArgs { | 28 typedef struct _ResolveCallbackArgs { |
28 DNSServiceRef resolver; | 29 DNSServiceRef resolver; |
29 guint resolver_handler; | 30 guint resolver_handler; |
31 gchar *full_service_name; | |
30 | 32 |
31 PurpleDnsQueryData *query; | 33 PurpleDnsQueryData *query; |
32 | 34 |
33 BonjourBuddy* buddy; | 35 BonjourBuddy* buddy; |
34 } ResolveCallbackArgs; | 36 } ResolveCallbackArgs; |
35 | 37 |
36 /* data used by win32 bonjour implementation */ | 38 /* data used by win32 bonjour implementation */ |
37 typedef struct _win32_session_impl_data { | 39 typedef struct _win32_session_impl_data { |
38 DNSServiceRef advertisement; | 40 DNSServiceRef advertisement_svc; |
39 DNSServiceRef browser; | 41 DNSServiceRef browser_svc; |
42 DNSServiceRef buddy_icon_svc; | |
43 DNSRecordRef buddy_icon_rec; | |
40 | 44 |
41 guint advertisement_handler; /* hack... windows bonjour is broken, so we have to have this */ | 45 guint advertisement_handler; /* hack... windows bonjour is broken, so we have to have this */ |
46 guint browser_handler; | |
47 guint buddy_icon_handler; | |
42 } Win32SessionImplData; | 48 } Win32SessionImplData; |
43 | 49 |
44 typedef struct _win32_buddy_impl_data { | 50 typedef struct _win32_buddy_impl_data { |
45 DNSServiceRef txt_query; | 51 DNSServiceRef txt_query; |
46 guint txt_query_handler; | 52 guint txt_query_handler; |
118 | 124 |
119 buddy->ip = g_strdup(inet_ntoa(addr->sin_addr)); | 125 buddy->ip = g_strdup(inet_ntoa(addr->sin_addr)); |
120 | 126 |
121 /* finally, set up the continuous txt record watcher, and add the buddy to purple */ | 127 /* finally, set up the continuous txt record watcher, and add the buddy to purple */ |
122 | 128 |
123 if (kDNSServiceErr_NoError == DNSServiceQueryRecord(&idata->txt_query, 0, 0, buddy->full_service_name, | 129 if (kDNSServiceErr_NoError == DNSServiceQueryRecord(&idata->txt_query, 0, 0, args->full_service_name, |
124 kDNSServiceType_TXT, kDNSServiceClass_IN, _mdns_text_record_query_callback, buddy)) { | 130 kDNSServiceType_TXT, kDNSServiceClass_IN, _mdns_text_record_query_callback, buddy)) { |
125 int fd = DNSServiceRefSockFD(idata->txt_query); | 131 int fd = DNSServiceRefSockFD(idata->txt_query); |
126 idata->txt_query_handler = purple_input_add(fd, PURPLE_INPUT_READ, _mdns_handle_event, idata->txt_query); | 132 idata->txt_query_handler = purple_input_add(fd, PURPLE_INPUT_READ, _mdns_handle_event, idata->txt_query); |
127 | 133 |
128 bonjour_buddy_add_to_purple(buddy); | 134 bonjour_buddy_add_to_purple(buddy); |
136 /* free the hosts list*/ | 142 /* free the hosts list*/ |
137 g_slist_free(hosts); | 143 g_slist_free(hosts); |
138 | 144 |
139 /* free the remaining args memory */ | 145 /* free the remaining args memory */ |
140 purple_dnsquery_destroy(args->query); | 146 purple_dnsquery_destroy(args->query); |
147 g_free(args->full_service_name); | |
141 g_free(args); | 148 g_free(args); |
142 } | 149 } |
143 | 150 |
144 static void DNSSD_API | 151 static void DNSSD_API |
145 _mdns_service_resolve_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, | 152 _mdns_service_resolve_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, |
163 | 170 |
164 /* parse the text record */ | 171 /* parse the text record */ |
165 _mdns_parse_text_record(args->buddy, txtRecord, txtLen); | 172 _mdns_parse_text_record(args->buddy, txtRecord, txtLen); |
166 | 173 |
167 /* set more arguments, and start the host resolver */ | 174 /* set more arguments, and start the host resolver */ |
168 args->buddy->full_service_name = g_strdup(fullname); | 175 args->full_service_name = g_strdup(fullname); |
169 | 176 |
170 if (!(args->query = | 177 if (!(args->query = |
171 purple_dnsquery_a(hosttarget, port, _mdns_resolve_host_callback, args))) | 178 purple_dnsquery_a(hosttarget, port, _mdns_resolve_host_callback, args))) |
172 { | 179 { |
173 purple_debug_error("bonjour", "service resolver - host resolution failed.\n"); | 180 purple_debug_error("bonjour", "service resolver - host resolution failed.\n"); |
174 bonjour_buddy_delete(args->buddy); | 181 bonjour_buddy_delete(args->buddy); |
182 g_free(args->full_service_name); | |
175 g_free(args); | 183 g_free(args); |
176 } | 184 } |
177 } | 185 } |
178 | 186 |
179 } | 187 } |
180 | 188 |
181 static void DNSSD_API | 189 static void DNSSD_API |
182 _mdns_service_register_callback(DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType errorCode, | 190 _mdns_service_register_callback(DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType errorCode, |
183 const char *name, const char *regtype, const char *domain, void *context) | 191 const char *name, const char *regtype, const char *domain, void *context) { |
184 { | 192 |
185 /* we don't actually care about anything said in this callback - this is only here because Bonjour for windows is broken */ | 193 /* we don't actually care about anything said in this callback - this is only here because Bonjour for windows is broken */ |
194 /* TODO: deal with collision */ | |
186 if (kDNSServiceErr_NoError != errorCode) | 195 if (kDNSServiceErr_NoError != errorCode) |
187 purple_debug_error("bonjour", "service advertisement - callback error.\n"); | 196 purple_debug_error("bonjour", "service advertisement - callback error (%d).\n", errorCode); |
188 else | 197 else |
189 purple_debug_info("bonjour", "service advertisement - callback.\n"); | 198 purple_debug_info("bonjour", "service advertisement - callback.\n"); |
199 } | |
200 | |
201 static void DNSSD_API | |
202 _mdns_set_buddy_icon_cb(DNSServiceRef sdRef, DNSRecordRef RecordRef, DNSServiceFlags flags, DNSServiceErrorType errorCode, | |
203 void *context) { | |
204 if (kDNSServiceErr_NoError != errorCode) | |
205 purple_debug_error("bonjour", "Error (%d) registering buddy icon data.\n", errorCode); | |
206 else { | |
207 purple_debug_info("bonjour", "Registered buddy icon data.\n"); | |
208 bonjour_dns_sd_buddy_icon_data_set((BonjourDnsSd *) context); | |
209 } | |
190 } | 210 } |
191 | 211 |
192 static void DNSSD_API | 212 static void DNSSD_API |
193 _mdns_service_browse_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, | 213 _mdns_service_browse_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, |
194 DNSServiceErrorType errorCode, const char *serviceName, const char *regtype, const char *replyDomain, void *context) | 214 DNSServiceErrorType errorCode, const char *serviceName, const char *regtype, const char *replyDomain, void *context) |
300 /* OK, we're done constructing the text record, (re)publish the service */ | 320 /* OK, we're done constructing the text record, (re)publish the service */ |
301 | 321 |
302 switch (type) { | 322 switch (type) { |
303 case PUBLISH_START: | 323 case PUBLISH_START: |
304 purple_debug_info("bonjour", "Registering service on port %d\n", data->port_p2pj); | 324 purple_debug_info("bonjour", "Registering service on port %d\n", data->port_p2pj); |
305 err = DNSServiceRegister(&idata->advertisement, 0, 0, purple_account_get_username(data->account), ICHAT_SERVICE, | 325 err = DNSServiceRegister(&idata->advertisement_svc, 0, 0, purple_account_get_username(data->account), ICHAT_SERVICE, |
306 NULL, NULL, htons(data->port_p2pj), TXTRecordGetLength(&dns_data), TXTRecordGetBytesPtr(&dns_data), | 326 NULL, NULL, htons(data->port_p2pj), TXTRecordGetLength(&dns_data), TXTRecordGetBytesPtr(&dns_data), |
307 _mdns_service_register_callback, NULL); | 327 _mdns_service_register_callback, NULL); |
308 break; | 328 break; |
309 | 329 |
310 case PUBLISH_UPDATE: | 330 case PUBLISH_UPDATE: |
311 err = DNSServiceUpdateRecord(idata->advertisement, NULL, 0, TXTRecordGetLength(&dns_data), TXTRecordGetBytesPtr(&dns_data), 0); | 331 err = DNSServiceUpdateRecord(idata->advertisement_svc, NULL, 0, TXTRecordGetLength(&dns_data), TXTRecordGetBytesPtr(&dns_data), 0); |
312 break; | 332 break; |
313 } | 333 } |
314 | 334 |
315 if (err != kDNSServiceErr_NoError) { | 335 if (err != kDNSServiceErr_NoError) { |
316 purple_debug_error("bonjour", "Failed to publish presence service.\n"); | 336 purple_debug_error("bonjour", "Failed to publish presence service.\n"); |
317 ret = FALSE; | 337 ret = FALSE; |
318 } else if (type == PUBLISH_START) { | 338 } else if (type == PUBLISH_START) { |
319 /* hack: Bonjour on windows is broken. We don't care about the callback but we have to listen anyway */ | 339 /* hack: Bonjour on windows is broken. We don't care about the callback but we have to listen anyway */ |
320 gint fd = DNSServiceRefSockFD(idata->advertisement); | 340 idata->advertisement_handler = purple_input_add(DNSServiceRefSockFD(idata->advertisement_svc), |
321 idata->advertisement_handler = purple_input_add(fd, PURPLE_INPUT_READ, _mdns_handle_event, idata->advertisement); | 341 PURPLE_INPUT_READ, _mdns_handle_event, idata->advertisement_svc); |
322 } | 342 } |
323 } | 343 } |
324 | 344 |
325 /* Free the memory used by temp data */ | 345 /* Free the memory used by temp data */ |
326 TXTRecordDeallocate(&dns_data); | 346 TXTRecordDeallocate(&dns_data); |
330 gboolean _mdns_browse(BonjourDnsSd *data) { | 350 gboolean _mdns_browse(BonjourDnsSd *data) { |
331 Win32SessionImplData *idata = data->mdns_impl_data; | 351 Win32SessionImplData *idata = data->mdns_impl_data; |
332 | 352 |
333 g_return_val_if_fail(idata != NULL, FALSE); | 353 g_return_val_if_fail(idata != NULL, FALSE); |
334 | 354 |
335 return (DNSServiceBrowse(&idata->browser, 0, 0, ICHAT_SERVICE, NULL, | 355 if (DNSServiceBrowse(&idata->browser_svc, 0, 0, ICHAT_SERVICE, NULL, |
336 _mdns_service_browse_callback, data->account) | 356 _mdns_service_browse_callback, data->account) |
337 == kDNSServiceErr_NoError); | 357 == kDNSServiceErr_NoError) { |
338 } | 358 idata->browser_handler = purple_input_add(DNSServiceRefSockFD(idata->browser_svc), |
339 | 359 PURPLE_INPUT_READ, _mdns_handle_event, idata->browser_svc); |
340 guint _mdns_register_to_mainloop(BonjourDnsSd *data) { | 360 return TRUE; |
341 Win32SessionImplData *idata = data->mdns_impl_data; | 361 } |
342 | 362 |
343 g_return_val_if_fail(idata != NULL, 0); | 363 return FALSE; |
344 | |
345 return purple_input_add(DNSServiceRefSockFD(idata->browser), | |
346 PURPLE_INPUT_READ, _mdns_handle_event, idata->browser); | |
347 } | 364 } |
348 | 365 |
349 void _mdns_stop(BonjourDnsSd *data) { | 366 void _mdns_stop(BonjourDnsSd *data) { |
350 Win32SessionImplData *idata = data->mdns_impl_data; | 367 Win32SessionImplData *idata = data->mdns_impl_data; |
351 | 368 |
352 if (idata == NULL || idata->advertisement == NULL || idata->browser == NULL) | 369 if (idata == NULL) |
353 return; | 370 return; |
354 | 371 |
355 /* hack: for win32, we need to stop listening to the advertisement pipe too */ | 372 if (idata->advertisement_svc != NULL) { |
356 purple_input_remove(idata->advertisement_handler); | 373 /* hack: for win32, we need to stop listening to the advertisement pipe too */ |
357 | 374 purple_input_remove(idata->advertisement_handler); |
358 DNSServiceRefDeallocate(idata->advertisement); | 375 DNSServiceRefDeallocate(idata->advertisement_svc); |
359 DNSServiceRefDeallocate(idata->browser); | 376 } |
377 | |
378 if (idata->browser_svc != NULL) { | |
379 purple_input_remove(idata->browser_handler); | |
380 DNSServiceRefDeallocate(idata->browser_svc); | |
381 } | |
382 | |
383 if (idata->buddy_icon_svc != NULL) { | |
384 purple_input_remove(idata->buddy_icon_handler); | |
385 DNSServiceRefDeallocate(idata->buddy_icon_svc); | |
386 } | |
387 | |
360 | 388 |
361 g_free(idata); | 389 g_free(idata); |
362 | 390 |
363 data->mdns_impl_data = NULL; | 391 data->mdns_impl_data = NULL; |
364 } | 392 } |
393 | |
394 void _mdns_set_buddy_icon_data(BonjourDnsSd *data, gconstpointer avatar_data, gsize avatar_len) { | |
395 Win32SessionImplData *idata = data->mdns_impl_data; | |
396 gboolean new_svc = FALSE; | |
397 DNSServiceErrorType err = kDNSServiceErr_NoError; | |
398 | |
399 g_return_if_fail(idata != NULL); | |
400 | |
401 if (avatar_data != NULL && idata->buddy_icon_svc == NULL) { | |
402 gchar *svc_name = g_strdup_printf("%s." ICHAT_SERVICE "local", purple_account_get_username(data->account)); | |
403 | |
404 purple_debug_info("bonjour", "Setting new buddy icon.\n"); | |
405 | |
406 err = DNSServiceCreateConnection(&idata->buddy_icon_svc); | |
407 if (err == kDNSServiceErr_NoError) { | |
408 err = DNSServiceRegisterRecord(idata->buddy_icon_svc, | |
409 &idata->buddy_icon_rec, kDNSServiceFlagsShared, kDNSServiceInterfaceIndexAny, svc_name, | |
410 kDNSServiceType_NULL, kDNSServiceClass_IN, | |
411 avatar_len, avatar_data, 10, _mdns_set_buddy_icon_cb, data); | |
412 | |
413 if (err != kDNSServiceErr_NoError) { | |
414 DNSServiceRefDeallocate(idata->buddy_icon_svc); | |
415 idata->buddy_icon_svc = NULL; | |
416 } | |
417 } | |
418 | |
419 g_free(svc_name); | |
420 | |
421 if (err == kDNSServiceErr_NoError) | |
422 idata->buddy_icon_handler = purple_input_add(DNSServiceRefSockFD(idata->buddy_icon_svc), | |
423 PURPLE_INPUT_READ, _mdns_handle_event, idata->buddy_icon_svc); | |
424 | |
425 new_svc = TRUE; | |
426 } else if (avatar_data != NULL) { | |
427 purple_debug_info("bonjour", "Updating existing buddy icon.\n"); | |
428 err = DNSServiceUpdateRecord(idata->buddy_icon_svc, idata->buddy_icon_rec, | |
429 0, avatar_len, avatar_data, 10); | |
430 } else if (idata->buddy_icon_svc != NULL) { | |
431 purple_debug_info("bonjour", "Removing existing buddy icon.\n"); | |
432 /* Must be removing the buddy icon */ | |
433 purple_input_remove(idata->buddy_icon_handler); | |
434 idata->buddy_icon_handler = 0; | |
435 DNSServiceRefDeallocate(idata->buddy_icon_svc); | |
436 idata->buddy_icon_svc = NULL; | |
437 idata->buddy_icon_rec = NULL; | |
438 } | |
439 | |
440 if (err != kDNSServiceErr_NoError) | |
441 purple_debug_error("bonjour", "Error (%d) setting buddy icon record.\n", err); | |
442 } | |
443 | |
365 | 444 |
366 void _mdns_init_buddy(BonjourBuddy *buddy) { | 445 void _mdns_init_buddy(BonjourBuddy *buddy) { |
367 buddy->mdns_impl_data = g_new0(Win32BuddyImplData, 1); | 446 buddy->mdns_impl_data = g_new0(Win32BuddyImplData, 1); |
368 } | 447 } |
369 | 448 |
387 buddy->mdns_impl_data = NULL; | 466 buddy->mdns_impl_data = NULL; |
388 } | 467 } |
389 | 468 |
390 void bonjour_dns_sd_retrieve_buddy_icon(BonjourBuddy* buddy) { | 469 void bonjour_dns_sd_retrieve_buddy_icon(BonjourBuddy* buddy) { |
391 Win32BuddyImplData *idata = buddy->mdns_impl_data; | 470 Win32BuddyImplData *idata = buddy->mdns_impl_data; |
471 gchar *svc_name; | |
392 | 472 |
393 g_return_if_fail(idata != NULL); | 473 g_return_if_fail(idata != NULL); |
394 | 474 |
395 /* Cancel any existing query */ | 475 /* Cancel any existing query */ |
396 if (idata->null_query != NULL) { | 476 if (idata->null_query != NULL) { |
398 idata->null_query_handler = 0; | 478 idata->null_query_handler = 0; |
399 DNSServiceRefDeallocate(idata->null_query); | 479 DNSServiceRefDeallocate(idata->null_query); |
400 idata->null_query = NULL; | 480 idata->null_query = NULL; |
401 } | 481 } |
402 | 482 |
403 if (kDNSServiceErr_NoError == DNSServiceQueryRecord(&idata->null_query, 0, 0, buddy->full_service_name, | 483 svc_name = g_strdup_printf("%s." ICHAT_SERVICE "local", buddy->name); |
484 if (kDNSServiceErr_NoError == DNSServiceQueryRecord(&idata->null_query, 0, 0, svc_name, | |
404 kDNSServiceType_NULL, kDNSServiceClass_IN, _mdns_text_record_query_callback, buddy)) { | 485 kDNSServiceType_NULL, kDNSServiceClass_IN, _mdns_text_record_query_callback, buddy)) { |
405 int fd = DNSServiceRefSockFD(idata->null_query); | 486 idata->null_query_handler = purple_input_add(DNSServiceRefSockFD(idata->null_query), |
406 idata->null_query_handler = purple_input_add(fd, PURPLE_INPUT_READ, _mdns_handle_event, idata->null_query); | 487 PURPLE_INPUT_READ, _mdns_handle_event, idata->null_query); |
407 } | 488 } |
408 | 489 g_free(svc_name); |
409 } | 490 |
410 | 491 } |
492 |