diff options
Diffstat (limited to 'src/peerinfo/peerinfo_api.c')
-rw-r--r-- | src/peerinfo/peerinfo_api.c | 580 |
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 | */ | ||
37 | struct 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 | */ | ||
84 | struct 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 | */ | ||
118 | static void | ||
119 | reconnect (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 | */ | ||
129 | struct GNUNET_PEERINFO_Handle * | ||
130 | GNUNET_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 | */ | ||
155 | void | ||
156 | GNUNET_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 | */ | ||
186 | static void | ||
187 | reconnect_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 | */ | ||
201 | static void | ||
202 | do_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 | */ | ||
232 | static void | ||
233 | mq_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 | */ | ||
250 | static int | ||
251 | check_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 | */ | ||
325 | static void | ||
326 | handle_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 | */ | ||
350 | static void | ||
351 | send_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 | */ | ||
400 | static void | ||
401 | handle_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 | */ | ||
435 | static void | ||
436 | reconnect (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 | */ | ||
486 | struct GNUNET_PEERINFO_IteratorContext * | ||
487 | GNUNET_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 | */ | ||
519 | void | ||
520 | GNUNET_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 | */ | ||
552 | struct GNUNET_MQ_Envelope * | ||
553 | GNUNET_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 */ | ||