diff options
Diffstat (limited to 'src/core/core_api.c')
-rw-r--r-- | src/core/core_api.c | 773 |
1 files changed, 0 insertions, 773 deletions
diff --git a/src/core/core_api.c b/src/core/core_api.c deleted file mode 100644 index 81118693d..000000000 --- a/src/core/core_api.c +++ /dev/null | |||
@@ -1,773 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009-2016 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 | * @file core/core_api.c | ||
22 | * @brief core service; this is the main API for encrypted P2P | ||
23 | * communications | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet_util_lib.h" | ||
28 | #include "gnunet_constants.h" | ||
29 | #include "gnunet_core_service.h" | ||
30 | #include "core.h" | ||
31 | |||
32 | #define LOG(kind, ...) GNUNET_log_from (kind, "core-api", __VA_ARGS__) | ||
33 | |||
34 | |||
35 | /** | ||
36 | * Information we track for each peer. | ||
37 | */ | ||
38 | struct PeerRecord | ||
39 | { | ||
40 | /** | ||
41 | * Corresponding CORE handle. | ||
42 | */ | ||
43 | struct GNUNET_CORE_Handle *h; | ||
44 | |||
45 | /** | ||
46 | * Message queue for the peer. | ||
47 | */ | ||
48 | struct GNUNET_MQ_Handle *mq; | ||
49 | |||
50 | /** | ||
51 | * Message we are currently trying to pass to the CORE service | ||
52 | * for this peer (from @e mq). | ||
53 | */ | ||
54 | struct GNUNET_MQ_Envelope *env; | ||
55 | |||
56 | /** | ||
57 | * Value the client returned when we connected, used | ||
58 | * as the closure in various places. | ||
59 | */ | ||
60 | void *client_cls; | ||
61 | |||
62 | /** | ||
63 | * Peer the record is about. | ||
64 | */ | ||
65 | struct GNUNET_PeerIdentity peer; | ||
66 | |||
67 | /** | ||
68 | * SendMessageRequest ID generator for this peer. | ||
69 | */ | ||
70 | uint16_t smr_id_gen; | ||
71 | }; | ||
72 | |||
73 | |||
74 | /** | ||
75 | * Context for the core service connection. | ||
76 | */ | ||
77 | struct GNUNET_CORE_Handle | ||
78 | { | ||
79 | /** | ||
80 | * Configuration we're using. | ||
81 | */ | ||
82 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
83 | |||
84 | /** | ||
85 | * Closure for the various callbacks. | ||
86 | */ | ||
87 | void *cls; | ||
88 | |||
89 | /** | ||
90 | * Function to call once we've handshaked with the core service. | ||
91 | */ | ||
92 | GNUNET_CORE_StartupCallback init; | ||
93 | |||
94 | /** | ||
95 | * Function to call whenever we're notified about a peer connecting. | ||
96 | */ | ||
97 | GNUNET_CORE_ConnectEventHandler connects; | ||
98 | |||
99 | /** | ||
100 | * Function to call whenever we're notified about a peer disconnecting. | ||
101 | */ | ||
102 | GNUNET_CORE_DisconnectEventHandler disconnects; | ||
103 | |||
104 | /** | ||
105 | * Function handlers for messages of particular type. | ||
106 | */ | ||
107 | struct GNUNET_MQ_MessageHandler *handlers; | ||
108 | |||
109 | /** | ||
110 | * Our message queue for transmissions to the service. | ||
111 | */ | ||
112 | struct GNUNET_MQ_Handle *mq; | ||
113 | |||
114 | /** | ||
115 | * Hash map listing all of the peers that we are currently | ||
116 | * connected to. | ||
117 | */ | ||
118 | struct GNUNET_CONTAINER_MultiPeerMap *peers; | ||
119 | |||
120 | /** | ||
121 | * Identity of this peer. | ||
122 | */ | ||
123 | struct GNUNET_PeerIdentity me; | ||
124 | |||
125 | /** | ||
126 | * ID of reconnect task (if any). | ||
127 | */ | ||
128 | struct GNUNET_SCHEDULER_Task *reconnect_task; | ||
129 | |||
130 | /** | ||
131 | * Current delay we use for re-trying to connect to core. | ||
132 | */ | ||
133 | struct GNUNET_TIME_Relative retry_backoff; | ||
134 | |||
135 | /** | ||
136 | * Number of entries in the handlers array. | ||
137 | */ | ||
138 | unsigned int hcnt; | ||
139 | |||
140 | /** | ||
141 | * Did we ever get INIT? | ||
142 | */ | ||
143 | int have_init; | ||
144 | }; | ||
145 | |||
146 | |||
147 | /** | ||
148 | * Our current client connection went down. Clean it up | ||
149 | * and try to reconnect! | ||
150 | * | ||
151 | * @param h our handle to the core service | ||
152 | */ | ||
153 | static void | ||
154 | reconnect (struct GNUNET_CORE_Handle *h); | ||
155 | |||
156 | |||
157 | /** | ||
158 | * Task schedule to try to re-connect to core. | ||
159 | * | ||
160 | * @param cls the `struct GNUNET_CORE_Handle` | ||
161 | * @param tc task context | ||
162 | */ | ||
163 | static void | ||
164 | reconnect_task (void *cls) | ||
165 | { | ||
166 | struct GNUNET_CORE_Handle *h = cls; | ||
167 | |||
168 | h->reconnect_task = NULL; | ||
169 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to CORE service after delay\n"); | ||
170 | reconnect (h); | ||
171 | } | ||
172 | |||
173 | |||
174 | /** | ||
175 | * Notify clients about disconnect and free the entry for connected | ||
176 | * peer. | ||
177 | * | ||
178 | * @param cls the `struct GNUNET_CORE_Handle *` | ||
179 | * @param key the peer identity (not used) | ||
180 | * @param value the `struct PeerRecord` to free. | ||
181 | * @return #GNUNET_YES (continue) | ||
182 | */ | ||
183 | static int | ||
184 | disconnect_and_free_peer_entry (void *cls, | ||
185 | const struct GNUNET_PeerIdentity *key, | ||
186 | void *value) | ||
187 | { | ||
188 | struct GNUNET_CORE_Handle *h = cls; | ||
189 | struct PeerRecord *pr = value; | ||
190 | |||
191 | GNUNET_assert (pr->h == h); | ||
192 | if (NULL != h->disconnects) | ||
193 | h->disconnects (h->cls, &pr->peer, pr->client_cls); | ||
194 | GNUNET_assert (GNUNET_YES == | ||
195 | GNUNET_CONTAINER_multipeermap_remove (h->peers, key, pr)); | ||
196 | GNUNET_MQ_destroy (pr->mq); | ||
197 | GNUNET_assert (NULL == pr->mq); | ||
198 | if (NULL != pr->env) | ||
199 | { | ||
200 | GNUNET_MQ_discard (pr->env); | ||
201 | pr->env = NULL; | ||
202 | } | ||
203 | GNUNET_free (pr); | ||
204 | return GNUNET_YES; | ||
205 | } | ||
206 | |||
207 | |||
208 | /** | ||
209 | * Close down any existing connection to the CORE service and | ||
210 | * try re-establishing it later. | ||
211 | * | ||
212 | * @param h our handle | ||
213 | */ | ||
214 | static void | ||
215 | reconnect_later (struct GNUNET_CORE_Handle *h) | ||
216 | { | ||
217 | GNUNET_assert (NULL == h->reconnect_task); | ||
218 | if (NULL != h->mq) | ||
219 | { | ||
220 | GNUNET_MQ_destroy (h->mq); | ||
221 | h->mq = NULL; | ||
222 | } | ||
223 | GNUNET_assert (NULL == h->reconnect_task); | ||
224 | h->reconnect_task = | ||
225 | GNUNET_SCHEDULER_add_delayed (h->retry_backoff, &reconnect_task, h); | ||
226 | GNUNET_CONTAINER_multipeermap_iterate (h->peers, | ||
227 | &disconnect_and_free_peer_entry, | ||
228 | h); | ||
229 | h->retry_backoff = GNUNET_TIME_STD_BACKOFF (h->retry_backoff); | ||
230 | } | ||
231 | |||
232 | |||
233 | /** | ||
234 | * Error handler for the message queue to the CORE service. | ||
235 | * On errors, we reconnect. | ||
236 | * | ||
237 | * @param cls closure, a `struct GNUNET_CORE_Handle *` | ||
238 | * @param error error code | ||
239 | */ | ||
240 | static void | ||
241 | handle_mq_error (void *cls, enum GNUNET_MQ_Error error) | ||
242 | { | ||
243 | struct GNUNET_CORE_Handle *h = cls; | ||
244 | |||
245 | LOG (GNUNET_ERROR_TYPE_DEBUG, "MQ ERROR: %d\n", error); | ||
246 | reconnect_later (h); | ||
247 | } | ||
248 | |||
249 | |||
250 | /** | ||
251 | * Implement sending functionality of a message queue for | ||
252 | * us sending messages to a peer. | ||
253 | * | ||
254 | * @param mq the message queue | ||
255 | * @param msg the message to send | ||
256 | * @param impl_state state of the implementation | ||
257 | */ | ||
258 | static void | ||
259 | core_mq_send_impl (struct GNUNET_MQ_Handle *mq, | ||
260 | const struct GNUNET_MessageHeader *msg, | ||
261 | void *impl_state) | ||
262 | { | ||
263 | struct PeerRecord *pr = impl_state; | ||
264 | struct GNUNET_CORE_Handle *h = pr->h; | ||
265 | struct SendMessageRequest *smr; | ||
266 | struct SendMessage *sm; | ||
267 | struct GNUNET_MQ_Envelope *env; | ||
268 | uint16_t msize; | ||
269 | enum GNUNET_MQ_PriorityPreferences flags; | ||
270 | |||
271 | if (NULL == h->mq) | ||
272 | { | ||
273 | /* We're currently reconnecting, pretend this worked */ | ||
274 | GNUNET_MQ_impl_send_continue (mq); | ||
275 | return; | ||
276 | } | ||
277 | GNUNET_assert (NULL == pr->env); | ||
278 | /* extract options from envelope */ | ||
279 | env = GNUNET_MQ_get_current_envelope (mq); | ||
280 | flags = GNUNET_MQ_env_get_options (env); | ||
281 | |||
282 | /* check message size for sanity */ | ||
283 | msize = ntohs (msg->size); | ||
284 | if (msize >= GNUNET_MAX_MESSAGE_SIZE - sizeof(struct SendMessage)) | ||
285 | { | ||
286 | GNUNET_break (0); | ||
287 | GNUNET_MQ_impl_send_continue (mq); | ||
288 | return; | ||
289 | } | ||
290 | |||
291 | /* ask core for transmission */ | ||
292 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
293 | "Asking core for transmission of %u bytes to `%s'\n", | ||
294 | (unsigned int) msize, | ||
295 | GNUNET_i2s (&pr->peer)); | ||
296 | env = GNUNET_MQ_msg (smr, GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST); | ||
297 | smr->priority = htonl ((uint32_t) flags); | ||
298 | smr->peer = pr->peer; | ||
299 | smr->size = htons (msize); | ||
300 | smr->smr_id = htons (++pr->smr_id_gen); | ||
301 | GNUNET_MQ_send (h->mq, env); | ||
302 | |||
303 | /* prepare message with actual transmission data */ | ||
304 | pr->env = GNUNET_MQ_msg_nested_mh (sm, GNUNET_MESSAGE_TYPE_CORE_SEND, msg); | ||
305 | sm->priority = htonl ((uint32_t) flags); | ||
306 | sm->peer = pr->peer; | ||
307 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
308 | "Calling get_message with buffer of %u bytes\n", | ||
309 | (unsigned int) msize); | ||
310 | } | ||
311 | |||
312 | |||
313 | /** | ||
314 | * Handle destruction of a message queue. Implementations must not | ||
315 | * free @a mq, but should take care of @a impl_state. | ||
316 | * | ||
317 | * @param mq the message queue to destroy | ||
318 | * @param impl_state state of the implementation | ||
319 | */ | ||
320 | static void | ||
321 | core_mq_destroy_impl (struct GNUNET_MQ_Handle *mq, void *impl_state) | ||
322 | { | ||
323 | struct PeerRecord *pr = impl_state; | ||
324 | |||
325 | GNUNET_assert (mq == pr->mq); | ||
326 | pr->mq = NULL; | ||
327 | } | ||
328 | |||
329 | |||
330 | /** | ||
331 | * Implementation function that cancels the currently sent message. | ||
332 | * Should basically undo whatever #mq_send_impl() did. | ||
333 | * | ||
334 | * @param mq message queue | ||
335 | * @param impl_state state specific to the implementation | ||
336 | */ | ||
337 | static void | ||
338 | core_mq_cancel_impl (struct GNUNET_MQ_Handle *mq, void *impl_state) | ||
339 | { | ||
340 | struct PeerRecord *pr = impl_state; | ||
341 | |||
342 | (void) mq; | ||
343 | GNUNET_assert (NULL != pr->env); | ||
344 | GNUNET_MQ_discard (pr->env); | ||
345 | pr->env = NULL; | ||
346 | } | ||
347 | |||
348 | |||
349 | /** | ||
350 | * We had an error processing a message we forwarded from a peer to | ||
351 | * the CORE service. We should just complain about it but otherwise | ||
352 | * continue processing. | ||
353 | * | ||
354 | * @param cls closure | ||
355 | * @param error error code | ||
356 | */ | ||
357 | static void | ||
358 | core_mq_error_handler (void *cls, enum GNUNET_MQ_Error error) | ||
359 | { | ||
360 | /* struct PeerRecord *pr = cls; */ | ||
361 | (void) cls; | ||
362 | (void) error; | ||
363 | GNUNET_break_op (0); | ||
364 | } | ||
365 | |||
366 | |||
367 | /** | ||
368 | * Add the given peer to the list of our connected peers | ||
369 | * and create the respective data structures and notify | ||
370 | * the application. | ||
371 | * | ||
372 | * @param h the core handle | ||
373 | * @param peer the peer that is connecting to us | ||
374 | */ | ||
375 | static void | ||
376 | connect_peer (struct GNUNET_CORE_Handle *h, | ||
377 | const struct GNUNET_PeerIdentity *peer) | ||
378 | { | ||
379 | struct PeerRecord *pr; | ||
380 | |||
381 | pr = GNUNET_new (struct PeerRecord); | ||
382 | pr->peer = *peer; | ||
383 | pr->h = h; | ||
384 | GNUNET_assert (GNUNET_YES == | ||
385 | GNUNET_CONTAINER_multipeermap_put ( | ||
386 | h->peers, | ||
387 | &pr->peer, | ||
388 | pr, | ||
389 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
390 | pr->mq = GNUNET_MQ_queue_for_callbacks (&core_mq_send_impl, | ||
391 | &core_mq_destroy_impl, | ||
392 | &core_mq_cancel_impl, | ||
393 | pr, | ||
394 | h->handlers, | ||
395 | &core_mq_error_handler, | ||
396 | pr); | ||
397 | if (NULL != h->connects) | ||
398 | { | ||
399 | pr->client_cls = h->connects (h->cls, &pr->peer, pr->mq); | ||
400 | GNUNET_MQ_set_handlers_closure (pr->mq, pr->client_cls); | ||
401 | } | ||
402 | } | ||
403 | |||
404 | |||
405 | /** | ||
406 | * Handle init reply message received from CORE service. Notify | ||
407 | * application that we are now connected to the CORE. Also fake | ||
408 | * loopback connection. | ||
409 | * | ||
410 | * @param cls the `struct GNUNET_CORE_Handle` | ||
411 | * @param m the init reply | ||
412 | */ | ||
413 | static void | ||
414 | handle_init_reply (void *cls, const struct InitReplyMessage *m) | ||
415 | { | ||
416 | struct GNUNET_CORE_Handle *h = cls; | ||
417 | GNUNET_CORE_StartupCallback init; | ||
418 | |||
419 | GNUNET_break (0 == ntohl (m->reserved)); | ||
420 | h->retry_backoff = GNUNET_TIME_UNIT_MILLISECONDS; | ||
421 | if (NULL != (init = h->init)) | ||
422 | { | ||
423 | /* mark so we don't call init on reconnect */ | ||
424 | h->init = NULL; | ||
425 | h->me = m->my_identity; | ||
426 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
427 | "Connected to core service of peer `%s'.\n", | ||
428 | GNUNET_i2s (&h->me)); | ||
429 | h->have_init = GNUNET_YES; | ||
430 | init (h->cls, &h->me); | ||
431 | } | ||
432 | else | ||
433 | { | ||
434 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
435 | "Successfully reconnected to core service.\n"); | ||
436 | if (GNUNET_NO == h->have_init) | ||
437 | { | ||
438 | h->me = m->my_identity; | ||
439 | h->have_init = GNUNET_YES; | ||
440 | } | ||
441 | else | ||
442 | { | ||
443 | GNUNET_break (0 == memcmp (&h->me, | ||
444 | &m->my_identity, | ||
445 | sizeof(struct GNUNET_PeerIdentity))); | ||
446 | } | ||
447 | } | ||
448 | /* fake 'connect to self' */ | ||
449 | connect_peer (h, &h->me); | ||
450 | } | ||
451 | |||
452 | |||
453 | /** | ||
454 | * Handle connect message received from CORE service. | ||
455 | * Notify the application about the new connection. | ||
456 | * | ||
457 | * @param cls the `struct GNUNET_CORE_Handle` | ||
458 | * @param cnm the connect message | ||
459 | */ | ||
460 | static void | ||
461 | handle_connect_notify (void *cls, const struct ConnectNotifyMessage *cnm) | ||
462 | { | ||
463 | struct GNUNET_CORE_Handle *h = cls; | ||
464 | struct PeerRecord *pr; | ||
465 | |||
466 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
467 | "Received notification about connection from `%s'.\n", | ||
468 | GNUNET_i2s (&cnm->peer)); | ||
469 | if (0 == memcmp (&h->me, &cnm->peer, sizeof(struct GNUNET_PeerIdentity))) | ||
470 | { | ||
471 | /* connect to self!? */ | ||
472 | GNUNET_break (0); | ||
473 | return; | ||
474 | } | ||
475 | pr = GNUNET_CONTAINER_multipeermap_get (h->peers, &cnm->peer); | ||
476 | if (NULL != pr) | ||
477 | { | ||
478 | GNUNET_break (0); | ||
479 | reconnect_later (h); | ||
480 | return; | ||
481 | } | ||
482 | connect_peer (h, &cnm->peer); | ||
483 | } | ||
484 | |||
485 | |||
486 | /** | ||
487 | * Handle disconnect message received from CORE service. | ||
488 | * Notify the application about the lost connection. | ||
489 | * | ||
490 | * @param cls the `struct GNUNET_CORE_Handle` | ||
491 | * @param dnm message about the disconnect event | ||
492 | */ | ||
493 | static void | ||
494 | handle_disconnect_notify (void *cls, const struct DisconnectNotifyMessage *dnm) | ||
495 | { | ||
496 | struct GNUNET_CORE_Handle *h = cls; | ||
497 | struct PeerRecord *pr; | ||
498 | |||
499 | if (0 == memcmp (&h->me, &dnm->peer, sizeof(struct GNUNET_PeerIdentity))) | ||
500 | { | ||
501 | /* disconnect from self!? */ | ||
502 | GNUNET_break (0); | ||
503 | return; | ||
504 | } | ||
505 | GNUNET_break (0 == ntohl (dnm->reserved)); | ||
506 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
507 | "Received notification about disconnect from `%s'.\n", | ||
508 | GNUNET_i2s (&dnm->peer)); | ||
509 | pr = GNUNET_CONTAINER_multipeermap_get (h->peers, &dnm->peer); | ||
510 | if (NULL == pr) | ||
511 | { | ||
512 | GNUNET_break (0); | ||
513 | reconnect_later (h); | ||
514 | return; | ||
515 | } | ||
516 | disconnect_and_free_peer_entry (h, &pr->peer, pr); | ||
517 | } | ||
518 | |||
519 | |||
520 | /** | ||
521 | * Check that message received from CORE service is well-formed. | ||
522 | * | ||
523 | * @param cls the `struct GNUNET_CORE_Handle` | ||
524 | * @param ntm the message we got | ||
525 | * @return #GNUNET_OK if the message is well-formed | ||
526 | */ | ||
527 | static int | ||
528 | check_notify_inbound (void *cls, const struct NotifyTrafficMessage *ntm) | ||
529 | { | ||
530 | uint16_t msize; | ||
531 | const struct GNUNET_MessageHeader *em; | ||
532 | |||
533 | (void) cls; | ||
534 | msize = ntohs (ntm->header.size) - sizeof(struct NotifyTrafficMessage); | ||
535 | if (msize < sizeof(struct GNUNET_MessageHeader)) | ||
536 | { | ||
537 | GNUNET_break (0); | ||
538 | return GNUNET_SYSERR; | ||
539 | } | ||
540 | em = (const struct GNUNET_MessageHeader *) &ntm[1]; | ||
541 | if (msize != ntohs (em->size)) | ||
542 | { | ||
543 | GNUNET_break (0); | ||
544 | return GNUNET_SYSERR; | ||
545 | } | ||
546 | return GNUNET_OK; | ||
547 | } | ||
548 | |||
549 | |||
550 | /** | ||
551 | * Handle inbound message received from CORE service. If applicable, | ||
552 | * notify the application. | ||
553 | * | ||
554 | * @param cls the `struct GNUNET_CORE_Handle` | ||
555 | * @param ntm the message we got from CORE. | ||
556 | */ | ||
557 | static void | ||
558 | handle_notify_inbound (void *cls, const struct NotifyTrafficMessage *ntm) | ||
559 | { | ||
560 | struct GNUNET_CORE_Handle *h = cls; | ||
561 | const struct GNUNET_MessageHeader *em; | ||
562 | struct PeerRecord *pr; | ||
563 | |||
564 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
565 | "Received inbound message from `%s'.\n", | ||
566 | GNUNET_i2s (&ntm->peer)); | ||
567 | em = (const struct GNUNET_MessageHeader *) &ntm[1]; | ||
568 | pr = GNUNET_CONTAINER_multipeermap_get (h->peers, &ntm->peer); | ||
569 | if (NULL == pr) | ||
570 | { | ||
571 | GNUNET_break (0); | ||
572 | reconnect_later (h); | ||
573 | return; | ||
574 | } | ||
575 | GNUNET_MQ_inject_message (pr->mq, em); | ||
576 | } | ||
577 | |||
578 | |||
579 | /** | ||
580 | * Handle message received from CORE service notifying us that we are | ||
581 | * now allowed to send a message to a peer. If that message is still | ||
582 | * pending, put it into the queue to be transmitted. | ||
583 | * | ||
584 | * @param cls the `struct GNUNET_CORE_Handle` | ||
585 | * @param smr the message we got | ||
586 | */ | ||
587 | static void | ||
588 | handle_send_ready (void *cls, const struct SendMessageReady *smr) | ||
589 | { | ||
590 | struct GNUNET_CORE_Handle *h = cls; | ||
591 | struct PeerRecord *pr; | ||
592 | |||
593 | pr = GNUNET_CONTAINER_multipeermap_get (h->peers, &smr->peer); | ||
594 | if (NULL == pr) | ||
595 | { | ||
596 | GNUNET_break (0); | ||
597 | reconnect_later (h); | ||
598 | return; | ||
599 | } | ||
600 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
601 | "Received notification about transmission readiness to `%s'.\n", | ||
602 | GNUNET_i2s (&smr->peer)); | ||
603 | if (NULL == pr->env) | ||
604 | { | ||
605 | /* request must have been cancelled between the original request | ||
606 | * and the response from CORE, ignore CORE's readiness */ | ||
607 | return; | ||
608 | } | ||
609 | if (ntohs (smr->smr_id) != pr->smr_id_gen) | ||
610 | { | ||
611 | /* READY message is for expired or cancelled message, | ||
612 | * ignore! (we should have already sent another request) */ | ||
613 | return; | ||
614 | } | ||
615 | |||
616 | /* ok, all good, send message out! */ | ||
617 | GNUNET_MQ_send (h->mq, pr->env); | ||
618 | pr->env = NULL; | ||
619 | GNUNET_MQ_impl_send_continue (pr->mq); | ||
620 | } | ||
621 | |||
622 | |||
623 | /** | ||
624 | * Our current client connection went down. Clean it up and try to | ||
625 | * reconnect! | ||
626 | * | ||
627 | * @param h our handle to the core service | ||
628 | */ | ||
629 | static void | ||
630 | reconnect (struct GNUNET_CORE_Handle *h) | ||
631 | { | ||
632 | struct GNUNET_MQ_MessageHandler handlers[] = | ||
633 | { GNUNET_MQ_hd_fixed_size (init_reply, | ||
634 | GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY, | ||
635 | struct InitReplyMessage, | ||
636 | h), | ||
637 | GNUNET_MQ_hd_fixed_size (connect_notify, | ||
638 | GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT, | ||
639 | struct ConnectNotifyMessage, | ||
640 | h), | ||
641 | GNUNET_MQ_hd_fixed_size (disconnect_notify, | ||
642 | GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT, | ||
643 | struct DisconnectNotifyMessage, | ||
644 | h), | ||
645 | GNUNET_MQ_hd_var_size (notify_inbound, | ||
646 | GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND, | ||
647 | struct NotifyTrafficMessage, | ||
648 | h), | ||
649 | GNUNET_MQ_hd_fixed_size (send_ready, | ||
650 | GNUNET_MESSAGE_TYPE_CORE_SEND_READY, | ||
651 | struct SendMessageReady, | ||
652 | h), | ||
653 | GNUNET_MQ_handler_end () }; | ||
654 | struct InitMessage *init; | ||
655 | struct GNUNET_MQ_Envelope *env; | ||
656 | uint16_t *ts; | ||
657 | |||
658 | GNUNET_assert (NULL == h->mq); | ||
659 | h->mq = GNUNET_CLIENT_connect (h->cfg, "core", handlers, &handle_mq_error, h); | ||
660 | if (NULL == h->mq) | ||
661 | { | ||
662 | reconnect_later (h); | ||
663 | return; | ||
664 | } | ||
665 | env = GNUNET_MQ_msg_extra (init, | ||
666 | sizeof(uint16_t) * h->hcnt, | ||
667 | GNUNET_MESSAGE_TYPE_CORE_INIT); | ||
668 | LOG (GNUNET_ERROR_TYPE_INFO, "(Re)connecting to CORE service\n"); | ||
669 | init->options = htonl (0); | ||
670 | ts = (uint16_t *) &init[1]; | ||
671 | for (unsigned int hpos = 0; hpos < h->hcnt; hpos++) | ||
672 | ts[hpos] = htons (h->handlers[hpos].type); | ||
673 | GNUNET_MQ_send (h->mq, env); | ||
674 | } | ||
675 | |||
676 | |||
677 | /** | ||
678 | * Connect to the core service. Note that the connection may complete | ||
679 | * (or fail) asynchronously. | ||
680 | * | ||
681 | * @param cfg configuration to use | ||
682 | * @param cls closure for the various callbacks that follow (including handlers in the handlers array) | ||
683 | * @param init callback to call once we have successfully | ||
684 | * connected to the core service | ||
685 | * @param connects function to call on peer connect, can be NULL | ||
686 | * @param disconnects function to call on peer disconnect / timeout, can be NULL | ||
687 | * @param handlers callbacks for messages we care about, NULL-terminated | ||
688 | * @return handle to the core service (only useful for disconnect until @a init is called); | ||
689 | * NULL on error (in this case, init is never called) | ||
690 | */ | ||
691 | struct GNUNET_CORE_Handle * | ||
692 | GNUNET_CORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
693 | void *cls, | ||
694 | GNUNET_CORE_StartupCallback init, | ||
695 | GNUNET_CORE_ConnectEventHandler connects, | ||
696 | GNUNET_CORE_DisconnectEventHandler disconnects, | ||
697 | const struct GNUNET_MQ_MessageHandler *handlers) | ||
698 | { | ||
699 | struct GNUNET_CORE_Handle *h; | ||
700 | |||
701 | h = GNUNET_new (struct GNUNET_CORE_Handle); | ||
702 | h->cfg = cfg; | ||
703 | h->cls = cls; | ||
704 | h->init = init; | ||
705 | h->connects = connects; | ||
706 | h->disconnects = disconnects; | ||
707 | h->peers = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_NO); | ||
708 | h->handlers = GNUNET_MQ_copy_handlers (handlers); | ||
709 | h->hcnt = GNUNET_MQ_count_handlers (handlers); | ||
710 | GNUNET_assert (h->hcnt < | ||
711 | (GNUNET_MAX_MESSAGE_SIZE - sizeof(struct InitMessage)) | ||
712 | / sizeof(uint16_t)); | ||
713 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to CORE service\n"); | ||
714 | reconnect (h); | ||
715 | if (NULL == h->mq) | ||
716 | { | ||
717 | GNUNET_CORE_disconnect (h); | ||
718 | return NULL; | ||
719 | } | ||
720 | return h; | ||
721 | } | ||
722 | |||
723 | |||
724 | /** | ||
725 | * Disconnect from the core service. | ||
726 | * | ||
727 | * @param handle connection to core to disconnect | ||
728 | */ | ||
729 | void | ||
730 | GNUNET_CORE_disconnect (struct GNUNET_CORE_Handle *handle) | ||
731 | { | ||
732 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from CORE service\n"); | ||
733 | GNUNET_CONTAINER_multipeermap_iterate (handle->peers, | ||
734 | &disconnect_and_free_peer_entry, | ||
735 | handle); | ||
736 | GNUNET_CONTAINER_multipeermap_destroy (handle->peers); | ||
737 | handle->peers = NULL; | ||
738 | if (NULL != handle->reconnect_task) | ||
739 | { | ||
740 | GNUNET_SCHEDULER_cancel (handle->reconnect_task); | ||
741 | handle->reconnect_task = NULL; | ||
742 | } | ||
743 | if (NULL != handle->mq) | ||
744 | { | ||
745 | GNUNET_MQ_destroy (handle->mq); | ||
746 | handle->mq = NULL; | ||
747 | } | ||
748 | GNUNET_free (handle->handlers); | ||
749 | GNUNET_free (handle); | ||
750 | } | ||
751 | |||
752 | |||
753 | /** | ||
754 | * Obtain the message queue for a connected peer. | ||
755 | * | ||
756 | * @param h the core handle | ||
757 | * @param pid the identity of the peer to check if it has been connected to us | ||
758 | * @return NULL if peer is not connected | ||
759 | */ | ||
760 | struct GNUNET_MQ_Handle * | ||
761 | GNUNET_CORE_get_mq (const struct GNUNET_CORE_Handle *h, | ||
762 | const struct GNUNET_PeerIdentity *pid) | ||
763 | { | ||
764 | struct PeerRecord *pr; | ||
765 | |||
766 | pr = GNUNET_CONTAINER_multipeermap_get (h->peers, pid); | ||
767 | if (NULL == pr) | ||
768 | return NULL; | ||
769 | return pr->mq; | ||
770 | } | ||
771 | |||
772 | |||
773 | /* end of core_api.c */ | ||