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 | |
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
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | src/Makefile.am | 1 | ||||
-rw-r--r-- | src/include/gnunet_multicast_service.h | 925 | ||||
-rw-r--r-- | src/multicast/.gitignore | 7 | ||||
-rw-r--r-- | src/multicast/Makefile.am | 75 | ||||
-rw-r--r-- | src/multicast/gnunet-multicast.c | 79 | ||||
-rw-r--r-- | src/multicast/gnunet-service-multicast.c | 2236 | ||||
-rw-r--r-- | src/multicast/multicast.conf.in | 21 | ||||
-rw-r--r-- | src/multicast/multicast.h | 303 | ||||
-rw-r--r-- | src/multicast/multicast_api.c | 1399 | ||||
-rw-r--r-- | src/multicast/test_multicast.c | 758 | ||||
-rw-r--r-- | src/multicast/test_multicast_2peers.c | 520 | ||||
-rw-r--r-- | src/multicast/test_multicast_multipeer.c | 643 |
13 files changed, 6969 insertions, 0 deletions
diff --git a/configure.ac b/configure.ac index 20258d622..9b46874ab 100644 --- a/configure.ac +++ b/configure.ac | |||
@@ -1435,6 +1435,8 @@ src/abd/abd.conf | |||
1435 | src/reclaim/Makefile | 1435 | src/reclaim/Makefile |
1436 | src/messenger/Makefile | 1436 | src/messenger/Makefile |
1437 | src/messenger/messenger.conf | 1437 | src/messenger/messenger.conf |
1438 | src/multicast/Makefile | ||
1439 | src/multicast/multicast.conf | ||
1438 | pkgconfig/Makefile | 1440 | pkgconfig/Makefile |
1439 | pkgconfig/gnunetarm.pc | 1441 | pkgconfig/gnunetarm.pc |
1440 | pkgconfig/gnunetats.pc | 1442 | pkgconfig/gnunetats.pc |
diff --git a/src/Makefile.am b/src/Makefile.am index d7c0b51f0..b84d35b38 100644 --- a/src/Makefile.am +++ b/src/Makefile.am | |||
@@ -93,5 +93,6 @@ SUBDIRS = \ | |||
93 | secretsharing \ | 93 | secretsharing \ |
94 | reclaim \ | 94 | reclaim \ |
95 | messenger \ | 95 | messenger \ |
96 | multicast \ | ||
96 | $(EXP_DIR) \ | 97 | $(EXP_DIR) \ |
97 | integration-tests | 98 | integration-tests |
diff --git a/src/include/gnunet_multicast_service.h b/src/include/gnunet_multicast_service.h new file mode 100644 index 000000000..58fca0b2e --- /dev/null +++ b/src/include/gnunet_multicast_service.h | |||
@@ -0,0 +1,925 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2012, 2013 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 | * @author Gabor X Toth | ||
23 | * @author Christian Grothoff | ||
24 | * | ||
25 | * @file | ||
26 | * Multicast service; multicast messaging via CADET | ||
27 | * | ||
28 | * @defgroup multicast Multicast service | ||
29 | * Multicast messaging via CADET. | ||
30 | * @{ | ||
31 | */ | ||
32 | |||
33 | #ifndef GNUNET_MULTICAST_SERVICE_H | ||
34 | #define GNUNET_MULTICAST_SERVICE_H | ||
35 | |||
36 | #ifdef __cplusplus | ||
37 | extern "C" | ||
38 | { | ||
39 | #if 0 /* keep Emacsens' auto-indent happy */ | ||
40 | } | ||
41 | #endif | ||
42 | #endif | ||
43 | |||
44 | #include "gnunet_util_lib.h" | ||
45 | #include "gnunet_transport_service.h" | ||
46 | |||
47 | /** | ||
48 | * Version number of GNUnet-multicast API. | ||
49 | */ | ||
50 | #define GNUNET_MULTICAST_VERSION 0x00000000 | ||
51 | |||
52 | /** | ||
53 | * Opaque handle for a multicast group member. | ||
54 | */ | ||
55 | struct GNUNET_MULTICAST_Member; | ||
56 | |||
57 | /** | ||
58 | * Handle for the origin of a multicast group. | ||
59 | */ | ||
60 | struct GNUNET_MULTICAST_Origin; | ||
61 | |||
62 | |||
63 | enum GNUNET_MULTICAST_MessageFlags | ||
64 | { | ||
65 | /** | ||
66 | * First fragment of a message. | ||
67 | */ | ||
68 | GNUNET_MULTICAST_MESSAGE_FIRST_FRAGMENT = 1 << 0, | ||
69 | |||
70 | /** | ||
71 | * Last fragment of a message. | ||
72 | */ | ||
73 | GNUNET_MULTICAST_MESSAGE_LAST_FRAGMENT = 1 << 1, | ||
74 | |||
75 | /** | ||
76 | * OR'ed flags if message is not fragmented. | ||
77 | */ | ||
78 | GNUNET_MULTICAST_MESSAGE_NOT_FRAGMENTED | ||
79 | = GNUNET_MULTICAST_MESSAGE_FIRST_FRAGMENT | ||
80 | | GNUNET_MULTICAST_MESSAGE_LAST_FRAGMENT, | ||
81 | |||
82 | /** | ||
83 | * Historic message, used only locally when replaying messages from local | ||
84 | * storage. | ||
85 | */ | ||
86 | GNUNET_MULTICAST_MESSAGE_HISTORIC = 1 << 30 | ||
87 | |||
88 | }; | ||
89 | |||
90 | |||
91 | GNUNET_NETWORK_STRUCT_BEGIN | ||
92 | |||
93 | /** | ||
94 | * Header of a multicast message fragment. | ||
95 | * | ||
96 | * This format is public as the replay mechanism must replay message fragments using the | ||
97 | * same format. This is needed as we want to integrity-check message fragments within | ||
98 | * the multicast layer to avoid multicasting mal-formed messages. | ||
99 | */ | ||
100 | struct GNUNET_MULTICAST_MessageHeader | ||
101 | { | ||
102 | |||
103 | /** | ||
104 | * Header for all multicast message fragments from the origin. | ||
105 | */ | ||
106 | struct GNUNET_MessageHeader header; | ||
107 | |||
108 | /** | ||
109 | * Number of hops this message fragment has taken since the origin. | ||
110 | * | ||
111 | * Helpful to determine shortest paths to the origin among honest peers for | ||
112 | * unicast requests from members. Updated at each hop and thus not signed and | ||
113 | * not secure. | ||
114 | */ | ||
115 | uint32_t hop_counter GNUNET_PACKED; | ||
116 | |||
117 | /** | ||
118 | * ECC signature of the message fragment. | ||
119 | * | ||
120 | * Signature must match the public key of the multicast group. | ||
121 | */ | ||
122 | struct GNUNET_CRYPTO_EddsaSignature signature; | ||
123 | |||
124 | /** | ||
125 | * Purpose for the signature and size of the signed data. | ||
126 | */ | ||
127 | struct GNUNET_CRYPTO_EccSignaturePurpose purpose; | ||
128 | |||
129 | /** | ||
130 | * Number of the message fragment, monotonically increasing starting from 1. | ||
131 | */ | ||
132 | uint64_t fragment_id GNUNET_PACKED; | ||
133 | |||
134 | /** | ||
135 | * Byte offset of this @e fragment of the @e message. | ||
136 | */ | ||
137 | uint64_t fragment_offset GNUNET_PACKED; | ||
138 | |||
139 | /** | ||
140 | * Number of the message this fragment belongs to. | ||
141 | * | ||
142 | * Set in GNUNET_MULTICAST_origin_to_all(). | ||
143 | */ | ||
144 | uint64_t message_id GNUNET_PACKED; | ||
145 | |||
146 | /** | ||
147 | * Counter that monotonically increases whenever a member parts the group. | ||
148 | * | ||
149 | * Set in GNUNET_MULTICAST_origin_to_all(). | ||
150 | * | ||
151 | * It has significance in case of replay requests: when a member has missed | ||
152 | * messages and gets a replay request: in this case if the @a group_generation | ||
153 | * is still the same before and after the missed messages, it means that no | ||
154 | * @e join or @e part operations happened during the missed messages. | ||
155 | */ | ||
156 | uint64_t group_generation GNUNET_PACKED; | ||
157 | |||
158 | /** | ||
159 | * Flags for this message fragment. | ||
160 | * | ||
161 | * @see enum GNUNET_MULTICAST_MessageFlags | ||
162 | */ | ||
163 | uint32_t flags GNUNET_PACKED; | ||
164 | |||
165 | /* Followed by message body. */ | ||
166 | }; | ||
167 | |||
168 | |||
169 | /** | ||
170 | * Header of a request from a member to the origin. | ||
171 | */ | ||
172 | struct GNUNET_MULTICAST_RequestHeader | ||
173 | { | ||
174 | /** | ||
175 | * Header for all requests from a member to the origin. | ||
176 | */ | ||
177 | struct GNUNET_MessageHeader header; | ||
178 | |||
179 | /** | ||
180 | * Public key of the sending member. | ||
181 | */ | ||
182 | struct GNUNET_CRYPTO_EcdsaPublicKey member_pub_key; | ||
183 | |||
184 | /** | ||
185 | * ECC signature of the request fragment. | ||
186 | * | ||
187 | * Signature must match the public key of the multicast group. | ||
188 | */ | ||
189 | struct GNUNET_CRYPTO_EcdsaSignature signature; | ||
190 | |||
191 | /** | ||
192 | * Purpose for the signature and size of the signed data. | ||
193 | */ | ||
194 | struct GNUNET_CRYPTO_EccSignaturePurpose purpose; | ||
195 | |||
196 | /** | ||
197 | * Number of the request fragment. | ||
198 | * Monotonically increasing from 1. | ||
199 | */ | ||
200 | uint64_t fragment_id GNUNET_PACKED; | ||
201 | |||
202 | /** | ||
203 | * Byte offset of this @e fragment of the @e request. | ||
204 | */ | ||
205 | uint64_t fragment_offset GNUNET_PACKED; | ||
206 | |||
207 | /** | ||
208 | * Number of the request this fragment belongs to. | ||
209 | * | ||
210 | * Set in GNUNET_MULTICAST_origin_to_all(). | ||
211 | */ | ||
212 | uint64_t request_id GNUNET_PACKED; | ||
213 | |||
214 | /** | ||
215 | * Flags for this request. | ||
216 | */ | ||
217 | enum GNUNET_MULTICAST_MessageFlags flags GNUNET_PACKED; | ||
218 | |||
219 | /* Followed by request body. */ | ||
220 | }; | ||
221 | |||
222 | GNUNET_NETWORK_STRUCT_END | ||
223 | |||
224 | |||
225 | /** | ||
226 | * Maximum size of a multicast message fragment. | ||
227 | */ | ||
228 | #define GNUNET_MULTICAST_FRAGMENT_MAX_SIZE (63 * 1024) | ||
229 | |||
230 | #define GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD \ | ||
231 | (GNUNET_MULTICAST_FRAGMENT_MAX_SIZE \ | ||
232 | - sizeof (struct GNUNET_MULTICAST_MessageHeader)) | ||
233 | |||
234 | |||
235 | /** | ||
236 | * Handle that identifies a join request. | ||
237 | * | ||
238 | * Used to match calls to #GNUNET_MULTICAST_JoinRequestCallback to the | ||
239 | * corresponding calls to #GNUNET_MULTICAST_join_decision(). | ||
240 | */ | ||
241 | struct GNUNET_MULTICAST_JoinHandle; | ||
242 | |||
243 | |||
244 | /** | ||
245 | * Function to call with the decision made for a join request. | ||
246 | * | ||
247 | * Must be called once and only once in response to an invocation of the | ||
248 | * #GNUNET_MULTICAST_JoinRequestCallback. | ||
249 | * | ||
250 | * @param jh | ||
251 | * Join request handle. | ||
252 | * @param is_admitted | ||
253 | * #GNUNET_YES if the join is approved, | ||
254 | * #GNUNET_NO if it is disapproved, | ||
255 | * #GNUNET_SYSERR if we cannot answer the request. | ||
256 | * @param relay_count | ||
257 | * Number of relays given. | ||
258 | * @param relays | ||
259 | * Array of suggested peers that might be useful relays to use | ||
260 | * when joining the multicast group (essentially a list of peers that | ||
261 | * are already part of the multicast group and might thus be willing | ||
262 | * to help with routing). If empty, only this local peer (which must | ||
263 | * be the multicast origin) is a good candidate for building the | ||
264 | * multicast tree. Note that it is unnecessary to specify our own | ||
265 | * peer identity in this array. | ||
266 | * @param join_resp | ||
267 | * Message to send in response to the joining peer; | ||
268 | * can also be used to redirect the peer to a different group at the | ||
269 | * application layer; this response is to be transmitted to the | ||
270 | * peer that issued the request even if admission is denied. | ||
271 | */ | ||
272 | struct GNUNET_MULTICAST_ReplayHandle * | ||
273 | GNUNET_MULTICAST_join_decision (struct GNUNET_MULTICAST_JoinHandle *jh, | ||
274 | int is_admitted, | ||
275 | uint16_t relay_count, | ||
276 | const struct GNUNET_PeerIdentity *relays, | ||
277 | const struct GNUNET_MessageHeader *join_resp); | ||
278 | |||
279 | |||
280 | /** | ||
281 | * Method called whenever another peer wants to join the multicast group. | ||
282 | * | ||
283 | * Implementations of this function must call GNUNET_MULTICAST_join_decision() | ||
284 | * with the decision. | ||
285 | * | ||
286 | * @param cls | ||
287 | * Closure. | ||
288 | * @param member_pub_key | ||
289 | * Public key of the member requesting join. | ||
290 | * @param join_msg | ||
291 | * Application-dependent join message from the new member. | ||
292 | * @param jh | ||
293 | * Join handle to pass to GNUNET_MULTICAST_join_decison(). | ||
294 | */ | ||
295 | typedef void | ||
296 | (*GNUNET_MULTICAST_JoinRequestCallback) (void *cls, | ||
297 | const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key, | ||
298 | const struct GNUNET_MessageHeader *join_msg, | ||
299 | struct GNUNET_MULTICAST_JoinHandle *jh); | ||
300 | |||
301 | |||
302 | /** | ||
303 | * Method called to inform about the decision in response to a join request. | ||
304 | * | ||
305 | * If @a is_admitted is not #GNUNET_YES, then the multicast service disconnects | ||
306 | * the client and the multicast member handle returned by | ||
307 | * GNUNET_MULTICAST_member_join() is invalidated. | ||
308 | * | ||
309 | * @param cls | ||
310 | * Closure. | ||
311 | * @param is_admitted | ||
312 | * #GNUNET_YES or #GNUNET_NO or #GNUNET_SYSERR | ||
313 | * @param peer | ||
314 | * The peer we are connected to and the join decision is from. | ||
315 | * @param relay_count | ||
316 | * Number of peers in the @a relays array. | ||
317 | * @param relays | ||
318 | * Peer identities of members of the group, which serve as relays | ||
319 | * and can be used to join the group at. If empty, only the origin can | ||
320 | * be used to connect to the group. | ||
321 | * @param join_msg | ||
322 | * Application-dependent join message from the origin. | ||
323 | */ | ||
324 | typedef void | ||
325 | (*GNUNET_MULTICAST_JoinDecisionCallback) (void *cls, | ||
326 | int is_admitted, | ||
327 | const struct GNUNET_PeerIdentity *peer, | ||
328 | uint16_t relay_count, | ||
329 | const struct GNUNET_PeerIdentity *relays, | ||
330 | const struct GNUNET_MessageHeader *join_msg); | ||
331 | |||
332 | |||
333 | /** | ||
334 | * Function called whenever a group member has transmitted a request | ||
335 | * to the origin (other than joining or leaving). | ||
336 | * | ||
337 | * FIXME: need to distinguish between origin cancelling a message (some fragments | ||
338 | * were sent, then the rest 'discarded') and the case where we got disconnected; | ||
339 | * right now, both would mean 'msg' is NULL, but they could be quite different... | ||
340 | * So the semantics from the receiver side of | ||
341 | * GNUNET_MULTICAST_member_to_origin_cancel() are not clear here. Maybe we | ||
342 | * should do something with the flags in this case? | ||
343 | * | ||
344 | * @param cls | ||
345 | * Closure (set from GNUNET_MULTICAST_origin_start). | ||
346 | * @param sender | ||
347 | * Identity of the sender. | ||
348 | * @param req | ||
349 | * Request to the origin. | ||
350 | * @param flags | ||
351 | * Flags for the request. | ||
352 | */ | ||
353 | typedef void | ||
354 | (*GNUNET_MULTICAST_RequestCallback) (void *cls, | ||
355 | const struct GNUNET_MULTICAST_RequestHeader *req); | ||
356 | |||
357 | |||
358 | /** | ||
359 | * Function called whenever a group member is receiving a message fragment from | ||
360 | * the origin. | ||
361 | * | ||
362 | * If admission to the group is denied, this function is called once with the | ||
363 | * response of the @e origin (as given to GNUNET_MULTICAST_join_decision()) and | ||
364 | * then a second time with NULL to indicate that the connection failed for good. | ||
365 | * | ||
366 | * FIXME: need to distinguish between origin cancelling a message (some fragments | ||
367 | * were sent, then the rest 'discarded') and the case where we got disconnected; | ||
368 | * right now, both would mean 'msg' is NULL, but they could be quite different... | ||
369 | * So the semantics from the receiver side of | ||
370 | * GNUNET_MULTICAST_origin_to_all_cancel() are not clear here. | ||
371 | * | ||
372 | * @param cls | ||
373 | * Closure (set from GNUNET_MULTICAST_member_join()) | ||
374 | * @param msg | ||
375 | * Message from the origin, NULL if the origin shut down | ||
376 | * (or we were kicked out, and we should thus call | ||
377 | * GNUNET_MULTICAST_member_part() next) | ||
378 | */ | ||
379 | typedef void | ||
380 | (*GNUNET_MULTICAST_MessageCallback) (void *cls, | ||
381 | const struct GNUNET_MULTICAST_MessageHeader *msg); | ||
382 | |||
383 | |||
384 | /** | ||
385 | * Opaque handle to a replay request from the multicast service. | ||
386 | */ | ||
387 | struct GNUNET_MULTICAST_ReplayHandle; | ||
388 | |||
389 | |||
390 | /** | ||
391 | * Functions with this signature are called whenever the multicast service needs | ||
392 | * a message fragment to be replayed by fragment_id. | ||
393 | * | ||
394 | * Implementations of this function MUST call GNUNET_MULTICAST_replay() ONCE | ||
395 | * (with a message or an error); however, if the origin is destroyed or the | ||
396 | * group is left, the replay handle must no longer be used. | ||
397 | * | ||
398 | * @param cls | ||
399 | * Closure (set from GNUNET_MULTICAST_origin_start() | ||
400 | * or GNUNET_MULTICAST_member_join()). | ||
401 | * @param member_pub_key | ||
402 | * The member requesting replay. | ||
403 | * @param fragment_id | ||
404 | * Which message fragment should be replayed. | ||
405 | * @param flags | ||
406 | * Flags for the replay. | ||
407 | * @param rh | ||
408 | * Handle to pass to message transmit function. | ||
409 | */ | ||
410 | typedef void | ||
411 | (*GNUNET_MULTICAST_ReplayFragmentCallback) (void *cls, | ||
412 | const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key, | ||
413 | uint64_t fragment_id, | ||
414 | uint64_t flags, | ||
415 | struct GNUNET_MULTICAST_ReplayHandle *rh); | ||
416 | |||
417 | /** | ||
418 | * Functions with this signature are called whenever the multicast service needs | ||
419 | * a message fragment to be replayed by message_id and fragment_offset. | ||
420 | * | ||
421 | * Implementations of this function MUST call GNUNET_MULTICAST_replay() ONCE | ||
422 | * (with a message or an error); however, if the origin is destroyed or the | ||
423 | * group is left, the replay handle must no longer be used. | ||
424 | * | ||
425 | * @param cls | ||
426 | * Closure (set from GNUNET_MULTICAST_origin_start() | ||
427 | * or GNUNET_MULTICAST_member_join()). | ||
428 | * @param member_pub_key | ||
429 | * The member requesting replay. | ||
430 | * @param message_id | ||
431 | * Which message should be replayed. | ||
432 | * @param fragment_offset | ||
433 | * Offset of the fragment within of @a message_id to be replayed. | ||
434 | * @param flags | ||
435 | * Flags for the replay. | ||
436 | * @param rh | ||
437 | * Handle to pass to message transmit function. | ||
438 | */ | ||
439 | typedef void | ||
440 | (*GNUNET_MULTICAST_ReplayMessageCallback) (void *cls, | ||
441 | const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key, | ||
442 | uint64_t message_id, | ||
443 | uint64_t fragment_offset, | ||
444 | uint64_t flags, | ||
445 | struct GNUNET_MULTICAST_ReplayHandle *rh); | ||
446 | |||
447 | |||
448 | /** | ||
449 | * Possible error codes during replay. | ||
450 | */ | ||
451 | enum GNUNET_MULTICAST_ReplayErrorCode | ||
452 | { | ||
453 | |||
454 | /** | ||
455 | * Everything is fine. | ||
456 | */ | ||
457 | GNUNET_MULTICAST_REC_OK = 0, | ||
458 | |||
459 | /** | ||
460 | * Message fragment not found in the message store. | ||
461 | * | ||
462 | * Either discarded if it is too old, or not arrived yet if this member has | ||
463 | * missed some messages. | ||
464 | */ | ||
465 | GNUNET_MULTICAST_REC_NOT_FOUND = 1, | ||
466 | |||
467 | /** | ||
468 | * Fragment ID counter was larger than the highest counter this | ||
469 | * replay function has ever encountered; thus it is likely the | ||
470 | * origin never sent it and we're at the HEAD of the multicast | ||
471 | * stream as far as this node is concerned. | ||
472 | * | ||
473 | * FIXME: needed? | ||
474 | */ | ||
475 | GNUNET_MULTICAST_REC_PAST_HEAD = 2, | ||
476 | |||
477 | /** | ||
478 | * Access is denied to the requested fragment, membership test did not pass. | ||
479 | */ | ||
480 | GNUNET_MULTICAST_REC_ACCESS_DENIED = 3, | ||
481 | |||
482 | /** | ||
483 | * Internal error (i.e. database error). Try some other peer. | ||
484 | */ | ||
485 | GNUNET_MULTICAST_REC_INTERNAL_ERROR = 4 | ||
486 | |||
487 | }; | ||
488 | |||
489 | |||
490 | /** | ||
491 | * Replay a message fragment for the multicast group. | ||
492 | * | ||
493 | * @param rh | ||
494 | * Replay handle identifying which replay operation was requested. | ||
495 | * @param msg | ||
496 | * Replayed message fragment, NULL if not found / an error occurred. | ||
497 | * @param ec | ||
498 | * Error code. See enum GNUNET_MULTICAST_ReplayErrorCode | ||
499 | * If not #GNUNET_MULTICAST_REC_OK, the replay handle is invalidated. | ||
500 | */ | ||
501 | void | ||
502 | GNUNET_MULTICAST_replay_response (struct GNUNET_MULTICAST_ReplayHandle *rh, | ||
503 | const struct GNUNET_MessageHeader *msg, | ||
504 | enum GNUNET_MULTICAST_ReplayErrorCode ec); | ||
505 | |||
506 | |||
507 | /** | ||
508 | * Indicate the end of the replay session. | ||
509 | * | ||
510 | * Invalidates the replay handle. | ||
511 | * | ||
512 | * @param rh Replay session to end. | ||
513 | */ | ||
514 | void | ||
515 | GNUNET_MULTICAST_replay_response_end (struct GNUNET_MULTICAST_ReplayHandle *rh); | ||
516 | |||
517 | |||
518 | /** | ||
519 | * Function called to provide data for a transmission for a replay. | ||
520 | * | ||
521 | * @see GNUNET_MULTICAST_replay2() | ||
522 | */ | ||
523 | typedef int | ||
524 | (*GNUNET_MULTICAST_ReplayTransmitNotify) (void *cls, | ||
525 | size_t *data_size, | ||
526 | void *data); | ||
527 | |||
528 | |||
529 | /** | ||
530 | * Replay a message for the multicast group. | ||
531 | * | ||
532 | * @param rh | ||
533 | * Replay handle identifying which replay operation was requested. | ||
534 | * @param notify | ||
535 | * Function to call to get the message. | ||
536 | * @param notify_cls | ||
537 | * Closure for @a notify. | ||
538 | */ | ||
539 | void | ||
540 | GNUNET_MULTICAST_replay_response2 (struct GNUNET_MULTICAST_ReplayHandle *rh, | ||
541 | GNUNET_MULTICAST_ReplayTransmitNotify notify, | ||
542 | void *notify_cls); | ||
543 | |||
544 | |||
545 | /** | ||
546 | * Start a multicast group. | ||
547 | * | ||
548 | * Peers that issue GNUNET_MULTICAST_member_join() can transmit a join request | ||
549 | * to either an existing group member or to the origin. If the joining is | ||
550 | * approved, the member is cleared for @e replay and will begin to receive | ||
551 | * messages transmitted to the group. If joining is disapproved, the failed | ||
552 | * candidate will be given a response. Members in the group can send messages | ||
553 | * to the origin. | ||
554 | * | ||
555 | * TODO: This function could optionally offer to advertise the origin in the | ||
556 | * P2P overlay network(where?) under the respective public key so that other | ||
557 | * peers can find an alternate PeerId to join it. Higher level protocols may | ||
558 | * however provide other means of solving the problem of the offline host | ||
559 | * (see secushare specs about that) and therefore merely need a way to provide | ||
560 | * a list of possible PeerIds. | ||
561 | * | ||
562 | * @param cfg | ||
563 | * Configuration to use. | ||
564 | * @param priv_key | ||
565 | * ECC key that will be used to sign messages for this | ||
566 | * multicast session; public key is used to identify the multicast group; | ||
567 | * @param max_fragment_id | ||
568 | * Maximum fragment ID already sent to the group. | ||
569 | * 0 for a new group. | ||
570 | * @param join_request_cb | ||
571 | * Function called to approve / disapprove joining of a peer. | ||
572 | * @param replay_frag_cb | ||
573 | * Function that can be called to replay a message fragment. | ||
574 | * @param replay_msg_cb | ||
575 | * Function that can be called to replay a message. | ||
576 | * @param request_cb | ||
577 | * Function called with message fragments from group members. | ||
578 | * @param message_cb | ||
579 | * Function called with the message fragments sent to the | ||
580 | * network by GNUNET_MULTICAST_origin_to_all(). These message fragments | ||
581 | * should be stored for answering replay requests later. | ||
582 | * @param cls | ||
583 | * Closure for the various callbacks that follow. | ||
584 | * | ||
585 | * @return Handle for the origin, NULL on error. | ||
586 | */ | ||
587 | struct GNUNET_MULTICAST_Origin * | ||
588 | GNUNET_MULTICAST_origin_start (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
589 | const struct GNUNET_CRYPTO_EddsaPrivateKey *priv_key, | ||
590 | uint64_t max_fragment_id, | ||
591 | GNUNET_MULTICAST_JoinRequestCallback join_request_cb, | ||
592 | GNUNET_MULTICAST_ReplayFragmentCallback replay_frag_cb, | ||
593 | GNUNET_MULTICAST_ReplayMessageCallback replay_msg_cb, | ||
594 | GNUNET_MULTICAST_RequestCallback request_cb, | ||
595 | GNUNET_MULTICAST_MessageCallback message_cb, | ||
596 | void *cls); | ||
597 | |||
598 | /** | ||
599 | * Function called to provide data for a transmission from the origin to all | ||
600 | * members. | ||
601 | * | ||
602 | * Note that returning #GNUNET_OK or #GNUNET_SYSERR (but not #GNUNET_NO) | ||
603 | * invalidates the respective transmission handle. | ||
604 | * | ||
605 | * @param cls | ||
606 | * Closure. | ||
607 | * @param[in,out] data_size | ||
608 | * Initially set to the number of bytes available in | ||
609 | * @a data, should be set to the number of bytes written to data. | ||
610 | * @param[out] data | ||
611 | * Where to write the body of the message to give to the | ||
612 | * method. The function must copy at most @a data_size bytes to @a data. | ||
613 | * | ||
614 | * @return #GNUNET_SYSERR on error (fatal, aborts transmission) | ||
615 | * #GNUNET_NO on success, if more data is to be transmitted later. | ||
616 | * Should be used if @a data_size was not big enough to take all the | ||
617 | * data. If 0 is returned in @a data_size the transmission is paused, | ||
618 | * and can be resumed with GNUNET_MULTICAST_origin_to_all_resume(). | ||
619 | * #GNUNET_YES if this completes the transmission (all data supplied) | ||
620 | * @deprecated should move to MQ-style API! | ||
621 | */ | ||
622 | typedef int | ||
623 | (*GNUNET_MULTICAST_OriginTransmitNotify) (void *cls, | ||
624 | size_t *data_size, | ||
625 | void *data); | ||
626 | |||
627 | |||
628 | /** | ||
629 | * Handle for a request to send a message to all multicast group members | ||
630 | * (from the origin). | ||
631 | */ | ||
632 | struct GNUNET_MULTICAST_OriginTransmitHandle; | ||
633 | |||
634 | |||
635 | /** | ||
636 | * Send a message to the multicast group. | ||
637 | * | ||
638 | * @param origin | ||
639 | * Handle to the multicast group. | ||
640 | * @param message_id | ||
641 | * Application layer ID for the message. Opaque to multicast. | ||
642 | * @param group_generation | ||
643 | * Group generation of the message. Documented in | ||
644 | * struct GNUNET_MULTICAST_MessageHeader. | ||
645 | * @param notify | ||
646 | * Function to call to get the message. | ||
647 | * @param notify_cls | ||
648 | * Closure for @a notify. | ||
649 | * | ||
650 | * @return NULL on error (i.e. request already pending). | ||
651 | * @deprecated should move to MQ-style API! | ||
652 | */ | ||
653 | struct GNUNET_MULTICAST_OriginTransmitHandle * | ||
654 | GNUNET_MULTICAST_origin_to_all (struct GNUNET_MULTICAST_Origin *origin, | ||
655 | uint64_t message_id, | ||
656 | uint64_t group_generation, | ||
657 | GNUNET_MULTICAST_OriginTransmitNotify notify, | ||
658 | void *notify_cls); | ||
659 | |||
660 | |||
661 | |||
662 | /** | ||
663 | * Resume message transmission to multicast group. | ||
664 | * | ||
665 | * @param th Transmission to cancel. | ||
666 | */ | ||
667 | void | ||
668 | GNUNET_MULTICAST_origin_to_all_resume (struct GNUNET_MULTICAST_OriginTransmitHandle *th); | ||
669 | |||
670 | |||
671 | /** | ||
672 | * Cancel request for message transmission to multicast group. | ||
673 | * | ||
674 | * @param th Transmission to cancel. | ||
675 | */ | ||
676 | void | ||
677 | GNUNET_MULTICAST_origin_to_all_cancel (struct GNUNET_MULTICAST_OriginTransmitHandle *th); | ||
678 | |||
679 | |||
680 | /** | ||
681 | * Stop a multicast group. | ||
682 | * | ||
683 | * @param origin Multicast group to stop. | ||
684 | */ | ||
685 | void | ||
686 | GNUNET_MULTICAST_origin_stop (struct GNUNET_MULTICAST_Origin *origin, | ||
687 | GNUNET_ContinuationCallback stop_cb, | ||
688 | void *stop_cls); | ||
689 | |||
690 | |||
691 | /** | ||
692 | * Join a multicast group. | ||
693 | * | ||
694 | * The entity joining is always the local peer. Further information about the | ||
695 | * candidate can be provided in @a join_msg. If the join fails, the | ||
696 | * @a message_cb is invoked with a (failure) response and then with NULL. If | ||
697 | * the join succeeds, outstanding (state) messages and ongoing multicast | ||
698 | * messages will be given to the @a message_cb until the member decides to part | ||
699 | * the group. The @a mem_test_cb and @a replay_cb functions may be called at | ||
700 | * anytime by the multicast service to support relaying messages to other | ||
701 | * members of the group. | ||
702 | * | ||
703 | * @param cfg | ||
704 | * Configuration to use. | ||
705 | * @param group_key | ||
706 | * ECC public key that identifies the group to join. | ||
707 | * @param member_pub_key | ||
708 | * ECC key that identifies the member | ||
709 | * and used to sign requests sent to the origin. | ||
710 | * @param origin | ||
711 | * Peer ID of the origin to send unicast requsets to. If NULL, | ||
712 | * unicast requests are sent back via multiple hops on the reverse path | ||
713 | * of multicast messages. | ||
714 | * @param relay_count | ||
715 | * Number of peers in the @a relays array. | ||
716 | * @param relays | ||
717 | * Peer identities of members of the group, which serve as relays | ||
718 | * and can be used to join the group at. and send the @a join_request to. | ||
719 | * If empty, the @a join_request is sent directly to the @a origin. | ||
720 | * @param join_msg | ||
721 | * Application-dependent join message to be passed to the peer @a origin. | ||
722 | * @param join_request_cb | ||
723 | * Function called to approve / disapprove joining of a peer. | ||
724 | * @param join_decision_cb | ||
725 | * Function called to inform about the join decision. | ||
726 | * @param replay_frag_cb | ||
727 | * Function that can be called to replay message fragments | ||
728 | * this peer already knows from this group. NULL if this | ||
729 | * client is unable to support replay. | ||
730 | * @param replay_msg_cb | ||
731 | * Function that can be called to replay message fragments | ||
732 | * this peer already knows from this group. NULL if this | ||
733 | * client is unable to support replay. | ||
734 | * @param message_cb | ||
735 | * Function to be called for all message fragments we | ||
736 | * receive from the group, excluding those our @a replay_cb | ||
737 | * already has. | ||
738 | * @param cls | ||
739 | * Closure for callbacks. | ||
740 | * | ||
741 | * @return Handle for the member, NULL on error. | ||
742 | */ | ||
743 | struct GNUNET_MULTICAST_Member * | ||
744 | GNUNET_MULTICAST_member_join (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
745 | const struct GNUNET_CRYPTO_EddsaPublicKey *group_key, | ||
746 | const struct GNUNET_CRYPTO_EcdsaPrivateKey *member_pub_key, | ||
747 | const struct GNUNET_PeerIdentity *origin, | ||
748 | uint16_t relay_count, | ||
749 | const struct GNUNET_PeerIdentity *relays, | ||
750 | const struct GNUNET_MessageHeader *join_request, | ||
751 | GNUNET_MULTICAST_JoinRequestCallback join_request_cb, | ||
752 | GNUNET_MULTICAST_JoinDecisionCallback join_decision_cb, | ||
753 | GNUNET_MULTICAST_ReplayFragmentCallback replay_frag_cb, | ||
754 | GNUNET_MULTICAST_ReplayMessageCallback replay_msg_cb, | ||
755 | GNUNET_MULTICAST_MessageCallback message_cb, | ||
756 | void *cls); | ||
757 | |||
758 | /** | ||
759 | * Handle for a replay request. | ||
760 | */ | ||
761 | struct GNUNET_MULTICAST_MemberReplayHandle; | ||
762 | |||
763 | |||
764 | /** | ||
765 | * Request a fragment to be replayed by fragment ID. | ||
766 | * | ||
767 | * Useful if messages below the @e max_known_fragment_id given when joining are | ||
768 | * needed and not known to the client. | ||
769 | * | ||
770 | * @param member | ||
771 | * Membership handle. | ||
772 | * @param fragment_id | ||
773 | * ID of a message fragment that this client would like to see replayed. | ||
774 | * @param flags | ||
775 | * Additional flags for the replay request. | ||
776 | * It is used and defined by GNUNET_MULTICAST_ReplayFragmentCallback | ||
777 | * | ||
778 | * @return Replay request handle, NULL on error. | ||
779 | */ | ||
780 | struct GNUNET_MULTICAST_MemberReplayHandle * | ||
781 | GNUNET_MULTICAST_member_replay_fragment (struct GNUNET_MULTICAST_Member *member, | ||
782 | uint64_t fragment_id, | ||
783 | uint64_t flags); | ||
784 | |||
785 | |||
786 | /** | ||
787 | * Request a message fr to be replayed. | ||
788 | * | ||
789 | * Useful if messages below the @e max_known_fragment_id given when joining are | ||
790 | * needed and not known to the client. | ||
791 | * | ||
792 | * @param member | ||
793 | * Membership handle. | ||
794 | * @param message_id | ||
795 | * ID of the message this client would like to see replayed. | ||
796 | * @param fragment_offset | ||
797 | * Offset of the fragment within the message to replay. | ||
798 | * @param flags | ||
799 | * Additional flags for the replay request. | ||
800 | * It is used & defined by GNUNET_MULTICAST_ReplayMessageCallback | ||
801 | * | ||
802 | * @return Replay request handle, NULL on error. | ||
803 | */ | ||
804 | struct GNUNET_MULTICAST_MemberReplayHandle * | ||
805 | GNUNET_MULTICAST_member_replay_message (struct GNUNET_MULTICAST_Member *member, | ||
806 | uint64_t message_id, | ||
807 | uint64_t fragment_offset, | ||
808 | uint64_t flags); | ||
809 | |||
810 | |||
811 | /** | ||
812 | * Cancel a replay request. | ||
813 | * | ||
814 | * @param rh | ||
815 | * Request to cancel. | ||
816 | */ | ||
817 | void | ||
818 | GNUNET_MULTICAST_member_replay_cancel (struct GNUNET_MULTICAST_MemberReplayHandle *rh); | ||
819 | |||
820 | |||
821 | /** | ||
822 | * Part a multicast group. | ||
823 | * | ||
824 | * Disconnects from all group members and invalidates the @a member handle. | ||
825 | * | ||
826 | * An application-dependent part message can be transmitted beforehand using | ||
827 | * #GNUNET_MULTICAST_member_to_origin()) | ||
828 | * | ||
829 | * @param member | ||
830 | * Membership handle. | ||
831 | */ | ||
832 | void | ||
833 | GNUNET_MULTICAST_member_part (struct GNUNET_MULTICAST_Member *member, | ||
834 | GNUNET_ContinuationCallback part_cb, | ||
835 | void *part_cls); | ||
836 | |||
837 | |||
838 | /** | ||
839 | * Function called to provide data for a transmission from a member to the origin. | ||
840 | * | ||
841 | * Note that returning #GNUNET_OK or #GNUNET_SYSERR (but not #GNUNET_NO) | ||
842 | * invalidates the respective transmission handle. | ||
843 | * | ||
844 | * @param cls | ||
845 | * Closure. | ||
846 | * @param[in,out] data_size | ||
847 | * Initially set to the number of bytes available in | ||
848 | * @a data, should be set to the number of bytes written to data. | ||
849 | * @param[out] data | ||
850 | * Where to write the body of the message to give to the | ||
851 | * method. The function must copy at most @a data_size bytes to @a data. | ||
852 | * | ||
853 | * @return #GNUNET_SYSERR on error (fatal, aborts transmission) | ||
854 | * #GNUNET_NO on success, if more data is to be transmitted later. | ||
855 | * Should be used if @a data_size was not big enough to take all the | ||
856 | * data. If 0 is returned in @a data_size the transmission is paused, | ||
857 | * and can be resumed with GNUNET_MULTICAST_member_to_origin_resume(). | ||
858 | * #GNUNET_YES if this completes the transmission (all data supplied) | ||
859 | * @deprecated should move to MQ-style API! | ||
860 | */ | ||
861 | typedef int | ||
862 | (*GNUNET_MULTICAST_MemberTransmitNotify) (void *cls, | ||
863 | size_t *data_size, | ||
864 | void *data); | ||
865 | |||
866 | |||
867 | /** | ||
868 | * Handle for a message to be delivered from a member to the origin. | ||
869 | */ | ||
870 | struct GNUNET_MULTICAST_MemberTransmitHandle; | ||
871 | |||
872 | |||
873 | /** | ||
874 | * Send a message to the origin of the multicast group. | ||
875 | * | ||
876 | * @param member | ||
877 | * Membership handle. | ||
878 | * @param request_id | ||
879 | * Application layer ID for the request. Opaque to multicast. | ||
880 | * @param notify | ||
881 | * Callback to call to get the message. | ||
882 | * @param notify_cls | ||
883 | * Closure for @a notify. | ||
884 | * | ||
885 | * @return Handle to cancel request, NULL on error (i.e. request already pending). | ||
886 | * @deprecated should move to MQ-style API! | ||
887 | */ | ||
888 | struct GNUNET_MULTICAST_MemberTransmitHandle * | ||
889 | GNUNET_MULTICAST_member_to_origin (struct GNUNET_MULTICAST_Member *member, | ||
890 | uint64_t request_id, | ||
891 | GNUNET_MULTICAST_MemberTransmitNotify notify, | ||
892 | void *notify_cls); | ||
893 | |||
894 | |||
895 | /** | ||
896 | * Resume message transmission to origin. | ||
897 | * | ||
898 | * @param th | ||
899 | * Transmission to cancel. | ||
900 | */ | ||
901 | void | ||
902 | GNUNET_MULTICAST_member_to_origin_resume (struct GNUNET_MULTICAST_MemberTransmitHandle *th); | ||
903 | |||
904 | |||
905 | /** | ||
906 | * Cancel request for message transmission to origin. | ||
907 | * | ||
908 | * @param th | ||
909 | * Transmission to cancel. | ||
910 | */ | ||
911 | void | ||
912 | GNUNET_MULTICAST_member_to_origin_cancel (struct GNUNET_MULTICAST_MemberTransmitHandle *th); | ||
913 | |||
914 | |||
915 | #if 0 /* keep Emacsens' auto-indent happy */ | ||
916 | { | ||
917 | #endif | ||
918 | #ifdef __cplusplus | ||
919 | } | ||
920 | #endif | ||
921 | |||
922 | /* ifndef GNUNET_MULTICAST_SERVICE_H */ | ||
923 | #endif | ||
924 | |||
925 | /** @} */ /* end of group */ | ||
diff --git a/src/multicast/.gitignore b/src/multicast/.gitignore new file mode 100644 index 000000000..a97844e81 --- /dev/null +++ b/src/multicast/.gitignore | |||
@@ -0,0 +1,7 @@ | |||
1 | gnunet-service-multicast | ||
2 | gnunet-multicast | ||
3 | test_multicast | ||
4 | test_multicast_multipeer | ||
5 | test_multicast_2peers | ||
6 | test_multicast_multipeer_line | ||
7 | test_multicast_multipeer_star | ||
diff --git a/src/multicast/Makefile.am b/src/multicast/Makefile.am new file mode 100644 index 000000000..0e1c77c41 --- /dev/null +++ b/src/multicast/Makefile.am | |||
@@ -0,0 +1,75 @@ | |||
1 | # This Makefile.am is in the public domain | ||
2 | AM_CPPFLAGS = -I$(top_srcdir)/src/include \ | ||
3 | $(GNUNET_CPPFLAGS) | ||
4 | pkgcfgdir= $(pkgdatadir)/config.d/ | ||
5 | |||
6 | libexecdir= $(pkglibdir)/libexec/ | ||
7 | |||
8 | pkgcfg_DATA = \ | ||
9 | multicast.conf | ||
10 | |||
11 | if USE_COVERAGE | ||
12 | AM_CFLAGS = -fprofile-arcs -ftest-coverage | ||
13 | endif | ||
14 | |||
15 | lib_LTLIBRARIES = libgnunetmulticast.la | ||
16 | |||
17 | libgnunetmulticast_la_SOURCES = \ | ||
18 | multicast_api.c multicast.h | ||
19 | libgnunetmulticast_la_LIBADD = \ | ||
20 | -lgnunetutil \ | ||
21 | $(GN_LIBINTL) $(XLIB) | ||
22 | libgnunetmulticast_la_LDFLAGS = \ | ||
23 | $(GN_LIB_LDFLAGS) $(WINFLAGS) \ | ||
24 | -version-info 0:0:0 | ||
25 | |||
26 | |||
27 | bin_PROGRAMS = \ | ||
28 | gnunet-multicast | ||
29 | |||
30 | libexec_PROGRAMS = \ | ||
31 | gnunet-service-multicast \ | ||
32 | $(EXP_LIBEXEC) | ||
33 | |||
34 | gnunet_multicast_SOURCES = \ | ||
35 | gnunet-multicast.c | ||
36 | gnunet_multicast_LDADD = \ | ||
37 | -lgnunetutil \ | ||
38 | $(GN_LIBINTL) | ||
39 | |||
40 | gnunet_service_multicast_SOURCES = \ | ||
41 | gnunet-service-multicast.c | ||
42 | gnunet_service_multicast_LDADD = \ | ||
43 | -lgnunetutil \ | ||
44 | -lgnunetcadet \ | ||
45 | -lgnunetstatistics \ | ||
46 | $(GN_LIBINTL) | ||
47 | |||
48 | check_PROGRAMS = \ | ||
49 | test_multicast \ | ||
50 | test_multicast_multipeer_star \ | ||
51 | test_multicast_multipeer_line | ||
52 | |||
53 | if ENABLE_TEST_RUN | ||
54 | AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@}; export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; unset XDG_DATA_HOME; unset XDG_CONFIG_HOME; | ||
55 | TESTS = $(check_PROGRAMS) | ||
56 | endif | ||
57 | |||
58 | test_multicast_SOURCES = \ | ||
59 | test_multicast.c | ||
60 | test_multicast_LDADD = \ | ||
61 | libgnunetmulticast.la \ | ||
62 | -lgnunettesting \ | ||
63 | -lgnunetutil | ||
64 | test_multicast_multipeer_star_SOURCES = \ | ||
65 | test_multicast_multipeer.c | ||
66 | test_multicast_multipeer_star_LDADD = \ | ||
67 | libgnunetmulticast.la \ | ||
68 | -lgnunettestbed \ | ||
69 | -lgnunetutil | ||
70 | test_multicast_multipeer_line_SOURCES = \ | ||
71 | test_multicast_multipeer.c | ||
72 | test_multicast_multipeer_line_LDADD = \ | ||
73 | libgnunetmulticast.la \ | ||
74 | -lgnunettestbed \ | ||
75 | -lgnunetutil | ||
diff --git a/src/multicast/gnunet-multicast.c b/src/multicast/gnunet-multicast.c new file mode 100644 index 000000000..802600487 --- /dev/null +++ b/src/multicast/gnunet-multicast.c | |||
@@ -0,0 +1,79 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2013 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-multicast.c | ||
23 | * @brief multicast for writing a tool | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet_util_lib.h" | ||
28 | /* #include "gnunet_multicast_service.h" */ | ||
29 | |||
30 | /** | ||
31 | * Final status code. | ||
32 | */ | ||
33 | static int ret; | ||
34 | |||
35 | /** | ||
36 | * Main function that will be run by the scheduler. | ||
37 | * | ||
38 | * @param cls closure | ||
39 | * @param args remaining command-line arguments | ||
40 | * @param cfgfile name of the configuration file used (for saving, can be NULL!) | ||
41 | * @param cfg configuration | ||
42 | */ | ||
43 | static void | ||
44 | run (void *cls, char *const *args, const char *cfgfile, | ||
45 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
46 | { | ||
47 | /* main code here */ | ||
48 | puts( gettext_noop ("This command doesn't do anything yet.") ); | ||
49 | ret = -1; | ||
50 | } | ||
51 | |||
52 | |||
53 | /** | ||
54 | * The main function. | ||
55 | * | ||
56 | * @param argc number of arguments from the command line | ||
57 | * @param argv command line arguments | ||
58 | * @return 0 ok, 1 on error | ||
59 | */ | ||
60 | int | ||
61 | main (int argc, char *const *argv) | ||
62 | { | ||
63 | static const struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
64 | /* FIMXE: add options here */ | ||
65 | GNUNET_GETOPT_OPTION_END | ||
66 | }; | ||
67 | if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) | ||
68 | return 2; | ||
69 | |||
70 | ret = (GNUNET_OK == | ||
71 | GNUNET_PROGRAM_run (argc, argv, "gnunet-multicast", | ||
72 | gettext_noop ("This command doesn't do anything yet."), | ||
73 | options, &run, | ||
74 | NULL)) ? ret : 1; | ||
75 | //XXX GNUNET_free ((void*) argv); | ||
76 | return ret; | ||
77 | } | ||
78 | |||
79 | /* end of gnunet-multicast.c */ | ||
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 */ | ||
diff --git a/src/multicast/multicast.conf.in b/src/multicast/multicast.conf.in new file mode 100644 index 000000000..df255e26d --- /dev/null +++ b/src/multicast/multicast.conf.in | |||
@@ -0,0 +1,21 @@ | |||
1 | [multicast] | ||
2 | START_ON_DEMAND = @START_ON_DEMAND@ | ||
3 | BINARY = gnunet-service-multicast | ||
4 | |||
5 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-multicast.sock | ||
6 | UNIX_MATCH_UID = YES | ||
7 | UNIX_MATCH_GID = YES | ||
8 | |||
9 | HOSTNAME = localhost | ||
10 | ACCEPT_FROM = 127.0.0.1; | ||
11 | ACCEPT_FROM6 = ::1; | ||
12 | |||
13 | # DISABLE_SOCKET_FORWARDING = NO | ||
14 | # USERNAME = | ||
15 | # MAXBUF = | ||
16 | # TIMEOUT = | ||
17 | # DISABLEV6 = | ||
18 | # BINDTO = | ||
19 | # REJECT_FROM = | ||
20 | # REJECT_FROM6 = | ||
21 | # PREFIX = | ||
diff --git a/src/multicast/multicast.h b/src/multicast/multicast.h new file mode 100644 index 000000000..8a3ca14c8 --- /dev/null +++ b/src/multicast/multicast.h | |||
@@ -0,0 +1,303 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2012, 2013 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/multicast.h | ||
23 | * @brief multicast IPC messages | ||
24 | * @author Christian Grothoff | ||
25 | * @author Gabor X Toth | ||
26 | */ | ||
27 | #ifndef MULTICAST_H | ||
28 | #define MULTICAST_H | ||
29 | |||
30 | #include "platform.h" | ||
31 | #include "gnunet_multicast_service.h" | ||
32 | |||
33 | GNUNET_NETWORK_STRUCT_BEGIN | ||
34 | |||
35 | |||
36 | /** | ||
37 | * Header of a join request sent to the origin or another member. | ||
38 | */ | ||
39 | struct MulticastJoinRequestMessage | ||
40 | { | ||
41 | /** | ||
42 | * Type: GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_REQUEST | ||
43 | */ | ||
44 | struct GNUNET_MessageHeader header; | ||
45 | |||
46 | /** | ||
47 | * Always zero. | ||
48 | */ | ||
49 | uint32_t reserved; | ||
50 | |||
51 | /** | ||
52 | * ECC signature of the rest of the fields of the join request. | ||
53 | * | ||
54 | * Signature must match the public key of the joining member. | ||
55 | */ | ||
56 | struct GNUNET_CRYPTO_EcdsaSignature signature; | ||
57 | |||
58 | /** | ||
59 | * Purpose for the signature and size of the signed data. | ||
60 | */ | ||
61 | struct GNUNET_CRYPTO_EccSignaturePurpose purpose; | ||
62 | |||
63 | /** | ||
64 | * Public key of the target group. | ||
65 | */ | ||
66 | struct GNUNET_CRYPTO_EddsaPublicKey group_pub_key; | ||
67 | |||
68 | /** | ||
69 | * Public key of the joining member. | ||
70 | */ | ||
71 | struct GNUNET_CRYPTO_EcdsaPublicKey member_pub_key; | ||
72 | |||
73 | /** | ||
74 | * Peer identity of the joining member. | ||
75 | */ | ||
76 | struct GNUNET_PeerIdentity peer; | ||
77 | |||
78 | /* Followed by struct GNUNET_MessageHeader join_message */ | ||
79 | }; | ||
80 | |||
81 | |||
82 | /** | ||
83 | * Header of a join decision message sent to a peer requesting join. | ||
84 | */ | ||
85 | struct MulticastJoinDecisionMessage | ||
86 | { | ||
87 | /** | ||
88 | * Type: GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION | ||
89 | */ | ||
90 | struct GNUNET_MessageHeader header; | ||
91 | |||
92 | /** | ||
93 | * #GNUNET_YES if the peer was admitted | ||
94 | * #GNUNET_NO if entry was refused, | ||
95 | * #GNUNET_SYSERR if the request could not be answered. | ||
96 | */ | ||
97 | int32_t is_admitted; | ||
98 | |||
99 | /** | ||
100 | * Number of relays given. | ||
101 | */ | ||
102 | uint32_t relay_count; | ||
103 | |||
104 | /* Followed by relay_count peer identities */ | ||
105 | |||
106 | /* Followed by the join response message */ | ||
107 | }; | ||
108 | |||
109 | |||
110 | /** | ||
111 | * Header added to a struct MulticastJoinDecisionMessage | ||
112 | * when sent between the client and service. | ||
113 | */ | ||
114 | struct MulticastJoinDecisionMessageHeader | ||
115 | { | ||
116 | /** | ||
117 | * Type: GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION | ||
118 | */ | ||
119 | struct GNUNET_MessageHeader header; | ||
120 | |||
121 | /** | ||
122 | * C->S: Peer to send the join decision to. | ||
123 | * S->C: Peer we received the join decision from. | ||
124 | */ | ||
125 | struct GNUNET_PeerIdentity peer; | ||
126 | |||
127 | /** | ||
128 | * C->S: Public key of the member requesting join. | ||
129 | * S->C: Unused. | ||
130 | */ | ||
131 | struct GNUNET_CRYPTO_EcdsaPublicKey member_pub_key; | ||
132 | |||
133 | /* Followed by struct MulticastJoinDecisionMessage */ | ||
134 | }; | ||
135 | |||
136 | |||
137 | /** | ||
138 | * Message sent from the client to the service to notify the service | ||
139 | * about the result of a membership test. | ||
140 | */ | ||
141 | struct MulticastMembershipTestResultMessage | ||
142 | { | ||
143 | /** | ||
144 | * Type: GNUNET_MESSAGE_TYPE_MULTICAST_MEMBERSHIP_TEST_RESULT | ||
145 | */ | ||
146 | struct GNUNET_MessageHeader header; | ||
147 | |||
148 | /** | ||
149 | * Unique ID that identifies the associated membership test. | ||
150 | */ | ||
151 | uint32_t uid; | ||
152 | |||
153 | /** | ||
154 | * #GNUNET_YES if the peer is a member | ||
155 | * #GNUNET_NO if peer is not a member, | ||
156 | * #GNUNET_SYSERR if the test could not be answered. | ||
157 | */ | ||
158 | int32_t is_admitted; | ||
159 | }; | ||
160 | |||
161 | |||
162 | /** | ||
163 | * Message sent from the client to the service OR the service to the | ||
164 | * client asking for a message fragment to be replayed. | ||
165 | */ | ||
166 | struct MulticastReplayRequestMessage | ||
167 | { | ||
168 | |||
169 | /** | ||
170 | * The message type should be | ||
171 | * #GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_REQUEST. | ||
172 | */ | ||
173 | struct GNUNET_MessageHeader header; | ||
174 | |||
175 | /** | ||
176 | * S->C: Public key of the member requesting replay. | ||
177 | * C->S: Unused. | ||
178 | */ | ||
179 | struct GNUNET_CRYPTO_EcdsaPublicKey member_pub_key; | ||
180 | |||
181 | /** | ||
182 | * ID of the message that is being requested. | ||
183 | */ | ||
184 | uint64_t fragment_id; | ||
185 | |||
186 | /** | ||
187 | * ID of the message that is being requested. | ||
188 | */ | ||
189 | uint64_t message_id; | ||
190 | |||
191 | /** | ||
192 | * Offset of the fragment that is being requested. | ||
193 | */ | ||
194 | uint64_t fragment_offset; | ||
195 | |||
196 | /** | ||
197 | * Additional flags for the request. | ||
198 | */ | ||
199 | uint64_t flags; | ||
200 | |||
201 | /** | ||
202 | * Replay request ID. | ||
203 | */ | ||
204 | uint32_t uid; | ||
205 | }; | ||
206 | |||
207 | |||
208 | /** | ||
209 | * Message sent from the client to the service to give the service | ||
210 | * a replayed message. | ||
211 | */ | ||
212 | struct MulticastReplayResponseMessage | ||
213 | { | ||
214 | |||
215 | /** | ||
216 | * Type: GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE | ||
217 | * or GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE_END | ||
218 | */ | ||
219 | struct GNUNET_MessageHeader header; | ||
220 | |||
221 | /** | ||
222 | * ID of the message that is being requested. | ||
223 | */ | ||
224 | uint64_t fragment_id; | ||
225 | |||
226 | /** | ||
227 | * ID of the message that is being requested. | ||
228 | */ | ||
229 | uint64_t message_id; | ||
230 | |||
231 | /** | ||
232 | * Offset of the fragment that is being requested. | ||
233 | */ | ||
234 | uint64_t fragment_offset; | ||
235 | |||
236 | /** | ||
237 | * Additional flags for the request. | ||
238 | */ | ||
239 | uint64_t flags; | ||
240 | |||
241 | /** | ||
242 | * An `enum GNUNET_MULTICAST_ReplayErrorCode` identifying issues (in NBO). | ||
243 | */ | ||
244 | int32_t error_code; | ||
245 | |||
246 | /* followed by replayed message */ | ||
247 | }; | ||
248 | |||
249 | |||
250 | /** | ||
251 | * Message sent from the client to the service to notify the service | ||
252 | * about the starting of a multicast group with this peers as its origin. | ||
253 | */ | ||
254 | struct MulticastOriginStartMessage | ||
255 | { | ||
256 | /** | ||
257 | * Type: GNUNET_MESSAGE_TYPE_MULTICAST_ORIGIN_START | ||
258 | */ | ||
259 | struct GNUNET_MessageHeader header; | ||
260 | |||
261 | /** | ||
262 | * Always zero. | ||
263 | */ | ||
264 | uint32_t reserved; | ||
265 | |||
266 | /** | ||
267 | * Private, non-ephemeral key for the multicast group. | ||
268 | */ | ||
269 | struct GNUNET_CRYPTO_EddsaPrivateKey group_key; | ||
270 | |||
271 | /** | ||
272 | * Last fragment ID sent to the group, used to continue counting fragments if | ||
273 | * we resume operating * a group. | ||
274 | */ | ||
275 | uint64_t max_fragment_id; | ||
276 | }; | ||
277 | |||
278 | |||
279 | struct MulticastMemberJoinMessage | ||
280 | { | ||
281 | /** | ||
282 | * Type: GNUNET_MESSAGE_TYPE_MULTICAST_MEMBER_JOIN | ||
283 | */ | ||
284 | struct GNUNET_MessageHeader header; | ||
285 | |||
286 | uint32_t relay_count GNUNET_PACKED; | ||
287 | |||
288 | struct GNUNET_CRYPTO_EddsaPublicKey group_pub_key; | ||
289 | |||
290 | struct GNUNET_CRYPTO_EcdsaPrivateKey member_key; | ||
291 | |||
292 | struct GNUNET_PeerIdentity origin; | ||
293 | |||
294 | /* Followed by struct GNUNET_PeerIdentity relays[relay_count] */ | ||
295 | |||
296 | /* Followed by struct GNUNET_MessageHeader join_msg */ | ||
297 | }; | ||
298 | |||
299 | |||
300 | GNUNET_NETWORK_STRUCT_END | ||
301 | |||
302 | #endif | ||
303 | /* end of multicast.h */ | ||
diff --git a/src/multicast/multicast_api.c b/src/multicast/multicast_api.c new file mode 100644 index 000000000..e5e830225 --- /dev/null +++ b/src/multicast/multicast_api.c | |||
@@ -0,0 +1,1399 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2012, 2013 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/multicast_api.c | ||
23 | * @brief Multicast service; implements multicast groups using CADET connections. | ||
24 | * @author Christian Grothoff | ||
25 | * @author Gabor X Toth | ||
26 | */ | ||
27 | |||
28 | #include "platform.h" | ||
29 | #include "gnunet_util_lib.h" | ||
30 | #include "gnunet_multicast_service.h" | ||
31 | #include "multicast.h" | ||
32 | |||
33 | #define LOG(kind,...) GNUNET_log_from (kind, "multicast-api",__VA_ARGS__) | ||
34 | |||
35 | |||
36 | /** | ||
37 | * Handle for a request to send a message to all multicast group members | ||
38 | * (from the origin). | ||
39 | */ | ||
40 | struct GNUNET_MULTICAST_OriginTransmitHandle | ||
41 | { | ||
42 | GNUNET_MULTICAST_OriginTransmitNotify notify; | ||
43 | void *notify_cls; | ||
44 | struct GNUNET_MULTICAST_Origin *origin; | ||
45 | |||
46 | uint64_t message_id; | ||
47 | uint64_t group_generation; | ||
48 | uint64_t fragment_offset; | ||
49 | }; | ||
50 | |||
51 | |||
52 | /** | ||
53 | * Handle for a message to be delivered from a member to the origin. | ||
54 | */ | ||
55 | struct GNUNET_MULTICAST_MemberTransmitHandle | ||
56 | { | ||
57 | GNUNET_MULTICAST_MemberTransmitNotify notify; | ||
58 | void *notify_cls; | ||
59 | struct GNUNET_MULTICAST_Member *member; | ||
60 | |||
61 | uint64_t request_id; | ||
62 | uint64_t fragment_offset; | ||
63 | }; | ||
64 | |||
65 | |||
66 | struct GNUNET_MULTICAST_Group | ||
67 | { | ||
68 | /** | ||
69 | * Configuration to use. | ||
70 | */ | ||
71 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
72 | |||
73 | /** | ||
74 | * Client connection to the service. | ||
75 | */ | ||
76 | struct GNUNET_MQ_Handle *mq; | ||
77 | |||
78 | /** | ||
79 | * Message to send on connect. | ||
80 | */ | ||
81 | struct GNUNET_MQ_Envelope *connect_env; | ||
82 | |||
83 | /** | ||
84 | * Time to wait until we try to reconnect on failure. | ||
85 | */ | ||
86 | struct GNUNET_TIME_Relative reconnect_delay; | ||
87 | |||
88 | /** | ||
89 | * Task for reconnecting when the listener fails. | ||
90 | */ | ||
91 | struct GNUNET_SCHEDULER_Task *reconnect_task; | ||
92 | |||
93 | GNUNET_MULTICAST_JoinRequestCallback join_req_cb; | ||
94 | GNUNET_MULTICAST_ReplayFragmentCallback replay_frag_cb; | ||
95 | GNUNET_MULTICAST_ReplayMessageCallback replay_msg_cb; | ||
96 | GNUNET_MULTICAST_MessageCallback message_cb; | ||
97 | void *cb_cls; | ||
98 | |||
99 | /** | ||
100 | * Function called after disconnected from the service. | ||
101 | */ | ||
102 | GNUNET_ContinuationCallback disconnect_cb; | ||
103 | |||
104 | /** | ||
105 | * Closure for @a disconnect_cb. | ||
106 | */ | ||
107 | void *disconnect_cls; | ||
108 | |||
109 | /** | ||
110 | * Are we currently transmitting a message? | ||
111 | */ | ||
112 | uint8_t in_transmit; | ||
113 | |||
114 | /** | ||
115 | * Number of MULTICAST_FRAGMENT_ACK messages we are still waiting for. | ||
116 | */ | ||
117 | uint8_t acks_pending; | ||
118 | |||
119 | /** | ||
120 | * Is this the origin or a member? | ||
121 | */ | ||
122 | uint8_t is_origin; | ||
123 | |||
124 | /** | ||
125 | * Is this channel in the process of disconnecting from the service? | ||
126 | * #GNUNET_YES or #GNUNET_NO | ||
127 | */ | ||
128 | uint8_t is_disconnecting; | ||
129 | }; | ||
130 | |||
131 | |||
132 | /** | ||
133 | * Handle for the origin of a multicast group. | ||
134 | */ | ||
135 | struct GNUNET_MULTICAST_Origin | ||
136 | { | ||
137 | struct GNUNET_MULTICAST_Group grp; | ||
138 | struct GNUNET_MULTICAST_OriginTransmitHandle tmit; | ||
139 | |||
140 | GNUNET_MULTICAST_RequestCallback request_cb; | ||
141 | }; | ||
142 | |||
143 | |||
144 | /** | ||
145 | * Handle for a multicast group member. | ||
146 | */ | ||
147 | struct GNUNET_MULTICAST_Member | ||
148 | { | ||
149 | struct GNUNET_MULTICAST_Group grp; | ||
150 | struct GNUNET_MULTICAST_MemberTransmitHandle tmit; | ||
151 | |||
152 | GNUNET_MULTICAST_JoinDecisionCallback join_dcsn_cb; | ||
153 | |||
154 | /** | ||
155 | * Replay fragment -> struct GNUNET_MULTICAST_MemberReplayHandle * | ||
156 | */ | ||
157 | struct GNUNET_CONTAINER_MultiHashMap *replay_reqs; | ||
158 | |||
159 | uint64_t next_fragment_id; | ||
160 | }; | ||
161 | |||
162 | |||
163 | /** | ||
164 | * Handle that identifies a join request. | ||
165 | * | ||
166 | * Used to match calls to #GNUNET_MULTICAST_JoinRequestCallback to the | ||
167 | * corresponding calls to #GNUNET_MULTICAST_join_decision(). | ||
168 | */ | ||
169 | struct GNUNET_MULTICAST_JoinHandle | ||
170 | { | ||
171 | struct GNUNET_MULTICAST_Group *group; | ||
172 | |||
173 | /** | ||
174 | * Public key of the member requesting join. | ||
175 | */ | ||
176 | struct GNUNET_CRYPTO_EcdsaPublicKey member_pub_key; | ||
177 | |||
178 | /** | ||
179 | * Peer identity of the member requesting join. | ||
180 | */ | ||
181 | struct GNUNET_PeerIdentity peer; | ||
182 | }; | ||
183 | |||
184 | |||
185 | /** | ||
186 | * Opaque handle to a replay request from the multicast service. | ||
187 | */ | ||
188 | struct GNUNET_MULTICAST_ReplayHandle | ||
189 | { | ||
190 | struct GNUNET_MULTICAST_Group *grp; | ||
191 | struct MulticastReplayRequestMessage req; | ||
192 | }; | ||
193 | |||
194 | |||
195 | /** | ||
196 | * Handle for a replay request. | ||
197 | */ | ||
198 | struct GNUNET_MULTICAST_MemberReplayHandle | ||
199 | { | ||
200 | }; | ||
201 | |||
202 | |||
203 | static void | ||
204 | origin_to_all (struct GNUNET_MULTICAST_Origin *orig); | ||
205 | |||
206 | static void | ||
207 | member_to_origin (struct GNUNET_MULTICAST_Member *mem); | ||
208 | |||
209 | |||
210 | /** | ||
211 | * Check join request message. | ||
212 | */ | ||
213 | static int | ||
214 | check_group_join_request (void *cls, | ||
215 | const struct MulticastJoinRequestMessage *jreq) | ||
216 | { | ||
217 | uint16_t size = ntohs (jreq->header.size); | ||
218 | |||
219 | if (sizeof (*jreq) == size) | ||
220 | return GNUNET_OK; | ||
221 | |||
222 | if (sizeof (*jreq) + sizeof (struct GNUNET_MessageHeader) <= size) | ||
223 | return GNUNET_OK; | ||
224 | |||
225 | return GNUNET_SYSERR; | ||
226 | } | ||
227 | |||
228 | |||
229 | /** | ||
230 | * Receive join request from service. | ||
231 | */ | ||
232 | static void | ||
233 | handle_group_join_request (void *cls, | ||
234 | const struct MulticastJoinRequestMessage *jreq) | ||
235 | { | ||
236 | struct GNUNET_MULTICAST_Group *grp = cls; | ||
237 | struct GNUNET_MULTICAST_JoinHandle *jh; | ||
238 | const struct GNUNET_MessageHeader *jmsg = NULL; | ||
239 | |||
240 | if (NULL == grp) | ||
241 | { | ||
242 | GNUNET_break (0); | ||
243 | return; | ||
244 | } | ||
245 | if (NULL == grp->join_req_cb) | ||
246 | return; | ||
247 | |||
248 | if (sizeof (*jreq) + sizeof (*jmsg) <= ntohs (jreq->header.size)) | ||
249 | jmsg = (const struct GNUNET_MessageHeader *) &jreq[1]; | ||
250 | |||
251 | jh = GNUNET_malloc (sizeof (*jh)); | ||
252 | jh->group = grp; | ||
253 | jh->member_pub_key = jreq->member_pub_key; | ||
254 | jh->peer = jreq->peer; | ||
255 | grp->join_req_cb (grp->cb_cls, &jreq->member_pub_key, jmsg, jh); | ||
256 | |||
257 | grp->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS; | ||
258 | } | ||
259 | |||
260 | |||
261 | /** | ||
262 | * Check multicast message. | ||
263 | */ | ||
264 | static int | ||
265 | check_group_message (void *cls, | ||
266 | const struct GNUNET_MULTICAST_MessageHeader *mmsg) | ||
267 | { | ||
268 | return GNUNET_OK; | ||
269 | } | ||
270 | |||
271 | |||
272 | /** | ||
273 | * Receive multicast message from service. | ||
274 | */ | ||
275 | static void | ||
276 | handle_group_message (void *cls, | ||
277 | const struct GNUNET_MULTICAST_MessageHeader *mmsg) | ||
278 | { | ||
279 | struct GNUNET_MULTICAST_Group *grp = cls; | ||
280 | |||
281 | if (GNUNET_YES == grp->is_disconnecting) | ||
282 | return; | ||
283 | |||
284 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
285 | "Calling message callback with a message of size %u.\n", | ||
286 | ntohs (mmsg->header.size)); | ||
287 | |||
288 | if (NULL != grp->message_cb) | ||
289 | grp->message_cb (grp->cb_cls, mmsg); | ||
290 | |||
291 | grp->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS; | ||
292 | } | ||
293 | |||
294 | |||
295 | /** | ||
296 | * Receive message/request fragment acknowledgement from service. | ||
297 | */ | ||
298 | static void | ||
299 | handle_group_fragment_ack (void *cls, | ||
300 | const struct GNUNET_MessageHeader *msg) | ||
301 | { | ||
302 | struct GNUNET_MULTICAST_Group *grp = cls; | ||
303 | |||
304 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
305 | "%p Got fragment ACK. in_transmit=%u, acks_pending=%u\n", | ||
306 | grp, grp->in_transmit, grp->acks_pending); | ||
307 | |||
308 | if (0 == grp->acks_pending) | ||
309 | { | ||
310 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
311 | "%p Ignoring extraneous fragment ACK.\n", grp); | ||
312 | return; | ||
313 | } | ||
314 | grp->acks_pending--; | ||
315 | |||
316 | if (GNUNET_YES != grp->in_transmit) | ||
317 | return; | ||
318 | |||
319 | if (GNUNET_YES == grp->is_origin) | ||
320 | origin_to_all ((struct GNUNET_MULTICAST_Origin *) grp); | ||
321 | else | ||
322 | member_to_origin ((struct GNUNET_MULTICAST_Member *) grp); | ||
323 | |||
324 | grp->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS; | ||
325 | } | ||
326 | |||
327 | |||
328 | /** | ||
329 | * Check unicast request. | ||
330 | */ | ||
331 | static int | ||
332 | check_origin_request (void *cls, | ||
333 | const struct GNUNET_MULTICAST_RequestHeader *req) | ||
334 | { | ||
335 | return GNUNET_OK; | ||
336 | } | ||
337 | |||
338 | |||
339 | /** | ||
340 | * Origin receives unicast request from a member. | ||
341 | */ | ||
342 | static void | ||
343 | handle_origin_request (void *cls, | ||
344 | const struct GNUNET_MULTICAST_RequestHeader *req) | ||
345 | { | ||
346 | struct GNUNET_MULTICAST_Group *grp; | ||
347 | struct GNUNET_MULTICAST_Origin *orig = cls; | ||
348 | grp = &orig->grp; | ||
349 | |||
350 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
351 | "Calling request callback with a request of size %u.\n", | ||
352 | ntohs (req->header.size)); | ||
353 | |||
354 | if (NULL != orig->request_cb) | ||
355 | orig->request_cb (grp->cb_cls, req); | ||
356 | |||
357 | grp->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS; | ||
358 | } | ||
359 | |||
360 | |||
361 | /** | ||
362 | * Receive multicast replay request from service. | ||
363 | */ | ||
364 | static void | ||
365 | handle_group_replay_request (void *cls, | ||
366 | const struct MulticastReplayRequestMessage *rep) | ||
367 | |||
368 | { | ||
369 | struct GNUNET_MULTICAST_Group *grp = cls; | ||
370 | |||
371 | if (GNUNET_YES == grp->is_disconnecting) | ||
372 | return; | ||
373 | |||
374 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got replay request.\n"); | ||
375 | |||
376 | if (0 != rep->fragment_id) | ||
377 | { | ||
378 | if (NULL != grp->replay_frag_cb) | ||
379 | { | ||
380 | struct GNUNET_MULTICAST_ReplayHandle * rh = GNUNET_malloc (sizeof (*rh)); | ||
381 | rh->grp = grp; | ||
382 | rh->req = *rep; | ||
383 | grp->replay_frag_cb (grp->cb_cls, &rep->member_pub_key, | ||
384 | GNUNET_ntohll (rep->fragment_id), | ||
385 | GNUNET_ntohll (rep->flags), rh); | ||
386 | } | ||
387 | } | ||
388 | else if (0 != rep->message_id) | ||
389 | { | ||
390 | if (NULL != grp->replay_msg_cb) | ||
391 | { | ||
392 | struct GNUNET_MULTICAST_ReplayHandle * rh = GNUNET_malloc (sizeof (*rh)); | ||
393 | rh->grp = grp; | ||
394 | rh->req = *rep; | ||
395 | grp->replay_msg_cb (grp->cb_cls, &rep->member_pub_key, | ||
396 | GNUNET_ntohll (rep->message_id), | ||
397 | GNUNET_ntohll (rep->fragment_offset), | ||
398 | GNUNET_ntohll (rep->flags), rh); | ||
399 | } | ||
400 | } | ||
401 | |||
402 | grp->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS; | ||
403 | } | ||
404 | |||
405 | |||
406 | /** | ||
407 | * Check replay response. | ||
408 | */ | ||
409 | static int | ||
410 | check_member_replay_response (void *cls, | ||
411 | const struct MulticastReplayResponseMessage *res) | ||
412 | { | ||
413 | uint16_t size = ntohs (res->header.size); | ||
414 | |||
415 | if (sizeof (*res) == size) | ||
416 | return GNUNET_OK; | ||
417 | |||
418 | if (sizeof (*res) + sizeof (struct GNUNET_MULTICAST_MessageHeader) <= size) | ||
419 | return GNUNET_OK; | ||
420 | |||
421 | return GNUNET_SYSERR; | ||
422 | } | ||
423 | |||
424 | |||
425 | /** | ||
426 | * Receive replay response from service. | ||
427 | */ | ||
428 | static void | ||
429 | handle_member_replay_response (void *cls, | ||
430 | const struct MulticastReplayResponseMessage *res) | ||
431 | { | ||
432 | struct GNUNET_MULTICAST_Group *grp; | ||
433 | struct GNUNET_MULTICAST_Member *mem = cls; | ||
434 | grp = &mem->grp; | ||
435 | |||
436 | if (GNUNET_YES == grp->is_disconnecting) | ||
437 | return; | ||
438 | |||
439 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got replay response.\n"); | ||
440 | |||
441 | // FIXME: return result | ||
442 | } | ||
443 | |||
444 | |||
445 | /** | ||
446 | * Check join decision. | ||
447 | */ | ||
448 | static int | ||
449 | check_member_join_decision (void *cls, | ||
450 | const struct MulticastJoinDecisionMessageHeader *hdcsn) | ||
451 | { | ||
452 | return GNUNET_OK; // checked in handle below | ||
453 | } | ||
454 | |||
455 | |||
456 | /** | ||
457 | * Member receives join decision. | ||
458 | */ | ||
459 | static void | ||
460 | handle_member_join_decision (void *cls, | ||
461 | const struct MulticastJoinDecisionMessageHeader *hdcsn) | ||
462 | { | ||
463 | struct GNUNET_MULTICAST_Group *grp; | ||
464 | struct GNUNET_MULTICAST_Member *mem = cls; | ||
465 | grp = &mem->grp; | ||
466 | |||
467 | const struct MulticastJoinDecisionMessage * | ||
468 | dcsn = (const struct MulticastJoinDecisionMessage *) &hdcsn[1]; | ||
469 | |||
470 | uint16_t dcsn_size = ntohs (dcsn->header.size); | ||
471 | int is_admitted = ntohl (dcsn->is_admitted); | ||
472 | |||
473 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
474 | "%p Member got join decision from multicast: %d\n", | ||
475 | mem, is_admitted); | ||
476 | |||
477 | const struct GNUNET_MessageHeader *join_resp = NULL; | ||
478 | uint16_t join_resp_size = 0; | ||
479 | |||
480 | uint16_t relay_count = ntohl (dcsn->relay_count); | ||
481 | const struct GNUNET_PeerIdentity *relays = NULL; | ||
482 | uint16_t relay_size = relay_count * sizeof (*relays); | ||
483 | if (0 < relay_count) | ||
484 | { | ||
485 | if (dcsn_size < sizeof (*dcsn) + relay_size) | ||
486 | { | ||
487 | GNUNET_break_op (0); | ||
488 | is_admitted = GNUNET_SYSERR; | ||
489 | } | ||
490 | else | ||
491 | { | ||
492 | relays = (struct GNUNET_PeerIdentity *) &dcsn[1]; | ||
493 | } | ||
494 | } | ||
495 | |||
496 | if (sizeof (*dcsn) + relay_size + sizeof (*join_resp) <= dcsn_size) | ||
497 | { | ||
498 | join_resp = (const struct GNUNET_MessageHeader *) ((char *) &dcsn[1] + relay_size); | ||
499 | join_resp_size = ntohs (join_resp->size); | ||
500 | } | ||
501 | if (dcsn_size < sizeof (*dcsn) + relay_size + join_resp_size) | ||
502 | { | ||
503 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
504 | "Received invalid join decision message from multicast: %u < %u + %u + %u\n", | ||
505 | dcsn_size , sizeof (*dcsn), relay_size, join_resp_size); | ||
506 | GNUNET_break_op (0); | ||
507 | is_admitted = GNUNET_SYSERR; | ||
508 | } | ||
509 | |||
510 | if (NULL != mem->join_dcsn_cb) | ||
511 | mem->join_dcsn_cb (grp->cb_cls, is_admitted, &hdcsn->peer, | ||
512 | relay_count, relays, join_resp); | ||
513 | |||
514 | // FIXME: | ||
515 | //if (GNUNET_YES != is_admitted) | ||
516 | // GNUNET_MULTICAST_member_part (mem); | ||
517 | |||
518 | grp->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS; | ||
519 | } | ||
520 | |||
521 | |||
522 | static void | ||
523 | group_cleanup (struct GNUNET_MULTICAST_Group *grp) | ||
524 | { | ||
525 | if (NULL != grp->connect_env) | ||
526 | { | ||
527 | GNUNET_MQ_discard (grp->connect_env); | ||
528 | grp->connect_env = NULL; | ||
529 | } | ||
530 | if (NULL != grp->mq) | ||
531 | { | ||
532 | GNUNET_MQ_destroy (grp->mq); | ||
533 | grp->mq = NULL; | ||
534 | } | ||
535 | if (NULL != grp->disconnect_cb) | ||
536 | { | ||
537 | grp->disconnect_cb (grp->disconnect_cls); | ||
538 | grp->disconnect_cb = NULL; | ||
539 | } | ||
540 | GNUNET_free (grp); | ||
541 | } | ||
542 | |||
543 | |||
544 | static void | ||
545 | handle_group_part_ack (void *cls, | ||
546 | const struct GNUNET_MessageHeader *msg) | ||
547 | { | ||
548 | struct GNUNET_MULTICAST_Group *grp = cls; | ||
549 | |||
550 | group_cleanup (grp); | ||
551 | } | ||
552 | |||
553 | |||
554 | /** | ||
555 | * Function to call with the decision made for a join request. | ||
556 | * | ||
557 | * Must be called once and only once in response to an invocation of the | ||
558 | * #GNUNET_MULTICAST_JoinRequestCallback. | ||
559 | * | ||
560 | * @param join | ||
561 | * Join request handle. | ||
562 | * @param is_admitted | ||
563 | * #GNUNET_YES if the join is approved, | ||
564 | * #GNUNET_NO if it is disapproved, | ||
565 | * #GNUNET_SYSERR if we cannot answer the request. | ||
566 | * @param relay_count | ||
567 | * Number of relays given. | ||
568 | * @param relays | ||
569 | * Array of suggested peers that might be useful relays to use | ||
570 | * when joining the multicast group (essentially a list of peers that | ||
571 | * are already part of the multicast group and might thus be willing | ||
572 | * to help with routing). If empty, only this local peer (which must | ||
573 | * be the multicast origin) is a good candidate for building the | ||
574 | * multicast tree. Note that it is unnecessary to specify our own | ||
575 | * peer identity in this array. | ||
576 | * @param join_resp | ||
577 | * Message to send in response to the joining peer; | ||
578 | * can also be used to redirect the peer to a different group at the | ||
579 | * application layer; this response is to be transmitted to the | ||
580 | * peer that issued the request even if admission is denied. | ||
581 | */ | ||
582 | struct GNUNET_MULTICAST_ReplayHandle * | ||
583 | GNUNET_MULTICAST_join_decision (struct GNUNET_MULTICAST_JoinHandle *join, | ||
584 | int is_admitted, | ||
585 | uint16_t relay_count, | ||
586 | const struct GNUNET_PeerIdentity *relays, | ||
587 | const struct GNUNET_MessageHeader *join_resp) | ||
588 | { | ||
589 | struct GNUNET_MULTICAST_Group *grp = join->group; | ||
590 | uint16_t join_resp_size = (NULL != join_resp) ? ntohs (join_resp->size) : 0; | ||
591 | uint16_t relay_size = relay_count * sizeof (*relays); | ||
592 | |||
593 | struct MulticastJoinDecisionMessageHeader *hdcsn; | ||
594 | struct MulticastJoinDecisionMessage *dcsn; | ||
595 | struct GNUNET_MQ_Envelope * | ||
596 | env = GNUNET_MQ_msg_extra (hdcsn, sizeof (*dcsn) + relay_size + join_resp_size, | ||
597 | GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION); | ||
598 | hdcsn->member_pub_key = join->member_pub_key; | ||
599 | hdcsn->peer = join->peer; | ||
600 | |||
601 | dcsn = (struct MulticastJoinDecisionMessage *) &hdcsn[1]; | ||
602 | dcsn->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION); | ||
603 | dcsn->header.size = htons (sizeof (*dcsn) + relay_size + join_resp_size); | ||
604 | dcsn->is_admitted = htonl (is_admitted); | ||
605 | dcsn->relay_count = htonl (relay_count); | ||
606 | if (0 < relay_size) | ||
607 | GNUNET_memcpy (&dcsn[1], relays, relay_size); | ||
608 | if (0 < join_resp_size) | ||
609 | GNUNET_memcpy (((char *) &dcsn[1]) + relay_size, join_resp, join_resp_size); | ||
610 | |||
611 | GNUNET_MQ_send (grp->mq, env); | ||
612 | GNUNET_free (join); | ||
613 | return NULL; | ||
614 | } | ||
615 | |||
616 | |||
617 | /** | ||
618 | * Replay a message fragment for the multicast group. | ||
619 | * | ||
620 | * @param rh | ||
621 | * Replay handle identifying which replay operation was requested. | ||
622 | * @param msg | ||
623 | * Replayed message fragment, NULL if not found / an error occurred. | ||
624 | * @param ec | ||
625 | * Error code. See enum GNUNET_MULTICAST_ReplayErrorCode | ||
626 | * If not #GNUNET_MULTICAST_REC_OK, the replay handle is invalidated. | ||
627 | */ | ||
628 | void | ||
629 | GNUNET_MULTICAST_replay_response (struct GNUNET_MULTICAST_ReplayHandle *rh, | ||
630 | const struct GNUNET_MessageHeader *msg, | ||
631 | enum GNUNET_MULTICAST_ReplayErrorCode ec) | ||
632 | { | ||
633 | uint8_t msg_size = (NULL != msg) ? ntohs (msg->size) : 0; | ||
634 | struct MulticastReplayResponseMessage *res; | ||
635 | struct GNUNET_MQ_Envelope * | ||
636 | env = GNUNET_MQ_msg_extra (res, msg_size, | ||
637 | GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE); | ||
638 | res->fragment_id = rh->req.fragment_id; | ||
639 | res->message_id = rh->req.message_id; | ||
640 | res->fragment_offset = rh->req.fragment_offset; | ||
641 | res->flags = rh->req.flags; | ||
642 | res->error_code = htonl (ec); | ||
643 | |||
644 | if (GNUNET_MULTICAST_REC_OK == ec) | ||
645 | { | ||
646 | GNUNET_assert (NULL != msg); | ||
647 | GNUNET_memcpy (&res[1], msg, msg_size); | ||
648 | } | ||
649 | |||
650 | GNUNET_MQ_send (rh->grp->mq, env); | ||
651 | |||
652 | if (GNUNET_MULTICAST_REC_OK != ec) | ||
653 | GNUNET_free (rh); | ||
654 | } | ||
655 | |||
656 | |||
657 | /** | ||
658 | * Indicate the end of the replay session. | ||
659 | * | ||
660 | * Invalidates the replay handle. | ||
661 | * | ||
662 | * @param rh | ||
663 | * Replay session to end. | ||
664 | */ | ||
665 | void | ||
666 | GNUNET_MULTICAST_replay_response_end (struct GNUNET_MULTICAST_ReplayHandle *rh) | ||
667 | { | ||
668 | struct MulticastReplayResponseMessage *end; | ||
669 | struct GNUNET_MQ_Envelope * | ||
670 | env = GNUNET_MQ_msg (end, GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE_END); | ||
671 | |||
672 | end->fragment_id = rh->req.fragment_id; | ||
673 | end->message_id = rh->req.message_id; | ||
674 | end->fragment_offset = rh->req.fragment_offset; | ||
675 | end->flags = rh->req.flags; | ||
676 | |||
677 | GNUNET_MQ_send (rh->grp->mq, env); | ||
678 | GNUNET_free (rh); | ||
679 | } | ||
680 | |||
681 | |||
682 | /** | ||
683 | * Replay a message for the multicast group. | ||
684 | * | ||
685 | * @param rh | ||
686 | * Replay handle identifying which replay operation was requested. | ||
687 | * @param notify | ||
688 | * Function to call to get the message. | ||
689 | * @param notify_cls | ||
690 | * Closure for @a notify. | ||
691 | */ | ||
692 | void | ||
693 | GNUNET_MULTICAST_replay_response2 (struct GNUNET_MULTICAST_ReplayHandle *rh, | ||
694 | GNUNET_MULTICAST_ReplayTransmitNotify notify, | ||
695 | void *notify_cls) | ||
696 | { | ||
697 | } | ||
698 | |||
699 | |||
700 | static void | ||
701 | origin_connect (struct GNUNET_MULTICAST_Origin *orig); | ||
702 | |||
703 | |||
704 | static void | ||
705 | origin_reconnect (void *cls) | ||
706 | { | ||
707 | origin_connect (cls); | ||
708 | } | ||
709 | |||
710 | |||
711 | /** | ||
712 | * Origin client disconnected from service. | ||
713 | * | ||
714 | * Reconnect after backoff period. | ||
715 | */ | ||
716 | static void | ||
717 | origin_disconnected (void *cls, enum GNUNET_MQ_Error error) | ||
718 | { | ||
719 | struct GNUNET_MULTICAST_Origin *orig = cls; | ||
720 | struct GNUNET_MULTICAST_Group *grp = &orig->grp; | ||
721 | |||
722 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
723 | "Origin client disconnected (%d), re-connecting\n", | ||
724 | (int) error); | ||
725 | if (NULL != grp->mq) | ||
726 | { | ||
727 | GNUNET_MQ_destroy (grp->mq); | ||
728 | grp->mq = NULL; | ||
729 | } | ||
730 | |||
731 | grp->reconnect_task = GNUNET_SCHEDULER_add_delayed (grp->reconnect_delay, | ||
732 | origin_reconnect, | ||
733 | orig); | ||
734 | grp->reconnect_delay = GNUNET_TIME_STD_BACKOFF (grp->reconnect_delay); | ||
735 | } | ||
736 | |||
737 | |||
738 | /** | ||
739 | * Connect to service as origin. | ||
740 | */ | ||
741 | static void | ||
742 | origin_connect (struct GNUNET_MULTICAST_Origin *orig) | ||
743 | { | ||
744 | struct GNUNET_MULTICAST_Group *grp = &orig->grp; | ||
745 | |||
746 | struct GNUNET_MQ_MessageHandler handlers[] = { | ||
747 | GNUNET_MQ_hd_var_size (group_message, | ||
748 | GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE, | ||
749 | struct GNUNET_MULTICAST_MessageHeader, | ||
750 | grp), | ||
751 | GNUNET_MQ_hd_var_size (origin_request, | ||
752 | GNUNET_MESSAGE_TYPE_MULTICAST_REQUEST, | ||
753 | struct GNUNET_MULTICAST_RequestHeader, | ||
754 | orig), | ||
755 | GNUNET_MQ_hd_fixed_size (group_fragment_ack, | ||
756 | GNUNET_MESSAGE_TYPE_MULTICAST_FRAGMENT_ACK, | ||
757 | struct GNUNET_MessageHeader, | ||
758 | grp), | ||
759 | GNUNET_MQ_hd_var_size (group_join_request, | ||
760 | GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_REQUEST, | ||
761 | struct MulticastJoinRequestMessage, | ||
762 | grp), | ||
763 | GNUNET_MQ_hd_fixed_size (group_part_ack, | ||
764 | GNUNET_MESSAGE_TYPE_MULTICAST_PART_ACK, | ||
765 | struct GNUNET_MessageHeader, | ||
766 | grp), | ||
767 | GNUNET_MQ_hd_fixed_size (group_replay_request, | ||
768 | GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_REQUEST, | ||
769 | struct MulticastReplayRequestMessage, | ||
770 | grp), | ||
771 | GNUNET_MQ_handler_end () | ||
772 | }; | ||
773 | |||
774 | grp->mq = GNUNET_CLIENT_connect (grp->cfg, "multicast", | ||
775 | handlers, origin_disconnected, orig); | ||
776 | GNUNET_assert (NULL != grp->mq); | ||
777 | GNUNET_MQ_send_copy (grp->mq, grp->connect_env); | ||
778 | } | ||
779 | |||
780 | |||
781 | /** | ||
782 | * Start a multicast group. | ||
783 | * | ||
784 | * Will advertise the origin in the P2P overlay network under the respective | ||
785 | * public key so that other peer can find this peer to join it. Peers that | ||
786 | * issue GNUNET_MULTICAST_member_join() can then transmit a join request to | ||
787 | * either an existing group member or to the origin. If the joining is | ||
788 | * approved, the member is cleared for @e replay and will begin to receive | ||
789 | * messages transmitted to the group. If joining is disapproved, the failed | ||
790 | * candidate will be given a response. Members in the group can send messages | ||
791 | * to the origin (one at a time). | ||
792 | * | ||
793 | * @param cfg | ||
794 | * Configuration to use. | ||
795 | * @param priv_key | ||
796 | * ECC key that will be used to sign messages for this | ||
797 | * multicast session; public key is used to identify the multicast group; | ||
798 | * @param max_fragment_id | ||
799 | * Maximum fragment ID already sent to the group. | ||
800 | * 0 for a new group. | ||
801 | * @param join_request_cb | ||
802 | * Function called to approve / disapprove joining of a peer. | ||
803 | * @param replay_frag_cb | ||
804 | * Function that can be called to replay a message fragment. | ||
805 | * @param replay_msg_cb | ||
806 | * Function that can be called to replay a message. | ||
807 | * @param request_cb | ||
808 | * Function called with message fragments from group members. | ||
809 | * @param message_cb | ||
810 | * Function called with the message fragments sent to the | ||
811 | * network by GNUNET_MULTICAST_origin_to_all(). These message fragments | ||
812 | * should be stored for answering replay requests later. | ||
813 | * @param cls | ||
814 | * Closure for the various callbacks that follow. | ||
815 | * | ||
816 | * @return Handle for the origin, NULL on error. | ||
817 | */ | ||
818 | struct GNUNET_MULTICAST_Origin * | ||
819 | GNUNET_MULTICAST_origin_start (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
820 | const struct GNUNET_CRYPTO_EddsaPrivateKey *priv_key, | ||
821 | uint64_t max_fragment_id, | ||
822 | GNUNET_MULTICAST_JoinRequestCallback join_request_cb, | ||
823 | GNUNET_MULTICAST_ReplayFragmentCallback replay_frag_cb, | ||
824 | GNUNET_MULTICAST_ReplayMessageCallback replay_msg_cb, | ||
825 | GNUNET_MULTICAST_RequestCallback request_cb, | ||
826 | GNUNET_MULTICAST_MessageCallback message_cb, | ||
827 | void *cls) | ||
828 | { | ||
829 | struct GNUNET_MULTICAST_Origin *orig = GNUNET_malloc (sizeof (*orig)); | ||
830 | struct GNUNET_MULTICAST_Group *grp = &orig->grp; | ||
831 | |||
832 | struct MulticastOriginStartMessage *start; | ||
833 | grp->connect_env = GNUNET_MQ_msg (start, | ||
834 | GNUNET_MESSAGE_TYPE_MULTICAST_ORIGIN_START); | ||
835 | start->max_fragment_id = max_fragment_id; | ||
836 | start->group_key = *priv_key; | ||
837 | |||
838 | grp->cfg = cfg; | ||
839 | grp->is_origin = GNUNET_YES; | ||
840 | grp->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS; | ||
841 | |||
842 | grp->cb_cls = cls; | ||
843 | grp->join_req_cb = join_request_cb; | ||
844 | grp->replay_frag_cb = replay_frag_cb; | ||
845 | grp->replay_msg_cb = replay_msg_cb; | ||
846 | grp->message_cb = message_cb; | ||
847 | |||
848 | orig->request_cb = request_cb; | ||
849 | |||
850 | origin_connect (orig); | ||
851 | return orig; | ||
852 | } | ||
853 | |||
854 | |||
855 | /** | ||
856 | * Stop a multicast group. | ||
857 | * | ||
858 | * @param origin | ||
859 | * Multicast group to stop. | ||
860 | */ | ||
861 | void | ||
862 | GNUNET_MULTICAST_origin_stop (struct GNUNET_MULTICAST_Origin *orig, | ||
863 | GNUNET_ContinuationCallback stop_cb, | ||
864 | void *stop_cls) | ||
865 | { | ||
866 | struct GNUNET_MULTICAST_Group *grp = &orig->grp; | ||
867 | struct GNUNET_MQ_Envelope *env; | ||
868 | |||
869 | grp->is_disconnecting = GNUNET_YES; | ||
870 | grp->disconnect_cb = stop_cb; | ||
871 | grp->disconnect_cls = stop_cls; | ||
872 | env = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_MULTICAST_PART_REQUEST); | ||
873 | GNUNET_MQ_send (grp->mq, env); | ||
874 | } | ||
875 | |||
876 | |||
877 | static void | ||
878 | origin_to_all (struct GNUNET_MULTICAST_Origin *orig) | ||
879 | { | ||
880 | LOG (GNUNET_ERROR_TYPE_DEBUG, "%p origin_to_all()\n", orig); | ||
881 | struct GNUNET_MULTICAST_Group *grp = &orig->grp; | ||
882 | struct GNUNET_MULTICAST_OriginTransmitHandle *tmit = &orig->tmit; | ||
883 | GNUNET_assert (GNUNET_YES == grp->in_transmit); | ||
884 | |||
885 | size_t buf_size = GNUNET_MULTICAST_FRAGMENT_MAX_SIZE; | ||
886 | struct GNUNET_MULTICAST_MessageHeader *msg; | ||
887 | struct GNUNET_MQ_Envelope * | ||
888 | env = GNUNET_MQ_msg_extra (msg, buf_size - sizeof(*msg), | ||
889 | GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE); | ||
890 | |||
891 | int ret = tmit->notify (tmit->notify_cls, &buf_size, &msg[1]); | ||
892 | |||
893 | if (! (GNUNET_YES == ret || GNUNET_NO == ret) | ||
894 | || GNUNET_MULTICAST_FRAGMENT_MAX_SIZE < buf_size) | ||
895 | { | ||
896 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
897 | "%p OriginTransmitNotify() returned error or invalid message size.\n", | ||
898 | orig); | ||
899 | /* FIXME: handle error */ | ||
900 | GNUNET_MQ_discard (env); | ||
901 | return; | ||
902 | } | ||
903 | |||
904 | if (GNUNET_NO == ret && 0 == buf_size) | ||
905 | { | ||
906 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
907 | "%p OriginTransmitNotify() - transmission paused.\n", orig); | ||
908 | GNUNET_MQ_discard (env); | ||
909 | return; /* Transmission paused. */ | ||
910 | } | ||
911 | |||
912 | msg->header.size = htons (sizeof (*msg) + buf_size); | ||
913 | msg->message_id = GNUNET_htonll (tmit->message_id); | ||
914 | msg->group_generation = tmit->group_generation; | ||
915 | msg->fragment_offset = GNUNET_htonll (tmit->fragment_offset); | ||
916 | tmit->fragment_offset += sizeof (*msg) + buf_size; | ||
917 | |||
918 | grp->acks_pending++; | ||
919 | GNUNET_MQ_send (grp->mq, env); | ||
920 | |||
921 | if (GNUNET_YES == ret) | ||
922 | grp->in_transmit = GNUNET_NO; | ||
923 | } | ||
924 | |||
925 | |||
926 | /** | ||
927 | * Send a message to the multicast group. | ||
928 | * | ||
929 | * @param orig | ||
930 | * Handle to the multicast group. | ||
931 | * @param message_id | ||
932 | * Application layer ID for the message. Opaque to multicast. | ||
933 | * @param group_generation | ||
934 | * Group generation of the message. | ||
935 | * Documented in struct GNUNET_MULTICAST_MessageHeader. | ||
936 | * @param notify | ||
937 | * Function to call to get the message. | ||
938 | * @param notify_cls | ||
939 | * Closure for @a notify. | ||
940 | * | ||
941 | * @return Message handle on success, | ||
942 | * NULL on error (i.e. another request is already pending). | ||
943 | */ | ||
944 | struct GNUNET_MULTICAST_OriginTransmitHandle * | ||
945 | GNUNET_MULTICAST_origin_to_all (struct GNUNET_MULTICAST_Origin *orig, | ||
946 | uint64_t message_id, | ||
947 | uint64_t group_generation, | ||
948 | GNUNET_MULTICAST_OriginTransmitNotify notify, | ||
949 | void *notify_cls) | ||
950 | { | ||
951 | struct GNUNET_MULTICAST_Group *grp = &orig->grp; | ||
952 | if (GNUNET_YES == grp->in_transmit) | ||
953 | return NULL; | ||
954 | grp->in_transmit = GNUNET_YES; | ||
955 | |||
956 | struct GNUNET_MULTICAST_OriginTransmitHandle *tmit = &orig->tmit; | ||
957 | tmit->origin = orig; | ||
958 | tmit->message_id = message_id; | ||
959 | tmit->fragment_offset = 0; | ||
960 | tmit->group_generation = group_generation; | ||
961 | tmit->notify = notify; | ||
962 | tmit->notify_cls = notify_cls; | ||
963 | |||
964 | origin_to_all (orig); | ||
965 | return tmit; | ||
966 | } | ||
967 | |||
968 | |||
969 | /** | ||
970 | * Resume message transmission to multicast group. | ||
971 | * | ||
972 | * @param th | ||
973 | * Transmission to cancel. | ||
974 | */ | ||
975 | void | ||
976 | GNUNET_MULTICAST_origin_to_all_resume (struct GNUNET_MULTICAST_OriginTransmitHandle *th) | ||
977 | { | ||
978 | struct GNUNET_MULTICAST_Group *grp = &th->origin->grp; | ||
979 | if (0 != grp->acks_pending || GNUNET_YES != grp->in_transmit) | ||
980 | return; | ||
981 | origin_to_all (th->origin); | ||
982 | } | ||
983 | |||
984 | |||
985 | /** | ||
986 | * Cancel request for message transmission to multicast group. | ||
987 | * | ||
988 | * @param th | ||
989 | * Transmission to cancel. | ||
990 | */ | ||
991 | void | ||
992 | GNUNET_MULTICAST_origin_to_all_cancel (struct GNUNET_MULTICAST_OriginTransmitHandle *th) | ||
993 | { | ||
994 | th->origin->grp.in_transmit = GNUNET_NO; | ||
995 | } | ||
996 | |||
997 | |||
998 | static void | ||
999 | member_connect (struct GNUNET_MULTICAST_Member *mem); | ||
1000 | |||
1001 | |||
1002 | static void | ||
1003 | member_reconnect (void *cls) | ||
1004 | { | ||
1005 | member_connect (cls); | ||
1006 | } | ||
1007 | |||
1008 | |||
1009 | /** | ||
1010 | * Member client disconnected from service. | ||
1011 | * | ||
1012 | * Reconnect after backoff period. | ||
1013 | */ | ||
1014 | static void | ||
1015 | member_disconnected (void *cls, enum GNUNET_MQ_Error error) | ||
1016 | { | ||
1017 | struct GNUNET_MULTICAST_Member *mem = cls; | ||
1018 | struct GNUNET_MULTICAST_Group *grp = &mem->grp; | ||
1019 | |||
1020 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1021 | "Member client disconnected (%d), re-connecting\n", | ||
1022 | (int) error); | ||
1023 | GNUNET_MQ_destroy (grp->mq); | ||
1024 | grp->mq = NULL; | ||
1025 | |||
1026 | grp->reconnect_task = GNUNET_SCHEDULER_add_delayed (grp->reconnect_delay, | ||
1027 | member_reconnect, | ||
1028 | mem); | ||
1029 | grp->reconnect_delay = GNUNET_TIME_STD_BACKOFF (grp->reconnect_delay); | ||
1030 | } | ||
1031 | |||
1032 | |||
1033 | /** | ||
1034 | * Connect to service as member. | ||
1035 | */ | ||
1036 | static void | ||
1037 | member_connect (struct GNUNET_MULTICAST_Member *mem) | ||
1038 | { | ||
1039 | struct GNUNET_MULTICAST_Group *grp = &mem->grp; | ||
1040 | |||
1041 | struct GNUNET_MQ_MessageHandler handlers[] = { | ||
1042 | GNUNET_MQ_hd_var_size (group_message, | ||
1043 | GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE, | ||
1044 | struct GNUNET_MULTICAST_MessageHeader, | ||
1045 | grp), | ||
1046 | GNUNET_MQ_hd_fixed_size (group_fragment_ack, | ||
1047 | GNUNET_MESSAGE_TYPE_MULTICAST_FRAGMENT_ACK, | ||
1048 | struct GNUNET_MessageHeader, | ||
1049 | grp), | ||
1050 | GNUNET_MQ_hd_var_size (group_join_request, | ||
1051 | GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_REQUEST, | ||
1052 | struct MulticastJoinRequestMessage, | ||
1053 | grp), | ||
1054 | GNUNET_MQ_hd_var_size (member_join_decision, | ||
1055 | GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION, | ||
1056 | struct MulticastJoinDecisionMessageHeader, | ||
1057 | mem), | ||
1058 | GNUNET_MQ_hd_fixed_size (group_part_ack, | ||
1059 | GNUNET_MESSAGE_TYPE_MULTICAST_PART_ACK, | ||
1060 | struct GNUNET_MessageHeader, | ||
1061 | grp), | ||
1062 | GNUNET_MQ_hd_fixed_size (group_replay_request, | ||
1063 | GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_REQUEST, | ||
1064 | struct MulticastReplayRequestMessage, | ||
1065 | grp), | ||
1066 | GNUNET_MQ_hd_var_size (member_replay_response, | ||
1067 | GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE, | ||
1068 | struct MulticastReplayResponseMessage, | ||
1069 | mem), | ||
1070 | GNUNET_MQ_handler_end () | ||
1071 | }; | ||
1072 | |||
1073 | grp->mq = GNUNET_CLIENT_connect (grp->cfg, "multicast", | ||
1074 | handlers, member_disconnected, mem); | ||
1075 | GNUNET_assert (NULL != grp->mq); | ||
1076 | GNUNET_MQ_send_copy (grp->mq, grp->connect_env); | ||
1077 | } | ||
1078 | |||
1079 | |||
1080 | /** | ||
1081 | * Join a multicast group. | ||
1082 | * | ||
1083 | * The entity joining is always the local peer. Further information about the | ||
1084 | * candidate can be provided in the @a join_request message. If the join fails, the | ||
1085 | * @a message_cb is invoked with a (failure) response and then with NULL. If | ||
1086 | * the join succeeds, outstanding (state) messages and ongoing multicast | ||
1087 | * messages will be given to the @a message_cb until the member decides to part | ||
1088 | * the group. The @a replay_cb function may be called at any time by the | ||
1089 | * multicast service to support relaying messages to other members of the group. | ||
1090 | * | ||
1091 | * @param cfg | ||
1092 | * Configuration to use. | ||
1093 | * @param group_key | ||
1094 | * ECC public key that identifies the group to join. | ||
1095 | * @param member_key | ||
1096 | * ECC key that identifies the member | ||
1097 | * and used to sign requests sent to the origin. | ||
1098 | * @param origin | ||
1099 | * Peer ID of the origin to send unicast requsets to. If NULL, | ||
1100 | * unicast requests are sent back via multiple hops on the reverse path | ||
1101 | * of multicast messages. | ||
1102 | * @param relay_count | ||
1103 | * Number of peers in the @a relays array. | ||
1104 | * @param relays | ||
1105 | * Peer identities of members of the group, which serve as relays | ||
1106 | * and can be used to join the group at. and send the @a join_request to. | ||
1107 | * If empty, the @a join_request is sent directly to the @a origin. | ||
1108 | * @param join_msg | ||
1109 | * Application-dependent join message to be passed to the peer @a origin. | ||
1110 | * @param join_request_cb | ||
1111 | * Function called to approve / disapprove joining of a peer. | ||
1112 | * @param join_decision_cb | ||
1113 | * Function called to inform about the join decision. | ||
1114 | * @param replay_frag_cb | ||
1115 | * Function that can be called to replay message fragments | ||
1116 | * this peer already knows from this group. NULL if this | ||
1117 | * client is unable to support replay. | ||
1118 | * @param replay_msg_cb | ||
1119 | * Function that can be called to replay message fragments | ||
1120 | * this peer already knows from this group. NULL if this | ||
1121 | * client is unable to support replay. | ||
1122 | * @param message_cb | ||
1123 | * Function to be called for all message fragments we | ||
1124 | * receive from the group, excluding those our @a replay_cb | ||
1125 | * already has. | ||
1126 | * @param cls | ||
1127 | * Closure for callbacks. | ||
1128 | * | ||
1129 | * @return Handle for the member, NULL on error. | ||
1130 | */ | ||
1131 | struct GNUNET_MULTICAST_Member * | ||
1132 | GNUNET_MULTICAST_member_join (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
1133 | const struct GNUNET_CRYPTO_EddsaPublicKey *group_pub_key, | ||
1134 | const struct GNUNET_CRYPTO_EcdsaPrivateKey *member_key, | ||
1135 | const struct GNUNET_PeerIdentity *origin, | ||
1136 | uint16_t relay_count, | ||
1137 | const struct GNUNET_PeerIdentity *relays, | ||
1138 | const struct GNUNET_MessageHeader *join_msg, | ||
1139 | GNUNET_MULTICAST_JoinRequestCallback join_request_cb, | ||
1140 | GNUNET_MULTICAST_JoinDecisionCallback join_decision_cb, | ||
1141 | GNUNET_MULTICAST_ReplayFragmentCallback replay_frag_cb, | ||
1142 | GNUNET_MULTICAST_ReplayMessageCallback replay_msg_cb, | ||
1143 | GNUNET_MULTICAST_MessageCallback message_cb, | ||
1144 | void *cls) | ||
1145 | { | ||
1146 | struct GNUNET_MULTICAST_Member *mem = GNUNET_malloc (sizeof (*mem)); | ||
1147 | struct GNUNET_MULTICAST_Group *grp = &mem->grp; | ||
1148 | |||
1149 | uint16_t relay_size = relay_count * sizeof (*relays); | ||
1150 | uint16_t join_msg_size = (NULL != join_msg) ? ntohs (join_msg->size) : 0; | ||
1151 | struct MulticastMemberJoinMessage *join; | ||
1152 | grp->connect_env = GNUNET_MQ_msg_extra (join, relay_size + join_msg_size, | ||
1153 | GNUNET_MESSAGE_TYPE_MULTICAST_MEMBER_JOIN); | ||
1154 | join->group_pub_key = *group_pub_key; | ||
1155 | join->member_key = *member_key; | ||
1156 | join->origin = *origin; | ||
1157 | join->relay_count = ntohl (relay_count); | ||
1158 | if (0 < relay_size) | ||
1159 | GNUNET_memcpy (&join[1], relays, relay_size); | ||
1160 | if (0 < join_msg_size) | ||
1161 | GNUNET_memcpy (((char *) &join[1]) + relay_size, join_msg, join_msg_size); | ||
1162 | |||
1163 | grp->cfg = cfg; | ||
1164 | grp->is_origin = GNUNET_NO; | ||
1165 | grp->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS; | ||
1166 | |||
1167 | mem->join_dcsn_cb = join_decision_cb; | ||
1168 | grp->join_req_cb = join_request_cb; | ||
1169 | grp->replay_frag_cb = replay_frag_cb; | ||
1170 | grp->replay_msg_cb = replay_msg_cb; | ||
1171 | grp->message_cb = message_cb; | ||
1172 | grp->cb_cls = cls; | ||
1173 | |||
1174 | member_connect (mem); | ||
1175 | return mem; | ||
1176 | } | ||
1177 | |||
1178 | |||
1179 | /** | ||
1180 | * Part a multicast group. | ||
1181 | * | ||
1182 | * Disconnects from all group members and invalidates the @a member handle. | ||
1183 | * | ||
1184 | * An application-dependent part message can be transmitted beforehand using | ||
1185 | * #GNUNET_MULTICAST_member_to_origin()) | ||
1186 | * | ||
1187 | * @param member | ||
1188 | * Membership handle. | ||
1189 | */ | ||
1190 | void | ||
1191 | GNUNET_MULTICAST_member_part (struct GNUNET_MULTICAST_Member *mem, | ||
1192 | GNUNET_ContinuationCallback part_cb, | ||
1193 | void *part_cls) | ||
1194 | { | ||
1195 | struct GNUNET_MULTICAST_Group *grp = &mem->grp; | ||
1196 | struct GNUNET_MQ_Envelope *env; | ||
1197 | |||
1198 | mem->join_dcsn_cb = NULL; | ||
1199 | grp->join_req_cb = NULL; | ||
1200 | grp->message_cb = NULL; | ||
1201 | grp->replay_msg_cb = NULL; | ||
1202 | grp->replay_frag_cb = NULL; | ||
1203 | grp->is_disconnecting = GNUNET_YES; | ||
1204 | grp->disconnect_cb = part_cb; | ||
1205 | grp->disconnect_cls = part_cls; | ||
1206 | env = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_MULTICAST_PART_REQUEST); | ||
1207 | GNUNET_MQ_send (grp->mq, env); | ||
1208 | } | ||
1209 | |||
1210 | |||
1211 | void | ||
1212 | member_replay_request (struct GNUNET_MULTICAST_Member *mem, | ||
1213 | uint64_t fragment_id, | ||
1214 | uint64_t message_id, | ||
1215 | uint64_t fragment_offset, | ||
1216 | uint64_t flags) | ||
1217 | { | ||
1218 | struct MulticastReplayRequestMessage *rep; | ||
1219 | struct GNUNET_MQ_Envelope * | ||
1220 | env = GNUNET_MQ_msg (rep, GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_REQUEST); | ||
1221 | |||
1222 | rep->fragment_id = GNUNET_htonll (fragment_id); | ||
1223 | rep->message_id = GNUNET_htonll (message_id); | ||
1224 | rep->fragment_offset = GNUNET_htonll (fragment_offset); | ||
1225 | rep->flags = GNUNET_htonll (flags); | ||
1226 | |||
1227 | GNUNET_MQ_send (mem->grp.mq, env); | ||
1228 | } | ||
1229 | |||
1230 | |||
1231 | /** | ||
1232 | * Request a fragment to be replayed by fragment ID. | ||
1233 | * | ||
1234 | * Useful if messages below the @e max_known_fragment_id given when joining are | ||
1235 | * needed and not known to the client. | ||
1236 | * | ||
1237 | * @param member | ||
1238 | * Membership handle. | ||
1239 | * @param fragment_id | ||
1240 | * ID of a message fragment that this client would like to see replayed. | ||
1241 | * @param flags | ||
1242 | * Additional flags for the replay request. | ||
1243 | * It is used and defined by GNUNET_MULTICAST_ReplayFragmentCallback | ||
1244 | * | ||
1245 | * @return Replay request handle. | ||
1246 | */ | ||
1247 | struct GNUNET_MULTICAST_MemberReplayHandle * | ||
1248 | GNUNET_MULTICAST_member_replay_fragment (struct GNUNET_MULTICAST_Member *mem, | ||
1249 | uint64_t fragment_id, | ||
1250 | uint64_t flags) | ||
1251 | { | ||
1252 | member_replay_request (mem, fragment_id, 0, 0, flags); | ||
1253 | // FIXME: return something useful | ||
1254 | return NULL; | ||
1255 | } | ||
1256 | |||
1257 | |||
1258 | /** | ||
1259 | * Request a message fragment to be replayed. | ||
1260 | * | ||
1261 | * Useful if messages below the @e max_known_fragment_id given when joining are | ||
1262 | * needed and not known to the client. | ||
1263 | * | ||
1264 | * @param member | ||
1265 | * Membership handle. | ||
1266 | * @param message_id | ||
1267 | * ID of the message this client would like to see replayed. | ||
1268 | * @param fragment_offset | ||
1269 | * Offset of the fragment within the message to replay. | ||
1270 | * @param flags | ||
1271 | * Additional flags for the replay request. | ||
1272 | * It is used & defined by GNUNET_MULTICAST_ReplayMessageCallback | ||
1273 | * | ||
1274 | * @return Replay request handle, NULL on error. | ||
1275 | */ | ||
1276 | struct GNUNET_MULTICAST_MemberReplayHandle * | ||
1277 | GNUNET_MULTICAST_member_replay_message (struct GNUNET_MULTICAST_Member *mem, | ||
1278 | uint64_t message_id, | ||
1279 | uint64_t fragment_offset, | ||
1280 | uint64_t flags) | ||
1281 | { | ||
1282 | member_replay_request (mem, 0, message_id, fragment_offset, flags); | ||
1283 | // FIXME: return something useful | ||
1284 | return NULL; | ||
1285 | } | ||
1286 | |||
1287 | |||
1288 | static void | ||
1289 | member_to_origin (struct GNUNET_MULTICAST_Member *mem) | ||
1290 | { | ||
1291 | LOG (GNUNET_ERROR_TYPE_DEBUG, "member_to_origin()\n"); | ||
1292 | struct GNUNET_MULTICAST_Group *grp = &mem->grp; | ||
1293 | struct GNUNET_MULTICAST_MemberTransmitHandle *tmit = &mem->tmit; | ||
1294 | GNUNET_assert (GNUNET_YES == grp->in_transmit); | ||
1295 | |||
1296 | size_t buf_size = GNUNET_MULTICAST_FRAGMENT_MAX_SIZE; | ||
1297 | struct GNUNET_MULTICAST_RequestHeader *req; | ||
1298 | struct GNUNET_MQ_Envelope * | ||
1299 | env = GNUNET_MQ_msg_extra (req, buf_size - sizeof(*req), | ||
1300 | GNUNET_MESSAGE_TYPE_MULTICAST_REQUEST); | ||
1301 | |||
1302 | int ret = tmit->notify (tmit->notify_cls, &buf_size, &req[1]); | ||
1303 | |||
1304 | if (! (GNUNET_YES == ret || GNUNET_NO == ret) | ||
1305 | || GNUNET_MULTICAST_FRAGMENT_MAX_SIZE < buf_size) | ||
1306 | { | ||
1307 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1308 | "MemberTransmitNotify() returned error or invalid message size. " | ||
1309 | "ret=%d, buf_size=%u\n", ret, buf_size); | ||
1310 | /* FIXME: handle error */ | ||
1311 | GNUNET_MQ_discard (env); | ||
1312 | return; | ||
1313 | } | ||
1314 | |||
1315 | if (GNUNET_NO == ret && 0 == buf_size) | ||
1316 | { | ||
1317 | /* Transmission paused. */ | ||
1318 | GNUNET_MQ_discard (env); | ||
1319 | return; | ||
1320 | } | ||
1321 | |||
1322 | req->header.size = htons (sizeof (*req) + buf_size); | ||
1323 | req->request_id = GNUNET_htonll (tmit->request_id); | ||
1324 | req->fragment_offset = GNUNET_ntohll (tmit->fragment_offset); | ||
1325 | tmit->fragment_offset += sizeof (*req) + buf_size; | ||
1326 | |||
1327 | GNUNET_MQ_send (grp->mq, env); | ||
1328 | |||
1329 | if (GNUNET_YES == ret) | ||
1330 | grp->in_transmit = GNUNET_NO; | ||
1331 | } | ||
1332 | |||
1333 | |||
1334 | /** | ||
1335 | * Send a message to the origin of the multicast group. | ||
1336 | * | ||
1337 | * @param mem | ||
1338 | * Membership handle. | ||
1339 | * @param request_id | ||
1340 | * Application layer ID for the request. Opaque to multicast. | ||
1341 | * @param notify | ||
1342 | * Callback to call to get the message. | ||
1343 | * @param notify_cls | ||
1344 | * Closure for @a notify. | ||
1345 | * | ||
1346 | * @return Handle to cancel request, NULL on error (i.e. request already pending). | ||
1347 | */ | ||
1348 | struct GNUNET_MULTICAST_MemberTransmitHandle * | ||
1349 | GNUNET_MULTICAST_member_to_origin (struct GNUNET_MULTICAST_Member *mem, | ||
1350 | uint64_t request_id, | ||
1351 | GNUNET_MULTICAST_MemberTransmitNotify notify, | ||
1352 | void *notify_cls) | ||
1353 | { | ||
1354 | if (GNUNET_YES == mem->grp.in_transmit) | ||
1355 | return NULL; | ||
1356 | mem->grp.in_transmit = GNUNET_YES; | ||
1357 | |||
1358 | struct GNUNET_MULTICAST_MemberTransmitHandle *tmit = &mem->tmit; | ||
1359 | tmit->member = mem; | ||
1360 | tmit->request_id = request_id; | ||
1361 | tmit->fragment_offset = 0; | ||
1362 | tmit->notify = notify; | ||
1363 | tmit->notify_cls = notify_cls; | ||
1364 | |||
1365 | member_to_origin (mem); | ||
1366 | return tmit; | ||
1367 | } | ||
1368 | |||
1369 | |||
1370 | /** | ||
1371 | * Resume message transmission to origin. | ||
1372 | * | ||
1373 | * @param th | ||
1374 | * Transmission to cancel. | ||
1375 | */ | ||
1376 | void | ||
1377 | GNUNET_MULTICAST_member_to_origin_resume (struct GNUNET_MULTICAST_MemberTransmitHandle *th) | ||
1378 | { | ||
1379 | struct GNUNET_MULTICAST_Group *grp = &th->member->grp; | ||
1380 | if (0 != grp->acks_pending || GNUNET_YES != grp->in_transmit) | ||
1381 | return; | ||
1382 | member_to_origin (th->member); | ||
1383 | } | ||
1384 | |||
1385 | |||
1386 | /** | ||
1387 | * Cancel request for message transmission to origin. | ||
1388 | * | ||
1389 | * @param th | ||
1390 | * Transmission to cancel. | ||
1391 | */ | ||
1392 | void | ||
1393 | GNUNET_MULTICAST_member_to_origin_cancel (struct GNUNET_MULTICAST_MemberTransmitHandle *th) | ||
1394 | { | ||
1395 | th->member->grp.in_transmit = GNUNET_NO; | ||
1396 | } | ||
1397 | |||
1398 | |||
1399 | /* end of multicast_api.c */ | ||
diff --git a/src/multicast/test_multicast.c b/src/multicast/test_multicast.c new file mode 100644 index 000000000..b03c52980 --- /dev/null +++ b/src/multicast/test_multicast.c | |||
@@ -0,0 +1,758 @@ | |||
1 | /* | ||
2 | * This file is part of GNUnet | ||
3 | * Copyright (C) 2013 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/test_multicast.c | ||
23 | * @brief Tests for the Multicast API. | ||
24 | * @author Gabor X Toth | ||
25 | */ | ||
26 | |||
27 | #include <inttypes.h> | ||
28 | |||
29 | #include <gnunet/platform.h> | ||
30 | #include <gnunet/gnunet_crypto_lib.h> | ||
31 | #include <gnunet/gnunet_common.h> | ||
32 | #include <gnunet/gnunet_util_lib.h> | ||
33 | #include <gnunet/gnunet_testing_lib.h> | ||
34 | #include "gnunet_multicast_service.h" | ||
35 | |||
36 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) | ||
37 | |||
38 | /** | ||
39 | * Return value from 'main'. | ||
40 | */ | ||
41 | static int res; | ||
42 | |||
43 | /** | ||
44 | * Handle for task for timeout termination. | ||
45 | */ | ||
46 | static struct GNUNET_SCHEDULER_Task * end_badly_task; | ||
47 | |||
48 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
49 | |||
50 | struct GNUNET_PeerIdentity this_peer; | ||
51 | |||
52 | struct GNUNET_MULTICAST_Origin *origin; | ||
53 | struct GNUNET_MULTICAST_Member *member; | ||
54 | |||
55 | struct GNUNET_CRYPTO_EddsaPrivateKey *group_key; | ||
56 | struct GNUNET_CRYPTO_EddsaPublicKey group_pub_key; | ||
57 | |||
58 | struct GNUNET_CRYPTO_EcdsaPrivateKey *member_key; | ||
59 | struct GNUNET_CRYPTO_EcdsaPublicKey member_pub_key; | ||
60 | |||
61 | struct TransmitClosure { | ||
62 | struct GNUNET_MULTICAST_OriginTransmitHandle *orig_tmit; | ||
63 | struct GNUNET_MULTICAST_MemberTransmitHandle *mem_tmit; | ||
64 | char * data[16]; | ||
65 | uint8_t data_delay[16]; | ||
66 | uint8_t data_count; | ||
67 | uint8_t paused; | ||
68 | uint8_t n; | ||
69 | } tmit_cls; | ||
70 | |||
71 | struct OriginClosure { | ||
72 | uint8_t msgs_expected; | ||
73 | uint8_t n; | ||
74 | } origin_cls; | ||
75 | |||
76 | struct MemberClosure { | ||
77 | uint8_t msgs_expected; | ||
78 | size_t n; | ||
79 | } member_cls; | ||
80 | |||
81 | struct GNUNET_MessageHeader *join_req, *join_resp; | ||
82 | |||
83 | enum | ||
84 | { | ||
85 | TEST_NONE = 0, | ||
86 | TEST_ORIGIN_START = 1, | ||
87 | TEST_MEMBER_JOIN_REFUSE = 2, | ||
88 | TEST_MEMBER_JOIN_ADMIT = 3, | ||
89 | TEST_ORIGIN_TO_ALL = 4, | ||
90 | TEST_ORIGIN_TO_ALL_RECV = 5, | ||
91 | TEST_MEMBER_TO_ORIGIN = 6, | ||
92 | TEST_MEMBER_REPLAY_ERROR = 7, | ||
93 | TEST_MEMBER_REPLAY_OK = 8, | ||
94 | TEST_MEMBER_PART = 9, | ||
95 | TEST_ORIGIN_STOP = 10, | ||
96 | } test; | ||
97 | |||
98 | uint64_t replay_fragment_id; | ||
99 | uint64_t replay_flags; | ||
100 | |||
101 | static void | ||
102 | member_join (int t); | ||
103 | |||
104 | |||
105 | /** | ||
106 | * Clean up all resources used. | ||
107 | */ | ||
108 | static void | ||
109 | cleanup () | ||
110 | { | ||
111 | if (NULL != member) | ||
112 | { | ||
113 | GNUNET_MULTICAST_member_part (member, NULL, NULL); | ||
114 | member = NULL; | ||
115 | } | ||
116 | if (NULL != origin) | ||
117 | { | ||
118 | GNUNET_MULTICAST_origin_stop (origin, NULL, NULL); | ||
119 | origin = NULL; | ||
120 | } | ||
121 | } | ||
122 | |||
123 | |||
124 | /** | ||
125 | * Terminate the test case (failure). | ||
126 | * | ||
127 | * @param cls NULL | ||
128 | */ | ||
129 | static void | ||
130 | end_badly (void *cls) | ||
131 | { | ||
132 | res = 1; | ||
133 | cleanup (); | ||
134 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Test FAILED.\n"); | ||
135 | } | ||
136 | |||
137 | |||
138 | /** | ||
139 | * Terminate the test case (success). | ||
140 | * | ||
141 | * @param cls NULL | ||
142 | */ | ||
143 | static void | ||
144 | end_normally (void *cls) | ||
145 | { | ||
146 | res = 0; | ||
147 | cleanup (); | ||
148 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Test PASSED.\n"); | ||
149 | } | ||
150 | |||
151 | |||
152 | /** | ||
153 | * Finish the test case (successfully). | ||
154 | */ | ||
155 | static void | ||
156 | end () | ||
157 | { | ||
158 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Ending tests.\n"); | ||
159 | |||
160 | if (end_badly_task != NULL) | ||
161 | { | ||
162 | GNUNET_SCHEDULER_cancel (end_badly_task); | ||
163 | end_badly_task = NULL; | ||
164 | } | ||
165 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS, | ||
166 | &end_normally, NULL); | ||
167 | } | ||
168 | |||
169 | |||
170 | static void | ||
171 | tmit_resume (void *cls) | ||
172 | { | ||
173 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmission resumed.\n"); | ||
174 | struct TransmitClosure *tmit = cls; | ||
175 | if (NULL != tmit->orig_tmit) | ||
176 | GNUNET_MULTICAST_origin_to_all_resume (tmit->orig_tmit); | ||
177 | else if (NULL != tmit->mem_tmit) | ||
178 | GNUNET_MULTICAST_member_to_origin_resume (tmit->mem_tmit); | ||
179 | } | ||
180 | |||
181 | |||
182 | static int | ||
183 | tmit_notify (void *cls, size_t *data_size, void *data) | ||
184 | { | ||
185 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
186 | "Test #%u: origin_tmit_notify()\n", test); | ||
187 | struct TransmitClosure *tmit = cls; | ||
188 | |||
189 | if (0 == tmit->data_count) | ||
190 | { | ||
191 | *data_size = 0; | ||
192 | return GNUNET_YES; | ||
193 | } | ||
194 | |||
195 | uint16_t size = strlen (tmit->data[tmit->n]); | ||
196 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
197 | "Transmit notify data: %u bytes available, processing fragment %u/%u (size %u).\n", | ||
198 | (unsigned int) *data_size, | ||
199 | tmit->n + 1, | ||
200 | tmit->data_count, | ||
201 | size); | ||
202 | if (*data_size < size) | ||
203 | { | ||
204 | *data_size = 0; | ||
205 | GNUNET_assert (0); | ||
206 | return GNUNET_SYSERR; | ||
207 | } | ||
208 | |||
209 | if (GNUNET_YES != tmit->paused && 0 < tmit->data_delay[tmit->n]) | ||
210 | { | ||
211 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmission paused.\n"); | ||
212 | tmit->paused = GNUNET_YES; | ||
213 | GNUNET_SCHEDULER_add_delayed ( | ||
214 | GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, | ||
215 | tmit->data_delay[tmit->n]), | ||
216 | tmit_resume, tmit); | ||
217 | *data_size = 0; | ||
218 | return GNUNET_NO; | ||
219 | } | ||
220 | tmit->paused = GNUNET_NO; | ||
221 | |||
222 | *data_size = size; | ||
223 | GNUNET_memcpy (data, tmit->data[tmit->n], size); | ||
224 | |||
225 | return ++tmit->n < tmit->data_count ? GNUNET_NO : GNUNET_YES; | ||
226 | } | ||
227 | |||
228 | |||
229 | static void | ||
230 | member_recv_join_request (void *cls, | ||
231 | const struct GNUNET_CRYPTO_EcdsaPublicKey *member_key, | ||
232 | const struct GNUNET_MessageHeader *join_msg, | ||
233 | struct GNUNET_MULTICAST_JoinHandle *jh) | ||
234 | { | ||
235 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
236 | "Test #%u: member_recv_join_request()\n", test); | ||
237 | } | ||
238 | |||
239 | |||
240 | static void | ||
241 | origin_stopped (void *cls) | ||
242 | { | ||
243 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
244 | "Test #%u: origin_stopped()\n", test); | ||
245 | end (); | ||
246 | } | ||
247 | |||
248 | |||
249 | static void | ||
250 | schedule_origin_stop (void *cls) | ||
251 | { | ||
252 | test = TEST_ORIGIN_STOP; | ||
253 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
254 | "Test #%u: origin_stop()\n", test); | ||
255 | GNUNET_MULTICAST_origin_stop (origin, origin_stopped, NULL); | ||
256 | origin = NULL; | ||
257 | } | ||
258 | |||
259 | |||
260 | static void | ||
261 | member_parted (void *cls) | ||
262 | { | ||
263 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
264 | "Test #%u: member_parted()\n", test); | ||
265 | member = NULL; | ||
266 | |||
267 | switch (test) | ||
268 | { | ||
269 | case TEST_MEMBER_JOIN_REFUSE: | ||
270 | // Test 3 starts here | ||
271 | member_join (TEST_MEMBER_JOIN_ADMIT); | ||
272 | break; | ||
273 | |||
274 | case TEST_MEMBER_PART: | ||
275 | GNUNET_SCHEDULER_add_now (&schedule_origin_stop, NULL); | ||
276 | break; | ||
277 | |||
278 | default: | ||
279 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
280 | "Invalid test #%d in member_parted()\n", test); | ||
281 | GNUNET_assert (0); | ||
282 | } | ||
283 | } | ||
284 | |||
285 | |||
286 | static void | ||
287 | schedule_member_part (void *cls) | ||
288 | { | ||
289 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
290 | "Test #%u: schedule_member_part()\n", test); | ||
291 | GNUNET_MULTICAST_member_part (member, member_parted, NULL); | ||
292 | } | ||
293 | |||
294 | |||
295 | static void | ||
296 | member_part () | ||
297 | { | ||
298 | test = TEST_MEMBER_PART; | ||
299 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
300 | "Test #%u: member_part()\n", test); | ||
301 | // Test 10 starts here | ||
302 | GNUNET_SCHEDULER_add_now (&schedule_member_part, NULL); | ||
303 | } | ||
304 | |||
305 | |||
306 | static void | ||
307 | member_replay_ok () | ||
308 | { | ||
309 | // Execution of test 8 here | ||
310 | test = TEST_MEMBER_REPLAY_OK; | ||
311 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
312 | "Test #%u: member_replay_ok()\n", test); | ||
313 | replay_fragment_id = 1; | ||
314 | replay_flags = 1 | 1<<11; | ||
315 | GNUNET_MULTICAST_member_replay_fragment (member, replay_fragment_id, | ||
316 | replay_flags); | ||
317 | } | ||
318 | |||
319 | |||
320 | static void | ||
321 | member_replay_error () | ||
322 | { | ||
323 | test = TEST_MEMBER_REPLAY_ERROR; | ||
324 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
325 | "Test #%u: member_replay_error()\n", test); | ||
326 | replay_fragment_id = 1234; | ||
327 | replay_flags = 11 | 1<<11; | ||
328 | GNUNET_MULTICAST_member_replay_fragment (member, replay_fragment_id, | ||
329 | replay_flags); | ||
330 | } | ||
331 | |||
332 | |||
333 | static void | ||
334 | origin_recv_replay_msg (void *cls, | ||
335 | const struct GNUNET_CRYPTO_EcdsaPublicKey *member_key, | ||
336 | uint64_t message_id, | ||
337 | uint64_t fragment_offset, | ||
338 | uint64_t flags, | ||
339 | struct GNUNET_MULTICAST_ReplayHandle *rh) | ||
340 | { | ||
341 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
342 | "Test #%u: origin_recv_replay_msg()\n", test); | ||
343 | GNUNET_assert (0); | ||
344 | } | ||
345 | |||
346 | |||
347 | static void | ||
348 | member_recv_replay_msg (void *cls, | ||
349 | const struct GNUNET_CRYPTO_EcdsaPublicKey *member_key, | ||
350 | uint64_t message_id, | ||
351 | uint64_t fragment_offset, | ||
352 | uint64_t flags, | ||
353 | struct GNUNET_MULTICAST_ReplayHandle *rh) | ||
354 | { | ||
355 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
356 | "Test #%u: member_recv_replay_msg()\n", test); | ||
357 | GNUNET_assert (0); | ||
358 | } | ||
359 | |||
360 | |||
361 | static void | ||
362 | origin_recv_replay_frag (void *cls, | ||
363 | const struct GNUNET_CRYPTO_EcdsaPublicKey *member_key, | ||
364 | uint64_t fragment_id, | ||
365 | uint64_t flags, | ||
366 | struct GNUNET_MULTICAST_ReplayHandle *rh) | ||
367 | { | ||
368 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
369 | "Test #%u: origin_recv_replay_frag()" | ||
370 | " - fragment_id=%" PRIu64 " flags=%" PRIu64 "\n", | ||
371 | test, fragment_id, flags); | ||
372 | GNUNET_assert (replay_fragment_id == fragment_id && replay_flags == flags); | ||
373 | switch (test) | ||
374 | { | ||
375 | case TEST_MEMBER_REPLAY_ERROR: | ||
376 | // Test 8 starts here | ||
377 | GNUNET_MULTICAST_replay_response (rh, NULL, GNUNET_SYSERR); | ||
378 | member_replay_ok (); | ||
379 | break; | ||
380 | |||
381 | case TEST_MEMBER_REPLAY_OK: | ||
382 | { | ||
383 | struct GNUNET_MULTICAST_MessageHeader mmsg = { | ||
384 | .header = { | ||
385 | .type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE), | ||
386 | .size = htons (sizeof (mmsg)), | ||
387 | }, | ||
388 | .fragment_id = GNUNET_htonll (1), | ||
389 | .message_id = GNUNET_htonll (1), | ||
390 | .fragment_offset = 0, | ||
391 | .group_generation = GNUNET_htonll (1), | ||
392 | .flags = 0, | ||
393 | }; | ||
394 | member_cls.n = 0; | ||
395 | member_cls.msgs_expected = 1; | ||
396 | GNUNET_MULTICAST_replay_response (rh, &mmsg.header, GNUNET_MULTICAST_REC_OK); | ||
397 | GNUNET_MULTICAST_replay_response_end (rh); | ||
398 | break; | ||
399 | } | ||
400 | |||
401 | default: | ||
402 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
403 | "Invalid test #%d in origin_recv_replay_frag()\n", test); | ||
404 | GNUNET_assert (0); | ||
405 | } | ||
406 | } | ||
407 | |||
408 | |||
409 | static void | ||
410 | member_recv_replay_frag (void *cls, | ||
411 | const struct GNUNET_CRYPTO_EcdsaPublicKey *member_key, | ||
412 | uint64_t fragment_id, | ||
413 | uint64_t flags, | ||
414 | struct GNUNET_MULTICAST_ReplayHandle *rh) | ||
415 | { | ||
416 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
417 | "Test #%u: member_recv_replay_frag()\n", test); | ||
418 | GNUNET_assert (0); | ||
419 | } | ||
420 | |||
421 | |||
422 | static void | ||
423 | origin_recv_request (void *cls, | ||
424 | const struct GNUNET_MULTICAST_RequestHeader *req) | ||
425 | { | ||
426 | struct OriginClosure *ocls = cls; | ||
427 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
428 | "Test #%u: origin_recv_request()\n", test); | ||
429 | if (++ocls->n != ocls->msgs_expected) | ||
430 | return; | ||
431 | |||
432 | GNUNET_assert (0 == memcmp (&req->member_pub_key, | ||
433 | &member_pub_key, sizeof (member_pub_key))); | ||
434 | |||
435 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
436 | "Test #%u: verify message content, take first 3 bytes: %.3s\n", | ||
437 | test, (char *)&req[1]); | ||
438 | GNUNET_assert (0 == memcmp (&req[1], "abc", 3)); | ||
439 | |||
440 | // Test 7 starts here | ||
441 | member_replay_error (); | ||
442 | } | ||
443 | |||
444 | |||
445 | static void | ||
446 | member_to_origin () | ||
447 | { | ||
448 | test = TEST_MEMBER_TO_ORIGIN; | ||
449 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
450 | "Test #%u: member_to_origin()\n", test); | ||
451 | |||
452 | struct TransmitClosure *tmit = &tmit_cls; | ||
453 | *tmit = (struct TransmitClosure) {}; | ||
454 | tmit->data[0] = "abc def"; | ||
455 | tmit->data[1] = "ghi jkl mno"; | ||
456 | tmit->data_delay[1] = 2; | ||
457 | tmit->data[2] = "pqr stuw xyz"; | ||
458 | tmit->data_count = 3; | ||
459 | |||
460 | origin_cls.n = 0; | ||
461 | origin_cls.msgs_expected = 1; | ||
462 | |||
463 | tmit->mem_tmit = GNUNET_MULTICAST_member_to_origin (member, 1, | ||
464 | tmit_notify, tmit); | ||
465 | } | ||
466 | |||
467 | |||
468 | static void | ||
469 | member_recv_message (void *cls, | ||
470 | const struct GNUNET_MULTICAST_MessageHeader *msg) | ||
471 | { | ||
472 | struct MemberClosure *mcls = cls; | ||
473 | |||
474 | // Test 5 starts here after message has been received from origin | ||
475 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
476 | "Test #%u: member_recv_message() %u/%u\n", | ||
477 | test, | ||
478 | (unsigned int) (mcls->n + 1), | ||
479 | mcls->msgs_expected); | ||
480 | if (++mcls->n != mcls->msgs_expected) | ||
481 | return; | ||
482 | |||
483 | // FIXME: check message content | ||
484 | |||
485 | switch (test) | ||
486 | { | ||
487 | case TEST_ORIGIN_TO_ALL: | ||
488 | test = TEST_ORIGIN_TO_ALL_RECV; | ||
489 | break; | ||
490 | |||
491 | case TEST_ORIGIN_TO_ALL_RECV: | ||
492 | // Test 6 starts here | ||
493 | member_to_origin (); | ||
494 | break; | ||
495 | |||
496 | case TEST_MEMBER_REPLAY_OK: | ||
497 | // Test 9 starts here | ||
498 | GNUNET_assert (replay_fragment_id == GNUNET_ntohll (msg->fragment_id)); | ||
499 | member_part (); | ||
500 | break; | ||
501 | |||
502 | default: | ||
503 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
504 | "Invalid test #%d in origin_recv_message()\n", test); | ||
505 | GNUNET_assert (0); | ||
506 | } | ||
507 | } | ||
508 | |||
509 | |||
510 | static void | ||
511 | origin_recv_message (void *cls, | ||
512 | const struct GNUNET_MULTICAST_MessageHeader *msg) | ||
513 | { | ||
514 | struct OriginClosure *ocls = cls; | ||
515 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
516 | "Test #%u: origin_recv_message() %u/%u\n", | ||
517 | test, ocls->n + 1, ocls->msgs_expected); | ||
518 | if (++ocls->n != ocls->msgs_expected) | ||
519 | return; | ||
520 | |||
521 | // FIXME: check message content | ||
522 | |||
523 | switch (test) | ||
524 | { | ||
525 | case TEST_ORIGIN_TO_ALL: | ||
526 | // Prepare to execute test 5 | ||
527 | test = TEST_ORIGIN_TO_ALL_RECV; | ||
528 | break; | ||
529 | |||
530 | case TEST_ORIGIN_TO_ALL_RECV: | ||
531 | // Test 6 starts here | ||
532 | member_to_origin (); | ||
533 | break; | ||
534 | |||
535 | default: | ||
536 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
537 | "Invalid test #%d in origin_recv_message()\n", test); | ||
538 | GNUNET_assert (0); | ||
539 | } | ||
540 | } | ||
541 | |||
542 | |||
543 | static void | ||
544 | origin_to_all () | ||
545 | { | ||
546 | test = TEST_ORIGIN_TO_ALL; | ||
547 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
548 | "Test #%u: origin_to_all()\n", test); | ||
549 | |||
550 | struct TransmitClosure *tmit = &tmit_cls; | ||
551 | *tmit = (struct TransmitClosure) {}; | ||
552 | tmit->data[0] = "ABC DEF"; | ||
553 | tmit->data[1] = GNUNET_malloc (GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD + 1); | ||
554 | uint16_t i; | ||
555 | for (i = 0; i < GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD; i++) | ||
556 | tmit->data[1][i] = (0 == i % 10000) ? '0' + i / 10000 : '_'; | ||
557 | tmit->data[2] = "GHI JKL MNO"; | ||
558 | tmit->data_delay[2] = 2; | ||
559 | tmit->data[3] = "PQR STUW XYZ"; | ||
560 | tmit->data_count = 4; | ||
561 | |||
562 | origin_cls.n = member_cls.n = 0; | ||
563 | origin_cls.msgs_expected = member_cls.msgs_expected = tmit->data_count; | ||
564 | |||
565 | tmit->orig_tmit = GNUNET_MULTICAST_origin_to_all (origin, 1, 1, | ||
566 | tmit_notify, tmit); | ||
567 | } | ||
568 | |||
569 | |||
570 | static void | ||
571 | member_recv_join_decision (void *cls, | ||
572 | int is_admitted, | ||
573 | const struct GNUNET_PeerIdentity *peer, | ||
574 | uint16_t relay_count, | ||
575 | const struct GNUNET_PeerIdentity *relays, | ||
576 | const struct GNUNET_MessageHeader *join_msg) | ||
577 | { | ||
578 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
579 | "Test #%u: member_recv_join_decision() - is_admitted: %d\n", | ||
580 | test, is_admitted); | ||
581 | |||
582 | GNUNET_assert (join_msg->size == join_resp->size); | ||
583 | GNUNET_assert (join_msg->type == join_resp->type); | ||
584 | GNUNET_assert (0 == memcmp (join_msg, join_resp, ntohs (join_resp->size))); | ||
585 | |||
586 | switch (test) | ||
587 | { | ||
588 | case TEST_MEMBER_JOIN_REFUSE: | ||
589 | GNUNET_assert (0 == relay_count); | ||
590 | // Test 3 starts here | ||
591 | GNUNET_SCHEDULER_add_now (&schedule_member_part, NULL); | ||
592 | break; | ||
593 | |||
594 | case TEST_MEMBER_JOIN_ADMIT: | ||
595 | GNUNET_assert (1 == relay_count); | ||
596 | GNUNET_assert (0 == memcmp (relays, &this_peer, sizeof (this_peer))); | ||
597 | // Test 4 starts here | ||
598 | origin_to_all (); | ||
599 | break; | ||
600 | |||
601 | default: | ||
602 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
603 | "Invalid test #%d in member_recv_join_decision()\n", test); | ||
604 | GNUNET_assert (0); | ||
605 | } | ||
606 | } | ||
607 | |||
608 | /** | ||
609 | * Test: origin receives join request | ||
610 | */ | ||
611 | static void | ||
612 | origin_recv_join_request (void *cls, | ||
613 | const struct GNUNET_CRYPTO_EcdsaPublicKey *mem_key, | ||
614 | const struct GNUNET_MessageHeader *join_msg, | ||
615 | struct GNUNET_MULTICAST_JoinHandle *jh) | ||
616 | { | ||
617 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
618 | "Test #%u: origin_recv_join_request()\n", test); | ||
619 | |||
620 | GNUNET_assert (0 == memcmp (mem_key, &member_pub_key, sizeof (member_pub_key))); | ||
621 | GNUNET_assert (join_msg->size == join_req->size); | ||
622 | GNUNET_assert (join_msg->type == join_req->type); | ||
623 | GNUNET_assert (0 == memcmp (join_msg, join_req, ntohs (join_req->size))); | ||
624 | |||
625 | char data[] = "here's the decision"; | ||
626 | uint8_t data_size = strlen (data) + 1; | ||
627 | join_resp = GNUNET_malloc (sizeof (join_resp) + data_size); | ||
628 | join_resp->size = htons (sizeof (join_resp) + data_size); | ||
629 | join_resp->type = htons (456); | ||
630 | GNUNET_memcpy (&join_resp[1], data, data_size); | ||
631 | |||
632 | switch (test) | ||
633 | { | ||
634 | case TEST_MEMBER_JOIN_REFUSE: | ||
635 | // Test 3 starts here | ||
636 | GNUNET_MULTICAST_join_decision (jh, GNUNET_NO, 0, NULL, join_resp); | ||
637 | break; | ||
638 | |||
639 | case TEST_MEMBER_JOIN_ADMIT: | ||
640 | // Test 3 is running | ||
641 | GNUNET_MULTICAST_join_decision (jh, GNUNET_YES, 1, &this_peer, join_resp); | ||
642 | break; | ||
643 | |||
644 | default: | ||
645 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
646 | "Invalid test #%d in origin_recv_join_request()\n", test); | ||
647 | GNUNET_assert (0); | ||
648 | break; | ||
649 | } | ||
650 | } | ||
651 | |||
652 | /** | ||
653 | * Test: member joins multicast group | ||
654 | */ | ||
655 | static void | ||
656 | member_join (int t) | ||
657 | { | ||
658 | test = t; | ||
659 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
660 | "Test #%u: member_join()\n", test); | ||
661 | |||
662 | member_key = GNUNET_CRYPTO_ecdsa_key_create (); | ||
663 | GNUNET_CRYPTO_ecdsa_key_get_public (member_key, &member_pub_key); | ||
664 | |||
665 | if (NULL != join_req) | ||
666 | GNUNET_free (join_req); | ||
667 | |||
668 | char data[] = "let me in!"; | ||
669 | uint8_t data_size = strlen (data) + 1; | ||
670 | join_req = GNUNET_malloc (sizeof (join_req) + data_size); | ||
671 | join_req->size = htons (sizeof (join_req) + data_size); | ||
672 | join_req->type = htons (123); | ||
673 | GNUNET_memcpy (&join_req[1], data, data_size); | ||
674 | |||
675 | member = GNUNET_MULTICAST_member_join (cfg, &group_pub_key, member_key, | ||
676 | &this_peer, 1, &this_peer, join_req, | ||
677 | member_recv_join_request, | ||
678 | member_recv_join_decision, | ||
679 | member_recv_replay_frag, | ||
680 | member_recv_replay_msg, | ||
681 | member_recv_message, | ||
682 | &member_cls); | ||
683 | } | ||
684 | |||
685 | /** | ||
686 | * Test: Start a multicast group as origin | ||
687 | */ | ||
688 | static void | ||
689 | origin_start () | ||
690 | { | ||
691 | test = TEST_ORIGIN_START; | ||
692 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
693 | "Test #%u: origin_start()\n", test); | ||
694 | |||
695 | group_key = GNUNET_CRYPTO_eddsa_key_create (); | ||
696 | GNUNET_CRYPTO_eddsa_key_get_public (group_key, &group_pub_key); | ||
697 | |||
698 | origin = GNUNET_MULTICAST_origin_start (cfg, group_key, 0, | ||
699 | origin_recv_join_request, | ||
700 | origin_recv_replay_frag, | ||
701 | origin_recv_replay_msg, | ||
702 | origin_recv_request, | ||
703 | origin_recv_message, | ||
704 | &origin_cls); | ||
705 | // Test 2 starts here | ||
706 | member_join (TEST_MEMBER_JOIN_REFUSE); | ||
707 | } | ||
708 | |||
709 | |||
710 | /** | ||
711 | * Main function of the test, run from scheduler. | ||
712 | * | ||
713 | * @param cls NULL | ||
714 | * @param cfg configuration we use (also to connect to Multicast service) | ||
715 | * @param peer handle to access more of the peer (not used) | ||
716 | */ | ||
717 | static void | ||
718 | #if DEBUG_TEST_MULTICAST | ||
719 | run (void *cls, | ||
720 | char *const *args, | ||
721 | const char *cfgfile, | ||
722 | const struct GNUNET_CONFIGURATION_Handle *c) | ||
723 | #else | ||
724 | run (void *cls, | ||
725 | const struct GNUNET_CONFIGURATION_Handle *c, | ||
726 | struct GNUNET_TESTING_Peer *peer) | ||
727 | #endif | ||
728 | { | ||
729 | cfg = c; | ||
730 | end_badly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, | ||
731 | &end_badly, NULL); | ||
732 | GNUNET_CRYPTO_get_peer_identity (cfg, &this_peer); | ||
733 | |||
734 | // Test 1 starts here | ||
735 | origin_start (); | ||
736 | } | ||
737 | |||
738 | |||
739 | int | ||
740 | main (int argc, char *argv[]) | ||
741 | { | ||
742 | res = 1; | ||
743 | #if DEBUG_TEST_MULTICAST | ||
744 | const struct GNUNET_GETOPT_CommandLineOption opts[] = { | ||
745 | GNUNET_GETOPT_OPTION_END | ||
746 | }; | ||
747 | if (GNUNET_OK != GNUNET_PROGRAM_run (argc, argv, "test-multicast", | ||
748 | "test-multicast [options]", | ||
749 | opts, &run, NULL)) | ||
750 | return 1; | ||
751 | #else | ||
752 | if (0 != GNUNET_TESTING_peer_run ("test-multicast", "test_multicast.conf", &run, NULL)) | ||
753 | return 1; | ||
754 | #endif | ||
755 | return res; | ||
756 | } | ||
757 | |||
758 | /* end of test_multicast.c */ | ||
diff --git a/src/multicast/test_multicast_2peers.c b/src/multicast/test_multicast_2peers.c new file mode 100644 index 000000000..009a0a11a --- /dev/null +++ b/src/multicast/test_multicast_2peers.c | |||
@@ -0,0 +1,520 @@ | |||
1 | /* | ||
2 | * This file is part of GNUnet | ||
3 | * Copyright (C) 2013 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/test_multicast_2peers.c | ||
23 | * @brief Tests for the Multicast API with two peers doing the ping | ||
24 | * pong test. | ||
25 | * @author xrs | ||
26 | */ | ||
27 | |||
28 | #include <inttypes.h> | ||
29 | |||
30 | #include <gnunet/platform.h> | ||
31 | #include <gnunet/gnunet_crypto_lib.h> | ||
32 | #include <gnunet/gnunet_common.h> | ||
33 | #include <gnunet/gnunet_util_lib.h> | ||
34 | #include <gnunet/gnunet_testbed_service.h> | ||
35 | #include "gnunet_multicast_service.h" | ||
36 | |||
37 | #define NUM_PEERS 2 | ||
38 | |||
39 | static struct GNUNET_TESTBED_Operation *op0; | ||
40 | static struct GNUNET_TESTBED_Operation *op1; | ||
41 | static struct GNUNET_TESTBED_Operation *pi_op0; | ||
42 | static struct GNUNET_TESTBED_Operation *pi_op1; | ||
43 | |||
44 | static struct GNUNET_TESTBED_Peer **peers; | ||
45 | const struct GNUNET_PeerIdentity *peer_id[2]; | ||
46 | |||
47 | static struct GNUNET_SCHEDULER_Task *timeout_tid; | ||
48 | |||
49 | static struct GNUNET_MULTICAST_Origin *origin; | ||
50 | static struct GNUNET_MULTICAST_Member *member; | ||
51 | |||
52 | struct GNUNET_CRYPTO_EddsaPrivateKey *group_key; | ||
53 | struct GNUNET_CRYPTO_EddsaPublicKey group_pub_key; | ||
54 | |||
55 | struct GNUNET_CRYPTO_EcdsaPrivateKey *member_key; | ||
56 | struct GNUNET_CRYPTO_EcdsaPublicKey member_pub_key; | ||
57 | |||
58 | /** | ||
59 | * Global result for testcase. | ||
60 | */ | ||
61 | static int result; | ||
62 | |||
63 | |||
64 | /** | ||
65 | * Function run on CTRL-C or shutdown (i.e. success/timeout/etc.). | ||
66 | * Cleans up. | ||
67 | */ | ||
68 | static void | ||
69 | shutdown_task (void *cls) | ||
70 | { | ||
71 | if (NULL != op0) | ||
72 | { | ||
73 | GNUNET_TESTBED_operation_done (op0); | ||
74 | op0 = NULL; | ||
75 | } | ||
76 | if (NULL != op1) | ||
77 | { | ||
78 | GNUNET_TESTBED_operation_done (op1); | ||
79 | op1 = NULL; | ||
80 | } | ||
81 | if (NULL != pi_op0) | ||
82 | { | ||
83 | GNUNET_TESTBED_operation_done (pi_op0); | ||
84 | pi_op0 = NULL; | ||
85 | } | ||
86 | if (NULL != pi_op1) | ||
87 | { | ||
88 | GNUNET_TESTBED_operation_done (pi_op1); | ||
89 | pi_op1 = NULL; | ||
90 | } | ||
91 | if (NULL != timeout_tid) | ||
92 | { | ||
93 | GNUNET_SCHEDULER_cancel (timeout_tid); | ||
94 | timeout_tid = NULL; | ||
95 | } | ||
96 | } | ||
97 | |||
98 | |||
99 | static void | ||
100 | timeout_task (void *cls) | ||
101 | { | ||
102 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
103 | "Timeout!\n"); | ||
104 | result = GNUNET_SYSERR; | ||
105 | GNUNET_SCHEDULER_shutdown (); | ||
106 | } | ||
107 | |||
108 | |||
109 | static void | ||
110 | member_join_request (void *cls, | ||
111 | const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key, | ||
112 | const struct GNUNET_MessageHeader *join_msg, | ||
113 | struct GNUNET_MULTICAST_JoinHandle *jh) | ||
114 | { | ||
115 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
116 | "Member sent a join request.\n"); | ||
117 | |||
118 | } | ||
119 | |||
120 | |||
121 | static int | ||
122 | notify (void *cls, | ||
123 | size_t *data_size, | ||
124 | void *data) | ||
125 | { | ||
126 | |||
127 | char text[] = "ping"; | ||
128 | *data_size = strlen(text)+1; | ||
129 | GNUNET_memcpy(data, text, *data_size); | ||
130 | |||
131 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
132 | "Member sents message to origin: %s\n", text); | ||
133 | |||
134 | return GNUNET_YES; | ||
135 | } | ||
136 | |||
137 | |||
138 | static void | ||
139 | member_join_decision (void *cls, | ||
140 | int is_admitted, | ||
141 | const struct GNUNET_PeerIdentity *peer, | ||
142 | uint16_t relay_count, | ||
143 | const struct GNUNET_PeerIdentity *relays, | ||
144 | const struct GNUNET_MessageHeader *join_msg) | ||
145 | { | ||
146 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
147 | "Member received a decision from origin: %s\n", | ||
148 | (GNUNET_YES == is_admitted) | ||
149 | ? "accepted" | ||
150 | : "rejected"); | ||
151 | |||
152 | if (GNUNET_YES == is_admitted) | ||
153 | { | ||
154 | struct GNUNET_MULTICAST_MemberTransmitHandle *req; | ||
155 | |||
156 | // FIXME: move to MQ-style API! | ||
157 | req = GNUNET_MULTICAST_member_to_origin (member, | ||
158 | 0, | ||
159 | ¬ify, | ||
160 | NULL); | ||
161 | } | ||
162 | } | ||
163 | |||
164 | |||
165 | static void | ||
166 | member_message (void *cls, | ||
167 | const struct GNUNET_MULTICAST_MessageHeader *msg) | ||
168 | { | ||
169 | if (0 != strncmp ("pong", (char *)&msg[1], 4)) | ||
170 | { | ||
171 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "member did not receive pong\n"); | ||
172 | result = GNUNET_SYSERR; | ||
173 | GNUNET_SCHEDULER_shutdown (); | ||
174 | } | ||
175 | |||
176 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
177 | "member receives: %s\n", (char *)&msg[1]); | ||
178 | |||
179 | // Testcase ends here. | ||
180 | result = GNUNET_YES; | ||
181 | GNUNET_SCHEDULER_shutdown (); | ||
182 | } | ||
183 | |||
184 | |||
185 | static void | ||
186 | origin_join_request (void *cls, | ||
187 | const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key, | ||
188 | const struct GNUNET_MessageHeader *join_msg, | ||
189 | struct GNUNET_MULTICAST_JoinHandle *jh) | ||
190 | { | ||
191 | struct GNUNET_MessageHeader *join_resp; | ||
192 | |||
193 | uint8_t data_size = ntohs (join_msg->size); | ||
194 | |||
195 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
196 | "origin got a join request...\n"); | ||
197 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
198 | "origin receives: '%s'\n", (char *)&join_msg[1]); | ||
199 | |||
200 | const char data[] = "Come in!"; | ||
201 | data_size = strlen (data) + 1; | ||
202 | join_resp = GNUNET_malloc (sizeof (join_resp) + data_size); | ||
203 | join_resp->size = htons (sizeof (join_resp) + data_size); | ||
204 | join_resp->type = htons (123); | ||
205 | GNUNET_memcpy (&join_resp[1], data, data_size); | ||
206 | |||
207 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
208 | "origin sends: '%s'\n", data); | ||
209 | |||
210 | GNUNET_MULTICAST_join_decision (jh, | ||
211 | GNUNET_YES, | ||
212 | 0, | ||
213 | NULL, | ||
214 | join_resp); | ||
215 | GNUNET_free (join_resp); | ||
216 | result = GNUNET_OK; | ||
217 | } | ||
218 | |||
219 | |||
220 | int | ||
221 | origin_notify (void *cls, | ||
222 | size_t *data_size, | ||
223 | void *data) | ||
224 | { | ||
225 | char text[] = "pong"; | ||
226 | |||
227 | *data_size = strlen(text)+1; | ||
228 | GNUNET_memcpy (data, | ||
229 | text, | ||
230 | *data_size); | ||
231 | |||
232 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin sends (to all): %s\n", text); | ||
233 | |||
234 | return GNUNET_YES; | ||
235 | } | ||
236 | |||
237 | |||
238 | static void | ||
239 | origin_request (void *cls, | ||
240 | const struct GNUNET_MULTICAST_RequestHeader *req) | ||
241 | { | ||
242 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin receives: %s\n", (char *)&req[1]); | ||
243 | |||
244 | if (0 != strncmp ("ping", (char *)&req[1], 4)) | ||
245 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "origin didn't reveice a correct request"); | ||
246 | |||
247 | GNUNET_MULTICAST_origin_to_all (origin, | ||
248 | 0, | ||
249 | 0, | ||
250 | origin_notify, | ||
251 | NULL); | ||
252 | } | ||
253 | |||
254 | |||
255 | static void | ||
256 | origin_message (void *cls, | ||
257 | const struct GNUNET_MULTICAST_MessageHeader *msg) | ||
258 | { | ||
259 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin message msg\n"); | ||
260 | } | ||
261 | |||
262 | |||
263 | static void | ||
264 | service_connect1 (void *cls, | ||
265 | struct GNUNET_TESTBED_Operation *op, | ||
266 | void *ca_result, | ||
267 | const char *emsg) | ||
268 | { | ||
269 | member = ca_result; | ||
270 | |||
271 | if (NULL == member) | ||
272 | { | ||
273 | result = GNUNET_SYSERR; | ||
274 | GNUNET_SCHEDULER_shutdown (); | ||
275 | } | ||
276 | else | ||
277 | { | ||
278 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connected to multicast service of member\n"); | ||
279 | } | ||
280 | } | ||
281 | |||
282 | |||
283 | static void | ||
284 | multicast_da1 (void *cls, | ||
285 | void * op_result) | ||
286 | { | ||
287 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
288 | "Member parting from multicast group\n"); | ||
289 | |||
290 | GNUNET_MULTICAST_member_part (member, NULL, NULL); | ||
291 | } | ||
292 | |||
293 | |||
294 | static void * | ||
295 | multicast_ca1 (void *cls, | ||
296 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
297 | { | ||
298 | struct GNUNET_MessageHeader *join_msg; | ||
299 | void *ret; | ||
300 | |||
301 | // Get members keys | ||
302 | member_key = GNUNET_CRYPTO_ecdsa_key_create (); | ||
303 | GNUNET_CRYPTO_ecdsa_key_get_public (member_key, &member_pub_key); | ||
304 | |||
305 | char data[] = "Hi, can I enter?"; | ||
306 | uint8_t data_size = strlen (data) + 1; | ||
307 | join_msg = GNUNET_malloc (sizeof (join_msg) + data_size); | ||
308 | join_msg->size = htons (sizeof (join_msg) + data_size); | ||
309 | join_msg->type = htons (123); | ||
310 | GNUNET_memcpy (&join_msg[1], data, data_size); | ||
311 | |||
312 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
313 | "Members tries to join multicast group\n"); | ||
314 | |||
315 | ret = GNUNET_MULTICAST_member_join (cfg, | ||
316 | &group_pub_key, | ||
317 | member_key, | ||
318 | peer_id[0], | ||
319 | 0, | ||
320 | NULL, | ||
321 | join_msg, /* join message */ | ||
322 | member_join_request, | ||
323 | member_join_decision, | ||
324 | NULL, /* no test for member_replay_frag */ | ||
325 | NULL, /* no test for member_replay_msg */ | ||
326 | member_message, | ||
327 | NULL); | ||
328 | GNUNET_free (join_msg); | ||
329 | return ret; | ||
330 | } | ||
331 | |||
332 | |||
333 | static void | ||
334 | peer_information_cb (void *cls, | ||
335 | struct GNUNET_TESTBED_Operation *op, | ||
336 | const struct GNUNET_TESTBED_PeerInformation *pinfo, | ||
337 | const char *emsg) | ||
338 | { | ||
339 | int i = (int) (long) cls; | ||
340 | |||
341 | if (NULL == pinfo) | ||
342 | { | ||
343 | result = GNUNET_SYSERR; | ||
344 | GNUNET_SCHEDULER_shutdown (); | ||
345 | } | ||
346 | |||
347 | peer_id[i] = pinfo->result.id; | ||
348 | |||
349 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
350 | "Got peer information of %s (%s)\n", (0==i)?"origin":"member" ,GNUNET_i2s(pinfo->result.id)); | ||
351 | |||
352 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
353 | "Create member peer\n"); | ||
354 | |||
355 | if (0 == i) | ||
356 | { | ||
357 | /* connect to multicast service of member */ | ||
358 | op1 = GNUNET_TESTBED_service_connect (NULL, /* Closure for operation */ | ||
359 | peers[1], /* The peer whose service to connect to */ | ||
360 | "multicast", /* The name of the service */ | ||
361 | service_connect1, /* callback to call after a handle to service | ||
362 | is opened */ | ||
363 | NULL, /* closure for the above callback */ | ||
364 | multicast_ca1, /* callback to call with peer's configuration; | ||
365 | this should open the needed service connection */ | ||
366 | multicast_da1, /* callback to be called when closing the | ||
367 | opened service connection */ | ||
368 | NULL); /* closure for the above two callbacks */ | ||
369 | } | ||
370 | } | ||
371 | |||
372 | |||
373 | /** | ||
374 | * Test logic of peer "0" being origin starts here. | ||
375 | * | ||
376 | * @param cls closure, for the example: NULL | ||
377 | * @param op should be equal to "dht_op" | ||
378 | * @param ca_result result of the connect operation, the | ||
379 | * connection to the DHT service | ||
380 | * @param emsg error message, if testbed somehow failed to | ||
381 | * connect to the DHT. | ||
382 | */ | ||
383 | static void | ||
384 | service_connect0 (void *cls, | ||
385 | struct GNUNET_TESTBED_Operation *op, | ||
386 | void *ca_result, | ||
387 | const char *emsg) | ||
388 | { | ||
389 | origin = ca_result; | ||
390 | |||
391 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
392 | "Connected to multicast service of origin\n"); | ||
393 | |||
394 | // Get GNUnet identity of origin | ||
395 | pi_op0 = GNUNET_TESTBED_peer_get_information (peers[0], | ||
396 | GNUNET_TESTBED_PIT_IDENTITY, | ||
397 | peer_information_cb, | ||
398 | (void *) 0); | ||
399 | // Get GNUnet identity of member | ||
400 | pi_op1 = GNUNET_TESTBED_peer_get_information (peers[1], | ||
401 | GNUNET_TESTBED_PIT_IDENTITY, | ||
402 | peer_information_cb, | ||
403 | (void *) 1); | ||
404 | |||
405 | /* Connection to service successful. Here we'd usually do something with | ||
406 | * the service. */ | ||
407 | result = GNUNET_OK; | ||
408 | //GNUNET_SCHEDULER_shutdown (); /* Also kills the testbed */ | ||
409 | } | ||
410 | |||
411 | |||
412 | |||
413 | /** | ||
414 | * Function run when service multicast has started and is providing us | ||
415 | * with a configuration file. | ||
416 | */ | ||
417 | static void * | ||
418 | multicast_ca0 (void *cls, | ||
419 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
420 | { | ||
421 | group_key = GNUNET_CRYPTO_eddsa_key_create (); | ||
422 | GNUNET_CRYPTO_eddsa_key_get_public (group_key, &group_pub_key); | ||
423 | |||
424 | return GNUNET_MULTICAST_origin_start (cfg, | ||
425 | group_key, | ||
426 | 0, | ||
427 | origin_join_request, | ||
428 | NULL, /* no test for origin_replay_frag */ | ||
429 | NULL, /* no test for origin_replay_msg */ | ||
430 | origin_request, | ||
431 | origin_message, | ||
432 | NULL); | ||
433 | } | ||
434 | |||
435 | static void | ||
436 | multicast_da0 (void *cls, | ||
437 | void *op_result) | ||
438 | { | ||
439 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
440 | "Origin closes multicast group\n"); | ||
441 | |||
442 | GNUNET_MULTICAST_origin_stop (origin, NULL, NULL); | ||
443 | } | ||
444 | |||
445 | |||
446 | /** | ||
447 | * Main function inovked from TESTBED once all of the | ||
448 | * peers are up and running. This one then connects | ||
449 | * just to the multicast service of peer 0 and 1. | ||
450 | * Peer 0 is going to be origin. | ||
451 | * Peer 1 is going to be one member. | ||
452 | * Origin will start a multicast group and the member will try to join it. | ||
453 | * After that we execute some multicast test. | ||
454 | * | ||
455 | * @param cls closure | ||
456 | * @param h the run handle | ||
457 | * @param peers started peers for the test | ||
458 | * @param num_peers size of the 'peers' array | ||
459 | * @param links_succeeded number of links between peers that were created | ||
460 | * @param links_failed number of links testbed was unable to establish | ||
461 | */ | ||
462 | static void | ||
463 | testbed_master (void *cls, | ||
464 | struct GNUNET_TESTBED_RunHandle *h, | ||
465 | unsigned int num_peers, | ||
466 | struct GNUNET_TESTBED_Peer **p, | ||
467 | unsigned int links_succeeded, | ||
468 | unsigned int links_failed) | ||
469 | { | ||
470 | /* Testbed is ready with peers running and connected in a pre-defined overlay | ||
471 | topology (FIXME) */ | ||
472 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
473 | "Connected to testbed_master()\n"); | ||
474 | |||
475 | peers = p; | ||
476 | |||
477 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
478 | "Create origin peer\n"); | ||
479 | op0 = GNUNET_TESTBED_service_connect (NULL, /* Closure for operation */ | ||
480 | peers[0], /* The peer whose service to connect to */ | ||
481 | "multicast", /* The name of the service */ | ||
482 | service_connect0, /* callback to call after a handle to service | ||
483 | is opened */ | ||
484 | NULL, /* closure for the above callback */ | ||
485 | multicast_ca0, /* callback to call with peer's configuration; | ||
486 | this should open the needed service connection */ | ||
487 | multicast_da0, /* callback to be called when closing the | ||
488 | opened service connection */ | ||
489 | NULL); /* closure for the above two callbacks */ | ||
490 | |||
491 | GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); /* Schedule a new task on shutdown */ | ||
492 | |||
493 | /* Schedule the shutdown task with a delay of a few Seconds */ | ||
494 | timeout_tid = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 50), | ||
495 | &timeout_task, NULL); | ||
496 | } | ||
497 | |||
498 | |||
499 | int | ||
500 | main (int argc, char *argv[]) | ||
501 | { | ||
502 | int ret; | ||
503 | |||
504 | result = GNUNET_SYSERR; | ||
505 | ret = GNUNET_TESTBED_test_run | ||
506 | ("test-multicast-2peers", /* test case name */ | ||
507 | "test_multicast.conf", /* template configuration */ | ||
508 | NUM_PEERS, /* number of peers to start */ | ||
509 | 0LL, /* Event mask - set to 0 for no event notifications */ | ||
510 | NULL, /* Controller event callback */ | ||
511 | NULL, /* Closure for controller event callback */ | ||
512 | testbed_master, /* continuation callback to be called when testbed setup is complete */ | ||
513 | NULL); /* Closure for the test_master callback */ | ||
514 | if ( (GNUNET_OK != ret) || (GNUNET_OK != result) ) | ||
515 | return 1; | ||
516 | return 0; | ||
517 | } | ||
518 | |||
519 | |||
520 | /* end of test_multicast_2peers.c */ | ||
diff --git a/src/multicast/test_multicast_multipeer.c b/src/multicast/test_multicast_multipeer.c new file mode 100644 index 000000000..95f42f4dd --- /dev/null +++ b/src/multicast/test_multicast_multipeer.c | |||
@@ -0,0 +1,643 @@ | |||
1 | /* | ||
2 | * This file is part of GNUnet | ||
3 | * Copyright (C) 2013 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/test_multicast_multipeers.c | ||
23 | * @brief Tests for the Multicast API with multiple peers. | ||
24 | * @author xrs | ||
25 | */ | ||
26 | |||
27 | #include <inttypes.h> | ||
28 | |||
29 | #include <gnunet/platform.h> | ||
30 | #include <gnunet/gnunet_crypto_lib.h> | ||
31 | #include <gnunet/gnunet_common.h> | ||
32 | #include <gnunet/gnunet_util_lib.h> | ||
33 | #include <gnunet/gnunet_testbed_service.h> | ||
34 | #include "gnunet_multicast_service.h" | ||
35 | |||
36 | #define PEERS_REQUESTED 12 | ||
37 | |||
38 | struct MulticastPeerContext | ||
39 | { | ||
40 | int peer; /* peer number */ | ||
41 | struct GNUNET_CRYPTO_EcdsaPrivateKey *key; | ||
42 | const struct GNUNET_PeerIdentity *id; | ||
43 | struct GNUNET_TESTBED_Operation *op; /* not yet in use */ | ||
44 | struct GNUNET_TESTBED_Operation *pi_op; /* not yet in use */ | ||
45 | int test_ok; | ||
46 | }; | ||
47 | |||
48 | enum pingpong | ||
49 | { | ||
50 | PING = 1, | ||
51 | PONG = 2 | ||
52 | }; | ||
53 | |||
54 | struct pingpong_msg | ||
55 | { | ||
56 | int peer; | ||
57 | enum pingpong msg; | ||
58 | }; | ||
59 | |||
60 | static void service_connect (void *cls, | ||
61 | struct GNUNET_TESTBED_Operation *op, | ||
62 | void *ca_result, | ||
63 | const char *emsg); | ||
64 | |||
65 | static struct MulticastPeerContext **multicast_peers; | ||
66 | static struct GNUNET_TESTBED_Peer **peers; | ||
67 | |||
68 | static struct GNUNET_TESTBED_Operation *op[PEERS_REQUESTED]; | ||
69 | static struct GNUNET_TESTBED_Operation *pi_op[PEERS_REQUESTED]; | ||
70 | |||
71 | static struct GNUNET_MULTICAST_Origin *origin; | ||
72 | static struct GNUNET_MULTICAST_Member *members[PEERS_REQUESTED]; /* first element always empty */ | ||
73 | |||
74 | static struct GNUNET_SCHEDULER_Task *timeout_tid; | ||
75 | |||
76 | static struct GNUNET_CRYPTO_EddsaPrivateKey *group_key; | ||
77 | static struct GNUNET_CRYPTO_EddsaPublicKey group_pub_key; | ||
78 | static struct GNUNET_HashCode group_pub_key_hash; | ||
79 | |||
80 | /** | ||
81 | * Global result for testcase. | ||
82 | */ | ||
83 | static int result; | ||
84 | |||
85 | /** | ||
86 | * Function run on CTRL-C or shutdown (i.e. success/timeout/etc.). | ||
87 | * Cleans up. | ||
88 | */ | ||
89 | static void | ||
90 | shutdown_task (void *cls) | ||
91 | { | ||
92 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
93 | "shutdown_task!\n"); | ||
94 | for (int i=0;i<PEERS_REQUESTED;i++) | ||
95 | { | ||
96 | if (NULL != op[i]) | ||
97 | { | ||
98 | GNUNET_TESTBED_operation_done(op[i]); | ||
99 | op[i] = NULL; | ||
100 | } | ||
101 | if (NULL != pi_op[i]) | ||
102 | { | ||
103 | GNUNET_TESTBED_operation_done (pi_op[i]); | ||
104 | pi_op[i] = NULL; | ||
105 | } | ||
106 | } | ||
107 | |||
108 | if (NULL != multicast_peers) | ||
109 | { | ||
110 | for (int i=0; i < PEERS_REQUESTED; i++) | ||
111 | { | ||
112 | GNUNET_free_non_null (multicast_peers[i]->key); | ||
113 | GNUNET_free (multicast_peers[i]); | ||
114 | multicast_peers[i] = NULL; | ||
115 | } | ||
116 | GNUNET_free (multicast_peers); | ||
117 | multicast_peers = NULL; | ||
118 | } | ||
119 | |||
120 | if (NULL != timeout_tid) | ||
121 | { | ||
122 | GNUNET_SCHEDULER_cancel (timeout_tid); | ||
123 | timeout_tid = NULL; | ||
124 | } | ||
125 | } | ||
126 | |||
127 | |||
128 | static void | ||
129 | timeout_task (void *cls) | ||
130 | { | ||
131 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
132 | "Timeout!\n"); | ||
133 | result = GNUNET_SYSERR; | ||
134 | GNUNET_SCHEDULER_shutdown (); | ||
135 | } | ||
136 | |||
137 | |||
138 | static void | ||
139 | member_join_request (void *cls, | ||
140 | const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key, | ||
141 | const struct GNUNET_MessageHeader *join_msg, | ||
142 | struct GNUNET_MULTICAST_JoinHandle *jh) | ||
143 | { | ||
144 | struct MulticastPeerContext *mc_peer = (struct MulticastPeerContext*)cls; | ||
145 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
146 | "Peer #%u (%s) sent a join request.\n", | ||
147 | mc_peer->peer, | ||
148 | GNUNET_i2s (multicast_peers[mc_peer->peer]->id)); | ||
149 | } | ||
150 | |||
151 | |||
152 | static int | ||
153 | notify (void *cls, | ||
154 | size_t *data_size, | ||
155 | void *data) | ||
156 | { | ||
157 | struct MulticastPeerContext *mc_peer = (struct MulticastPeerContext*)cls; | ||
158 | |||
159 | struct pingpong_msg *pp_msg = GNUNET_new (struct pingpong_msg); | ||
160 | pp_msg->peer = mc_peer->peer; | ||
161 | pp_msg->msg = PING; | ||
162 | |||
163 | *data_size = sizeof (struct pingpong_msg); | ||
164 | GNUNET_memcpy(data, pp_msg, *data_size); | ||
165 | GNUNET_free (pp_msg); | ||
166 | |||
167 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
168 | "Peer #%u sents ping to origin\n", mc_peer->peer); | ||
169 | |||
170 | return GNUNET_YES; | ||
171 | } | ||
172 | |||
173 | |||
174 | static void | ||
175 | member_join_decision (void *cls, | ||
176 | int is_admitted, | ||
177 | const struct GNUNET_PeerIdentity *peer, | ||
178 | uint16_t relay_count, | ||
179 | const struct GNUNET_PeerIdentity *relays, | ||
180 | const struct GNUNET_MessageHeader *join_msg) | ||
181 | { | ||
182 | struct MulticastPeerContext *mc_peer = (struct MulticastPeerContext*)cls; | ||
183 | |||
184 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
185 | "Peer #%u (%s) received a decision from origin: %s\n", | ||
186 | mc_peer->peer, | ||
187 | GNUNET_i2s (multicast_peers[mc_peer->peer]->id), | ||
188 | (GNUNET_YES == is_admitted)?"accepted":"rejected"); | ||
189 | |||
190 | if (GNUNET_YES == is_admitted) | ||
191 | { | ||
192 | GNUNET_MULTICAST_member_to_origin (members[mc_peer->peer], | ||
193 | 0, | ||
194 | notify, | ||
195 | cls); | ||
196 | |||
197 | } | ||
198 | } | ||
199 | |||
200 | |||
201 | static void | ||
202 | member_replay_frag () | ||
203 | { | ||
204 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
205 | "member replay frag...\n"); | ||
206 | } | ||
207 | |||
208 | |||
209 | static void | ||
210 | member_replay_msg () | ||
211 | { | ||
212 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
213 | "member replay msg...\n"); | ||
214 | } | ||
215 | |||
216 | |||
217 | static void | ||
218 | origin_disconnected_cb (void *cls) | ||
219 | { | ||
220 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
221 | "Origin disconnected. Shutting down.\n"); | ||
222 | result = GNUNET_YES; | ||
223 | GNUNET_SCHEDULER_shutdown (); | ||
224 | } | ||
225 | |||
226 | |||
227 | static void | ||
228 | member_disconnected_cb (void *cls) | ||
229 | { | ||
230 | for (int i = 1; i < PEERS_REQUESTED; ++i) | ||
231 | if (GNUNET_NO == multicast_peers[i]->test_ok) | ||
232 | return; | ||
233 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
234 | "All member disconnected. Stopping origin.\n"); | ||
235 | GNUNET_MULTICAST_origin_stop (origin, origin_disconnected_cb, cls); | ||
236 | } | ||
237 | |||
238 | |||
239 | static void | ||
240 | member_message (void *cls, | ||
241 | const struct GNUNET_MULTICAST_MessageHeader *msg) | ||
242 | { | ||
243 | struct MulticastPeerContext *mc_peer = (struct MulticastPeerContext*)cls; | ||
244 | struct pingpong_msg *pp_msg = (struct pingpong_msg*) &(msg[1]); | ||
245 | |||
246 | if (PONG == pp_msg->msg && mc_peer->peer == pp_msg->peer) | ||
247 | { | ||
248 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
249 | "peer #%i (%s) receives a pong\n", | ||
250 | mc_peer->peer, | ||
251 | GNUNET_i2s (multicast_peers[mc_peer->peer]->id)); | ||
252 | mc_peer->test_ok = GNUNET_OK; | ||
253 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
254 | "peer #%u (%s) parting from multicast group\n", | ||
255 | mc_peer->peer, | ||
256 | GNUNET_i2s (multicast_peers[mc_peer->peer]->id)); | ||
257 | |||
258 | GNUNET_MULTICAST_member_part (members[mc_peer->peer], member_disconnected_cb, cls); | ||
259 | } | ||
260 | } | ||
261 | |||
262 | |||
263 | static void | ||
264 | origin_join_request (void *cls, | ||
265 | const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key, | ||
266 | const struct GNUNET_MessageHeader *join_msg, | ||
267 | struct GNUNET_MULTICAST_JoinHandle *jh) | ||
268 | { | ||
269 | struct GNUNET_MessageHeader *join_resp; | ||
270 | |||
271 | uint8_t data_size = ntohs (join_msg->size); | ||
272 | |||
273 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
274 | "origin got a join request...\n"); | ||
275 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
276 | "origin receives: '%s'\n", (char *)&join_msg[1]); | ||
277 | |||
278 | char data[] = "Come in!"; | ||
279 | data_size = strlen (data) + 1; | ||
280 | join_resp = GNUNET_malloc (sizeof (join_resp) + data_size); | ||
281 | join_resp->size = htons (sizeof (join_resp) + data_size); | ||
282 | join_resp->type = htons (123); | ||
283 | GNUNET_memcpy (&join_resp[1], data, data_size); | ||
284 | |||
285 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
286 | "origin sends: '%s'\n", data); | ||
287 | |||
288 | GNUNET_MULTICAST_join_decision (jh, | ||
289 | GNUNET_YES, | ||
290 | 0, | ||
291 | NULL, | ||
292 | join_resp); | ||
293 | |||
294 | result = GNUNET_OK; | ||
295 | } | ||
296 | |||
297 | |||
298 | static void | ||
299 | origin_replay_frag (void *cls, | ||
300 | const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key, | ||
301 | uint64_t fragment_id, | ||
302 | uint64_t flags, | ||
303 | struct GNUNET_MULTICAST_ReplayHandle *rh) | ||
304 | { | ||
305 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin replay fraq msg\n"); | ||
306 | } | ||
307 | |||
308 | |||
309 | static void | ||
310 | origin_replay_msg (void *cls, | ||
311 | const struct GNUNET_CRYPTO_EcdsaPublicKey *member_pub_key, | ||
312 | uint64_t message_id, | ||
313 | uint64_t fragment_offset, | ||
314 | uint64_t flags, | ||
315 | struct GNUNET_MULTICAST_ReplayHandle *rh) | ||
316 | { | ||
317 | |||
318 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin replay msg\n"); | ||
319 | } | ||
320 | |||
321 | |||
322 | static int | ||
323 | origin_notify (void *cls, | ||
324 | size_t *data_size, | ||
325 | void *data) | ||
326 | { | ||
327 | struct pingpong_msg *rcv_pp_msg = (struct pingpong_msg*)cls; | ||
328 | struct pingpong_msg *pp_msg = GNUNET_new (struct pingpong_msg); | ||
329 | |||
330 | pp_msg->peer = rcv_pp_msg->peer; | ||
331 | pp_msg->msg = PONG; | ||
332 | *data_size = sizeof (struct pingpong_msg); | ||
333 | GNUNET_memcpy(data, pp_msg, *data_size); | ||
334 | GNUNET_free (pp_msg); | ||
335 | |||
336 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin sends pong\n"); | ||
337 | |||
338 | return GNUNET_YES; | ||
339 | } | ||
340 | |||
341 | |||
342 | static void | ||
343 | origin_request (void *cls, | ||
344 | const struct GNUNET_MULTICAST_RequestHeader *req) | ||
345 | { | ||
346 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin receives a msg\n"); | ||
347 | |||
348 | req++; | ||
349 | struct pingpong_msg *pp_msg = (struct pingpong_msg *) req; | ||
350 | |||
351 | if (1 != pp_msg->msg) { | ||
352 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "origin didn't reveice a correct request"); | ||
353 | } | ||
354 | |||
355 | GNUNET_MULTICAST_origin_to_all (origin, | ||
356 | 0, | ||
357 | 0, | ||
358 | origin_notify, | ||
359 | pp_msg); | ||
360 | } | ||
361 | |||
362 | |||
363 | static void | ||
364 | origin_message (void *cls, | ||
365 | const struct GNUNET_MULTICAST_MessageHeader *msg) | ||
366 | { | ||
367 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "origin message msg\n"); | ||
368 | } | ||
369 | |||
370 | |||
371 | static void | ||
372 | multicast_disconnect (void *cls, | ||
373 | void *op_result) | ||
374 | { | ||
375 | |||
376 | } | ||
377 | |||
378 | |||
379 | static void * | ||
380 | multicast_connect (void *cls, | ||
381 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
382 | { | ||
383 | struct MulticastPeerContext *multicast_peer = cls; | ||
384 | struct GNUNET_MessageHeader *join_msg; | ||
385 | char data[64]; | ||
386 | |||
387 | if (0 == multicast_peer->peer) | ||
388 | { | ||
389 | group_key = GNUNET_CRYPTO_eddsa_key_create (); | ||
390 | GNUNET_CRYPTO_eddsa_key_get_public (group_key, &group_pub_key); | ||
391 | |||
392 | GNUNET_CRYPTO_hash (&group_pub_key, sizeof (group_pub_key), &group_pub_key_hash); | ||
393 | origin = GNUNET_MULTICAST_origin_start (cfg, | ||
394 | group_key, | ||
395 | 0, | ||
396 | origin_join_request, | ||
397 | origin_replay_frag, | ||
398 | origin_replay_msg, | ||
399 | origin_request, | ||
400 | origin_message, | ||
401 | cls); | ||
402 | if (NULL == origin) | ||
403 | { | ||
404 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
405 | "Peer #%u could not create a multicast group", | ||
406 | multicast_peer->peer); | ||
407 | return NULL; | ||
408 | } | ||
409 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
410 | "Peer #%u connected as origin to group %s\n", | ||
411 | multicast_peer->peer, | ||
412 | GNUNET_h2s (&group_pub_key_hash)); | ||
413 | return origin; | ||
414 | } | ||
415 | else | ||
416 | { | ||
417 | multicast_peer->key = GNUNET_CRYPTO_ecdsa_key_create (); | ||
418 | |||
419 | sprintf(data, "Hi, I am peer #%u (%s). Can I enter?", | ||
420 | multicast_peer->peer, | ||
421 | GNUNET_i2s (multicast_peers[multicast_peer->peer]->id)); | ||
422 | uint8_t data_size = strlen (data) + 1; | ||
423 | join_msg = GNUNET_malloc (sizeof (join_msg) + data_size); | ||
424 | join_msg->size = htons (sizeof (join_msg) + data_size); | ||
425 | join_msg->type = htons (123); | ||
426 | GNUNET_memcpy (&join_msg[1], data, data_size); | ||
427 | |||
428 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
429 | "Peer #%u (%s) tries to join multicast group %s\n", | ||
430 | multicast_peer->peer, | ||
431 | GNUNET_i2s (multicast_peers[multicast_peer->peer]->id), | ||
432 | GNUNET_h2s (&group_pub_key_hash)); | ||
433 | |||
434 | members[multicast_peer->peer] = | ||
435 | GNUNET_MULTICAST_member_join (cfg, | ||
436 | &group_pub_key, | ||
437 | multicast_peer->key, | ||
438 | multicast_peers[0]->id, | ||
439 | 0, | ||
440 | NULL, | ||
441 | join_msg, /* join message */ | ||
442 | member_join_request, | ||
443 | member_join_decision, | ||
444 | member_replay_frag, | ||
445 | member_replay_msg, | ||
446 | member_message, | ||
447 | cls); | ||
448 | return members[multicast_peer->peer]; | ||
449 | } | ||
450 | } | ||
451 | |||
452 | |||
453 | static void | ||
454 | peer_information_cb (void *cls, | ||
455 | struct GNUNET_TESTBED_Operation *operation, | ||
456 | const struct GNUNET_TESTBED_PeerInformation *pinfo, | ||
457 | const char *emsg) | ||
458 | { | ||
459 | struct MulticastPeerContext *mc_peer = (struct MulticastPeerContext*)cls; | ||
460 | |||
461 | if (NULL == pinfo) { | ||
462 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "got no peer information\n"); | ||
463 | result = GNUNET_SYSERR; | ||
464 | GNUNET_SCHEDULER_shutdown (); | ||
465 | } | ||
466 | |||
467 | multicast_peers[mc_peer->peer]->id = pinfo->result.id; | ||
468 | |||
469 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
470 | "Got peer information of %s (%s)\n", | ||
471 | (0 == mc_peer->peer)? "origin" : "member", | ||
472 | GNUNET_i2s (pinfo->result.id)); | ||
473 | |||
474 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
475 | "Create peer #%u (%s)\n", | ||
476 | mc_peer->peer, | ||
477 | GNUNET_i2s (multicast_peers[mc_peer->peer]->id)); | ||
478 | |||
479 | if (0 != mc_peer->peer) | ||
480 | { | ||
481 | /* connect to multicast service of members */ | ||
482 | op[mc_peer->peer] = | ||
483 | GNUNET_TESTBED_service_connect (/* Closure for operation */ | ||
484 | NULL, | ||
485 | /* The peer whose service to connect to */ | ||
486 | peers[mc_peer->peer], | ||
487 | /* The name of the service */ | ||
488 | "multicast", | ||
489 | /* called after a handle to service is opened */ | ||
490 | service_connect, | ||
491 | /* closure for the above callback */ | ||
492 | cls, | ||
493 | /* called when opening the service connection */ | ||
494 | multicast_connect, | ||
495 | /* called when closing the service connection */ | ||
496 | multicast_disconnect, | ||
497 | /* closure for the above two callbacks */ | ||
498 | cls); | ||
499 | } | ||
500 | } | ||
501 | |||
502 | |||
503 | static void | ||
504 | service_connect (void *cls, | ||
505 | struct GNUNET_TESTBED_Operation *op, | ||
506 | void *ca_result, | ||
507 | const char *emsg) | ||
508 | { | ||
509 | struct MulticastPeerContext *mc_peer = (struct MulticastPeerContext*)cls; | ||
510 | |||
511 | if (NULL == ca_result) | ||
512 | { | ||
513 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
514 | "Connection adapter not created for peer #%u (%s)\n", | ||
515 | mc_peer->peer, | ||
516 | GNUNET_i2s (multicast_peers[mc_peer->peer]->id)); | ||
517 | |||
518 | result = GNUNET_SYSERR; | ||
519 | GNUNET_SCHEDULER_shutdown(); | ||
520 | } | ||
521 | |||
522 | if (0 == mc_peer->peer) | ||
523 | { | ||
524 | // Get GNUnet identity of members | ||
525 | for (int i = 0; i<PEERS_REQUESTED; i++) | ||
526 | { | ||
527 | pi_op[i] = GNUNET_TESTBED_peer_get_information (peers[i], | ||
528 | GNUNET_TESTBED_PIT_IDENTITY, | ||
529 | peer_information_cb, | ||
530 | multicast_peers[i]); | ||
531 | } | ||
532 | } | ||
533 | } | ||
534 | |||
535 | |||
536 | |||
537 | /** | ||
538 | * Main function inovked from TESTBED once all of the | ||
539 | * peers are up and running. This one then connects | ||
540 | * just to the multicast service of peer 0 and 1. | ||
541 | * Peer 0 is going to be origin. | ||
542 | * Peer 1 is going to be one member. | ||
543 | * Origin will start a multicast group and the member will try to join it. | ||
544 | * After that we execute some multicast test. | ||
545 | * | ||
546 | * @param cls closure | ||
547 | * @param h the run handle | ||
548 | * @param peers started peers for the test | ||
549 | * @param PEERS_REQUESTED size of the 'peers' array | ||
550 | * @param links_succeeded number of links between peers that were created | ||
551 | * @param links_failed number of links testbed was unable to establish | ||
552 | */ | ||
553 | static void | ||
554 | testbed_master (void *cls, | ||
555 | struct GNUNET_TESTBED_RunHandle *h, | ||
556 | unsigned int num_peers, | ||
557 | struct GNUNET_TESTBED_Peer **p, | ||
558 | unsigned int links_succeeded, | ||
559 | unsigned int links_failed) | ||
560 | { | ||
561 | /* Testbed is ready with peers running and connected in a pre-defined overlay | ||
562 | topology (FIXME) */ | ||
563 | peers = p; | ||
564 | multicast_peers = GNUNET_new_array (PEERS_REQUESTED, struct MulticastPeerContext*); | ||
565 | |||
566 | // Create test contexts for members | ||
567 | for (int i = 0; i<PEERS_REQUESTED; i++) | ||
568 | { | ||
569 | multicast_peers[i] = GNUNET_new (struct MulticastPeerContext); | ||
570 | multicast_peers[i]->peer = i; | ||
571 | multicast_peers[i]->test_ok = GNUNET_NO; | ||
572 | } | ||
573 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
574 | "Create origin peer\n"); | ||
575 | op[0] = | ||
576 | GNUNET_TESTBED_service_connect (/* Closure for operation */ | ||
577 | NULL, | ||
578 | /* The peer whose service to connect to */ | ||
579 | peers[0], | ||
580 | /* The name of the service */ | ||
581 | "multicast", | ||
582 | /* called after a handle to service is opened */ | ||
583 | service_connect, | ||
584 | /* closure for the above callback */ | ||
585 | multicast_peers[0], | ||
586 | /* called when opening the service connection */ | ||
587 | multicast_connect, | ||
588 | /* called when closing the service connection */ | ||
589 | multicast_disconnect, | ||
590 | /* closure for the above two callbacks */ | ||
591 | multicast_peers[0]); | ||
592 | /* Schedule a new task on shutdown */ | ||
593 | GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); | ||
594 | /* Schedule the shutdown task with a delay of a few Seconds */ | ||
595 | timeout_tid = | ||
596 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply | ||
597 | (GNUNET_TIME_UNIT_SECONDS, 400), | ||
598 | &timeout_task, | ||
599 | NULL); | ||
600 | } | ||
601 | |||
602 | |||
603 | int | ||
604 | main (int argc, char *argv[]) | ||
605 | { | ||
606 | int ret; | ||
607 | char const *config_file; | ||
608 | |||
609 | if (strstr (argv[0], "_line") != NULL) | ||
610 | { | ||
611 | config_file = "test_multicast_line.conf"; | ||
612 | } | ||
613 | else if (strstr(argv[0], "_star") != NULL) | ||
614 | { | ||
615 | config_file = "test_multicast_star.conf"; | ||
616 | } | ||
617 | else | ||
618 | { | ||
619 | config_file = "test_multicast_star.conf"; | ||
620 | } | ||
621 | |||
622 | result = GNUNET_SYSERR; | ||
623 | ret = | ||
624 | GNUNET_TESTBED_test_run ("test-multicast-multipeer", | ||
625 | config_file, | ||
626 | /* number of peers to start */ | ||
627 | PEERS_REQUESTED, | ||
628 | /* Event mask - set to 0 for no event notifications */ | ||
629 | 0LL, | ||
630 | /* Controller event callback */ | ||
631 | NULL, | ||
632 | /* Closure for controller event callback */ | ||
633 | NULL, | ||
634 | /* called when testbed setup is complete */ | ||
635 | testbed_master, | ||
636 | /* Closure for the test_master callback */ | ||
637 | NULL); | ||
638 | if ( (GNUNET_OK != ret) || (GNUNET_OK != result) ) | ||
639 | return 1; | ||
640 | return 0; | ||
641 | } | ||
642 | |||
643 | /* end of test_multicast_multipeer.c */ | ||