diff options
Diffstat (limited to 'src/peerinfo/peerinfo_api.c')
-rw-r--r-- | src/peerinfo/peerinfo_api.c | 557 |
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 | */ | ||
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 | struct GNUNET_PEERINFO_Handle * | ||
123 | GNUNET_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 | */ | ||
148 | void | ||
149 | GNUNET_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 | */ | ||
179 | static void | ||
180 | reconnect_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 | */ | ||
194 | static void | ||
195 | do_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 | */ | ||
225 | static void | ||
226 | mq_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 | */ | ||
243 | static int | ||
244 | check_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 | */ | ||
318 | static void | ||
319 | handle_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 | */ | ||
343 | static void | ||
344 | send_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 | */ | ||
393 | static void | ||
394 | handle_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 | */ | ||
428 | static void | ||
429 | reconnect (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 | |||
463 | struct GNUNET_PEERINFO_IteratorContext * | ||
464 | GNUNET_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 | */ | ||
496 | void | ||
497 | GNUNET_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 | */ | ||
529 | struct GNUNET_MQ_Envelope * | ||
530 | GNUNET_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 */ | ||