Mercurial > hg > index.fcgi > gift-gnutella > gift-gnutella-0.0.11-1pba
comparison src/message/query_reply.c @ 0:d39e1d0d75b6
initial add
author | paulo@hit-nxdomain.opendns.com |
---|---|
date | Sat, 20 Feb 2010 21:18:28 -0800 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:00850cf11263 |
---|---|
1 /* | |
2 * $Id: query_reply.c,v 1.3 2004/03/24 06:35:10 hipnod Exp $ | |
3 * | |
4 * Copyright (C) 2001-2003 giFT project (gift.sourceforge.net) | |
5 * | |
6 * This program is free software; you can redistribute it and/or modify it | |
7 * under the terms of the GNU General Public License as published by the | |
8 * Free Software Foundation; either version 2, or (at your option) any | |
9 * later version. | |
10 * | |
11 * This program is distributed in the hope that it will be useful, but | |
12 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 * General Public License for more details. | |
15 */ | |
16 | |
17 #include "gt_gnutella.h" | |
18 #include "message/msg_handler.h" | |
19 | |
20 #include "sha1.h" | |
21 #include "xml.h" | |
22 | |
23 #include "gt_search.h" | |
24 | |
25 #include "gt_urn.h" | |
26 #include "gt_ban.h" | |
27 | |
28 #include "gt_share_file.h" | |
29 | |
30 #include <libgift/mime.h> | |
31 | |
32 /*****************************************************************************/ | |
33 | |
34 /* | |
35 * Whether to attach the number of hops each result travelled as a metadata | |
36 * field "Hops". Interesting to see but probably not too useful for the | |
37 * average user, and so disabled by default. | |
38 */ | |
39 #define HOPS_AS_META gt_config_get_int("search/hops_as_meta=0") | |
40 | |
41 /*****************************************************************************/ | |
42 | |
43 extern void gt_parse_extended_data (char *ext_block, gt_urn_t **r_urn, | |
44 Dataset **r_meta); /* query.c */ | |
45 | |
46 /*****************************************************************************/ | |
47 | |
48 static void add_meta (ds_data_t *key, ds_data_t *value, FileShare *file) | |
49 { | |
50 char *keystr = key->data; | |
51 char *valuestr = value->data; | |
52 | |
53 share_set_meta (file, keystr, valuestr); | |
54 } | |
55 | |
56 /* parse XML data right before the client guid */ | |
57 static void parse_xml_block (GtPacket *packet, size_t xml_bin_len, | |
58 Share **results, size_t hits) | |
59 { | |
60 int old_offset; | |
61 char *xml; | |
62 uint8_t savechr; | |
63 | |
64 /* if the length is one there is only the null terminator */ | |
65 if (xml_bin_len < 1) | |
66 return; | |
67 | |
68 /* | |
69 * Look for the XML before the client guid. Subtract the length of the | |
70 * client guid and the size of the XML. | |
71 */ | |
72 old_offset = gt_packet_seek (packet, packet->len - 16 - xml_bin_len); | |
73 | |
74 /* hopefully, if xml_bin_len is bogus this will fail */ | |
75 if (old_offset < 0) | |
76 return; | |
77 | |
78 xml = gt_packet_get_ustr (packet, xml_bin_len); | |
79 | |
80 if (!xml) | |
81 return; | |
82 | |
83 /* | |
84 * Null terminate the packet even if the remote end didn't. We know this | |
85 * is safe because the client GUID resides after the XML, and is 16 bytes | |
86 * long. | |
87 * | |
88 * Note that the null char should be at xml[xml_bin_len - 1], so we end up | |
89 * actually null-terminating twice if the XML is already terminated. | |
90 * gt_xml_parse_indexed must take this into account (and it does by | |
91 * largely ignoring xml_bin_len when the XML is plaintext). | |
92 */ | |
93 savechr = xml[xml_bin_len]; | |
94 xml[xml_bin_len] = 0; | |
95 | |
96 if (XML_DEBUG) | |
97 GT->dbg (GT, "xmldata=%s", xml); | |
98 | |
99 /* | |
100 * The XML before the client guid that we are parsing has a special | |
101 * property "index" indicating which share the XML property corresponds | |
102 * to, and so needs to be handled differently from XML appearing in | |
103 * each individual hit. | |
104 */ | |
105 gt_xml_parse_indexed (xml, xml_bin_len, results, hits); | |
106 | |
107 /* put the saved character back */ | |
108 xml[xml_bin_len] = savechr; | |
109 } | |
110 | |
111 /* | |
112 * Attach the travelled hops as a metadata field. | |
113 */ | |
114 static void attach_hops (Share *share, int hops) | |
115 { | |
116 char buf[12]; | |
117 | |
118 if (!HOPS_AS_META) | |
119 return; | |
120 | |
121 snprintf (buf, sizeof (buf) - 1, "%u", hops); | |
122 share_set_meta (share, "Hops", buf); | |
123 } | |
124 | |
125 void gt_query_hits_parse (GtPacket *packet, GtSearch *search, | |
126 TCPC *c, gt_guid_t *client_guid) | |
127 { | |
128 uint8_t count; | |
129 in_port_t port; | |
130 in_addr_t host; | |
131 uint32_t speed; | |
132 Share *results[255]; | |
133 uint16_t xml_len = 0; | |
134 int i, availability = 1; | |
135 BOOL firewalled = FALSE; | |
136 int total; | |
137 | |
138 count = gt_packet_get_uint8 (packet); | |
139 port = gt_packet_get_port (packet); | |
140 host = gt_packet_get_ip (packet); | |
141 speed = gt_packet_get_uint32 (packet); | |
142 | |
143 /* check if this host is banned */ | |
144 if (gt_ban_ipv4_is_banned (host)) | |
145 { | |
146 GT->dbg (GT, "discarding search results from %s [address banned]", | |
147 net_ip_str (host)); | |
148 return; | |
149 } | |
150 | |
151 for (i = 0; i < count; i++) | |
152 { | |
153 uint32_t index; | |
154 uint32_t size; | |
155 char *fname, *data; | |
156 gt_urn_t *urn = NULL; | |
157 Dataset *meta = NULL; | |
158 Share *file; | |
159 | |
160 index = gt_packet_get_uint32 (packet); | |
161 size = gt_packet_get_uint32 (packet); | |
162 fname = gt_packet_get_str (packet); | |
163 data = gt_packet_get_str (packet); | |
164 | |
165 /* If there was an error parsing the packet (not enough results), | |
166 * stop parsing */ | |
167 if (gt_packet_error (packet)) | |
168 break; | |
169 | |
170 if (!fname || string_isempty (fname)) | |
171 { | |
172 results[i] = NULL; | |
173 continue; | |
174 } | |
175 | |
176 gt_parse_extended_data (data, &urn, &meta); | |
177 | |
178 /* | |
179 * WARNING: calling gt_urn_data here assumes sha1. | |
180 * | |
181 * TODO: this is a potential bug if gt_share_new() makes assumptions | |
182 * about the hash data's size and gt_urn_t changes to be multiple | |
183 * sizes later. | |
184 */ | |
185 if (!(file = gt_share_new (fname, index, size, gt_urn_data (urn)))) | |
186 { | |
187 GIFT_ERROR (("error making fileshare, why?")); | |
188 | |
189 dataset_clear (meta); | |
190 free (urn); | |
191 | |
192 /* make sure we find out about it if we're missing results ;) */ | |
193 assert (0); | |
194 | |
195 results[i] = NULL; | |
196 continue; | |
197 } | |
198 | |
199 /* HACK: set the mimetype from the file extension */ | |
200 share_set_mime (file, mime_type (fname)); | |
201 | |
202 dataset_foreach (meta, DS_FOREACH(add_meta), file); | |
203 | |
204 /* Attach the hops the search travelled as a metadata field */ | |
205 attach_hops (file, gt_packet_hops (packet)); | |
206 | |
207 dataset_clear (meta); | |
208 free (urn); | |
209 | |
210 results[i] = file; | |
211 } | |
212 | |
213 total = i; | |
214 | |
215 /* look for the query hit descriptor */ | |
216 if (!gt_packet_error (packet) && | |
217 packet->len - packet->offset >= 16 + 7 /* min qhd len */) | |
218 { | |
219 unsigned char *vendor; | |
220 uint8_t eqhd_len; | |
221 uint8_t eqhd[2]; | |
222 | |
223 vendor = gt_packet_get_ustr (packet, 4); | |
224 eqhd_len = gt_packet_get_uint8 (packet); | |
225 eqhd[0] = gt_packet_get_uint8 (packet); | |
226 eqhd[1] = gt_packet_get_uint8 (packet); | |
227 | |
228 /* set availability to 0 or 1 depending on the busy flag */ | |
229 availability = ((eqhd[0] & EQHD1_HAS_BUSY) && | |
230 !(eqhd[1] & EQHD2_BUSY_FLAG)) ? 1 : 0; | |
231 | |
232 /* set firewalled status based on the PUSH flag */ | |
233 firewalled = BOOL_EXPR ((eqhd[0] & EQHD1_PUSH_FLAG) && | |
234 (eqhd[1] & EQHD2_HAS_PUSH)); | |
235 | |
236 /* | |
237 * Check for an XML metadata block, that is usually present | |
238 * when the size of the "public area" is 4 | |
239 */ | |
240 if (eqhd_len >= 4) | |
241 xml_len = gt_packet_get_uint16 (packet); | |
242 | |
243 if (xml_len > 0) | |
244 { | |
245 if (XML_DEBUG) | |
246 { | |
247 char str[5] = { 0 }; | |
248 | |
249 if (vendor) | |
250 memcpy (str, vendor, 4); | |
251 | |
252 GT->dbg (GT, "(%s) xml_len=%d", str, xml_len); | |
253 } | |
254 | |
255 parse_xml_block (packet, xml_len, results, total); | |
256 } | |
257 | |
258 #if 0 | |
259 if (MSG_DEBUG) | |
260 { | |
261 GT->DBGFN (GT, "vendor = %s, qhd_len = %u, qhd_0 = %x, qhd_1 = %x," | |
262 " availability = %i, firewalled = %i", | |
263 make_str (vendor, 4), qhd_len, qhd[0], qhd[1], | |
264 availability, firewalled); | |
265 } | |
266 #endif | |
267 } | |
268 | |
269 /* send the results to the interface protocol */ | |
270 for (i = 0; i < total; i++) | |
271 { | |
272 if (results[i]) | |
273 { | |
274 gt_search_reply (search, c, host, port, client_guid, availability, | |
275 firewalled, results[i]); | |
276 | |
277 gt_share_unref (results[i]); | |
278 } | |
279 } | |
280 } | |
281 | |
282 /* should split this up into two routines */ | |
283 GT_MSG_HANDLER(gt_msg_query_reply) | |
284 { | |
285 GtSearch *search; | |
286 int save_offset; | |
287 gt_guid_t *client_guid; | |
288 | |
289 /* Each client has a unique identifier at the end of the | |
290 * packet. Grab that first. */ | |
291 if (packet->len < 16) | |
292 { | |
293 if (MSG_DEBUG) | |
294 GT->DBGSOCK (GT, c, "illegal query response packet, < 16 bytes"); | |
295 | |
296 return; | |
297 } | |
298 | |
299 /* hack the offset in the packet */ | |
300 save_offset = packet->offset; | |
301 packet->offset = packet->len - 16; | |
302 | |
303 client_guid = gt_packet_get_ustr (packet, 16); | |
304 | |
305 /* put the offset back */ | |
306 packet->offset = save_offset; | |
307 | |
308 if (!(search = gt_search_find (gt_packet_guid (packet))) | |
309 /*&& query_cache_lookup (packet->guid)*/) | |
310 { | |
311 /* TODO: support forwarding of query responses by | |
312 * looking up their destinations in the guid cache */ | |
313 | |
314 /*gt_route_forward_packet (packet, c);*/ | |
315 | |
316 /* add the client GUID to the push cache: in case of a | |
317 * push request we know where to send it */ | |
318 /*push_cache_add (client_guid, c);*/ | |
319 | |
320 return; | |
321 } | |
322 | |
323 gt_query_hits_parse (packet, search, c, client_guid); | |
324 } |