diff options
Diffstat (limited to 'src/namecache/namecache_api.c')
-rw-r--r-- | src/namecache/namecache_api.c | 738 |
1 files changed, 738 insertions, 0 deletions
diff --git a/src/namecache/namecache_api.c b/src/namecache/namecache_api.c new file mode 100644 index 000000000..a28ed7d53 --- /dev/null +++ b/src/namecache/namecache_api.c | |||
@@ -0,0 +1,738 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | (C) 2010-2013 Christian Grothoff (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
18 | Boston, MA 02111-1307, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file namecache/namecache_api.c | ||
23 | * @brief API to access the NAMECACHE service | ||
24 | * @author Martin Schanzenbach | ||
25 | * @author Matthias Wachs | ||
26 | * @author Christian Grothoff | ||
27 | */ | ||
28 | |||
29 | #include "platform.h" | ||
30 | #include "gnunet_util_lib.h" | ||
31 | #include "gnunet_crypto_lib.h" | ||
32 | #include "gnunet_constants.h" | ||
33 | #include "gnunet_dnsparser_lib.h" | ||
34 | #include "gnunet_arm_service.h" | ||
35 | #include "gnunet_signatures.h" | ||
36 | #include "gnunet_namecache_service.h" | ||
37 | #include "gnunet_namestore_service.h" | ||
38 | #include "namecache.h" | ||
39 | |||
40 | |||
41 | #define LOG(kind,...) GNUNET_log_from (kind, "namecache-api",__VA_ARGS__) | ||
42 | |||
43 | |||
44 | /** | ||
45 | * An QueueEntry used to store information for a pending | ||
46 | * NAMECACHE record operation | ||
47 | */ | ||
48 | struct GNUNET_NAMECACHE_QueueEntry | ||
49 | { | ||
50 | |||
51 | /** | ||
52 | * Kept in a DLL. | ||
53 | */ | ||
54 | struct GNUNET_NAMECACHE_QueueEntry *next; | ||
55 | |||
56 | /** | ||
57 | * Kept in a DLL. | ||
58 | */ | ||
59 | struct GNUNET_NAMECACHE_QueueEntry *prev; | ||
60 | |||
61 | /** | ||
62 | * Main handle to access the namecache. | ||
63 | */ | ||
64 | struct GNUNET_NAMECACHE_Handle *nsh; | ||
65 | |||
66 | /** | ||
67 | * Continuation to call | ||
68 | */ | ||
69 | GNUNET_NAMECACHE_ContinuationWithStatus cont; | ||
70 | |||
71 | /** | ||
72 | * Closure for @e cont. | ||
73 | */ | ||
74 | void *cont_cls; | ||
75 | |||
76 | /** | ||
77 | * Function to call with the blocks we get back; or NULL. | ||
78 | */ | ||
79 | GNUNET_NAMESTORE_BlockProcessor block_proc; | ||
80 | |||
81 | /** | ||
82 | * Closure for @e block_proc. | ||
83 | */ | ||
84 | void *block_proc_cls; | ||
85 | |||
86 | /** | ||
87 | * The operation id this zone iteration operation has | ||
88 | */ | ||
89 | uint32_t op_id; | ||
90 | |||
91 | }; | ||
92 | |||
93 | |||
94 | /** | ||
95 | * Message in linked list we should send to the service. The | ||
96 | * actual binary message follows this struct. | ||
97 | */ | ||
98 | struct PendingMessage | ||
99 | { | ||
100 | |||
101 | /** | ||
102 | * Kept in a DLL. | ||
103 | */ | ||
104 | struct PendingMessage *next; | ||
105 | |||
106 | /** | ||
107 | * Kept in a DLL. | ||
108 | */ | ||
109 | struct PendingMessage *prev; | ||
110 | |||
111 | /** | ||
112 | * Size of the message. | ||
113 | */ | ||
114 | size_t size; | ||
115 | |||
116 | }; | ||
117 | |||
118 | |||
119 | /** | ||
120 | * Connection to the NAMECACHE service. | ||
121 | */ | ||
122 | struct GNUNET_NAMECACHE_Handle | ||
123 | { | ||
124 | |||
125 | /** | ||
126 | * Configuration to use. | ||
127 | */ | ||
128 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
129 | |||
130 | /** | ||
131 | * Socket (if available). | ||
132 | */ | ||
133 | struct GNUNET_CLIENT_Connection *client; | ||
134 | |||
135 | /** | ||
136 | * Currently pending transmission request (or NULL). | ||
137 | */ | ||
138 | struct GNUNET_CLIENT_TransmitHandle *th; | ||
139 | |||
140 | /** | ||
141 | * Head of linked list of pending messages to send to the service | ||
142 | */ | ||
143 | struct PendingMessage *pending_head; | ||
144 | |||
145 | /** | ||
146 | * Tail of linked list of pending messages to send to the service | ||
147 | */ | ||
148 | struct PendingMessage *pending_tail; | ||
149 | |||
150 | /** | ||
151 | * Head of pending namecache queue entries | ||
152 | */ | ||
153 | struct GNUNET_NAMECACHE_QueueEntry *op_head; | ||
154 | |||
155 | /** | ||
156 | * Tail of pending namecache queue entries | ||
157 | */ | ||
158 | struct GNUNET_NAMECACHE_QueueEntry *op_tail; | ||
159 | |||
160 | /** | ||
161 | * Reconnect task | ||
162 | */ | ||
163 | GNUNET_SCHEDULER_TaskIdentifier reconnect_task; | ||
164 | |||
165 | /** | ||
166 | * Delay introduced before we reconnect. | ||
167 | */ | ||
168 | struct GNUNET_TIME_Relative reconnect_delay; | ||
169 | |||
170 | /** | ||
171 | * Should we reconnect to service due to some serious error? | ||
172 | */ | ||
173 | int reconnect; | ||
174 | |||
175 | /** | ||
176 | * Did we start to receive yet? | ||
177 | */ | ||
178 | int is_receiving; | ||
179 | |||
180 | /** | ||
181 | * The last operation id used for a NAMECACHE operation | ||
182 | */ | ||
183 | uint32_t last_op_id_used; | ||
184 | |||
185 | }; | ||
186 | |||
187 | |||
188 | /** | ||
189 | * Disconnect from service and then reconnect. | ||
190 | * | ||
191 | * @param h our handle | ||
192 | */ | ||
193 | static void | ||
194 | force_reconnect (struct GNUNET_NAMECACHE_Handle *h); | ||
195 | |||
196 | |||
197 | /** | ||
198 | * Handle an incoming message of type | ||
199 | * #GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK_RESPONSE. | ||
200 | * | ||
201 | * @param qe the respective entry in the message queue | ||
202 | * @param msg the message we received | ||
203 | * @param size the message size | ||
204 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on error and we did NOT notify the client | ||
205 | */ | ||
206 | static int | ||
207 | handle_lookup_block_response (struct GNUNET_NAMECACHE_QueueEntry *qe, | ||
208 | const struct LookupBlockResponseMessage *msg, | ||
209 | size_t size) | ||
210 | { | ||
211 | struct GNUNET_NAMESTORE_Block *block; | ||
212 | char buf[size + sizeof (struct GNUNET_NAMESTORE_Block) | ||
213 | - sizeof (struct LookupBlockResponseMessage)]; | ||
214 | |||
215 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
216 | "Received `%s'\n", | ||
217 | "LOOKUP_BLOCK_RESPONSE"); | ||
218 | if (0 == GNUNET_TIME_absolute_ntoh (msg->expire).abs_value_us) | ||
219 | { | ||
220 | /* no match found */ | ||
221 | if (NULL != qe->block_proc) | ||
222 | qe->block_proc (qe->block_proc_cls, NULL); | ||
223 | return GNUNET_OK; | ||
224 | } | ||
225 | |||
226 | block = (struct GNUNET_NAMESTORE_Block *) buf; | ||
227 | block->signature = msg->signature; | ||
228 | block->derived_key = msg->derived_key; | ||
229 | block->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_GNS_RECORD_SIGN); | ||
230 | block->purpose.size = htonl (size - sizeof (struct LookupBlockResponseMessage) + | ||
231 | sizeof (struct GNUNET_TIME_AbsoluteNBO) + | ||
232 | sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose)); | ||
233 | block->expiration_time = msg->expire; | ||
234 | memcpy (&block[1], | ||
235 | &msg[1], | ||
236 | size - sizeof (struct LookupBlockResponseMessage)); | ||
237 | if (GNUNET_OK != | ||
238 | GNUNET_NAMESTORE_block_verify (block)) | ||
239 | { | ||
240 | GNUNET_break (0); | ||
241 | return GNUNET_SYSERR; | ||
242 | } | ||
243 | if (NULL != qe->block_proc) | ||
244 | qe->block_proc (qe->block_proc_cls, block); | ||
245 | else | ||
246 | GNUNET_break (0); | ||
247 | return GNUNET_OK; | ||
248 | } | ||
249 | |||
250 | |||
251 | /** | ||
252 | * Handle an incoming message of type | ||
253 | * #GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE_RESPONSE | ||
254 | * | ||
255 | * @param qe the respective entry in the message queue | ||
256 | * @param msg the message we received | ||
257 | * @param size the message size | ||
258 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on error and we did NOT notify the client | ||
259 | */ | ||
260 | static int | ||
261 | handle_block_cache_response (struct GNUNET_NAMECACHE_QueueEntry *qe, | ||
262 | const struct BlockCacheResponseMessage *msg, | ||
263 | size_t size) | ||
264 | { | ||
265 | int res; | ||
266 | |||
267 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
268 | "Received `%s'\n", | ||
269 | "BLOCK_CACHE_RESPONSE"); | ||
270 | res = ntohl (msg->op_result); | ||
271 | /* TODO: add actual error message from namecache to response... */ | ||
272 | if (NULL != qe->cont) | ||
273 | qe->cont (qe->cont_cls, | ||
274 | res, | ||
275 | (GNUNET_OK == res) ? | ||
276 | NULL | ||
277 | : _("Namecache failed to cache block")); | ||
278 | return GNUNET_OK; | ||
279 | } | ||
280 | |||
281 | |||
282 | /** | ||
283 | * Handle incoming messages for record operations | ||
284 | * | ||
285 | * @param qe the respective zone iteration handle | ||
286 | * @param msg the message we received | ||
287 | * @param type the message type in host byte order | ||
288 | * @param size the message size | ||
289 | * @return #GNUNET_OK on success, #GNUNET_NO if we notified the client about | ||
290 | * the error, #GNUNET_SYSERR on error and we did NOT notify the client | ||
291 | */ | ||
292 | static int | ||
293 | manage_record_operations (struct GNUNET_NAMECACHE_QueueEntry *qe, | ||
294 | const struct GNUNET_MessageHeader *msg, | ||
295 | uint16_t type, | ||
296 | size_t size) | ||
297 | { | ||
298 | /* handle different message type */ | ||
299 | switch (type) | ||
300 | { | ||
301 | case GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK_RESPONSE: | ||
302 | if (size < sizeof (struct LookupBlockResponseMessage)) | ||
303 | { | ||
304 | GNUNET_break (0); | ||
305 | return GNUNET_SYSERR; | ||
306 | } | ||
307 | return handle_lookup_block_response (qe, (const struct LookupBlockResponseMessage *) msg, size); | ||
308 | case GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE_RESPONSE: | ||
309 | if (size != sizeof (struct BlockCacheResponseMessage)) | ||
310 | { | ||
311 | GNUNET_break (0); | ||
312 | return GNUNET_SYSERR; | ||
313 | } | ||
314 | return handle_block_cache_response (qe, (const struct BlockCacheResponseMessage *) msg, size); | ||
315 | default: | ||
316 | GNUNET_break (0); | ||
317 | return GNUNET_SYSERR; | ||
318 | } | ||
319 | } | ||
320 | |||
321 | |||
322 | /** | ||
323 | * Type of a function to call when we receive a message | ||
324 | * from the service. | ||
325 | * | ||
326 | * @param cls the `struct GNUNET_NAMECACHE_SchedulingHandle` | ||
327 | * @param msg message received, NULL on timeout or fatal error | ||
328 | */ | ||
329 | static void | ||
330 | process_namecache_message (void *cls, | ||
331 | const struct GNUNET_MessageHeader *msg) | ||
332 | { | ||
333 | struct GNUNET_NAMECACHE_Handle *h = cls; | ||
334 | const struct GNUNET_NAMECACHE_Header *gm; | ||
335 | struct GNUNET_NAMECACHE_QueueEntry *qe; | ||
336 | uint16_t size; | ||
337 | uint16_t type; | ||
338 | uint32_t r_id; | ||
339 | int ret; | ||
340 | |||
341 | if (NULL == msg) | ||
342 | { | ||
343 | force_reconnect (h); | ||
344 | return; | ||
345 | } | ||
346 | size = ntohs (msg->size); | ||
347 | type = ntohs (msg->type); | ||
348 | if (size < sizeof (struct GNUNET_NAMECACHE_Header)) | ||
349 | { | ||
350 | GNUNET_break_op (0); | ||
351 | GNUNET_CLIENT_receive (h->client, | ||
352 | &process_namecache_message, h, | ||
353 | GNUNET_TIME_UNIT_FOREVER_REL); | ||
354 | return; | ||
355 | } | ||
356 | gm = (const struct GNUNET_NAMECACHE_Header *) msg; | ||
357 | r_id = ntohl (gm->r_id); | ||
358 | |||
359 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
360 | "Received message type %u size %u op %u\n", | ||
361 | (unsigned int) type, | ||
362 | (unsigned int) size, | ||
363 | (unsigned int) r_id); | ||
364 | |||
365 | /* Is it a record related operation ? */ | ||
366 | for (qe = h->op_head; qe != NULL; qe = qe->next) | ||
367 | if (qe->op_id == r_id) | ||
368 | break; | ||
369 | if (NULL != qe) | ||
370 | { | ||
371 | ret = manage_record_operations (qe, msg, type, size); | ||
372 | if (GNUNET_SYSERR == ret) | ||
373 | { | ||
374 | /* protocol error, need to reconnect */ | ||
375 | h->reconnect = GNUNET_YES; | ||
376 | } | ||
377 | else | ||
378 | { | ||
379 | /* client was notified about success or failure, clean up 'qe' */ | ||
380 | GNUNET_CONTAINER_DLL_remove (h->op_head, | ||
381 | h->op_tail, | ||
382 | qe); | ||
383 | GNUNET_free (qe); | ||
384 | } | ||
385 | } | ||
386 | if (GNUNET_YES == h->reconnect) | ||
387 | { | ||
388 | force_reconnect (h); | ||
389 | return; | ||
390 | } | ||
391 | GNUNET_CLIENT_receive (h->client, &process_namecache_message, h, | ||
392 | GNUNET_TIME_UNIT_FOREVER_REL); | ||
393 | } | ||
394 | |||
395 | |||
396 | /** | ||
397 | * Transmit messages from the message queue to the service | ||
398 | * (if there are any, and if we are not already trying). | ||
399 | * | ||
400 | * @param h handle to use | ||
401 | */ | ||
402 | static void | ||
403 | do_transmit (struct GNUNET_NAMECACHE_Handle *h); | ||
404 | |||
405 | |||
406 | /** | ||
407 | * We can now transmit a message to NAMECACHE. Do it. | ||
408 | * | ||
409 | * @param cls the `struct GNUNET_NAMECACHE_Handle` | ||
410 | * @param size number of bytes we can transmit | ||
411 | * @param buf where to copy the messages | ||
412 | * @return number of bytes copied into @a buf | ||
413 | */ | ||
414 | static size_t | ||
415 | transmit_message_to_namecache (void *cls, | ||
416 | size_t size, | ||
417 | void *buf) | ||
418 | { | ||
419 | struct GNUNET_NAMECACHE_Handle *h = cls; | ||
420 | struct PendingMessage *p; | ||
421 | size_t ret; | ||
422 | char *cbuf; | ||
423 | |||
424 | h->th = NULL; | ||
425 | if ((0 == size) || (NULL == buf)) | ||
426 | { | ||
427 | force_reconnect (h); | ||
428 | return 0; | ||
429 | } | ||
430 | ret = 0; | ||
431 | cbuf = buf; | ||
432 | while ( (NULL != (p = h->pending_head)) && | ||
433 | (p->size <= size) ) | ||
434 | { | ||
435 | memcpy (&cbuf[ret], &p[1], p->size); | ||
436 | ret += p->size; | ||
437 | size -= p->size; | ||
438 | GNUNET_CONTAINER_DLL_remove (h->pending_head, | ||
439 | h->pending_tail, | ||
440 | p); | ||
441 | if (GNUNET_NO == h->is_receiving) | ||
442 | { | ||
443 | h->is_receiving = GNUNET_YES; | ||
444 | GNUNET_CLIENT_receive (h->client, | ||
445 | &process_namecache_message, h, | ||
446 | GNUNET_TIME_UNIT_FOREVER_REL); | ||
447 | } | ||
448 | GNUNET_free (p); | ||
449 | } | ||
450 | do_transmit (h); | ||
451 | return ret; | ||
452 | } | ||
453 | |||
454 | |||
455 | /** | ||
456 | * Transmit messages from the message queue to the service | ||
457 | * (if there are any, and if we are not already trying). | ||
458 | * | ||
459 | * @param h handle to use | ||
460 | */ | ||
461 | static void | ||
462 | do_transmit (struct GNUNET_NAMECACHE_Handle *h) | ||
463 | { | ||
464 | struct PendingMessage *p; | ||
465 | |||
466 | if (NULL != h->th) | ||
467 | return; /* transmission request already pending */ | ||
468 | if (NULL == (p = h->pending_head)) | ||
469 | return; /* transmission queue empty */ | ||
470 | if (NULL == h->client) | ||
471 | return; /* currently reconnecting */ | ||
472 | h->th = GNUNET_CLIENT_notify_transmit_ready (h->client, p->size, | ||
473 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
474 | GNUNET_NO, &transmit_message_to_namecache, | ||
475 | h); | ||
476 | GNUNET_break (NULL != h->th); | ||
477 | } | ||
478 | |||
479 | |||
480 | /** | ||
481 | * Reconnect to namecache service. | ||
482 | * | ||
483 | * @param h the handle to the NAMECACHE service | ||
484 | */ | ||
485 | static void | ||
486 | reconnect (struct GNUNET_NAMECACHE_Handle *h) | ||
487 | { | ||
488 | GNUNET_assert (NULL == h->client); | ||
489 | h->client = GNUNET_CLIENT_connect ("namecache", h->cfg); | ||
490 | GNUNET_assert (NULL != h->client); | ||
491 | do_transmit (h); | ||
492 | } | ||
493 | |||
494 | |||
495 | /** | ||
496 | * Re-establish the connection to the service. | ||
497 | * | ||
498 | * @param cls handle to use to re-connect. | ||
499 | * @param tc scheduler context | ||
500 | */ | ||
501 | static void | ||
502 | reconnect_task (void *cls, | ||
503 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
504 | { | ||
505 | struct GNUNET_NAMECACHE_Handle *h = cls; | ||
506 | |||
507 | h->reconnect_task = GNUNET_SCHEDULER_NO_TASK; | ||
508 | reconnect (h); | ||
509 | } | ||
510 | |||
511 | |||
512 | /** | ||
513 | * Disconnect from service and then reconnect. | ||
514 | * | ||
515 | * @param h our handle | ||
516 | */ | ||
517 | static void | ||
518 | force_reconnect (struct GNUNET_NAMECACHE_Handle *h) | ||
519 | { | ||
520 | if (NULL != h->th) | ||
521 | { | ||
522 | GNUNET_CLIENT_notify_transmit_ready_cancel (h->th); | ||
523 | h->th = NULL; | ||
524 | } | ||
525 | h->reconnect = GNUNET_NO; | ||
526 | GNUNET_CLIENT_disconnect (h->client); | ||
527 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
528 | "Reconnecting to namecache\n"); | ||
529 | h->is_receiving = GNUNET_NO; | ||
530 | h->client = NULL; | ||
531 | h->reconnect_delay = GNUNET_TIME_STD_BACKOFF (h->reconnect_delay); | ||
532 | h->reconnect_task = GNUNET_SCHEDULER_add_delayed (h->reconnect_delay, | ||
533 | &reconnect_task, | ||
534 | h); | ||
535 | } | ||
536 | |||
537 | |||
538 | /** | ||
539 | * Get a fresh operation id to distinguish between namecache requests | ||
540 | * | ||
541 | * @param h the namecache handle | ||
542 | * @return next operation id to use | ||
543 | */ | ||
544 | static uint32_t | ||
545 | get_op_id (struct GNUNET_NAMECACHE_Handle *h) | ||
546 | { | ||
547 | return h->last_op_id_used++; | ||
548 | } | ||
549 | |||
550 | |||
551 | /** | ||
552 | * Initialize the connection with the NAMECACHE service. | ||
553 | * | ||
554 | * @param cfg configuration to use | ||
555 | * @return handle to the GNS service, or NULL on error | ||
556 | */ | ||
557 | struct GNUNET_NAMECACHE_Handle * | ||
558 | GNUNET_NAMECACHE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
559 | { | ||
560 | struct GNUNET_NAMECACHE_Handle *h; | ||
561 | |||
562 | h = GNUNET_new (struct GNUNET_NAMECACHE_Handle); | ||
563 | h->cfg = cfg; | ||
564 | h->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect_task, h); | ||
565 | h->last_op_id_used = 0; | ||
566 | return h; | ||
567 | } | ||
568 | |||
569 | |||
570 | /** | ||
571 | * Disconnect from the namecache service (and free associated | ||
572 | * resources). | ||
573 | * | ||
574 | * @param h handle to the namecache | ||
575 | */ | ||
576 | void | ||
577 | GNUNET_NAMECACHE_disconnect (struct GNUNET_NAMECACHE_Handle *h) | ||
578 | { | ||
579 | struct PendingMessage *p; | ||
580 | struct GNUNET_NAMECACHE_QueueEntry *q; | ||
581 | |||
582 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Cleaning up\n"); | ||
583 | GNUNET_assert (NULL != h); | ||
584 | if (NULL != h->th) | ||
585 | { | ||
586 | GNUNET_CLIENT_notify_transmit_ready_cancel (h->th); | ||
587 | h->th = NULL; | ||
588 | } | ||
589 | while (NULL != (p = h->pending_head)) | ||
590 | { | ||
591 | GNUNET_CONTAINER_DLL_remove (h->pending_head, h->pending_tail, p); | ||
592 | GNUNET_free (p); | ||
593 | } | ||
594 | GNUNET_break (NULL == h->op_head); | ||
595 | while (NULL != (q = h->op_head)) | ||
596 | { | ||
597 | GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, q); | ||
598 | GNUNET_free (q); | ||
599 | } | ||
600 | if (NULL != h->client) | ||
601 | { | ||
602 | GNUNET_CLIENT_disconnect (h->client); | ||
603 | h->client = NULL; | ||
604 | } | ||
605 | if (GNUNET_SCHEDULER_NO_TASK != h->reconnect_task) | ||
606 | { | ||
607 | GNUNET_SCHEDULER_cancel (h->reconnect_task); | ||
608 | h->reconnect_task = GNUNET_SCHEDULER_NO_TASK; | ||
609 | } | ||
610 | GNUNET_free (h); | ||
611 | } | ||
612 | |||
613 | |||
614 | /** | ||
615 | * Store an item in the namecache. If the item is already present, | ||
616 | * it is replaced with the new record. | ||
617 | * | ||
618 | * @param h handle to the namecache | ||
619 | * @param block block to store | ||
620 | * @param cont continuation to call when done | ||
621 | * @param cont_cls closure for cont | ||
622 | * @return handle to abort the request | ||
623 | */ | ||
624 | struct GNUNET_NAMECACHE_QueueEntry * | ||
625 | GNUNET_NAMECACHE_block_cache (struct GNUNET_NAMECACHE_Handle *h, | ||
626 | const struct GNUNET_NAMESTORE_Block *block, | ||
627 | GNUNET_NAMECACHE_ContinuationWithStatus cont, | ||
628 | void *cont_cls) | ||
629 | { | ||
630 | struct GNUNET_NAMECACHE_QueueEntry *qe; | ||
631 | struct PendingMessage *pe; | ||
632 | struct BlockCacheMessage *msg; | ||
633 | uint32_t rid; | ||
634 | size_t blen; | ||
635 | size_t msg_size; | ||
636 | |||
637 | GNUNET_assert (NULL != h); | ||
638 | blen = ntohl (block->purpose.size) | ||
639 | - sizeof (struct GNUNET_TIME_AbsoluteNBO) | ||
640 | - sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose); | ||
641 | rid = get_op_id (h); | ||
642 | qe = GNUNET_new (struct GNUNET_NAMECACHE_QueueEntry); | ||
643 | qe->nsh = h; | ||
644 | qe->cont = cont; | ||
645 | qe->cont_cls = cont_cls; | ||
646 | qe->op_id = rid; | ||
647 | GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, qe); | ||
648 | |||
649 | /* setup msg */ | ||
650 | msg_size = sizeof (struct BlockCacheMessage) + blen; | ||
651 | pe = GNUNET_malloc (sizeof (struct PendingMessage) + msg_size); | ||
652 | pe->size = msg_size; | ||
653 | msg = (struct BlockCacheMessage *) &pe[1]; | ||
654 | msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE); | ||
655 | msg->gns_header.header.size = htons (msg_size); | ||
656 | msg->gns_header.r_id = htonl (rid); | ||
657 | msg->expire = block->expiration_time; | ||
658 | msg->signature = block->signature; | ||
659 | msg->derived_key = block->derived_key; | ||
660 | memcpy (&msg[1], &block[1], blen); | ||
661 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
662 | "Sending `%s' message with size %u and expiration %s\n", | ||
663 | "NAMECACHE_BLOCK_CACHE", | ||
664 | (unsigned int) msg_size, | ||
665 | GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh (msg->expire))); | ||
666 | GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe); | ||
667 | do_transmit (h); | ||
668 | return qe; | ||
669 | } | ||
670 | |||
671 | |||
672 | /** | ||
673 | * Get a result for a particular key from the namecache. The processor | ||
674 | * will only be called once. | ||
675 | * | ||
676 | * @param h handle to the namecache | ||
677 | * @param derived_hash hash of zone key combined with name to lookup | ||
678 | * @param proc function to call on the matching block, or with | ||
679 | * NULL if there is no matching block | ||
680 | * @param proc_cls closure for proc | ||
681 | * @return a handle that can be used to cancel | ||
682 | */ | ||
683 | struct GNUNET_NAMECACHE_QueueEntry * | ||
684 | GNUNET_NAMECACHE_lookup_block (struct GNUNET_NAMECACHE_Handle *h, | ||
685 | const struct GNUNET_HashCode *derived_hash, | ||
686 | GNUNET_NAMESTORE_BlockProcessor proc, void *proc_cls) | ||
687 | { | ||
688 | struct GNUNET_NAMECACHE_QueueEntry *qe; | ||
689 | struct PendingMessage *pe; | ||
690 | struct LookupBlockMessage *msg; | ||
691 | size_t msg_size; | ||
692 | uint32_t rid; | ||
693 | |||
694 | GNUNET_assert (NULL != h); | ||
695 | GNUNET_assert (NULL != derived_hash); | ||
696 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
697 | "Looking for block under %s\n", | ||
698 | GNUNET_h2s (derived_hash)); | ||
699 | rid = get_op_id(h); | ||
700 | qe = GNUNET_new (struct GNUNET_NAMECACHE_QueueEntry); | ||
701 | qe->nsh = h; | ||
702 | qe->block_proc = proc; | ||
703 | qe->block_proc_cls = proc_cls; | ||
704 | qe->op_id = rid; | ||
705 | GNUNET_CONTAINER_DLL_insert_tail (h->op_head, h->op_tail, qe); | ||
706 | |||
707 | msg_size = sizeof (struct LookupBlockMessage); | ||
708 | pe = GNUNET_malloc (sizeof (struct PendingMessage) + msg_size); | ||
709 | pe->size = msg_size; | ||
710 | msg = (struct LookupBlockMessage *) &pe[1]; | ||
711 | msg->gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK); | ||
712 | msg->gns_header.header.size = htons (msg_size); | ||
713 | msg->gns_header.r_id = htonl (rid); | ||
714 | msg->query = *derived_hash; | ||
715 | GNUNET_CONTAINER_DLL_insert_tail (h->pending_head, h->pending_tail, pe); | ||
716 | do_transmit (h); | ||
717 | return qe; | ||
718 | } | ||
719 | |||
720 | |||
721 | /** | ||
722 | * Cancel a namecache operation. The final callback from the | ||
723 | * operation must not have been done yet. | ||
724 | * | ||
725 | * @param qe operation to cancel | ||
726 | */ | ||
727 | void | ||
728 | GNUNET_NAMECACHE_cancel (struct GNUNET_NAMECACHE_QueueEntry *qe) | ||
729 | { | ||
730 | struct GNUNET_NAMECACHE_Handle *h = qe->nsh; | ||
731 | |||
732 | GNUNET_assert (NULL != qe); | ||
733 | GNUNET_CONTAINER_DLL_remove (h->op_head, h->op_tail, qe); | ||
734 | GNUNET_free(qe); | ||
735 | } | ||
736 | |||
737 | |||
738 | /* end of namecache_api.c */ | ||