comparison libpurple/protocols/bonjour/mdns_win32.c @ 31017:014a58e994da

Use DNSServiceGetAddrInfo() from dns_sd.h to resolve the IP for remote bonjour users on Win32 instead of the libpurple resolving API. This way, we make sure we're using the same interface as we received the presence notification on. There is also some debug message improvement and using constants instead of magic numbers in this commit.
author Daniel Atallah <daniel.atallah@gmail.com>
date Mon, 04 Oct 2010 00:35:26 +0000
parents 927e01ad06ae
children 9c8b28dc6656
comparison
equal deleted inserted replaced
31016:cc05402eb2ba 31017:014a58e994da
23 #include "debug.h" 23 #include "debug.h"
24 24
25 #include "buddy.h" 25 #include "buddy.h"
26 #include "mdns_interface.h" 26 #include "mdns_interface.h"
27 #include "dns_sd_proxy.h" 27 #include "dns_sd_proxy.h"
28 #include "dnsquery.h"
29 #include "mdns_common.h" 28 #include "mdns_common.h"
30 29
31 static GSList *pending_buddies = NULL; 30 static GSList *pending_buddies = NULL;
32 31
33 typedef struct _dnssd_service_ref_handler { 32 typedef struct _dnssd_service_ref_handler {
63 DnsSDServiceRefHandlerData *resolver_query; 62 DnsSDServiceRefHandlerData *resolver_query;
64 PurpleAccount *account; 63 PurpleAccount *account;
65 BonjourBuddy *bb; 64 BonjourBuddy *bb;
66 Win32SvcResolverData *res_data; 65 Win32SvcResolverData *res_data;
67 gchar *full_service_name; 66 gchar *full_service_name;
68 PurpleDnsQueryData *dns_query;
69 } ResolveCallbackArgs; 67 } ResolveCallbackArgs;
70 68
71 69
72 static gint 70 static gint
73 _find_resolver_data(gconstpointer a, gconstpointer b) { 71 _find_resolver_data(gconstpointer a, gconstpointer b) {
133 uint16_t rrtype, uint16_t rrclass, uint16_t rdlen, const void *rdata, 131 uint16_t rrtype, uint16_t rrclass, uint16_t rdlen, const void *rdata,
134 uint32_t ttl, void *context) 132 uint32_t ttl, void *context)
135 { 133 {
136 134
137 if (errorCode != kDNSServiceErr_NoError) { 135 if (errorCode != kDNSServiceErr_NoError) {
138 purple_debug_error("bonjour", "record query - callback error.\n"); 136 purple_debug_error("bonjour", "record query - callback error (%d).\n", errorCode);
139 /* TODO: Probably should remove the buddy when this happens */ 137 /* TODO: Probably should remove the buddy when this happens */
140 } else if (flags & kDNSServiceFlagsAdd) { 138 } else if (flags & kDNSServiceFlagsAdd) {
141 if (rrtype == kDNSServiceType_TXT) { 139 if (rrtype == kDNSServiceType_TXT) {
142 /* New Buddy */ 140 /* New Buddy */
143 BonjourBuddy *bb = (BonjourBuddy*) context; 141 BonjourBuddy *bb = (BonjourBuddy*) context;
159 idata->null_query = NULL; 157 idata->null_query = NULL;
160 } 158 }
161 } 159 }
162 } 160 }
163 161
164 static void 162 static void DNSSD_API
165 _mdns_resolve_host_callback(GSList *hosts, gpointer data, const char *error_message) 163 _mdns_resolve_host_callback(DNSServiceRef sdRef, DNSServiceFlags flags,
164 uint32_t interfaceIndex, DNSServiceErrorType errorCode,
165 const char *hostname, const struct sockaddr *address,
166 uint32_t ttl, void *context)
166 { 167 {
167 ResolveCallbackArgs *args = (ResolveCallbackArgs*) data; 168 ResolveCallbackArgs *args = (ResolveCallbackArgs*) context;
168 Win32BuddyImplData *idata = args->bb->mdns_impl_data; 169 Win32BuddyImplData *idata = args->bb->mdns_impl_data;
169 gboolean delete_buddy = FALSE; 170 gboolean delete_buddy = FALSE;
170 PurpleBuddy *pb = NULL; 171 PurpleBuddy *pb = NULL;
172
173 purple_input_remove(args->resolver_query->input_handler);
174 DNSServiceRefDeallocate(args->resolver_query->sdRef);
175 g_free(args->resolver_query);
176 args->resolver_query = NULL;
171 177
172 if ((pb = purple_find_buddy(args->account, args->res_data->name))) { 178 if ((pb = purple_find_buddy(args->account, args->res_data->name))) {
173 if (pb->proto_data != args->bb) { 179 if (pb->proto_data != args->bb) {
174 purple_debug_error("bonjour", "Found purple buddy for %s not matching bonjour buddy record.", 180 purple_debug_error("bonjour", "Found purple buddy for %s not matching bonjour buddy record.",
175 args->res_data->name); 181 args->res_data->name);
179 } else if (g_slist_find(pending_buddies, args->bb) == NULL) { 185 } else if (g_slist_find(pending_buddies, args->bb) == NULL) {
180 purple_debug_error("bonjour", "host resolution - complete, but buddy no longer pending.\n"); 186 purple_debug_error("bonjour", "host resolution - complete, but buddy no longer pending.\n");
181 goto cleanup; 187 goto cleanup;
182 } 188 }
183 189
184 if (!hosts || !hosts->data) { 190 if (errorCode != kDNSServiceErr_NoError) {
185 purple_debug_error("bonjour", "host resolution - callback error.\n"); 191 purple_debug_error("bonjour", "host resolution - callback error (%d).\n", errorCode);
186 delete_buddy = TRUE; 192 delete_buddy = TRUE;
187 } else { 193 } else {
188 struct sockaddr_in *addr = g_slist_nth_data(hosts, 1);
189 DNSServiceErrorType errorCode;
190 DNSServiceRef txt_query_sr; 194 DNSServiceRef txt_query_sr;
191 195
192 /* finally, set up the continuous txt record watcher, and add the buddy to purple */ 196 /* finally, set up the continuous txt record watcher, and add the buddy to purple */
193 errorCode = DNSServiceQueryRecord(&txt_query_sr, kDNSServiceFlagsLongLivedQuery, 197 errorCode = DNSServiceQueryRecord(&txt_query_sr, kDNSServiceFlagsLongLivedQuery,
194 kDNSServiceInterfaceIndexAny, args->full_service_name, kDNSServiceType_TXT, 198 kDNSServiceInterfaceIndexAny, args->full_service_name, kDNSServiceType_TXT,
195 kDNSServiceClass_IN, _mdns_record_query_callback, args->bb); 199 kDNSServiceClass_IN, _mdns_record_query_callback, args->bb);
196 if (errorCode == kDNSServiceErr_NoError) { 200 if (errorCode == kDNSServiceErr_NoError) {
197 const char *ip = inet_ntoa(addr->sin_addr); 201 const char *ip = inet_ntoa(((struct sockaddr_in *) address)->sin_addr);
198 202
199 purple_debug_info("bonjour", "Found buddy %s at %s:%d\n", args->bb->name, ip, args->bb->port_p2pj); 203 purple_debug_info("bonjour", "Found buddy %s at %s:%d\n", args->bb->name, ip, args->bb->port_p2pj);
200 204
201 args->bb->ips = g_slist_prepend(args->bb->ips, g_strdup(ip)); 205 args->bb->ips = g_slist_prepend(args->bb->ips, g_strdup(ip));
202 args->res_data->ip = args->bb->ips->data; 206 args->res_data->ip = args->bb->ips->data;
215 } 219 }
216 220
217 } 221 }
218 222
219 cleanup: 223 cleanup:
220
221 /* free the hosts list*/
222 while (hosts != NULL) {
223 hosts = g_slist_remove(hosts, hosts->data);
224 g_free(hosts->data);
225 hosts = g_slist_remove(hosts, hosts->data);
226 }
227 224
228 if (delete_buddy) { 225 if (delete_buddy) {
229 idata->resolvers = g_slist_remove(idata->resolvers, args->res_data); 226 idata->resolvers = g_slist_remove(idata->resolvers, args->res_data);
230 _cleanup_resolver_data(args->res_data); 227 _cleanup_resolver_data(args->res_data);
231 228
257 Win32BuddyImplData *idata = args->bb->mdns_impl_data; 254 Win32BuddyImplData *idata = args->bb->mdns_impl_data;
258 255
259 /* remove the input fd and destroy the service ref */ 256 /* remove the input fd and destroy the service ref */
260 purple_input_remove(args->resolver_query->input_handler); 257 purple_input_remove(args->resolver_query->input_handler);
261 DNSServiceRefDeallocate(args->resolver_query->sdRef); 258 DNSServiceRefDeallocate(args->resolver_query->sdRef);
259
260 if (errorCode != kDNSServiceErr_NoError)
261 purple_debug_error("bonjour", "service resolver - callback error. (%d)\n", errorCode);
262 else {
263 DNSServiceRef getaddrinfo_sr;
264 /* set more arguments, and start the host resolver */
265 errorCode = DNSServiceGetAddrInfo(&getaddrinfo_sr, 0, interfaceIndex,
266 kDNSServiceProtocol_IPv4, hosttarget, _mdns_resolve_host_callback, args);
267 if (errorCode != kDNSServiceErr_NoError)
268 purple_debug_error("bonjour", "service resolver - host resolution failed.\n");
269 else {
270 args->resolver_query->sdRef = getaddrinfo_sr;
271 args->resolver_query->input_handler = purple_input_add(DNSServiceRefSockFD(getaddrinfo_sr),
272 PURPLE_INPUT_READ, _mdns_handle_event, args->resolver_query);
273 args->full_service_name = g_strdup(fullname);
274
275 /* TODO: Should this be per resolver? */
276 args->bb->port_p2pj = ntohs(port);
277
278 /* We don't want to hit the cleanup code */
279 return;
280 }
281 }
282
283 /* If we get this far, clean up */
284
262 g_free(args->resolver_query); 285 g_free(args->resolver_query);
263 args->resolver_query = NULL; 286 args->resolver_query = NULL;
264
265 if (errorCode != kDNSServiceErr_NoError)
266 purple_debug_error("bonjour", "service resolver - callback error.\n");
267 else {
268 /* set more arguments, and start the host resolver */
269
270 if ((args->dns_query =
271 purple_dnsquery_a(hosttarget, port, _mdns_resolve_host_callback, args)) != NULL) {
272
273 args->full_service_name = g_strdup(fullname);
274
275 /* TODO: Should this be per resolver? */
276 args->bb->port_p2pj = ntohs(port);
277
278 /* We don't want to hit the cleanup code */
279 return;
280 } else
281 purple_debug_error("bonjour", "service resolver - host resolution failed.\n");
282 }
283
284 /* If we get this far, clean up */
285 287
286 idata->resolvers = g_slist_remove(idata->resolvers, args->res_data); 288 idata->resolvers = g_slist_remove(idata->resolvers, args->res_data);
287 _cleanup_resolver_data(args->res_data); 289 _cleanup_resolver_data(args->res_data);
288 290
289 /* If this was the last resolver, remove the buddy */ 291 /* If this was the last resolver, remove the buddy */
332 334
333 purple_debug_info("bonjour", "Received new record for '%s' on iface %u (%s, %s)\n", 335 purple_debug_info("bonjour", "Received new record for '%s' on iface %u (%s, %s)\n",
334 serviceName, interfaceIndex, regtype ? regtype : "", 336 serviceName, interfaceIndex, regtype ? regtype : "",
335 replyDomain ? replyDomain : ""); 337 replyDomain ? replyDomain : "");
336 338
337 resErrorCode = DNSServiceResolve(&resolver_sr, 0, 0, serviceName, regtype, 339 resErrorCode = DNSServiceResolve(&resolver_sr, 0, interfaceIndex, serviceName, regtype,
338 replyDomain, _mdns_service_resolve_callback, args); 340 replyDomain, _mdns_service_resolve_callback, args);
339 if (resErrorCode == kDNSServiceErr_NoError) { 341 if (resErrorCode == kDNSServiceErr_NoError) {
340 GSList *tmp = pending_buddies; 342 GSList *tmp = pending_buddies;
341 PurpleBuddy *pb; 343 PurpleBuddy *pb;
342 BonjourBuddy* bb = NULL; 344 BonjourBuddy* bb = NULL;
481 DNSServiceRef presence_sr; 483 DNSServiceRef presence_sr;
482 484
483 switch (type) { 485 switch (type) {
484 case PUBLISH_START: 486 case PUBLISH_START:
485 purple_debug_info("bonjour", "Registering presence on port %d\n", data->port_p2pj); 487 purple_debug_info("bonjour", "Registering presence on port %d\n", data->port_p2pj);
486 errorCode = DNSServiceRegister(&presence_sr, 0, 0, purple_account_get_username(data->account), LINK_LOCAL_RECORD_NAME, 488 errorCode = DNSServiceRegister(&presence_sr, kDNSServiceInterfaceIndexAny,
489 0, purple_account_get_username(data->account), LINK_LOCAL_RECORD_NAME,
487 NULL, NULL, htons(data->port_p2pj), TXTRecordGetLength(&dns_data), TXTRecordGetBytesPtr(&dns_data), 490 NULL, NULL, htons(data->port_p2pj), TXTRecordGetLength(&dns_data), TXTRecordGetBytesPtr(&dns_data),
488 _mdns_service_register_callback, NULL); 491 _mdns_service_register_callback, NULL);
489 break; 492 break;
490 493
491 case PUBLISH_UPDATE: 494 case PUBLISH_UPDATE:
520 Win32SessionImplData *idata = data->mdns_impl_data; 523 Win32SessionImplData *idata = data->mdns_impl_data;
521 DNSServiceRef browser_sr; 524 DNSServiceRef browser_sr;
522 525
523 g_return_val_if_fail(idata != NULL, FALSE); 526 g_return_val_if_fail(idata != NULL, FALSE);
524 527
525 errorCode = DNSServiceBrowse(&browser_sr, 0, 0, LINK_LOCAL_RECORD_NAME, NULL, 528 errorCode = DNSServiceBrowse(&browser_sr, 0, kDNSServiceInterfaceIndexAny,
526 _mdns_service_browse_callback, data->account); 529 LINK_LOCAL_RECORD_NAME, NULL,_mdns_service_browse_callback,
530 data->account);
527 if (errorCode == kDNSServiceErr_NoError) { 531 if (errorCode == kDNSServiceErr_NoError) {
528 idata->browser_query = g_new(DnsSDServiceRefHandlerData, 1); 532 idata->browser_query = g_new(DnsSDServiceRefHandlerData, 1);
529 idata->browser_query->sdRef = browser_sr; 533 idata->browser_query->sdRef = browser_sr;
530 idata->browser_query->account = data->account; 534 idata->browser_query->account = data->account;
531 idata->browser_query->input_handler = purple_input_add(DNSServiceRefSockFD(browser_sr), 535 idata->browser_query->input_handler = purple_input_add(DNSServiceRefSockFD(browser_sr),