rev |
line source |
paulo@0
|
1 /*
|
paulo@0
|
2 * $Id: gt_share.c,v 1.35 2004/03/26 11:53:18 hipnod Exp $
|
paulo@0
|
3 *
|
paulo@0
|
4 * Copyright (C) 2001-2003 giFT project (gift.sourceforge.net)
|
paulo@0
|
5 *
|
paulo@0
|
6 * This program is free software; you can redistribute it and/or modify it
|
paulo@0
|
7 * under the terms of the GNU General Public License as published by the
|
paulo@0
|
8 * Free Software Foundation; either version 2, or (at your option) any
|
paulo@0
|
9 * later version.
|
paulo@0
|
10 *
|
paulo@0
|
11 * This program is distributed in the hope that it will be useful, but
|
paulo@0
|
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
|
paulo@0
|
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
paulo@0
|
14 * General Public License for more details.
|
paulo@0
|
15 */
|
paulo@0
|
16
|
paulo@0
|
17 #include "gt_gnutella.h"
|
paulo@0
|
18 #include "sha1.h"
|
paulo@0
|
19
|
paulo@0
|
20 #include "gt_share.h"
|
paulo@0
|
21 #include "gt_share_file.h"
|
paulo@0
|
22 #include "gt_query_route.h"
|
paulo@0
|
23 #include "gt_search.h"
|
paulo@0
|
24 #include "gt_search_exec.h"
|
paulo@0
|
25
|
paulo@0
|
26 #include "encoding/url.h"
|
paulo@0
|
27
|
paulo@0
|
28 /******************************************************************************/
|
paulo@0
|
29
|
paulo@0
|
30 #define SHARE_DEBUG gt_config_get_int("share/debug=0")
|
paulo@0
|
31
|
paulo@0
|
32 /*****************************************************************************/
|
paulo@0
|
33
|
paulo@0
|
34 /* each share is assigned an index here */
|
paulo@0
|
35 static Dataset *indices;
|
paulo@0
|
36
|
paulo@0
|
37 /* maps binary sha1 hashes -> FileShares */
|
paulo@0
|
38 static Dataset *sha1_hashes;
|
paulo@0
|
39
|
paulo@0
|
40 /* stored index of the last index assigned */
|
paulo@0
|
41 static uint32_t index_counter;
|
paulo@0
|
42
|
paulo@0
|
43 /* whether shares have been completely synchronized yet */
|
paulo@0
|
44 static BOOL sync_begun;
|
paulo@0
|
45
|
paulo@0
|
46 /* if shares are currently being synced */
|
paulo@0
|
47 static BOOL sync_done;
|
paulo@0
|
48
|
paulo@0
|
49 /******************************************************************************/
|
paulo@0
|
50
|
paulo@0
|
51 static void add_hash (FileShare *file);
|
paulo@0
|
52 static void remove_hash (FileShare *file);
|
paulo@0
|
53
|
paulo@0
|
54 /******************************************************************************/
|
paulo@0
|
55
|
paulo@0
|
56 /*
|
paulo@0
|
57 * Find the old index, using the SHA1 hash as a key.
|
paulo@0
|
58 */
|
paulo@0
|
59 static uint32_t get_old_index (Hash *hash)
|
paulo@0
|
60 {
|
paulo@0
|
61 Share *old_share;
|
paulo@0
|
62 uint32_t index = 0;
|
paulo@0
|
63
|
paulo@0
|
64 old_share = dataset_lookup (sha1_hashes, hash->data, SHA1_BINSIZE);
|
paulo@0
|
65 if (old_share != NULL)
|
paulo@0
|
66 {
|
paulo@0
|
67 GtShare *gt_share = share_get_udata (old_share, GT->name);
|
paulo@0
|
68
|
paulo@0
|
69 if (gt_share)
|
paulo@0
|
70 index = gt_share->index;
|
paulo@0
|
71 }
|
paulo@0
|
72
|
paulo@0
|
73 return index;
|
paulo@0
|
74 }
|
paulo@0
|
75
|
paulo@0
|
76 /*
|
paulo@0
|
77 * Find an unused index, but reuse the existing index if possible.
|
paulo@0
|
78 */
|
paulo@0
|
79 static uint32_t get_share_index (Share *share)
|
paulo@0
|
80 {
|
paulo@0
|
81 Hash *hash;
|
paulo@0
|
82 uint32_t index;
|
paulo@0
|
83
|
paulo@0
|
84 if ((hash = share_get_hash (share, "SHA1")) != NULL)
|
paulo@0
|
85 {
|
paulo@0
|
86 uint32_t hash_tmp;
|
paulo@0
|
87
|
paulo@0
|
88 /* if a Share with the same hash has another index, re-use that one */
|
paulo@0
|
89 if ((index = get_old_index (hash)) != 0)
|
paulo@0
|
90 return index;
|
paulo@0
|
91
|
paulo@0
|
92 memcpy (&hash_tmp, hash->data, 4);
|
paulo@0
|
93
|
paulo@0
|
94 /* use the first 24 bits of the SHA1 hash to seed the file index */
|
paulo@0
|
95 index_counter = hash_tmp & 0xfffffff;
|
paulo@0
|
96 }
|
paulo@0
|
97
|
paulo@0
|
98 if (!(index = dataset_uniq32 (indices, &index_counter)))
|
paulo@0
|
99 return 0;
|
paulo@0
|
100
|
paulo@0
|
101 return index;
|
paulo@0
|
102 }
|
paulo@0
|
103
|
paulo@0
|
104 static void add_index (Share *share, GtShare *gt_share)
|
paulo@0
|
105 {
|
paulo@0
|
106 uint32_t index;
|
paulo@0
|
107
|
paulo@0
|
108 if (SHARE_DEBUG)
|
paulo@0
|
109 GT->dbg (GT, "++[%d]->%s", gt_share->index, gt_share->filename);
|
paulo@0
|
110
|
paulo@0
|
111 index = get_share_index (share);
|
paulo@0
|
112 dataset_insert (&indices, &index, sizeof(index), share, 0);
|
paulo@0
|
113 }
|
paulo@0
|
114
|
paulo@0
|
115 static void remove_index (Share *share, GtShare *gt_share)
|
paulo@0
|
116 {
|
paulo@0
|
117 uint32_t index = gt_share->index;
|
paulo@0
|
118
|
paulo@0
|
119 assert (index > 0);
|
paulo@0
|
120
|
paulo@0
|
121 /*
|
paulo@0
|
122 * Check if the index is pointing at a different share. This case happens
|
paulo@0
|
123 * for every Share that is not removed on a resync, due to the weird way
|
paulo@0
|
124 * giftd 0.11.x use the new/add/remove/free interface.
|
paulo@0
|
125 */
|
paulo@0
|
126 if (dataset_lookup (indices, &index, sizeof(index)) != share)
|
paulo@0
|
127 return;
|
paulo@0
|
128
|
paulo@0
|
129 if (SHARE_DEBUG)
|
paulo@0
|
130 GT->dbg (GT, "--[%d]->%s", gt_share->index, gt_share->filename);
|
paulo@0
|
131
|
paulo@0
|
132 index = gt_share->index;
|
paulo@0
|
133 dataset_remove (indices, &index, sizeof(index));
|
paulo@0
|
134
|
paulo@0
|
135 if (dataset_length (indices) == 0)
|
paulo@0
|
136 {
|
paulo@0
|
137 dataset_clear (indices);
|
paulo@0
|
138 indices = NULL;
|
paulo@0
|
139 }
|
paulo@0
|
140 }
|
paulo@0
|
141
|
paulo@0
|
142 /******************************************************************************/
|
paulo@0
|
143
|
paulo@0
|
144 /* TODO: This duplicates memory thats already stored on the FileShare.
|
paulo@0
|
145 * Prevent this by maintaining a per-hash algorithm map of FileShares */
|
paulo@0
|
146 static void add_hash (FileShare *file)
|
paulo@0
|
147 {
|
paulo@0
|
148 Hash *hash;
|
paulo@0
|
149 ds_data_t key;
|
paulo@0
|
150 ds_data_t value;
|
paulo@0
|
151
|
paulo@0
|
152 if (!(hash = share_get_hash (file, "SHA1")))
|
paulo@0
|
153 return;
|
paulo@0
|
154
|
paulo@0
|
155 /* This shares the hash memory with the FileShare and also
|
paulo@0
|
156 * points directly at it. */
|
paulo@0
|
157 ds_data_init (&key, hash->data, hash->len, DS_NOCOPY);
|
paulo@0
|
158 ds_data_init (&value, file, 0, DS_NOCOPY);
|
paulo@0
|
159
|
paulo@0
|
160 /* We share the key with the FileShare, so remove the old key first
|
paulo@0
|
161 * so we don't end up sharing an old FileShare's hash. */
|
paulo@0
|
162 dataset_remove_ex (sha1_hashes, &key);
|
paulo@0
|
163 dataset_insert_ex (&sha1_hashes, &key, &value);
|
paulo@0
|
164 }
|
paulo@0
|
165
|
paulo@0
|
166 static void remove_hash (FileShare *file)
|
paulo@0
|
167 {
|
paulo@0
|
168 Hash *hash;
|
paulo@0
|
169
|
paulo@0
|
170 if (!(hash = share_get_hash (file, "SHA1")))
|
paulo@0
|
171 return;
|
paulo@0
|
172
|
paulo@0
|
173 /*
|
paulo@0
|
174 * If a FileShare is already present at this hash, and it isn't
|
paulo@0
|
175 * this FileShare, then don't remove it. This _will_ happen
|
paulo@0
|
176 * due to the way FileShares get added and removed on resyncs.
|
paulo@0
|
177 */
|
paulo@0
|
178 if (dataset_lookup (sha1_hashes, hash->data, hash->len) != file)
|
paulo@0
|
179 return;
|
paulo@0
|
180
|
paulo@0
|
181 dataset_remove (sha1_hashes, hash->data, hash->len);
|
paulo@0
|
182
|
paulo@0
|
183 if (dataset_length (sha1_hashes) == 0)
|
paulo@0
|
184 {
|
paulo@0
|
185 dataset_clear (sha1_hashes);
|
paulo@0
|
186 sha1_hashes = NULL;
|
paulo@0
|
187 }
|
paulo@0
|
188 }
|
paulo@0
|
189
|
paulo@0
|
190 /******************************************************************************/
|
paulo@0
|
191
|
paulo@0
|
192 static GtShare *gt_share_local_add (FileShare *file)
|
paulo@0
|
193 {
|
paulo@0
|
194 GtShare *share;
|
paulo@0
|
195 uint32_t index;
|
paulo@0
|
196
|
paulo@0
|
197 if (share_get_udata (file, GT->name))
|
paulo@0
|
198 return NULL;
|
paulo@0
|
199
|
paulo@0
|
200 index = get_share_index (file);
|
paulo@0
|
201
|
paulo@0
|
202 if (!(share = gt_share_new_data (file, index)))
|
paulo@0
|
203 return NULL;
|
paulo@0
|
204
|
paulo@0
|
205 add_hash (file);
|
paulo@0
|
206 add_index (file, share);
|
paulo@0
|
207
|
paulo@0
|
208 return share;
|
paulo@0
|
209 }
|
paulo@0
|
210
|
paulo@0
|
211 static void gt_share_local_remove (FileShare *file, GtShare *share)
|
paulo@0
|
212 {
|
paulo@0
|
213 remove_index (file, share);
|
paulo@0
|
214 remove_hash (file);
|
paulo@0
|
215
|
paulo@0
|
216 gt_share_free_data (file, share);
|
paulo@0
|
217 }
|
paulo@0
|
218
|
paulo@0
|
219 static int find_by_index (ds_data_t *key, ds_data_t *value, void **args)
|
paulo@0
|
220 {
|
paulo@0
|
221 uint32_t *index = args[0];
|
paulo@0
|
222 char *filename = args[1];
|
paulo@0
|
223 FileShare **ret = args[2];
|
paulo@0
|
224 FileShare *file = value->data;
|
paulo@0
|
225 GtShare *share;
|
paulo@0
|
226
|
paulo@0
|
227 if (!file || !(share = share_get_udata (file, GT->name)))
|
paulo@0
|
228 return DS_CONTINUE;
|
paulo@0
|
229
|
paulo@0
|
230 if (share->index == *index &&
|
paulo@0
|
231 (!filename || !strcmp (filename, share->filename)))
|
paulo@0
|
232 {
|
paulo@0
|
233 *ret = file;
|
paulo@0
|
234 return DS_BREAK;
|
paulo@0
|
235 }
|
paulo@0
|
236
|
paulo@0
|
237 return DS_CONTINUE;
|
paulo@0
|
238 }
|
paulo@0
|
239
|
paulo@0
|
240 FileShare *gt_share_local_lookup_by_index (uint32_t index, char *filename)
|
paulo@0
|
241 {
|
paulo@0
|
242 FileShare *ret = NULL;
|
paulo@0
|
243 void *args[] = { &index, filename, &ret };
|
paulo@0
|
244
|
paulo@0
|
245 share_foreach (DS_FOREACH_EX(find_by_index), args);
|
paulo@0
|
246
|
paulo@0
|
247 return ret;
|
paulo@0
|
248 }
|
paulo@0
|
249
|
paulo@0
|
250 static FileShare *lookup_sha1 (char *urn)
|
paulo@0
|
251 {
|
paulo@0
|
252 char *str, *str0;
|
paulo@0
|
253 char *prefix;
|
paulo@0
|
254 unsigned char *bin;
|
paulo@0
|
255 FileShare *file;
|
paulo@0
|
256
|
paulo@0
|
257 if (!(str0 = str = STRDUP (urn)))
|
paulo@0
|
258 return NULL;
|
paulo@0
|
259
|
paulo@0
|
260 /* TODO: consolidate with gt_protocol.c:parse_extended_data */
|
paulo@0
|
261 string_upper (str0);
|
paulo@0
|
262 string_sep (&str, "URN:");
|
paulo@0
|
263
|
paulo@0
|
264 prefix = string_sep (&str, ":");
|
paulo@0
|
265
|
paulo@0
|
266 /* Only support urn:sha1 or urn:sha-1 urns now */
|
paulo@0
|
267 if (STRCMP (prefix, "SHA1") != 0 && STRCMP (prefix, "SHA-1") != 0)
|
paulo@0
|
268 {
|
paulo@0
|
269 free (str0);
|
paulo@0
|
270 return NULL;
|
paulo@0
|
271 }
|
paulo@0
|
272
|
paulo@0
|
273 string_trim (str);
|
paulo@0
|
274
|
paulo@0
|
275 if (strlen (str) != 32)
|
paulo@0
|
276 {
|
paulo@0
|
277 free (str0);
|
paulo@0
|
278 return NULL;
|
paulo@0
|
279 }
|
paulo@0
|
280
|
paulo@0
|
281 if (!(bin = sha1_bin (str)))
|
paulo@0
|
282 {
|
paulo@0
|
283 free (str0);
|
paulo@0
|
284 return NULL;
|
paulo@0
|
285 }
|
paulo@0
|
286
|
paulo@0
|
287 file = dataset_lookup (sha1_hashes, bin, SHA1_BINSIZE);
|
paulo@0
|
288
|
paulo@0
|
289 free (str0);
|
paulo@0
|
290 free (bin);
|
paulo@0
|
291
|
paulo@0
|
292 return file;
|
paulo@0
|
293 }
|
paulo@0
|
294
|
paulo@0
|
295 FileShare *gt_share_local_lookup_by_urn (char *urn)
|
paulo@0
|
296 {
|
paulo@0
|
297 return lookup_sha1 (urn);
|
paulo@0
|
298 }
|
paulo@0
|
299
|
paulo@0
|
300 static char *get_sha1 (FileShare *file)
|
paulo@0
|
301 {
|
paulo@0
|
302 Hash *hash;
|
paulo@0
|
303 char *urn;
|
paulo@0
|
304 char *str;
|
paulo@0
|
305
|
paulo@0
|
306 if (!(hash = share_get_hash (file, "SHA1")))
|
paulo@0
|
307 return NULL;
|
paulo@0
|
308
|
paulo@0
|
309 assert (hash->len == SHA1_BINSIZE);
|
paulo@0
|
310
|
paulo@0
|
311 if (!(str = sha1_string (hash->data)))
|
paulo@0
|
312 return NULL;
|
paulo@0
|
313
|
paulo@0
|
314 urn = stringf_dup ("urn:sha1:%s", str);
|
paulo@0
|
315 free (str);
|
paulo@0
|
316
|
paulo@0
|
317 return urn;
|
paulo@0
|
318 }
|
paulo@0
|
319
|
paulo@0
|
320 char *gt_share_local_get_urns (FileShare *file)
|
paulo@0
|
321 {
|
paulo@0
|
322 char *urn;
|
paulo@0
|
323
|
paulo@0
|
324 urn = get_sha1 (file);
|
paulo@0
|
325
|
paulo@0
|
326 return urn;
|
paulo@0
|
327 }
|
paulo@0
|
328
|
paulo@0
|
329 int gt_share_local_sync_is_done (void)
|
paulo@0
|
330 {
|
paulo@0
|
331 return sync_done;
|
paulo@0
|
332 }
|
paulo@0
|
333
|
paulo@0
|
334 /******************************************************************************/
|
paulo@0
|
335
|
paulo@0
|
336 void *gnutella_share_new (Protocol *p, FileShare *file)
|
paulo@0
|
337 {
|
paulo@0
|
338 /* add this share to the data structures for searching */
|
paulo@0
|
339 gt_search_exec_add (file);
|
paulo@0
|
340
|
paulo@0
|
341 return gt_share_local_add (file);
|
paulo@0
|
342 }
|
paulo@0
|
343
|
paulo@0
|
344 void gnutella_share_free (Protocol *p, FileShare *file, void *data)
|
paulo@0
|
345 {
|
paulo@0
|
346 /* remove data structures for searching */
|
paulo@0
|
347 gt_search_exec_remove (file);
|
paulo@0
|
348
|
paulo@0
|
349 gt_share_local_remove (file, data);
|
paulo@0
|
350 }
|
paulo@0
|
351
|
paulo@0
|
352 int gnutella_share_add (Protocol *p, FileShare *file, void *data)
|
paulo@0
|
353 {
|
paulo@0
|
354 /* add to query routing tables */
|
paulo@0
|
355 gt_query_router_self_add (file);
|
paulo@0
|
356
|
paulo@0
|
357 return TRUE;
|
paulo@0
|
358 }
|
paulo@0
|
359
|
paulo@0
|
360 int gnutella_share_remove (Protocol *p, FileShare *file, void *data)
|
paulo@0
|
361 {
|
paulo@0
|
362 /* remove from query routing tables */
|
paulo@0
|
363 gt_query_router_self_remove (file);
|
paulo@0
|
364
|
paulo@0
|
365 return TRUE;
|
paulo@0
|
366 }
|
paulo@0
|
367
|
paulo@0
|
368 void gnutella_share_sync (Protocol *p, int begin)
|
paulo@0
|
369 {
|
paulo@0
|
370 gt_query_router_self_sync (begin);
|
paulo@0
|
371
|
paulo@0
|
372 if (begin)
|
paulo@0
|
373 {
|
paulo@0
|
374 sync_begun = TRUE;
|
paulo@0
|
375 }
|
paulo@0
|
376 else if (sync_begun)
|
paulo@0
|
377 {
|
paulo@0
|
378 sync_begun = FALSE;
|
paulo@0
|
379 sync_done = TRUE;
|
paulo@0
|
380
|
paulo@0
|
381 /* synchronize the search structures (possibly, to disk) */
|
paulo@0
|
382 gt_search_exec_sync ();
|
paulo@0
|
383 }
|
paulo@0
|
384 }
|