OBS: update support for CentOS & Scientific Linux 7
[siplcs.git] / src / purple / purple-dnsquery.c
blob9bc9756679c74a0f2afcd71587a54715c25cc386
1 /**
2 * @file purple-dnsquery.c
4 * pidgin-sipe
6 * Copyright (C) 2010-2018 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(2,8,0)
28 #include "account.h"
29 #endif
30 #if PURPLE_VERSION_CHECK(3,0,0)
31 #include "protocols.h"
32 #include <gio/gio.h>
33 #else
35 #ifdef _WIN32
36 /* wrappers for write() & friends for socket handling */
37 #include "win32/win32dep.h"
38 #include <ws2tcpip.h>
39 #else
40 #include <sys/types.h>
41 #include <sys/socket.h>
42 #include <netinet/in.h>
43 #include <arpa/inet.h>
44 #endif
46 #include "dnsquery.h"
47 #include "dnssrv.h"
49 #endif
51 #include "sipe-backend.h"
52 #include "sipe-core.h"
54 #include "purple-private.h"
56 struct sipe_dns_query {
57 struct sipe_backend_private *purple_private;
58 sipe_dns_resolved_cb callback;
59 gpointer extradata;
60 gpointer purple_query_data;
61 gboolean is_valid;
62 #if PURPLE_VERSION_CHECK(3,0,0)
63 guint port;
64 #else
65 enum {
67 SRV
68 } type;
69 #endif
72 static void sipe_dns_query_free(struct sipe_dns_query *query)
74 #if PURPLE_VERSION_CHECK(3,0,0)
75 g_object_unref(query->purple_query_data);
76 #endif
77 g_free(query);
80 #if PURPLE_VERSION_CHECK(3,0,0)
81 static void dns_a_response(GObject *source,
82 GAsyncResult *res,
83 gpointer user_data)
85 struct sipe_dns_query *query = user_data;
86 GList *hosts;
87 GError *error = NULL;
88 gchar *address_str = NULL;
90 if (!query->is_valid) {
91 /* Ignore spurious responses after disconnect */
92 return;
95 query->purple_private->dns_queries =
96 g_slist_remove(query->purple_private->dns_queries,
97 query);
99 hosts = g_resolver_lookup_by_name_finish(G_RESOLVER(source), res,
100 &error);
102 if (!error && g_list_length(hosts) > 0) {
103 address_str = g_inet_address_to_string(hosts->data);
106 query->callback(query->extradata, address_str,
107 address_str ? query->port : 0);
109 g_free(address_str);
110 if (error)
111 g_error_free(error);
112 g_resolver_free_addresses(hosts);
113 sipe_dns_query_free(query);
115 #else
116 static void dns_a_response(GSList *hosts,
117 struct sipe_dns_query *query,
118 const char *error_message)
120 char ipstr[INET6_ADDRSTRLEN];
121 struct sockaddr *addr;
122 const void *addrdata;
123 int port;
125 /* Ignore spurious responses after disconnect */
126 if (query->is_valid) {
127 struct sipe_backend_private *purple_private = query->purple_private;
129 purple_private->dns_queries = g_slist_remove(purple_private->dns_queries,
130 query);
132 if (error_message || !g_slist_next(hosts)) {
133 query->callback(query->extradata, NULL, 0);
134 g_slist_free(hosts);
135 return;
138 addr = g_slist_next(hosts)->data;
139 if (addr->sa_family == AF_INET6) {
140 /* OS provides addr so it must be properly aligned */
141 struct sockaddr_in6 *sin6 = (void *) addr;
142 addrdata = &sin6->sin6_addr;
143 port = sin6->sin6_port;
144 } else {
145 /* OS provides addr so it must be properly aligned */
146 struct sockaddr_in *sin = (void *) addr;
147 addrdata = &sin->sin_addr;
148 port = sin->sin_port;
151 inet_ntop(addr->sa_family, addrdata, ipstr, sizeof (ipstr));
153 query->callback(query->extradata, ipstr, port);
155 g_free(query);
158 for (; hosts; hosts = g_slist_delete_link(hosts, hosts)) {
159 // Free the addrlen, no data in this link
160 hosts = g_slist_delete_link(hosts, hosts);
161 // Free the address
162 g_free(hosts->data);
165 #endif
167 struct sipe_dns_query *sipe_backend_dns_query_a(struct sipe_core_public *sipe_public,
168 const gchar *hostname,
169 guint port,
170 sipe_dns_resolved_cb callback,
171 gpointer data)
173 struct sipe_dns_query *query = g_new(struct sipe_dns_query, 1);
174 struct sipe_backend_private *purple_private = sipe_public->backend_private;
175 #if PURPLE_VERSION_CHECK(3,0,0)
176 GResolver *resolver = g_resolver_get_default();
177 #endif
179 query->purple_private = purple_private;
180 query->callback = callback;
181 query->extradata = data;
182 query->is_valid = TRUE;
184 purple_private->dns_queries = g_slist_prepend(purple_private->dns_queries,
185 query);
187 #if PURPLE_VERSION_CHECK(3,0,0)
188 query->port = port;
189 query->purple_query_data = g_cancellable_new();
191 g_resolver_lookup_by_name_async(resolver,
192 hostname,
193 query->purple_query_data,
194 dns_a_response,
195 query);
196 g_object_unref(resolver);
197 #else
198 query->type = A;
199 query->purple_query_data =
200 #if PURPLE_VERSION_CHECK(2,8,0)
201 purple_dnsquery_a_account(
202 purple_private->account,
203 #else
204 purple_dnsquery_a(
205 #endif
206 hostname,
207 port,
208 (PurpleDnsQueryConnectFunction) dns_a_response,
209 query);
210 #endif
212 return query;
215 #if PURPLE_VERSION_CHECK(3,0,0)
216 static void dns_srv_response(GObject *source,
217 GAsyncResult *res,
218 gpointer user_data)
220 struct sipe_dns_query *query = user_data;
221 GError *error = NULL;
222 GList *targets;
224 if (!query->is_valid) {
225 /* Ignore spurious responses after disconnect */
226 return;
229 query->purple_private->dns_queries =
230 g_slist_remove(query->purple_private->dns_queries,
231 query);
233 targets = g_resolver_lookup_service_finish(G_RESOLVER(source), res,
234 &error);
236 if (error || g_list_length(targets) == 0) {
237 query->callback(query->extradata, NULL, 0);
238 } else {
239 query->callback(query->extradata,
240 g_srv_target_get_hostname(targets->data),
241 g_srv_target_get_port(targets->data));
244 if (error)
245 g_error_free(error);
246 g_resolver_free_targets(targets);
247 sipe_dns_query_free(query);
249 #else
250 static void dns_srv_response(PurpleSrvResponse *resp,
251 int results,
252 struct sipe_dns_query *query)
254 /* Ignore spurious responses after disconnect */
255 if (query->is_valid) {
256 struct sipe_backend_private *purple_private = query->purple_private;
258 purple_private->dns_queries = g_slist_remove(purple_private->dns_queries,
259 query);
261 if (results)
262 query->callback(query->extradata, resp->hostname, resp->port);
263 else
264 query->callback(query->extradata, NULL, 0);
266 g_free(query);
269 g_free(resp);
271 #endif
273 struct sipe_dns_query *sipe_backend_dns_query_srv(struct sipe_core_public *sipe_public,
274 const gchar *protocol,
275 const gchar *transport,
276 const gchar *domain,
277 sipe_dns_resolved_cb callback,
278 gpointer data)
280 struct sipe_dns_query *query = g_new(struct sipe_dns_query, 1);
281 struct sipe_backend_private *purple_private = sipe_public->backend_private;
282 #if PURPLE_VERSION_CHECK(3,0,0)
283 GResolver *resolver = g_resolver_get_default();
284 #endif
286 query->purple_private = purple_private;
287 query->callback = callback;
288 query->extradata = data;
289 query->is_valid = TRUE;
291 purple_private->dns_queries = g_slist_prepend(purple_private->dns_queries,
292 query);
294 #if PURPLE_VERSION_CHECK(3,0,0)
295 query->purple_query_data = g_cancellable_new();
297 g_resolver_lookup_service_async(resolver,
298 protocol,
299 transport,
300 domain,
301 query->purple_query_data,
302 dns_srv_response,
303 query);
304 g_object_unref(resolver);
305 #else
306 query->type = SRV;
307 query->purple_query_data =
308 #if PURPLE_VERSION_CHECK(2,8,0)
309 purple_srv_resolve_account(
310 purple_private->account,
311 #else
312 purple_srv_resolve(
313 #endif
314 protocol,
315 transport,
316 domain,
317 (PurpleSrvCallback) dns_srv_response,
318 query);
319 #endif
321 return query;
324 static gboolean dns_query_deferred_destroy(gpointer user_data)
327 * All pending events on query have been processed.
328 * Now it is safe to destroy the data structure.
330 SIPE_DEBUG_INFO("dns_query_deferred_destroy: %p", user_data);
331 sipe_dns_query_free(user_data);
332 return(FALSE);
335 void sipe_backend_dns_query_cancel(struct sipe_dns_query *query)
337 SIPE_DEBUG_INFO("sipe_backend_dns_query_cancel: %p", query);
339 if (query->is_valid) {
340 struct sipe_backend_private *purple_private = query->purple_private;
341 purple_private->dns_queries = g_slist_remove(purple_private->dns_queries,
342 query);
344 #if PURPLE_VERSION_CHECK(3,0,0)
345 g_cancellable_cancel(query->purple_query_data);
346 #else
347 switch (query->type) {
348 case A:
349 purple_dnsquery_destroy(query->purple_query_data);
350 break;
351 case SRV:
352 #if PURPLE_VERSION_CHECK(2,8,0)
353 purple_srv_txt_query_destroy(query->purple_query_data);
354 #else
355 purple_srv_cancel(query->purple_query_data);
356 #endif
357 break;
359 #endif
361 /* defer deletion of query data structure to idle callback */
362 query->is_valid = FALSE;
363 g_idle_add(dns_query_deferred_destroy, query);
367 void sipe_purple_dns_query_cancel_all(struct sipe_backend_private *purple_private)
369 GSList *entry;
370 SIPE_DEBUG_INFO_NOFORMAT("sipe_purple_dns_query_cancel_all: entered");
371 while ((entry = purple_private->dns_queries) != NULL)
372 sipe_backend_dns_query_cancel(entry->data);
377 Local Variables:
378 mode: c
379 c-file-style: "bsd"
380 indent-tabs-mode: t
381 tab-width: 8
382 End: