aboutsummaryrefslogtreecommitdiff
path: root/src/peerinfo/peerinfo_api.c
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2016-06-24 11:54:36 +0000
committerChristian Grothoff <christian@grothoff.org>2016-06-24 11:54:36 +0000
commiteafc8188ef6584f77dc4dbc6827210f384986e1a (patch)
tree501f87ddd224b0cbd5aaf9008b57005b129cac24 /src/peerinfo/peerinfo_api.c
parent2e95a6961bf57170b215ab28e50dbf2376d46747 (diff)
downloadgnunet-eafc8188ef6584f77dc4dbc6827210f384986e1a.tar.gz
gnunet-eafc8188ef6584f77dc4dbc6827210f384986e1a.zip
update peerinfo API to use MQ
Diffstat (limited to 'src/peerinfo/peerinfo_api.c')
-rw-r--r--src/peerinfo/peerinfo_api.c780
1 files changed, 266 insertions, 514 deletions
diff --git a/src/peerinfo/peerinfo_api.c b/src/peerinfo/peerinfo_api.c
index 0637eda72..e477186ee 100644
--- a/src/peerinfo/peerinfo_api.c
+++ b/src/peerinfo/peerinfo_api.c
@@ -32,46 +32,6 @@
32 32
33 33
34/** 34/**
35 * Entry in the transmission queue to PEERINFO service. We use
36 * the same structure for queueing 'iteration' requests and
37 * actual 'add' messages.
38 */
39struct GNUNET_PEERINFO_AddContext
40{
41 /**
42 * This is a linked list.
43 */
44 struct GNUNET_PEERINFO_AddContext *next;
45
46 /**
47 * This is a linked list.
48 */
49 struct GNUNET_PEERINFO_AddContext *prev;
50
51 /**
52 * Handle to the PEERINFO service.
53 */
54 struct GNUNET_PEERINFO_Handle *h;
55
56 /**
57 * Function to call after request has been transmitted, or NULL.
58 */
59 GNUNET_PEERINFO_Continuation cont;
60
61 /**
62 * Closure for @e cont.
63 */
64 void *cont_cls;
65
66 /**
67 * Number of bytes of the request message (follows after this struct).
68 */
69 size_t size;
70
71};
72
73
74/**
75 * Context for an iteration request. 35 * Context for an iteration request.
76 */ 36 */
77struct GNUNET_PEERINFO_IteratorContext 37struct GNUNET_PEERINFO_IteratorContext
@@ -103,21 +63,6 @@ struct GNUNET_PEERINFO_IteratorContext
103 void *callback_cls; 63 void *callback_cls;
104 64
105 /** 65 /**
106 * Our entry in the transmission queue.
107 */
108 struct GNUNET_PEERINFO_AddContext *ac;
109
110 /**
111 * Task responsible for timeout.
112 */
113 struct GNUNET_SCHEDULER_Task *timeout_task;
114
115 /**
116 * Timeout for the operation.
117 */
118 struct GNUNET_TIME_Absolute timeout;
119
120 /**
121 * Peer we are interested in (only valid if iteration was restricted to one peer). 66 * Peer we are interested in (only valid if iteration was restricted to one peer).
122 */ 67 */
123 struct GNUNET_PeerIdentity peer; 68 struct GNUNET_PeerIdentity peer;
@@ -128,10 +73,9 @@ struct GNUNET_PEERINFO_IteratorContext
128 int have_peer; 73 int have_peer;
129 74
130 /** 75 /**
131 * Set to #GNUNET_YES if we are currently receiving replies from the 76 * Only include friends in reply?
132 * service.
133 */ 77 */
134 int request_transmitted; 78 int include_friend_only;
135 79
136}; 80};
137 81
@@ -149,22 +93,7 @@ struct GNUNET_PEERINFO_Handle
149 /** 93 /**
150 * Connection to the service. 94 * Connection to the service.
151 */ 95 */
152 struct GNUNET_CLIENT_Connection *client; 96 struct GNUNET_MQ_Handle *mq;
153
154 /**
155 * Head of transmission queue.
156 */
157 struct GNUNET_PEERINFO_AddContext *ac_head;
158
159 /**
160 * Tail of transmission queue.
161 */
162 struct GNUNET_PEERINFO_AddContext *ac_tail;
163
164 /**
165 * Handle for the current transmission request, or NULL if none is pending.
166 */
167 struct GNUNET_CLIENT_TransmitHandle *th;
168 97
169 /** 98 /**
170 * Head of iterator DLL. 99 * Head of iterator DLL.
@@ -181,15 +110,19 @@ struct GNUNET_PEERINFO_Handle
181 */ 110 */
182 struct GNUNET_SCHEDULER_Task *r_task; 111 struct GNUNET_SCHEDULER_Task *r_task;
183 112
184 /**
185 * Are we now receiving?
186 */
187 int in_receive;
188
189}; 113};
190 114
191 115
192/** 116/**
117 * Close the existing connection to PEERINFO and reconnect.
118 *
119 * @param h handle to the service
120 */
121static void
122reconnect (struct GNUNET_PEERINFO_Handle *h);
123
124
125/**
193 * Connect to the peerinfo service. 126 * Connect to the peerinfo service.
194 * 127 *
195 * @param cfg configuration to use 128 * @param cfg configuration to use
@@ -202,8 +135,13 @@ GNUNET_PEERINFO_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
202 struct GNUNET_PEERINFO_Handle *h; 135 struct GNUNET_PEERINFO_Handle *h;
203 136
204 h = GNUNET_new (struct GNUNET_PEERINFO_Handle); 137 h = GNUNET_new (struct GNUNET_PEERINFO_Handle);
205 h->client = GNUNET_CLIENT_connect ("peerinfo", cfg);
206 h->cfg = cfg; 138 h->cfg = cfg;
139 reconnect (h);
140 if (NULL == h->mq)
141 {
142 GNUNET_free (h);
143 return NULL;
144 }
207 return h; 145 return h;
208} 146}
209 147
@@ -220,32 +158,19 @@ GNUNET_PEERINFO_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
220void 158void
221GNUNET_PEERINFO_disconnect (struct GNUNET_PEERINFO_Handle *h) 159GNUNET_PEERINFO_disconnect (struct GNUNET_PEERINFO_Handle *h)
222{ 160{
223 struct GNUNET_PEERINFO_AddContext *ac;
224 struct GNUNET_PEERINFO_IteratorContext *ic; 161 struct GNUNET_PEERINFO_IteratorContext *ic;
225 162
226 while (NULL != (ic = h->ic_head)) 163 while (NULL != (ic = h->ic_head))
227 { 164 {
228 GNUNET_break (GNUNET_YES == ic->request_transmitted); 165 GNUNET_CONTAINER_DLL_remove (h->ic_head,
229 ic->request_transmitted = GNUNET_NO; 166 h->ic_tail,
230 GNUNET_PEERINFO_iterate_cancel (ic); 167 ic);
231 } 168 GNUNET_free (ic);
232 while (NULL != (ac = h->ac_head))
233 {
234 GNUNET_CONTAINER_DLL_remove (h->ac_head, h->ac_tail, ac);
235 if (NULL != ac->cont)
236 ac->cont (ac->cont_cls,
237 _("aborted due to explicit disconnect request"));
238 GNUNET_free (ac);
239 }
240 if (NULL != h->th)
241 {
242 GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
243 h->th = NULL;
244 } 169 }
245 if (NULL != h->client) 170 if (NULL != h->mq)
246 { 171 {
247 GNUNET_CLIENT_disconnect (h->client); 172 GNUNET_MQ_destroy (h->mq);
248 h->client = NULL; 173 h->mq = NULL;
249 } 174 }
250 if (NULL != h->r_task) 175 if (NULL != h->r_task)
251 { 176 {
@@ -257,25 +182,6 @@ GNUNET_PEERINFO_disconnect (struct GNUNET_PEERINFO_Handle *h)
257 182
258 183
259/** 184/**
260 * Check if we have a request pending in the transmission queue and are
261 * able to transmit it right now. If so, schedule transmission.
262 *
263 * @param h handle to the service
264 */
265static void
266trigger_transmit (struct GNUNET_PEERINFO_Handle *h);
267
268
269/**
270 * Close the existing connection to PEERINFO and reconnect.
271 *
272 * @param h handle to the service
273 */
274static void
275reconnect (struct GNUNET_PEERINFO_Handle *h);
276
277
278/**
279 * Task scheduled to re-try connecting to the peerinfo service. 185 * Task scheduled to re-try connecting to the peerinfo service.
280 * 186 *
281 * @param cls the `struct GNUNET_PEERINFO_Handle *` 187 * @param cls the `struct GNUNET_PEERINFO_Handle *`
@@ -291,277 +197,79 @@ reconnect_task (void *cls)
291 197
292 198
293/** 199/**
294 * Close the existing connection to PEERINFO and reconnect. 200 * We encountered an error, reconnect to the PEERINFO service.
295 * 201 *
296 * @param h handle to the service 202 * @param h handle to reconnect
297 */ 203 */
298static void 204static void
299reconnect (struct GNUNET_PEERINFO_Handle *h) 205do_reconnect (struct GNUNET_PEERINFO_Handle *h)
300{ 206{
301 if (NULL != h->r_task) 207 struct GNUNET_PEERINFO_IteratorContext *ic = h->ic_head;
302 {
303 GNUNET_SCHEDULER_cancel (h->r_task);
304 h->r_task = NULL;
305 }
306 if (NULL != h->th)
307 {
308 GNUNET_CLIENT_notify_transmit_ready_cancel (h->th);
309 h->th = NULL;
310 }
311 if (NULL != h->client)
312 {
313 GNUNET_CLIENT_disconnect (h->client);
314 h->client = NULL;
315 }
316 h->in_receive = GNUNET_NO;
317 h->client = GNUNET_CLIENT_connect ("peerinfo", h->cfg);
318 if (NULL == h->client)
319 {
320 h->r_task =
321 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
322 &reconnect_task,
323 h);
324 return;
325 }
326 trigger_transmit (h);
327}
328
329
330/**
331 * Transmit the request at the head of the transmission queue
332 * and trigger continuation (if any).
333 *
334 * @param cls the `struct GNUNET_PEERINFO_Handle *` (with the queue)
335 * @param size size of @a buf (0 on error)
336 * @param buf where to copy the message
337 * @return number of bytes copied to @a buf
338 */
339static size_t
340do_transmit (void *cls,
341 size_t size,
342 void *buf)
343{
344 struct GNUNET_PEERINFO_Handle *h = cls;
345 struct GNUNET_PEERINFO_AddContext *ac = h->ac_head;
346 size_t ret;
347 208
348 h->th = NULL; 209 GNUNET_MQ_destroy (h->mq);
349 if (NULL == ac) 210 h->mq = NULL;
350 return 0; /* request was cancelled in the meantime */ 211 if (NULL != ic)
351 if (NULL == buf)
352 { 212 {
353 /* peerinfo service died */ 213 GNUNET_CONTAINER_DLL_remove (h->ic_head,
354 LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, 214 h->ic_tail,
355 "Failed to transmit message to `%s' service.\n", 215 ic);
356 "PEERINFO"); 216 if (NULL != ic->callback)
357 GNUNET_CONTAINER_DLL_remove (h->ac_head, h->ac_tail, ac); 217 ic->callback (ic->callback_cls,
358 reconnect (h); 218 NULL,
359 if (NULL != ac->cont) 219 NULL,
360 ac->cont (ac->cont_cls, 220 _("Failed to receive response from `PEERINFO' service."));
361 _("failed to transmit request (service down?)")); 221 GNUNET_free (ic);
362 GNUNET_free (ac);
363 return 0;
364 } 222 }
365 ret = ac->size; 223 h->r_task = GNUNET_SCHEDULER_add_now (&reconnect_task,
366 if (size < ret) 224 h);
367 {
368 /* change in head of queue (i.e. cancel + add), try again */
369 trigger_transmit (h);
370 return 0;
371 }
372 LOG (GNUNET_ERROR_TYPE_DEBUG,
373 "Transmitting request of size %u to `%s' service.\n",
374 ret,
375 "PEERINFO");
376 memcpy (buf, &ac[1], ret);
377 GNUNET_CONTAINER_DLL_remove (h->ac_head, h->ac_tail, ac);
378 trigger_transmit (h);
379 if (NULL != ac->cont)
380 ac->cont (ac->cont_cls, NULL);
381 GNUNET_free (ac);
382 return ret;
383} 225}
384 226
385 227
386/** 228/**
387 * Check if we have a request pending in the transmission queue and are 229 * We got a disconnect after asking regex to do the announcement.
388 * able to transmit it right now. If so, schedule transmission. 230 * Retry.
389 * 231 *
390 * @param h handle to the service 232 * @param cls the `struct GNUNET_PEERINFO_Handle` to retry
233 * @param error error code
391 */ 234 */
392static void 235static void
393trigger_transmit (struct GNUNET_PEERINFO_Handle *h) 236mq_error_handler (void *cls,
237 enum GNUNET_MQ_Error error)
394{ 238{
395 struct GNUNET_PEERINFO_AddContext *ac; 239 struct GNUNET_PEERINFO_Handle *h = cls;
396
397 if (NULL == (ac = h->ac_head))
398 return; /* no requests queued */
399 if (NULL != h->th)
400 return; /* request already pending */
401 if (NULL == h->client)
402 {
403 /* disconnected, try to reconnect */
404 reconnect (h);
405 return;
406 }
407 h->th =
408 GNUNET_CLIENT_notify_transmit_ready (h->client,
409 ac->size,
410 GNUNET_TIME_UNIT_FOREVER_REL,
411 GNUNET_YES,
412 &do_transmit, h);
413}
414
415
416/**
417 * Add a host to the persistent list. This method operates in
418 * semi-reliable mode: if the transmission is not completed by
419 * the time #GNUNET_PEERINFO_disconnect() is called, it will be
420 * aborted. Furthermore, if a second HELLO is added for the
421 * same peer before the first one was transmitted, PEERINFO may
422 * merge the two HELLOs prior to transmission to the service.
423 *
424 * @param h handle to the peerinfo service
425 * @param hello the verified (!) HELLO message
426 * @param cont continuation to call when done, NULL is allowed
427 * @param cont_cls closure for @a cont
428 * @return handle to cancel add operation; all pending
429 * 'add' operations will be cancelled automatically
430 * on disconnect, so it is not necessary to keep this
431 * handle (unless @a cont is NULL and at some point
432 * calling @a cont must be prevented)
433 */
434struct GNUNET_PEERINFO_AddContext *
435GNUNET_PEERINFO_add_peer (struct GNUNET_PEERINFO_Handle *h,
436 const struct GNUNET_HELLO_Message *hello,
437 GNUNET_PEERINFO_Continuation cont,
438 void *cont_cls)
439{
440 uint16_t hs = GNUNET_HELLO_size (hello);
441 struct GNUNET_PEERINFO_AddContext *ac;
442 struct GNUNET_PeerIdentity peer;
443 240
444 GNUNET_assert (GNUNET_OK == GNUNET_HELLO_get_id (hello, &peer)); 241 do_reconnect (h);
445 LOG (GNUNET_ERROR_TYPE_DEBUG,
446 "Adding peer `%s' to PEERINFO database (%u bytes of HELLO)\n",
447 GNUNET_i2s (&peer),
448 hs);
449 ac = GNUNET_malloc (sizeof (struct GNUNET_PEERINFO_AddContext) + hs);
450 ac->h = h;
451 ac->size = hs;
452 ac->cont = cont;
453 ac->cont_cls = cont_cls;
454 memcpy (&ac[1], hello, hs);
455 GNUNET_CONTAINER_DLL_insert_tail (h->ac_head, h->ac_tail, ac);
456 trigger_transmit (h);
457 return ac;
458} 242}
459 243
460 244
461/**
462 * Cancel pending 'add' operation. Must only be called before
463 * either 'cont' or #GNUNET_PEERINFO_disconnect() are invoked.
464 *
465 * @param ac handle for the add operation to cancel
466 */
467void
468GNUNET_PEERINFO_add_peer_cancel (struct GNUNET_PEERINFO_AddContext *ac)
469{
470 struct GNUNET_PEERINFO_Handle *h = ac->h;
471
472 GNUNET_CONTAINER_DLL_remove (h->ac_head, h->ac_tail, ac);
473 GNUNET_free (ac);
474}
475
476 245
477/** 246/**
478 * Type of a function to call when we receive a message from the 247 * Function called when we receive an info message. Check it is
479 * service. Call the iterator with the result and (if applicable) 248 * well-formed.
480 * continue to receive more messages or trigger processing the next
481 * event (if applicable).
482 * 249 *
483 * @param cls closure 250 * @param cls closure
484 * @param msg message received, NULL on timeout or fatal error 251 * @param im message received
252 * @return #GNUNET_OK if the message is OK
485 */ 253 */
486static void 254static int
487peerinfo_handler (void *cls, 255check_info (void *cls,
488 const struct GNUNET_MessageHeader *msg) 256 const struct InfoMessage *im)
489{ 257{
490 struct GNUNET_PEERINFO_Handle *h = cls; 258 struct GNUNET_PEERINFO_Handle *h = cls;
491 struct GNUNET_PEERINFO_IteratorContext *ic = h->ic_head; 259 struct GNUNET_PEERINFO_IteratorContext *ic = h->ic_head;
492 const struct InfoMessage *im; 260 uint16_t ms = ntohs (im->header.size) - sizeof (*im);
493 const struct GNUNET_HELLO_Message *hello;
494 GNUNET_PEERINFO_Processor cb;
495 struct GNUNET_PeerIdentity id;
496 void *cb_cls;
497 uint16_t ms;
498 261
499 h->in_receive = GNUNET_NO; 262 if (0 != ntohl (im->reserved))
500 if (NULL == msg)
501 { 263 {
502 /* peerinfo service died, signal error */ 264 GNUNET_break (0);
503 if (NULL != ic) 265 return GNUNET_SYSERR;
504 {
505 cb = ic->callback;
506 cb_cls = ic->callback_cls;
507 GNUNET_PEERINFO_iterate_cancel (ic);
508 }
509 else
510 {
511 cb = NULL;
512 }
513 reconnect (h);
514 if (NULL != cb)
515 cb (cb_cls, NULL, NULL,
516 _("Failed to receive response from `PEERINFO' service."));
517 return;
518 } 266 }
519 if (NULL == ic) 267 if (NULL == ic)
520 { 268 {
521 /* didn't expect a response, reconnect */ 269 /* didn't expect a response, bad */
522 reconnect (h);
523 return;
524 }
525 ic->request_transmitted = GNUNET_NO;
526 cb = ic->callback;
527 cb_cls = ic->callback_cls;
528 if (GNUNET_MESSAGE_TYPE_PEERINFO_INFO_END == ntohs (msg->type))
529 {
530 /* normal end of list of peers, signal end, process next pending request */
531 LOG (GNUNET_ERROR_TYPE_DEBUG,
532 "Received end of list of peers from `%s' service\n",
533 "PEERINFO");
534 GNUNET_PEERINFO_iterate_cancel (ic);
535 trigger_transmit (h);
536 if ( (GNUNET_NO == h->in_receive) &&
537 (NULL != h->ic_head) )
538 {
539 h->in_receive = GNUNET_YES;
540 GNUNET_CLIENT_receive (h->client,
541 &peerinfo_handler,
542 h,
543 GNUNET_TIME_absolute_get_remaining (h->ic_head->timeout));
544 }
545 if (NULL != cb)
546 cb (cb_cls, NULL, NULL, NULL);
547 return;
548 }
549
550 ms = ntohs (msg->size);
551 if ((ms < sizeof (struct InfoMessage)) ||
552 (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_PEERINFO_INFO))
553 {
554 /* malformed message */
555 GNUNET_break (0); 270 GNUNET_break (0);
556 GNUNET_PEERINFO_iterate_cancel (ic); 271 return GNUNET_SYSERR;
557 reconnect (h);
558 if (NULL != cb)
559 cb (cb_cls, NULL, NULL,
560 _("Received invalid message from `PEERINFO' service."));
561 return;
562 } 272 }
563 im = (const struct InfoMessage *) msg;
564 GNUNET_break (0 == ntohl (im->reserved));
565 if ( (GNUNET_YES == ic->have_peer) && 273 if ( (GNUNET_YES == ic->have_peer) &&
566 (0 != memcmp (&ic->peer, 274 (0 != memcmp (&ic->peer,
567 &im->peer, 275 &im->peer,
@@ -572,46 +280,28 @@ peerinfo_handler (void *cls,
572 "Received HELLO for peer `%s', expected peer `%s'\n", 280 "Received HELLO for peer `%s', expected peer `%s'\n",
573 GNUNET_i2s (&im->peer), 281 GNUNET_i2s (&im->peer),
574 GNUNET_i2s (&ic->peer)); 282 GNUNET_i2s (&ic->peer));
575
576 GNUNET_break (0); 283 GNUNET_break (0);
577 GNUNET_PEERINFO_iterate_cancel (ic); 284 return GNUNET_SYSERR;
578 reconnect (h);
579 if (NULL != cb)
580 cb (cb_cls,
581 NULL,
582 NULL,
583 _("Received invalid message from `PEERINFO' service."));
584 return;
585 } 285 }
586 hello = NULL; 286 if (ms > sizeof (struct GNUNET_MessageHeader))
587 if (ms > sizeof (struct InfoMessage) + sizeof (struct GNUNET_MessageHeader))
588 { 287 {
288 const struct GNUNET_HELLO_Message *hello;
289 struct GNUNET_PeerIdentity id;
290
589 hello = (const struct GNUNET_HELLO_Message *) &im[1]; 291 hello = (const struct GNUNET_HELLO_Message *) &im[1];
590 if (ms != sizeof (struct InfoMessage) + GNUNET_HELLO_size (hello)) 292 if (ms != GNUNET_HELLO_size (hello))
591 { 293 {
592 /* malformed message */ 294 /* malformed message */
593 GNUNET_break (0); 295 GNUNET_break (0);
594 GNUNET_PEERINFO_iterate_cancel (ic); 296 return GNUNET_SYSERR;
595 reconnect (h);
596 if (NULL != cb)
597 cb (cb_cls,
598 NULL,
599 NULL,
600 _("Received invalid message from `PEERINFO' service."));
601 return;
602 } 297 }
603 if (GNUNET_OK != GNUNET_HELLO_get_id (hello, &id)) 298 if (GNUNET_OK !=
299 GNUNET_HELLO_get_id (hello,
300 &id))
604 { 301 {
605 /* malformed message */ 302 /* malformed message */
606 GNUNET_break (0); 303 GNUNET_break (0);
607 GNUNET_PEERINFO_iterate_cancel (ic); 304 return GNUNET_SYSERR;
608 reconnect (h);
609 if (NULL != cb)
610 cb (cb_cls,
611 NULL,
612 NULL,
613 _("Received invalid message from `PEERINFO' service."));
614 return;
615 } 305 }
616 if (0 != memcmp (&im->peer, 306 if (0 != memcmp (&im->peer,
617 &id, 307 &id,
@@ -619,100 +309,166 @@ peerinfo_handler (void *cls,
619 { 309 {
620 /* malformed message */ 310 /* malformed message */
621 GNUNET_break (0); 311 GNUNET_break (0);
622 GNUNET_PEERINFO_iterate_cancel (ic); 312 return GNUNET_SYSERR;
623 reconnect (h);
624 if (NULL != cb)
625 cb (cb_cls,
626 NULL,
627 NULL,
628 _("Received invalid message from `PEERINFO' service."));
629 return;
630 } 313 }
631 } 314 }
315 else if (0 != ms)
316 {
317 /* malformed message */
318 GNUNET_break (0);
319 return GNUNET_SYSERR;
320 }
321 return GNUNET_OK;
322}
632 323
633 /* normal data message */ 324
634 LOG (GNUNET_ERROR_TYPE_DEBUG, 325/**
635 "Received %u bytes of `%s' information about peer `%s' from `%s' service\n", 326 * Handle info message.
636 (hello == NULL) ? 0 : (unsigned int) GNUNET_HELLO_size (hello), 327 *
637 "HELLO", 328 * @param cls closure
638 GNUNET_i2s (&im->peer), 329 * @param im message received
639 "PEERINFO"); 330 */
640 h->in_receive = GNUNET_YES; 331static void
641 GNUNET_CLIENT_receive (h->client, 332handle_info (void *cls,
642 &peerinfo_handler, 333 const struct InfoMessage *im)
643 h, 334{
644 GNUNET_TIME_absolute_get_remaining (ic->timeout)); 335 struct GNUNET_PEERINFO_Handle *h = cls;
645 if (NULL != cb) 336 struct GNUNET_PEERINFO_IteratorContext *ic = h->ic_head;
646 cb (cb_cls, 337 const struct GNUNET_HELLO_Message *hello;
647 &im->peer, 338 uint16_t ms;
648 hello, 339
649 NULL); 340 ms = ntohs (im->header.size);
341 hello = (0 == ms) ? NULL : (const struct GNUNET_HELLO_Message *) &im[1];
342 if (NULL != ic->callback)
343 ic->callback (ic->callback_cls,
344 &im->peer,
345 hello,
346 NULL);
650} 347}
651 348
652 349
653/** 350/**
654 * We've transmitted the iteration request. Now get ready to process 351 * Send the next IC request at the head of the queue.
655 * the results (or handle transmission error).
656 * 352 *
657 * @param cls the `struct GNUNET_PEERINFO_IteratorContext *` 353 * @param h handle
658 * @param emsg error message, NULL if transmission worked
659 */ 354 */
660static void 355static void
661iterator_start_receive (void *cls, 356send_ic_request (struct GNUNET_PEERINFO_Handle *h)
662 const char *emsg)
663{ 357{
664 struct GNUNET_PEERINFO_IteratorContext *ic = cls; 358 struct GNUNET_PEERINFO_IteratorContext *ic = h->ic_head;
665 struct GNUNET_PEERINFO_Handle *h = ic->h; 359 struct GNUNET_MQ_Envelope *env;
666 GNUNET_PEERINFO_Processor cb; 360 struct ListAllPeersMessage *lapm;
667 void *cb_cls; 361 struct ListPeerMessage *lpm;
668 362
669 ic->ac = NULL; 363 if (NULL == ic)
670 if (NULL != emsg)
671 { 364 {
672 cb = ic->callback; 365 GNUNET_break (0);
673 cb_cls = ic->callback_cls;
674 GNUNET_PEERINFO_iterate_cancel (ic);
675 reconnect (h);
676 if (NULL != cb)
677 cb (cb_cls, NULL, NULL, emsg);
678 return; 366 return;
679 } 367 }
680 LOG (GNUNET_ERROR_TYPE_DEBUG, 368 if (NULL == h->mq)
681 "Waiting for response from `%s' service.\n", 369 {
682 "PEERINFO"); 370 GNUNET_break (0);
683 ic->request_transmitted = GNUNET_YES; 371 return;
684 if (GNUNET_NO == h->in_receive) 372 }
373 if (GNUNET_NO == ic->have_peer)
374 {
375 LOG (GNUNET_ERROR_TYPE_DEBUG,
376 "Requesting list of peers from PEERINFO service\n");
377 env = GNUNET_MQ_msg (lapm,
378 GNUNET_MESSAGE_TYPE_PEERINFO_GET_ALL);
379 lapm->include_friend_only = htonl (ic->include_friend_only);
380 }
381 else
382 {
383 LOG (GNUNET_ERROR_TYPE_DEBUG,
384 "Requesting information on peer `%s' from PEERINFO service\n",
385 GNUNET_i2s (&ic->peer));
386 env = GNUNET_MQ_msg (lpm,
387 GNUNET_MESSAGE_TYPE_PEERINFO_GET);
388 lpm->include_friend_only = htonl (ic->include_friend_only);
389 lpm->peer = ic->peer;
390 }
391 GNUNET_MQ_send (h->mq,
392 env);
393}
394
395
396/**
397 * Type of a function to call when we receive a message from the
398 * service. Call the iterator with the result and (if applicable)
399 * continue to receive more messages or trigger processing the next
400 * event (if applicable).
401 *
402 * @param cls closure
403 * @param msg message received, NULL on timeout or fatal error
404 */
405static void
406handle_end_iteration (void *cls,
407 const struct GNUNET_MessageHeader *msg)
408{
409 struct GNUNET_PEERINFO_Handle *h = cls;
410 struct GNUNET_PEERINFO_IteratorContext *ic = h->ic_head;
411
412 if (NULL == ic)
685 { 413 {
686 h->in_receive = GNUNET_YES; 414 /* didn't expect a response, reconnect */
687 GNUNET_CLIENT_receive (h->client, 415 GNUNET_break (0);
688 &peerinfo_handler, 416 reconnect (h);
689 h, 417 return;
690 GNUNET_TIME_absolute_get_remaining (ic->timeout));
691 } 418 }
419 LOG (GNUNET_ERROR_TYPE_DEBUG,
420 "Received end of list of peers from PEERINFO service\n");
421 GNUNET_CONTAINER_DLL_remove (h->ic_head,
422 h->ic_tail,
423 ic);
424 if (NULL != h->ic_head)
425 send_ic_request (h);
426 if (NULL != ic->callback)
427 ic->callback (ic->callback_cls,
428 NULL,
429 NULL,
430 NULL);
431 GNUNET_free (ic);
692} 432}
693 433
694 434
695/** 435/**
696 * Peerinfo iteration request has timed out. 436 * Close the existing connection to PEERINFO and reconnect.
697 * 437 *
698 * @param cls the `struct GNUNET_PEERINFO_IteratorContext *` 438 * @param h handle to the service
699 */ 439 */
700static void 440static void
701signal_timeout (void *cls) 441reconnect (struct GNUNET_PEERINFO_Handle *h)
702{ 442{
703 struct GNUNET_PEERINFO_IteratorContext *ic = cls; 443 GNUNET_MQ_hd_var_size (info,
704 GNUNET_PEERINFO_Processor cb; 444 GNUNET_MESSAGE_TYPE_PEERINFO_INFO,
705 void *cb_cls; 445 struct InfoMessage);
706 446 GNUNET_MQ_hd_fixed_size (end_iteration,
707 ic->timeout_task = NULL; 447 GNUNET_MESSAGE_TYPE_PEERINFO_INFO_END,
708 cb = ic->callback; 448 struct GNUNET_MessageHeader);
709 cb_cls = ic->callback_cls; 449 struct GNUNET_MQ_MessageHandler handlers[] = {
710 GNUNET_PEERINFO_iterate_cancel (ic); 450 make_info_handler (h),
711 if (NULL != cb) 451 make_end_iteration_handler (h),
712 cb (cb_cls, 452 GNUNET_MQ_handler_end ()
713 NULL, 453 };
714 NULL, 454
715 _("Timeout transmitting iteration request to `PEERINFO' service.")); 455 if (NULL != h->r_task)
456 {
457 GNUNET_SCHEDULER_cancel (h->r_task);
458 h->r_task = NULL;
459 }
460 if (NULL != h->mq)
461 {
462 GNUNET_MQ_destroy (h->mq);
463 h->mq = NULL;
464 }
465 h->mq = GNUNET_CLIENT_connecT (h->cfg,
466 "peerinfo",
467 handlers,
468 &mq_error_handler,
469 h);
470 if (NULL != h->ic_head)
471 send_ic_request (h);
716} 472}
717 473
718 474
@@ -728,7 +484,6 @@ signal_timeout (void *cls)
728 * @param h handle to the peerinfo service 484 * @param h handle to the peerinfo service
729 * @param include_friend_only include HELLO messages for friends only 485 * @param include_friend_only include HELLO messages for friends only
730 * @param peer restrict iteration to this peer only (can be NULL) 486 * @param peer restrict iteration to this peer only (can be NULL)
731 * @param timeout how long to wait until timing out
732 * @param callback the method to call for each peer 487 * @param callback the method to call for each peer
733 * @param callback_cls closure for @a callback 488 * @param callback_cls closure for @a callback
734 * @return iterator context 489 * @return iterator context
@@ -737,62 +492,26 @@ struct GNUNET_PEERINFO_IteratorContext *
737GNUNET_PEERINFO_iterate (struct GNUNET_PEERINFO_Handle *h, 492GNUNET_PEERINFO_iterate (struct GNUNET_PEERINFO_Handle *h,
738 int include_friend_only, 493 int include_friend_only,
739 const struct GNUNET_PeerIdentity *peer, 494 const struct GNUNET_PeerIdentity *peer,
740 struct GNUNET_TIME_Relative timeout,
741 GNUNET_PEERINFO_Processor callback, 495 GNUNET_PEERINFO_Processor callback,
742 void *callback_cls) 496 void *callback_cls)
743{ 497{
744 struct ListAllPeersMessage *lapm;
745 struct ListPeerMessage *lpm;
746 struct GNUNET_PEERINFO_IteratorContext *ic; 498 struct GNUNET_PEERINFO_IteratorContext *ic;
747 struct GNUNET_PEERINFO_AddContext *ac;
748 499
749 ic = GNUNET_new (struct GNUNET_PEERINFO_IteratorContext); 500 ic = GNUNET_new (struct GNUNET_PEERINFO_IteratorContext);
750 if (NULL == peer) 501 ic->h = h;
751 { 502 ic->include_friend_only = include_friend_only;
752 LOG (GNUNET_ERROR_TYPE_DEBUG, 503 ic->callback = callback;
753 "Requesting list of peers from PEERINFO service\n"); 504 ic->callback_cls = callback_cls;
754 ac = 505 if (NULL != peer)
755 GNUNET_malloc (sizeof (struct GNUNET_PEERINFO_AddContext) +
756 sizeof (struct ListAllPeersMessage));
757 ac->size = sizeof (struct ListAllPeersMessage);
758 lapm = (struct ListAllPeersMessage *) &ac[1];
759 lapm->header.size = htons (sizeof (struct ListAllPeersMessage));
760 lapm->header.type = htons (GNUNET_MESSAGE_TYPE_PEERINFO_GET_ALL);
761 lapm->include_friend_only = htonl (include_friend_only);
762 }
763 else
764 { 506 {
765 LOG (GNUNET_ERROR_TYPE_DEBUG,
766 "Requesting information on peer `%4s' from PEERINFO service\n",
767 GNUNET_i2s (peer));
768 ac =
769 GNUNET_malloc (sizeof (struct GNUNET_PEERINFO_AddContext) +
770 sizeof (struct ListPeerMessage));
771 ac->size = sizeof (struct ListPeerMessage);
772 lpm = (struct ListPeerMessage *) &ac[1];
773 lpm->header.size = htons (sizeof (struct ListPeerMessage));
774 lpm->header.type = htons (GNUNET_MESSAGE_TYPE_PEERINFO_GET);
775 lpm->include_friend_only = htonl (include_friend_only);
776 memcpy (&lpm->peer, peer, sizeof (struct GNUNET_PeerIdentity));
777 ic->have_peer = GNUNET_YES; 507 ic->have_peer = GNUNET_YES;
778 ic->peer = *peer; 508 ic->peer = *peer;
779 } 509 }
780 ic->h = h;
781 ic->ac = ac;
782 ic->callback = callback;
783 ic->callback_cls = callback_cls;
784 ic->timeout = GNUNET_TIME_relative_to_absolute (timeout);
785 ic->timeout_task =
786 GNUNET_SCHEDULER_add_delayed (timeout, &signal_timeout, ic);
787 ac->cont = &iterator_start_receive;
788 ac->cont_cls = ic;
789 GNUNET_CONTAINER_DLL_insert_tail (h->ac_head,
790 h->ac_tail,
791 ac);
792 GNUNET_CONTAINER_DLL_insert_tail (h->ic_head, 510 GNUNET_CONTAINER_DLL_insert_tail (h->ic_head,
793 h->ic_tail, 511 h->ic_tail,
794 ic); 512 ic);
795 trigger_transmit (h); 513 if (h->ic_head == ic)
514 send_ic_request (h);
796 return ic; 515 return ic;
797} 516}
798 517
@@ -805,29 +524,62 @@ GNUNET_PEERINFO_iterate (struct GNUNET_PEERINFO_Handle *h,
805void 524void
806GNUNET_PEERINFO_iterate_cancel (struct GNUNET_PEERINFO_IteratorContext *ic) 525GNUNET_PEERINFO_iterate_cancel (struct GNUNET_PEERINFO_IteratorContext *ic)
807{ 526{
808 struct GNUNET_PEERINFO_Handle *h; 527 struct GNUNET_PEERINFO_Handle *h = ic->h;
809 528
810 h = ic->h;
811 if (NULL != ic->timeout_task)
812 {
813 GNUNET_SCHEDULER_cancel (ic->timeout_task);
814 ic->timeout_task = NULL;
815 }
816 ic->callback = NULL; 529 ic->callback = NULL;
817 if (GNUNET_YES == ic->request_transmitted) 530 if (ic == h->ic_head)
818 return; /* need to finish processing */ 531 return;
819 GNUNET_CONTAINER_DLL_remove (h->ic_head, 532 GNUNET_CONTAINER_DLL_remove (h->ic_head,
820 h->ic_tail, 533 h->ic_tail,
821 ic); 534 ic);
822 if (NULL != ic->ac)
823 {
824 GNUNET_CONTAINER_DLL_remove (h->ac_head,
825 h->ac_tail,
826 ic->ac);
827 GNUNET_free (ic->ac);
828 }
829 GNUNET_free (ic); 535 GNUNET_free (ic);
830} 536}
831 537
832 538
539/**
540 * Add a host to the persistent list. This method operates in
541 * semi-reliable mode: if the transmission is not completed by
542 * the time #GNUNET_PEERINFO_disconnect() is called, it will be
543 * aborted. Furthermore, if a second HELLO is added for the
544 * same peer before the first one was transmitted, PEERINFO may
545 * merge the two HELLOs prior to transmission to the service.
546 *
547 * @param h handle to the peerinfo service
548 * @param hello the verified (!) HELLO message
549 * @param cont continuation to call when done, NULL is allowed
550 * @param cont_cls closure for @a cont
551 * @return handle to cancel add operation; all pending
552 * 'add' operations will be cancelled automatically
553 * on disconnect, so it is not necessary to keep this
554 * handle (unless @a cont is NULL and at some point
555 * calling @a cont must be prevented)
556 */
557struct GNUNET_MQ_Envelope *
558GNUNET_PEERINFO_add_peer (struct GNUNET_PEERINFO_Handle *h,
559 const struct GNUNET_HELLO_Message *hello,
560 GNUNET_MQ_NotifyCallback cont,
561 void *cont_cls)
562{
563 struct GNUNET_MQ_Envelope *env;
564 struct GNUNET_PeerIdentity peer;
565
566 if (NULL == h->mq)
567 return NULL;
568 GNUNET_assert (GNUNET_OK ==
569 GNUNET_HELLO_get_id (hello,
570 &peer));
571 LOG (GNUNET_ERROR_TYPE_DEBUG,
572 "Adding peer `%s' to PEERINFO database\n",
573 GNUNET_i2s (&peer));
574 env = GNUNET_MQ_msg_copy ((const struct GNUNET_MessageHeader *) hello);
575 if (NULL != cont)
576 GNUNET_MQ_notify_sent (env,
577 cont,
578 cont_cls);
579 GNUNET_MQ_send (h->mq,
580 env);
581 return env;
582}
583
584
833/* end of peerinfo_api.c */ 585/* end of peerinfo_api.c */