Mercurial > pidgin
comparison src/dnssrv.c @ 11373:c84c35ee8202
[gaim-migrate @ 13598]
adding async SRV resolver
committer: Tailor Script <tailor@pidgin.im>
author | Thomas Butter <tbutter> |
---|---|
date | Tue, 30 Aug 2005 15:28:49 +0000 |
parents | |
children | 51c189755f1d |
comparison
equal
deleted
inserted
replaced
11372:aea5faca82dc | 11373:c84c35ee8202 |
---|---|
1 /** | |
2 * @file srvresolve.c | |
3 * | |
4 * gaim | |
5 * | |
6 * Copyright (C) 2005 Thomas Butter <butter@uni-mannheim.de> | |
7 * | |
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. | |
12 * | |
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. | |
17 * | |
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 | |
21 */ | |
22 #include <glib.h> | |
23 #include <resolv.h> | |
24 #include <stdlib.h> | |
25 #include <arpa/nameser_compat.h> | |
26 #ifndef T_SRV | |
27 #define T_SRV 33 | |
28 #endif | |
29 | |
30 #include "dnssrv.h" | |
31 #include <stdio.h> | |
32 #include <unistd.h> | |
33 #include <string.h> | |
34 #include "eventloop.h" | |
35 #include "debug.h" | |
36 | |
37 typedef union { | |
38 HEADER hdr; | |
39 u_char buf[1024]; | |
40 } queryans; | |
41 | |
42 struct resdata { | |
43 SRVCallback cb; | |
44 guint handle; | |
45 }; | |
46 | |
47 static gint responsecompare(gconstpointer ar, gconstpointer br) { | |
48 struct srv_response *a = (struct srv_response*)ar; | |
49 struct srv_response *b = (struct srv_response*)br; | |
50 | |
51 if(a->pref == b->pref) { | |
52 if(a->weight == b->weight) | |
53 return 0; | |
54 if(a->weight < b->weight) | |
55 return -1; | |
56 return 1; | |
57 } | |
58 if(a->pref < b->pref) | |
59 return -1; | |
60 return 1; | |
61 } | |
62 | |
63 static void resolve(int in, int out) { | |
64 GList *ret = NULL; | |
65 struct srv_response *srvres; | |
66 queryans answer; | |
67 int size; | |
68 int qdcount; | |
69 int ancount; | |
70 gchar *end; | |
71 gchar *cp; | |
72 gchar name[256]; | |
73 int type, dlen, pref, weight, port; | |
74 gchar query[256]; | |
75 | |
76 if(read(in, query, 256) <= 0) { | |
77 _exit(0); | |
78 } | |
79 size = res_query( query, C_IN, T_SRV, (u_char*)&answer, sizeof( answer)); | |
80 | |
81 qdcount = ntohs(answer.hdr.qdcount); | |
82 ancount = ntohs(answer.hdr.ancount); | |
83 | |
84 | |
85 cp = (char*)&answer + sizeof(HEADER); | |
86 end = (char*)&answer + size; | |
87 | |
88 /* skip over unwanted stuff */ | |
89 while (qdcount-- > 0 && cp < end) { | |
90 size = dn_expand( (char*)&answer, end, cp, name, 256); | |
91 if(size < 0) goto end; | |
92 cp += size + QFIXEDSZ; | |
93 } | |
94 | |
95 while (ancount-- > 0 && cp < end) { | |
96 size = dn_expand((char*)&answer, end, cp, name, 256); | |
97 if(size < 0) | |
98 goto end; | |
99 | |
100 cp += size; | |
101 | |
102 NS_GET16(type,cp); | |
103 cp += 6; /* skip ttl and class since we already know it */ | |
104 | |
105 NS_GET16(dlen,cp); | |
106 | |
107 if (type == T_SRV) { | |
108 NS_GET16(pref,cp); | |
109 | |
110 NS_GET16(weight, cp); | |
111 | |
112 NS_GET16(port, cp); | |
113 | |
114 size = dn_expand( (char*)&answer, end, cp, name, 256); | |
115 if(size < 0 ) | |
116 goto end; | |
117 | |
118 cp += size; | |
119 | |
120 srvres = g_new0(struct srv_response,1); | |
121 strcpy(srvres->hostname, name); | |
122 srvres->pref = pref; | |
123 srvres->port = port; | |
124 srvres->weight = weight; | |
125 | |
126 ret = g_list_insert_sorted(ret, srvres, responsecompare); | |
127 } else { | |
128 cp += dlen; | |
129 } | |
130 } | |
131 end: size = g_list_length(ret); | |
132 write(out, &size, 4); | |
133 while(g_list_first(ret)) { | |
134 write(out, g_list_first(ret)->data, sizeof(struct srv_response)); | |
135 g_free(g_list_first(ret)->data); | |
136 ret = g_list_remove(ret, g_list_first(ret)->data); | |
137 } | |
138 | |
139 /* Should the resolver be reused? | |
140 * There is most likely only 1 SRV queries per prpl... | |
141 */ | |
142 _exit(0); | |
143 } | |
144 | |
145 static void resolved(gpointer data, gint source, GaimInputCondition cond) { | |
146 int size; | |
147 struct resdata *rdata = (struct resdata*)data; | |
148 struct srv_response *res; | |
149 struct srv_response *tmp; | |
150 SRVCallback cb = rdata->cb; | |
151 | |
152 read(source, &size, 4); | |
153 gaim_debug_info("srv","found %d SRV entries\n", size); | |
154 tmp = res = g_malloc0(sizeof(struct srv_response)*size); | |
155 while(size) { | |
156 read(source, tmp++, sizeof(struct srv_response)); | |
157 size--; | |
158 } | |
159 cb(res, size); | |
160 gaim_input_remove(rdata->handle); | |
161 g_free(rdata); | |
162 } | |
163 | |
164 void gaim_srv_resolve(char *protocol, char *transport, char *domain, SRVCallback cb) { | |
165 char *query = g_strdup_printf("_%s._%s.%s",protocol, transport, domain); | |
166 int in[2], out[2]; | |
167 int pid; | |
168 struct resdata *rdata; | |
169 gaim_debug_info("dnssrv","querying SRV record for %s\n",query); | |
170 if(pipe(in) || pipe(out)) { | |
171 gaim_debug_error("srv", "Could not create pipe\n"); | |
172 g_free(query); | |
173 cb(NULL, 0); | |
174 return; | |
175 } | |
176 | |
177 pid = fork(); | |
178 | |
179 if(pid == -1) { | |
180 gaim_debug_error("srv","Could not create process!\n"); | |
181 cb(NULL, 0); | |
182 g_free(query); | |
183 return; | |
184 } | |
185 /* Child */ | |
186 if( pid == 0 ) { | |
187 close(out[0]); | |
188 close(in[1]); | |
189 resolve(in[0], out[1]); | |
190 } | |
191 | |
192 close(out[1]); | |
193 close(in[0]); | |
194 | |
195 if(write(in[1], query, strlen(query)+1)<0) { | |
196 gaim_debug_error("srv", "Could not write to SRV resolver\n"); | |
197 } | |
198 rdata = g_new0(struct resdata,1); | |
199 rdata->cb = cb; | |
200 rdata->handle = gaim_input_add(out[0], GAIM_INPUT_READ, resolved, rdata); | |
201 g_free(query); | |
202 } |