diff options
author | Tobias Platen <tplaten@posteo.de> | 2022-07-20 20:26:59 +0200 |
---|---|---|
committer | Tobias Platen <tplaten@posteo.de> | 2022-07-20 20:26:59 +0200 |
commit | 12db287bf58f2076a65bc34382ce07ec9fe76e38 (patch) | |
tree | 89ae191a5c25c701f5fd734f738ac25f7561bdba /src/multicast/gnunet-service-multicast.c | |
parent | 6a60c7d436f5c4c47752ee54a0980583f0c3fe37 (diff) | |
download | gnunet-dev/tplaten/multicast_messenger.tar.gz gnunet-dev/tplaten/multicast_messenger.zip |
inital import of multicast from secusharedev/tplaten/multicast_messenger
Diffstat (limited to 'src/multicast/gnunet-service-multicast.c')
-rw-r--r-- | src/multicast/gnunet-service-multicast.c | 2236 |
1 files changed, 2236 insertions, 0 deletions
diff --git a/src/multicast/gnunet-service-multicast.c b/src/multicast/gnunet-service-multicast.c new file mode 100644 index 000000000..236a7c8cd --- /dev/null +++ b/src/multicast/gnunet-service-multicast.c | |||
@@ -0,0 +1,2236 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009 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 multicast/gnunet-service-multicast.c | ||
23 | * @brief program that does multicast | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | |||
27 | #include "platform.h" | ||
28 | #include "gnunet_util_lib.h" | ||
29 | #include "gnunet_signatures.h" | ||
30 | #include "gnunet_util_lib.h" | ||
31 | #include "gnunet_signatures.h" | ||
32 | #include "gnunet_applications.h" | ||
33 | #include "gnunet_statistics_service.h" | ||
34 | #include "gnunet_cadet_service.h" | ||
35 | #include "gnunet_multicast_service.h" | ||
36 | #include "multicast.h" | ||
37 | |||
38 | /** | ||
39 | * Handle to our current configuration. | ||
40 | */ | ||
41 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
42 | |||
43 | /** | ||
44 | * Service handle. | ||
45 | */ | ||
46 | static struct GNUNET_SERVICE_Handle *service; | ||
47 | |||
48 | /** | ||
49 | * CADET handle. | ||
50 | */ | ||
51 | static struct GNUNET_CADET_Handle *cadet; | ||
52 | |||
53 | /** | ||
54 | * Identity of this peer. | ||
55 | */ | ||
56 | static struct GNUNET_PeerIdentity this_peer; | ||
57 | |||
58 | /** | ||
59 | * Handle to the statistics service. | ||
60 | */ | ||
61 | static struct GNUNET_STATISTICS_Handle *stats; | ||
62 | |||
63 | /** | ||
64 | * All connected origin clients. | ||
65 | * Group's pub_key_hash -> struct Origin * (uniq) | ||
66 | */ | ||
67 | static struct GNUNET_CONTAINER_MultiHashMap *origins; | ||
68 | |||
69 | /** | ||
70 | * All connected member clients. | ||
71 | * Group's pub_key_hash -> struct Member * (multi) | ||
72 | */ | ||
73 | static struct GNUNET_CONTAINER_MultiHashMap *members; | ||
74 | |||
75 | /** | ||
76 | * Connected member clients per group. | ||
77 | * Group's pub_key_hash -> Member's pub_key_hash (uniq) -> struct Member * (uniq) | ||
78 | */ | ||
79 | static struct GNUNET_CONTAINER_MultiHashMap *group_members; | ||
80 | |||
81 | /** | ||
82 | * Incoming CADET channels with connected children in the tree. | ||
83 | * Group's pub_key_hash -> struct Channel * (multi) | ||
84 | */ | ||
85 | static struct GNUNET_CONTAINER_MultiHashMap *channels_in; | ||
86 | |||
87 | /** | ||
88 | * Outgoing CADET channels connecting to parents in the tree. | ||
89 | * Group's pub_key_hash -> struct Channel * (multi) | ||
90 | */ | ||
91 | static struct GNUNET_CONTAINER_MultiHashMap *channels_out; | ||
92 | |||
93 | /** | ||
94 | * Incoming replay requests from CADET. | ||
95 | * Group's pub_key_hash -> | ||
96 | * H(fragment_id, message_id, fragment_offset, flags) -> struct Channel * | ||
97 | */ | ||
98 | static struct GNUNET_CONTAINER_MultiHashMap *replay_req_cadet; | ||
99 | |||
100 | /** | ||
101 | * Incoming replay requests from clients. | ||
102 | * Group's pub_key_hash -> | ||
103 | * H(fragment_id, message_id, fragment_offset, flags) -> struct GNUNET_SERVICE_Client * | ||
104 | */ | ||
105 | static struct GNUNET_CONTAINER_MultiHashMap *replay_req_client; | ||
106 | |||
107 | |||
108 | /** | ||
109 | * Join status of a remote peer. | ||
110 | */ | ||
111 | enum JoinStatus | ||
112 | { | ||
113 | JOIN_REFUSED = -1, | ||
114 | JOIN_NOT_ASKED = 0, | ||
115 | JOIN_WAITING = 1, | ||
116 | JOIN_ADMITTED = 2, | ||
117 | }; | ||
118 | |||
119 | enum ChannelDirection | ||
120 | { | ||
121 | DIR_INCOMING = 0, | ||
122 | DIR_OUTGOING = 1, | ||
123 | }; | ||
124 | |||
125 | |||
126 | /** | ||
127 | * Context for a CADET channel. | ||
128 | */ | ||
129 | struct Channel | ||
130 | { | ||
131 | /** | ||
132 | * Group the channel belongs to. | ||
133 | * | ||
134 | * Only set for outgoing channels. | ||
135 | */ | ||
136 | struct Group *group; | ||
137 | |||
138 | /** | ||
139 | * CADET channel. | ||
140 | */ | ||
141 | struct GNUNET_CADET_Channel *channel; | ||
142 | |||
143 | // FIXME: not used | ||
144 | /** | ||
145 | * CADET transmission handle. | ||
146 | */ | ||
147 | struct GNUNET_CADET_TransmitHandle *tmit_handle; | ||
148 | |||
149 | /** | ||
150 | * Public key of the target group. | ||
151 | */ | ||
152 | struct GNUNET_CRYPTO_EddsaPublicKey group_pub_key; | ||
153 | |||
154 | /** | ||
155 | * Hash of @a group_pub_key. | ||
156 | */ | ||
157 | struct GNUNET_HashCode group_pub_hash; | ||
158 | |||
159 | /** | ||
160 | * Public key of the joining member. | ||
161 | */ | ||
162 | struct GNUNET_CRYPTO_EcdsaPublicKey member_pub_key; | ||
163 | |||
164 | /** | ||
165 | * Remote peer identity. | ||
166 | */ | ||
167 | struct GNUNET_PeerIdentity peer; | ||
168 | |||
169 | /** | ||
170 | * Current window size, set by cadet_notify_window_change() | ||
171 | */ | ||
172 | int32_t window_size; | ||
173 | |||
174 | /** | ||
175 | * Is the connection established? | ||
176 | */ | ||
177 | int8_t is_connected; | ||
178 | |||
179 | /** | ||
180 | * Is the remote peer admitted to the group? | ||
181 | * @see enum JoinStatus | ||
182 | */ | ||
183 | int8_t join_status; | ||
184 | |||
185 | /** | ||
186 | * Number of messages waiting to be sent to CADET. | ||
187 | */ | ||
188 | uint8_t msgs_pending; | ||
189 | |||
190 | /** | ||
191 | * Channel direction. | ||
192 | * @see enum ChannelDirection | ||
193 | */ | ||
194 | uint8_t direction; | ||
195 | }; | ||
196 | |||
197 | |||
198 | /** | ||
199 | * List of connected clients. | ||
200 | */ | ||
201 | struct ClientList | ||
202 | { | ||
203 | struct ClientList *prev; | ||
204 | struct ClientList *next; | ||
205 | struct GNUNET_SERVICE_Client *client; | ||
206 | }; | ||
207 | |||
208 | |||
209 | /** | ||
210 | * Client context for an origin or member. | ||
211 | */ | ||
212 | struct Group | ||
213 | { | ||
214 | struct ClientList *clients_head; | ||
215 | struct ClientList *clients_tail; | ||
216 | |||
217 | /** | ||
218 | * Public key of the group. | ||
219 | */ | ||
220 | struct GNUNET_CRYPTO_EddsaPublicKey pub_key; | ||
221 | |||
222 | /** | ||
223 | * Hash of @a pub_key. | ||
224 | */ | ||
225 | struct GNUNET_HashCode pub_key_hash; | ||
226 | |||
227 | /** | ||
228 | * CADET port hash. | ||
229 | */ | ||
230 | struct GNUNET_HashCode cadet_port_hash; | ||
231 | |||
232 | /** | ||
233 | * Is the client disconnected? #GNUNET_YES or #GNUNET_NO | ||
234 | */ | ||
235 | uint8_t is_disconnected; | ||
236 | |||
237 | /** | ||
238 | * Is this an origin (#GNUNET_YES), or member (#GNUNET_NO)? | ||
239 | */ | ||
240 | uint8_t is_origin; | ||
241 | |||
242 | union { | ||
243 | struct Origin *origin; | ||
244 | struct Member *member; | ||
245 | }; | ||
246 | }; | ||
247 | |||
248 | |||
249 | /** | ||
250 | * Client context for a group's origin. | ||
251 | */ | ||
252 | struct Origin | ||
253 | { | ||
254 | struct Group group; | ||
255 | |||
256 | /** | ||
257 | * Private key of the group. | ||
258 | */ | ||
259 | struct GNUNET_CRYPTO_EddsaPrivateKey priv_key; | ||
260 | |||
261 | /** | ||
262 | * CADET port. | ||
263 | */ | ||
264 | struct GNUNET_CADET_Port *cadet_port; | ||
265 | |||
266 | /** | ||
267 | * Last message fragment ID sent to the group. | ||
268 | */ | ||
269 | uint64_t max_fragment_id; | ||
270 | }; | ||
271 | |||
272 | |||
273 | /** | ||
274 | * Client context for a group member. | ||
275 | */ | ||
276 | struct Member | ||
277 | { | ||
278 | struct Group group; | ||
279 | |||
280 | /** | ||
281 | * Private key of the member. | ||
282 | */ | ||
283 | struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key; | ||
284 | |||
285 | /** | ||
286 | * Public key of the member. | ||
287 | */ | ||
288 | struct GNUNET_CRYPTO_EcdsaPublicKey pub_key; | ||
289 | |||
290 | /** | ||
291 | * Hash of @a pub_key. | ||
292 | */ | ||
293 | struct GNUNET_HashCode pub_key_hash; | ||
294 | |||
295 | /** | ||
296 | * Join request sent to the origin / members. | ||
297 | */ | ||
298 | struct MulticastJoinRequestMessage *join_req; | ||
299 | |||
300 | /** | ||
301 | * Join decision sent in reply to our request. | ||
302 | * | ||
303 | * Only a positive decision is stored here, in case of a negative decision the | ||
304 | * client is disconnected. | ||
305 | */ | ||
306 | struct MulticastJoinDecisionMessageHeader *join_dcsn; | ||
307 | |||
308 | /** | ||
309 | * CADET channel to the origin. | ||
310 | */ | ||
311 | struct Channel *origin_channel; | ||
312 | |||
313 | /** | ||
314 | * Peer identity of origin. | ||
315 | */ | ||
316 | struct GNUNET_PeerIdentity origin; | ||
317 | |||
318 | /** | ||
319 | * Peer identity of relays (other members to connect). | ||
320 | */ | ||
321 | struct GNUNET_PeerIdentity *relays; | ||
322 | |||
323 | /** | ||
324 | * Last request fragment ID sent to the origin. | ||
325 | */ | ||
326 | uint64_t max_fragment_id; | ||
327 | |||
328 | /** | ||
329 | * Number of @a relays. | ||
330 | */ | ||
331 | uint32_t relay_count; | ||
332 | }; | ||
333 | |||
334 | |||
335 | /** | ||
336 | * Client context. | ||
337 | */ | ||
338 | struct Client { | ||
339 | struct GNUNET_SERVICE_Client *client; | ||
340 | struct Group *group; | ||
341 | }; | ||
342 | |||
343 | |||
344 | struct ReplayRequestKey | ||
345 | { | ||
346 | uint64_t fragment_id; | ||
347 | uint64_t message_id; | ||
348 | uint64_t fragment_offset; | ||
349 | uint64_t flags; | ||
350 | }; | ||
351 | |||
352 | |||
353 | static struct Channel * | ||
354 | cadet_channel_create (struct Group *grp, struct GNUNET_PeerIdentity *peer); | ||
355 | |||
356 | static void | ||
357 | cadet_channel_destroy (struct Channel *chn); | ||
358 | |||
359 | static void | ||
360 | client_send_join_decision (struct Member *mem, | ||
361 | const struct MulticastJoinDecisionMessageHeader *hdcsn); | ||
362 | |||
363 | |||
364 | /** | ||
365 | * Task run during shutdown. | ||
366 | * | ||
367 | * @param cls unused | ||
368 | */ | ||
369 | static void | ||
370 | shutdown_task (void *cls) | ||
371 | { | ||
372 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
373 | "shutting down\n"); | ||
374 | if (NULL != cadet) | ||
375 | { | ||
376 | GNUNET_CADET_disconnect (cadet); | ||
377 | cadet = NULL; | ||
378 | } | ||
379 | if (NULL != stats) | ||
380 | { | ||
381 | GNUNET_STATISTICS_destroy (stats, GNUNET_YES); | ||
382 | stats = NULL; | ||
383 | } | ||
384 | /* FIXME: do more clean up here */ | ||
385 | } | ||
386 | |||
387 | |||
388 | /** | ||
389 | * Clean up origin data structures after a client disconnected. | ||
390 | */ | ||
391 | static void | ||
392 | cleanup_origin (struct Origin *orig) | ||
393 | { | ||
394 | struct Group *grp = &orig->group; | ||
395 | GNUNET_CONTAINER_multihashmap_remove (origins, &grp->pub_key_hash, orig); | ||
396 | if (NULL != orig->cadet_port) | ||
397 | { | ||
398 | GNUNET_CADET_close_port (orig->cadet_port); | ||
399 | orig->cadet_port = NULL; | ||
400 | } | ||
401 | GNUNET_free (orig); | ||
402 | } | ||
403 | |||
404 | |||
405 | /** | ||
406 | * Clean up member data structures after a client disconnected. | ||
407 | */ | ||
408 | static void | ||
409 | cleanup_member (struct Member *mem) | ||
410 | { | ||
411 | struct Group *grp = &mem->group; | ||
412 | struct GNUNET_CONTAINER_MultiHashMap * | ||
413 | grp_mem = GNUNET_CONTAINER_multihashmap_get (group_members, | ||
414 | &grp->pub_key_hash); | ||
415 | GNUNET_assert (NULL != grp_mem); | ||
416 | GNUNET_CONTAINER_multihashmap_remove (grp_mem, &mem->pub_key_hash, mem); | ||
417 | |||
418 | if (0 == GNUNET_CONTAINER_multihashmap_size (grp_mem)) | ||
419 | { | ||
420 | GNUNET_CONTAINER_multihashmap_remove (group_members, &grp->pub_key_hash, | ||
421 | grp_mem); | ||
422 | GNUNET_CONTAINER_multihashmap_destroy (grp_mem); | ||
423 | } | ||
424 | if (NULL != mem->join_dcsn) | ||
425 | { | ||
426 | GNUNET_free (mem->join_dcsn); | ||
427 | mem->join_dcsn = NULL; | ||
428 | } | ||
429 | if (NULL != mem->origin_channel) | ||
430 | { | ||
431 | GNUNET_CADET_channel_destroy (mem->origin_channel->channel); | ||
432 | mem->origin_channel = NULL; | ||
433 | } | ||
434 | GNUNET_CONTAINER_multihashmap_remove (members, &grp->pub_key_hash, mem); | ||
435 | GNUNET_free (mem); | ||
436 | } | ||
437 | |||
438 | |||
439 | /** | ||
440 | * Clean up group data structures after a client disconnected. | ||
441 | */ | ||
442 | static void | ||
443 | cleanup_group (struct Group *grp) | ||
444 | { | ||
445 | (GNUNET_YES == grp->is_origin) | ||
446 | ? cleanup_origin (grp->origin) | ||
447 | : cleanup_member (grp->member); | ||
448 | } | ||
449 | |||
450 | |||
451 | void | ||
452 | replay_key_hash (uint64_t fragment_id, uint64_t message_id, | ||
453 | uint64_t fragment_offset, uint64_t flags, | ||
454 | struct GNUNET_HashCode *key_hash) | ||
455 | { | ||
456 | struct ReplayRequestKey key = { | ||
457 | .fragment_id = fragment_id, | ||
458 | .message_id = message_id, | ||
459 | .fragment_offset = fragment_offset, | ||
460 | .flags = flags, | ||
461 | }; | ||
462 | GNUNET_CRYPTO_hash (&key, sizeof (key), key_hash); | ||
463 | } | ||
464 | |||
465 | |||
466 | /** | ||
467 | * Remove channel from replay request hashmap. | ||
468 | * | ||
469 | * @param chn | ||
470 | * Channel to remove. | ||
471 | * | ||
472 | * @return #GNUNET_YES if there are more entries to process, | ||
473 | * #GNUNET_NO when reached end of hashmap. | ||
474 | */ | ||
475 | static int | ||
476 | replay_req_remove_cadet (struct Channel *chn) | ||
477 | { | ||
478 | if (NULL == chn || NULL == chn->group) | ||
479 | return GNUNET_SYSERR; | ||
480 | |||
481 | struct GNUNET_CONTAINER_MultiHashMap * | ||
482 | grp_replay_req = GNUNET_CONTAINER_multihashmap_get (replay_req_cadet, | ||
483 | &chn->group->pub_key_hash); | ||
484 | if (NULL == grp_replay_req) | ||
485 | return GNUNET_NO; | ||
486 | |||
487 | struct GNUNET_CONTAINER_MultiHashMapIterator * | ||
488 | it = GNUNET_CONTAINER_multihashmap_iterator_create (grp_replay_req); | ||
489 | struct GNUNET_HashCode key; | ||
490 | const struct Channel *c; | ||
491 | while (GNUNET_YES | ||
492 | == GNUNET_CONTAINER_multihashmap_iterator_next (it, &key, | ||
493 | (const void **) &c)) | ||
494 | { | ||
495 | if (c == chn) | ||
496 | { | ||
497 | GNUNET_CONTAINER_multihashmap_remove (grp_replay_req, &key, chn); | ||
498 | GNUNET_CONTAINER_multihashmap_iterator_destroy (it); | ||
499 | return GNUNET_YES; | ||
500 | } | ||
501 | } | ||
502 | GNUNET_CONTAINER_multihashmap_iterator_destroy (it); | ||
503 | return GNUNET_NO; | ||
504 | } | ||
505 | |||
506 | |||
507 | /** | ||
508 | * Remove client from replay request hashmap. | ||
509 | * | ||
510 | * @param client | ||
511 | * Client to remove. | ||
512 | * | ||
513 | * @return #GNUNET_YES if there are more entries to process, | ||
514 | * #GNUNET_NO when reached end of hashmap. | ||
515 | */ | ||
516 | static int | ||
517 | replay_req_remove_client (struct Group *grp, struct GNUNET_SERVICE_Client *client) | ||
518 | { | ||
519 | struct GNUNET_CONTAINER_MultiHashMap * | ||
520 | grp_replay_req = GNUNET_CONTAINER_multihashmap_get (replay_req_client, | ||
521 | &grp->pub_key_hash); | ||
522 | if (NULL == grp_replay_req) | ||
523 | return GNUNET_NO; | ||
524 | |||
525 | struct GNUNET_CONTAINER_MultiHashMapIterator * | ||
526 | it = GNUNET_CONTAINER_multihashmap_iterator_create (grp_replay_req); | ||
527 | struct GNUNET_HashCode key; | ||
528 | const struct GNUNET_SERVICE_Client *c; | ||
529 | while (GNUNET_YES | ||
530 | == GNUNET_CONTAINER_multihashmap_iterator_next (it, &key, | ||
531 | (const void **) &c)) | ||
532 | { | ||
533 | if (c == client) | ||
534 | { | ||
535 | GNUNET_CONTAINER_multihashmap_remove (grp_replay_req, &key, client); | ||
536 | GNUNET_CONTAINER_multihashmap_iterator_destroy (it); | ||
537 | return GNUNET_YES; | ||
538 | } | ||
539 | } | ||
540 | GNUNET_CONTAINER_multihashmap_iterator_destroy (it); | ||
541 | return GNUNET_NO; | ||
542 | } | ||
543 | |||
544 | |||
545 | /** | ||
546 | * Send message to a client. | ||
547 | */ | ||
548 | static void | ||
549 | client_send (struct GNUNET_SERVICE_Client *client, | ||
550 | const struct GNUNET_MessageHeader *msg) | ||
551 | { | ||
552 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
553 | "%p Sending message to client.\n", client); | ||
554 | |||
555 | struct GNUNET_MQ_Envelope * | ||
556 | env = GNUNET_MQ_msg_copy (msg); | ||
557 | |||
558 | GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), | ||
559 | env); | ||
560 | } | ||
561 | |||
562 | |||
563 | /** | ||
564 | * Send message to all clients connected to the group. | ||
565 | */ | ||
566 | static void | ||
567 | client_send_group_keep_envelope (const struct Group *grp, | ||
568 | struct GNUNET_MQ_Envelope *env) | ||
569 | { | ||
570 | struct ClientList *cli = grp->clients_head; | ||
571 | |||
572 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
573 | "%p Sending message to all clients of the group.\n", | ||
574 | grp); | ||
575 | while (NULL != cli) | ||
576 | { | ||
577 | GNUNET_MQ_send_copy (GNUNET_SERVICE_client_get_mq (cli->client), | ||
578 | env); | ||
579 | cli = cli->next; | ||
580 | } | ||
581 | } | ||
582 | |||
583 | |||
584 | /** | ||
585 | * Send message to all clients connected to the group and | ||
586 | * takes care of freeing @env. | ||
587 | */ | ||
588 | static void | ||
589 | client_send_group (const struct Group *grp, | ||
590 | struct GNUNET_MQ_Envelope *env) | ||
591 | { | ||
592 | client_send_group_keep_envelope (grp, env); | ||
593 | GNUNET_MQ_discard (env); | ||
594 | } | ||
595 | |||
596 | |||
597 | /** | ||
598 | * Iterator callback for sending a message to origin clients. | ||
599 | */ | ||
600 | static int | ||
601 | client_send_origin_cb (void *cls, const struct GNUNET_HashCode *pub_key_hash, | ||
602 | void *origin) | ||
603 | { | ||
604 | struct GNUNET_MQ_Envelope *env = cls; | ||
605 | struct Member *orig = origin; | ||
606 | |||
607 | client_send_group_keep_envelope (&orig->group, env); | ||
608 | return GNUNET_YES; | ||
609 | } | ||
610 | |||
611 | |||
612 | /** | ||
613 | * Iterator callback for sending a message to member clients. | ||
614 | */ | ||
615 | static int | ||
616 | client_send_member_cb (void *cls, const struct GNUNET_HashCode *pub_key_hash, | ||
617 | void *member) | ||
618 | { | ||
619 | struct GNUNET_MQ_Envelope *env = cls; | ||
620 | struct Member *mem = member; | ||
621 | |||
622 | if (NULL != mem->join_dcsn) | ||
623 | { /* Only send message to admitted members */ | ||
624 | client_send_group_keep_envelope (&mem->group, env); | ||
625 | } | ||
626 | return GNUNET_YES; | ||
627 | } | ||
628 | |||
629 | |||
630 | /** | ||
631 | * Send message to all origin and member clients connected to the group. | ||
632 | * | ||
633 | * @param pub_key_hash | ||
634 | * H(key_pub) of the group. | ||
635 | * @param msg | ||
636 | * Message to send. | ||
637 | */ | ||
638 | static int | ||
639 | client_send_all (struct GNUNET_HashCode *pub_key_hash, | ||
640 | struct GNUNET_MQ_Envelope *env) | ||
641 | { | ||
642 | int n = 0; | ||
643 | n += GNUNET_CONTAINER_multihashmap_get_multiple (origins, pub_key_hash, | ||
644 | client_send_origin_cb, | ||
645 | (void *) env); | ||
646 | n += GNUNET_CONTAINER_multihashmap_get_multiple (members, pub_key_hash, | ||
647 | client_send_member_cb, | ||
648 | (void *) env); | ||
649 | GNUNET_MQ_discard (env); | ||
650 | return n; | ||
651 | } | ||
652 | |||
653 | |||
654 | /** | ||
655 | * Send message to a random origin client or a random member client. | ||
656 | * | ||
657 | * @param grp The group to send @a msg to. | ||
658 | * @param msg Message to send. | ||
659 | */ | ||
660 | static int | ||
661 | client_send_random (struct GNUNET_HashCode *pub_key_hash, | ||
662 | struct GNUNET_MQ_Envelope *env) | ||
663 | { | ||
664 | int n = 0; | ||
665 | n = GNUNET_CONTAINER_multihashmap_get_random (origins, client_send_origin_cb, | ||
666 | (void *) env); | ||
667 | if (n <= 0) | ||
668 | n = GNUNET_CONTAINER_multihashmap_get_random (members, client_send_member_cb, | ||
669 | (void *) env); | ||
670 | GNUNET_MQ_discard (env); | ||
671 | return n; | ||
672 | } | ||
673 | |||
674 | |||
675 | /** | ||
676 | * Send message to all origin clients connected to the group. | ||
677 | * | ||
678 | * @param pub_key_hash | ||
679 | * H(key_pub) of the group. | ||
680 | * @param msg | ||
681 | * Message to send. | ||
682 | */ | ||
683 | static int | ||
684 | client_send_origin (struct GNUNET_HashCode *pub_key_hash, | ||
685 | struct GNUNET_MQ_Envelope *env) | ||
686 | { | ||
687 | int n = 0; | ||
688 | n += GNUNET_CONTAINER_multihashmap_get_multiple (origins, pub_key_hash, | ||
689 | client_send_origin_cb, | ||
690 | (void *) env); | ||
691 | return n; | ||
692 | } | ||
693 | |||
694 | |||
695 | /** | ||
696 | * Send fragment acknowledgement to all clients of the channel. | ||
697 | * | ||
698 | * @param pub_key_hash | ||
699 | * H(key_pub) of the group. | ||
700 | */ | ||
701 | static void | ||
702 | client_send_ack (struct GNUNET_HashCode *pub_key_hash) | ||
703 | { | ||
704 | struct GNUNET_MQ_Envelope *env; | ||
705 | |||
706 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
707 | "Sending message ACK to client.\n"); | ||
708 | env = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_MULTICAST_FRAGMENT_ACK); | ||
709 | client_send_all (pub_key_hash, env); | ||
710 | } | ||
711 | |||
712 | |||
713 | struct CadetTransmitClosure | ||
714 | { | ||
715 | struct Channel *chn; | ||
716 | const struct GNUNET_MessageHeader *msg; | ||
717 | }; | ||
718 | |||
719 | |||
720 | /** | ||
721 | * Send a message to a CADET channel. | ||
722 | * | ||
723 | * @param chn Channel. | ||
724 | * @param msg Message. | ||
725 | */ | ||
726 | static void | ||
727 | cadet_send_channel (struct Channel *chn, const struct GNUNET_MessageHeader *msg) | ||
728 | { | ||
729 | struct GNUNET_MQ_Envelope * | ||
730 | env = GNUNET_MQ_msg_copy (msg); | ||
731 | |||
732 | GNUNET_MQ_send (GNUNET_CADET_get_mq (chn->channel), env); | ||
733 | |||
734 | if (0 < chn->window_size) | ||
735 | { | ||
736 | client_send_ack (&chn->group_pub_hash); | ||
737 | } | ||
738 | else | ||
739 | { | ||
740 | chn->msgs_pending++; | ||
741 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
742 | "%p Queuing message. Pending messages: %u\n", | ||
743 | chn, chn->msgs_pending); | ||
744 | } | ||
745 | } | ||
746 | |||
747 | |||
748 | /** | ||
749 | * Create CADET channel and send a join request. | ||
750 | */ | ||
751 | static void | ||
752 | cadet_send_join_request (struct Member *mem) | ||
753 | { | ||
754 | mem->origin_channel = cadet_channel_create (&mem->group, &mem->origin); | ||
755 | cadet_send_channel (mem->origin_channel, &mem->join_req->header); | ||
756 | |||
757 | uint32_t i; | ||
758 | for (i = 0; i < mem->relay_count; i++) | ||
759 | { | ||
760 | struct Channel * | ||
761 | chn = cadet_channel_create (&mem->group, &mem->relays[i]); | ||
762 | cadet_send_channel (chn, &mem->join_req->header); | ||
763 | } | ||
764 | } | ||
765 | |||
766 | |||
767 | static int | ||
768 | cadet_send_join_decision_cb (void *cls, | ||
769 | const struct GNUNET_HashCode *group_pub_hash, | ||
770 | void *channel) | ||
771 | { | ||
772 | const struct MulticastJoinDecisionMessageHeader *hdcsn = cls; | ||
773 | struct Channel *chn = channel; | ||
774 | |||
775 | const struct MulticastJoinDecisionMessage *dcsn = | ||
776 | (struct MulticastJoinDecisionMessage *) &hdcsn[1]; | ||
777 | |||
778 | if (0 == memcmp (&hdcsn->member_pub_key, &chn->member_pub_key, sizeof (chn->member_pub_key)) | ||
779 | && 0 == memcmp (&hdcsn->peer, &chn->peer, sizeof (chn->peer))) | ||
780 | { | ||
781 | if (GNUNET_YES == ntohl (dcsn->is_admitted)) | ||
782 | { | ||
783 | chn->join_status = JOIN_ADMITTED; | ||
784 | } | ||
785 | else | ||
786 | { | ||
787 | chn->join_status = JOIN_REFUSED; | ||
788 | } | ||
789 | cadet_send_channel (chn, &hdcsn->header); | ||
790 | return GNUNET_YES; | ||
791 | } | ||
792 | |||
793 | // return GNUNET_YES to continue the multihashmap_get iteration | ||
794 | return GNUNET_YES; | ||
795 | } | ||
796 | |||
797 | |||
798 | /** | ||
799 | * Send join decision to a remote peer. | ||
800 | */ | ||
801 | static void | ||
802 | cadet_send_join_decision (struct Group *grp, | ||
803 | const struct MulticastJoinDecisionMessageHeader *hdcsn) | ||
804 | { | ||
805 | GNUNET_CONTAINER_multihashmap_get_multiple (channels_in, &grp->pub_key_hash, | ||
806 | &cadet_send_join_decision_cb, | ||
807 | (void *) hdcsn); | ||
808 | } | ||
809 | |||
810 | |||
811 | /** | ||
812 | * Iterator callback for sending a message to origin clients. | ||
813 | */ | ||
814 | static int | ||
815 | cadet_send_cb (void *cls, const struct GNUNET_HashCode *pub_key_hash, | ||
816 | void *channel) | ||
817 | { | ||
818 | const struct GNUNET_MessageHeader *msg = cls; | ||
819 | struct Channel *chn = channel; | ||
820 | if (JOIN_ADMITTED == chn->join_status) | ||
821 | cadet_send_channel (chn, msg); | ||
822 | return GNUNET_YES; | ||
823 | } | ||
824 | |||
825 | |||
826 | /** | ||
827 | * Send message to all connected children. | ||
828 | */ | ||
829 | static int | ||
830 | cadet_send_children (struct GNUNET_HashCode *pub_key_hash, | ||
831 | const struct GNUNET_MessageHeader *msg) | ||
832 | { | ||
833 | int n = 0; | ||
834 | if (channels_in != NULL) | ||
835 | n += GNUNET_CONTAINER_multihashmap_get_multiple (channels_in, pub_key_hash, | ||
836 | cadet_send_cb, (void *) msg); | ||
837 | return n; | ||
838 | } | ||
839 | |||
840 | |||
841 | #if 0 // unused as yet | ||
842 | /** | ||
843 | * Send message to all connected parents. | ||
844 | */ | ||
845 | static int | ||
846 | cadet_send_parents (struct GNUNET_HashCode *pub_key_hash, | ||
847 | const struct GNUNET_MessageHeader *msg) | ||
848 | { | ||
849 | int n = 0; | ||
850 | if (channels_in != NULL) | ||
851 | n += GNUNET_CONTAINER_multihashmap_get_multiple (channels_out, pub_key_hash, | ||
852 | cadet_send_cb, (void *) msg); | ||
853 | return n; | ||
854 | } | ||
855 | #endif | ||
856 | |||
857 | |||
858 | /** | ||
859 | * CADET channel connect handler. | ||
860 | * | ||
861 | * @see GNUNET_CADET_ConnectEventHandler() | ||
862 | */ | ||
863 | static void * | ||
864 | cadet_notify_connect (void *cls, | ||
865 | struct GNUNET_CADET_Channel *channel, | ||
866 | const struct GNUNET_PeerIdentity *source) | ||
867 | { | ||
868 | struct Channel *chn = GNUNET_malloc (sizeof (struct Channel)); | ||
869 | chn->group = cls; | ||
870 | chn->channel = channel; | ||
871 | chn->direction = DIR_INCOMING; | ||
872 | chn->join_status = JOIN_NOT_ASKED; | ||
873 | |||
874 | GNUNET_CONTAINER_multihashmap_put (channels_in, &chn->group->pub_key_hash, chn, | ||
875 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
876 | return chn; | ||
877 | } | ||
878 | |||
879 | |||
880 | /** | ||
881 | * CADET window size change handler. | ||
882 | * | ||
883 | * @see GNUNET_CADET_WindowSizeEventHandler() | ||
884 | */ | ||
885 | static void | ||
886 | cadet_notify_window_change (void *cls, | ||
887 | const struct GNUNET_CADET_Channel *channel, | ||
888 | int window_size) | ||
889 | { | ||
890 | struct Channel *chn = cls; | ||
891 | |||
892 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
893 | "%p Window size changed to %d. Pending messages: %u\n", | ||
894 | chn, window_size, chn->msgs_pending); | ||
895 | |||
896 | chn->is_connected = GNUNET_YES; | ||
897 | chn->window_size = (int32_t) window_size; | ||
898 | |||
899 | for (int i = 0; i < window_size; i++) | ||
900 | { | ||
901 | if (0 < chn->msgs_pending) | ||
902 | { | ||
903 | client_send_ack (&chn->group_pub_hash); | ||
904 | chn->msgs_pending--; | ||
905 | } | ||
906 | else | ||
907 | { | ||
908 | break; | ||
909 | } | ||
910 | } | ||
911 | } | ||
912 | |||
913 | |||
914 | /** | ||
915 | * CADET channel disconnect handler. | ||
916 | * | ||
917 | * @see GNUNET_CADET_DisconnectEventHandler() | ||
918 | */ | ||
919 | static void | ||
920 | cadet_notify_disconnect (void *cls, | ||
921 | const struct GNUNET_CADET_Channel *channel) | ||
922 | { | ||
923 | if (NULL == cls) | ||
924 | return; | ||
925 | |||
926 | struct Channel *chn = cls; | ||
927 | if (NULL != chn->group) | ||
928 | { | ||
929 | if (GNUNET_NO == chn->group->is_origin) | ||
930 | { | ||
931 | struct Member *mem = (struct Member *) chn->group; | ||
932 | if (chn == mem->origin_channel) | ||
933 | mem->origin_channel = NULL; | ||
934 | } | ||
935 | } | ||
936 | |||
937 | int ret; | ||
938 | do | ||
939 | { | ||
940 | ret = replay_req_remove_cadet (chn); | ||
941 | } | ||
942 | while (GNUNET_YES == ret); | ||
943 | |||
944 | GNUNET_free (chn); | ||
945 | } | ||
946 | |||
947 | |||
948 | static int | ||
949 | check_cadet_join_request (void *cls, | ||
950 | const struct MulticastJoinRequestMessage *req) | ||
951 | { | ||
952 | struct Channel *chn = cls; | ||
953 | |||
954 | if (NULL == chn | ||
955 | || JOIN_NOT_ASKED != chn->join_status) | ||
956 | { | ||
957 | return GNUNET_SYSERR; | ||
958 | } | ||
959 | |||
960 | uint16_t size = ntohs (req->header.size); | ||
961 | if (size < sizeof (*req)) | ||
962 | { | ||
963 | GNUNET_break_op (0); | ||
964 | return GNUNET_SYSERR; | ||
965 | } | ||
966 | if (ntohl (req->purpose.size) != (size | ||
967 | - sizeof (req->header) | ||
968 | - sizeof (req->reserved) | ||
969 | - sizeof (req->signature))) | ||
970 | { | ||
971 | GNUNET_break_op (0); | ||
972 | return GNUNET_SYSERR; | ||
973 | } | ||
974 | if (GNUNET_OK != | ||
975 | GNUNET_CRYPTO_ecdsa_verify_ (GNUNET_SIGNATURE_PURPOSE_MULTICAST_REQUEST, | ||
976 | &req->purpose, &req->signature, | ||
977 | &req->member_pub_key)) | ||
978 | { | ||
979 | GNUNET_break_op (0); | ||
980 | return GNUNET_SYSERR; | ||
981 | } | ||
982 | |||
983 | return GNUNET_OK; | ||
984 | } | ||
985 | |||
986 | |||
987 | /** | ||
988 | * Incoming join request message from CADET. | ||
989 | */ | ||
990 | static void | ||
991 | handle_cadet_join_request (void *cls, | ||
992 | const struct MulticastJoinRequestMessage *req) | ||
993 | { | ||
994 | struct Channel *chn = cls; | ||
995 | GNUNET_CADET_receive_done (chn->channel); | ||
996 | |||
997 | struct GNUNET_HashCode group_pub_hash; | ||
998 | GNUNET_CRYPTO_hash (&req->group_pub_key, sizeof (req->group_pub_key), &group_pub_hash); | ||
999 | chn->group_pub_key = req->group_pub_key; | ||
1000 | chn->group_pub_hash = group_pub_hash; | ||
1001 | chn->member_pub_key = req->member_pub_key; | ||
1002 | chn->peer = req->peer; | ||
1003 | chn->join_status = JOIN_WAITING; | ||
1004 | |||
1005 | client_send_all (&group_pub_hash, | ||
1006 | GNUNET_MQ_msg_copy (&req->header)); | ||
1007 | } | ||
1008 | |||
1009 | |||
1010 | static int | ||
1011 | check_cadet_join_decision (void *cls, | ||
1012 | const struct MulticastJoinDecisionMessageHeader *hdcsn) | ||
1013 | { | ||
1014 | uint16_t size = ntohs (hdcsn->header.size); | ||
1015 | if (size < sizeof (struct MulticastJoinDecisionMessageHeader) + | ||
1016 | sizeof (struct MulticastJoinDecisionMessage)) | ||
1017 | { | ||
1018 | GNUNET_break_op (0); | ||
1019 | return GNUNET_SYSERR; | ||
1020 | } | ||
1021 | |||
1022 | struct Channel *chn = cls; | ||
1023 | if (NULL == chn) | ||
1024 | { | ||
1025 | GNUNET_break (0); | ||
1026 | return GNUNET_SYSERR; | ||
1027 | } | ||
1028 | if (NULL == chn->group || GNUNET_NO != chn->group->is_origin) | ||
1029 | { | ||
1030 | GNUNET_break (0); | ||
1031 | return GNUNET_SYSERR; | ||
1032 | } | ||
1033 | switch (chn->join_status) | ||
1034 | { | ||
1035 | case JOIN_REFUSED: | ||
1036 | return GNUNET_SYSERR; | ||
1037 | |||
1038 | case JOIN_ADMITTED: | ||
1039 | return GNUNET_OK; | ||
1040 | |||
1041 | case JOIN_NOT_ASKED: | ||
1042 | case JOIN_WAITING: | ||
1043 | break; | ||
1044 | } | ||
1045 | |||
1046 | return GNUNET_OK; | ||
1047 | } | ||
1048 | |||
1049 | |||
1050 | /** | ||
1051 | * Incoming join decision message from CADET. | ||
1052 | */ | ||
1053 | static void | ||
1054 | handle_cadet_join_decision (void *cls, | ||
1055 | const struct MulticastJoinDecisionMessageHeader *hdcsn) | ||
1056 | { | ||
1057 | const struct MulticastJoinDecisionMessage * | ||
1058 | dcsn = (const struct MulticastJoinDecisionMessage *) &hdcsn[1]; | ||
1059 | |||
1060 | struct Channel *chn = cls; | ||
1061 | GNUNET_CADET_receive_done (chn->channel); | ||
1062 | |||
1063 | // FIXME: do we need to copy chn->peer or compare it with hdcsn->peer? | ||
1064 | struct Member *mem = (struct Member *) chn->group; | ||
1065 | client_send_join_decision (mem, hdcsn); | ||
1066 | if (GNUNET_YES == ntohl (dcsn->is_admitted)) | ||
1067 | { | ||
1068 | chn->join_status = JOIN_ADMITTED; | ||
1069 | } | ||
1070 | else | ||
1071 | { | ||
1072 | chn->join_status = JOIN_REFUSED; | ||
1073 | cadet_channel_destroy (chn); | ||
1074 | } | ||
1075 | } | ||
1076 | |||
1077 | |||
1078 | static int | ||
1079 | check_cadet_message (void *cls, | ||
1080 | const struct GNUNET_MULTICAST_MessageHeader *msg) | ||
1081 | { | ||
1082 | uint16_t size = ntohs (msg->header.size); | ||
1083 | if (size < sizeof (*msg)) | ||
1084 | { | ||
1085 | GNUNET_break_op (0); | ||
1086 | return GNUNET_SYSERR; | ||
1087 | } | ||
1088 | |||
1089 | struct Channel *chn = cls; | ||
1090 | if (NULL == chn) | ||
1091 | { | ||
1092 | GNUNET_break (0); | ||
1093 | return GNUNET_SYSERR; | ||
1094 | } | ||
1095 | if (ntohl (msg->purpose.size) != (size | ||
1096 | - sizeof (msg->header) | ||
1097 | - sizeof (msg->hop_counter) | ||
1098 | - sizeof (msg->signature))) | ||
1099 | { | ||
1100 | GNUNET_break_op (0); | ||
1101 | return GNUNET_SYSERR; | ||
1102 | } | ||
1103 | if (GNUNET_OK != | ||
1104 | GNUNET_CRYPTO_eddsa_verify_ (GNUNET_SIGNATURE_PURPOSE_MULTICAST_MESSAGE, | ||
1105 | &msg->purpose, &msg->signature, | ||
1106 | &chn->group_pub_key)) | ||
1107 | { | ||
1108 | GNUNET_break_op (0); | ||
1109 | return GNUNET_SYSERR; | ||
1110 | } | ||
1111 | |||
1112 | return GNUNET_OK; | ||
1113 | } | ||
1114 | |||
1115 | |||
1116 | /** | ||
1117 | * Incoming multicast message from CADET. | ||
1118 | */ | ||
1119 | static void | ||
1120 | handle_cadet_message (void *cls, | ||
1121 | const struct GNUNET_MULTICAST_MessageHeader *msg) | ||
1122 | { | ||
1123 | struct Channel *chn = cls; | ||
1124 | GNUNET_CADET_receive_done (chn->channel); | ||
1125 | client_send_all (&chn->group_pub_hash, | ||
1126 | GNUNET_MQ_msg_copy (&msg->header)); | ||
1127 | } | ||
1128 | |||
1129 | |||
1130 | static int | ||
1131 | check_cadet_request (void *cls, | ||
1132 | const struct GNUNET_MULTICAST_RequestHeader *req) | ||
1133 | { | ||
1134 | uint16_t size = ntohs (req->header.size); | ||
1135 | if (size < sizeof (*req)) | ||
1136 | { | ||
1137 | GNUNET_break_op (0); | ||
1138 | return GNUNET_SYSERR; | ||
1139 | } | ||
1140 | |||
1141 | struct Channel *chn = cls; | ||
1142 | if (NULL == chn) | ||
1143 | { | ||
1144 | GNUNET_break (0); | ||
1145 | return GNUNET_SYSERR; | ||
1146 | } | ||
1147 | if (ntohl (req->purpose.size) != (size | ||
1148 | - sizeof (req->header) | ||
1149 | - sizeof (req->member_pub_key) | ||
1150 | - sizeof (req->signature))) | ||
1151 | { | ||
1152 | GNUNET_break_op (0); | ||
1153 | return GNUNET_SYSERR; | ||
1154 | } | ||
1155 | if (GNUNET_OK != | ||
1156 | GNUNET_CRYPTO_ecdsa_verify_ (GNUNET_SIGNATURE_PURPOSE_MULTICAST_REQUEST, | ||
1157 | &req->purpose, &req->signature, | ||
1158 | &req->member_pub_key)) | ||
1159 | { | ||
1160 | GNUNET_break_op (0); | ||
1161 | return GNUNET_SYSERR; | ||
1162 | } | ||
1163 | |||
1164 | return GNUNET_OK; | ||
1165 | } | ||
1166 | |||
1167 | |||
1168 | /** | ||
1169 | * Incoming multicast request message from CADET. | ||
1170 | */ | ||
1171 | static void | ||
1172 | handle_cadet_request (void *cls, | ||
1173 | const struct GNUNET_MULTICAST_RequestHeader *req) | ||
1174 | { | ||
1175 | struct Channel *chn = cls; | ||
1176 | GNUNET_CADET_receive_done (chn->channel); | ||
1177 | client_send_origin (&chn->group_pub_hash, | ||
1178 | GNUNET_MQ_msg_copy (&req->header)); | ||
1179 | } | ||
1180 | |||
1181 | |||
1182 | // FIXME: do checks in handle_cadet_replay_request | ||
1183 | //static int | ||
1184 | //check_cadet_replay_request (void *cls, | ||
1185 | // const struct MulticastReplayRequestMessage *req) | ||
1186 | //{ | ||
1187 | // uint16_t size = ntohs (req->header.size); | ||
1188 | // if (size < sizeof (*req)) | ||
1189 | // { | ||
1190 | // GNUNET_break_op (0); | ||
1191 | // return GNUNET_SYSERR; | ||
1192 | // } | ||
1193 | // | ||
1194 | // struct Channel *chn = cls; | ||
1195 | // if (NULL == chn) | ||
1196 | // { | ||
1197 | // GNUNET_break_op (0); | ||
1198 | // return GNUNET_SYSERR; | ||
1199 | // } | ||
1200 | // | ||
1201 | // return GNUNET_OK; | ||
1202 | //} | ||
1203 | |||
1204 | |||
1205 | /** | ||
1206 | * Incoming multicast replay request from CADET. | ||
1207 | */ | ||
1208 | static void | ||
1209 | handle_cadet_replay_request (void *cls, | ||
1210 | const struct MulticastReplayRequestMessage *req) | ||
1211 | { | ||
1212 | struct Channel *chn = cls; | ||
1213 | |||
1214 | GNUNET_CADET_receive_done (chn->channel); | ||
1215 | |||
1216 | struct MulticastReplayRequestMessage rep = *req; | ||
1217 | GNUNET_memcpy (&rep.member_pub_key, &chn->member_pub_key, sizeof (chn->member_pub_key)); | ||
1218 | |||
1219 | struct GNUNET_CONTAINER_MultiHashMap * | ||
1220 | grp_replay_req = GNUNET_CONTAINER_multihashmap_get (replay_req_cadet, | ||
1221 | &chn->group->pub_key_hash); | ||
1222 | if (NULL == grp_replay_req) | ||
1223 | { | ||
1224 | grp_replay_req = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); | ||
1225 | GNUNET_CONTAINER_multihashmap_put (replay_req_cadet, | ||
1226 | &chn->group->pub_key_hash, grp_replay_req, | ||
1227 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); | ||
1228 | } | ||
1229 | struct GNUNET_HashCode key_hash; | ||
1230 | replay_key_hash (rep.fragment_id, | ||
1231 | rep.message_id, | ||
1232 | rep.fragment_offset, | ||
1233 | rep.flags, | ||
1234 | &key_hash); | ||
1235 | GNUNET_CONTAINER_multihashmap_put (grp_replay_req, &key_hash, chn, | ||
1236 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
1237 | |||
1238 | client_send_random (&chn->group_pub_hash, | ||
1239 | GNUNET_MQ_msg_copy (&rep.header)); | ||
1240 | } | ||
1241 | |||
1242 | |||
1243 | static int | ||
1244 | check_cadet_replay_response (void *cls, | ||
1245 | const struct MulticastReplayResponseMessage *res) | ||
1246 | { | ||
1247 | struct Channel *chn = cls; | ||
1248 | if (NULL == chn) | ||
1249 | { | ||
1250 | GNUNET_break (0); | ||
1251 | return GNUNET_SYSERR; | ||
1252 | } | ||
1253 | return GNUNET_OK; | ||
1254 | } | ||
1255 | |||
1256 | |||
1257 | /** | ||
1258 | * Incoming multicast replay response from CADET. | ||
1259 | */ | ||
1260 | static void | ||
1261 | handle_cadet_replay_response (void *cls, | ||
1262 | const struct MulticastReplayResponseMessage *res) | ||
1263 | { | ||
1264 | struct Channel *chn = cls; | ||
1265 | GNUNET_CADET_receive_done (chn->channel); | ||
1266 | |||
1267 | /* @todo FIXME: got replay error response, send request to other members */ | ||
1268 | } | ||
1269 | |||
1270 | |||
1271 | static void | ||
1272 | group_set_cadet_port_hash (struct Group *grp) | ||
1273 | { | ||
1274 | struct CadetPort { | ||
1275 | struct GNUNET_CRYPTO_EddsaPublicKey pub_key; | ||
1276 | uint32_t app_type; | ||
1277 | } port = { | ||
1278 | grp->pub_key, | ||
1279 | GNUNET_APPLICATION_TYPE_MULTICAST, | ||
1280 | }; | ||
1281 | GNUNET_CRYPTO_hash (&port, sizeof (port), &grp->cadet_port_hash); | ||
1282 | } | ||
1283 | |||
1284 | |||
1285 | |||
1286 | /** | ||
1287 | * Create new outgoing CADET channel. | ||
1288 | * | ||
1289 | * @param peer | ||
1290 | * Peer to connect to. | ||
1291 | * @param group_pub_key | ||
1292 | * Public key of group the channel belongs to. | ||
1293 | * @param group_pub_hash | ||
1294 | * Hash of @a group_pub_key. | ||
1295 | * | ||
1296 | * @return Channel. | ||
1297 | */ | ||
1298 | static struct Channel * | ||
1299 | cadet_channel_create (struct Group *grp, struct GNUNET_PeerIdentity *peer) | ||
1300 | { | ||
1301 | struct Channel *chn = GNUNET_malloc (sizeof (*chn)); | ||
1302 | chn->group = grp; | ||
1303 | chn->group_pub_key = grp->pub_key; | ||
1304 | chn->group_pub_hash = grp->pub_key_hash; | ||
1305 | chn->peer = *peer; | ||
1306 | chn->direction = DIR_OUTGOING; | ||
1307 | chn->is_connected = GNUNET_NO; | ||
1308 | chn->join_status = JOIN_WAITING; | ||
1309 | |||
1310 | struct GNUNET_MQ_MessageHandler cadet_handlers[] = { | ||
1311 | GNUNET_MQ_hd_var_size (cadet_message, | ||
1312 | GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE, | ||
1313 | struct GNUNET_MULTICAST_MessageHeader, | ||
1314 | chn), | ||
1315 | |||
1316 | GNUNET_MQ_hd_var_size (cadet_join_decision, | ||
1317 | GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION, | ||
1318 | struct MulticastJoinDecisionMessageHeader, | ||
1319 | chn), | ||
1320 | |||
1321 | GNUNET_MQ_hd_fixed_size (cadet_replay_request, | ||
1322 | GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_REQUEST, | ||
1323 | struct MulticastReplayRequestMessage, | ||
1324 | chn), | ||
1325 | |||
1326 | GNUNET_MQ_hd_var_size (cadet_replay_response, | ||
1327 | GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE, | ||
1328 | struct MulticastReplayResponseMessage, | ||
1329 | chn), | ||
1330 | |||
1331 | GNUNET_MQ_handler_end () | ||
1332 | }; | ||
1333 | |||
1334 | chn->channel = GNUNET_CADET_channel_create (cadet, chn, &chn->peer, | ||
1335 | &grp->cadet_port_hash, | ||
1336 | cadet_notify_window_change, | ||
1337 | cadet_notify_disconnect, | ||
1338 | cadet_handlers); | ||
1339 | GNUNET_CONTAINER_multihashmap_put (channels_out, &chn->group_pub_hash, chn, | ||
1340 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
1341 | return chn; | ||
1342 | } | ||
1343 | |||
1344 | |||
1345 | /** | ||
1346 | * Destroy outgoing CADET channel. | ||
1347 | */ | ||
1348 | static void | ||
1349 | cadet_channel_destroy (struct Channel *chn) | ||
1350 | { | ||
1351 | GNUNET_CADET_channel_destroy (chn->channel); | ||
1352 | GNUNET_CONTAINER_multihashmap_remove_all (channels_out, &chn->group_pub_hash); | ||
1353 | GNUNET_free (chn); | ||
1354 | } | ||
1355 | |||
1356 | /** | ||
1357 | * Handle a connecting client starting an origin. | ||
1358 | */ | ||
1359 | static void | ||
1360 | handle_client_origin_start (void *cls, | ||
1361 | const struct MulticastOriginStartMessage *msg) | ||
1362 | { | ||
1363 | struct Client *c = cls; | ||
1364 | struct GNUNET_SERVICE_Client *client = c->client; | ||
1365 | |||
1366 | struct GNUNET_CRYPTO_EddsaPublicKey pub_key; | ||
1367 | struct GNUNET_HashCode pub_key_hash; | ||
1368 | |||
1369 | GNUNET_CRYPTO_eddsa_key_get_public (&msg->group_key, &pub_key); | ||
1370 | GNUNET_CRYPTO_hash (&pub_key, sizeof (pub_key), &pub_key_hash); | ||
1371 | |||
1372 | struct Origin * | ||
1373 | orig = GNUNET_CONTAINER_multihashmap_get (origins, &pub_key_hash); | ||
1374 | struct Group *grp; | ||
1375 | |||
1376 | if (NULL == orig) | ||
1377 | { | ||
1378 | orig = GNUNET_new (struct Origin); | ||
1379 | orig->priv_key = msg->group_key; | ||
1380 | orig->max_fragment_id = GNUNET_ntohll (msg->max_fragment_id); | ||
1381 | |||
1382 | grp = c->group = &orig->group; | ||
1383 | grp->origin = orig; | ||
1384 | grp->is_origin = GNUNET_YES; | ||
1385 | grp->pub_key = pub_key; | ||
1386 | grp->pub_key_hash = pub_key_hash; | ||
1387 | grp->is_disconnected = GNUNET_NO; | ||
1388 | |||
1389 | GNUNET_CONTAINER_multihashmap_put (origins, &grp->pub_key_hash, orig, | ||
1390 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); | ||
1391 | |||
1392 | group_set_cadet_port_hash (grp); | ||
1393 | |||
1394 | struct GNUNET_MQ_MessageHandler cadet_handlers[] = { | ||
1395 | GNUNET_MQ_hd_var_size (cadet_message, | ||
1396 | GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE, | ||
1397 | struct GNUNET_MULTICAST_MessageHeader, | ||
1398 | grp), | ||
1399 | |||
1400 | GNUNET_MQ_hd_var_size (cadet_request, | ||
1401 | GNUNET_MESSAGE_TYPE_MULTICAST_REQUEST, | ||
1402 | struct GNUNET_MULTICAST_RequestHeader, | ||
1403 | grp), | ||
1404 | |||
1405 | GNUNET_MQ_hd_var_size (cadet_join_request, | ||
1406 | GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_REQUEST, | ||
1407 | struct MulticastJoinRequestMessage, | ||
1408 | grp), | ||
1409 | |||
1410 | GNUNET_MQ_hd_fixed_size (cadet_replay_request, | ||
1411 | GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_REQUEST, | ||
1412 | struct MulticastReplayRequestMessage, | ||
1413 | grp), | ||
1414 | |||
1415 | GNUNET_MQ_hd_var_size (cadet_replay_response, | ||
1416 | GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE, | ||
1417 | struct MulticastReplayResponseMessage, | ||
1418 | grp), | ||
1419 | |||
1420 | GNUNET_MQ_handler_end () | ||
1421 | }; | ||
1422 | |||
1423 | |||
1424 | orig->cadet_port = GNUNET_CADET_open_port (cadet, | ||
1425 | &grp->cadet_port_hash, | ||
1426 | cadet_notify_connect, | ||
1427 | grp, | ||
1428 | cadet_notify_window_change, | ||
1429 | cadet_notify_disconnect, | ||
1430 | cadet_handlers); | ||
1431 | } | ||
1432 | else | ||
1433 | { | ||
1434 | grp = &orig->group; | ||
1435 | } | ||
1436 | |||
1437 | struct ClientList *cl = GNUNET_new (struct ClientList); | ||
1438 | cl->client = client; | ||
1439 | GNUNET_CONTAINER_DLL_insert (grp->clients_head, grp->clients_tail, cl); | ||
1440 | |||
1441 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1442 | "%p Client connected as origin to group %s.\n", | ||
1443 | orig, GNUNET_h2s (&grp->pub_key_hash)); | ||
1444 | GNUNET_SERVICE_client_continue (client); | ||
1445 | } | ||
1446 | |||
1447 | |||
1448 | static int | ||
1449 | check_client_member_join (void *cls, | ||
1450 | const struct MulticastMemberJoinMessage *msg) | ||
1451 | { | ||
1452 | uint16_t msg_size = ntohs (msg->header.size); | ||
1453 | struct GNUNET_PeerIdentity *relays = (struct GNUNET_PeerIdentity *) &msg[1]; | ||
1454 | uint32_t relay_count = ntohl (msg->relay_count); | ||
1455 | |||
1456 | if (0 != relay_count) | ||
1457 | { | ||
1458 | if (UINT32_MAX / relay_count < sizeof (*relays)){ | ||
1459 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1460 | "relay_count (%lu) * sizeof (*relays) (%lu) exceeds UINT32_MAX!\n", | ||
1461 | (unsigned long)relay_count, | ||
1462 | sizeof (*relays)); | ||
1463 | return GNUNET_SYSERR; | ||
1464 | } | ||
1465 | } | ||
1466 | uint32_t relay_size = relay_count * sizeof (*relays); | ||
1467 | struct GNUNET_MessageHeader *join_msg = NULL; | ||
1468 | uint16_t join_msg_size = 0; | ||
1469 | if (sizeof (*msg) + relay_size + sizeof (struct GNUNET_MessageHeader) | ||
1470 | <= msg_size) | ||
1471 | { | ||
1472 | join_msg = (struct GNUNET_MessageHeader *) | ||
1473 | (((char *) &msg[1]) + relay_size); | ||
1474 | join_msg_size = ntohs (join_msg->size); | ||
1475 | if (UINT16_MAX - join_msg_size < sizeof (struct MulticastJoinRequestMessage)){ | ||
1476 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1477 | "join_msg_size (%u) + sizeof (struct MulticastJoinRequestMessage) (%lu) exceeds UINT16_MAX!\n", | ||
1478 | (unsigned)join_msg_size, | ||
1479 | (unsigned long)sizeof (struct MulticastJoinRequestMessage)); | ||
1480 | return GNUNET_SYSERR; | ||
1481 | } | ||
1482 | } | ||
1483 | if (msg_size != (sizeof (*msg) + relay_size + join_msg_size)){ | ||
1484 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1485 | "msg_size does not match real size of message!\n"); | ||
1486 | return GNUNET_SYSERR; | ||
1487 | }else{ | ||
1488 | return GNUNET_OK; | ||
1489 | } | ||
1490 | } | ||
1491 | |||
1492 | |||
1493 | /** | ||
1494 | * Handle a connecting client joining a group. | ||
1495 | */ | ||
1496 | static void | ||
1497 | handle_client_member_join (void *cls, | ||
1498 | const struct MulticastMemberJoinMessage *msg) | ||
1499 | { | ||
1500 | struct Client *c = cls; | ||
1501 | struct GNUNET_SERVICE_Client *client = c->client; | ||
1502 | |||
1503 | uint16_t msg_size = ntohs (msg->header.size); | ||
1504 | |||
1505 | struct GNUNET_CRYPTO_EcdsaPublicKey mem_pub_key; | ||
1506 | struct GNUNET_HashCode pub_key_hash, mem_pub_key_hash; | ||
1507 | |||
1508 | GNUNET_CRYPTO_ecdsa_key_get_public (&msg->member_key, &mem_pub_key); | ||
1509 | GNUNET_CRYPTO_hash (&mem_pub_key, sizeof (mem_pub_key), &mem_pub_key_hash); | ||
1510 | GNUNET_CRYPTO_hash (&msg->group_pub_key, sizeof (msg->group_pub_key), &pub_key_hash); | ||
1511 | |||
1512 | struct GNUNET_CONTAINER_MultiHashMap * | ||
1513 | grp_mem = GNUNET_CONTAINER_multihashmap_get (group_members, &pub_key_hash); | ||
1514 | struct Member *mem = NULL; | ||
1515 | struct Group *grp; | ||
1516 | |||
1517 | if (NULL != grp_mem) | ||
1518 | { | ||
1519 | mem = GNUNET_CONTAINER_multihashmap_get (grp_mem, &mem_pub_key_hash); | ||
1520 | } | ||
1521 | |||
1522 | if (NULL == mem) | ||
1523 | { | ||
1524 | mem = GNUNET_new (struct Member); | ||
1525 | mem->origin = msg->origin; | ||
1526 | mem->priv_key = msg->member_key; | ||
1527 | mem->pub_key = mem_pub_key; | ||
1528 | mem->pub_key_hash = mem_pub_key_hash; | ||
1529 | mem->max_fragment_id = 0; // FIXME | ||
1530 | |||
1531 | grp = c->group = &mem->group; | ||
1532 | grp->member = mem; | ||
1533 | grp->is_origin = GNUNET_NO; | ||
1534 | grp->pub_key = msg->group_pub_key; | ||
1535 | grp->pub_key_hash = pub_key_hash; | ||
1536 | grp->is_disconnected = GNUNET_NO; | ||
1537 | group_set_cadet_port_hash (grp); | ||
1538 | |||
1539 | if (NULL == grp_mem) | ||
1540 | { | ||
1541 | grp_mem = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES); | ||
1542 | GNUNET_CONTAINER_multihashmap_put (group_members, &grp->pub_key_hash, grp_mem, | ||
1543 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); | ||
1544 | } | ||
1545 | GNUNET_CONTAINER_multihashmap_put (grp_mem, &mem->pub_key_hash, mem, | ||
1546 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); | ||
1547 | |||
1548 | // FIXME: should the members hash map have option UNIQUE_FAST? | ||
1549 | GNUNET_CONTAINER_multihashmap_put (members, &grp->pub_key_hash, mem, | ||
1550 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
1551 | } | ||
1552 | else | ||
1553 | { | ||
1554 | grp = &mem->group; | ||
1555 | } | ||
1556 | |||
1557 | struct ClientList *cl = GNUNET_new (struct ClientList); | ||
1558 | cl->client = client; | ||
1559 | GNUNET_CONTAINER_DLL_insert (grp->clients_head, grp->clients_tail, cl); | ||
1560 | |||
1561 | char *str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&mem->pub_key); | ||
1562 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1563 | "Client connected to group %s as member %s (%s). size = %d\n", | ||
1564 | GNUNET_h2s (&grp->pub_key_hash), | ||
1565 | GNUNET_h2s2 (&mem->pub_key_hash), | ||
1566 | str, | ||
1567 | GNUNET_CONTAINER_multihashmap_size (members)); | ||
1568 | GNUNET_free (str); | ||
1569 | |||
1570 | if (NULL != mem->join_dcsn) | ||
1571 | { /* Already got a join decision, send it to client. */ | ||
1572 | struct GNUNET_MQ_Envelope * | ||
1573 | env = GNUNET_MQ_msg_copy (&mem->join_dcsn->header); | ||
1574 | |||
1575 | GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), | ||
1576 | env); | ||
1577 | } | ||
1578 | else | ||
1579 | { /* First client of the group, send join request. */ | ||
1580 | struct GNUNET_PeerIdentity *relays = (struct GNUNET_PeerIdentity *) &msg[1]; | ||
1581 | uint32_t relay_count = ntohl (msg->relay_count); | ||
1582 | uint16_t relay_size = relay_count * sizeof (*relays); | ||
1583 | struct GNUNET_MessageHeader *join_msg = NULL; | ||
1584 | uint16_t join_msg_size = 0; | ||
1585 | if (sizeof (*msg) + relay_size + sizeof (struct GNUNET_MessageHeader) | ||
1586 | <= msg_size) | ||
1587 | { | ||
1588 | join_msg = (struct GNUNET_MessageHeader *) | ||
1589 | (((char *) &msg[1]) + relay_size); | ||
1590 | join_msg_size = ntohs (join_msg->size); | ||
1591 | } | ||
1592 | |||
1593 | uint16_t req_msg_size = sizeof (struct MulticastJoinRequestMessage) + join_msg_size; | ||
1594 | struct MulticastJoinRequestMessage * | ||
1595 | req = GNUNET_malloc (req_msg_size); | ||
1596 | req->header.size = htons (req_msg_size); | ||
1597 | req->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_REQUEST); | ||
1598 | req->group_pub_key = grp->pub_key; | ||
1599 | req->peer = this_peer; | ||
1600 | GNUNET_CRYPTO_ecdsa_key_get_public (&mem->priv_key, &req->member_pub_key); | ||
1601 | if (0 < join_msg_size) | ||
1602 | GNUNET_memcpy (&req[1], join_msg, join_msg_size); | ||
1603 | |||
1604 | req->member_pub_key = mem->pub_key; | ||
1605 | req->purpose.size = htonl (req_msg_size | ||
1606 | - sizeof (req->header) | ||
1607 | - sizeof (req->reserved) | ||
1608 | - sizeof (req->signature)); | ||
1609 | req->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_MULTICAST_REQUEST); | ||
1610 | |||
1611 | if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_sign_ (&mem->priv_key, &req->purpose, | ||
1612 | &req->signature)) | ||
1613 | { | ||
1614 | /* FIXME: handle error */ | ||
1615 | GNUNET_assert (0); | ||
1616 | } | ||
1617 | |||
1618 | if (NULL != mem->join_req) | ||
1619 | GNUNET_free (mem->join_req); | ||
1620 | mem->join_req = req; | ||
1621 | |||
1622 | if (0 == | ||
1623 | client_send_origin (&grp->pub_key_hash, | ||
1624 | GNUNET_MQ_msg_copy (&mem->join_req->header))) | ||
1625 | { /* No local origins, send to remote origin */ | ||
1626 | cadet_send_join_request (mem); | ||
1627 | } | ||
1628 | } | ||
1629 | GNUNET_SERVICE_client_continue (client); | ||
1630 | } | ||
1631 | |||
1632 | |||
1633 | static void | ||
1634 | client_send_join_decision (struct Member *mem, | ||
1635 | const struct MulticastJoinDecisionMessageHeader *hdcsn) | ||
1636 | { | ||
1637 | client_send_group (&mem->group, GNUNET_MQ_msg_copy (&hdcsn->header)); | ||
1638 | |||
1639 | const struct MulticastJoinDecisionMessage * | ||
1640 | dcsn = (const struct MulticastJoinDecisionMessage *) &hdcsn[1]; | ||
1641 | if (GNUNET_YES == ntohl (dcsn->is_admitted)) | ||
1642 | { /* Member admitted, store join_decision. */ | ||
1643 | uint16_t dcsn_size = ntohs (dcsn->header.size); | ||
1644 | mem->join_dcsn = GNUNET_malloc (dcsn_size); | ||
1645 | GNUNET_memcpy (mem->join_dcsn, dcsn, dcsn_size); | ||
1646 | } | ||
1647 | else | ||
1648 | { /* Refused entry, but replay would be still possible for past members. */ | ||
1649 | } | ||
1650 | } | ||
1651 | |||
1652 | |||
1653 | static int | ||
1654 | check_client_join_decision (void *cls, | ||
1655 | const struct MulticastJoinDecisionMessageHeader *hdcsn) | ||
1656 | { | ||
1657 | return GNUNET_OK; | ||
1658 | } | ||
1659 | |||
1660 | |||
1661 | /** | ||
1662 | * Join decision from client. | ||
1663 | */ | ||
1664 | static void | ||
1665 | handle_client_join_decision (void *cls, | ||
1666 | const struct MulticastJoinDecisionMessageHeader *hdcsn) | ||
1667 | { | ||
1668 | struct Client *c = cls; | ||
1669 | struct GNUNET_SERVICE_Client *client = c->client; | ||
1670 | struct Group *grp = c->group; | ||
1671 | |||
1672 | if (NULL == grp) | ||
1673 | { | ||
1674 | GNUNET_break (0); | ||
1675 | GNUNET_SERVICE_client_drop (client); | ||
1676 | return; | ||
1677 | } | ||
1678 | GNUNET_assert (GNUNET_NO == grp->is_disconnected); | ||
1679 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1680 | "%p got join decision from client for group %s..\n", | ||
1681 | grp, GNUNET_h2s (&grp->pub_key_hash)); | ||
1682 | |||
1683 | struct GNUNET_CONTAINER_MultiHashMap * | ||
1684 | grp_mem = GNUNET_CONTAINER_multihashmap_get (group_members, | ||
1685 | &grp->pub_key_hash); | ||
1686 | struct Member *mem = NULL; | ||
1687 | if (NULL != grp_mem) | ||
1688 | { | ||
1689 | struct GNUNET_HashCode member_key_hash; | ||
1690 | GNUNET_CRYPTO_hash (&hdcsn->member_pub_key, sizeof (hdcsn->member_pub_key), | ||
1691 | &member_key_hash); | ||
1692 | mem = GNUNET_CONTAINER_multihashmap_get (grp_mem, &member_key_hash); | ||
1693 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1694 | "%p ..and member %s: %p\n", | ||
1695 | grp, GNUNET_h2s (&member_key_hash), mem); | ||
1696 | } | ||
1697 | |||
1698 | if (NULL != mem) | ||
1699 | { /* Found local member */ | ||
1700 | client_send_join_decision (mem, hdcsn); | ||
1701 | } | ||
1702 | else | ||
1703 | { /* Look for remote member */ | ||
1704 | cadet_send_join_decision (grp, hdcsn); | ||
1705 | } | ||
1706 | GNUNET_SERVICE_client_continue (client); | ||
1707 | } | ||
1708 | |||
1709 | |||
1710 | static void | ||
1711 | handle_client_part_request (void *cls, | ||
1712 | const struct GNUNET_MessageHeader *msg) | ||
1713 | { | ||
1714 | struct Client *c = cls; | ||
1715 | struct GNUNET_SERVICE_Client *client = c->client; | ||
1716 | struct Group *grp = c->group; | ||
1717 | struct GNUNET_MQ_Envelope *env; | ||
1718 | |||
1719 | if (NULL == grp) | ||
1720 | { | ||
1721 | GNUNET_break (0); | ||
1722 | GNUNET_SERVICE_client_drop (client); | ||
1723 | return; | ||
1724 | } | ||
1725 | GNUNET_assert (GNUNET_NO == grp->is_disconnected); | ||
1726 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1727 | "%p got part request from client for group %s.\n", | ||
1728 | grp, GNUNET_h2s (&grp->pub_key_hash)); | ||
1729 | grp->is_disconnected = GNUNET_YES; | ||
1730 | env = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_MULTICAST_PART_ACK); | ||
1731 | client_send_group (grp, env); | ||
1732 | GNUNET_SERVICE_client_continue (client); | ||
1733 | } | ||
1734 | |||
1735 | |||
1736 | static int | ||
1737 | check_client_multicast_message (void *cls, | ||
1738 | const struct GNUNET_MULTICAST_MessageHeader *msg) | ||
1739 | { | ||
1740 | return GNUNET_OK; | ||
1741 | } | ||
1742 | |||
1743 | |||
1744 | /** | ||
1745 | * Incoming message from a client. | ||
1746 | */ | ||
1747 | static void | ||
1748 | handle_client_multicast_message (void *cls, | ||
1749 | const struct GNUNET_MULTICAST_MessageHeader *msg) | ||
1750 | { | ||
1751 | // FIXME: what if GNUNET_YES == grp->is_disconnected? Do we allow sending messages? | ||
1752 | struct Client *c = cls; | ||
1753 | struct GNUNET_SERVICE_Client *client = c->client; | ||
1754 | struct Group *grp = c->group; | ||
1755 | |||
1756 | if (NULL == grp) | ||
1757 | { | ||
1758 | GNUNET_break (0); | ||
1759 | GNUNET_SERVICE_client_drop (client); | ||
1760 | return; | ||
1761 | } | ||
1762 | GNUNET_assert (GNUNET_YES == grp->is_origin); | ||
1763 | struct Origin *orig = grp->origin; | ||
1764 | |||
1765 | // FIXME: use GNUNET_MQ_msg_copy | ||
1766 | /* FIXME: yucky, should use separate message structs for P2P and CS! */ | ||
1767 | struct GNUNET_MULTICAST_MessageHeader * | ||
1768 | out = (struct GNUNET_MULTICAST_MessageHeader *) GNUNET_copy_message (&msg->header); | ||
1769 | out->fragment_id = GNUNET_htonll (++orig->max_fragment_id); | ||
1770 | out->purpose.size = htonl (ntohs (out->header.size) | ||
1771 | - sizeof (out->header) | ||
1772 | - sizeof (out->hop_counter) | ||
1773 | - sizeof (out->signature)); | ||
1774 | out->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_MULTICAST_MESSAGE); | ||
1775 | |||
1776 | if (GNUNET_OK != GNUNET_CRYPTO_eddsa_sign_ (&orig->priv_key, &out->purpose, | ||
1777 | &out->signature)) | ||
1778 | { | ||
1779 | GNUNET_assert (0); | ||
1780 | } | ||
1781 | |||
1782 | client_send_all (&grp->pub_key_hash, GNUNET_MQ_msg_copy (&out->header)); | ||
1783 | cadet_send_children (&grp->pub_key_hash, &out->header); | ||
1784 | client_send_ack (&grp->pub_key_hash); | ||
1785 | GNUNET_free (out); | ||
1786 | |||
1787 | GNUNET_SERVICE_client_continue (client); | ||
1788 | } | ||
1789 | |||
1790 | |||
1791 | static int | ||
1792 | check_client_multicast_request (void *cls, | ||
1793 | const struct GNUNET_MULTICAST_RequestHeader *req) | ||
1794 | { | ||
1795 | return GNUNET_OK; | ||
1796 | } | ||
1797 | |||
1798 | |||
1799 | /** | ||
1800 | * Incoming request from a client. | ||
1801 | */ | ||
1802 | static void | ||
1803 | handle_client_multicast_request (void *cls, | ||
1804 | const struct GNUNET_MULTICAST_RequestHeader *req) | ||
1805 | { | ||
1806 | struct Client *c = cls; | ||
1807 | struct GNUNET_SERVICE_Client *client = c->client; | ||
1808 | struct Group *grp = c->group; | ||
1809 | |||
1810 | if (NULL == grp) | ||
1811 | { | ||
1812 | GNUNET_break (0); | ||
1813 | GNUNET_SERVICE_client_drop (client); | ||
1814 | return; | ||
1815 | } | ||
1816 | GNUNET_assert (GNUNET_NO == grp->is_disconnected); | ||
1817 | GNUNET_assert (GNUNET_NO == grp->is_origin); | ||
1818 | struct Member *mem = grp->member; | ||
1819 | |||
1820 | /* FIXME: yucky, should use separate message structs for P2P and CS! */ | ||
1821 | struct GNUNET_MULTICAST_RequestHeader * | ||
1822 | out = (struct GNUNET_MULTICAST_RequestHeader *) GNUNET_copy_message (&req->header); | ||
1823 | out->member_pub_key = mem->pub_key; | ||
1824 | out->fragment_id = GNUNET_ntohll (++mem->max_fragment_id); | ||
1825 | out->purpose.size = htonl (ntohs (out->header.size) | ||
1826 | - sizeof (out->header) | ||
1827 | - sizeof (out->member_pub_key) | ||
1828 | - sizeof (out->signature)); | ||
1829 | out->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_MULTICAST_REQUEST); | ||
1830 | |||
1831 | if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_sign_ (&mem->priv_key, &out->purpose, | ||
1832 | &out->signature)) | ||
1833 | { | ||
1834 | GNUNET_assert (0); | ||
1835 | } | ||
1836 | |||
1837 | uint8_t send_ack = GNUNET_YES; | ||
1838 | if (0 == | ||
1839 | client_send_origin (&grp->pub_key_hash, | ||
1840 | GNUNET_MQ_msg_copy (&out->header))) | ||
1841 | { /* No local origins, send to remote origin */ | ||
1842 | if (NULL != mem->origin_channel) | ||
1843 | { | ||
1844 | cadet_send_channel (mem->origin_channel, &out->header); | ||
1845 | send_ack = GNUNET_NO; | ||
1846 | } | ||
1847 | else | ||
1848 | { | ||
1849 | /* FIXME: not yet connected to origin */ | ||
1850 | GNUNET_SERVICE_client_drop (client); | ||
1851 | GNUNET_free (out); | ||
1852 | return; | ||
1853 | } | ||
1854 | } | ||
1855 | if (GNUNET_YES == send_ack) | ||
1856 | { | ||
1857 | client_send_ack (&grp->pub_key_hash); | ||
1858 | } | ||
1859 | GNUNET_free (out); | ||
1860 | GNUNET_SERVICE_client_continue (client); | ||
1861 | } | ||
1862 | |||
1863 | |||
1864 | /** | ||
1865 | * Incoming replay request from a client. | ||
1866 | */ | ||
1867 | static void | ||
1868 | handle_client_replay_request (void *cls, | ||
1869 | const struct MulticastReplayRequestMessage *rep) | ||
1870 | { | ||
1871 | struct Client *c = cls; | ||
1872 | struct GNUNET_SERVICE_Client *client = c->client; | ||
1873 | struct Group *grp = c->group; | ||
1874 | |||
1875 | if (NULL == grp) | ||
1876 | { | ||
1877 | GNUNET_break (0); | ||
1878 | GNUNET_SERVICE_client_drop (client); | ||
1879 | return; | ||
1880 | } | ||
1881 | GNUNET_assert (GNUNET_NO == grp->is_disconnected); | ||
1882 | GNUNET_assert (GNUNET_NO == grp->is_origin); | ||
1883 | struct Member *mem = grp->member; | ||
1884 | |||
1885 | struct GNUNET_CONTAINER_MultiHashMap * | ||
1886 | grp_replay_req = GNUNET_CONTAINER_multihashmap_get (replay_req_client, | ||
1887 | &grp->pub_key_hash); | ||
1888 | if (NULL == grp_replay_req) | ||
1889 | { | ||
1890 | grp_replay_req = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); | ||
1891 | GNUNET_CONTAINER_multihashmap_put (replay_req_client, | ||
1892 | &grp->pub_key_hash, grp_replay_req, | ||
1893 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); | ||
1894 | } | ||
1895 | |||
1896 | struct GNUNET_HashCode key_hash; | ||
1897 | replay_key_hash (rep->fragment_id, rep->message_id, rep->fragment_offset, | ||
1898 | rep->flags, &key_hash); | ||
1899 | GNUNET_CONTAINER_multihashmap_put (grp_replay_req, &key_hash, client, | ||
1900 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
1901 | |||
1902 | if (0 == | ||
1903 | client_send_origin (&grp->pub_key_hash, | ||
1904 | GNUNET_MQ_msg_copy (&rep->header))) | ||
1905 | { /* No local origin, replay from remote members / origin. */ | ||
1906 | if (NULL != mem->origin_channel) | ||
1907 | { | ||
1908 | cadet_send_channel (mem->origin_channel, &rep->header); | ||
1909 | } | ||
1910 | else | ||
1911 | { | ||
1912 | /* FIXME: not yet connected to origin */ | ||
1913 | |||
1914 | GNUNET_assert (0); | ||
1915 | GNUNET_SERVICE_client_drop (client); | ||
1916 | return; | ||
1917 | } | ||
1918 | } | ||
1919 | GNUNET_SERVICE_client_continue (client); | ||
1920 | } | ||
1921 | |||
1922 | |||
1923 | static int | ||
1924 | cadet_send_replay_response_cb (void *cls, | ||
1925 | const struct GNUNET_HashCode *key_hash, | ||
1926 | void *value) | ||
1927 | { | ||
1928 | struct Channel *chn = value; | ||
1929 | struct GNUNET_MessageHeader *msg = cls; | ||
1930 | |||
1931 | cadet_send_channel (chn, msg); | ||
1932 | return GNUNET_OK; | ||
1933 | } | ||
1934 | |||
1935 | |||
1936 | static int | ||
1937 | client_send_replay_response_cb (void *cls, | ||
1938 | const struct GNUNET_HashCode *key_hash, | ||
1939 | void *value) | ||
1940 | { | ||
1941 | struct GNUNET_SERVICE_Client *client = value; | ||
1942 | struct GNUNET_MessageHeader *msg = cls; | ||
1943 | |||
1944 | client_send (client, msg); | ||
1945 | return GNUNET_OK; | ||
1946 | } | ||
1947 | |||
1948 | |||
1949 | static int | ||
1950 | check_client_replay_response_end (void *cls, | ||
1951 | const struct MulticastReplayResponseMessage *res) | ||
1952 | { | ||
1953 | return GNUNET_OK; | ||
1954 | } | ||
1955 | |||
1956 | |||
1957 | /** | ||
1958 | * End of replay response from a client. | ||
1959 | */ | ||
1960 | static void | ||
1961 | handle_client_replay_response_end (void *cls, | ||
1962 | const struct MulticastReplayResponseMessage *res) | ||
1963 | { | ||
1964 | struct Client *c = cls; | ||
1965 | struct GNUNET_SERVICE_Client *client = c->client; | ||
1966 | struct Group *grp = c->group; | ||
1967 | |||
1968 | if (NULL == grp) | ||
1969 | { | ||
1970 | GNUNET_break (0); | ||
1971 | GNUNET_SERVICE_client_drop (client); | ||
1972 | return; | ||
1973 | } | ||
1974 | GNUNET_assert (GNUNET_NO == grp->is_disconnected); | ||
1975 | |||
1976 | struct GNUNET_HashCode key_hash; | ||
1977 | replay_key_hash (res->fragment_id, res->message_id, res->fragment_offset, | ||
1978 | res->flags, &key_hash); | ||
1979 | |||
1980 | struct GNUNET_CONTAINER_MultiHashMap * | ||
1981 | grp_replay_req_cadet = GNUNET_CONTAINER_multihashmap_get (replay_req_cadet, | ||
1982 | &grp->pub_key_hash); | ||
1983 | if (NULL != grp_replay_req_cadet) | ||
1984 | { | ||
1985 | GNUNET_CONTAINER_multihashmap_remove_all (grp_replay_req_cadet, &key_hash); | ||
1986 | } | ||
1987 | struct GNUNET_CONTAINER_MultiHashMap * | ||
1988 | grp_replay_req_client = GNUNET_CONTAINER_multihashmap_get (replay_req_client, | ||
1989 | &grp->pub_key_hash); | ||
1990 | if (NULL != grp_replay_req_client) | ||
1991 | { | ||
1992 | GNUNET_CONTAINER_multihashmap_remove_all (grp_replay_req_client, &key_hash); | ||
1993 | } | ||
1994 | GNUNET_SERVICE_client_continue (client); | ||
1995 | } | ||
1996 | |||
1997 | |||
1998 | static int | ||
1999 | check_client_replay_response (void *cls, | ||
2000 | const struct MulticastReplayResponseMessage *res) | ||
2001 | { | ||
2002 | const struct GNUNET_MessageHeader *msg; | ||
2003 | if (GNUNET_MULTICAST_REC_OK == res->error_code) | ||
2004 | { | ||
2005 | msg = GNUNET_MQ_extract_nested_mh (res); | ||
2006 | if (NULL == msg) | ||
2007 | { | ||
2008 | return GNUNET_SYSERR; | ||
2009 | } | ||
2010 | } | ||
2011 | return GNUNET_OK; | ||
2012 | } | ||
2013 | |||
2014 | |||
2015 | /** | ||
2016 | * Incoming replay response from a client. | ||
2017 | * | ||
2018 | * Respond with a multicast message on success, or otherwise with an error code. | ||
2019 | */ | ||
2020 | static void | ||
2021 | handle_client_replay_response (void *cls, | ||
2022 | const struct MulticastReplayResponseMessage *res) | ||
2023 | { | ||
2024 | struct Client *c = cls; | ||
2025 | struct GNUNET_SERVICE_Client *client = c->client; | ||
2026 | struct Group *grp = c->group; | ||
2027 | |||
2028 | if (NULL == grp) | ||
2029 | { | ||
2030 | GNUNET_break (0); | ||
2031 | GNUNET_SERVICE_client_drop (client); | ||
2032 | return; | ||
2033 | } | ||
2034 | GNUNET_assert (GNUNET_NO == grp->is_disconnected); | ||
2035 | |||
2036 | const struct GNUNET_MessageHeader *msg = &res->header; | ||
2037 | if (GNUNET_MULTICAST_REC_OK == res->error_code) | ||
2038 | { | ||
2039 | msg = GNUNET_MQ_extract_nested_mh (res); | ||
2040 | } | ||
2041 | |||
2042 | struct GNUNET_HashCode key_hash; | ||
2043 | replay_key_hash (res->fragment_id, res->message_id, res->fragment_offset, | ||
2044 | res->flags, &key_hash); | ||
2045 | |||
2046 | struct GNUNET_CONTAINER_MultiHashMap * | ||
2047 | grp_replay_req_cadet = GNUNET_CONTAINER_multihashmap_get (replay_req_cadet, | ||
2048 | &grp->pub_key_hash); | ||
2049 | if (NULL != grp_replay_req_cadet) | ||
2050 | { | ||
2051 | GNUNET_CONTAINER_multihashmap_get_multiple (grp_replay_req_cadet, &key_hash, | ||
2052 | cadet_send_replay_response_cb, | ||
2053 | (void *) msg); | ||
2054 | } | ||
2055 | if (GNUNET_MULTICAST_REC_OK == res->error_code) | ||
2056 | { | ||
2057 | struct GNUNET_CONTAINER_MultiHashMap * | ||
2058 | grp_replay_req_client = GNUNET_CONTAINER_multihashmap_get (replay_req_client, | ||
2059 | &grp->pub_key_hash); | ||
2060 | if (NULL != grp_replay_req_client) | ||
2061 | { | ||
2062 | GNUNET_CONTAINER_multihashmap_get_multiple (grp_replay_req_client, &key_hash, | ||
2063 | client_send_replay_response_cb, | ||
2064 | (void *) msg); | ||
2065 | } | ||
2066 | } | ||
2067 | else | ||
2068 | { | ||
2069 | handle_client_replay_response_end (c, res); | ||
2070 | return; | ||
2071 | } | ||
2072 | GNUNET_SERVICE_client_continue (client); | ||
2073 | } | ||
2074 | |||
2075 | |||
2076 | /** | ||
2077 | * A new client connected. | ||
2078 | * | ||
2079 | * @param cls NULL | ||
2080 | * @param client client to add | ||
2081 | * @param mq message queue for @a client | ||
2082 | * @return @a client | ||
2083 | */ | ||
2084 | static void * | ||
2085 | client_notify_connect (void *cls, | ||
2086 | struct GNUNET_SERVICE_Client *client, | ||
2087 | struct GNUNET_MQ_Handle *mq) | ||
2088 | { | ||
2089 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client connected: %p\n", client); | ||
2090 | /* FIXME: send connect ACK */ | ||
2091 | |||
2092 | struct Client *c = GNUNET_new (struct Client); | ||
2093 | c->client = client; | ||
2094 | |||
2095 | return c; | ||
2096 | } | ||
2097 | |||
2098 | |||
2099 | /** | ||
2100 | * Called whenever a client is disconnected. | ||
2101 | * Frees our resources associated with that client. | ||
2102 | * | ||
2103 | * @param cls closure | ||
2104 | * @param client identification of the client | ||
2105 | * @param app_ctx must match @a client | ||
2106 | */ | ||
2107 | static void | ||
2108 | client_notify_disconnect (void *cls, | ||
2109 | struct GNUNET_SERVICE_Client *client, | ||
2110 | void *app_ctx) | ||
2111 | { | ||
2112 | struct Client *c = app_ctx; | ||
2113 | struct Group *grp = c->group; | ||
2114 | GNUNET_free (c); | ||
2115 | |||
2116 | if (NULL == grp) | ||
2117 | { | ||
2118 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
2119 | "%p User context is NULL in client_disconnect()\n", grp); | ||
2120 | GNUNET_break (0); | ||
2121 | return; | ||
2122 | } | ||
2123 | |||
2124 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2125 | "%p Client (%s) disconnected from group %s\n", | ||
2126 | grp, (GNUNET_YES == grp->is_origin) ? "origin" : "member", | ||
2127 | GNUNET_h2s (&grp->pub_key_hash)); | ||
2128 | |||
2129 | // FIXME (due to protocol change): here we must not remove all clients, | ||
2130 | // only the one we were notified about! | ||
2131 | struct ClientList *cl = grp->clients_head; | ||
2132 | while (NULL != cl) | ||
2133 | { | ||
2134 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2135 | "iterating clients for group %p\n", | ||
2136 | grp); | ||
2137 | if (cl->client == client) | ||
2138 | { | ||
2139 | GNUNET_CONTAINER_DLL_remove (grp->clients_head, grp->clients_tail, cl); | ||
2140 | GNUNET_free (cl); | ||
2141 | break; | ||
2142 | } | ||
2143 | cl = cl->next; | ||
2144 | } | ||
2145 | |||
2146 | while (GNUNET_YES == replay_req_remove_client (grp, client)); | ||
2147 | |||
2148 | if (NULL == grp->clients_head) | ||
2149 | { /* Last client disconnected. */ | ||
2150 | cleanup_group (grp); | ||
2151 | } | ||
2152 | } | ||
2153 | |||
2154 | |||
2155 | /** | ||
2156 | * Service started. | ||
2157 | * | ||
2158 | * @param cls closure | ||
2159 | * @param server the initialized server | ||
2160 | * @param cfg configuration to use | ||
2161 | */ | ||
2162 | static void | ||
2163 | run (void *cls, | ||
2164 | const struct GNUNET_CONFIGURATION_Handle *c, | ||
2165 | struct GNUNET_SERVICE_Handle *svc) | ||
2166 | { | ||
2167 | cfg = c; | ||
2168 | service = svc; | ||
2169 | GNUNET_CRYPTO_get_peer_identity (cfg, &this_peer); | ||
2170 | |||
2171 | stats = GNUNET_STATISTICS_create ("multicast", cfg); | ||
2172 | origins = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES); | ||
2173 | members = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES); | ||
2174 | group_members = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); | ||
2175 | channels_in = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES); | ||
2176 | channels_out = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES); | ||
2177 | replay_req_cadet = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); | ||
2178 | replay_req_client = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); | ||
2179 | |||
2180 | cadet = GNUNET_CADET_connect (cfg); | ||
2181 | |||
2182 | GNUNET_assert (NULL != cadet); | ||
2183 | |||
2184 | GNUNET_SCHEDULER_add_shutdown (&shutdown_task, | ||
2185 | NULL); | ||
2186 | } | ||
2187 | |||
2188 | |||
2189 | /** | ||
2190 | * Define "main" method using service macro. | ||
2191 | */ | ||
2192 | GNUNET_SERVICE_MAIN | ||
2193 | ("multicast", | ||
2194 | GNUNET_SERVICE_OPTION_NONE, | ||
2195 | &run, | ||
2196 | &client_notify_connect, | ||
2197 | &client_notify_disconnect, | ||
2198 | NULL, | ||
2199 | GNUNET_MQ_hd_fixed_size (client_origin_start, | ||
2200 | GNUNET_MESSAGE_TYPE_MULTICAST_ORIGIN_START, | ||
2201 | struct MulticastOriginStartMessage, | ||
2202 | NULL), | ||
2203 | GNUNET_MQ_hd_var_size (client_member_join, | ||
2204 | GNUNET_MESSAGE_TYPE_MULTICAST_MEMBER_JOIN, | ||
2205 | struct MulticastMemberJoinMessage, | ||
2206 | NULL), | ||
2207 | GNUNET_MQ_hd_var_size (client_join_decision, | ||
2208 | GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION, | ||
2209 | struct MulticastJoinDecisionMessageHeader, | ||
2210 | NULL), | ||
2211 | GNUNET_MQ_hd_fixed_size (client_part_request, | ||
2212 | GNUNET_MESSAGE_TYPE_MULTICAST_PART_REQUEST, | ||
2213 | struct GNUNET_MessageHeader, | ||
2214 | NULL), | ||
2215 | GNUNET_MQ_hd_var_size (client_multicast_message, | ||
2216 | GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE, | ||
2217 | struct GNUNET_MULTICAST_MessageHeader, | ||
2218 | NULL), | ||
2219 | GNUNET_MQ_hd_var_size (client_multicast_request, | ||
2220 | GNUNET_MESSAGE_TYPE_MULTICAST_REQUEST, | ||
2221 | struct GNUNET_MULTICAST_RequestHeader, | ||
2222 | NULL), | ||
2223 | GNUNET_MQ_hd_fixed_size (client_replay_request, | ||
2224 | GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_REQUEST, | ||
2225 | struct MulticastReplayRequestMessage, | ||
2226 | NULL), | ||
2227 | GNUNET_MQ_hd_var_size (client_replay_response, | ||
2228 | GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE, | ||
2229 | struct MulticastReplayResponseMessage, | ||
2230 | NULL), | ||
2231 | GNUNET_MQ_hd_var_size (client_replay_response_end, | ||
2232 | GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE_END, | ||
2233 | struct MulticastReplayResponseMessage, | ||
2234 | NULL)); | ||
2235 | |||
2236 | /* end of gnunet-service-multicast.c */ | ||