2 * @file purple-dnsquery.c
6 * Copyright (C) 2010-2013 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
24 /* wrappers for write() & friends for socket handling */
25 #include "win32/win32dep.h"
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <netinet/in.h>
31 #include <arpa/inet.h>
39 #include "sipe-common.h"
40 #include "sipe-backend.h"
41 #include "sipe-core.h"
43 #include "purple-private.h"
45 struct sipe_dns_query
{
50 struct sipe_backend_private
*purple_private
;
51 sipe_dns_resolved_cb callback
;
53 gpointer purple_query_data
;
57 static void dns_a_response(GSList
*hosts
,
58 struct sipe_dns_query
*query
,
59 const char *error_message
)
61 char ipstr
[INET6_ADDRSTRLEN
];
62 struct sockaddr
*addr
;
66 /* Ignore spurious responses after disconnect */
67 if (query
->is_valid
) {
68 struct sipe_backend_private
*purple_private
= query
->purple_private
;
70 purple_private
->dns_queries
= g_slist_remove(purple_private
->dns_queries
,
73 if (error_message
|| !g_slist_next(hosts
)) {
74 query
->callback(query
->extradata
, NULL
, 0);
79 addr
= g_slist_next(hosts
)->data
;
80 if (addr
->sa_family
== AF_INET6
) {
81 /* OS provides addr so it must be properly aligned */
82 struct sockaddr_in6
*sin6
= (void *) addr
;
83 addrdata
= &sin6
->sin6_addr
;
84 port
= sin6
->sin6_port
;
86 /* OS provides addr so it must be properly aligned */
87 struct sockaddr_in
*sin
= (void *) addr
;
88 addrdata
= &sin
->sin_addr
;
92 inet_ntop(addr
->sa_family
, addrdata
, ipstr
, sizeof (ipstr
));
94 query
->callback(query
->extradata
, ipstr
, port
);
99 for (; hosts
; hosts
= g_slist_delete_link(hosts
, hosts
)) {
100 // Free the addrlen, no data in this link
101 hosts
= g_slist_delete_link(hosts
, hosts
);
107 struct sipe_dns_query
*sipe_backend_dns_query_a(struct sipe_core_public
*sipe_public
,
108 const gchar
*hostname
,
110 sipe_dns_resolved_cb callback
,
113 struct sipe_dns_query
*query
= g_new(struct sipe_dns_query
, 1);
114 struct sipe_backend_private
*purple_private
= sipe_public
->backend_private
;
117 query
->purple_private
= purple_private
;
118 query
->callback
= callback
;
119 query
->extradata
= data
;
120 query
->is_valid
= TRUE
;
122 purple_private
->dns_queries
= g_slist_prepend(purple_private
->dns_queries
,
125 query
->purple_query_data
=
126 #if PURPLE_VERSION_CHECK(3,0,0)
128 purple_private
->account
,
129 #elif PURPLE_VERSION_CHECK(2,8,0)
130 purple_dnsquery_a_account(
131 purple_private
->account
,
137 (PurpleDnsQueryConnectFunction
) dns_a_response
,
144 static void dns_srv_response(PurpleSrvResponse
*resp
,
146 struct sipe_dns_query
*query
)
148 /* Ignore spurious responses after disconnect */
149 if (query
->is_valid
) {
150 struct sipe_backend_private
*purple_private
= query
->purple_private
;
152 purple_private
->dns_queries
= g_slist_remove(purple_private
->dns_queries
,
156 query
->callback(query
->extradata
, resp
->hostname
, resp
->port
);
158 query
->callback(query
->extradata
, NULL
, 0);
166 struct sipe_dns_query
*sipe_backend_dns_query_srv(struct sipe_core_public
*sipe_public
,
167 const gchar
*protocol
,
168 const gchar
*transport
,
170 sipe_dns_resolved_cb callback
,
173 struct sipe_dns_query
*query
= g_new(struct sipe_dns_query
, 1);
174 struct sipe_backend_private
*purple_private
= sipe_public
->backend_private
;
177 query
->purple_private
= purple_private
;
178 query
->callback
= callback
;
179 query
->extradata
= data
;
180 query
->is_valid
= TRUE
;
182 purple_private
->dns_queries
= g_slist_prepend(purple_private
->dns_queries
,
185 query
->purple_query_data
=
186 #if PURPLE_VERSION_CHECK(3,0,0)
188 purple_private
->account
,
189 #elif PURPLE_VERSION_CHECK(2,8,0)
190 purple_srv_resolve_account(
191 purple_private
->account
,
198 (PurpleSrvCallback
) dns_srv_response
,
204 static gboolean
dns_query_deferred_destroy(gpointer user_data
)
207 * All pending events on query have been processed.
208 * Now it is safe to destroy the data structure.
210 SIPE_DEBUG_INFO("dns_query_deferred_destroy: %p", user_data
);
215 void sipe_backend_dns_query_cancel(struct sipe_dns_query
*query
)
217 SIPE_DEBUG_INFO("sipe_backend_dns_query_cancel: %p", query
);
219 if (query
->is_valid
) {
220 struct sipe_backend_private
*purple_private
= query
->purple_private
;
221 purple_private
->dns_queries
= g_slist_remove(purple_private
->dns_queries
,
224 switch (query
->type
) {
226 purple_dnsquery_destroy(query
->purple_query_data
);
229 #if PURPLE_VERSION_CHECK(2,8,0) || PURPLE_VERSION_CHECK(3,0,0)
230 purple_srv_txt_query_destroy(query
->purple_query_data
);
232 purple_srv_cancel(query
->purple_query_data
);
237 /* defer deletion of query data structure to idle callback */
238 query
->is_valid
= FALSE
;
239 g_idle_add(dns_query_deferred_destroy
, query
);
243 void sipe_purple_dns_query_cancel_all(struct sipe_backend_private
*purple_private
)
246 SIPE_DEBUG_INFO_NOFORMAT("sipe_purple_dns_query_cancel_all: entered");
247 while ((entry
= purple_private
->dns_queries
) != NULL
)
248 sipe_backend_dns_query_cancel(entry
->data
);