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