aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2009-09-11 14:22:19 +0000
committerChristian Grothoff <christian@grothoff.org>2009-09-11 14:22:19 +0000
commit92b434b649de5bc75628eff46f17db18104a4dd8 (patch)
tree7d55ced99e9f0539f414c017c3504c4bd45da7f4 /src
parentb60d9cfa7d42f0a933d7de137a2c8b17eaece4dd (diff)
downloadgnunet-92b434b649de5bc75628eff46f17db18104a4dd8.tar.gz
gnunet-92b434b649de5bc75628eff46f17db18104a4dd8.zip
more FS coding
Diffstat (limited to 'src')
-rw-r--r--src/fs/fs_uri.c4
-rw-r--r--src/fs/gnunet-service-fs.c490
-rw-r--r--src/upnp/upnp_util.h2
3 files changed, 469 insertions, 27 deletions
diff --git a/src/fs/fs_uri.c b/src/fs/fs_uri.c
index 4f4a82c2c..1c0686ed9 100644
--- a/src/fs/fs_uri.c
+++ b/src/fs/fs_uri.c
@@ -1481,7 +1481,9 @@ gather_uri_data (void *cls,
1481 * Construct a keyword-URI from meta-data (take all entries 1481 * Construct a keyword-URI from meta-data (take all entries
1482 * in the meta-data and construct one large keyword URI 1482 * in the meta-data and construct one large keyword URI
1483 * that lists all keywords that can be found in the meta-data). 1483 * that lists all keywords that can be found in the meta-data).
1484 * @deprecated 1484 *
1485 * @param md metadata to use
1486 * @return NULL on error, otherwise a KSK URI
1485 */ 1487 */
1486struct GNUNET_FS_Uri * 1488struct GNUNET_FS_Uri *
1487GNUNET_FS_uri_ksk_create_from_meta_data (const struct GNUNET_CONTAINER_MetaData *md) 1489GNUNET_FS_uri_ksk_create_from_meta_data (const struct GNUNET_CONTAINER_MetaData *md)
diff --git a/src/fs/gnunet-service-fs.c b/src/fs/gnunet-service-fs.c
index bf64f73f1..b85a63d4b 100644
--- a/src/fs/gnunet-service-fs.c
+++ b/src/fs/gnunet-service-fs.c
@@ -22,6 +22,13 @@
22 * @file fs/gnunet-service-fs.c 22 * @file fs/gnunet-service-fs.c
23 * @brief program that provides the file-sharing service 23 * @brief program that provides the file-sharing service
24 * @author Christian Grothoff 24 * @author Christian Grothoff
25 *
26 * TODO:
27 * - INDEX_START handling
28 * - INDEX_LIST handling
29 * - UNINDEX handling
30 * - bloomfilter support (GET, CS-request with BF, etc.)
31 * - all P2P messages
25 */ 32 */
26#include "platform.h" 33#include "platform.h"
27#include "gnunet_protocols.h" 34#include "gnunet_protocols.h"
@@ -30,9 +37,22 @@
30#include "gnunet_util_lib.h" 37#include "gnunet_util_lib.h"
31#include "fs.h" 38#include "fs.h"
32 39
40/**
41 * Our connection to the datastore.
42 */
33static struct GNUNET_DATASTORE_Handle *dsh; 43static struct GNUNET_DATASTORE_Handle *dsh;
34 44
35/** 45/**
46 * Our scheduler.
47 */
48static struct GNUNET_SCHEDULER_Handle *sched;
49
50/**
51 * Our configuration.
52 */
53const struct GNUNET_CONFIGURATION_Handle *cfg;
54
55/**
36 * Handle INDEX_START-message. 56 * Handle INDEX_START-message.
37 * 57 *
38 * @param cls closure 58 * @param cls closure
@@ -141,7 +161,8 @@ handle_unindex (void *cls,
141 161
142 162
143/** 163/**
144 * FIXME 164 * Signature of a function that is called whenever a datastore
165 * request can be processed (or an entry put on the queue times out).
145 * 166 *
146 * @param cls closure 167 * @param cls closure
147 * @param ok GNUNET_OK if DS is ready, GNUNET_SYSERR on timeout 168 * @param ok GNUNET_OK if DS is ready, GNUNET_SYSERR on timeout
@@ -151,65 +172,453 @@ typedef void (*RequestFunction)(void *cls,
151 172
152 173
153/** 174/**
175 * Doubly-linked list of our requests for the datastore.
176 */
177struct DatastoreRequestQueue
178{
179
180 /**
181 * This is a doubly-linked list.
182 */
183 struct DatastoreRequestQueue *next;
184
185 /**
186 * This is a doubly-linked list.
187 */
188 struct DatastoreRequestQueue *prev;
189
190 /**
191 * Function to call (will issue the request).
192 */
193 RequestFunction req;
194
195 /**
196 * Closure for req.
197 */
198 void *req_cls;
199
200 /**
201 * When should this request time-out because we don't care anymore?
202 */
203 struct GNUNET_TIME_Absolute timeout;
204
205 /**
206 * ID of task used for signaling timeout.
207 */
208 GNUNET_SCHEDULER_TaskIdentifier task;
209
210};
211
212
213/**
214 * Head of request queue for the datastore, sorted by timeout.
215 */
216static struct DatastoreRequestQueue *drq_head;
217
218/**
219 * Tail of request queue for the datastore.
220 */
221static struct DatastoreRequestQueue *drq_tail;
222
223
224/**
154 * Run the next DS request in our 225 * Run the next DS request in our
155 * queue, we're done with the current one. 226 * queue, we're done with the current one.
156 */ 227 */
157static void 228static void
158next_ds_request () 229next_ds_request ()
159{ 230{
231 struct DatastoreRequestQueue *e;
232
233 while (NULL != (e = drq_head))
234 {
235 if (0 != GNUNET_TIME_absolute_get_remaining (e->timeout).value)
236 break;
237 if (e->task != GNUNET_SCHEDULER_NO_TASK)
238 GNUNET_SCHEDULER_cancel (sched, e->task);
239 GNUNET_CONTAINER_DLL_remove (drq_head, drq_tail, e);
240 e->req (e->req_cls, GNUNET_NO);
241 GNUNET_free (e);
242 }
243 if (e == NULL)
244 return;
245 if (e->task != GNUNET_SCHEDULER_NO_TASK)
246 GNUNET_SCHEDULER_cancel (sched, e->task);
247 e->task = GNUNET_SCHEDULER_NO_TASK;
248 e->req (e->req_cls, GNUNET_YES);
249 GNUNET_CONTAINER_DLL_remove (drq_head, drq_tail, e);
250 GNUNET_free (e);
160} 251}
161 252
162 253
163/** 254/**
164 * FIXME. 255 * A datastore request had to be timed out.
256 *
257 * @param cls closure (of type "struct DatastoreRequestQueue*")
258 * @param tc task context, unused
165 */ 259 */
166static void 260static void
261timeout_ds_request (void *cls,
262 const struct GNUNET_SCHEDULER_TaskContext *tc)
263{
264 struct DatastoreRequestQueue *e = cls;
265
266 e->task = GNUNET_SCHEDULER_NO_TASK;
267 GNUNET_CONTAINER_DLL_remove (drq_head, drq_tail, e);
268 e->req (e->req_cls, GNUNET_NO);
269 GNUNET_free (e);
270}
271
272
273/**
274 * Queue a request for the datastore.
275 *
276 * @param deadline by when the request should run
277 * @param fun function to call once the request can be run
278 * @param fun_cls closure for fun
279 */
280static struct DatastoreRequestQueue *
167queue_ds_request (struct GNUNET_TIME_Relative deadline, 281queue_ds_request (struct GNUNET_TIME_Relative deadline,
168 RequestFunction fun, 282 RequestFunction fun,
169 void *fun_cls) 283 void *fun_cls)
170{ 284{
171} 285 struct DatastoreRequestQueue *e;
286 struct DatastoreRequestQueue *bef;
172 287
288 if (drq_head == NULL)
289 {
290 /* no other requests pending, run immediately */
291 fun (fun_cls, GNUNET_OK);
292 return NULL;
293 }
294 e = GNUNET_malloc (sizeof (struct DatastoreRequestQueue));
295 e->timeout = GNUNET_TIME_relative_to_absolute (deadline);
296 e->req = fun;
297 e->req_cls = fun_cls;
298 if (deadline.value == GNUNET_TIME_UNIT_FOREVER_REL.value)
299 {
300 /* local request, highest prio, put at head of queue
301 regardless of deadline */
302 bef = NULL;
303 }
304 else
305 {
306 bef = drq_tail;
307 while ( (NULL != bef) &&
308 (e->timeout.value < bef->timeout.value) )
309 bef = bef->prev;
310 }
311 GNUNET_CONTAINER_DLL_insert_after (drq_head, drq_tail, bef, e);
312 if (deadline.value == GNUNET_TIME_UNIT_FOREVER_REL.value)
313 return e;
314 e->task = GNUNET_SCHEDULER_add_delayed (sched,
315 GNUNET_NO,
316 GNUNET_SCHEDULER_PRIORITY_BACKGROUND,
317 GNUNET_SCHEDULER_NO_TASK,
318 deadline,
319 &timeout_ds_request,
320 e);
321 return e;
322}
173 323
174 324
175/** 325/**
176 * Closure for processing START_SEARCH 326 * Closure for processing START_SEARCH messages from a client.
177 * messages from a client.
178 */ 327 */
179struct LocalGetContext 328struct LocalGetContext
180{ 329{
330
331 /**
332 * This is a doubly-linked list.
333 */
334 struct LocalGetContext *next;
335
336 /**
337 * This is a doubly-linked list.
338 */
339 struct LocalGetContext *prev;
340
181 /** 341 /**
182 * Client that initiated the search. 342 * Client that initiated the search.
183 */ 343 */
184 struct GNUNET_SERVER_Client *client; 344 struct GNUNET_SERVER_Client *client;
185 345
346 /**
347 * Array of results that we've already received
348 * (can be NULL).
349 */
350 GNUNET_HashCode *results;
186 351
352 /**
353 * Bloomfilter over all results (for fast query construction);
354 * NULL if we don't have any results.
355 */
356 struct GNUNET_CONTAINER_BloomFilter *results_bf;
357
358 /**
359 * DS request associated with this operation.
360 */
361 struct DatastoreRequestQueue *req;
362
363 /**
364 * Current result message to transmit to client (or NULL).
365 */
366 struct ContentMessage *result;
367
368 /**
369 * Type of the content that we're looking for.
370 * 0 for any.
371 */
372 uint32_t type;
373
374 /**
375 * Desired anonymity level.
376 */
377 uint32_t anonymity_level;
378
379 /**
380 * Number of results actually stored in the results array.
381 */
382 unsigned int results_used;
187 383
384 /**
385 * Size of the results array in memory.
386 */
387 unsigned int results_size;
388
389 /**
390 * If the request is for a DBLOCK or IBLOCK, this is the identity of
391 * the peer that is known to have a response. Set to all-zeros if
392 * such a target is not known (note that even if OUR anonymity
393 * level is >0 we may happen to know the responder's identity;
394 * nevertheless, we should probably not use it for a DHT-lookup
395 * or similar blunt actions in order to avoid exposing ourselves).
396 * <p>
397 * If the request is for an SBLOCK, this is the identity of the
398 * pseudonym to which the SBLOCK belongs.
399 * <p>
400 * If the request is for a KBLOCK, "target" must be all zeros.
401 */
402 GNUNET_HashCode target;
403
404 /**
405 * Hash of the keyword (aka query) for KBLOCKs; Hash of
406 * the CHK-encoded block for DBLOCKS and IBLOCKS (aka query)
407 * and hash of the identifier XORed with the target for
408 * SBLOCKS (aka query).
409 */
410 GNUNET_HashCode query;
411
188}; 412};
189 413
190 414
191static void 415/**
416 * Head of doubly-linked LGC list.
417 */
418static struct LocalGetContext *lgc_head;
419
420/**
421 * Tail of doubly-linked LGC list.
422 */
423static struct LocalGetContext *lgc_tail;
424
425
426/**
427 * Free the state associated with a local get context.
428 *
429 * @param lgc the lgc to free
430 */
431static void
432local_get_context_free (struct LocalGetContext *lgc)
433{
434 GNUNET_CONTAINER_DLL_remove (lgc_head, lgc_tail, lgc);
435 GNUNET_SERVER_client_drop (lgc->client);
436 GNUNET_free_non_null (lgc->results);
437 if (lgc->results_bf != NULL)
438 GNUNET_CONTAINER_bloomfilter_free (lgc->results_bf);
439 if (lgc->req != NULL)
440 {
441 if (lgc->req->task != GNUNET_SCHEDULER_NO_TASK)
442 GNUNET_SCHEDULER_cancel (sched, lgc->req->task);
443 GNUNET_CONTAINER_DLL_remove (lgc_head, lgc_tail, lgc);
444 GNUNET_free (lgc->req);
445 }
446 GNUNET_free (lgc);
447}
448
449
450/**
451 * We're able to transmit the next (local) result to the client.
452 * Do it and ask the datastore for more. Or, on error, tell
453 * the datastore to stop giving us more.
454 *
455 * @param cls our closure (struct LocalGetContext)
456 * @param max maximum number of bytes we can transmit
457 * @param buf where to copy our message
458 * @return number of bytes copied to buf
459 */
460static size_t
461transmit_local_result (void *cls,
462 size_t max,
463 void *buf)
464{
465 struct LocalGetContext *lgc = cls;
466 uint16_t msize;
467
468 if (NULL == buf)
469 {
470 /* error, abort! */
471 GNUNET_free (lgc->result);
472 lgc->result = NULL;
473 GNUNET_DATASTORE_get_next (dsh, GNUNET_NO);
474 return 0;
475 }
476 msize = ntohs (lgc->result->header.size);
477 GNUNET_assert (max >= msize);
478 memcpy (buf, lgc->result, msize);
479 GNUNET_free (lgc->result);
480 lgc->result = NULL;
481 GNUNET_DATASTORE_get_next (dsh, GNUNET_YES);
482 return msize;
483}
484
485
486/**
487 * We're processing (local) results for a search request
488 * from a (local) client. Pass applicable results to the
489 * client and if we are done either clean up (operation
490 * complete) or switch to P2P search (more results possible).
491 *
492 * @param cls our closure (struct LocalGetContext)
493 * @param key key for the content
494 * @param size number of bytes in data
495 * @param data content stored
496 * @param type type of the content
497 * @param priority priority of the content
498 * @param anonymity anonymity-level for the content
499 * @param expiration expiration time for the content
500 * @param uid unique identifier for the datum;
501 * maybe 0 if no unique identifier is available
502 */
503static void
504process_local_get_result (void *cls,
505 const GNUNET_HashCode * key,
506 uint32_t size,
507 const void *data,
508 uint32_t type,
509 uint32_t priority,
510 uint32_t anonymity,
511 struct GNUNET_TIME_Absolute
512 expiration,
513 uint64_t uid)
514{
515 struct LocalGetContext *lgc = cls;
516 size_t msize;
517
518 if (key == NULL)
519 {
520 /* no further results from datastore; continue
521 processing further requests from the client and
522 allow the next task to use the datastore; also,
523 switch to P2P requests or clean up our state. */
524 next_ds_request ();
525 GNUNET_SERVER_receive_done (lgc->client,
526 GNUNET_OK);
527 if ( (lgc->results_used == 0) ||
528 (lgc->type == GNUNET_DATASTORE_BLOCKTYPE_KBLOCK) ||
529 (lgc->type == GNUNET_DATASTORE_BLOCKTYPE_SBLOCK) ||
530 (lgc->type == GNUNET_DATASTORE_BLOCKTYPE_SKBLOCK) )
531 {
532 // FIXME: initiate P2P search
533 return;
534 }
535 /* got all possible results, clean up! */
536 local_get_context_free (lgc);
537 return;
538 }
539 if (lgc->results_used == lgc->results_size)
540 {
541 GNUNET_array_grow (lgc->results,
542 lgc->results_size,
543 lgc->results_size * 2 + 2);
544 if ( (lgc->type != GNUNET_DATASTORE_BLOCKTYPE_DBLOCK) ||
545 (lgc->type != GNUNET_DATASTORE_BLOCKTYPE_IBLOCK) )
546 {
547 // FIXME: possibly grow/create BF!
548 }
549 }
550 GNUNET_CRYPTO_hash (data,
551 size,
552 &lgc->results[lgc->results_used++]);
553 if ( (lgc->type != GNUNET_DATASTORE_BLOCKTYPE_DBLOCK) ||
554 (lgc->type != GNUNET_DATASTORE_BLOCKTYPE_IBLOCK) )
555 {
556 // FIXME: add result to BF!
557 }
558 msize = size + sizeof (struct ContentMessage);
559 GNUNET_assert (msize < GNUNET_SERVER_MAX_MESSAGE_SIZE);
560 lgc->result = GNUNET_malloc (msize);
561 lgc->result->header.size = htons (msize);
562 lgc->result->header.type = htons (GNUNET_MESSAGE_TYPE_FS_CONTENT);
563 lgc->result->type = htonl (type);
564 lgc->result->expiration = GNUNET_TIME_absolute_hton (expiration);
565 memcpy (&lgc->result[1],
566 data,
567 size);
568 GNUNET_SERVER_notify_transmit_ready (lgc->client,
569 msize,
570 GNUNET_TIME_UNIT_FOREVER_REL,
571 &transmit_local_result,
572 lgc);
573}
574
575
576/**
577 * We're processing a search request from a local
578 * client. Now it is our turn to query the datastore.
579 *
580 * @param cls our closure (struct LocalGetContext)
581 * @param tc unused
582 */
583static void
192transmit_local_get (void *cls, 584transmit_local_get (void *cls,
193 int ok) 585 const struct GNUNET_SCHEDULER_TaskContext *tc)
194{ 586{
195 struct LocalGetContext *lgc = cls; 587 struct LocalGetContext *lgc = cls;
196 // FIXME: search locally
197 588
198 GNUNET_assert (GNUNET_OK == ok); 589 GNUNET_DATASTORE_get (dsh,
199 GNUNET_SERVER_receive_done (lgc->client, 590 &lgc->query,
200 GNUNET_OK); 591 lgc->type,
592 &process_local_get_result,
593 lgc,
594 GNUNET_TIME_UNIT_FOREVER_REL);
595}
201 596
202 // once we're done processing the DS reply, do:
203 next_ds_request ();
204 // FIXME: if not found, initiate P2P search
205 597
206 // FIXME: once done with "client" handle: 598/**
207 GNUNET_SERVER_client_drop (lgc->client); 599 * We're processing a search request from a local
600 * client. Now it is our turn to query the datastore.
601 *
602 * @param cls our closure (struct LocalGetContext)
603 * @param ok did we succeed to queue for datastore access, should always be GNUNET_OK
604 */
605static void
606transmit_local_get_ready (void *cls,
607 int ok)
608{
609 struct LocalGetContext *lgc = cls;
610
611 GNUNET_assert (GNUNET_OK == ok);
612 GNUNET_SCHEDULER_add_continuation (sched,
613 GNUNET_NO,
614 &transmit_local_get,
615 lgc,
616 GNUNET_SCHEDULER_REASON_PREREQ_DONE);
208} 617}
209 618
210 619
211/** 620/**
212 * Handle START_SEARCH-message. 621 * Handle START_SEARCH-message (search request from client).
213 * 622 *
214 * @param cls closure 623 * @param cls closure
215 * @param client identification of the client 624 * @param client identification of the client
@@ -227,10 +636,14 @@ handle_start_search (void *cls,
227 GNUNET_SERVER_client_keep (client); 636 GNUNET_SERVER_client_keep (client);
228 lgc = GNUNET_malloc (sizeof (struct LocalGetContext)); 637 lgc = GNUNET_malloc (sizeof (struct LocalGetContext));
229 lgc->client = client; 638 lgc->client = client;
230 // lgc->x = y; 639 lgc->type = ntohl (sm->type);
231 queue_ds_request (GNUNET_TIME_UNIT_FOREVER_REL, 640 lgc->anonymity_level = ntohl (sm->anonymity_level);
232 &transmit_local_get, 641 lgc->target = sm->target;
233 lgc); 642 lgc->query = sm->query;
643 GNUNET_CONTAINER_DLL_insert (lgc_head, lgc_tail, lgc);
644 lgc->req = queue_ds_request (GNUNET_TIME_UNIT_FOREVER_REL,
645 &transmit_local_get_ready,
646 lgc);
234} 647}
235 648
236 649
@@ -252,6 +665,29 @@ static struct GNUNET_SERVER_MessageHandler handlers[] = {
252 665
253 666
254/** 667/**
668 * A client disconnected. Remove all of its pending queries.
669 *
670 * @param cls closure, NULL
671 * @param client identification of the client
672 */
673static void
674handle_client_disconnect (void *cls,
675 struct GNUNET_SERVER_Client
676 * client)
677{
678 struct LocalGetContext *lgc;
679
680 lgc = lgc_head;
681 while ( (NULL != lgc) &&
682 (lgc->client != client) )
683 lgc = lgc->next;
684 if (lgc == NULL)
685 return; /* not one of our clients */
686 local_get_context_free (lgc);
687}
688
689
690/**
255 * Task run during shutdown. 691 * Task run during shutdown.
256 * 692 *
257 * @param cls unused 693 * @param cls unused
@@ -277,10 +713,12 @@ shutdown_task (void *cls,
277 */ 713 */
278static void 714static void
279run (void *cls, 715run (void *cls,
280 struct GNUNET_SCHEDULER_Handle *sched, 716 struct GNUNET_SCHEDULER_Handle *s,
281 struct GNUNET_SERVER_Handle *server, 717 struct GNUNET_SERVER_Handle *server,
282 const struct GNUNET_CONFIGURATION_Handle *cfg) 718 const struct GNUNET_CONFIGURATION_Handle *c)
283{ 719{
720 sched = s;
721 cfg = c;
284 dsh = GNUNET_DATASTORE_connect (cfg, 722 dsh = GNUNET_DATASTORE_connect (cfg,
285 sched); 723 sched);
286 if (NULL == dsh) 724 if (NULL == dsh)
@@ -289,9 +727,11 @@ run (void *cls,
289 _("Failed to connect to datastore service.\n")); 727 _("Failed to connect to datastore service.\n"));
290 return; 728 return;
291 } 729 }
730 GNUNET_SERVER_disconnect_notify (server,
731 &handle_client_disconnect,
732 NULL);
292 GNUNET_SERVER_add_handlers (server, handlers); 733 GNUNET_SERVER_add_handlers (server, handlers);
293 // FIXME: also handle P2P messages! 734 // FIXME: also register with core to handle P2P messages!
294
295 GNUNET_SCHEDULER_add_delayed (sched, 735 GNUNET_SCHEDULER_add_delayed (sched,
296 GNUNET_YES, 736 GNUNET_YES,
297 GNUNET_SCHEDULER_PRIORITY_IDLE, 737 GNUNET_SCHEDULER_PRIORITY_IDLE,
diff --git a/src/upnp/upnp_util.h b/src/upnp/upnp_util.h
index 32c790493..1c7555b09 100644
--- a/src/upnp/upnp_util.h
+++ b/src/upnp/upnp_util.h
@@ -1,5 +1,5 @@
1/** 1/**
2 * @file transport/upnp_util.h Utility Functions 2 * @file upnp/upnp_util.h Utility Functions
3 * @ingroup core 3 * @ingroup core
4 * 4 *
5 * gaim 5 * gaim