OBS: updates for Ubuntu 16.04
[siplcs.git] / src / purple / purple-dnsquery.c
blobf578fcbb63c971d37efc035b626a3d74d8dbf222
1 /**
2 * @file purple-dnsquery.c
4 * pidgin-sipe
6 * Copyright (C) 2010-2016 SIPE Project <http://sipe.sourceforge.net/>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include <glib.h>
25 #include "version.h"
27 #if PURPLE_VERSION_CHECK(3,0,0)
28 #include "protocols.h"
29 #include <gio/gio.h>
30 #else
32 #ifdef _WIN32
33 /* wrappers for write() & friends for socket handling */
34 #include "win32/win32dep.h"
35 #include <ws2tcpip.h>
36 #else
37 #include <sys/types.h>
38 #include <sys/socket.h>
39 #include <netinet/in.h>
40 #include <arpa/inet.h>
41 #endif
43 #include "dnsquery.h"
44 #include "dnssrv.h"
46 #endif
48 #include "sipe-common.h"
49 #include "sipe-backend.h"
50 #include "sipe-core.h"
52 #include "purple-private.h"
54 struct sipe_dns_query {
55 struct sipe_backend_private *purple_private;
56 sipe_dns_resolved_cb callback;
57 gpointer extradata;
58 gpointer purple_query_data;
59 gboolean is_valid;
60 #if PURPLE_VERSION_CHECK(3,0,0)
61 guint port;
62 #else
63 enum {
65 SRV
66 } type;
67 #endif
70 static void sipe_dns_query_free(struct sipe_dns_query *query)
72 #if PURPLE_VERSION_CHECK(3,0,0)
73 g_object_unref(query->purple_query_data);
74 #endif
75 g_free(query);
78 #if PURPLE_VERSION_CHECK(3,0,0)
79 static void dns_a_response(GObject *source,
80 GAsyncResult *res,
81 gpointer user_data)
83 struct sipe_dns_query *query = user_data;
84 GList *hosts;
85 GError *error = NULL;
86 gchar *address_str = NULL;
88 if (!query->is_valid) {
89 /* Ignore spurious responses after disconnect */
90 return;
93 query->purple_private->dns_queries =
94 g_slist_remove(query->purple_private->dns_queries,
95 query);
97 hosts = g_resolver_lookup_by_name_finish(G_RESOLVER(source), res,
98 &error);
100 if (!error && g_list_length(hosts) > 0) {
101 address_str = g_inet_address_to_string(hosts->data);
104 query->callback(query->extradata, address_str,
105 address_str ? query->port : 0);
107 g_free(address_str);
108 g_error_free(error);
109 g_resolver_free_addresses(hosts);
110 sipe_dns_query_free(query);
112 #else
113 static void dns_a_response(GSList *hosts,
114 struct sipe_dns_query *query,
115 const char *error_message)
117 char ipstr[INET6_ADDRSTRLEN];
118 struct sockaddr *addr;
119 const void *addrdata;
120 int port;
122 /* Ignore spurious responses after disconnect */
123 if (query->is_valid) {
124 struct sipe_backend_private *purple_private = query->purple_private;
126 purple_private->dns_queries = g_slist_remove(purple_private->dns_queries,
127 query);
129 if (error_message || !g_slist_next(hosts)) {
130 query->callback(query->extradata, NULL, 0);
131 g_slist_free(hosts);
132 return;
135 addr = g_slist_next(hosts)->data;
136 if (addr->sa_family == AF_INET6) {
137 /* OS provides addr so it must be properly aligned */
138 struct sockaddr_in6 *sin6 = (void *) addr;
139 addrdata = &sin6->sin6_addr;
140 port = sin6->sin6_port;
141 } else {
142 /* OS provides addr so it must be properly aligned */
143 struct sockaddr_in *sin = (void *) addr;
144 addrdata = &sin->sin_addr;
145 port = sin->sin_port;
148 inet_ntop(addr->sa_family, addrdata, ipstr, sizeof (ipstr));
150 query->callback(query->extradata, ipstr, port);
152 g_free(query);
155 for (; hosts; hosts = g_slist_delete_link(hosts, hosts)) {
156 // Free the addrlen, no data in this link
157 hosts = g_slist_delete_link(hosts, hosts);
158 // Free the address
159 g_free(hosts->data);
162 #endif
164 struct sipe_dns_query *sipe_backend_dns_query_a(struct sipe_core_public *sipe_public,
165 const gchar *hostname,
166 guint port,
167 sipe_dns_resolved_cb callback,
168 gpointer data)
170 struct sipe_dns_query *query = g_new(struct sipe_dns_query, 1);
171 struct sipe_backend_private *purple_private = sipe_public->backend_private;
172 #if PURPLE_VERSION_CHECK(3,0,0)
173 GResolver *resolver = g_resolver_get_default();
174 #endif
176 query->purple_private = purple_private;
177 query->callback = callback;
178 query->extradata = data;
179 query->is_valid = TRUE;
181 purple_private->dns_queries = g_slist_prepend(purple_private->dns_queries,
182 query);
184 #if PURPLE_VERSION_CHECK(3,0,0)
185 query->port = port;
186 query->purple_query_data = g_cancellable_new();
188 g_resolver_lookup_by_name_async(resolver,
189 hostname,
190 query->purple_query_data,
191 dns_a_response,
192 query);
193 g_object_unref(resolver);
194 #else
195 query->type = A;
196 query->purple_query_data =
197 #if PURPLE_VERSION_CHECK(2,8,0)
198 purple_dnsquery_a_account(
199 purple_private->account,
200 #else
201 purple_dnsquery_a(
202 #endif
203 hostname,
204 port,
205 (PurpleDnsQueryConnectFunction) dns_a_response,
206 query);
207 #endif
209 return query;
212 #if PURPLE_VERSION_CHECK(3,0,0)
213 static void dns_srv_response(GObject *source,
214 GAsyncResult *res,
215 gpointer user_data)
217 struct sipe_dns_query *query = user_data;
218 GError *error = NULL;
219 GList *targets;
221 if (!query->is_valid) {
222 /* Ignore spurious responses after disconnect */
223 return;
226 query->purple_private->dns_queries =
227 g_slist_remove(query->purple_private->dns_queries,
228 query);
230 targets = g_resolver_lookup_service_finish(G_RESOLVER(source), res,
231 &error);
233 if (error || g_list_length(targets) == 0) {
234 query->callback(query->extradata, NULL, 0);
235 } else {
236 query->callback(query->extradata,
237 g_srv_target_get_hostname(targets->data),
238 g_srv_target_get_port(targets->data));
241 g_error_free(error);
242 g_resolver_free_targets(targets);
243 sipe_dns_query_free(query);
245 #else
246 static void dns_srv_response(PurpleSrvResponse *resp,
247 int results,
248 struct sipe_dns_query *query)
250 /* Ignore spurious responses after disconnect */
251 if (query->is_valid) {
252 struct sipe_backend_private *purple_private = query->purple_private;
254 purple_private->dns_queries = g_slist_remove(purple_private->dns_queries,
255 query);
257 if (results)
258 query->callback(query->extradata, resp->hostname, resp->port);
259 else
260 query->callback(query->extradata, NULL, 0);
262 g_free(query);
265 g_free(resp);
267 #endif
269 struct sipe_dns_query *sipe_backend_dns_query_srv(struct sipe_core_public *sipe_public,
270 const gchar *protocol,
271 const gchar *transport,
272 const gchar *domain,
273 sipe_dns_resolved_cb callback,
274 gpointer data)
276 struct sipe_dns_query *query = g_new(struct sipe_dns_query, 1);
277 struct sipe_backend_private *purple_private = sipe_public->backend_private;
278 #if PURPLE_VERSION_CHECK(3,0,0)
279 GResolver *resolver = g_resolver_get_default();
280 #endif
282 query->purple_private = purple_private;
283 query->callback = callback;
284 query->extradata = data;
285 query->is_valid = TRUE;
287 purple_private->dns_queries = g_slist_prepend(purple_private->dns_queries,
288 query);
290 #if PURPLE_VERSION_CHECK(3,0,0)
291 query->purple_query_data = g_cancellable_new();
293 g_resolver_lookup_service_async(resolver,
294 protocol,
295 transport,
296 domain,
297 query->purple_query_data,
298 dns_srv_response,
299 query);
300 g_object_unref(resolver);
301 #else
302 query->type = SRV;
303 query->purple_query_data =
304 #if PURPLE_VERSION_CHECK(2,8,0)
305 purple_srv_resolve_account(
306 purple_private->account,
307 #else
308 purple_srv_resolve(
309 #endif
310 protocol,
311 transport,
312 domain,
313 (PurpleSrvCallback) dns_srv_response,
314 query);
315 #endif
317 return query;
320 static gboolean dns_query_deferred_destroy(gpointer user_data)
323 * All pending events on query have been processed.
324 * Now it is safe to destroy the data structure.
326 SIPE_DEBUG_INFO("dns_query_deferred_destroy: %p", user_data);
327 sipe_dns_query_free(user_data);
328 return(FALSE);
331 void sipe_backend_dns_query_cancel(struct sipe_dns_query *query)
333 SIPE_DEBUG_INFO("sipe_backend_dns_query_cancel: %p", query);
335 if (query->is_valid) {
336 struct sipe_backend_private *purple_private = query->purple_private;
337 purple_private->dns_queries = g_slist_remove(purple_private->dns_queries,
338 query);
340 #if PURPLE_VERSION_CHECK(3,0,0)
341 g_cancellable_cancel(query->purple_query_data);
342 #else
343 switch (query->type) {
344 case A:
345 purple_dnsquery_destroy(query->purple_query_data);
346 break;
347 case SRV:
348 #if PURPLE_VERSION_CHECK(2,8,0)
349 purple_srv_txt_query_destroy(query->purple_query_data);
350 #else
351 purple_srv_cancel(query->purple_query_data);
352 #endif
353 break;
355 #endif
357 /* defer deletion of query data structure to idle callback */
358 query->is_valid = FALSE;
359 g_idle_add(dns_query_deferred_destroy, query);
363 void sipe_purple_dns_query_cancel_all(struct sipe_backend_private *purple_private)
365 GSList *entry;
366 SIPE_DEBUG_INFO_NOFORMAT("sipe_purple_dns_query_cancel_all: entered");
367 while ((entry = purple_private->dns_queries) != NULL)
368 sipe_backend_dns_query_cancel(entry->data);
373 Local Variables:
374 mode: c
375 c-file-style: "bsd"
376 indent-tabs-mode: t
377 tab-width: 8
378 End: