Release 1.25.0 -- Buddy Idle Time, RTF
[siplcs.git] / src / purple / purple-dnsquery.c
blobeab40e41f2b1723b84645192c27653fb327f17c4
1 /**
2 * @file purple-dnsquery.c
4 * pidgin-sipe
6 * Copyright (C) 2010-2019 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 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
27 #include <glib.h>
29 #include "version.h"
31 #if PURPLE_VERSION_CHECK(2,8,0)
32 #include "account.h"
33 #endif
34 #if PURPLE_VERSION_CHECK(3,0,0)
35 #include "protocols.h"
36 #include <gio/gio.h>
37 #else
39 #ifdef _WIN32
40 /* wrappers for write() & friends for socket handling */
41 #include "win32/win32dep.h"
42 #include <ws2tcpip.h>
43 #else
44 #include <sys/types.h>
45 #include <sys/socket.h>
46 #include <netinet/in.h>
47 #include <arpa/inet.h>
48 #endif
50 #include "dnsquery.h"
51 #include "dnssrv.h"
53 #endif
55 #include "sipe-backend.h"
56 #include "sipe-core.h"
58 #include "purple-private.h"
60 struct sipe_dns_query {
61 struct sipe_backend_private *purple_private;
62 sipe_dns_resolved_cb callback;
63 gpointer extradata;
64 gpointer purple_query_data;
65 gboolean is_valid;
66 #if PURPLE_VERSION_CHECK(3,0,0)
67 guint port;
68 #else
69 enum {
71 SRV
72 } type;
73 #endif
76 static void sipe_dns_query_free(struct sipe_dns_query *query)
78 #if PURPLE_VERSION_CHECK(3,0,0)
79 g_object_unref(query->purple_query_data);
80 #endif
81 g_free(query);
84 #if PURPLE_VERSION_CHECK(3,0,0)
85 static void dns_a_response(GObject *source,
86 GAsyncResult *res,
87 gpointer user_data)
89 struct sipe_dns_query *query = user_data;
90 GList *hosts;
91 GError *error = NULL;
92 gchar *address_str = NULL;
94 if (!query->is_valid) {
95 /* Ignore spurious responses after disconnect */
96 return;
99 query->purple_private->dns_queries =
100 g_slist_remove(query->purple_private->dns_queries,
101 query);
103 hosts = g_resolver_lookup_by_name_finish(G_RESOLVER(source), res,
104 &error);
106 if (!error && g_list_length(hosts) > 0) {
107 address_str = g_inet_address_to_string(hosts->data);
110 query->callback(query->extradata, address_str,
111 address_str ? query->port : 0);
113 g_free(address_str);
114 if (error)
115 g_error_free(error);
116 g_resolver_free_addresses(hosts);
117 sipe_dns_query_free(query);
119 #else
120 static void dns_a_response(GSList *hosts,
121 struct sipe_dns_query *query,
122 const char *error_message)
124 char ipstr[INET6_ADDRSTRLEN];
125 struct sockaddr *addr;
126 const void *addrdata;
127 int port;
129 /* Ignore spurious responses after disconnect */
130 if (query->is_valid) {
131 struct sipe_backend_private *purple_private = query->purple_private;
133 purple_private->dns_queries = g_slist_remove(purple_private->dns_queries,
134 query);
136 if (error_message || !g_slist_next(hosts)) {
137 query->callback(query->extradata, NULL, 0);
138 g_slist_free(hosts);
139 return;
142 addr = g_slist_next(hosts)->data;
143 if (addr->sa_family == AF_INET6) {
144 /* OS provides addr so it must be properly aligned */
145 struct sockaddr_in6 *sin6 = (void *) addr;
146 addrdata = &sin6->sin6_addr;
147 port = sin6->sin6_port;
148 } else {
149 /* OS provides addr so it must be properly aligned */
150 struct sockaddr_in *sin = (void *) addr;
151 addrdata = &sin->sin_addr;
152 port = sin->sin_port;
155 inet_ntop(addr->sa_family, addrdata, ipstr, sizeof (ipstr));
157 query->callback(query->extradata, ipstr, port);
159 g_free(query);
162 for (; hosts; hosts = g_slist_delete_link(hosts, hosts)) {
163 // Free the addrlen, no data in this link
164 hosts = g_slist_delete_link(hosts, hosts);
165 // Free the address
166 g_free(hosts->data);
169 #endif
171 struct sipe_dns_query *sipe_backend_dns_query_a(struct sipe_core_public *sipe_public,
172 const gchar *hostname,
173 guint port,
174 sipe_dns_resolved_cb callback,
175 gpointer data)
177 struct sipe_dns_query *query = g_new(struct sipe_dns_query, 1);
178 struct sipe_backend_private *purple_private = sipe_public->backend_private;
179 #if PURPLE_VERSION_CHECK(3,0,0)
180 GResolver *resolver = g_resolver_get_default();
181 #endif
183 query->purple_private = purple_private;
184 query->callback = callback;
185 query->extradata = data;
186 query->is_valid = TRUE;
188 purple_private->dns_queries = g_slist_prepend(purple_private->dns_queries,
189 query);
191 #if PURPLE_VERSION_CHECK(3,0,0)
192 query->port = port;
193 query->purple_query_data = g_cancellable_new();
195 g_resolver_lookup_by_name_async(resolver,
196 hostname,
197 query->purple_query_data,
198 dns_a_response,
199 query);
200 g_object_unref(resolver);
201 #else
202 query->type = A;
203 query->purple_query_data =
204 #if PURPLE_VERSION_CHECK(2,8,0)
205 purple_dnsquery_a_account(
206 purple_private->account,
207 #else
208 purple_dnsquery_a(
209 #endif
210 hostname,
211 port,
212 (PurpleDnsQueryConnectFunction) dns_a_response,
213 query);
214 #endif
216 return query;
219 #if PURPLE_VERSION_CHECK(3,0,0)
220 static void dns_srv_response(GObject *source,
221 GAsyncResult *res,
222 gpointer user_data)
224 struct sipe_dns_query *query = user_data;
225 GError *error = NULL;
226 GList *targets;
228 if (!query->is_valid) {
229 /* Ignore spurious responses after disconnect */
230 return;
233 query->purple_private->dns_queries =
234 g_slist_remove(query->purple_private->dns_queries,
235 query);
237 targets = g_resolver_lookup_service_finish(G_RESOLVER(source), res,
238 &error);
240 if (error || g_list_length(targets) == 0) {
241 query->callback(query->extradata, NULL, 0);
242 } else {
243 query->callback(query->extradata,
244 g_srv_target_get_hostname(targets->data),
245 g_srv_target_get_port(targets->data));
248 if (error)
249 g_error_free(error);
250 g_resolver_free_targets(targets);
251 sipe_dns_query_free(query);
253 #else
254 static void dns_srv_response(PurpleSrvResponse *resp,
255 int results,
256 struct sipe_dns_query *query)
258 /* Ignore spurious responses after disconnect */
259 if (query->is_valid) {
260 struct sipe_backend_private *purple_private = query->purple_private;
262 purple_private->dns_queries = g_slist_remove(purple_private->dns_queries,
263 query);
265 if (results)
266 query->callback(query->extradata, resp->hostname, resp->port);
267 else
268 query->callback(query->extradata, NULL, 0);
270 g_free(query);
273 g_free(resp);
275 #endif
277 struct sipe_dns_query *sipe_backend_dns_query_srv(struct sipe_core_public *sipe_public,
278 const gchar *protocol,
279 const gchar *transport,
280 const gchar *domain,
281 sipe_dns_resolved_cb callback,
282 gpointer data)
284 struct sipe_dns_query *query = g_new(struct sipe_dns_query, 1);
285 struct sipe_backend_private *purple_private = sipe_public->backend_private;
286 #if PURPLE_VERSION_CHECK(3,0,0)
287 GResolver *resolver = g_resolver_get_default();
288 #endif
290 query->purple_private = purple_private;
291 query->callback = callback;
292 query->extradata = data;
293 query->is_valid = TRUE;
295 purple_private->dns_queries = g_slist_prepend(purple_private->dns_queries,
296 query);
298 #if PURPLE_VERSION_CHECK(3,0,0)
299 query->purple_query_data = g_cancellable_new();
301 g_resolver_lookup_service_async(resolver,
302 protocol,
303 transport,
304 domain,
305 query->purple_query_data,
306 dns_srv_response,
307 query);
308 g_object_unref(resolver);
309 #else
310 query->type = SRV;
311 query->purple_query_data =
312 #if PURPLE_VERSION_CHECK(2,8,0)
313 purple_srv_resolve_account(
314 purple_private->account,
315 #else
316 purple_srv_resolve(
317 #endif
318 protocol,
319 transport,
320 domain,
321 (PurpleSrvCallback) dns_srv_response,
322 query);
323 #endif
325 return query;
328 static gboolean dns_query_deferred_destroy(gpointer user_data)
331 * All pending events on query have been processed.
332 * Now it is safe to destroy the data structure.
334 SIPE_DEBUG_INFO("dns_query_deferred_destroy: %p", user_data);
335 sipe_dns_query_free(user_data);
336 return(FALSE);
339 void sipe_backend_dns_query_cancel(struct sipe_dns_query *query)
341 SIPE_DEBUG_INFO("sipe_backend_dns_query_cancel: %p", query);
343 if (query->is_valid) {
344 struct sipe_backend_private *purple_private = query->purple_private;
345 purple_private->dns_queries = g_slist_remove(purple_private->dns_queries,
346 query);
348 #if PURPLE_VERSION_CHECK(3,0,0)
349 g_cancellable_cancel(query->purple_query_data);
350 #else
351 switch (query->type) {
352 case A:
353 purple_dnsquery_destroy(query->purple_query_data);
354 break;
355 case SRV:
356 #if PURPLE_VERSION_CHECK(2,8,0)
357 purple_srv_txt_query_destroy(query->purple_query_data);
358 #else
359 purple_srv_cancel(query->purple_query_data);
360 #endif
361 break;
363 #endif
365 /* defer deletion of query data structure to idle callback */
366 query->is_valid = FALSE;
367 g_idle_add(dns_query_deferred_destroy, query);
371 void sipe_purple_dns_query_cancel_all(struct sipe_backend_private *purple_private)
373 GSList *entry;
374 SIPE_DEBUG_INFO_NOFORMAT("sipe_purple_dns_query_cancel_all: entered");
375 while ((entry = purple_private->dns_queries) != NULL)
376 sipe_backend_dns_query_cancel(entry->data);
381 Local Variables:
382 mode: c
383 c-file-style: "bsd"
384 indent-tabs-mode: t
385 tab-width: 8
386 End: