Mercurial > hg > index.fcgi > gift-gnutella > gift-gnutella-0.0.11-1pba
diff 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 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/message/query_reply.c Sat Feb 20 21:18:28 2010 -0800 1.3 @@ -0,0 +1,324 @@ 1.4 +/* 1.5 + * $Id: query_reply.c,v 1.3 2004/03/24 06:35:10 hipnod Exp $ 1.6 + * 1.7 + * Copyright (C) 2001-2003 giFT project (gift.sourceforge.net) 1.8 + * 1.9 + * This program is free software; you can redistribute it and/or modify it 1.10 + * under the terms of the GNU General Public License as published by the 1.11 + * Free Software Foundation; either version 2, or (at your option) any 1.12 + * later version. 1.13 + * 1.14 + * This program is distributed in the hope that it will be useful, but 1.15 + * WITHOUT ANY WARRANTY; without even the implied warranty of 1.16 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1.17 + * General Public License for more details. 1.18 + */ 1.19 + 1.20 +#include "gt_gnutella.h" 1.21 +#include "message/msg_handler.h" 1.22 + 1.23 +#include "sha1.h" 1.24 +#include "xml.h" 1.25 + 1.26 +#include "gt_search.h" 1.27 + 1.28 +#include "gt_urn.h" 1.29 +#include "gt_ban.h" 1.30 + 1.31 +#include "gt_share_file.h" 1.32 + 1.33 +#include <libgift/mime.h> 1.34 + 1.35 +/*****************************************************************************/ 1.36 + 1.37 +/* 1.38 + * Whether to attach the number of hops each result travelled as a metadata 1.39 + * field "Hops". Interesting to see but probably not too useful for the 1.40 + * average user, and so disabled by default. 1.41 + */ 1.42 +#define HOPS_AS_META gt_config_get_int("search/hops_as_meta=0") 1.43 + 1.44 +/*****************************************************************************/ 1.45 + 1.46 +extern void gt_parse_extended_data (char *ext_block, gt_urn_t **r_urn, 1.47 + Dataset **r_meta); /* query.c */ 1.48 + 1.49 +/*****************************************************************************/ 1.50 + 1.51 +static void add_meta (ds_data_t *key, ds_data_t *value, FileShare *file) 1.52 +{ 1.53 + char *keystr = key->data; 1.54 + char *valuestr = value->data; 1.55 + 1.56 + share_set_meta (file, keystr, valuestr); 1.57 +} 1.58 + 1.59 +/* parse XML data right before the client guid */ 1.60 +static void parse_xml_block (GtPacket *packet, size_t xml_bin_len, 1.61 + Share **results, size_t hits) 1.62 +{ 1.63 + int old_offset; 1.64 + char *xml; 1.65 + uint8_t savechr; 1.66 + 1.67 + /* if the length is one there is only the null terminator */ 1.68 + if (xml_bin_len < 1) 1.69 + return; 1.70 + 1.71 + /* 1.72 + * Look for the XML before the client guid. Subtract the length of the 1.73 + * client guid and the size of the XML. 1.74 + */ 1.75 + old_offset = gt_packet_seek (packet, packet->len - 16 - xml_bin_len); 1.76 + 1.77 + /* hopefully, if xml_bin_len is bogus this will fail */ 1.78 + if (old_offset < 0) 1.79 + return; 1.80 + 1.81 + xml = gt_packet_get_ustr (packet, xml_bin_len); 1.82 + 1.83 + if (!xml) 1.84 + return; 1.85 + 1.86 + /* 1.87 + * Null terminate the packet even if the remote end didn't. We know this 1.88 + * is safe because the client GUID resides after the XML, and is 16 bytes 1.89 + * long. 1.90 + * 1.91 + * Note that the null char should be at xml[xml_bin_len - 1], so we end up 1.92 + * actually null-terminating twice if the XML is already terminated. 1.93 + * gt_xml_parse_indexed must take this into account (and it does by 1.94 + * largely ignoring xml_bin_len when the XML is plaintext). 1.95 + */ 1.96 + savechr = xml[xml_bin_len]; 1.97 + xml[xml_bin_len] = 0; 1.98 + 1.99 + if (XML_DEBUG) 1.100 + GT->dbg (GT, "xmldata=%s", xml); 1.101 + 1.102 + /* 1.103 + * The XML before the client guid that we are parsing has a special 1.104 + * property "index" indicating which share the XML property corresponds 1.105 + * to, and so needs to be handled differently from XML appearing in 1.106 + * each individual hit. 1.107 + */ 1.108 + gt_xml_parse_indexed (xml, xml_bin_len, results, hits); 1.109 + 1.110 + /* put the saved character back */ 1.111 + xml[xml_bin_len] = savechr; 1.112 +} 1.113 + 1.114 +/* 1.115 + * Attach the travelled hops as a metadata field. 1.116 + */ 1.117 +static void attach_hops (Share *share, int hops) 1.118 +{ 1.119 + char buf[12]; 1.120 + 1.121 + if (!HOPS_AS_META) 1.122 + return; 1.123 + 1.124 + snprintf (buf, sizeof (buf) - 1, "%u", hops); 1.125 + share_set_meta (share, "Hops", buf); 1.126 +} 1.127 + 1.128 +void gt_query_hits_parse (GtPacket *packet, GtSearch *search, 1.129 + TCPC *c, gt_guid_t *client_guid) 1.130 +{ 1.131 + uint8_t count; 1.132 + in_port_t port; 1.133 + in_addr_t host; 1.134 + uint32_t speed; 1.135 + Share *results[255]; 1.136 + uint16_t xml_len = 0; 1.137 + int i, availability = 1; 1.138 + BOOL firewalled = FALSE; 1.139 + int total; 1.140 + 1.141 + count = gt_packet_get_uint8 (packet); 1.142 + port = gt_packet_get_port (packet); 1.143 + host = gt_packet_get_ip (packet); 1.144 + speed = gt_packet_get_uint32 (packet); 1.145 + 1.146 + /* check if this host is banned */ 1.147 + if (gt_ban_ipv4_is_banned (host)) 1.148 + { 1.149 + GT->dbg (GT, "discarding search results from %s [address banned]", 1.150 + net_ip_str (host)); 1.151 + return; 1.152 + } 1.153 + 1.154 + for (i = 0; i < count; i++) 1.155 + { 1.156 + uint32_t index; 1.157 + uint32_t size; 1.158 + char *fname, *data; 1.159 + gt_urn_t *urn = NULL; 1.160 + Dataset *meta = NULL; 1.161 + Share *file; 1.162 + 1.163 + index = gt_packet_get_uint32 (packet); 1.164 + size = gt_packet_get_uint32 (packet); 1.165 + fname = gt_packet_get_str (packet); 1.166 + data = gt_packet_get_str (packet); 1.167 + 1.168 + /* If there was an error parsing the packet (not enough results), 1.169 + * stop parsing */ 1.170 + if (gt_packet_error (packet)) 1.171 + break; 1.172 + 1.173 + if (!fname || string_isempty (fname)) 1.174 + { 1.175 + results[i] = NULL; 1.176 + continue; 1.177 + } 1.178 + 1.179 + gt_parse_extended_data (data, &urn, &meta); 1.180 + 1.181 + /* 1.182 + * WARNING: calling gt_urn_data here assumes sha1. 1.183 + * 1.184 + * TODO: this is a potential bug if gt_share_new() makes assumptions 1.185 + * about the hash data's size and gt_urn_t changes to be multiple 1.186 + * sizes later. 1.187 + */ 1.188 + if (!(file = gt_share_new (fname, index, size, gt_urn_data (urn)))) 1.189 + { 1.190 + GIFT_ERROR (("error making fileshare, why?")); 1.191 + 1.192 + dataset_clear (meta); 1.193 + free (urn); 1.194 + 1.195 + /* make sure we find out about it if we're missing results ;) */ 1.196 + assert (0); 1.197 + 1.198 + results[i] = NULL; 1.199 + continue; 1.200 + } 1.201 + 1.202 + /* HACK: set the mimetype from the file extension */ 1.203 + share_set_mime (file, mime_type (fname)); 1.204 + 1.205 + dataset_foreach (meta, DS_FOREACH(add_meta), file); 1.206 + 1.207 + /* Attach the hops the search travelled as a metadata field */ 1.208 + attach_hops (file, gt_packet_hops (packet)); 1.209 + 1.210 + dataset_clear (meta); 1.211 + free (urn); 1.212 + 1.213 + results[i] = file; 1.214 + } 1.215 + 1.216 + total = i; 1.217 + 1.218 + /* look for the query hit descriptor */ 1.219 + if (!gt_packet_error (packet) && 1.220 + packet->len - packet->offset >= 16 + 7 /* min qhd len */) 1.221 + { 1.222 + unsigned char *vendor; 1.223 + uint8_t eqhd_len; 1.224 + uint8_t eqhd[2]; 1.225 + 1.226 + vendor = gt_packet_get_ustr (packet, 4); 1.227 + eqhd_len = gt_packet_get_uint8 (packet); 1.228 + eqhd[0] = gt_packet_get_uint8 (packet); 1.229 + eqhd[1] = gt_packet_get_uint8 (packet); 1.230 + 1.231 + /* set availability to 0 or 1 depending on the busy flag */ 1.232 + availability = ((eqhd[0] & EQHD1_HAS_BUSY) && 1.233 + !(eqhd[1] & EQHD2_BUSY_FLAG)) ? 1 : 0; 1.234 + 1.235 + /* set firewalled status based on the PUSH flag */ 1.236 + firewalled = BOOL_EXPR ((eqhd[0] & EQHD1_PUSH_FLAG) && 1.237 + (eqhd[1] & EQHD2_HAS_PUSH)); 1.238 + 1.239 + /* 1.240 + * Check for an XML metadata block, that is usually present 1.241 + * when the size of the "public area" is 4 1.242 + */ 1.243 + if (eqhd_len >= 4) 1.244 + xml_len = gt_packet_get_uint16 (packet); 1.245 + 1.246 + if (xml_len > 0) 1.247 + { 1.248 + if (XML_DEBUG) 1.249 + { 1.250 + char str[5] = { 0 }; 1.251 + 1.252 + if (vendor) 1.253 + memcpy (str, vendor, 4); 1.254 + 1.255 + GT->dbg (GT, "(%s) xml_len=%d", str, xml_len); 1.256 + } 1.257 + 1.258 + parse_xml_block (packet, xml_len, results, total); 1.259 + } 1.260 + 1.261 +#if 0 1.262 + if (MSG_DEBUG) 1.263 + { 1.264 + GT->DBGFN (GT, "vendor = %s, qhd_len = %u, qhd_0 = %x, qhd_1 = %x," 1.265 + " availability = %i, firewalled = %i", 1.266 + make_str (vendor, 4), qhd_len, qhd[0], qhd[1], 1.267 + availability, firewalled); 1.268 + } 1.269 +#endif 1.270 + } 1.271 + 1.272 + /* send the results to the interface protocol */ 1.273 + for (i = 0; i < total; i++) 1.274 + { 1.275 + if (results[i]) 1.276 + { 1.277 + gt_search_reply (search, c, host, port, client_guid, availability, 1.278 + firewalled, results[i]); 1.279 + 1.280 + gt_share_unref (results[i]); 1.281 + } 1.282 + } 1.283 +} 1.284 + 1.285 +/* should split this up into two routines */ 1.286 +GT_MSG_HANDLER(gt_msg_query_reply) 1.287 +{ 1.288 + GtSearch *search; 1.289 + int save_offset; 1.290 + gt_guid_t *client_guid; 1.291 + 1.292 + /* Each client has a unique identifier at the end of the 1.293 + * packet. Grab that first. */ 1.294 + if (packet->len < 16) 1.295 + { 1.296 + if (MSG_DEBUG) 1.297 + GT->DBGSOCK (GT, c, "illegal query response packet, < 16 bytes"); 1.298 + 1.299 + return; 1.300 + } 1.301 + 1.302 + /* hack the offset in the packet */ 1.303 + save_offset = packet->offset; 1.304 + packet->offset = packet->len - 16; 1.305 + 1.306 + client_guid = gt_packet_get_ustr (packet, 16); 1.307 + 1.308 + /* put the offset back */ 1.309 + packet->offset = save_offset; 1.310 + 1.311 + if (!(search = gt_search_find (gt_packet_guid (packet))) 1.312 + /*&& query_cache_lookup (packet->guid)*/) 1.313 + { 1.314 + /* TODO: support forwarding of query responses by 1.315 + * looking up their destinations in the guid cache */ 1.316 + 1.317 + /*gt_route_forward_packet (packet, c);*/ 1.318 + 1.319 + /* add the client GUID to the push cache: in case of a 1.320 + * push request we know where to send it */ 1.321 + /*push_cache_add (client_guid, c);*/ 1.322 + 1.323 + return; 1.324 + } 1.325 + 1.326 + gt_query_hits_parse (packet, search, c, client_guid); 1.327 +}