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.c557
1 files changed, 0 insertions, 557 deletions
diff --git a/src/peerinfo/peerinfo_api.c b/src/peerinfo/peerinfo_api.c
deleted file mode 100644
index 65e429bef..000000000
--- a/src/peerinfo/peerinfo_api.c
+++ /dev/null
@@ -1,557 +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
122struct GNUNET_PEERINFO_Handle *
123GNUNET_PEERINFO_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
124{
125 struct GNUNET_PEERINFO_Handle *h;
126
127 h = GNUNET_new (struct GNUNET_PEERINFO_Handle);
128 h->cfg = cfg;
129 reconnect (h);
130 if (NULL == h->mq)
131 {
132 GNUNET_free (h);
133 return NULL;
134 }
135 return h;
136}
137
138
139/**
140 * Disconnect from the peerinfo service. Note that all iterators must
141 * have completed or have been cancelled by the time this function is
142 * called (otherwise, calling this function is a serious error).
143 * Furthermore, if #GNUNET_PEERINFO_add_peer() operations are still
144 * pending, they will be cancelled silently on disconnect.
145 *
146 * @param h handle to disconnect
147 */
148void
149GNUNET_PEERINFO_disconnect (struct GNUNET_PEERINFO_Handle *h)
150{
151 struct GNUNET_PEERINFO_IteratorContext *ic;
152
153 while (NULL != (ic = h->ic_head))
154 {
155 GNUNET_CONTAINER_DLL_remove (h->ic_head,
156 h->ic_tail,
157 ic);
158 GNUNET_free (ic);
159 }
160 if (NULL != h->mq)
161 {
162 GNUNET_MQ_destroy (h->mq);
163 h->mq = NULL;
164 }
165 if (NULL != h->r_task)
166 {
167 GNUNET_SCHEDULER_cancel (h->r_task);
168 h->r_task = NULL;
169 }
170 GNUNET_free (h);
171}
172
173
174/**
175 * Task scheduled to re-try connecting to the peerinfo service.
176 *
177 * @param cls the `struct GNUNET_PEERINFO_Handle *`
178 */
179static void
180reconnect_task (void *cls)
181{
182 struct GNUNET_PEERINFO_Handle *h = cls;
183
184 h->r_task = NULL;
185 reconnect (h);
186}
187
188
189/**
190 * We encountered an error, reconnect to the PEERINFO service.
191 *
192 * @param h handle to reconnect
193 */
194static void
195do_reconnect (struct GNUNET_PEERINFO_Handle *h)
196{
197 struct GNUNET_PEERINFO_IteratorContext *ic = h->ic_head;
198
199 GNUNET_MQ_destroy (h->mq);
200 h->mq = NULL;
201 if (NULL != ic)
202 {
203 GNUNET_CONTAINER_DLL_remove (h->ic_head,
204 h->ic_tail,
205 ic);
206 if (NULL != ic->callback)
207 ic->callback (ic->callback_cls,
208 NULL,
209 NULL,
210 _ ("Failed to receive response from `PEERINFO' service."));
211 GNUNET_free (ic);
212 }
213 h->r_task = GNUNET_SCHEDULER_add_now (&reconnect_task,
214 h);
215}
216
217
218/**
219 * We got a disconnect after asking regex to do the announcement.
220 * Retry.
221 *
222 * @param cls the `struct GNUNET_PEERINFO_Handle` to retry
223 * @param error error code
224 */
225static void
226mq_error_handler (void *cls,
227 enum GNUNET_MQ_Error error)
228{
229 struct GNUNET_PEERINFO_Handle *h = cls;
230
231 do_reconnect (h);
232}
233
234
235/**
236 * Function called when we receive an info message. Check it is
237 * well-formed.
238 *
239 * @param cls closure
240 * @param im message received
241 * @return #GNUNET_OK if the message is OK
242 */
243static int
244check_info (void *cls,
245 const struct InfoMessage *im)
246{
247 struct GNUNET_PEERINFO_Handle *h = cls;
248 struct GNUNET_PEERINFO_IteratorContext *ic = h->ic_head;
249 uint16_t ms = ntohs (im->header.size) - sizeof(*im);
250
251 if (0 != ntohl (im->reserved))
252 {
253 GNUNET_break (0);
254 return GNUNET_SYSERR;
255 }
256 if (NULL == ic)
257 {
258 /* didn't expect a response, bad */
259 GNUNET_break (0);
260 return GNUNET_SYSERR;
261 }
262 if ((GNUNET_YES == ic->have_peer) &&
263 (0 != GNUNET_memcmp (&ic->peer,
264 &im->peer)))
265 {
266 /* bogus message (from a different iteration call?); out of sequence! */
267 LOG (GNUNET_ERROR_TYPE_ERROR,
268 "Received HELLO for peer `%s', expected peer `%s'\n",
269 GNUNET_i2s (&im->peer),
270 GNUNET_i2s (&ic->peer));
271 GNUNET_break (0);
272 return GNUNET_SYSERR;
273 }
274 if (ms > sizeof(struct GNUNET_MessageHeader))
275 {
276 const struct GNUNET_HELLO_Message *hello;
277 struct GNUNET_PeerIdentity id;
278
279 hello = (const struct GNUNET_HELLO_Message *) &im[1];
280 if (ms != GNUNET_HELLO_size (hello))
281 {
282 /* malformed message */
283 GNUNET_break (0);
284 return GNUNET_SYSERR;
285 }
286 if (GNUNET_OK !=
287 GNUNET_HELLO_get_id (hello,
288 &id))
289 {
290 /* malformed message */
291 GNUNET_break (0);
292 return GNUNET_SYSERR;
293 }
294 if (0 != GNUNET_memcmp (&im->peer,
295 &id))
296 {
297 /* malformed message */
298 GNUNET_break (0);
299 return GNUNET_SYSERR;
300 }
301 }
302 else if (0 != ms)
303 {
304 /* malformed message */
305 GNUNET_break (0);
306 return GNUNET_SYSERR;
307 }
308 return GNUNET_OK;
309}
310
311
312/**
313 * Handle info message.
314 *
315 * @param cls closure
316 * @param im message received
317 */
318static void
319handle_info (void *cls,
320 const struct InfoMessage *im)
321{
322 struct GNUNET_PEERINFO_Handle *h = cls;
323 struct GNUNET_PEERINFO_IteratorContext *ic = h->ic_head;
324 const struct GNUNET_HELLO_Message *hello = NULL;
325 uint16_t ms;
326
327 ms = ntohs (im->header.size);
328 if (ms > sizeof(struct InfoMessage))
329 hello = (const struct GNUNET_HELLO_Message *) &im[1];
330 if (NULL != ic->callback)
331 ic->callback (ic->callback_cls,
332 &im->peer,
333 hello,
334 NULL);
335}
336
337
338/**
339 * Send the next IC request at the head of the queue.
340 *
341 * @param h handle
342 */
343static void
344send_ic_request (struct GNUNET_PEERINFO_Handle *h)
345{
346 struct GNUNET_PEERINFO_IteratorContext *ic = h->ic_head;
347 struct GNUNET_MQ_Envelope *env;
348 struct ListAllPeersMessage *lapm;
349 struct ListPeerMessage *lpm;
350
351 if (NULL == ic)
352 {
353 GNUNET_break (0);
354 return;
355 }
356 if (NULL == h->mq)
357 {
358 GNUNET_break (0);
359 return;
360 }
361 if (GNUNET_NO == ic->have_peer)
362 {
363 LOG (GNUNET_ERROR_TYPE_DEBUG,
364 "Requesting list of peers from PEERINFO service\n");
365 env = GNUNET_MQ_msg (lapm,
366 GNUNET_MESSAGE_TYPE_PEERINFO_GET_ALL);
367 lapm->include_friend_only = htonl (ic->include_friend_only);
368 }
369 else
370 {
371 LOG (GNUNET_ERROR_TYPE_DEBUG,
372 "Requesting information on peer `%s' from PEERINFO service\n",
373 GNUNET_i2s (&ic->peer));
374 env = GNUNET_MQ_msg (lpm,
375 GNUNET_MESSAGE_TYPE_PEERINFO_GET);
376 lpm->include_friend_only = htonl (ic->include_friend_only);
377 lpm->peer = ic->peer;
378 }
379 GNUNET_MQ_send (h->mq,
380 env);
381}
382
383
384/**
385 * Type of a function to call when we receive a message from the
386 * service. Call the iterator with the result and (if applicable)
387 * continue to receive more messages or trigger processing the next
388 * event (if applicable).
389 *
390 * @param cls closure
391 * @param msg message received, NULL on timeout or fatal error
392 */
393static void
394handle_end_iteration (void *cls,
395 const struct GNUNET_MessageHeader *msg)
396{
397 struct GNUNET_PEERINFO_Handle *h = cls;
398 struct GNUNET_PEERINFO_IteratorContext *ic = h->ic_head;
399
400 if (NULL == ic)
401 {
402 /* didn't expect a response, reconnect */
403 GNUNET_break (0);
404 reconnect (h);
405 return;
406 }
407 LOG (GNUNET_ERROR_TYPE_DEBUG,
408 "Received end of list of peers from PEERINFO service\n");
409 GNUNET_CONTAINER_DLL_remove (h->ic_head,
410 h->ic_tail,
411 ic);
412 if (NULL != h->ic_head)
413 send_ic_request (h);
414 if (NULL != ic->callback)
415 ic->callback (ic->callback_cls,
416 NULL,
417 NULL,
418 NULL);
419 GNUNET_free (ic);
420}
421
422
423/**
424 * Close the existing connection to PEERINFO and reconnect.
425 *
426 * @param h handle to the service
427 */
428static void
429reconnect (struct GNUNET_PEERINFO_Handle *h)
430{
431 struct GNUNET_MQ_MessageHandler handlers[] = {
432 GNUNET_MQ_hd_var_size (info,
433 GNUNET_MESSAGE_TYPE_PEERINFO_INFO,
434 struct InfoMessage,
435 h),
436 GNUNET_MQ_hd_fixed_size (end_iteration,
437 GNUNET_MESSAGE_TYPE_PEERINFO_INFO_END,
438 struct GNUNET_MessageHeader,
439 h),
440 GNUNET_MQ_handler_end ()
441 };
442
443 if (NULL != h->r_task)
444 {
445 GNUNET_SCHEDULER_cancel (h->r_task);
446 h->r_task = NULL;
447 }
448 if (NULL != h->mq)
449 {
450 GNUNET_MQ_destroy (h->mq);
451 h->mq = NULL;
452 }
453 h->mq = GNUNET_CLIENT_connect (h->cfg,
454 "peerinfo",
455 handlers,
456 &mq_error_handler,
457 h);
458 if (NULL != h->ic_head)
459 send_ic_request (h);
460}
461
462
463struct GNUNET_PEERINFO_IteratorContext *
464GNUNET_PEERINFO_iterate (struct GNUNET_PEERINFO_Handle *h,
465 int include_friend_only,
466 const struct GNUNET_PeerIdentity *peer,
467 GNUNET_PEERINFO_Processor callback,
468 void *callback_cls)
469{
470 struct GNUNET_PEERINFO_IteratorContext *ic;
471
472 ic = GNUNET_new (struct GNUNET_PEERINFO_IteratorContext);
473 ic->h = h;
474 ic->include_friend_only = include_friend_only;
475 ic->callback = callback;
476 ic->callback_cls = callback_cls;
477 if (NULL != peer)
478 {
479 ic->have_peer = GNUNET_YES;
480 ic->peer = *peer;
481 }
482 GNUNET_CONTAINER_DLL_insert_tail (h->ic_head,
483 h->ic_tail,
484 ic);
485 if (h->ic_head == ic)
486 send_ic_request (h);
487 return ic;
488}
489
490
491/**
492 * Cancel an iteration over peer information.
493 *
494 * @param ic context of the iterator to cancel
495 */
496void
497GNUNET_PEERINFO_iterate_cancel (struct GNUNET_PEERINFO_IteratorContext *ic)
498{
499 struct GNUNET_PEERINFO_Handle *h = ic->h;
500
501 ic->callback = NULL;
502 if (ic == h->ic_head)
503 return;
504 GNUNET_CONTAINER_DLL_remove (h->ic_head,
505 h->ic_tail,
506 ic);
507 GNUNET_free (ic);
508}
509
510
511/**
512 * Add a host to the persistent list. This method operates in
513 * semi-reliable mode: if the transmission is not completed by
514 * the time #GNUNET_PEERINFO_disconnect() is called, it will be
515 * aborted. Furthermore, if a second HELLO is added for the
516 * same peer before the first one was transmitted, PEERINFO may
517 * merge the two HELLOs prior to transmission to the service.
518 *
519 * @param h handle to the peerinfo service
520 * @param hello the verified (!) HELLO message
521 * @param cont continuation to call when done, NULL is allowed
522 * @param cont_cls closure for @a cont
523 * @return handle to cancel add operation; all pending
524 * 'add' operations will be cancelled automatically
525 * on disconnect, so it is not necessary to keep this
526 * handle (unless @a cont is NULL and at some point
527 * calling @a cont must be prevented)
528 */
529struct GNUNET_MQ_Envelope *
530GNUNET_PEERINFO_add_peer (struct GNUNET_PEERINFO_Handle *h,
531 const struct GNUNET_HELLO_Message *hello,
532 GNUNET_SCHEDULER_TaskCallback cont,
533 void *cont_cls)
534{
535 struct GNUNET_MQ_Envelope *env;
536 struct GNUNET_PeerIdentity peer;
537
538 if (NULL == h->mq)
539 return NULL;
540 GNUNET_assert (GNUNET_OK ==
541 GNUNET_HELLO_get_id (hello,
542 &peer));
543 LOG (GNUNET_ERROR_TYPE_DEBUG,
544 "Adding peer `%s' to PEERINFO database\n",
545 GNUNET_i2s (&peer));
546 env = GNUNET_MQ_msg_copy ((const struct GNUNET_MessageHeader *) hello);
547 if (NULL != cont)
548 GNUNET_MQ_notify_sent (env,
549 cont,
550 cont_cls);
551 GNUNET_MQ_send (h->mq,
552 env);
553 return env;
554}
555
556
557/* end of peerinfo_api.c */