aboutsummaryrefslogtreecommitdiff
path: root/src/peerinfo/peerinfo_api.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/peerinfo/peerinfo_api.c')
-rw-r--r--src/peerinfo/peerinfo_api.c580
1 files changed, 0 insertions, 580 deletions
diff --git a/src/peerinfo/peerinfo_api.c b/src/peerinfo/peerinfo_api.c
deleted file mode 100644
index b73d9d927..000000000
--- a/src/peerinfo/peerinfo_api.c
+++ /dev/null
@@ -1,580 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001-2014 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file peerinfo/peerinfo_api.c
23 * @brief API to access peerinfo service
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_protocols.h"
29#include "peerinfo.h"
30
31#define LOG(kind, ...) GNUNET_log_from (kind, "peerinfo-api", __VA_ARGS__)
32
33
34/**
35 * Context for an iteration request.
36 */
37struct GNUNET_PEERINFO_IteratorContext
38{
39 /**
40 * Kept in a DLL.
41 */
42 struct GNUNET_PEERINFO_IteratorContext *next;
43
44 /**
45 * Kept in a DLL.
46 */
47 struct GNUNET_PEERINFO_IteratorContext *prev;
48
49 /**
50 * Handle to the PEERINFO service.
51 */
52 struct GNUNET_PEERINFO_Handle *h;
53
54 /**
55 * Function to call with the results.
56 */
57 GNUNET_PEERINFO_Processor callback;
58
59 /**
60 * Closure for @e callback.
61 */
62 void *callback_cls;
63
64 /**
65 * Peer we are interested in (only valid if iteration was restricted to one peer).
66 */
67 struct GNUNET_PeerIdentity peer;
68
69 /**
70 * Is @e peer set?
71 */
72 int have_peer;
73
74 /**
75 * Only include friends in reply?
76 */
77 int include_friend_only;
78};
79
80
81/**
82 * Handle to the peerinfo service.
83 */
84struct GNUNET_PEERINFO_Handle
85{
86 /**
87 * Our configuration.
88 */
89 const struct GNUNET_CONFIGURATION_Handle *cfg;
90
91 /**
92 * Connection to the service.
93 */
94 struct GNUNET_MQ_Handle *mq;
95
96 /**
97 * Head of iterator DLL.
98 */
99 struct GNUNET_PEERINFO_IteratorContext *ic_head;
100
101 /**
102 * Tail of iterator DLL.
103 */
104 struct GNUNET_PEERINFO_IteratorContext *ic_tail;
105
106 /**
107 * ID for a reconnect task.
108 */
109 struct GNUNET_SCHEDULER_Task *r_task;
110};
111
112
113/**
114 * Close the existing connection to PEERINFO and reconnect.
115 *
116 * @param h handle to the service
117 */
118static void
119reconnect (struct GNUNET_PEERINFO_Handle *h);
120
121
122/**
123 * Connect to the peerinfo service.
124 *
125 * @param cfg configuration to use
126 * @return NULL on error (configuration related, actual connection
127 * establishment may happen asynchronously).
128 */
129struct GNUNET_PEERINFO_Handle *
130GNUNET_PEERINFO_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
131{
132 struct GNUNET_PEERINFO_Handle *h;
133
134 h = GNUNET_new (struct GNUNET_PEERINFO_Handle);
135 h->cfg = cfg;
136 reconnect (h);
137 if (NULL == h->mq)
138 {
139 GNUNET_free (h);
140 return NULL;
141 }
142 return h;
143}
144
145
146/**
147 * Disconnect from the peerinfo service. Note that all iterators must
148 * have completed or have been cancelled by the time this function is
149 * called (otherwise, calling this function is a serious error).
150 * Furthermore, if #GNUNET_PEERINFO_add_peer() operations are still
151 * pending, they will be cancelled silently on disconnect.
152 *
153 * @param h handle to disconnect
154 */
155void
156GNUNET_PEERINFO_disconnect (struct GNUNET_PEERINFO_Handle *h)
157{
158 struct GNUNET_PEERINFO_IteratorContext *ic;
159
160 while (NULL != (ic = h->ic_head))
161 {
162 GNUNET_CONTAINER_DLL_remove (h->ic_head,
163 h->ic_tail,
164 ic);
165 GNUNET_free (ic);
166 }
167 if (NULL != h->mq)
168 {
169 GNUNET_MQ_destroy (h->mq);
170 h->mq = NULL;
171 }
172 if (NULL != h->r_task)
173 {
174 GNUNET_SCHEDULER_cancel (h->r_task);
175 h->r_task = NULL;
176 }
177 GNUNET_free (h);
178}
179
180
181/**
182 * Task scheduled to re-try connecting to the peerinfo service.
183 *
184 * @param cls the `struct GNUNET_PEERINFO_Handle *`
185 */
186static void
187reconnect_task (void *cls)
188{
189 struct GNUNET_PEERINFO_Handle *h = cls;
190
191 h->r_task = NULL;
192 reconnect (h);
193}
194
195
196/**
197 * We encountered an error, reconnect to the PEERINFO service.
198 *
199 * @param h handle to reconnect
200 */
201static void
202do_reconnect (struct GNUNET_PEERINFO_Handle *h)
203{
204 struct GNUNET_PEERINFO_IteratorContext *ic = h->ic_head;
205
206 GNUNET_MQ_destroy (h->mq);
207 h->mq = NULL;
208 if (NULL != ic)
209 {
210 GNUNET_CONTAINER_DLL_remove (h->ic_head,
211 h->ic_tail,
212 ic);
213 if (NULL != ic->callback)
214 ic->callback (ic->callback_cls,
215 NULL,
216 NULL,
217 _ ("Failed to receive response from `PEERINFO' service."));
218 GNUNET_free (ic);
219 }
220 h->r_task = GNUNET_SCHEDULER_add_now (&reconnect_task,
221 h);
222}
223
224
225/**
226 * We got a disconnect after asking regex to do the announcement.
227 * Retry.
228 *
229 * @param cls the `struct GNUNET_PEERINFO_Handle` to retry
230 * @param error error code
231 */
232static void
233mq_error_handler (void *cls,
234 enum GNUNET_MQ_Error error)
235{
236 struct GNUNET_PEERINFO_Handle *h = cls;
237
238 do_reconnect (h);
239}
240
241
242/**
243 * Function called when we receive an info message. Check it is
244 * well-formed.
245 *
246 * @param cls closure
247 * @param im message received
248 * @return #GNUNET_OK if the message is OK
249 */
250static int
251check_info (void *cls,
252 const struct InfoMessage *im)
253{
254 struct GNUNET_PEERINFO_Handle *h = cls;
255 struct GNUNET_PEERINFO_IteratorContext *ic = h->ic_head;
256 uint16_t ms = ntohs (im->header.size) - sizeof(*im);
257
258 if (0 != ntohl (im->reserved))
259 {
260 GNUNET_break (0);
261 return GNUNET_SYSERR;
262 }
263 if (NULL == ic)
264 {
265 /* didn't expect a response, bad */
266 GNUNET_break (0);
267 return GNUNET_SYSERR;
268 }
269 if ((GNUNET_YES == ic->have_peer) &&
270 (0 != GNUNET_memcmp (&ic->peer,
271 &im->peer)))
272 {
273 /* bogus message (from a different iteration call?); out of sequence! */
274 LOG (GNUNET_ERROR_TYPE_ERROR,
275 "Received HELLO for peer `%s', expected peer `%s'\n",
276 GNUNET_i2s (&im->peer),
277 GNUNET_i2s (&ic->peer));
278 GNUNET_break (0);
279 return GNUNET_SYSERR;
280 }
281 if (ms > sizeof(struct GNUNET_MessageHeader))
282 {
283 const struct GNUNET_HELLO_Message *hello;
284 struct GNUNET_PeerIdentity id;
285
286 hello = (const struct GNUNET_HELLO_Message *) &im[1];
287 if (ms != GNUNET_HELLO_size (hello))
288 {
289 /* malformed message */
290 GNUNET_break (0);
291 return GNUNET_SYSERR;
292 }
293 if (GNUNET_OK !=
294 GNUNET_HELLO_get_id (hello,
295 &id))
296 {
297 /* malformed message */
298 GNUNET_break (0);
299 return GNUNET_SYSERR;
300 }
301 if (0 != GNUNET_memcmp (&im->peer,
302 &id))
303 {
304 /* malformed message */
305 GNUNET_break (0);
306 return GNUNET_SYSERR;
307 }
308 }
309 else if (0 != ms)
310 {
311 /* malformed message */
312 GNUNET_break (0);
313 return GNUNET_SYSERR;
314 }
315 return GNUNET_OK;
316}
317
318
319/**
320 * Handle info message.
321 *
322 * @param cls closure
323 * @param im message received
324 */
325static void
326handle_info (void *cls,
327 const struct InfoMessage *im)
328{
329 struct GNUNET_PEERINFO_Handle *h = cls;
330 struct GNUNET_PEERINFO_IteratorContext *ic = h->ic_head;
331 const struct GNUNET_HELLO_Message *hello = NULL;
332 uint16_t ms;
333
334 ms = ntohs (im->header.size);
335 if (ms > sizeof(struct InfoMessage))
336 hello = (const struct GNUNET_HELLO_Message *) &im[1];
337 if (NULL != ic->callback)
338 ic->callback (ic->callback_cls,
339 &im->peer,
340 hello,
341 NULL);
342}
343
344
345/**
346 * Send the next IC request at the head of the queue.
347 *
348 * @param h handle
349 */
350static void
351send_ic_request (struct GNUNET_PEERINFO_Handle *h)
352{
353 struct GNUNET_PEERINFO_IteratorContext *ic = h->ic_head;
354 struct GNUNET_MQ_Envelope *env;
355 struct ListAllPeersMessage *lapm;
356 struct ListPeerMessage *lpm;
357
358 if (NULL == ic)
359 {
360 GNUNET_break (0);
361 return;
362 }
363 if (NULL == h->mq)
364 {
365 GNUNET_break (0);
366 return;
367 }
368 if (GNUNET_NO == ic->have_peer)
369 {
370 LOG (GNUNET_ERROR_TYPE_DEBUG,
371 "Requesting list of peers from PEERINFO service\n");
372 env = GNUNET_MQ_msg (lapm,
373 GNUNET_MESSAGE_TYPE_PEERINFO_GET_ALL);
374 lapm->include_friend_only = htonl (ic->include_friend_only);
375 }
376 else
377 {
378 LOG (GNUNET_ERROR_TYPE_DEBUG,
379 "Requesting information on peer `%s' from PEERINFO service\n",
380 GNUNET_i2s (&ic->peer));
381 env = GNUNET_MQ_msg (lpm,
382 GNUNET_MESSAGE_TYPE_PEERINFO_GET);
383 lpm->include_friend_only = htonl (ic->include_friend_only);
384 lpm->peer = ic->peer;
385 }
386 GNUNET_MQ_send (h->mq,
387 env);
388}
389
390
391/**
392 * Type of a function to call when we receive a message from the
393 * service. Call the iterator with the result and (if applicable)
394 * continue to receive more messages or trigger processing the next
395 * event (if applicable).
396 *
397 * @param cls closure
398 * @param msg message received, NULL on timeout or fatal error
399 */
400static void
401handle_end_iteration (void *cls,
402 const struct GNUNET_MessageHeader *msg)
403{
404 struct GNUNET_PEERINFO_Handle *h = cls;
405 struct GNUNET_PEERINFO_IteratorContext *ic = h->ic_head;
406
407 if (NULL == ic)
408 {
409 /* didn't expect a response, reconnect */
410 GNUNET_break (0);
411 reconnect (h);
412 return;
413 }
414 LOG (GNUNET_ERROR_TYPE_DEBUG,
415 "Received end of list of peers from PEERINFO service\n");
416 GNUNET_CONTAINER_DLL_remove (h->ic_head,
417 h->ic_tail,
418 ic);
419 if (NULL != h->ic_head)
420 send_ic_request (h);
421 if (NULL != ic->callback)
422 ic->callback (ic->callback_cls,
423 NULL,
424 NULL,
425 NULL);
426 GNUNET_free (ic);
427}
428
429
430/**
431 * Close the existing connection to PEERINFO and reconnect.
432 *
433 * @param h handle to the service
434 */
435static void
436reconnect (struct GNUNET_PEERINFO_Handle *h)
437{
438 struct GNUNET_MQ_MessageHandler handlers[] = {
439 GNUNET_MQ_hd_var_size (info,
440 GNUNET_MESSAGE_TYPE_PEERINFO_INFO,
441 struct InfoMessage,
442 h),
443 GNUNET_MQ_hd_fixed_size (end_iteration,
444 GNUNET_MESSAGE_TYPE_PEERINFO_INFO_END,
445 struct GNUNET_MessageHeader,
446 h),
447 GNUNET_MQ_handler_end ()
448 };
449
450 if (NULL != h->r_task)
451 {
452 GNUNET_SCHEDULER_cancel (h->r_task);
453 h->r_task = NULL;
454 }
455 if (NULL != h->mq)
456 {
457 GNUNET_MQ_destroy (h->mq);
458 h->mq = NULL;
459 }
460 h->mq = GNUNET_CLIENT_connect (h->cfg,
461 "peerinfo",
462 handlers,
463 &mq_error_handler,
464 h);
465 if (NULL != h->ic_head)
466 send_ic_request (h);
467}
468
469
470/**
471 * Call a method for each known matching host. The callback method
472 * will be invoked once for each matching host and then finally once
473 * with a NULL pointer. After that final invocation, the iterator
474 * context must no longer be used.
475 *
476 * Instead of calling this function with `peer == NULL` it is often
477 * better to use #GNUNET_PEERINFO_notify().
478 *
479 * @param h handle to the peerinfo service
480 * @param include_friend_only include HELLO messages for friends only
481 * @param peer restrict iteration to this peer only (can be NULL)
482 * @param callback the method to call for each peer
483 * @param callback_cls closure for @a callback
484 * @return iterator context
485 */
486struct GNUNET_PEERINFO_IteratorContext *
487GNUNET_PEERINFO_iterate (struct GNUNET_PEERINFO_Handle *h,
488 int include_friend_only,
489 const struct GNUNET_PeerIdentity *peer,
490 GNUNET_PEERINFO_Processor callback,
491 void *callback_cls)
492{
493 struct GNUNET_PEERINFO_IteratorContext *ic;
494
495 ic = GNUNET_new (struct GNUNET_PEERINFO_IteratorContext);
496 ic->h = h;
497 ic->include_friend_only = include_friend_only;
498 ic->callback = callback;
499 ic->callback_cls = callback_cls;
500 if (NULL != peer)
501 {
502 ic->have_peer = GNUNET_YES;
503 ic->peer = *peer;
504 }
505 GNUNET_CONTAINER_DLL_insert_tail (h->ic_head,
506 h->ic_tail,
507 ic);
508 if (h->ic_head == ic)
509 send_ic_request (h);
510 return ic;
511}
512
513
514/**
515 * Cancel an iteration over peer information.
516 *
517 * @param ic context of the iterator to cancel
518 */
519void
520GNUNET_PEERINFO_iterate_cancel (struct GNUNET_PEERINFO_IteratorContext *ic)
521{
522 struct GNUNET_PEERINFO_Handle *h = ic->h;
523
524 ic->callback = NULL;
525 if (ic == h->ic_head)
526 return;
527 GNUNET_CONTAINER_DLL_remove (h->ic_head,
528 h->ic_tail,
529 ic);
530 GNUNET_free (ic);
531}
532
533
534/**
535 * Add a host to the persistent list. This method operates in
536 * semi-reliable mode: if the transmission is not completed by
537 * the time #GNUNET_PEERINFO_disconnect() is called, it will be
538 * aborted. Furthermore, if a second HELLO is added for the
539 * same peer before the first one was transmitted, PEERINFO may
540 * merge the two HELLOs prior to transmission to the service.
541 *
542 * @param h handle to the peerinfo service
543 * @param hello the verified (!) HELLO message
544 * @param cont continuation to call when done, NULL is allowed
545 * @param cont_cls closure for @a cont
546 * @return handle to cancel add operation; all pending
547 * 'add' operations will be cancelled automatically
548 * on disconnect, so it is not necessary to keep this
549 * handle (unless @a cont is NULL and at some point
550 * calling @a cont must be prevented)
551 */
552struct GNUNET_MQ_Envelope *
553GNUNET_PEERINFO_add_peer (struct GNUNET_PEERINFO_Handle *h,
554 const struct GNUNET_HELLO_Message *hello,
555 GNUNET_SCHEDULER_TaskCallback cont,
556 void *cont_cls)
557{
558 struct GNUNET_MQ_Envelope *env;
559 struct GNUNET_PeerIdentity peer;
560
561 if (NULL == h->mq)
562 return NULL;
563 GNUNET_assert (GNUNET_OK ==
564 GNUNET_HELLO_get_id (hello,
565 &peer));
566 LOG (GNUNET_ERROR_TYPE_DEBUG,
567 "Adding peer `%s' to PEERINFO database\n",
568 GNUNET_i2s (&peer));
569 env = GNUNET_MQ_msg_copy ((const struct GNUNET_MessageHeader *) hello);
570 if (NULL != cont)
571 GNUNET_MQ_notify_sent (env,
572 cont,
573 cont_cls);
574 GNUNET_MQ_send (h->mq,
575 env);
576 return env;
577}
578
579
580/* end of peerinfo_api.c */