Mercurial > pidgin.yaz
comparison libpurple/dnssrv.c @ 25987:c4fd9222dda1
propagate from branch 'im.pidgin.pidgin' (head 303af74a38e7b313d4fb0be4d4054a16cb13d819)
to branch 'im.pidgin.cpw.darkrain42.xmpp.bosh' (head 650d82b8a5f0c8860804dd8004cd54badea48e1e)
author | Paul Aurich <paul@darkrain42.org> |
---|---|
date | Sat, 07 Mar 2009 01:59:40 +0000 |
parents | 1d1d1829de11 |
children | e4a060a1e3de |
comparison
equal
deleted
inserted
replaced
25464:0e93bbb7f5ca | 25987:c4fd9222dda1 |
---|---|
31 #include <arpa/nameser_compat.h> | 31 #include <arpa/nameser_compat.h> |
32 #endif | 32 #endif |
33 #ifndef T_SRV | 33 #ifndef T_SRV |
34 #define T_SRV 33 | 34 #define T_SRV 33 |
35 #endif | 35 #endif |
36 #else | 36 #ifndef T_TXT |
37 #define T_TXT 16 | |
38 #endif | |
39 #else /* WIN32 */ | |
37 #include <windns.h> | 40 #include <windns.h> |
38 /* Missing from the mingw headers */ | 41 /* Missing from the mingw headers */ |
39 #ifndef DNS_TYPE_SRV | 42 #ifndef DNS_TYPE_SRV |
40 # define DNS_TYPE_SRV 33 | 43 # define DNS_TYPE_SRV 33 |
44 #endif | |
45 #ifndef DNS_TYPE_TXT | |
46 # define DNS_TYPE_TXT 16 | |
41 #endif | 47 #endif |
42 #endif | 48 #endif |
43 | 49 |
44 #include "dnssrv.h" | 50 #include "dnssrv.h" |
45 #include "eventloop.h" | 51 #include "eventloop.h" |
58 static void (WINAPI *MyDnsRecordListFree) (PDNS_RECORD pRecordList, | 64 static void (WINAPI *MyDnsRecordListFree) (PDNS_RECORD pRecordList, |
59 DNS_FREE_TYPE FreeType) = NULL; | 65 DNS_FREE_TYPE FreeType) = NULL; |
60 #endif | 66 #endif |
61 | 67 |
62 struct _PurpleSrvQueryData { | 68 struct _PurpleSrvQueryData { |
63 PurpleSrvCallback cb; | 69 union { |
70 PurpleSrvCallback srv; | |
71 PurpleTxtCallback txt; | |
72 } cb; | |
73 | |
64 gpointer extradata; | 74 gpointer extradata; |
65 guint handle; | 75 guint handle; |
76 int type; | |
66 #ifdef _WIN32 | 77 #ifdef _WIN32 |
67 GThread *resolver; | 78 GThread *resolver; |
68 char *query; | 79 char *query; |
69 char *error_message; | 80 char *error_message; |
70 GSList *results; | 81 GSList *results; |
72 int fd_in, fd_out; | 83 int fd_in, fd_out; |
73 pid_t pid; | 84 pid_t pid; |
74 #endif | 85 #endif |
75 }; | 86 }; |
76 | 87 |
88 typedef struct _PurpleSrvInternalQuery { | |
89 int type; | |
90 char query[256]; | |
91 } PurpleSrvInternalQuery; | |
92 | |
77 static gint | 93 static gint |
78 responsecompare(gconstpointer ar, gconstpointer br) | 94 responsecompare(gconstpointer ar, gconstpointer br) |
79 { | 95 { |
80 PurpleSrvResponse *a = (PurpleSrvResponse*)ar; | 96 PurpleSrvResponse *a = (PurpleSrvResponse*)ar; |
81 PurpleSrvResponse *b = (PurpleSrvResponse*)br; | 97 PurpleSrvResponse *b = (PurpleSrvResponse*)br; |
97 G_GNUC_NORETURN static void | 113 G_GNUC_NORETURN static void |
98 resolve(int in, int out) | 114 resolve(int in, int out) |
99 { | 115 { |
100 GList *ret = NULL; | 116 GList *ret = NULL; |
101 PurpleSrvResponse *srvres; | 117 PurpleSrvResponse *srvres; |
118 PurpleTxtResponse *txtres; | |
102 queryans answer; | 119 queryans answer; |
103 int size; | 120 int size; |
104 int qdcount; | 121 int qdcount; |
105 int ancount; | 122 int ancount; |
106 guchar *end; | 123 guchar *end; |
107 guchar *cp; | 124 guchar *cp; |
108 gchar name[256]; | 125 gchar name[256]; |
109 guint16 type, dlen, pref, weight, port; | 126 guint16 type, dlen, pref, weight, port; |
110 gchar query[256]; | 127 PurpleSrvInternalQuery query; |
111 | 128 |
112 #ifdef HAVE_SIGNAL_H | 129 #ifdef HAVE_SIGNAL_H |
113 purple_restore_default_signal_handlers(); | 130 purple_restore_default_signal_handlers(); |
114 #endif | 131 #endif |
115 | 132 |
116 if (read(in, query, 256) <= 0) { | 133 if (read(in, &query, sizeof(query)) <= 0) { |
117 close(out); | 134 close(out); |
118 close(in); | 135 close(in); |
119 _exit(0); | 136 _exit(0); |
120 } | 137 } |
121 | 138 |
122 size = res_query( query, C_IN, T_SRV, (u_char*)&answer, sizeof( answer)); | 139 size = res_query( query.query, C_IN, query.type, (u_char*)&answer, sizeof( answer)); |
123 | 140 |
124 qdcount = ntohs(answer.hdr.qdcount); | 141 qdcount = ntohs(answer.hdr.qdcount); |
125 ancount = ntohs(answer.hdr.ancount); | 142 ancount = ntohs(answer.hdr.ancount); |
126 | |
127 cp = (guchar*)&answer + sizeof(HEADER); | 143 cp = (guchar*)&answer + sizeof(HEADER); |
128 end = (guchar*)&answer + size; | 144 end = (guchar*)&answer + size; |
129 | 145 |
130 /* skip over unwanted stuff */ | 146 /* skip over unwanted stuff */ |
131 while (qdcount-- > 0 && cp < end) { | 147 while (qdcount-- > 0 && cp < end) { |
136 | 152 |
137 while (ancount-- > 0 && cp < end) { | 153 while (ancount-- > 0 && cp < end) { |
138 size = dn_expand((unsigned char*)&answer, end, cp, name, 256); | 154 size = dn_expand((unsigned char*)&answer, end, cp, name, 256); |
139 if(size < 0) | 155 if(size < 0) |
140 goto end; | 156 goto end; |
141 | |
142 cp += size; | 157 cp += size; |
143 | |
144 GETSHORT(type,cp); | 158 GETSHORT(type,cp); |
145 | 159 |
146 /* skip ttl and class since we already know it */ | 160 /* skip ttl and class since we already know it */ |
147 cp += 6; | 161 cp += 6; |
148 | 162 |
149 GETSHORT(dlen,cp); | 163 GETSHORT(dlen,cp); |
150 | 164 if (query.type == T_SRV) { |
151 if (type == T_SRV) { | |
152 GETSHORT(pref,cp); | 165 GETSHORT(pref,cp); |
153 | 166 |
154 GETSHORT(weight,cp); | 167 GETSHORT(weight,cp); |
155 | 168 |
156 GETSHORT(port,cp); | 169 GETSHORT(port,cp); |
166 srvres->pref = pref; | 179 srvres->pref = pref; |
167 srvres->port = port; | 180 srvres->port = port; |
168 srvres->weight = weight; | 181 srvres->weight = weight; |
169 | 182 |
170 ret = g_list_insert_sorted(ret, srvres, responsecompare); | 183 ret = g_list_insert_sorted(ret, srvres, responsecompare); |
184 } else if (query.type == T_TXT) { | |
185 txtres = g_new0(PurpleTxtResponse, 1); | |
186 strncpy(txtres->content, (gchar*)(++cp), dlen-1); | |
187 ret = g_list_append(ret, txtres); | |
188 cp += dlen - 1; | |
171 } else { | 189 } else { |
172 cp += dlen; | 190 cp += dlen; |
173 } | 191 } |
174 } | 192 } |
175 | 193 |
176 end: | 194 end: |
177 size = g_list_length(ret); | 195 size = g_list_length(ret); |
178 write(out, &size, sizeof(int)); | 196 write(out, &(query.type), sizeof(query.type)); |
197 write(out, &size, sizeof(size)); | |
179 while (ret != NULL) | 198 while (ret != NULL) |
180 { | 199 { |
181 write(out, ret->data, sizeof(PurpleSrvResponse)); | 200 if (query.type == T_SRV) write(out, ret->data, sizeof(PurpleSrvResponse)); |
201 if (query.type == T_TXT) write(out, ret->data, sizeof(PurpleTxtResponse)); | |
182 g_free(ret->data); | 202 g_free(ret->data); |
183 ret = g_list_remove(ret, ret->data); | 203 ret = g_list_remove(ret, ret->data); |
184 } | 204 } |
185 | 205 |
186 close(out); | 206 close(out); |
191 | 211 |
192 static void | 212 static void |
193 resolved(gpointer data, gint source, PurpleInputCondition cond) | 213 resolved(gpointer data, gint source, PurpleInputCondition cond) |
194 { | 214 { |
195 int size; | 215 int size; |
216 int type; | |
196 PurpleSrvQueryData *query_data = (PurpleSrvQueryData*)data; | 217 PurpleSrvQueryData *query_data = (PurpleSrvQueryData*)data; |
197 PurpleSrvResponse *res; | |
198 PurpleSrvResponse *tmp; | |
199 int i; | 218 int i; |
200 PurpleSrvCallback cb = query_data->cb; | |
201 int status; | 219 int status; |
202 | 220 |
203 if (read(source, &size, sizeof(int)) == sizeof(int)) | 221 if (read(source, &type, sizeof(type)) == sizeof(type)) { |
204 { | 222 if (type == T_SRV) { |
205 ssize_t red; | 223 PurpleSrvResponse *res; |
206 purple_debug_info("dnssrv","found %d SRV entries\n", size); | 224 PurpleSrvResponse *tmp; |
207 tmp = res = g_new0(PurpleSrvResponse, size); | 225 PurpleSrvCallback cb = query_data->cb.srv; |
208 for (i = 0; i < size; i++) { | 226 if (read(source, &size, sizeof(int)) == sizeof(int)) { |
209 red = read(source, tmp++, sizeof(PurpleSrvResponse)); | 227 ssize_t red; |
210 if (red != sizeof(PurpleSrvResponse)) { | 228 purple_debug_info("dnssrv","found %d SRV entries\n", size); |
211 purple_debug_error("dnssrv","unable to read srv " | 229 tmp = res = g_new0(PurpleSrvResponse, size); |
212 "response: %s\n", g_strerror(errno)); | 230 for (i = 0; i < size; i++) { |
231 red = read(source, tmp++, sizeof(PurpleSrvResponse)); | |
232 if (red != sizeof(PurpleSrvResponse)) { | |
233 purple_debug_error("dnssrv","unable to read srv " | |
234 "response: %s\n", g_strerror(errno)); | |
235 size = 0; | |
236 g_free(res); | |
237 res = NULL; | |
238 } | |
239 } | |
240 } else { | |
241 purple_debug_info("dnssrv","found 0 SRV entries; errno is %i\n", errno); | |
213 size = 0; | 242 size = 0; |
214 g_free(res); | |
215 res = NULL; | 243 res = NULL; |
216 } | 244 } |
245 cb(res, size, query_data->extradata); | |
246 } else if (type == T_TXT) { | |
247 PurpleTxtResponse *res; | |
248 PurpleTxtResponse *tmp; | |
249 PurpleTxtCallback cb = query_data->cb.txt; | |
250 if (read(source, &size, sizeof(int)) == sizeof(int)) { | |
251 ssize_t red; | |
252 purple_debug_info("dnssrv","found %d TXT entries\n", size); | |
253 tmp = res = g_new0(PurpleTxtResponse, size); | |
254 for (i = 0; i < size; i++) { | |
255 red = read(source, tmp++, sizeof(PurpleTxtResponse)); | |
256 if (red != sizeof(PurpleTxtResponse)) { | |
257 purple_debug_error("dnssrv","unable to read txt " | |
258 "response: %s\n", g_strerror(errno)); | |
259 size = 0; | |
260 g_free(res); | |
261 res = NULL; | |
262 } | |
263 } | |
264 } else { | |
265 purple_debug_info("dnssrv","found 0 TXT entries; errno is %i\n", errno); | |
266 size = 0; | |
267 res = NULL; | |
268 } | |
269 cb(res, size, query_data->extradata); | |
270 } else { | |
271 purple_debug_info("dnssrv","type unknown of DNS result entry; errno is %i\n", errno); | |
217 } | 272 } |
218 } | 273 } |
219 else | 274 |
220 { | |
221 purple_debug_info("dnssrv","found 0 SRV entries; errno is %i\n", errno); | |
222 size = 0; | |
223 res = NULL; | |
224 } | |
225 | |
226 cb(res, size, query_data->extradata); | |
227 waitpid(query_data->pid, &status, 0); | 275 waitpid(query_data->pid, &status, 0); |
228 | |
229 purple_srv_cancel(query_data); | 276 purple_srv_cancel(query_data); |
230 } | 277 } |
231 | 278 |
232 #else /* _WIN32 */ | 279 #else /* _WIN32 */ |
233 | 280 |
235 | 282 |
236 static gboolean | 283 static gboolean |
237 res_main_thread_cb(gpointer data) | 284 res_main_thread_cb(gpointer data) |
238 { | 285 { |
239 PurpleSrvResponse *srvres = NULL; | 286 PurpleSrvResponse *srvres = NULL; |
287 PurpleTxtResponse *txtres = NULL; | |
240 int size = 0; | 288 int size = 0; |
241 PurpleSrvQueryData *query_data = data; | 289 PurpleSrvQueryData *query_data = data; |
242 | |
243 if(query_data->error_message != NULL) | 290 if(query_data->error_message != NULL) |
244 purple_debug_error("dnssrv", query_data->error_message); | 291 purple_debug_error("dnssrv", query_data->error_message); |
245 else { | 292 else { |
246 PurpleSrvResponse *srvres_tmp = NULL; | 293 if (query_data->type == T_SRV) { |
247 GSList *lst = query_data->results; | 294 PurpleSrvResponse *srvres_tmp = NULL; |
248 | 295 GSList *lst = query_data->results; |
249 size = g_slist_length(lst); | 296 |
250 | 297 size = g_slist_length(lst); |
251 if(query_data->cb && size > 0) | 298 |
252 srvres_tmp = srvres = g_new0(PurpleSrvResponse, size); | 299 if(query_data->cb.srv && size > 0) |
253 while (lst) { | 300 srvres_tmp = srvres = g_new0(PurpleSrvResponse, size); |
254 if(query_data->cb) | 301 while (lst) { |
255 memcpy(srvres_tmp++, lst->data, sizeof(PurpleSrvResponse)); | 302 if(query_data->cb.srv) |
256 g_free(lst->data); | 303 memcpy(srvres_tmp++, lst->data, sizeof(PurpleSrvResponse)); |
257 lst = g_slist_remove(lst, lst->data); | 304 g_free(lst->data); |
305 lst = g_slist_remove(lst, lst->data); | |
306 } | |
307 | |
308 query_data->results = NULL; | |
309 | |
310 purple_debug_info("dnssrv", "found %d SRV entries\n", size); | |
311 | |
312 if(query_data->cb.srv) query_data->cb.srv(srvres, size, query_data->extradata); | |
313 } else if (query_data->type == T_TXT) { | |
314 PurpleTxtResponse *txtres_tmp = NULL; | |
315 GSList *lst = query_data->results; | |
316 | |
317 size = g_slist_length(lst); | |
318 | |
319 if(query_data->cb.txt && size > 0) | |
320 txtres_tmp = txtres = g_new0(PurpleTxtResponse, size); | |
321 while (lst) { | |
322 if(query_data->cb.txt) | |
323 memcpy(txtres_tmp++, lst->data, sizeof(PurpleTxtResponse)); | |
324 g_free(lst->data); | |
325 lst = g_slist_remove(lst, lst->data); | |
326 } | |
327 | |
328 query_data->results = NULL; | |
329 | |
330 purple_debug_info("dnssrv", "found %d TXT entries\n", size); | |
331 | |
332 if(query_data->cb.txt) query_data->cb.txt(txtres, size, query_data->extradata); | |
333 } else { | |
334 purple_debug_error("dnssrv", "unknown query type"); | |
258 } | 335 } |
259 | 336 } |
260 query_data->results = NULL; | |
261 | |
262 purple_debug_info("dnssrv", "found %d SRV entries\n", size); | |
263 } | |
264 | |
265 if(query_data->cb) | |
266 query_data->cb(srvres, size, query_data->extradata); | |
267 | 337 |
268 query_data->resolver = NULL; | 338 query_data->resolver = NULL; |
269 query_data->handle = 0; | 339 query_data->handle = 0; |
270 | 340 |
271 purple_srv_cancel(query_data); | 341 purple_srv_cancel(query_data); |
275 | 345 |
276 static gpointer | 346 static gpointer |
277 res_thread(gpointer data) | 347 res_thread(gpointer data) |
278 { | 348 { |
279 PDNS_RECORD dr = NULL; | 349 PDNS_RECORD dr = NULL; |
280 int type = DNS_TYPE_SRV; | 350 int type; |
281 DNS_STATUS ds; | 351 DNS_STATUS ds; |
282 PurpleSrvQueryData *query_data = data; | 352 PurpleSrvQueryData *query_data = data; |
283 | 353 type = query_data->type; |
284 ds = MyDnsQuery_UTF8(query_data->query, type, DNS_QUERY_STANDARD, NULL, &dr, NULL); | 354 ds = MyDnsQuery_UTF8(query_data->query, type, DNS_QUERY_STANDARD, NULL, &dr, NULL); |
285 if (ds != ERROR_SUCCESS) { | 355 if (ds != ERROR_SUCCESS) { |
286 gchar *msg = g_win32_error_message(ds); | 356 gchar *msg = g_win32_error_message(ds); |
287 query_data->error_message = g_strdup_printf("Couldn't look up SRV record. %s (%lu).\n", msg, ds); | 357 if (type == DNS_TYPE_SRV) { |
358 query_data->error_message = g_strdup_printf("Couldn't look up SRV record. %s (%lu).\n", msg, ds); | |
359 } else if (type == DNS_TYPE_TXT) { | |
360 query_data->error_message = g_strdup_printf("Couldn't look up TXT record. %s (%lu).\n", msg, ds); | |
361 } | |
288 g_free(msg); | 362 g_free(msg); |
289 } else { | 363 } else { |
290 PDNS_RECORD dr_tmp; | 364 if (type == DNS_TYPE_SRV) { |
291 GSList *lst = NULL; | 365 PDNS_RECORD dr_tmp; |
292 DNS_SRV_DATA *srv_data; | 366 GSList *lst = NULL; |
293 PurpleSrvResponse *srvres; | 367 DNS_SRV_DATA *srv_data; |
294 | 368 PurpleSrvResponse *srvres; |
295 for (dr_tmp = dr; dr_tmp != NULL; dr_tmp = dr_tmp->pNext) { | 369 |
296 /* Discard any incorrect entries. I'm not sure if this is necessary */ | 370 for (dr_tmp = dr; dr_tmp != NULL; dr_tmp = dr_tmp->pNext) { |
297 if (dr_tmp->wType != type || strcmp(dr_tmp->pName, query_data->query) != 0) { | 371 /* Discard any incorrect entries. I'm not sure if this is necessary */ |
298 continue; | 372 if (dr_tmp->wType != type || strcmp(dr_tmp->pName, query_data->query) != 0) { |
373 continue; | |
374 } | |
375 | |
376 srv_data = &dr_tmp->Data.SRV; | |
377 srvres = g_new0(PurpleSrvResponse, 1); | |
378 strncpy(srvres->hostname, srv_data->pNameTarget, 255); | |
379 srvres->hostname[255] = '\0'; | |
380 srvres->pref = srv_data->wPriority; | |
381 srvres->port = srv_data->wPort; | |
382 srvres->weight = srv_data->wWeight; | |
383 | |
384 lst = g_slist_insert_sorted(lst, srvres, responsecompare); | |
299 } | 385 } |
300 | 386 |
301 srv_data = &dr_tmp->Data.SRV; | 387 MyDnsRecordListFree(dr, DnsFreeRecordList); |
302 srvres = g_new0(PurpleSrvResponse, 1); | 388 query_data->results = lst; |
303 strncpy(srvres->hostname, srv_data->pNameTarget, 255); | 389 } else if (type == T_TXT) { |
304 srvres->hostname[255] = '\0'; | 390 #error IMPLEMENTATION MISSING |
305 srvres->pref = srv_data->wPriority; | 391 } else { |
306 srvres->port = srv_data->wPort; | 392 |
307 srvres->weight = srv_data->wWeight; | |
308 | |
309 lst = g_slist_insert_sorted(lst, srvres, responsecompare); | |
310 } | 393 } |
311 | |
312 MyDnsRecordListFree(dr, DnsFreeRecordList); | |
313 query_data->results = lst; | |
314 } | 394 } |
315 | 395 |
316 /* back to main thread */ | 396 /* back to main thread */ |
317 /* Note: this should *not* be attached to query_data->handle - it will cause leakage */ | 397 /* Note: this should *not* be attached to query_data->handle - it will cause leakage */ |
318 purple_timeout_add(0, res_main_thread_cb, query_data); | 398 purple_timeout_add(0, res_main_thread_cb, query_data); |
326 PurpleSrvQueryData * | 406 PurpleSrvQueryData * |
327 purple_srv_resolve(const char *protocol, const char *transport, const char *domain, PurpleSrvCallback cb, gpointer extradata) | 407 purple_srv_resolve(const char *protocol, const char *transport, const char *domain, PurpleSrvCallback cb, gpointer extradata) |
328 { | 408 { |
329 char *query; | 409 char *query; |
330 PurpleSrvQueryData *query_data; | 410 PurpleSrvQueryData *query_data; |
411 PurpleSrvInternalQuery internal_query; | |
331 #ifndef _WIN32 | 412 #ifndef _WIN32 |
332 int in[2], out[2]; | 413 int in[2], out[2]; |
333 int pid; | 414 int pid; |
334 #else | 415 #else |
335 GError* err = NULL; | 416 GError* err = NULL; |
373 } | 454 } |
374 | 455 |
375 close(out[1]); | 456 close(out[1]); |
376 close(in[0]); | 457 close(in[0]); |
377 | 458 |
378 if (write(in[1], query, strlen(query)+1) < 0) | 459 internal_query.type = T_SRV; |
460 strncpy(internal_query.query, query, 255); | |
461 | |
462 if (write(in[1], &internal_query, sizeof(internal_query)) < 0) | |
379 purple_debug_error("dnssrv", "Could not write to SRV resolver\n"); | 463 purple_debug_error("dnssrv", "Could not write to SRV resolver\n"); |
464 | |
380 | 465 |
381 query_data = g_new0(PurpleSrvQueryData, 1); | 466 query_data = g_new0(PurpleSrvQueryData, 1); |
382 query_data->cb = cb; | 467 query_data->type = T_SRV; |
468 query_data->cb.srv = cb; | |
383 query_data->extradata = extradata; | 469 query_data->extradata = extradata; |
384 query_data->pid = pid; | 470 query_data->pid = pid; |
385 query_data->fd_out = out[0]; | 471 query_data->fd_out = out[0]; |
386 query_data->fd_in = in[1]; | 472 query_data->fd_in = in[1]; |
387 query_data->handle = purple_input_add(out[0], PURPLE_INPUT_READ, resolved, query_data); | 473 query_data->handle = purple_input_add(out[0], PURPLE_INPUT_READ, resolved, query_data); |
396 "dnsapi.dll", "DnsRecordListFree"); | 482 "dnsapi.dll", "DnsRecordListFree"); |
397 initialized = TRUE; | 483 initialized = TRUE; |
398 } | 484 } |
399 | 485 |
400 query_data = g_new0(PurpleSrvQueryData, 1); | 486 query_data = g_new0(PurpleSrvQueryData, 1); |
401 query_data->cb = cb; | 487 query_data->type = DNS_TYPE_SRV; |
488 query_data->cb.srv = cb; | |
402 query_data->query = query; | 489 query_data->query = query; |
403 query_data->extradata = extradata; | 490 query_data->extradata = extradata; |
404 | 491 |
405 if (!MyDnsQuery_UTF8 || !MyDnsRecordListFree) | 492 if (!MyDnsQuery_UTF8 || !MyDnsRecordListFree) |
406 query_data->error_message = g_strdup("System missing DNS API (Requires W2K+)\n"); | 493 query_data->error_message = g_strdup("System missing DNS API (Requires W2K+)\n"); |
407 else { | 494 else { |
408 query_data->resolver = g_thread_create(res_thread, query_data, FALSE, &err); | 495 query_data->resolver = g_thread_create(res_thread, query_data, FALSE, &err); |
409 if (query_data->resolver == NULL) { | 496 if (query_data->resolver == NULL) { |
410 query_data->error_message = g_strdup_printf("SRV thread create failure: %s\n", (err && err->message) ? err->message : ""); | 497 query_data->error_message = g_strdup_printf("SRV thread create failure: %s\n", (err && err->message) ? err->message : ""); |
498 g_error_free(err); | |
499 } | |
500 } | |
501 | |
502 /* The query isn't going to happen, so finish the SRV lookup now. | |
503 * Asynchronously call the callback since stuff may not expect | |
504 * the callback to be called before this returns */ | |
505 if (query_data->error_message != NULL) | |
506 query_data->handle = purple_timeout_add(0, res_main_thread_cb, query_data); | |
507 | |
508 return query_data; | |
509 #endif | |
510 } | |
511 | |
512 PurpleSrvQueryData *purple_txt_resolve(const char *owner, const char *domain, PurpleTxtCallback cb, gpointer extradata) | |
513 { | |
514 char *query; | |
515 PurpleSrvQueryData *query_data; | |
516 PurpleSrvInternalQuery internal_query; | |
517 #ifndef _WIN32 | |
518 int in[2], out[2]; | |
519 int pid; | |
520 #else | |
521 GError* err = NULL; | |
522 static gboolean initialized = FALSE; | |
523 #endif | |
524 | |
525 query = g_strdup_printf("%s.%s", owner, domain); | |
526 purple_debug_info("dnssrv","querying TXT record for %s\n", query); | |
527 | |
528 #ifndef _WIN32 | |
529 if(pipe(in) || pipe(out)) { | |
530 purple_debug_error("dnssrv", "Could not create pipe\n"); | |
531 g_free(query); | |
532 cb(NULL, 0, extradata); | |
533 return NULL; | |
534 } | |
535 | |
536 pid = fork(); | |
537 if (pid == -1) { | |
538 purple_debug_error("dnssrv", "Could not create process!\n"); | |
539 cb(NULL, 0, extradata); | |
540 g_free(query); | |
541 return NULL; | |
542 } | |
543 | |
544 /* Child */ | |
545 if (pid == 0) | |
546 { | |
547 g_free(query); | |
548 | |
549 close(out[0]); | |
550 close(in[1]); | |
551 resolve(in[0], out[1]); | |
552 /* resolve() does not return */ | |
553 } | |
554 | |
555 close(out[1]); | |
556 close(in[0]); | |
557 | |
558 internal_query.type = T_TXT; | |
559 strncpy(internal_query.query, query, 255); | |
560 | |
561 if (write(in[1], &internal_query, sizeof(internal_query)) < 0) | |
562 purple_debug_error("dnssrv", "Could not write to TXT resolver\n"); | |
563 | |
564 query_data = g_new0(PurpleSrvQueryData, 1); | |
565 query_data->type = T_TXT; | |
566 query_data->cb.txt = cb; | |
567 query_data->extradata = extradata; | |
568 query_data->pid = pid; | |
569 query_data->fd_out = out[0]; | |
570 query_data->fd_in = in[1]; | |
571 query_data->handle = purple_input_add(out[0], PURPLE_INPUT_READ, resolved, query_data); | |
572 | |
573 g_free(query); | |
574 | |
575 return query_data; | |
576 #else | |
577 if (!initialized) { | |
578 MyDnsQuery_UTF8 = (void*) wpurple_find_and_loadproc("dnsapi.dll", "DnsQuery_UTF8"); | |
579 MyDnsRecordListFree = (void*) wpurple_find_and_loadproc( | |
580 "dnsapi.dll", "DnsRecordListFree"); | |
581 initialized = TRUE; | |
582 } | |
583 | |
584 query_data = g_new0(PurpleSrvQueryData, 1); | |
585 query_data->type = DNS_TYPE_TXT; | |
586 query_data->cb.txt = cb; | |
587 query_data->query = query; | |
588 query_data->extradata = extradata; | |
589 | |
590 if (!MyDnsQuery_UTF8 || !MyDnsRecordListFree) | |
591 query_data->error_message = g_strdup("System missing DNS API (Requires W2K+)\n"); | |
592 else { | |
593 query_data->resolver = g_thread_create(res_thread, query_data, FALSE, &err); | |
594 if (query_data->resolver == NULL) { | |
595 query_data->error_message = g_strdup_printf("TXT thread create failure: %s\n", (err && err->message) ? err->message : ""); | |
411 g_error_free(err); | 596 g_error_free(err); |
412 } | 597 } |
413 } | 598 } |
414 | 599 |
415 /* The query isn't going to happen, so finish the SRV lookup now. | 600 /* The query isn't going to happen, so finish the SRV lookup now. |
433 /* | 618 /* |
434 * It's not really possible to kill a thread. So instead we | 619 * It's not really possible to kill a thread. So instead we |
435 * just set the callback to NULL and let the DNS lookup | 620 * just set the callback to NULL and let the DNS lookup |
436 * finish. | 621 * finish. |
437 */ | 622 */ |
438 query_data->cb = NULL; | 623 query_data->cb.srv = NULL; |
439 return; | 624 return; |
440 } | 625 } |
441 g_free(query_data->query); | 626 g_free(query_data->query); |
442 g_free(query_data->error_message); | 627 g_free(query_data->error_message); |
443 #else | 628 #else |
444 close(query_data->fd_out); | 629 close(query_data->fd_out); |
445 close(query_data->fd_in); | 630 close(query_data->fd_in); |
446 #endif | 631 #endif |
447 g_free(query_data); | 632 g_free(query_data); |
448 } | 633 } |
634 | |
635 void | |
636 purple_txt_cancel(PurpleSrvQueryData *query_data) | |
637 { | |
638 purple_srv_cancel(query_data); | |
639 } |