Mercurial > hg > index.fcgi > gift-gnutella > gift-gnutella-0.0.11-1pba
comparison 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 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:f54c0a0efc23 |
---|---|
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 */ | |
16 | |
17 #include "gt_gnutella.h" | |
18 #include "sha1.h" | |
19 | |
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" | |
25 | |
26 #include "encoding/url.h" | |
27 | |
28 /******************************************************************************/ | |
29 | |
30 #define SHARE_DEBUG gt_config_get_int("share/debug=0") | |
31 | |
32 /*****************************************************************************/ | |
33 | |
34 /* each share is assigned an index here */ | |
35 static Dataset *indices; | |
36 | |
37 /* maps binary sha1 hashes -> FileShares */ | |
38 static Dataset *sha1_hashes; | |
39 | |
40 /* stored index of the last index assigned */ | |
41 static uint32_t index_counter; | |
42 | |
43 /* whether shares have been completely synchronized yet */ | |
44 static BOOL sync_begun; | |
45 | |
46 /* if shares are currently being synced */ | |
47 static BOOL sync_done; | |
48 | |
49 /******************************************************************************/ | |
50 | |
51 static void add_hash (FileShare *file); | |
52 static void remove_hash (FileShare *file); | |
53 | |
54 /******************************************************************************/ | |
55 | |
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; | |
63 | |
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); | |
68 | |
69 if (gt_share) | |
70 index = gt_share->index; | |
71 } | |
72 | |
73 return index; | |
74 } | |
75 | |
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; | |
83 | |
84 if ((hash = share_get_hash (share, "SHA1")) != NULL) | |
85 { | |
86 uint32_t hash_tmp; | |
87 | |
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; | |
91 | |
92 memcpy (&hash_tmp, hash->data, 4); | |
93 | |
94 /* use the first 24 bits of the SHA1 hash to seed the file index */ | |
95 index_counter = hash_tmp & 0xfffffff; | |
96 } | |
97 | |
98 if (!(index = dataset_uniq32 (indices, &index_counter))) | |
99 return 0; | |
100 | |
101 return index; | |
102 } | |
103 | |
104 static void add_index (Share *share, GtShare *gt_share) | |
105 { | |
106 uint32_t index; | |
107 | |
108 if (SHARE_DEBUG) | |
109 GT->dbg (GT, "++[%d]->%s", gt_share->index, gt_share->filename); | |
110 | |
111 index = get_share_index (share); | |
112 dataset_insert (&indices, &index, sizeof(index), share, 0); | |
113 } | |
114 | |
115 static void remove_index (Share *share, GtShare *gt_share) | |
116 { | |
117 uint32_t index = gt_share->index; | |
118 | |
119 assert (index > 0); | |
120 | |
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; | |
128 | |
129 if (SHARE_DEBUG) | |
130 GT->dbg (GT, "--[%d]->%s", gt_share->index, gt_share->filename); | |
131 | |
132 index = gt_share->index; | |
133 dataset_remove (indices, &index, sizeof(index)); | |
134 | |
135 if (dataset_length (indices) == 0) | |
136 { | |
137 dataset_clear (indices); | |
138 indices = NULL; | |
139 } | |
140 } | |
141 | |
142 /******************************************************************************/ | |
143 | |
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; | |
151 | |
152 if (!(hash = share_get_hash (file, "SHA1"))) | |
153 return; | |
154 | |
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); | |
159 | |
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 } | |
165 | |
166 static void remove_hash (FileShare *file) | |
167 { | |
168 Hash *hash; | |
169 | |
170 if (!(hash = share_get_hash (file, "SHA1"))) | |
171 return; | |
172 | |
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; | |
180 | |
181 dataset_remove (sha1_hashes, hash->data, hash->len); | |
182 | |
183 if (dataset_length (sha1_hashes) == 0) | |
184 { | |
185 dataset_clear (sha1_hashes); | |
186 sha1_hashes = NULL; | |
187 } | |
188 } | |
189 | |
190 /******************************************************************************/ | |
191 | |
192 static GtShare *gt_share_local_add (FileShare *file) | |
193 { | |
194 GtShare *share; | |
195 uint32_t index; | |
196 | |
197 if (share_get_udata (file, GT->name)) | |
198 return NULL; | |
199 | |
200 index = get_share_index (file); | |
201 | |
202 if (!(share = gt_share_new_data (file, index))) | |
203 return NULL; | |
204 | |
205 add_hash (file); | |
206 add_index (file, share); | |
207 | |
208 return share; | |
209 } | |
210 | |
211 static void gt_share_local_remove (FileShare *file, GtShare *share) | |
212 { | |
213 remove_index (file, share); | |
214 remove_hash (file); | |
215 | |
216 gt_share_free_data (file, share); | |
217 } | |
218 | |
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; | |
226 | |
227 if (!file || !(share = share_get_udata (file, GT->name))) | |
228 return DS_CONTINUE; | |
229 | |
230 if (share->index == *index && | |
231 (!filename || !strcmp (filename, share->filename))) | |
232 { | |
233 *ret = file; | |
234 return DS_BREAK; | |
235 } | |
236 | |
237 return DS_CONTINUE; | |
238 } | |
239 | |
240 FileShare *gt_share_local_lookup_by_index (uint32_t index, char *filename) | |
241 { | |
242 FileShare *ret = NULL; | |
243 void *args[] = { &index, filename, &ret }; | |
244 | |
245 share_foreach (DS_FOREACH_EX(find_by_index), args); | |
246 | |
247 return ret; | |
248 } | |
249 | |
250 static FileShare *lookup_sha1 (char *urn) | |
251 { | |
252 char *str, *str0; | |
253 char *prefix; | |
254 unsigned char *bin; | |
255 FileShare *file; | |
256 | |
257 if (!(str0 = str = STRDUP (urn))) | |
258 return NULL; | |
259 | |
260 /* TODO: consolidate with gt_protocol.c:parse_extended_data */ | |
261 string_upper (str0); | |
262 string_sep (&str, "URN:"); | |
263 | |
264 prefix = string_sep (&str, ":"); | |
265 | |
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 } | |
272 | |
273 string_trim (str); | |
274 | |
275 if (strlen (str) != 32) | |
276 { | |
277 free (str0); | |
278 return NULL; | |
279 } | |
280 | |
281 if (!(bin = sha1_bin (str))) | |
282 { | |
283 free (str0); | |
284 return NULL; | |
285 } | |
286 | |
287 file = dataset_lookup (sha1_hashes, bin, SHA1_BINSIZE); | |
288 | |
289 free (str0); | |
290 free (bin); | |
291 | |
292 return file; | |
293 } | |
294 | |
295 FileShare *gt_share_local_lookup_by_urn (char *urn) | |
296 { | |
297 return lookup_sha1 (urn); | |
298 } | |
299 | |
300 static char *get_sha1 (FileShare *file) | |
301 { | |
302 Hash *hash; | |
303 char *urn; | |
304 char *str; | |
305 | |
306 if (!(hash = share_get_hash (file, "SHA1"))) | |
307 return NULL; | |
308 | |
309 assert (hash->len == SHA1_BINSIZE); | |
310 | |
311 if (!(str = sha1_string (hash->data))) | |
312 return NULL; | |
313 | |
314 urn = stringf_dup ("urn:sha1:%s", str); | |
315 free (str); | |
316 | |
317 return urn; | |
318 } | |
319 | |
320 char *gt_share_local_get_urns (FileShare *file) | |
321 { | |
322 char *urn; | |
323 | |
324 urn = get_sha1 (file); | |
325 | |
326 return urn; | |
327 } | |
328 | |
329 int gt_share_local_sync_is_done (void) | |
330 { | |
331 return sync_done; | |
332 } | |
333 | |
334 /******************************************************************************/ | |
335 | |
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); | |
340 | |
341 return gt_share_local_add (file); | |
342 } | |
343 | |
344 void gnutella_share_free (Protocol *p, FileShare *file, void *data) | |
345 { | |
346 /* remove data structures for searching */ | |
347 gt_search_exec_remove (file); | |
348 | |
349 gt_share_local_remove (file, data); | |
350 } | |
351 | |
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); | |
356 | |
357 return TRUE; | |
358 } | |
359 | |
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); | |
364 | |
365 return TRUE; | |
366 } | |
367 | |
368 void gnutella_share_sync (Protocol *p, int begin) | |
369 { | |
370 gt_query_router_self_sync (begin); | |
371 | |
372 if (begin) | |
373 { | |
374 sync_begun = TRUE; | |
375 } | |
376 else if (sync_begun) | |
377 { | |
378 sync_begun = FALSE; | |
379 sync_done = TRUE; | |
380 | |
381 /* synchronize the search structures (possibly, to disk) */ | |
382 gt_search_exec_sync (); | |
383 } | |
384 } |