summaryrefslogtreecommitdiff
path: root/src/gns/gns_api.c
diff options
context:
space:
mode:
authorMartin Schanzenbach <mschanzenbach@posteo.de>2012-02-16 14:21:22 +0000
committerMartin Schanzenbach <mschanzenbach@posteo.de>2012-02-16 14:21:22 +0000
commitbd742f26f08fed45b48eeb1567447acd7a77d350 (patch)
tree4f526d6824b91946d3ec52b8e2d95292b75adea0 /src/gns/gns_api.c
parent758f38a2171dadd20328c7db93164bbcd46b72dc (diff)
downloadgnunet-bd742f26f08fed45b48eeb1567447acd7a77d350.tar.gz
gnunet-bd742f26f08fed45b48eeb1567447acd7a77d350.zip
- added makefile, borrowed lots of code from dht for client handling
Diffstat (limited to 'src/gns/gns_api.c')
-rw-r--r--src/gns/gns_api.c400
1 files changed, 359 insertions, 41 deletions
diff --git a/src/gns/gns_api.c b/src/gns/gns_api.c
index e6b1b9513..ed0b447a7 100644
--- a/src/gns/gns_api.c
+++ b/src/gns/gns_api.c
@@ -31,11 +31,79 @@
31#include "gnunet_hello_lib.h" 31#include "gnunet_hello_lib.h"
32#include "gnunet_protocols.h" 32#include "gnunet_protocols.h"
33#include "gnunet_dht_service.h" 33#include "gnunet_dht_service.h"
34#include "gns.h"
35#include "gnunet_gns_service.h"
34 36
35#define DEBUG_GNS_API GNUNET_EXTRA_LOGGING 37#define DEBUG_GNS_API GNUNET_EXTRA_LOGGING
36 38
37#define LOG(kind,...) GNUNET_log_from (kind, "gns-api",__VA_ARGS__) 39#define LOG(kind,...) GNUNET_log_from (kind, "gns-api",__VA_ARGS__)
38 40
41/* TODO into gnunet_protocols */
42#define GNUNET_MESSAGE_TYPE_GNS_CLIENT_LOOKUP 23
43#define GNUNET_MESSAGE_TYPE_GNS_CLIENT_RESULT 24
44
45/**
46 * Entry in our list of messages to be (re-)transmitted.
47 */
48struct PendingMessage
49{
50 /**
51 * This is a doubly-linked list.
52 */
53 struct PendingMessage *prev;
54
55 /**
56 * This is a doubly-linked list.
57 */
58 struct PendingMessage *next;
59
60 /**
61 * Message that is pending, allocated at the end
62 * of this struct.
63 */
64 const struct GNUNET_MessageHeader *msg;
65
66 /**
67 * Handle to the GNS API context.
68 */
69 struct GNUNET_GNS_Handle *handle;
70
71 /**
72 * Continuation to call when the request has been
73 * transmitted (for the first time) to the service; can be NULL.
74 */
75 GNUNET_SCHEDULER_Task cont;
76
77 /**
78 * Closure for 'cont'.
79 */
80 void *cont_cls;
81
82 /**
83 * Timeout task for this message
84 */
85 GNUNET_SCHEDULER_TaskIdentifier timeout_task;
86
87 /**
88 * Unique ID for this request
89 */
90 uint64_t unique_id;
91
92 /**
93 * Free the saved message once sent, set to GNUNET_YES for messages
94 * that do not receive responses; GNUNET_NO if this pending message
95 * is aliased from a 'struct GNUNET_DHT_RouteHandle' and will be freed
96 * from there.
97 */
98
99 int free_on_send;
100 /**
101 * GNUNET_YES if this message is in our pending queue right now.
102 */
103 int in_pending_queue;
104
105};
106
39/** 107/**
40 * Handle to a Lookup request 108 * Handle to a Lookup request
41 */ 109 */
@@ -67,8 +135,17 @@ struct GNUNET_GNS_LookupHandle
67 */ 135 */
68 uint64_t unique_id; 136 uint64_t unique_id;
69 137
138 struct PendingMessage *message;
139
70}; 140};
71 141
142/**
143 * A GNS Record.
144 */
145struct GNUNET_GNS_Record
146{
147 enum GNUNET_GNS_RecordType type;
148};
72 149
73/** 150/**
74 * Connection to the GNS service. 151 * Connection to the GNS service.
@@ -91,6 +168,21 @@ struct GNUNET_GNS_Handle
91 */ 168 */
92 struct GNUNET_CLIENT_TransmitHandle *th; 169 struct GNUNET_CLIENT_TransmitHandle *th;
93 170
171 /**
172 * Head of linked list of messages we would like to transmit.
173 */
174 struct PendingMessage *pending_head;
175
176 /**
177 * Tail of linked list of messages we would like to transmit.
178 */
179 struct PendingMessage *pending_tail;
180
181 /**
182 * Hash map containing the current outstanding unique requests.
183 */
184 struct GNUNET_CONTAINER_MultiHashMap *active_requests;
185
94 GNUNET_SCHEDULER_TaskIdentifier reconnect_task; 186 GNUNET_SCHEDULER_TaskIdentifier reconnect_task;
95 187
96 /** 188 /**
@@ -110,6 +202,12 @@ struct GNUNET_GNS_Handle
110 int in_receive; 202 int in_receive;
111}; 203};
112 204
205/**
206 * Try to send messages from list of messages to send
207 * @param handle GNS_Handle
208 */
209static void
210process_pending_messages (struct GNUNET_GNS_Handle *handle);
113 211
114/** 212/**
115 * Try to (re)connect to the GNS service. 213 * Try to (re)connect to the GNS service.
@@ -143,7 +241,7 @@ try_reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
143{ 241{
144 struct GNUNET_GNS_Handle *handle = cls; 242 struct GNUNET_GNS_Handle *handle = cls;
145 243
146#if DEBUG_DHT 244#if DEBUG_GNS
147 LOG (GNUNET_ERROR_TYPE_DEBUG, "Reconnecting with GNS %p\n", handle); 245 LOG (GNUNET_ERROR_TYPE_DEBUG, "Reconnecting with GNS %p\n", handle);
148#endif 246#endif
149 handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK; 247 handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
@@ -156,7 +254,7 @@ try_reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
156 handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK; 254 handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
157 if (GNUNET_YES != try_connect (handle)) 255 if (GNUNET_YES != try_connect (handle))
158 { 256 {
159#if DEBUG_DHT 257#if DEBUG_GNS
160 LOG (GNUNET_ERROR_TYPE_DEBUG, "GNS reconnect failed(!)\n"); 258 LOG (GNUNET_ERROR_TYPE_DEBUG, "GNS reconnect failed(!)\n");
161#endif 259#endif
162 return; 260 return;
@@ -190,11 +288,215 @@ do_disconnect (struct GNUNET_GNS_Handle *handle)
190 GNUNET_SCHEDULER_add_delayed (handle->retry_time, &try_reconnect, handle); 288 GNUNET_SCHEDULER_add_delayed (handle->retry_time, &try_reconnect, handle);
191} 289}
192 290
291/**
292 * Transmit the next pending message, called by notify_transmit_ready
293 */
294static size_t
295transmit_pending (void *cls, size_t size, void *buf);
296
297/**
298 * Handler for messages received from the GNS service
299 *
300 * @param cls the 'struct GNUNET_GNS_Handle'
301 * @param msg the incoming message
302 */
303static void
304message_handler (void *cls, const struct GNUNET_MessageHeader *msg);
305
306/**
307 * Try to send messages from list of messages to send
308 */
309static void
310process_pending_messages (struct GNUNET_GNS_Handle *handle)
311{
312 struct PendingMessage *head;
313
314 if (handle->client == NULL)
315 {
316 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
317 "process_pending_messages called, but client is null, reconnecting\n");
318 do_disconnect (handle);
319 return;
320 }
321 if (handle->th != NULL)
322 return;
323 if (NULL == (head = handle->pending_head))
324 return;
325 handle->th =
326 GNUNET_CLIENT_notify_transmit_ready (handle->client,
327 ntohs (head->msg->size),
328 GNUNET_TIME_UNIT_FOREVER_REL,
329 GNUNET_YES, &transmit_pending,
330 handle);
331 if (NULL != handle->th)
332 return;
333 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
334 "notify_transmit_ready returned NULL, reconnecting\n");
335 do_disconnect (handle);
336}
337
338
339/**
340 * Transmit the next pending message, called by notify_transmit_ready
341 */
342static size_t
343transmit_pending (void *cls, size_t size, void *buf)
344{
345 struct GNUNET_GNS_Handle *handle = cls;
346 struct PendingMessage *head;
347 size_t tsize;
348
349 handle->th = NULL;
350 if (buf == NULL)
351 {
352#if DEBUG_GNS
353 LOG (GNUNET_ERROR_TYPE_DEBUG,
354 "Transmission to GNS service failed! Reconnecting!\n");
355#endif
356 do_disconnect (handle);
357 return 0;
358 }
359 if (NULL == (head = handle->pending_head))
360 return 0;
361
362 tsize = ntohs (head->msg->size);
363 if (size < tsize)
364 {
365 process_pending_messages (handle);
366 return 0;
367 }
368 memcpy (buf, head->msg, tsize);
369 GNUNET_CONTAINER_DLL_remove (handle->pending_head, handle->pending_tail,
370 head);
371 head->in_pending_queue = GNUNET_NO;
372 if (head->timeout_task != GNUNET_SCHEDULER_NO_TASK)
373 {
374 GNUNET_SCHEDULER_cancel (head->timeout_task);
375 head->timeout_task = GNUNET_SCHEDULER_NO_TASK;
376 }
377 if (GNUNET_YES == head->free_on_send)
378 GNUNET_free (head);
379 process_pending_messages (handle);
380#if DEBUG_GNS
381 LOG (GNUNET_ERROR_TYPE_DEBUG,
382 "Forwarded request of %u bytes to GNS service\n", (unsigned int) tsize);
383#endif
384 if (GNUNET_NO == handle->in_receive)
385 {
386#if DEBUG_GNS
387 LOG (GNUNET_ERROR_TYPE_DEBUG, "Starting to process replies from GNS\n");
388#endif
389 handle->in_receive = GNUNET_YES;
390 GNUNET_CLIENT_receive (handle->client, &message_handler, handle,
391 GNUNET_TIME_UNIT_FOREVER_REL);
392 }
393 return tsize;
394}
395
396/**
397 * Process a given reply that might match the given
398 * request.
399 *
400 * @param cls the 'struct GNUNET_GNS_ClientResultMessage'
401 * @param key query of the request
402 * @param value the 'struct GNUNET_GNS_LookupHandle' of a request matching the same key
403 * @return GNUNET_YES to continue to iterate over all results,
404 * GNUNET_NO if the reply is malformed
405 */
406static int
407process_reply (void *cls, const GNUNET_HashCode * key, void *value)
408{
409 const struct GNUNET_GNS_ClientResultMessage *gns_msg = cls;
410 struct GNUNET_GNS_LookupHandle *lookup_handle = value;
411 const struct GNUNET_GNS_Record *records;
412 uint32_t num_records;
413 size_t meta_length;
414 size_t msize;
415
416 if (gns_msg->unique_id != lookup_handle->unique_id)
417 {
418 /* UID mismatch */
419#if DEBUG_GNS
420 LOG (GNUNET_ERROR_TYPE_DEBUG,
421 "Ignoring reply for %s: UID mismatch: %llu/%llu\n", GNUNET_h2s (key),
422 gns_msg->unique_id, lookup_handle->unique_id);
423#endif
424 return GNUNET_YES;
425 }
426 msize = ntohs (gns_msg->header.size);
427 num_records = ntohl (gns_msg->num_records);
428 meta_length =
429 sizeof (struct GNUNET_GNS_ClientResultMessage) +
430 sizeof (struct GNUNET_GNS_Record) * (num_records);
431 if ((msize < meta_length) ||
432 (num_records >
433 GNUNET_SERVER_MAX_MESSAGE_SIZE / sizeof (struct GNUNET_GNS_Record)))
434 {
435 GNUNET_break (0);
436 return GNUNET_NO;
437 }
438#if DEBUG_GNS
439 LOG (GNUNET_ERROR_TYPE_DEBUG, "Giving %u byte reply for %s to application\n",
440 (unsigned int) (msize - meta_length), GNUNET_h2s (key));
441#endif
442 records = (const struct GNUNET_GNS_Record *) &gns_msg[1];
443 lookup_handle->iter (lookup_handle->iter_cls, key, records, num_records);
444 return GNUNET_YES;
445}
446
447
448/**
449 * Handler for messages received from the GNS service
450 *
451 * @param cls the 'struct GNUNET_GNS_Handle'
452 * @param msg the incoming message
453 */
454static void
455message_handler (void *cls, const struct GNUNET_MessageHeader *msg)
456{
457 struct GNUNET_GNS_Handle *handle = cls;
458 const struct GNUNET_GNS_ClientResultMessage *gns_msg;
459
460 if (msg == NULL)
461 {
462#if DEBUG_GNS
463 LOG (GNUNET_ERROR_TYPE_DEBUG,
464 "Error receiving data from GNS service, reconnecting\n");
465#endif
466 do_disconnect (handle);
467 return;
468 }
469 if (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_GNS_CLIENT_RESULT)
470 {
471 GNUNET_break (0);
472 do_disconnect (handle);
473 return;
474 }
475 if (ntohs (msg->size) < sizeof (struct GNUNET_GNS_ClientResultMessage))
476 {
477 GNUNET_break (0);
478 do_disconnect (handle);
479 return;
480 }
481 gns_msg = (const struct GNUNET_GNS_ClientResultMessage *) msg;
482#if DEBUG_GNS
483 LOG (GNUNET_ERROR_TYPE_DEBUG, "Received reply for `%s' from GNS service %p\n",
484 &gns_msg->name, handle);
485#endif
486 /* TODO uniquely identify requests... maybe hash(name) or uid */
487 GNUNET_CONTAINER_multihashmap_get_multiple (handle->active_requests,
488 &gns_msg->key, &process_reply,
489 (void *) gns_msg);
490 GNUNET_CLIENT_receive (handle->client, &message_handler, handle,
491 GNUNET_TIME_UNIT_FOREVER_REL);
492}
493
193 494
194/** 495/**
195 * Initialize the connection with the GNS service. 496 * Initialize the connection with the GNS service.
196 * 497 *
197 * @param cfg configuration to use 498 * @param cfg configuration to use
499 * @param ht_len size of the internal hash table to use for parallel requests
198 * @return handle to the GNS service, or NULL on error 500 * @return handle to the GNS service, or NULL on error
199 */ 501 */
200struct GNUNET_GNS_Handle * 502struct GNUNET_GNS_Handle *
@@ -225,7 +527,7 @@ GNUNET_GNS_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
225void 527void
226GNUNET_GNS_disconnect (struct GNUNET_GNS_Handle *handle) 528GNUNET_GNS_disconnect (struct GNUNET_GNS_Handle *handle)
227{ 529{
228 /* disco from GNS */ 530 /* disco from GNS */
229} 531}
230 532
231 533
@@ -233,38 +535,28 @@ GNUNET_GNS_disconnect (struct GNUNET_GNS_Handle *handle)
233 * Add a new record to the GNS. 535 * Add a new record to the GNS.
234 * 536 *
235 * @param handle handle to GNS service 537 * @param handle handle to GNS service
236 * @param key the key to store under 538 * @param record the record to store
237 * @param desired_replication_level estimate of how many
238 * nearest peers this request should reach
239 * @param options routing options for this message
240 * @param type type of the value
241 * @param size number of bytes in data; must be less than 64k
242 * @param data the data to store
243 * @param exp desired expiration time for the value 539 * @param exp desired expiration time for the value
244 * @param timeout how long to wait for transmission of this request 540 * @param timeout how long to wait for transmission of this request
245 * @param cont continuation to call when done (transmitting request to service)
246 * @param cont_cls closure for cont
247 */ 541 */
248void 542void
249GNUNET_GNS_add_record (struct GNUNET_GNS_Handle *handle, const GNUNET_HashCode * key, 543GNUNET_GNS_add_record (struct GNUNET_GNS_Handle *handle,
250 uint32_t desired_replication_level, 544 const char* name,
251 enum GNUNET_DHT_RouteOption options, 545 enum GNUNET_GNS_RecordType type,
252 enum GNUNET_BLOCK_Type type, size_t size, const char *data, 546 size_t size, const char *data,
253 struct GNUNET_TIME_Absolute exp, 547 struct GNUNET_TIME_Absolute exp,
254 struct GNUNET_TIME_Relative timeout, GNUNET_SCHEDULER_Task cont, 548 struct GNUNET_TIME_Relative timeout)
255 void *cont_cls)
256{ 549{
257 /** 550 /**
258 * build add record message 551 * build add record message
259 */ 552 */
260 struct GNUNET_GNS_Record *record; 553 struct GNUNET_GNS_Record *record;
261
262 record = GNUNET_malloc(sizeof (struct GNUNET_GNS_Record));
263 /* TODO fill */
264 queue_record_msg(handle, record);
265}
266
267 554
555 record = GNUNET_malloc(sizeof (struct GNUNET_GNS_Record));
556 /**
557 * TODO
558 * queue_record_msg(handle, record);
559 **/
268} 560}
269 561
270 562
@@ -273,13 +565,7 @@ GNUNET_GNS_add_record (struct GNUNET_GNS_Handle *handle, const GNUNET_HashCode *
273 * 565 *
274 * @param handle handle to the GNS service 566 * @param handle handle to the GNS service
275 * @param timeout how long to wait for transmission of this request to the service 567 * @param timeout how long to wait for transmission of this request to the service
276 * @param type expected type of the response object 568 * @param name the name to look up
277 * @param key the key to look up
278 * @param desired_replication_level estimate of how many
279 nearest peers this request should reach
280 * @param options routing options for this message
281 * @param xquery extended query data (can be NULL, depending on type)
282 * @param xquery_size number of bytes in xquery
283 * @param iter function to call on each result 569 * @param iter function to call on each result
284 * @param iter_cls closure for iter 570 * @param iter_cls closure for iter
285 * @return handle to stop the async get 571 * @return handle to stop the async get
@@ -287,13 +573,45 @@ GNUNET_GNS_add_record (struct GNUNET_GNS_Handle *handle, const GNUNET_HashCode *
287struct GNUNET_GNS_LookupHandle * 573struct GNUNET_GNS_LookupHandle *
288GNUNET_GNS_lookup_start (struct GNUNET_GNS_Handle *handle, 574GNUNET_GNS_lookup_start (struct GNUNET_GNS_Handle *handle,
289 struct GNUNET_TIME_Relative timeout, 575 struct GNUNET_TIME_Relative timeout,
290 enum GNUNET_BLOCK_Type type, const GNUNET_HashCode * key, 576 const char * name,
291 uint32_t desired_replication_level, 577 enum GNUNET_GNS_RecordType type,
292 enum GNUNET_DHT_RouteOption options, const void *xquery, 578 GNUNET_GNS_LookupIterator iter,
293 size_t xquery_size, GNUNET_GNS_LookupIterator iter,
294 void *iter_cls) 579 void *iter_cls)
295{ 580{
296 /* IPC to look for local entries, start dht lookup, return lookup_handle */ 581 /* IPC to look for local entries, start dht lookup, return lookup_handle */
582 struct GNUNET_GNS_ClientLookupMessage *lookup_msg;
583 struct GNUNET_GNS_LookupHandle *lookup_handle;
584 size_t msize;
585 struct PendingMessage *pending;
586
587 msize = sizeof (struct GNUNET_GNS_ClientLookupMessage) + strlen(name);
588#if DEBUG_GNS
589 LOG (GNUNET_ERROR_TYPE_DEBUG, "Starting lookup for %s in GNS %p\n",
590 name, handle);
591#endif
592 pending = GNUNET_malloc (sizeof (struct PendingMessage) + msize);
593 lookup_msg = (struct GNUNET_GNS_ClientLookupMessage *) &pending[1];
594 pending->msg = &lookup_msg->header;
595 pending->handle = handle;
596 pending->free_on_send = GNUNET_NO;
597 lookup_msg->header.size = htons (msize);
598 lookup_msg->header.type = htons (GNUNET_MESSAGE_TYPE_GNS_CLIENT_LOOKUP);
599 lookup_msg->namelen = strlen(name);
600 memcpy(&lookup_msg[1], name, strlen(name));
601 handle->uid_gen++;
602 lookup_msg->unique_id = handle->uid_gen;
603 GNUNET_CONTAINER_DLL_insert (handle->pending_head, handle->pending_tail,
604 pending);
605 pending->in_pending_queue = GNUNET_YES;
606 lookup_handle = GNUNET_malloc (sizeof (struct GNUNET_GNS_LookupHandle));
607 lookup_handle->iter = iter;
608 lookup_handle->iter_cls = iter_cls;
609 lookup_handle->message = pending;
610 lookup_handle->unique_id = lookup_msg->unique_id;
611 GNUNET_CONTAINER_multihashmap_put (handle->active_requests, key, lookup_handle,
612 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
613 process_pending_messages (handle);
614 return lookup_handle;
297} 615}
298 616
299 617
@@ -305,7 +623,7 @@ GNUNET_GNS_lookup_start (struct GNUNET_GNS_Handle *handle,
305void 623void
306GNUNET_GNS_lookup_stop (struct GNUNET_GNS_LookupHandle *lookup_handle) 624GNUNET_GNS_lookup_stop (struct GNUNET_GNS_LookupHandle *lookup_handle)
307{ 625{
308 /* TODO Stop dht lookups */ 626 /* TODO Stop dht lookups */
309} 627}
310 628
311 629