Mercurial > hg > index.fcgi > gift-gnutella > gift-gnutella-0.0.11-1pba
diff src/gt_share.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/gt_share.c Sat Feb 20 21:18:28 2010 -0800 1.3 @@ -0,0 +1,384 @@ 1.4 +/* 1.5 + * $Id: gt_share.c,v 1.35 2004/03/26 11:53:18 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 "sha1.h" 1.22 + 1.23 +#include "gt_share.h" 1.24 +#include "gt_share_file.h" 1.25 +#include "gt_query_route.h" 1.26 +#include "gt_search.h" 1.27 +#include "gt_search_exec.h" 1.28 + 1.29 +#include "encoding/url.h" 1.30 + 1.31 +/******************************************************************************/ 1.32 + 1.33 +#define SHARE_DEBUG gt_config_get_int("share/debug=0") 1.34 + 1.35 +/*****************************************************************************/ 1.36 + 1.37 +/* each share is assigned an index here */ 1.38 +static Dataset *indices; 1.39 + 1.40 +/* maps binary sha1 hashes -> FileShares */ 1.41 +static Dataset *sha1_hashes; 1.42 + 1.43 +/* stored index of the last index assigned */ 1.44 +static uint32_t index_counter; 1.45 + 1.46 +/* whether shares have been completely synchronized yet */ 1.47 +static BOOL sync_begun; 1.48 + 1.49 +/* if shares are currently being synced */ 1.50 +static BOOL sync_done; 1.51 + 1.52 +/******************************************************************************/ 1.53 + 1.54 +static void add_hash (FileShare *file); 1.55 +static void remove_hash (FileShare *file); 1.56 + 1.57 +/******************************************************************************/ 1.58 + 1.59 +/* 1.60 + * Find the old index, using the SHA1 hash as a key. 1.61 + */ 1.62 +static uint32_t get_old_index (Hash *hash) 1.63 +{ 1.64 + Share *old_share; 1.65 + uint32_t index = 0; 1.66 + 1.67 + old_share = dataset_lookup (sha1_hashes, hash->data, SHA1_BINSIZE); 1.68 + if (old_share != NULL) 1.69 + { 1.70 + GtShare *gt_share = share_get_udata (old_share, GT->name); 1.71 + 1.72 + if (gt_share) 1.73 + index = gt_share->index; 1.74 + } 1.75 + 1.76 + return index; 1.77 +} 1.78 + 1.79 +/* 1.80 + * Find an unused index, but reuse the existing index if possible. 1.81 + */ 1.82 +static uint32_t get_share_index (Share *share) 1.83 +{ 1.84 + Hash *hash; 1.85 + uint32_t index; 1.86 + 1.87 + if ((hash = share_get_hash (share, "SHA1")) != NULL) 1.88 + { 1.89 + uint32_t hash_tmp; 1.90 + 1.91 + /* if a Share with the same hash has another index, re-use that one */ 1.92 + if ((index = get_old_index (hash)) != 0) 1.93 + return index; 1.94 + 1.95 + memcpy (&hash_tmp, hash->data, 4); 1.96 + 1.97 + /* use the first 24 bits of the SHA1 hash to seed the file index */ 1.98 + index_counter = hash_tmp & 0xfffffff; 1.99 + } 1.100 + 1.101 + if (!(index = dataset_uniq32 (indices, &index_counter))) 1.102 + return 0; 1.103 + 1.104 + return index; 1.105 +} 1.106 + 1.107 +static void add_index (Share *share, GtShare *gt_share) 1.108 +{ 1.109 + uint32_t index; 1.110 + 1.111 + if (SHARE_DEBUG) 1.112 + GT->dbg (GT, "++[%d]->%s", gt_share->index, gt_share->filename); 1.113 + 1.114 + index = get_share_index (share); 1.115 + dataset_insert (&indices, &index, sizeof(index), share, 0); 1.116 +} 1.117 + 1.118 +static void remove_index (Share *share, GtShare *gt_share) 1.119 +{ 1.120 + uint32_t index = gt_share->index; 1.121 + 1.122 + assert (index > 0); 1.123 + 1.124 + /* 1.125 + * Check if the index is pointing at a different share. This case happens 1.126 + * for every Share that is not removed on a resync, due to the weird way 1.127 + * giftd 0.11.x use the new/add/remove/free interface. 1.128 + */ 1.129 + if (dataset_lookup (indices, &index, sizeof(index)) != share) 1.130 + return; 1.131 + 1.132 + if (SHARE_DEBUG) 1.133 + GT->dbg (GT, "--[%d]->%s", gt_share->index, gt_share->filename); 1.134 + 1.135 + index = gt_share->index; 1.136 + dataset_remove (indices, &index, sizeof(index)); 1.137 + 1.138 + if (dataset_length (indices) == 0) 1.139 + { 1.140 + dataset_clear (indices); 1.141 + indices = NULL; 1.142 + } 1.143 +} 1.144 + 1.145 +/******************************************************************************/ 1.146 + 1.147 +/* TODO: This duplicates memory thats already stored on the FileShare. 1.148 + * Prevent this by maintaining a per-hash algorithm map of FileShares */ 1.149 +static void add_hash (FileShare *file) 1.150 +{ 1.151 + Hash *hash; 1.152 + ds_data_t key; 1.153 + ds_data_t value; 1.154 + 1.155 + if (!(hash = share_get_hash (file, "SHA1"))) 1.156 + return; 1.157 + 1.158 + /* This shares the hash memory with the FileShare and also 1.159 + * points directly at it. */ 1.160 + ds_data_init (&key, hash->data, hash->len, DS_NOCOPY); 1.161 + ds_data_init (&value, file, 0, DS_NOCOPY); 1.162 + 1.163 + /* We share the key with the FileShare, so remove the old key first 1.164 + * so we don't end up sharing an old FileShare's hash. */ 1.165 + dataset_remove_ex (sha1_hashes, &key); 1.166 + dataset_insert_ex (&sha1_hashes, &key, &value); 1.167 +} 1.168 + 1.169 +static void remove_hash (FileShare *file) 1.170 +{ 1.171 + Hash *hash; 1.172 + 1.173 + if (!(hash = share_get_hash (file, "SHA1"))) 1.174 + return; 1.175 + 1.176 + /* 1.177 + * If a FileShare is already present at this hash, and it isn't 1.178 + * this FileShare, then don't remove it. This _will_ happen 1.179 + * due to the way FileShares get added and removed on resyncs. 1.180 + */ 1.181 + if (dataset_lookup (sha1_hashes, hash->data, hash->len) != file) 1.182 + return; 1.183 + 1.184 + dataset_remove (sha1_hashes, hash->data, hash->len); 1.185 + 1.186 + if (dataset_length (sha1_hashes) == 0) 1.187 + { 1.188 + dataset_clear (sha1_hashes); 1.189 + sha1_hashes = NULL; 1.190 + } 1.191 +} 1.192 + 1.193 +/******************************************************************************/ 1.194 + 1.195 +static GtShare *gt_share_local_add (FileShare *file) 1.196 +{ 1.197 + GtShare *share; 1.198 + uint32_t index; 1.199 + 1.200 + if (share_get_udata (file, GT->name)) 1.201 + return NULL; 1.202 + 1.203 + index = get_share_index (file); 1.204 + 1.205 + if (!(share = gt_share_new_data (file, index))) 1.206 + return NULL; 1.207 + 1.208 + add_hash (file); 1.209 + add_index (file, share); 1.210 + 1.211 + return share; 1.212 +} 1.213 + 1.214 +static void gt_share_local_remove (FileShare *file, GtShare *share) 1.215 +{ 1.216 + remove_index (file, share); 1.217 + remove_hash (file); 1.218 + 1.219 + gt_share_free_data (file, share); 1.220 +} 1.221 + 1.222 +static int find_by_index (ds_data_t *key, ds_data_t *value, void **args) 1.223 +{ 1.224 + uint32_t *index = args[0]; 1.225 + char *filename = args[1]; 1.226 + FileShare **ret = args[2]; 1.227 + FileShare *file = value->data; 1.228 + GtShare *share; 1.229 + 1.230 + if (!file || !(share = share_get_udata (file, GT->name))) 1.231 + return DS_CONTINUE; 1.232 + 1.233 + if (share->index == *index && 1.234 + (!filename || !strcmp (filename, share->filename))) 1.235 + { 1.236 + *ret = file; 1.237 + return DS_BREAK; 1.238 + } 1.239 + 1.240 + return DS_CONTINUE; 1.241 +} 1.242 + 1.243 +FileShare *gt_share_local_lookup_by_index (uint32_t index, char *filename) 1.244 +{ 1.245 + FileShare *ret = NULL; 1.246 + void *args[] = { &index, filename, &ret }; 1.247 + 1.248 + share_foreach (DS_FOREACH_EX(find_by_index), args); 1.249 + 1.250 + return ret; 1.251 +} 1.252 + 1.253 +static FileShare *lookup_sha1 (char *urn) 1.254 +{ 1.255 + char *str, *str0; 1.256 + char *prefix; 1.257 + unsigned char *bin; 1.258 + FileShare *file; 1.259 + 1.260 + if (!(str0 = str = STRDUP (urn))) 1.261 + return NULL; 1.262 + 1.263 + /* TODO: consolidate with gt_protocol.c:parse_extended_data */ 1.264 + string_upper (str0); 1.265 + string_sep (&str, "URN:"); 1.266 + 1.267 + prefix = string_sep (&str, ":"); 1.268 + 1.269 + /* Only support urn:sha1 or urn:sha-1 urns now */ 1.270 + if (STRCMP (prefix, "SHA1") != 0 && STRCMP (prefix, "SHA-1") != 0) 1.271 + { 1.272 + free (str0); 1.273 + return NULL; 1.274 + } 1.275 + 1.276 + string_trim (str); 1.277 + 1.278 + if (strlen (str) != 32) 1.279 + { 1.280 + free (str0); 1.281 + return NULL; 1.282 + } 1.283 + 1.284 + if (!(bin = sha1_bin (str))) 1.285 + { 1.286 + free (str0); 1.287 + return NULL; 1.288 + } 1.289 + 1.290 + file = dataset_lookup (sha1_hashes, bin, SHA1_BINSIZE); 1.291 + 1.292 + free (str0); 1.293 + free (bin); 1.294 + 1.295 + return file; 1.296 +} 1.297 + 1.298 +FileShare *gt_share_local_lookup_by_urn (char *urn) 1.299 +{ 1.300 + return lookup_sha1 (urn); 1.301 +} 1.302 + 1.303 +static char *get_sha1 (FileShare *file) 1.304 +{ 1.305 + Hash *hash; 1.306 + char *urn; 1.307 + char *str; 1.308 + 1.309 + if (!(hash = share_get_hash (file, "SHA1"))) 1.310 + return NULL; 1.311 + 1.312 + assert (hash->len == SHA1_BINSIZE); 1.313 + 1.314 + if (!(str = sha1_string (hash->data))) 1.315 + return NULL; 1.316 + 1.317 + urn = stringf_dup ("urn:sha1:%s", str); 1.318 + free (str); 1.319 + 1.320 + return urn; 1.321 +} 1.322 + 1.323 +char *gt_share_local_get_urns (FileShare *file) 1.324 +{ 1.325 + char *urn; 1.326 + 1.327 + urn = get_sha1 (file); 1.328 + 1.329 + return urn; 1.330 +} 1.331 + 1.332 +int gt_share_local_sync_is_done (void) 1.333 +{ 1.334 + return sync_done; 1.335 +} 1.336 + 1.337 +/******************************************************************************/ 1.338 + 1.339 +void *gnutella_share_new (Protocol *p, FileShare *file) 1.340 +{ 1.341 + /* add this share to the data structures for searching */ 1.342 + gt_search_exec_add (file); 1.343 + 1.344 + return gt_share_local_add (file); 1.345 +} 1.346 + 1.347 +void gnutella_share_free (Protocol *p, FileShare *file, void *data) 1.348 +{ 1.349 + /* remove data structures for searching */ 1.350 + gt_search_exec_remove (file); 1.351 + 1.352 + gt_share_local_remove (file, data); 1.353 +} 1.354 + 1.355 +int gnutella_share_add (Protocol *p, FileShare *file, void *data) 1.356 +{ 1.357 + /* add to query routing tables */ 1.358 + gt_query_router_self_add (file); 1.359 + 1.360 + return TRUE; 1.361 +} 1.362 + 1.363 +int gnutella_share_remove (Protocol *p, FileShare *file, void *data) 1.364 +{ 1.365 + /* remove from query routing tables */ 1.366 + gt_query_router_self_remove (file); 1.367 + 1.368 + return TRUE; 1.369 +} 1.370 + 1.371 +void gnutella_share_sync (Protocol *p, int begin) 1.372 +{ 1.373 + gt_query_router_self_sync (begin); 1.374 + 1.375 + if (begin) 1.376 + { 1.377 + sync_begun = TRUE; 1.378 + } 1.379 + else if (sync_begun) 1.380 + { 1.381 + sync_begun = FALSE; 1.382 + sync_done = TRUE; 1.383 + 1.384 + /* synchronize the search structures (possibly, to disk) */ 1.385 + gt_search_exec_sync (); 1.386 + } 1.387 +}