diff -r d10dda2777a9 -r b63ebf84c42b src/dnssrv.c --- a/src/dnssrv.c Sat Aug 19 00:24:14 2006 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,358 +0,0 @@ -/** - * @file dnssrv.c - * - * gaim - * - * Copyright (C) 2005 Thomas Butter - * - * 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 - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "internal.h" - -#ifndef _WIN32 -#include -#include -#ifdef HAVE_ARPA_NAMESER_COMPAT_H -#include -#endif -#ifndef T_SRV -#define T_SRV 33 -#endif -#else -#include -/* Missing from the mingw headers */ -#ifndef DNS_TYPE_SRV -# define DNS_TYPE_SRV 33 -#endif -#endif - -#include "dnssrv.h" -#include "eventloop.h" -#include "debug.h" - -#ifndef _WIN32 -typedef union { - HEADER hdr; - u_char buf[1024]; -} queryans; -#else -static DNS_STATUS WINAPI (*MyDnsQuery_UTF8) ( - PCSTR lpstrName, WORD wType, DWORD fOptions, - PIP4_ARRAY aipServers, PDNS_RECORD* ppQueryResultsSet, - PVOID* pReserved) = NULL; -static void WINAPI (*MyDnsRecordListFree) (PDNS_RECORD pRecordList, - DNS_FREE_TYPE FreeType) = NULL; -#endif - -struct resdata { - GaimSRVCallback cb; - gpointer extradata; -#ifndef _WIN32 - guint handle; -#else - char *query; - char *errmsg; - GSList *results; -#endif -}; - -static gint responsecompare(gconstpointer ar, gconstpointer br) { - GaimSrvResponse *a = (GaimSrvResponse*)ar; - GaimSrvResponse *b = (GaimSrvResponse*)br; - - if(a->pref == b->pref) { - if(a->weight == b->weight) - return 0; - if(a->weight < b->weight) - return -1; - return 1; - } - if(a->pref < b->pref) - return -1; - return 1; -} -#ifndef _WIN32 -static void resolve(int in, int out) { - GList *ret = NULL; - GaimSrvResponse *srvres; - queryans answer; - int size; - int qdcount; - int ancount; - guchar *end; - guchar *cp; - gchar name[256]; - guint16 type, dlen, pref, weight, port; - gchar query[256]; - - 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; - - /* skip over unwanted stuff */ - while (qdcount-- > 0 && cp < end) { - size = dn_expand( (unsigned char*)&answer, end, cp, name, 256); - if(size < 0) goto end; - cp += size + QFIXEDSZ; - } - - while (ancount-- > 0 && cp < end) { - size = dn_expand((unsigned char*)&answer, end, cp, name, 256); - if(size < 0) - goto end; - - cp += size; - - GETSHORT(type,cp); - - /* skip ttl and class since we already know it */ - cp += 6; - - GETSHORT(dlen,cp); - - if (type == T_SRV) { - GETSHORT(pref,cp); - - GETSHORT(weight,cp); - - GETSHORT(port,cp); - - size = dn_expand( (unsigned char*)&answer, end, cp, name, 256); - if(size < 0 ) - goto end; - - cp += size; - - srvres = g_new0(GaimSrvResponse, 1); - strcpy(srvres->hostname, name); - srvres->pref = pref; - srvres->port = port; - srvres->weight = weight; - - ret = g_list_insert_sorted(ret, srvres, responsecompare); - } else { - cp += dlen; - } - } -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); - } - - /* 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) { - int size; - struct resdata *rdata = (struct resdata*)data; - GaimSrvResponse *res; - GaimSrvResponse *tmp; - int i; - GaimSRVCallback cb = rdata->cb; - - read(source, &size, sizeof(int)); - gaim_debug_info("srv","found %d SRV entries\n", size); - tmp = res = g_new0(GaimSrvResponse, size); - i = size; - while(i) { - read(source, tmp++, sizeof(GaimSrvResponse)); - i--; - } - cb(res, size, rdata->extradata); - gaim_input_remove(rdata->handle); - g_free(rdata); -} - -#else /* _WIN32 */ - -/** The Jabber Server code was inspiration for parts of this. */ - -static gboolean res_main_thread_cb(gpointer data) { - GaimSrvResponse *srvres = NULL; - int size = 0; - struct resdata *rdata = data; - - if (rdata->errmsg != NULL) { - gaim_debug_error("srv", rdata->errmsg); - g_free(rdata->errmsg); - } else { - GaimSrvResponse *srvres_tmp; - GSList *lst = rdata->results; - - size = g_slist_length(rdata->results); - - srvres_tmp = srvres = g_new0(GaimSrvResponse, size); - while (lst) { - memcpy(srvres_tmp++, lst->data, sizeof(GaimSrvResponse)); - g_free(lst->data); - lst = g_slist_remove(lst, lst->data); - } - - rdata->results = lst; - } - - gaim_debug_info("srv", "found %d SRV entries\n", size); - - rdata->cb(srvres, size, rdata->extradata); - - g_free(rdata->query); - g_free(rdata); - - return FALSE; -} - -static gpointer res_thread(gpointer data) { - PDNS_RECORD dr = NULL; - int type = DNS_TYPE_SRV; - DNS_STATUS ds; - struct resdata *rdata = data; - - ds = MyDnsQuery_UTF8(rdata->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); - g_free(msg); - } else { - PDNS_RECORD dr_tmp; - GSList *lst = NULL; - DNS_SRV_DATA *srv_data; - GaimSrvResponse *srvres; - - 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) { - continue; - } - - srv_data = &dr_tmp->Data.SRV; - srvres = g_new0(GaimSrvResponse, 1); - strncpy(srvres->hostname, srv_data->pNameTarget, 255); - srvres->hostname[255] = '\0'; - srvres->pref = srv_data->wPriority; - srvres->port = srv_data->wPort; - srvres->weight = srv_data->wWeight; - - lst = g_slist_insert_sorted(lst, srvres, responsecompare); - } - - MyDnsRecordListFree(dr, DnsFreeRecordList); - rdata->results = lst; - } - - /* back to main thread */ - g_idle_add(res_main_thread_cb, rdata); - - g_thread_exit(NULL); - return NULL; -} - -#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; -#ifndef _WIN32 - int in[2], out[2]; - int pid; - gaim_debug_info("srv","querying SRV record for %s\n", query); - if(pipe(in) || pipe(out)) { - gaim_debug_error("srv", "Could not create pipe\n"); - g_free(query); - cb(NULL, 0, extradata); - return; - } - - pid = fork(); - - if(pid == -1) { - gaim_debug_error("srv","Could not create process!\n"); - cb(NULL, 0, extradata); - g_free(query); - return; - } - /* Child */ - if( pid == 0 ) { - close(out[0]); - close(in[1]); - resolve(in[0], out[1]); - } - - 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); - - g_free(query); -#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( - "dnsapi.dll", "DnsRecordListFree"); - initialized = TRUE; - } - - if (!MyDnsQuery_UTF8 || !MyDnsRecordListFree) { - gaim_debug_error("srv", "System missing DNS API (Requires W2K+)\n"); - g_free(query); - cb(NULL, 0, extradata); - return; - } - - rdata = g_new0(struct resdata, 1); - rdata->cb = cb; - rdata->query = query; - rdata->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 : ""); - g_error_free(err); - res_main_thread_cb(rdata); - } -#endif -} -