Mercurial > pidgin
changeset 14308:9ad313800b19
[gaim-migrate @ 16998]
Make gaim_srv_resolve cancelable. Please test and let me know of any
problems. I was unable to test the WIN32 method for this, since it
actually uses Windows stuff.
committer: Tailor Script <tailor@pidgin.im>
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Wed, 23 Aug 2006 08:02:05 +0000 |
parents | 7c91ba42b9ba |
children | 578a2c9af05e |
files | libgaim/dnssrv.c libgaim/dnssrv.h libgaim/protocols/jabber/jabber.c libgaim/protocols/jabber/jabber.h libgaim/protocols/simple/simple.c libgaim/protocols/simple/simple.h |
diffstat | 6 files changed, 152 insertions(+), 115 deletions(-) [+] |
line wrap: on
line diff
--- a/libgaim/dnssrv.c Wed Aug 23 07:14:19 2006 +0000 +++ b/libgaim/dnssrv.c Wed Aug 23 08:02:05 2006 +0000 @@ -57,19 +57,22 @@ DNS_FREE_TYPE FreeType) = NULL; #endif -struct resdata { - GaimSRVCallback cb; +struct _GaimSrvQueryData { + GaimSrvCallback cb; gpointer extradata; #ifndef _WIN32 guint handle; #else + GThread *resolver; char *query; - char *errmsg; + char *error_message; GSList *results; #endif }; -static gint responsecompare(gconstpointer ar, gconstpointer br) { +static gint +responsecompare(gconstpointer ar, gconstpointer br) +{ GaimSrvResponse *a = (GaimSrvResponse*)ar; GaimSrvResponse *b = (GaimSrvResponse*)br; @@ -84,8 +87,12 @@ return -1; return 1; } + #ifndef _WIN32 -static void resolve(int in, int out) { + +static void +resolve(int in, int out) +{ GList *ret = NULL; GaimSrvResponse *srvres; queryans answer; @@ -98,15 +105,14 @@ guint16 type, dlen, pref, weight, port; gchar query[256]; - if(read(in, query, 256) <= 0) { + if (read(in, query, 256) <= 0) _exit(0); - } + size = res_query( query, C_IN, T_SRV, (u_char*)&answer, sizeof( answer)); qdcount = ntohs(answer.hdr.qdcount); ancount = ntohs(answer.hdr.ancount); - cp = (guchar*)&answer + sizeof(HEADER); end = (guchar*)&answer + size; @@ -155,58 +161,60 @@ cp += dlen; } } -end: size = g_list_length(ret); + +end: + size = g_list_length(ret); write(out, &size, sizeof(int)); - while(g_list_first(ret)) { - write(out, g_list_first(ret)->data, sizeof(GaimSrvResponse)); - g_free(g_list_first(ret)->data); - ret = g_list_remove(ret, g_list_first(ret)->data); + while (ret != NULL) + { + write(out, ret->data, sizeof(GaimSrvResponse)); + g_free(ret->data); + ret = g_list_remove(ret, ret->data); } - /* Should the resolver be reused? - * There is most likely only 1 SRV queries per prpl... - */ _exit(0); } -static void resolved(gpointer data, gint source, GaimInputCondition cond) { +static void +resolved(gpointer data, gint source, GaimInputCondition cond) +{ int size; - struct resdata *rdata = (struct resdata*)data; + GaimSrvQueryData *query_data = (GaimSrvQueryData*)data; GaimSrvResponse *res; GaimSrvResponse *tmp; int i; - GaimSRVCallback cb = rdata->cb; + GaimSrvCallback cb = query_data->cb; read(source, &size, sizeof(int)); - gaim_debug_info("srv","found %d SRV entries\n", size); + gaim_debug_info("dnssrv","found %d SRV entries\n", size); tmp = res = g_new0(GaimSrvResponse, size); - i = size; - while(i) { + for (i = 0; i < size; i++) { read(source, tmp++, sizeof(GaimSrvResponse)); - i--; } - cb(res, size, rdata->extradata); - gaim_input_remove(rdata->handle); - g_free(rdata); + + cb(res, size, query_data->extradata); + + gaim_srv_cancel(query_data); } #else /* _WIN32 */ /** The Jabber Server code was inspiration for parts of this. */ -static gboolean res_main_thread_cb(gpointer data) { +static gboolean +res_main_thread_cb(gpointer data) +{ GaimSrvResponse *srvres = NULL; int size = 0; - struct resdata *rdata = data; + GaimSrvQueryData *query_data = data; - if (rdata->errmsg != NULL) { - gaim_debug_error("srv", rdata->errmsg); - g_free(rdata->errmsg); + if (query_data->error_message != NULL) { + gaim_debug_error("dnssrv", query_data->error_message); } else { GaimSrvResponse *srvres_tmp; - GSList *lst = rdata->results; + GSList *lst = query_data->results; - size = g_slist_length(rdata->results); + size = g_slist_length(query_data->results); srvres_tmp = srvres = g_new0(GaimSrvResponse, size); while (lst) { @@ -215,29 +223,30 @@ lst = g_slist_remove(lst, lst->data); } - rdata->results = lst; + query_data->results = lst; } - gaim_debug_info("srv", "found %d SRV entries\n", size); + gaim_debug_info("dnssrv", "found %d SRV entries\n", size); - rdata->cb(srvres, size, rdata->extradata); + query_data->cb(srvres, size, query_data->extradata); - g_free(rdata->query); - g_free(rdata); + gaim_srv_cancel(query_data); return FALSE; } -static gpointer res_thread(gpointer data) { +static gpointer +res_thread(gpointer data) +{ PDNS_RECORD dr = NULL; int type = DNS_TYPE_SRV; DNS_STATUS ds; - struct resdata *rdata = data; + GaimSrvQueryData *query_data = data; - ds = MyDnsQuery_UTF8(rdata->query, type, DNS_QUERY_STANDARD, NULL, &dr, NULL); + ds = MyDnsQuery_UTF8(query_data->query, type, DNS_QUERY_STANDARD, NULL, &dr, NULL); if (ds != ERROR_SUCCESS) { gchar *msg = g_win32_error_message(ds); - rdata->errmsg = g_strdup_printf("Couldn't look up SRV record. %s (%lu).\n", msg, ds); + query_data->error_message = g_strdup_printf("Couldn't look up SRV record. %s (%lu).\n", msg, ds); g_free(msg); } else { PDNS_RECORD dr_tmp; @@ -247,7 +256,7 @@ for (dr_tmp = dr; dr_tmp != NULL; dr_tmp = dr_tmp->pNext) { /* Discard any incorrect entries. I'm not sure if this is necessary */ - if (dr_tmp->wType != type || strcmp(dr_tmp->pName, rdata->query) != 0) { + if (dr_tmp->wType != type || strcmp(dr_tmp->pName, query_data->query) != 0) { continue; } @@ -263,11 +272,11 @@ } MyDnsRecordListFree(dr, DnsFreeRecordList); - rdata->results = lst; + query_data->results = lst; } /* back to main thread */ - g_idle_add(res_main_thread_cb, rdata); + g_idle_add(res_main_thread_cb, query_data); g_thread_exit(NULL); return NULL; @@ -275,36 +284,41 @@ #endif -/* - * TODO: It would be really good if this returned some sort of handle - * that we could use to cancel the DNS query. As it is now, - * each callback has to check to make sure gc is still valid. - * And that is ugly. - */ -void gaim_srv_resolve(const char *protocol, const char *transport, const char *domain, GaimSRVCallback cb, gpointer extradata) { - char *query = g_strdup_printf("_%s._%s.%s",protocol, transport, domain); - struct resdata *rdata; +GaimSrvQueryData * +gaim_srv_resolve(const char *protocol, const char *transport, const char *domain, GaimSrvCallback cb, gpointer extradata) +{ + char *query; + GaimSrvQueryData *query_data; #ifndef _WIN32 int in[2], out[2]; int pid; - gaim_debug_info("srv","querying SRV record for %s\n", query); +#else + GError* err = NULL; + static gboolean initialized = FALSE; +#endif + +#ifndef _WIN32 + query = g_strdup_printf("_%s._%s.%s", protocol, transport, domain); + gaim_debug_info("dnssrv","querying SRV record for %s\n", query); + if(pipe(in) || pipe(out)) { - gaim_debug_error("srv", "Could not create pipe\n"); + gaim_debug_error("dnssrv", "Could not create pipe\n"); g_free(query); cb(NULL, 0, extradata); - return; + return NULL; } pid = fork(); - - if(pid == -1) { - gaim_debug_error("srv","Could not create process!\n"); + if (pid == -1) { + gaim_debug_error("dnssrv", "Could not create process!\n"); cb(NULL, 0, extradata); g_free(query); - return; + return NULL; } + /* Child */ - if( pid == 0 ) { + if (pid == 0) + { close(out[0]); close(in[1]); resolve(in[0], out[1]); @@ -313,22 +327,18 @@ close(out[1]); close(in[0]); - if(write(in[1], query, strlen(query)+1)<0) { - gaim_debug_error("srv", "Could not write to SRV resolver\n"); - } - rdata = g_new0(struct resdata,1); - rdata->cb = cb; - rdata->extradata = extradata; - rdata->handle = gaim_input_add(out[0], GAIM_INPUT_READ, resolved, rdata); + if (write(in[1], query, strlen(query)+1) < 0) + gaim_debug_error("dnssrv", "Could not write to SRV resolver\n"); + + query_data = g_new0(GaimSrvQueryData, 1); + query_data->cb = cb; + query_data->extradata = extradata; + query_data->handle = gaim_input_add(out[0], GAIM_INPUT_READ, resolved, query_data); g_free(query); + + return query_data; #else - GError* err = NULL; - - static gboolean initialized = FALSE; - - gaim_debug_info("srv","querying SRV record for %s\n", query); - if (!initialized) { MyDnsQuery_UTF8 = (void*) wgaim_find_and_loadproc("dnsapi.dll", "DnsQuery_UTF8"); MyDnsRecordListFree = (void*) wgaim_find_and_loadproc( @@ -337,22 +347,49 @@ } if (!MyDnsQuery_UTF8 || !MyDnsRecordListFree) { - gaim_debug_error("srv", "System missing DNS API (Requires W2K+)\n"); + gaim_debug_error("dnssrv", "System missing DNS API (Requires W2K+)\n"); g_free(query); cb(NULL, 0, extradata); - return; + return NULL; } - rdata = g_new0(struct resdata, 1); - rdata->cb = cb; - rdata->query = query; - rdata->extradata = extradata; + query_data = g_new0(GaimSrvQueryData, 1); + query_data->cb = cb; + query_data->query = query; + query_data->extradata = extradata; - if (!g_thread_create(res_thread, rdata, FALSE, &err)) { - rdata->errmsg = g_strdup_printf("SRV thread create failure: %s\n", err ? err->message : ""); + query_data->resolver = g_thread_create(res_thread, query_data, FALSE, &err); + if (query_data->resolver == NULL) + { + query_data->error_message = g_strdup_printf("SRV thread create failure: %s\n", err ? err->message : ""); g_error_free(err); - res_main_thread_cb(rdata); + res_main_thread_cb(query_data); + return NULL; } + + return query_data; #endif } +void +gaim_srv_cancel(GaimSrvQueryData *query_data) +{ +#ifndef _WIN32 + if (query_data->handle > 0) + gaim_input_remove(query_data->handle); +#else + if (query_data->resolver != NULL) + { + /* + * It's not really possible to kill a thread. So instead we + * just set the callback to NULL and let the DNS lookup + * finish. + */ + query_data->callback = NULL; + return; + } + g_free(query_data->query); + g_free(query_data->error_message); +#endif + g_free(query_data); +}
--- a/libgaim/dnssrv.h Wed Aug 23 07:14:19 2006 +0000 +++ b/libgaim/dnssrv.h Wed Aug 23 08:02:05 2006 +0000 @@ -1,10 +1,10 @@ /** * @file dnssrv.h - * + * * gaim * * Copyright (C) 2005, Thomas Butter <butter@uni-mannheim.de> - * + *i * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -24,6 +24,7 @@ #define _GAIM_DNSSRV_H typedef struct _GaimSrvResponse GaimSrvResponse; +typedef struct _GaimSrvQueryData GaimSrvQueryData; struct _GaimSrvResponse { char hostname[256]; @@ -32,17 +33,24 @@ int pref; }; -typedef void (*GaimSRVCallback)(GaimSrvResponse *resp, int results, gpointer data); +typedef void (*GaimSrvCallback)(GaimSrvResponse *resp, int results, gpointer data); /** * Queries an SRV record. * * @param protocol Name of the protocol (e.g. "sip") * @param transport Name of the transport ("tcp" or "udp") - * @param domain Domainname to query (e.g. "blubb.com") + * @param domain Domain name to query (e.g. "blubb.com") * @param cb A callback which will be called with the results * @param extradata Extra data to be passed to the callback */ -void gaim_srv_resolve(const char *protocol, const char *transport, const char *domain, GaimSRVCallback cb, gpointer extradata); +GaimSrvQueryData *gaim_srv_resolve(const char *protocol, const char *transport, const char *domain, GaimSrvCallback cb, gpointer extradata); + +/** + * Cancel an SRV DNS query. + * + * @param query_data The request to cancel. + */ +void gaim_srv_cancel(GaimSrvQueryData *query_data); #endif /* _GAIM_DNSSRV_H */
--- a/libgaim/protocols/jabber/jabber.c Wed Aug 23 07:14:19 2006 +0000 +++ b/libgaim/protocols/jabber/jabber.c Wed Aug 23 08:02:05 2006 +0000 @@ -486,18 +486,10 @@ static void srv_resolved_cb(GaimSrvResponse *resp, int results, gpointer data) { - GaimConnection *gc; JabberStream *js; - gc = data; - if (!GAIM_CONNECTION_IS_VALID(gc)) - { - /* This connection has been closed */ - g_free(resp); - return; - } - - js = (JabberStream*)gc->proto_data; + js = data; + js->srv_query_data = NULL; if(results) { jabber_login_connect(js, resp->hostname, resp->port); @@ -577,7 +569,8 @@ if(connect_server[0]) { jabber_login_connect(js, connect_server, gaim_account_get_int(account, "port", 5222)); } else { - gaim_srv_resolve("xmpp-client", "tcp", js->user->domain, srv_resolved_cb, gc); + js->srv_query_data = gaim_srv_resolve("xmpp-client", + "tcp", js->user->domain, srv_resolved_cb, js); } } } @@ -936,6 +929,9 @@ if (!gc->disconnect_timeout) jabber_send_raw(js, "</stream:stream>", -1); + if (js->srv_query_data) + gaim_srv_cancel(js->srv_query_data); + if (js->connect_data) gaim_proxy_connect_cancel(js->connect_data);
--- a/libgaim/protocols/jabber/jabber.h Wed Aug 23 07:14:19 2006 +0000 +++ b/libgaim/protocols/jabber/jabber.h Wed Aug 23 08:02:05 2006 +0000 @@ -28,6 +28,7 @@ #include <glib.h> #include "circbuffer.h" #include "connection.h" +#include "dnssrv.h" #include "roomlist.h" #include "sslconn.h" @@ -67,6 +68,7 @@ { int fd; + GaimSrvQueryData *srv_query_data; GaimProxyConnectData *connect_data; #ifdef HAVE_LIBXML
--- a/libgaim/protocols/simple/simple.c Wed Aug 23 07:14:19 2006 +0000 +++ b/libgaim/protocols/simple/simple.c Wed Aug 23 08:02:05 2006 +0000 @@ -1584,20 +1584,13 @@ } static void srvresolved(GaimSrvResponse *resp, int results, gpointer data) { - GaimConnection *gc; struct simple_account_data *sip; gchar *hostname; int port; - gc = data; - if (!GAIM_CONNECTION_IS_VALID(gc)) - { - /* This connection has been closed */ - g_free(resp); - return; - } + sip = data; + sip->srv_query_data = NULL; - sip = gc->proto_data; port = gaim_account_get_int(sip->account, "port", 0); /* find the host to connect to */ @@ -1682,12 +1675,8 @@ hosttoconnect = g_strdup(gaim_account_get_string(account, "proxy", sip->servername)); } - /* TCP case */ - if(!sip->udp) { - gaim_srv_resolve("sip", "tcp", hosttoconnect, srvresolved, gc); - } else { /* UDP */ - gaim_srv_resolve("sip", "udp", hosttoconnect, srvresolved, gc); - } + sip->srv_query_data = gaim_srv_resolve("sip", + sip->udp ? "udp" : "tcp", hosttoconnect, srvresolved, sip); g_free(hosttoconnect); } @@ -1703,6 +1692,9 @@ if (sip->query_data != NULL) gaim_dnsquery_destroy(sip->query_data); + if (sip->srv_query_data != NULL) + gaim_srv_cancel(sip->srv_query_data); + if (sip->listen_data != NULL) gaim_network_listen_cancel(sip->listen_data);
--- a/libgaim/protocols/simple/simple.h Wed Aug 23 07:14:19 2006 +0000 +++ b/libgaim/protocols/simple/simple.h Wed Aug 23 08:02:05 2006 +0000 @@ -29,6 +29,7 @@ #include "cipher.h" #include "circbuffer.h" #include "dnsquery.h" +#include "dnssrv.h" #include "network.h" #include "proxy.h" #include "prpl.h" @@ -73,6 +74,7 @@ gchar *username; gchar *password; GaimDnsQueryData *query_data; + GaimSrvQueryData *srv_query_data; GaimNetworkListenData *listen_data; int fd; int cseq;