view 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 source
1 /*
2 * $Id: gt_share.c,v 1.35 2004/03/26 11:53:18 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 */
17 #include "gt_gnutella.h"
18 #include "sha1.h"
20 #include "gt_share.h"
21 #include "gt_share_file.h"
22 #include "gt_query_route.h"
23 #include "gt_search.h"
24 #include "gt_search_exec.h"
26 #include "encoding/url.h"
28 /******************************************************************************/
30 #define SHARE_DEBUG gt_config_get_int("share/debug=0")
32 /*****************************************************************************/
34 /* each share is assigned an index here */
35 static Dataset *indices;
37 /* maps binary sha1 hashes -> FileShares */
38 static Dataset *sha1_hashes;
40 /* stored index of the last index assigned */
41 static uint32_t index_counter;
43 /* whether shares have been completely synchronized yet */
44 static BOOL sync_begun;
46 /* if shares are currently being synced */
47 static BOOL sync_done;
49 /******************************************************************************/
51 static void add_hash (FileShare *file);
52 static void remove_hash (FileShare *file);
54 /******************************************************************************/
56 /*
57 * Find the old index, using the SHA1 hash as a key.
58 */
59 static uint32_t get_old_index (Hash *hash)
60 {
61 Share *old_share;
62 uint32_t index = 0;
64 old_share = dataset_lookup (sha1_hashes, hash->data, SHA1_BINSIZE);
65 if (old_share != NULL)
66 {
67 GtShare *gt_share = share_get_udata (old_share, GT->name);
69 if (gt_share)
70 index = gt_share->index;
71 }
73 return index;
74 }
76 /*
77 * Find an unused index, but reuse the existing index if possible.
78 */
79 static uint32_t get_share_index (Share *share)
80 {
81 Hash *hash;
82 uint32_t index;
84 if ((hash = share_get_hash (share, "SHA1")) != NULL)
85 {
86 uint32_t hash_tmp;
88 /* if a Share with the same hash has another index, re-use that one */
89 if ((index = get_old_index (hash)) != 0)
90 return index;
92 memcpy (&hash_tmp, hash->data, 4);
94 /* use the first 24 bits of the SHA1 hash to seed the file index */
95 index_counter = hash_tmp & 0xfffffff;
96 }
98 if (!(index = dataset_uniq32 (indices, &index_counter)))
99 return 0;
101 return index;
102 }
104 static void add_index (Share *share, GtShare *gt_share)
105 {
106 uint32_t index;
108 if (SHARE_DEBUG)
109 GT->dbg (GT, "++[%d]->%s", gt_share->index, gt_share->filename);
111 index = get_share_index (share);
112 dataset_insert (&indices, &index, sizeof(index), share, 0);
113 }
115 static void remove_index (Share *share, GtShare *gt_share)
116 {
117 uint32_t index = gt_share->index;
119 assert (index > 0);
121 /*
122 * Check if the index is pointing at a different share. This case happens
123 * for every Share that is not removed on a resync, due to the weird way
124 * giftd 0.11.x use the new/add/remove/free interface.
125 */
126 if (dataset_lookup (indices, &index, sizeof(index)) != share)
127 return;
129 if (SHARE_DEBUG)
130 GT->dbg (GT, "--[%d]->%s", gt_share->index, gt_share->filename);
132 index = gt_share->index;
133 dataset_remove (indices, &index, sizeof(index));
135 if (dataset_length (indices) == 0)
136 {
137 dataset_clear (indices);
138 indices = NULL;
139 }
140 }
142 /******************************************************************************/
144 /* TODO: This duplicates memory thats already stored on the FileShare.
145 * Prevent this by maintaining a per-hash algorithm map of FileShares */
146 static void add_hash (FileShare *file)
147 {
148 Hash *hash;
149 ds_data_t key;
150 ds_data_t value;
152 if (!(hash = share_get_hash (file, "SHA1")))
153 return;
155 /* This shares the hash memory with the FileShare and also
156 * points directly at it. */
157 ds_data_init (&key, hash->data, hash->len, DS_NOCOPY);
158 ds_data_init (&value, file, 0, DS_NOCOPY);
160 /* We share the key with the FileShare, so remove the old key first
161 * so we don't end up sharing an old FileShare's hash. */
162 dataset_remove_ex (sha1_hashes, &key);
163 dataset_insert_ex (&sha1_hashes, &key, &value);
164 }
166 static void remove_hash (FileShare *file)
167 {
168 Hash *hash;
170 if (!(hash = share_get_hash (file, "SHA1")))
171 return;
173 /*
174 * If a FileShare is already present at this hash, and it isn't
175 * this FileShare, then don't remove it. This _will_ happen
176 * due to the way FileShares get added and removed on resyncs.
177 */
178 if (dataset_lookup (sha1_hashes, hash->data, hash->len) != file)
179 return;
181 dataset_remove (sha1_hashes, hash->data, hash->len);
183 if (dataset_length (sha1_hashes) == 0)
184 {
185 dataset_clear (sha1_hashes);
186 sha1_hashes = NULL;
187 }
188 }
190 /******************************************************************************/
192 static GtShare *gt_share_local_add (FileShare *file)
193 {
194 GtShare *share;
195 uint32_t index;
197 if (share_get_udata (file, GT->name))
198 return NULL;
200 index = get_share_index (file);
202 if (!(share = gt_share_new_data (file, index)))
203 return NULL;
205 add_hash (file);
206 add_index (file, share);
208 return share;
209 }
211 static void gt_share_local_remove (FileShare *file, GtShare *share)
212 {
213 remove_index (file, share);
214 remove_hash (file);
216 gt_share_free_data (file, share);
217 }
219 static int find_by_index (ds_data_t *key, ds_data_t *value, void **args)
220 {
221 uint32_t *index = args[0];
222 char *filename = args[1];
223 FileShare **ret = args[2];
224 FileShare *file = value->data;
225 GtShare *share;
227 if (!file || !(share = share_get_udata (file, GT->name)))
228 return DS_CONTINUE;
230 if (share->index == *index &&
231 (!filename || !strcmp (filename, share->filename)))
232 {
233 *ret = file;
234 return DS_BREAK;
235 }
237 return DS_CONTINUE;
238 }
240 FileShare *gt_share_local_lookup_by_index (uint32_t index, char *filename)
241 {
242 FileShare *ret = NULL;
243 void *args[] = { &index, filename, &ret };
245 share_foreach (DS_FOREACH_EX(find_by_index), args);
247 return ret;
248 }
250 static FileShare *lookup_sha1 (char *urn)
251 {
252 char *str, *str0;
253 char *prefix;
254 unsigned char *bin;
255 FileShare *file;
257 if (!(str0 = str = STRDUP (urn)))
258 return NULL;
260 /* TODO: consolidate with gt_protocol.c:parse_extended_data */
261 string_upper (str0);
262 string_sep (&str, "URN:");
264 prefix = string_sep (&str, ":");
266 /* Only support urn:sha1 or urn:sha-1 urns now */
267 if (STRCMP (prefix, "SHA1") != 0 && STRCMP (prefix, "SHA-1") != 0)
268 {
269 free (str0);
270 return NULL;
271 }
273 string_trim (str);
275 if (strlen (str) != 32)
276 {
277 free (str0);
278 return NULL;
279 }
281 if (!(bin = sha1_bin (str)))
282 {
283 free (str0);
284 return NULL;
285 }
287 file = dataset_lookup (sha1_hashes, bin, SHA1_BINSIZE);
289 free (str0);
290 free (bin);
292 return file;
293 }
295 FileShare *gt_share_local_lookup_by_urn (char *urn)
296 {
297 return lookup_sha1 (urn);
298 }
300 static char *get_sha1 (FileShare *file)
301 {
302 Hash *hash;
303 char *urn;
304 char *str;
306 if (!(hash = share_get_hash (file, "SHA1")))
307 return NULL;
309 assert (hash->len == SHA1_BINSIZE);
311 if (!(str = sha1_string (hash->data)))
312 return NULL;
314 urn = stringf_dup ("urn:sha1:%s", str);
315 free (str);
317 return urn;
318 }
320 char *gt_share_local_get_urns (FileShare *file)
321 {
322 char *urn;
324 urn = get_sha1 (file);
326 return urn;
327 }
329 int gt_share_local_sync_is_done (void)
330 {
331 return sync_done;
332 }
334 /******************************************************************************/
336 void *gnutella_share_new (Protocol *p, FileShare *file)
337 {
338 /* add this share to the data structures for searching */
339 gt_search_exec_add (file);
341 return gt_share_local_add (file);
342 }
344 void gnutella_share_free (Protocol *p, FileShare *file, void *data)
345 {
346 /* remove data structures for searching */
347 gt_search_exec_remove (file);
349 gt_share_local_remove (file, data);
350 }
352 int gnutella_share_add (Protocol *p, FileShare *file, void *data)
353 {
354 /* add to query routing tables */
355 gt_query_router_self_add (file);
357 return TRUE;
358 }
360 int gnutella_share_remove (Protocol *p, FileShare *file, void *data)
361 {
362 /* remove from query routing tables */
363 gt_query_router_self_remove (file);
365 return TRUE;
366 }
368 void gnutella_share_sync (Protocol *p, int begin)
369 {
370 gt_query_router_self_sync (begin);
372 if (begin)
373 {
374 sync_begun = TRUE;
375 }
376 else if (sync_begun)
377 {
378 sync_begun = FALSE;
379 sync_done = TRUE;
381 /* synchronize the search structures (possibly, to disk) */
382 gt_search_exec_sync ();
383 }
384 }