diff options
author | Christian Grothoff <christian@grothoff.org> | 2019-02-11 21:07:26 +0100 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2019-02-11 21:07:26 +0100 |
commit | 0d4f151374efb1972361c40b6624bf4fd0e3fcaa (patch) | |
tree | 2183ffe652714501efd34525756a8e107b49f690 /src | |
parent | 3f6d37c74ee2357cc2cdae7f0022ff422f0a92c6 (diff) | |
download | gnunet-0d4f151374efb1972361c40b6624bf4fd0e3fcaa.tar.gz gnunet-0d4f151374efb1972361c40b6624bf4fd0e3fcaa.zip |
externalizing secushare logic
Diffstat (limited to 'src')
65 files changed, 3 insertions, 40279 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 5fd65141b..03738e4ed 100644 --- a/src/Makefile.am +++ b/src/Makefile.am | |||
@@ -11,13 +11,7 @@ endif | |||
11 | 11 | ||
12 | if HAVE_EXPERIMENTAL | 12 | if HAVE_EXPERIMENTAL |
13 | EXP_DIR = \ | 13 | EXP_DIR = \ |
14 | rps \ | 14 | rps |
15 | multicast \ | ||
16 | psycutil \ | ||
17 | psycstore \ | ||
18 | psyc \ | ||
19 | social | ||
20 | # dv (FTBFS) | ||
21 | if HAVE_ABE | 15 | if HAVE_ABE |
22 | if HAVE_JSON | 16 | if HAVE_JSON |
23 | EXP_DIR += \ | 17 | EXP_DIR += \ |
diff --git a/src/include/Makefile.am b/src/include/Makefile.am index 195cac075..69ea7c83e 100644 --- a/src/include/Makefile.am +++ b/src/include/Makefile.am | |||
@@ -69,8 +69,8 @@ gnunetinclude_HEADERS = \ | |||
69 | gnunet_hello_lib.h \ | 69 | gnunet_hello_lib.h \ |
70 | gnunet_helper_lib.h \ | 70 | gnunet_helper_lib.h \ |
71 | gnunet_identity_service.h \ | 71 | gnunet_identity_service.h \ |
72 | gnunet_abe_lib.h \ | 72 | gnunet_abe_lib.h \ |
73 | gnunet_reclaim_attribute_lib.h \ | 73 | gnunet_reclaim_attribute_lib.h \ |
74 | gnunet_reclaim_attribute_plugin.h \ | 74 | gnunet_reclaim_attribute_plugin.h \ |
75 | gnunet_reclaim_plugin.h \ | 75 | gnunet_reclaim_plugin.h \ |
76 | gnunet_reclaim_service.h \ | 76 | gnunet_reclaim_service.h \ |
@@ -78,7 +78,6 @@ gnunetinclude_HEADERS = \ | |||
78 | gnunet_load_lib.h \ | 78 | gnunet_load_lib.h \ |
79 | gnunet_cadet_service.h \ | 79 | gnunet_cadet_service.h \ |
80 | gnunet_microphone_lib.h \ | 80 | gnunet_microphone_lib.h \ |
81 | gnunet_multicast_service.h \ | ||
82 | gnunet_mst_lib.h \ | 81 | gnunet_mst_lib.h \ |
83 | gnunet_mq_lib.h \ | 82 | gnunet_mq_lib.h \ |
84 | gnunet_my_lib.h \ | 83 | gnunet_my_lib.h \ |
@@ -101,13 +100,6 @@ gnunetinclude_HEADERS = \ | |||
101 | gnunet_peerstore_service.h \ | 100 | gnunet_peerstore_service.h \ |
102 | gnunet_plugin_lib.h \ | 101 | gnunet_plugin_lib.h \ |
103 | gnunet_pq_lib.h \ | 102 | gnunet_pq_lib.h \ |
104 | gnunet_psycstore_plugin.h \ | ||
105 | gnunet_psycstore_service.h \ | ||
106 | gnunet_psyc_service.h \ | ||
107 | gnunet_psyc_util_lib.h \ | ||
108 | gnunet_psyc_env.h \ | ||
109 | gnunet_psyc_message.h \ | ||
110 | gnunet_psyc_slicer.h \ | ||
111 | gnunet_program_lib.h \ | 103 | gnunet_program_lib.h \ |
112 | gnunet_protocols.h \ | 104 | gnunet_protocols.h \ |
113 | gnunet_resolver_service.h \ | 105 | gnunet_resolver_service.h \ |
@@ -122,7 +114,6 @@ gnunetinclude_HEADERS = \ | |||
122 | gnunet_set_service.h \ | 114 | gnunet_set_service.h \ |
123 | gnunet_signal_lib.h \ | 115 | gnunet_signal_lib.h \ |
124 | gnunet_signatures.h \ | 116 | gnunet_signatures.h \ |
125 | gnunet_social_service.h \ | ||
126 | gnunet_socks.h \ | 117 | gnunet_socks.h \ |
127 | gnunet_speaker_lib.h \ | 118 | gnunet_speaker_lib.h \ |
128 | gnunet_sq_lib.h \ | 119 | gnunet_sq_lib.h \ |
diff --git a/src/include/gnunet_multicast_service.h b/src/include/gnunet_multicast_service.h deleted file mode 100644 index 58fca0b2e..000000000 --- a/src/include/gnunet_multicast_service.h +++ /dev/null | |||
@@ -1,925 +0,0 @@ | |||
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/include/gnunet_psyc_env.h b/src/include/gnunet_psyc_env.h deleted file mode 100644 index 0d878cb96..000000000 --- a/src/include/gnunet_psyc_env.h +++ /dev/null | |||
@@ -1,340 +0,0 @@ | |||
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 | * @author Gabor X Toth | ||
23 | * | ||
24 | * @file | ||
25 | * PSYC Environment library | ||
26 | * | ||
27 | * @defgroup psyc-util-env PSYC Utilities library: Environment | ||
28 | * Environment data structure operations for PSYC and Social messages. | ||
29 | * | ||
30 | * Library providing operations for the @e environment of | ||
31 | * PSYC and Social messages, and for (de)serializing variable values. | ||
32 | * | ||
33 | * @{ | ||
34 | */ | ||
35 | |||
36 | |||
37 | #ifndef GNUNET_PSYC_ENV_H | ||
38 | #define GNUNET_PSYC_ENV_H | ||
39 | |||
40 | #ifdef __cplusplus | ||
41 | extern "C" | ||
42 | { | ||
43 | #if 0 /* keep Emacsens' auto-indent happy */ | ||
44 | } | ||
45 | #endif | ||
46 | #endif | ||
47 | |||
48 | |||
49 | /** | ||
50 | * Possible operations on PSYC state (persistent) and transient variables (per message). | ||
51 | */ | ||
52 | enum GNUNET_PSYC_Operator | ||
53 | { | ||
54 | /** | ||
55 | * Set value of a transient variable. | ||
56 | */ | ||
57 | GNUNET_PSYC_OP_SET = ':', | ||
58 | |||
59 | /** | ||
60 | * Assign value for a persistent state variable. | ||
61 | * | ||
62 | * If an assigned value is NULL, the variable is deleted. | ||
63 | */ | ||
64 | GNUNET_PSYC_OP_ASSIGN = '=', | ||
65 | |||
66 | /** | ||
67 | * Augment state variable. | ||
68 | * | ||
69 | * Used for appending strings, adding numbers, and adding new items to a list or dictionary. | ||
70 | */ | ||
71 | GNUNET_PSYC_OP_AUGMENT = '+', | ||
72 | |||
73 | /** | ||
74 | * Diminish state variable. | ||
75 | * | ||
76 | * Used for subtracting numbers, and removing items from a list or dictionary. | ||
77 | */ | ||
78 | GNUNET_PSYC_OP_DIMINISH = '-', | ||
79 | |||
80 | /** | ||
81 | * Update state variable. | ||
82 | * | ||
83 | * Used for modifying a single item of a list or dictionary. | ||
84 | */ | ||
85 | GNUNET_PSYC_OP_UPDATE = '@', | ||
86 | }; | ||
87 | |||
88 | |||
89 | /** | ||
90 | * PSYC variable types. | ||
91 | */ | ||
92 | enum GNUNET_PSYC_Type | ||
93 | { | ||
94 | GNUNET_PSYC_TYPE_DATA = 0, | ||
95 | GNUNET_PSYC_TYPE_NUMBER, | ||
96 | GNUNET_PSYC_TYPE_LIST, | ||
97 | GNUNET_PSYC_TYPE_DICT | ||
98 | }; | ||
99 | |||
100 | |||
101 | /** | ||
102 | * PSYC state modifier. | ||
103 | */ | ||
104 | struct GNUNET_PSYC_Modifier | ||
105 | { | ||
106 | /** | ||
107 | * State operation. | ||
108 | */ | ||
109 | enum GNUNET_PSYC_Operator oper; | ||
110 | |||
111 | /** | ||
112 | * Variable name. | ||
113 | */ | ||
114 | const char *name; | ||
115 | |||
116 | /** | ||
117 | * Size of @a value. | ||
118 | */ | ||
119 | size_t value_size; | ||
120 | |||
121 | /** | ||
122 | * Value of variable. | ||
123 | */ | ||
124 | const void *value; | ||
125 | |||
126 | /** | ||
127 | * Next modifier. | ||
128 | */ | ||
129 | struct GNUNET_PSYC_Modifier *next; | ||
130 | |||
131 | /** | ||
132 | * Previous modifier. | ||
133 | */ | ||
134 | struct GNUNET_PSYC_Modifier *prev; | ||
135 | }; | ||
136 | |||
137 | |||
138 | /** | ||
139 | * Environment for a message. | ||
140 | * | ||
141 | * Contains modifiers. | ||
142 | */ | ||
143 | struct GNUNET_PSYC_Environment; | ||
144 | |||
145 | |||
146 | /** | ||
147 | * Create an environment. | ||
148 | * | ||
149 | * @return A newly allocated environment. | ||
150 | */ | ||
151 | struct GNUNET_PSYC_Environment * | ||
152 | GNUNET_PSYC_env_create (); | ||
153 | |||
154 | |||
155 | /** | ||
156 | * Add a modifier to the environment. | ||
157 | * | ||
158 | * @param env The environment. | ||
159 | * @param oper Operation to perform. | ||
160 | * @param name Name of the variable. | ||
161 | * @param value Value of the variable. | ||
162 | * @param value_size Size of @a value. | ||
163 | */ | ||
164 | void | ||
165 | GNUNET_PSYC_env_add (struct GNUNET_PSYC_Environment *env, | ||
166 | enum GNUNET_PSYC_Operator oper, const char *name, | ||
167 | const void *value, size_t value_size); | ||
168 | |||
169 | |||
170 | /** | ||
171 | * Get the first modifier of the environment. | ||
172 | */ | ||
173 | struct GNUNET_PSYC_Modifier * | ||
174 | GNUNET_PSYC_env_head (const struct GNUNET_PSYC_Environment *env); | ||
175 | |||
176 | |||
177 | |||
178 | /** | ||
179 | * Get the last modifier of the environment. | ||
180 | */ | ||
181 | struct GNUNET_PSYC_Modifier * | ||
182 | GNUNET_PSYC_env_tail (const struct GNUNET_PSYC_Environment *env); | ||
183 | |||
184 | |||
185 | /** | ||
186 | * Remove a modifier from the environment. | ||
187 | */ | ||
188 | void | ||
189 | GNUNET_PSYC_env_remove (struct GNUNET_PSYC_Environment *env, | ||
190 | struct GNUNET_PSYC_Modifier *mod); | ||
191 | |||
192 | |||
193 | /** | ||
194 | * Remove a modifier at the beginning of the environment. | ||
195 | */ | ||
196 | int | ||
197 | GNUNET_PSYC_env_shift (struct GNUNET_PSYC_Environment *env, | ||
198 | enum GNUNET_PSYC_Operator *oper, const char **name, | ||
199 | const void **value, size_t *value_size); | ||
200 | |||
201 | |||
202 | /** | ||
203 | * Iterator for modifiers in the environment. | ||
204 | * | ||
205 | * @param cls Closure. | ||
206 | * @param mod Modifier. | ||
207 | * | ||
208 | * @return #GNUNET_YES to continue iterating, | ||
209 | * #GNUNET_NO to stop. | ||
210 | */ | ||
211 | typedef int | ||
212 | (*GNUNET_PSYC_Iterator) (void *cls, enum GNUNET_PSYC_Operator oper, | ||
213 | const char *name, const char *value, | ||
214 | uint32_t value_size); | ||
215 | |||
216 | |||
217 | /** | ||
218 | * Iterate through all modifiers in the environment. | ||
219 | * | ||
220 | * @param env The environment. | ||
221 | * @param it Iterator. | ||
222 | * @param it_cls Closure for iterator. | ||
223 | */ | ||
224 | void | ||
225 | GNUNET_PSYC_env_iterate (const struct GNUNET_PSYC_Environment *env, | ||
226 | GNUNET_PSYC_Iterator it, void *it_cls); | ||
227 | |||
228 | |||
229 | /** | ||
230 | * Get the number of modifiers in the environment. | ||
231 | * | ||
232 | * @param env The environment. | ||
233 | * | ||
234 | * @return Number of modifiers. | ||
235 | */ | ||
236 | size_t | ||
237 | GNUNET_PSYC_env_get_count (const struct GNUNET_PSYC_Environment *env); | ||
238 | |||
239 | |||
240 | /** | ||
241 | * Destroy an environment. | ||
242 | * | ||
243 | * @param env The environment to destroy. | ||
244 | */ | ||
245 | void | ||
246 | GNUNET_PSYC_env_destroy (struct GNUNET_PSYC_Environment *env); | ||
247 | |||
248 | |||
249 | /** | ||
250 | * Get the type of variable. | ||
251 | * | ||
252 | * @param name Name of the variable. | ||
253 | * | ||
254 | * @return Variable type. | ||
255 | */ | ||
256 | enum GNUNET_PSYC_Type | ||
257 | GNUNET_PSYC_var_get_type (char *name); | ||
258 | |||
259 | |||
260 | /** | ||
261 | * Perform an operation on a variable. | ||
262 | * | ||
263 | * @param name Name of variable. | ||
264 | * @param current_value Current value of variable. | ||
265 | * @param current_value_size Size of @a current_value. | ||
266 | * @param oper Operator. | ||
267 | * @param args Arguments for the operation. | ||
268 | * @param args_size Size of @a args. | ||
269 | * @param return_value Return value. | ||
270 | * @param return_value_size Size of @a return_value. | ||
271 | * | ||
272 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
273 | */ | ||
274 | int | ||
275 | GNUNET_PSYC_operation (char *name, void *current_value, size_t current_value_size, | ||
276 | enum GNUNET_PSYC_Operator oper, void *args, size_t args_size, | ||
277 | void **return_value, size_t *return_value_size); | ||
278 | |||
279 | |||
280 | /** | ||
281 | * Get the variable's value as an integer. | ||
282 | * | ||
283 | * @param size Size of value. | ||
284 | * @param value Raw value of variable. | ||
285 | * @param[out] number Value converted to a 64-bit integer. | ||
286 | * | ||
287 | * @return #GNUNET_OK on success, #GNUNET_SYSERR if an error occurred (e.g. the value is invalid). | ||
288 | */ | ||
289 | int | ||
290 | GNUNET_PSYC_value_to_number (size_t size, const void *value, int64_t *number); | ||
291 | |||
292 | |||
293 | /** | ||
294 | * Get the variable's value as a dictionary. | ||
295 | * | ||
296 | * @param size Size of value. | ||
297 | * @param value Raw value of variable. | ||
298 | * @param[out] dict A newly created hashmap holding the elements of the dictionary. | ||
299 | * | ||
300 | * @return #GNUNET_OK on success, #GNUNET_SYSERR if an error occurred (e.g. the value is invalid). | ||
301 | */ | ||
302 | int | ||
303 | GNUNET_PSYC_value_to_dict (size_t size, const void *value, struct GNUNET_CONTAINER_MultiHashMap **dict); | ||
304 | |||
305 | |||
306 | /** | ||
307 | * Create a PSYC variable value from an integer. | ||
308 | * | ||
309 | * @param number The number to convert. | ||
310 | * @param[out] value_size Size of returned value. | ||
311 | * | ||
312 | * @return A newly allocated value or NULL on error. | ||
313 | */ | ||
314 | void * | ||
315 | GNUNET_PSYC_value_from_number (int64_t number, size_t *value_size); | ||
316 | |||
317 | |||
318 | /** | ||
319 | * Create a PSYC variable value from a dictionary. | ||
320 | * | ||
321 | * @param dict The dict to convert. | ||
322 | * @param[out] value_size Size of returned value. | ||
323 | * | ||
324 | * @return A newly allocated value or NULL on error. | ||
325 | */ | ||
326 | void * | ||
327 | GNUNET_PSYC_value_from_dict (struct GNUNET_CONTAINER_MultiHashMap *dict, size_t *value_size); | ||
328 | |||
329 | |||
330 | #if 0 /* keep Emacsens' auto-indent happy */ | ||
331 | { | ||
332 | #endif | ||
333 | #ifdef __cplusplus | ||
334 | } | ||
335 | #endif | ||
336 | |||
337 | /* ifndef GNUNET_PSYC_ENV_H */ | ||
338 | #endif | ||
339 | |||
340 | /** @} */ /* end of group */ | ||
diff --git a/src/include/gnunet_psyc_message.h b/src/include/gnunet_psyc_message.h deleted file mode 100644 index d0cf9cc6a..000000000 --- a/src/include/gnunet_psyc_message.h +++ /dev/null | |||
@@ -1,278 +0,0 @@ | |||
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 | * | ||
24 | * @file | ||
25 | * PSYC message utilities; receiving/transmitting/logging PSYC messages | ||
26 | * | ||
27 | * @defgroup psyc-util-message PSYC Utilities library: Messages | ||
28 | * Receiving, transmitting, logging PSYC messages. | ||
29 | * @{ | ||
30 | */ | ||
31 | |||
32 | #ifndef GNUNET_PSYC_MESSAGE_H | ||
33 | #define GNUNET_PSYC_MESSAGE_H | ||
34 | |||
35 | #ifdef __cplusplus | ||
36 | extern "C" | ||
37 | { | ||
38 | #if 0 /* keep Emacsens' auto-indent happy */ | ||
39 | } | ||
40 | #endif | ||
41 | #endif | ||
42 | |||
43 | |||
44 | #include "gnunet_util_lib.h" | ||
45 | #include "gnunet_psyc_util_lib.h" | ||
46 | #include "gnunet_psyc_service.h" | ||
47 | |||
48 | |||
49 | /** | ||
50 | * Create a PSYC message. | ||
51 | * | ||
52 | * @param method_name | ||
53 | * PSYC method for the message. | ||
54 | * @param env | ||
55 | * Environment for the message. | ||
56 | * @param data | ||
57 | * Data payload for the message. | ||
58 | * @param data_size | ||
59 | * Size of @a data. | ||
60 | * | ||
61 | * @return Message header with size information, | ||
62 | * followed by the message parts. | ||
63 | * | ||
64 | * FIXME: arg order | ||
65 | */ | ||
66 | struct GNUNET_PSYC_Message * | ||
67 | GNUNET_PSYC_message_create (const char *method_name, | ||
68 | const struct GNUNET_PSYC_Environment *env, | ||
69 | const void *data, | ||
70 | size_t data_size); | ||
71 | |||
72 | /** | ||
73 | * Parse PSYC message. | ||
74 | * | ||
75 | * @param msg | ||
76 | * The PSYC message to parse. | ||
77 | * @param env | ||
78 | * The environment for the message with a list of modifiers. | ||
79 | * @param[out] method_name | ||
80 | * Pointer to the method name inside @a pmsg. | ||
81 | * @param[out] data | ||
82 | * Pointer to data inside @a pmsg. | ||
83 | * @param[out] data_size | ||
84 | * Size of @data is written here. | ||
85 | * | ||
86 | * @return #GNUNET_OK on success, | ||
87 | * #GNUNET_SYSERR on parse error. | ||
88 | * | ||
89 | * FIXME: arg order | ||
90 | */ | ||
91 | int | ||
92 | GNUNET_PSYC_message_parse (const struct GNUNET_PSYC_MessageHeader *msg, | ||
93 | const char **method_name, | ||
94 | struct GNUNET_PSYC_Environment *env, | ||
95 | const void **data, | ||
96 | uint16_t *data_size); | ||
97 | |||
98 | |||
99 | void | ||
100 | GNUNET_PSYC_log_message (enum GNUNET_ErrorType kind, | ||
101 | const struct GNUNET_MessageHeader *msg); | ||
102 | |||
103 | |||
104 | struct GNUNET_PSYC_TransmitHandle; | ||
105 | |||
106 | /** | ||
107 | * Create a transmission handle. | ||
108 | */ | ||
109 | struct GNUNET_PSYC_TransmitHandle * | ||
110 | GNUNET_PSYC_transmit_create (struct GNUNET_MQ_Handle *mq); | ||
111 | |||
112 | |||
113 | /** | ||
114 | * Destroy a transmission handle. | ||
115 | */ | ||
116 | void | ||
117 | GNUNET_PSYC_transmit_destroy (struct GNUNET_PSYC_TransmitHandle *tmit); | ||
118 | |||
119 | |||
120 | /** | ||
121 | * Transmit a message. | ||
122 | * | ||
123 | * @param tmit | ||
124 | * Transmission handle. | ||
125 | * @param method_name | ||
126 | * Which method should be invoked. | ||
127 | * @param env | ||
128 | * Environment for the message. | ||
129 | * Should stay available until the first call to notify_data. | ||
130 | * Can be NULL if there are no modifiers or @a notify_mod is | ||
131 | * provided instead. | ||
132 | * @param notify_mod | ||
133 | * Function to call to obtain modifiers. | ||
134 | * Can be NULL if there are no modifiers or @a env is provided instead. | ||
135 | * @param notify_data | ||
136 | * Function to call to obtain fragments of the data. | ||
137 | * @param notify_cls | ||
138 | * Closure for @a notify_mod and @a notify_data. | ||
139 | * @param flags | ||
140 | * Flags for the message being transmitted. | ||
141 | * | ||
142 | * @return #GNUNET_OK if the transmission was started. | ||
143 | * #GNUNET_SYSERR if another transmission is already going on. | ||
144 | */ | ||
145 | int | ||
146 | GNUNET_PSYC_transmit_message (struct GNUNET_PSYC_TransmitHandle *tmit, | ||
147 | const char *method_name, | ||
148 | const struct GNUNET_PSYC_Environment *env, | ||
149 | GNUNET_PSYC_TransmitNotifyModifier notify_mod, | ||
150 | GNUNET_PSYC_TransmitNotifyData notify_data, | ||
151 | void *notify_cls, | ||
152 | uint32_t flags); | ||
153 | |||
154 | |||
155 | /** | ||
156 | * Resume transmission. | ||
157 | * | ||
158 | * @param tmit Transmission handle. | ||
159 | */ | ||
160 | void | ||
161 | GNUNET_PSYC_transmit_resume (struct GNUNET_PSYC_TransmitHandle *tmit); | ||
162 | |||
163 | |||
164 | /** | ||
165 | * Abort transmission request. | ||
166 | * | ||
167 | * @param tmit Transmission handle. | ||
168 | */ | ||
169 | void | ||
170 | GNUNET_PSYC_transmit_cancel (struct GNUNET_PSYC_TransmitHandle *tmit); | ||
171 | |||
172 | |||
173 | /** | ||
174 | * Got acknowledgement of a transmitted message part, continue transmission. | ||
175 | * | ||
176 | * @param tmit Transmission handle. | ||
177 | */ | ||
178 | void | ||
179 | GNUNET_PSYC_transmit_got_ack (struct GNUNET_PSYC_TransmitHandle *tmit); | ||
180 | |||
181 | |||
182 | struct GNUNET_PSYC_ReceiveHandle; | ||
183 | |||
184 | |||
185 | /** | ||
186 | * Create handle for receiving messages. | ||
187 | */ | ||
188 | struct GNUNET_PSYC_ReceiveHandle * | ||
189 | GNUNET_PSYC_receive_create (GNUNET_PSYC_MessageCallback message_cb, | ||
190 | GNUNET_PSYC_MessagePartCallback message_part_cb, | ||
191 | void *cb_cls); | ||
192 | |||
193 | |||
194 | /** | ||
195 | * Destroy handle for receiving messages. | ||
196 | */ | ||
197 | void | ||
198 | GNUNET_PSYC_receive_destroy (struct GNUNET_PSYC_ReceiveHandle *recv); | ||
199 | |||
200 | |||
201 | /** | ||
202 | * Reset stored data related to the last received message. | ||
203 | */ | ||
204 | void | ||
205 | GNUNET_PSYC_receive_reset (struct GNUNET_PSYC_ReceiveHandle *recv); | ||
206 | |||
207 | |||
208 | /** | ||
209 | * Handle incoming PSYC message. | ||
210 | * | ||
211 | * @param recv | ||
212 | * Receive handle. | ||
213 | * @param msg | ||
214 | * The message. | ||
215 | * | ||
216 | * @return #GNUNET_OK on success, | ||
217 | * #GNUNET_SYSERR on receive error. | ||
218 | */ | ||
219 | int | ||
220 | GNUNET_PSYC_receive_message (struct GNUNET_PSYC_ReceiveHandle *recv, | ||
221 | const struct GNUNET_PSYC_MessageHeader *msg); | ||
222 | |||
223 | |||
224 | /** | ||
225 | * Check if @a data contains a series of valid message parts. | ||
226 | * | ||
227 | * @param data_size | ||
228 | * Size of @a data. | ||
229 | * @param data | ||
230 | * Data. | ||
231 | * @param[out] first_ptype | ||
232 | * Type of first message part. | ||
233 | * @param[out] last_ptype | ||
234 | * Type of last message part. | ||
235 | * | ||
236 | * @return Number of message parts found in @a data. | ||
237 | * or GNUNET_SYSERR if the message contains invalid parts. | ||
238 | */ | ||
239 | int | ||
240 | GNUNET_PSYC_receive_check_parts (uint16_t data_size, const char *data, | ||
241 | uint16_t *first_ptype, uint16_t *last_ptype); | ||
242 | |||
243 | |||
244 | /** | ||
245 | * Initialize PSYC message header. | ||
246 | */ | ||
247 | void | ||
248 | GNUNET_PSYC_message_header_init (struct GNUNET_PSYC_MessageHeader *pmsg, | ||
249 | const struct GNUNET_MULTICAST_MessageHeader *mmsg, | ||
250 | uint32_t flags); | ||
251 | |||
252 | |||
253 | /** | ||
254 | * Create a new PSYC message header from a multicast message for sending it to clients. | ||
255 | */ | ||
256 | struct GNUNET_PSYC_MessageHeader * | ||
257 | GNUNET_PSYC_message_header_create (const struct GNUNET_MULTICAST_MessageHeader *mmsg, | ||
258 | uint32_t flags); | ||
259 | |||
260 | |||
261 | /** | ||
262 | * Create a new PSYC message header from a PSYC message. | ||
263 | */ | ||
264 | struct GNUNET_PSYC_MessageHeader * | ||
265 | GNUNET_PSYC_message_header_create_from_psyc (const struct GNUNET_PSYC_Message *msg); | ||
266 | |||
267 | |||
268 | #if 0 /* keep Emacsens' auto-indent happy */ | ||
269 | { | ||
270 | #endif | ||
271 | #ifdef __cplusplus | ||
272 | } | ||
273 | #endif | ||
274 | |||
275 | /* ifndef GNUNET_PSYC_MESSAGE_H */ | ||
276 | #endif | ||
277 | |||
278 | /** @} */ /* end of group */ | ||
diff --git a/src/include/gnunet_psyc_service.h b/src/include/gnunet_psyc_service.h deleted file mode 100644 index 3a3131e33..000000000 --- a/src/include/gnunet_psyc_service.h +++ /dev/null | |||
@@ -1,1364 +0,0 @@ | |||
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 | * PSYC service | ||
27 | * | ||
28 | * @defgroup psyc PSYC service | ||
29 | * Send/receive messages in PSYC channels and access the PSYC Store. | ||
30 | * | ||
31 | * Note that clients of this API are NOT expected to understand the PSYC message | ||
32 | * format, only the semantics! Parsing (and serializing) the PSYC stream format | ||
33 | * is done within the implementation of the libgnunetpsyc library, and this API | ||
34 | * deliberately exposes as little as possible of the actual data stream format | ||
35 | * to the application! | ||
36 | * | ||
37 | * NOTE: | ||
38 | * - this API does not know about PSYC's "root" and "places"; | ||
39 | * there is no 'root' in GNUnet-PSYC as we're decentralized; | ||
40 | * 'places' and 'persons' are combined within the same | ||
41 | * abstraction, that of a "channel". Channels are identified | ||
42 | * and accessed in this API using a public/private key. | ||
43 | * Higher-level applications should use NAMES within GNS | ||
44 | * to obtain public keys, and the distinction between | ||
45 | * 'places' and 'persons' can then be made with the help | ||
46 | * of the naming system (and/or conventions). | ||
47 | * Channels are (as in PSYC) organized into a hierarchy; each | ||
48 | * channel master (the one with the private key) is then | ||
49 | * the operator of the multicast group (its Origin in | ||
50 | * the terminology of the multicast API). | ||
51 | * - The API supports passing large amounts of data using | ||
52 | * 'streaming' for the argument passed to a method. State | ||
53 | * and variables must fit into memory and cannot be streamed | ||
54 | * (thus, no passing of 4 GB of data in a variable; | ||
55 | * once we implement this, we might want to create a | ||
56 | * @c \#define for the maximum size of a variable). | ||
57 | * - PSYC defines standard variables, methods, etc. This | ||
58 | * library deliberately abstracts over all of these; a | ||
59 | * higher-level API should combine the naming system (GNS) | ||
60 | * and standard methods (_converse, _notice, _request, | ||
61 | * _warning, _error etc) and variables (_action, _color, | ||
62 | * _time, etc). However, this API does take over the | ||
63 | * routing variables, specifically '_context' (channel), | ||
64 | * and '_source'. We only kind-of support '_target', as | ||
65 | * the target is either everyone in the group or the | ||
66 | * origin, and never just a single member of the group; | ||
67 | * for such individual messages, an application needs to | ||
68 | * construct an 'inbox' channel where the master (only) | ||
69 | * receives messages (but never forwards; private responses | ||
70 | * would be transmitted by joining the senders 'inbox' | ||
71 | * channel -- or a inbox#bob subchannel). The | ||
72 | * goal for all of this is to keep the abstractions in this | ||
73 | * API minimal: interaction with multicast, try \& slice, | ||
74 | * state/variable/channel management. Higher-level | ||
75 | * operations belong elsewhere (so maybe this API should | ||
76 | * be called 'PSYC-low', whereas a higher-level API | ||
77 | * implementing defaults for standard methods and | ||
78 | * variables might be called 'PSYC-std' or 'PSYC-high'. | ||
79 | * | ||
80 | * In PSYC terminology this is simply called the "PSYC | ||
81 | * routing layer" and the abstractions, for instance in | ||
82 | * psyced, are quite similar. The higher one is called | ||
83 | * "PSYC entity layer." In the text rendering of the | ||
84 | * protocol the two are separated by an empty line. See | ||
85 | * http://about.psyc.eu/Spec:Packet and related. --lynX | ||
86 | * | ||
87 | * @{ | ||
88 | */ | ||
89 | |||
90 | #ifndef GNUNET_PSYC_SERVICE_H | ||
91 | #define GNUNET_PSYC_SERVICE_H | ||
92 | |||
93 | #ifdef __cplusplus | ||
94 | extern "C" | ||
95 | { | ||
96 | #if 0 /* keep Emacsens' auto-indent happy */ | ||
97 | } | ||
98 | #endif | ||
99 | #endif | ||
100 | |||
101 | #include "gnunet_util_lib.h" | ||
102 | #include "gnunet_multicast_service.h" | ||
103 | //Mingw work around | ||
104 | #ifdef MINGW | ||
105 | # ifndef UINT64_MAX | ||
106 | # define UINT64_MAX 0xffffffffffffffffULL | ||
107 | # endif | ||
108 | #endif | ||
109 | |||
110 | /** | ||
111 | * Version number of GNUnet-PSYC API. | ||
112 | */ | ||
113 | #define GNUNET_PSYC_VERSION 0x00000000 | ||
114 | |||
115 | |||
116 | /** | ||
117 | * Policy flags for a channel. | ||
118 | */ | ||
119 | enum GNUNET_PSYC_ChannelFlags | ||
120 | { | ||
121 | /** | ||
122 | * Admission must be confirmed by the master. | ||
123 | */ | ||
124 | GNUNET_PSYC_CHANNEL_ADMISSION_CONTROL = 1 << 0, | ||
125 | |||
126 | /** | ||
127 | * Past messages are only available to slaves who were admitted at the time | ||
128 | * they were sent to the channel. | ||
129 | */ | ||
130 | GNUNET_PSYC_CHANNEL_RESTRICTED_HISTORY = 1 << 1 | ||
131 | }; | ||
132 | |||
133 | |||
134 | /** | ||
135 | * PSYC channel policies. | ||
136 | */ | ||
137 | enum GNUNET_PSYC_Policy | ||
138 | { | ||
139 | /** | ||
140 | * Anyone can join the channel, without announcing their presence; | ||
141 | * all messages are always public and can be distributed freely. | ||
142 | * Joins may be announced, but this is not required. | ||
143 | */ | ||
144 | GNUNET_PSYC_CHANNEL_ANONYMOUS = 0, | ||
145 | |||
146 | /** | ||
147 | * The master must approve membership to the channel, messages must only be | ||
148 | * distributed to current channel slaves. This includes the channel | ||
149 | * state as well as transient messages. | ||
150 | */ | ||
151 | GNUNET_PSYC_CHANNEL_PRIVATE | ||
152 | = GNUNET_PSYC_CHANNEL_ADMISSION_CONTROL | ||
153 | | GNUNET_PSYC_CHANNEL_RESTRICTED_HISTORY | ||
154 | |||
155 | #if IDEAS_FOR_FUTURE | ||
156 | /** | ||
157 | * Anyone can freely join the channel (no approval required); | ||
158 | * however, messages must only be distributed to current channel | ||
159 | * slaves, so the master must still acknowledge that the slave | ||
160 | * joined before transient messages are delivered. As approval is | ||
161 | * guaranteed, the presistent channel state can be synchronized freely | ||
162 | * immediately, prior to master confirmation. | ||
163 | */ | ||
164 | GNUNET_PSYC_CHANNEL_OPEN | ||
165 | = GNUNET_PSYC_CHANNEL_RESTRICTED_HISTORY, | ||
166 | |||
167 | /** | ||
168 | * The master must approve joins to the channel, but past messages can be | ||
169 | * freely distributed to slaves. | ||
170 | */ | ||
171 | GNUNET_PSYC_CHANNEL_CLOSED | ||
172 | = GNUNET_PSYC_CHANNEL_ADMISSION_CONTROL, | ||
173 | #endif | ||
174 | }; | ||
175 | |||
176 | |||
177 | enum GNUNET_PSYC_MessageFlags | ||
178 | { | ||
179 | /** | ||
180 | * Default / no flags. | ||
181 | */ | ||
182 | GNUNET_PSYC_MESSAGE_DEFAULT = 0, | ||
183 | |||
184 | /** | ||
185 | * Historic message, retrieved from PSYCstore. | ||
186 | */ | ||
187 | GNUNET_PSYC_MESSAGE_HISTORIC = 1 << 0, | ||
188 | |||
189 | /** | ||
190 | * Request from slave to master. | ||
191 | */ | ||
192 | GNUNET_PSYC_MESSAGE_REQUEST = 1 << 1, | ||
193 | |||
194 | /** | ||
195 | * Message can be delivered out of order. | ||
196 | */ | ||
197 | GNUNET_PSYC_MESSAGE_ORDER_ANY = 1 << 2 | ||
198 | }; | ||
199 | |||
200 | |||
201 | /** | ||
202 | * Values for the @a state_delta field of GNUNET_PSYC_MessageHeader. | ||
203 | */ | ||
204 | enum GNUNET_PSYC_StateDeltaValues | ||
205 | { | ||
206 | GNUNET_PSYC_STATE_RESET = 0, | ||
207 | |||
208 | GNUNET_PSYC_STATE_NOT_MODIFIED = UINT64_MAX | ||
209 | }; | ||
210 | |||
211 | |||
212 | GNUNET_NETWORK_STRUCT_BEGIN | ||
213 | |||
214 | /** | ||
215 | * A PSYC message. | ||
216 | * | ||
217 | * Used for single-fragment messages e.g. in a join request or response. | ||
218 | */ | ||
219 | struct GNUNET_PSYC_Message | ||
220 | { | ||
221 | /** | ||
222 | * Message header with size and type information. | ||
223 | */ | ||
224 | struct GNUNET_MessageHeader header; | ||
225 | |||
226 | /* Followed by concatenated PSYC message parts: | ||
227 | * messages with GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_* types | ||
228 | */ | ||
229 | }; | ||
230 | |||
231 | |||
232 | /** | ||
233 | * Header of a PSYC message. | ||
234 | * | ||
235 | * The PSYC service adds this when delivering the message to local clients, | ||
236 | * not present on the multicast layer. | ||
237 | */ | ||
238 | struct GNUNET_PSYC_MessageHeader | ||
239 | { | ||
240 | /** | ||
241 | * Generic message header with size and type information. | ||
242 | */ | ||
243 | struct GNUNET_MessageHeader header; | ||
244 | |||
245 | /** | ||
246 | * Flags for this message fragment. | ||
247 | * | ||
248 | * @see enum GNUNET_PSYC_MessageFlags | ||
249 | */ | ||
250 | uint32_t flags GNUNET_PACKED; | ||
251 | |||
252 | /** | ||
253 | * Number of the message this message part belongs to. | ||
254 | * Monotonically increasing from 1. | ||
255 | */ | ||
256 | uint64_t message_id GNUNET_PACKED; | ||
257 | |||
258 | /** | ||
259 | * Byte offset of this @e fragment of the @e message. | ||
260 | */ | ||
261 | uint64_t fragment_offset GNUNET_PACKED; | ||
262 | |||
263 | /** | ||
264 | * Sending slave's public key. | ||
265 | * Not set if the message is from the master. | ||
266 | */ | ||
267 | struct GNUNET_CRYPTO_EcdsaPublicKey slave_pub_key; | ||
268 | |||
269 | /* Followed by concatenated PSYC message parts: | ||
270 | * messages with GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_* types | ||
271 | */ | ||
272 | }; | ||
273 | |||
274 | |||
275 | /** | ||
276 | * The method of a message. | ||
277 | */ | ||
278 | struct GNUNET_PSYC_MessageMethod | ||
279 | { | ||
280 | /** | ||
281 | * Type: GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD | ||
282 | */ | ||
283 | struct GNUNET_MessageHeader header; | ||
284 | |||
285 | /** | ||
286 | * OR'ed GNUNET_PSYC_MasterTransmitFlags | ||
287 | */ | ||
288 | uint32_t flags GNUNET_PACKED; | ||
289 | |||
290 | /** | ||
291 | * Number of message IDs since the last message that contained state | ||
292 | * operations. @see enum GNUNET_PSYC_StateDeltaValues | ||
293 | */ | ||
294 | uint64_t state_delta GNUNET_PACKED; | ||
295 | |||
296 | /* Followed by NUL-terminated method name. */ | ||
297 | }; | ||
298 | |||
299 | |||
300 | /** | ||
301 | * A modifier of a message. | ||
302 | */ | ||
303 | struct GNUNET_PSYC_MessageModifier | ||
304 | { | ||
305 | /** | ||
306 | * Type: GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER | ||
307 | */ | ||
308 | struct GNUNET_MessageHeader header; | ||
309 | |||
310 | /** | ||
311 | * Size of value. | ||
312 | */ | ||
313 | uint32_t value_size GNUNET_PACKED; | ||
314 | |||
315 | /** | ||
316 | * Size of name, including NUL terminator. | ||
317 | */ | ||
318 | uint16_t name_size GNUNET_PACKED; | ||
319 | |||
320 | /** | ||
321 | * enum GNUNET_PSYC_Operator | ||
322 | */ | ||
323 | uint8_t oper; | ||
324 | |||
325 | /* Followed by NUL-terminated name, then the value. */ | ||
326 | }; | ||
327 | |||
328 | |||
329 | struct GNUNET_PSYC_CountersResultMessage | ||
330 | { | ||
331 | /** | ||
332 | * Type: GNUNET_MESSAGE_TYPE_PSYC_RESULT_COUNTERS | ||
333 | */ | ||
334 | struct GNUNET_MessageHeader header; | ||
335 | |||
336 | /** | ||
337 | * Status code for the operation. | ||
338 | */ | ||
339 | uint32_t result_code GNUNET_PACKED; | ||
340 | |||
341 | /** | ||
342 | * Last message ID sent to the channel. | ||
343 | */ | ||
344 | uint64_t max_message_id GNUNET_PACKED; | ||
345 | }; | ||
346 | |||
347 | |||
348 | /** | ||
349 | * Join request sent to a PSYC master. | ||
350 | */ | ||
351 | struct GNUNET_PSYC_JoinRequestMessage | ||
352 | { | ||
353 | /** | ||
354 | * Type: GNUNET_MESSAGE_TYPE_PSYC_MASTER_JOIN_REQUEST | ||
355 | */ | ||
356 | struct GNUNET_MessageHeader header; | ||
357 | /** | ||
358 | * Public key of the joining slave. | ||
359 | */ | ||
360 | struct GNUNET_CRYPTO_EcdsaPublicKey slave_pub_key; | ||
361 | |||
362 | /* Followed by struct GNUNET_MessageHeader join_request */ | ||
363 | }; | ||
364 | |||
365 | |||
366 | /** | ||
367 | * Join decision sent in reply to a join request. | ||
368 | */ | ||
369 | struct GNUNET_PSYC_JoinDecisionMessage | ||
370 | { | ||
371 | /** | ||
372 | * Type: GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION | ||
373 | */ | ||
374 | struct GNUNET_MessageHeader header; | ||
375 | |||
376 | /** | ||
377 | * #GNUNET_YES if the slave was admitted. | ||
378 | */ | ||
379 | int32_t is_admitted; | ||
380 | |||
381 | /** | ||
382 | * Public key of the joining slave. | ||
383 | * Only set when the master is sending the decision, | ||
384 | * not set when a slave is receiving it. | ||
385 | */ | ||
386 | struct GNUNET_CRYPTO_EcdsaPublicKey slave_pub_key; | ||
387 | |||
388 | /* Followed by struct GNUNET_MessageHeader join_response */ | ||
389 | }; | ||
390 | |||
391 | |||
392 | enum GNUNET_PSYC_HistoryReplayFlags | ||
393 | { | ||
394 | /** | ||
395 | * Replay locally available messages. | ||
396 | */ | ||
397 | GNUNET_PSYC_HISTORY_REPLAY_LOCAL = 0, | ||
398 | |||
399 | /** | ||
400 | * Replay messages from remote peers if not found locally. | ||
401 | */ | ||
402 | GNUNET_PSYC_HISTORY_REPLAY_REMOTE = 1, | ||
403 | }; | ||
404 | |||
405 | |||
406 | struct GNUNET_PSYC_HistoryRequestMessage | ||
407 | { | ||
408 | /** | ||
409 | * Type: GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_HISTORY_REPLAY | ||
410 | */ | ||
411 | struct GNUNET_MessageHeader header; | ||
412 | |||
413 | /** | ||
414 | * @see enum GNUNET_PSYC_HistoryReplayFlags | ||
415 | */ | ||
416 | uint32_t flags GNUNET_PACKED; | ||
417 | |||
418 | /** | ||
419 | * ID for this operation. | ||
420 | */ | ||
421 | uint64_t op_id GNUNET_PACKED; | ||
422 | |||
423 | uint64_t start_message_id GNUNET_PACKED; | ||
424 | |||
425 | uint64_t end_message_id GNUNET_PACKED; | ||
426 | |||
427 | uint64_t message_limit GNUNET_PACKED; | ||
428 | |||
429 | /* Followed by NUL-terminated method name prefix. */ | ||
430 | }; | ||
431 | |||
432 | |||
433 | struct GNUNET_PSYC_StateRequestMessage | ||
434 | { | ||
435 | /** | ||
436 | * Types: | ||
437 | * - GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_STATE_GET | ||
438 | * - GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_STATE_GET_PREFIX | ||
439 | */ | ||
440 | struct GNUNET_MessageHeader header; | ||
441 | |||
442 | uint32_t reserved GNUNET_PACKED; | ||
443 | |||
444 | /** | ||
445 | * ID for this operation. | ||
446 | */ | ||
447 | uint64_t op_id GNUNET_PACKED; | ||
448 | |||
449 | /* Followed by NUL-terminated name. */ | ||
450 | }; | ||
451 | |||
452 | |||
453 | /**** service -> library ****/ | ||
454 | |||
455 | |||
456 | /** | ||
457 | * Answer from service to client about last operation. | ||
458 | */ | ||
459 | struct GNUNET_PSYC_OperationResultMessage | ||
460 | { | ||
461 | /** | ||
462 | * Types: | ||
463 | * - GNUNET_MESSAGE_TYPE_PSYC_RESULT_CODE | ||
464 | * - GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_STATE_RESULT | ||
465 | */ | ||
466 | struct GNUNET_MessageHeader header; | ||
467 | |||
468 | uint32_t reserved GNUNET_PACKED; | ||
469 | |||
470 | /** | ||
471 | * Operation ID. | ||
472 | */ | ||
473 | uint64_t op_id GNUNET_PACKED; | ||
474 | |||
475 | /** | ||
476 | * Status code for the operation. | ||
477 | */ | ||
478 | uint64_t result_code GNUNET_PACKED; | ||
479 | |||
480 | /* Followed by: | ||
481 | * - on error: NUL-terminated error message | ||
482 | * - on success: one of the following message types | ||
483 | * | ||
484 | * For a STATE_RESULT, one of: | ||
485 | * - GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER | ||
486 | * - GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT | ||
487 | * - GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END | ||
488 | */ | ||
489 | }; | ||
490 | |||
491 | GNUNET_NETWORK_STRUCT_END | ||
492 | |||
493 | |||
494 | #define GNUNET_PSYC_MODIFIER_MAX_PAYLOAD \ | ||
495 | GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD \ | ||
496 | - sizeof (struct GNUNET_PSYC_MessageModifier) | ||
497 | |||
498 | #define GNUNET_PSYC_MOD_CONT_MAX_PAYLOAD \ | ||
499 | GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD \ | ||
500 | - sizeof (struct GNUNET_MessageHeader) | ||
501 | |||
502 | #define GNUNET_PSYC_DATA_MAX_PAYLOAD \ | ||
503 | GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD \ | ||
504 | - sizeof (struct GNUNET_MessageHeader) | ||
505 | |||
506 | |||
507 | /** | ||
508 | * PSYC message part processing states. | ||
509 | */ | ||
510 | enum GNUNET_PSYC_MessageState | ||
511 | { | ||
512 | GNUNET_PSYC_MESSAGE_STATE_START = 0, | ||
513 | GNUNET_PSYC_MESSAGE_STATE_HEADER = 1, | ||
514 | GNUNET_PSYC_MESSAGE_STATE_METHOD = 2, | ||
515 | GNUNET_PSYC_MESSAGE_STATE_MODIFIER = 3, | ||
516 | GNUNET_PSYC_MESSAGE_STATE_MOD_CONT = 4, | ||
517 | GNUNET_PSYC_MESSAGE_STATE_DATA = 5, | ||
518 | GNUNET_PSYC_MESSAGE_STATE_END = 6, | ||
519 | GNUNET_PSYC_MESSAGE_STATE_CANCEL = 7, | ||
520 | GNUNET_PSYC_MESSAGE_STATE_ERROR = 8, | ||
521 | }; | ||
522 | |||
523 | |||
524 | /** | ||
525 | * Handle that identifies a join request. | ||
526 | * | ||
527 | * Used to match calls to #GNUNET_PSYC_JoinCallback to the | ||
528 | * corresponding calls to GNUNET_PSYC_join_decision(). | ||
529 | */ | ||
530 | struct GNUNET_PSYC_JoinHandle; | ||
531 | |||
532 | |||
533 | /** | ||
534 | * Method called from PSYC upon receiving a message. | ||
535 | * | ||
536 | * @param cls Closure. | ||
537 | * @param message_id Sequence number of the message. | ||
538 | * @param flags OR'ed GNUNET_PSYC_MessageFlags | ||
539 | * @param msg Message part, one of the following types: | ||
540 | */ | ||
541 | typedef void | ||
542 | (*GNUNET_PSYC_MessageCallback) (void *cls, | ||
543 | const struct GNUNET_PSYC_MessageHeader *msg); | ||
544 | |||
545 | |||
546 | /** | ||
547 | * Method called from PSYC upon receiving part of a message. | ||
548 | * | ||
549 | * @param cls | ||
550 | * Closure. | ||
551 | * @param slave_pub_key | ||
552 | * Public key of the slave sending the message. | ||
553 | * Only set for channel master. | ||
554 | * @param message_id | ||
555 | * Sequence number of the message. | ||
556 | * @param flags | ||
557 | * OR'ed GNUNET_PSYC_MessageFlags | ||
558 | * @param fragment_offset | ||
559 | * Multicast message fragment offset. | ||
560 | * @param msg Message part, one of the following types: | ||
561 | * - #GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_HEADER | ||
562 | * - #GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD | ||
563 | * - #GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER | ||
564 | * - #GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT | ||
565 | * - #GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA | ||
566 | * or NULL if an error occurred while receiving a message. | ||
567 | */ | ||
568 | typedef void | ||
569 | (*GNUNET_PSYC_MessagePartCallback) (void *cls, | ||
570 | const struct GNUNET_PSYC_MessageHeader *msg, | ||
571 | const struct GNUNET_MessageHeader *pmsg); | ||
572 | |||
573 | |||
574 | /** | ||
575 | * Method called from PSYC upon receiving a join request. | ||
576 | * | ||
577 | * @param cls | ||
578 | * Closure. | ||
579 | * @param slave_pub_key | ||
580 | * Public key of the slave requesting join. | ||
581 | * @param join_msg | ||
582 | * Join message sent along with the request. | ||
583 | * @param jh | ||
584 | * Join handle to use with GNUNET_PSYC_join_decision() | ||
585 | */ | ||
586 | typedef void | ||
587 | (*GNUNET_PSYC_JoinRequestCallback) (void *cls, | ||
588 | const struct GNUNET_PSYC_JoinRequestMessage *req, | ||
589 | const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_pub_key, | ||
590 | const struct GNUNET_PSYC_Message *join_msg, | ||
591 | struct GNUNET_PSYC_JoinHandle *jh); | ||
592 | |||
593 | |||
594 | /** | ||
595 | * Function to call with the decision made for a join request. | ||
596 | * | ||
597 | * Must be called once and only once in response to an invocation of the | ||
598 | * #GNUNET_PSYC_JoinCallback. | ||
599 | * | ||
600 | * @param jh Join request handle. | ||
601 | * @param is_admitted | ||
602 | * #GNUNET_YES if the join is approved, | ||
603 | * #GNUNET_NO if it is disapproved, | ||
604 | * #GNUNET_SYSERR if we cannot answer the request. | ||
605 | * @param relay_count Number of relays given. | ||
606 | * @param relays Array of suggested peers that might be useful relays to use | ||
607 | * when joining the multicast group (essentially a list of peers that | ||
608 | * are already part of the multicast group and might thus be willing | ||
609 | * to help with routing). If empty, only this local peer (which must | ||
610 | * be the multicast origin) is a good candidate for building the | ||
611 | * multicast tree. Note that it is unnecessary to specify our own | ||
612 | * peer identity in this array. | ||
613 | * @param join_resp Application-dependent join response message to send along | ||
614 | * with the decision. | ||
615 | * | ||
616 | * @return #GNUNET_OK on success, | ||
617 | * #GNUNET_SYSERR if @a join_resp is too large. | ||
618 | */ | ||
619 | int | ||
620 | GNUNET_PSYC_join_decision (struct GNUNET_PSYC_JoinHandle *jh, | ||
621 | int is_admitted, | ||
622 | uint32_t relay_count, | ||
623 | const struct GNUNET_PeerIdentity *relays, | ||
624 | const struct GNUNET_PSYC_Message *join_resp); | ||
625 | |||
626 | |||
627 | /** | ||
628 | * Handle for the master of a PSYC channel. | ||
629 | */ | ||
630 | struct GNUNET_PSYC_Master; | ||
631 | |||
632 | |||
633 | /** | ||
634 | * Function called once we are connected to the PSYC service | ||
635 | * and the channel master is started. | ||
636 | * | ||
637 | * Also called when we reconnected to the service | ||
638 | * after the connection closed unexpectedly. | ||
639 | * | ||
640 | * @param cls | ||
641 | * Closure. | ||
642 | * @param result | ||
643 | * #GNUNET_YES if there were already messages sent to the channel, | ||
644 | * #GNUNET_NO if the message history is empty, | ||
645 | * #GNUNET_SYSERR on error. | ||
646 | * @param max_message_id | ||
647 | * Last message ID sent to the channel. | ||
648 | */ | ||
649 | typedef void | ||
650 | (*GNUNET_PSYC_MasterStartCallback) (void *cls, int result, | ||
651 | uint64_t max_message_id); | ||
652 | |||
653 | |||
654 | /** | ||
655 | * Start a PSYC master channel. | ||
656 | * | ||
657 | * Will start a multicast group identified by the given ECC key. Messages | ||
658 | * received from group members will be given to the respective handler methods. | ||
659 | * If a new member wants to join a group, the "join" method handler will be | ||
660 | * invoked; the join handler must then generate a "join" message to approve the | ||
661 | * joining of the new member. The channel can also change group membership | ||
662 | * without explicit requests. Note that PSYC doesn't itself "understand" join | ||
663 | * or part messages, the respective methods must call other PSYC functions to | ||
664 | * inform PSYC about the meaning of the respective events. | ||
665 | * | ||
666 | * @param cfg Configuration to use (to connect to PSYC service). | ||
667 | * @param channel_key ECC key that will be used to sign messages for this | ||
668 | * PSYC session. The public key is used to identify the PSYC channel. | ||
669 | * Note that end-users will usually not use the private key directly, but | ||
670 | * rather look it up in GNS for places managed by other users, or select | ||
671 | * a file with the private key(s) when setting up their own channels | ||
672 | * FIXME: we'll likely want to use NOT the p521 curve here, but a cheaper | ||
673 | * one in the future. | ||
674 | * @param policy Channel policy specifying join and history restrictions. | ||
675 | * Used to automate join decisions. | ||
676 | * @param master_start_cb Function to invoke after the channel master started. | ||
677 | * @param join_request_cb Function to invoke when a slave wants to join. | ||
678 | * @param message_cb Function to invoke on message parts sent to the channel | ||
679 | * and received from slaves | ||
680 | * @param cls Closure for @a method and @a join_cb. | ||
681 | * | ||
682 | * @return Handle for the channel master, NULL on error. | ||
683 | */ | ||
684 | struct GNUNET_PSYC_Master * | ||
685 | GNUNET_PSYC_master_start (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
686 | const struct GNUNET_CRYPTO_EddsaPrivateKey *channel_key, | ||
687 | enum GNUNET_PSYC_Policy policy, | ||
688 | GNUNET_PSYC_MasterStartCallback master_start_cb, | ||
689 | GNUNET_PSYC_JoinRequestCallback join_request_cb, | ||
690 | GNUNET_PSYC_MessageCallback message_cb, | ||
691 | GNUNET_PSYC_MessagePartCallback message_part_cb, | ||
692 | void *cls); | ||
693 | |||
694 | |||
695 | /** | ||
696 | * Function called to provide data for a transmission via PSYC. | ||
697 | * | ||
698 | * Note that returning #GNUNET_YES or #GNUNET_SYSERR (but not #GNUNET_NO) | ||
699 | * invalidates the respective transmission handle. | ||
700 | * | ||
701 | * @param cls Closure. | ||
702 | * @param[in,out] data_size Initially set to the number of bytes available in | ||
703 | * @a data, should be set to the number of bytes written to data. | ||
704 | * @param[out] data Where to write the body of the message to give to the | ||
705 | * method. The function must copy at most @a data_size bytes to @a data. | ||
706 | * @return #GNUNET_SYSERR on error (fatal, aborts transmission) | ||
707 | * #GNUNET_NO on success, if more data is to be transmitted later. | ||
708 | * Should be used if @a data_size was not big enough to take all the | ||
709 | * data. If 0 is returned in @a data_size the transmission is paused, | ||
710 | * and can be resumed with GNUNET_PSYC_master_transmit_resume(). | ||
711 | * #GNUNET_YES if this completes the transmission (all data supplied) | ||
712 | */ | ||
713 | typedef int | ||
714 | (*GNUNET_PSYC_TransmitNotifyData) (void *cls, | ||
715 | uint16_t *data_size, | ||
716 | void *data); | ||
717 | |||
718 | /** | ||
719 | * Function called to provide a modifier for a transmission via PSYC. | ||
720 | * | ||
721 | * Note that returning #GNUNET_YES or #GNUNET_SYSERR (but not #GNUNET_NO) | ||
722 | * invalidates the respective transmission handle. | ||
723 | * | ||
724 | * @param cls Closure. | ||
725 | * @param[in,out] data_size Initially set to the number of bytes available in | ||
726 | * @a data, should be set to the number of bytes written to data. | ||
727 | * @param[out] data Where to write the modifier's name and value. | ||
728 | * The function must copy at most @a data_size bytes to @a data. | ||
729 | * When this callback is first called for a modifier, @a data should | ||
730 | * contain: "name\0value". If the whole value does not fit, subsequent | ||
731 | * calls to this function should write continuations of the value to | ||
732 | * @a data. | ||
733 | * @param[out] oper Where to write the operator of the modifier. | ||
734 | * Only needed during the first call to this callback at the beginning | ||
735 | * of the modifier. In case of subsequent calls asking for value | ||
736 | * continuations @a oper is set to #NULL. | ||
737 | * @param[out] full_value_size Where to write the full size of the value. | ||
738 | * Only needed during the first call to this callback at the beginning | ||
739 | * of the modifier. In case of subsequent calls asking for value | ||
740 | * continuations @a value_size is set to #NULL. | ||
741 | * @return #GNUNET_SYSERR on error (fatal, aborts transmission) | ||
742 | * #GNUNET_NO on success, if more data is to be transmitted later. | ||
743 | * Should be used if @a data_size was not big enough to take all the | ||
744 | * data for the modifier's value (the name must be always returned | ||
745 | * during the first call to this callback). | ||
746 | * If 0 is returned in @a data_size the transmission is paused, | ||
747 | * and can be resumed with GNUNET_PSYC_master_transmit_resume(). | ||
748 | * #GNUNET_YES if this completes the modifier (the whole value is supplied). | ||
749 | */ | ||
750 | typedef int | ||
751 | (*GNUNET_PSYC_TransmitNotifyModifier) (void *cls, | ||
752 | uint16_t *data_size, | ||
753 | void *data, | ||
754 | uint8_t *oper, | ||
755 | uint32_t *full_value_size); | ||
756 | |||
757 | /** | ||
758 | * Flags for transmitting messages to a channel by the master. | ||
759 | */ | ||
760 | enum GNUNET_PSYC_MasterTransmitFlags | ||
761 | { | ||
762 | GNUNET_PSYC_MASTER_TRANSMIT_NONE = 0, | ||
763 | |||
764 | /** | ||
765 | * Whether this message should reset the channel state, | ||
766 | * i.e. remove all previously stored state variables. | ||
767 | */ | ||
768 | |||
769 | GNUNET_PSYC_MASTER_TRANSMIT_STATE_RESET = 1 << 0, | ||
770 | |||
771 | /** | ||
772 | * Whether this message contains any state modifiers. | ||
773 | */ | ||
774 | GNUNET_PSYC_MASTER_TRANSMIT_STATE_MODIFY = 1 << 1, | ||
775 | |||
776 | /** | ||
777 | * Add PSYC header variable with the hash of the current channel state. | ||
778 | */ | ||
779 | GNUNET_PSYC_MASTER_TRANSMIT_STATE_HASH = 1 << 2, | ||
780 | |||
781 | /** | ||
782 | * Whether we need to increment the group generation counter after | ||
783 | * transmitting this message. | ||
784 | */ | ||
785 | GNUNET_PSYC_MASTER_TRANSMIT_INC_GROUP_GEN = 1 << 3 | ||
786 | }; | ||
787 | |||
788 | |||
789 | /** | ||
790 | * Handle for a pending PSYC transmission operation. | ||
791 | */ | ||
792 | struct GNUNET_PSYC_MasterTransmitHandle; | ||
793 | |||
794 | |||
795 | /** | ||
796 | * Send a message to call a method to all members in the PSYC channel. | ||
797 | * | ||
798 | * @param master Handle to the PSYC channel. | ||
799 | * @param method_name Which method should be invoked. | ||
800 | * @param notify_mod Function to call to obtain modifiers. | ||
801 | * @param notify_data Function to call to obtain fragments of the data. | ||
802 | * @param notify_cls Closure for @a notify_mod and @a notify_data. | ||
803 | * @param flags Flags for the message being transmitted. | ||
804 | * @return Transmission handle, NULL on error (i.e. more than one request queued). | ||
805 | */ | ||
806 | struct GNUNET_PSYC_MasterTransmitHandle * | ||
807 | GNUNET_PSYC_master_transmit (struct GNUNET_PSYC_Master *master, | ||
808 | const char *method_name, | ||
809 | GNUNET_PSYC_TransmitNotifyModifier notify_mod, | ||
810 | GNUNET_PSYC_TransmitNotifyData notify_data, | ||
811 | void *notify_cls, | ||
812 | enum GNUNET_PSYC_MasterTransmitFlags flags); | ||
813 | |||
814 | |||
815 | /** | ||
816 | * Resume transmission to the channel. | ||
817 | * | ||
818 | * @param th Handle of the request that is being resumed. | ||
819 | */ | ||
820 | void | ||
821 | GNUNET_PSYC_master_transmit_resume (struct GNUNET_PSYC_MasterTransmitHandle *th); | ||
822 | |||
823 | |||
824 | /** | ||
825 | * Abort transmission request to channel. | ||
826 | * | ||
827 | * @param th Handle of the request that is being aborted. | ||
828 | */ | ||
829 | void | ||
830 | GNUNET_PSYC_master_transmit_cancel (struct GNUNET_PSYC_MasterTransmitHandle *th); | ||
831 | |||
832 | |||
833 | /** | ||
834 | * Relay a message | ||
835 | * | ||
836 | * @param master Handle to the PSYC channel. | ||
837 | * @param method_name Which method should be invoked. | ||
838 | * @param notify_mod Function to call to obtain modifiers. | ||
839 | * @param notify_data Function to call to obtain fragments of the data. | ||
840 | * @param notify_cls Closure for @a notify_mod and @a notify_data. | ||
841 | * @param flags Flags for the message being transmitted. | ||
842 | * @return Transmission handle, NULL on error (i.e. more than one request queued). | ||
843 | */ | ||
844 | struct GNUNET_PSYC_MasterTransmitHandle * | ||
845 | GNUNET_PSYC_master_relay (struct GNUNET_PSYC_Master *master, | ||
846 | uint64_t message_id); | ||
847 | |||
848 | |||
849 | /** | ||
850 | * Stop a PSYC master channel. | ||
851 | * | ||
852 | * @param master | ||
853 | * PSYC channel master to stop. | ||
854 | * @param keep_active | ||
855 | * Keep place active after last application disconnected. | ||
856 | * @param stop_cb | ||
857 | * Function called after the master stopped | ||
858 | * and disconnected from the psyc service. | ||
859 | * @param stop_cls | ||
860 | * Closure for @a part_cb. | ||
861 | */ | ||
862 | void | ||
863 | GNUNET_PSYC_master_stop (struct GNUNET_PSYC_Master *master, | ||
864 | int keep_active, | ||
865 | GNUNET_ContinuationCallback stop_cb, | ||
866 | void *stop_cls); | ||
867 | |||
868 | |||
869 | /** | ||
870 | * Handle for a PSYC channel slave. | ||
871 | */ | ||
872 | struct GNUNET_PSYC_Slave; | ||
873 | |||
874 | |||
875 | /** | ||
876 | * Function called after the slave connected to the PSYC service. | ||
877 | * | ||
878 | * Also called when reconnected to the service | ||
879 | * after the connection closed unexpectedly. | ||
880 | * | ||
881 | * @param cls | ||
882 | * Closure. | ||
883 | * @param result | ||
884 | * #GNUNET_YES if there were already messages sent to the channel, | ||
885 | * #GNUNET_NO if the message history is empty, | ||
886 | * #GNUNET_SYSERR on error. | ||
887 | * @param max_message_id | ||
888 | * Last message ID sent to the channel. | ||
889 | */ | ||
890 | typedef void | ||
891 | (*GNUNET_PSYC_SlaveConnectCallback) (void *cls, int result, | ||
892 | uint64_t max_message_id); | ||
893 | |||
894 | |||
895 | /** | ||
896 | * Method called to inform about the decision in response to a join request. | ||
897 | * | ||
898 | * If @a is_admitted is not #GNUNET_YES, then sending messages to the channel is | ||
899 | * not possible, but earlier history can be still queried. | ||
900 | * | ||
901 | * @param cls Closure. | ||
902 | * @param is_admitted #GNUNET_YES or #GNUNET_NO or #GNUNET_SYSERR | ||
903 | * @param join_msg Application-dependent join message from the origin. | ||
904 | */ | ||
905 | typedef void | ||
906 | (*GNUNET_PSYC_JoinDecisionCallback) (void *cls, | ||
907 | const struct GNUNET_PSYC_JoinDecisionMessage *dcsn, | ||
908 | int is_admitted, | ||
909 | const struct GNUNET_PSYC_Message *join_msg); | ||
910 | |||
911 | /** | ||
912 | * Flags for GNUNET_PSYC_slave_join() | ||
913 | */ | ||
914 | enum GNUNET_PSYC_SlaveJoinFlags | ||
915 | { | ||
916 | GNUNET_PSYC_SLAVE_JOIN_NONE = 0, | ||
917 | |||
918 | /** | ||
919 | * Local join for history access, no network connection is established. | ||
920 | */ | ||
921 | GNUNET_PSYC_SLAVE_JOIN_LOCAL = 1, | ||
922 | }; | ||
923 | |||
924 | |||
925 | /** | ||
926 | * Join a PSYC channel. | ||
927 | * | ||
928 | * The entity joining is always the local peer. The user must immediately use | ||
929 | * the GNUNET_PSYC_slave_transmit() functions to transmit a @e join_msg to the | ||
930 | * channel; if the join request succeeds, the channel state (and @e recent | ||
931 | * method calls) will be replayed to the joining member. There is no explicit | ||
932 | * notification on failure (as the channel may simply take days to approve, | ||
933 | * and disapproval is simply being ignored). | ||
934 | * | ||
935 | * @param cfg | ||
936 | * Configuration to use. | ||
937 | * @param channel_pub_key | ||
938 | * ECC public key that identifies the channel we wish to join. | ||
939 | * @param slave_pub_key | ||
940 | * ECC private-public key pair that identifies the slave, and | ||
941 | * used by multicast to sign the join request and subsequent unicast | ||
942 | * requests sent to the master. | ||
943 | * @param flags | ||
944 | * Join flags. | ||
945 | * @param origin | ||
946 | * Peer identity of the origin. | ||
947 | * @param relay_count | ||
948 | * Number of peers in the @a relays array. | ||
949 | * @param relays | ||
950 | * Peer identities of members of the multicast group, which serve | ||
951 | * as relays and used to join the group at. | ||
952 | * @param message_cb | ||
953 | * Function to invoke on message fragments received from the channel. | ||
954 | * @param message_part_cb | ||
955 | * Function to invoke on message parts received from the channel. | ||
956 | * @param slave_connect_cb | ||
957 | * Function invoked once we have connected to the PSYC service. | ||
958 | * @param join_decision_cb | ||
959 | * Function invoked once we have received a join decision. | ||
960 | * @param cls | ||
961 | * Closure for @a message_cb and @a slave_joined_cb. | ||
962 | * @param join_msg | ||
963 | * Join message. | ||
964 | * | ||
965 | * @return Handle for the slave, NULL on error. | ||
966 | */ | ||
967 | struct GNUNET_PSYC_Slave * | ||
968 | GNUNET_PSYC_slave_join (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
969 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_pub_key, | ||
970 | const struct GNUNET_CRYPTO_EcdsaPrivateKey *slave_pub_key, | ||
971 | enum GNUNET_PSYC_SlaveJoinFlags flags, | ||
972 | const struct GNUNET_PeerIdentity *origin, | ||
973 | uint32_t relay_count, | ||
974 | const struct GNUNET_PeerIdentity *relays, | ||
975 | GNUNET_PSYC_MessageCallback message_cb, | ||
976 | GNUNET_PSYC_MessagePartCallback message_part_cb, | ||
977 | GNUNET_PSYC_SlaveConnectCallback slave_connect_cb, | ||
978 | GNUNET_PSYC_JoinDecisionCallback join_decision_cb, | ||
979 | void *cls, | ||
980 | const struct GNUNET_PSYC_Message *join_msg); | ||
981 | |||
982 | |||
983 | /** | ||
984 | * Part a PSYC channel. | ||
985 | * | ||
986 | * Will terminate the connection to the PSYC service. Polite clients should | ||
987 | * first explicitly send a part request (via GNUNET_PSYC_slave_transmit()). | ||
988 | * | ||
989 | * @param slave | ||
990 | * Slave handle. | ||
991 | * @param keep_active | ||
992 | * Keep place active after last application disconnected. | ||
993 | * @param part_cb | ||
994 | * Function called after the slave parted the channel | ||
995 | * and disconnected from the psyc service. | ||
996 | * @param part_cls | ||
997 | * Closure for @a part_cb. | ||
998 | */ | ||
999 | void | ||
1000 | GNUNET_PSYC_slave_part (struct GNUNET_PSYC_Slave *slave, | ||
1001 | int keep_active, | ||
1002 | GNUNET_ContinuationCallback part_cb, | ||
1003 | void *part_cls); | ||
1004 | |||
1005 | |||
1006 | /** | ||
1007 | * Flags for transmitting messages to the channel master by a slave. | ||
1008 | */ | ||
1009 | enum GNUNET_PSYC_SlaveTransmitFlags | ||
1010 | { | ||
1011 | GNUNET_PSYC_SLAVE_TRANSMIT_NONE = 0 | ||
1012 | }; | ||
1013 | |||
1014 | |||
1015 | /** | ||
1016 | * Handle for a pending PSYC transmission operation. | ||
1017 | */ | ||
1018 | struct GNUNET_PSYC_SlaveTransmitHandle; | ||
1019 | |||
1020 | |||
1021 | /** | ||
1022 | * Request a message to be sent to the channel master. | ||
1023 | * | ||
1024 | * @param slave Slave handle. | ||
1025 | * @param method_name Which (PSYC) method should be invoked (on host). | ||
1026 | * @param notify_mod Function to call to obtain modifiers. | ||
1027 | * @param notify_data Function to call to obtain fragments of the data. | ||
1028 | * @param notify_cls Closure for @a notify. | ||
1029 | * @param flags Flags for the message being transmitted. | ||
1030 | * @return Transmission handle, NULL on error (i.e. more than one request queued). | ||
1031 | */ | ||
1032 | struct GNUNET_PSYC_SlaveTransmitHandle * | ||
1033 | GNUNET_PSYC_slave_transmit (struct GNUNET_PSYC_Slave *slave, | ||
1034 | const char *method_name, | ||
1035 | GNUNET_PSYC_TransmitNotifyModifier notify_mod, | ||
1036 | GNUNET_PSYC_TransmitNotifyData notify_data, | ||
1037 | void *notify_cls, | ||
1038 | enum GNUNET_PSYC_SlaveTransmitFlags flags); | ||
1039 | |||
1040 | |||
1041 | /** | ||
1042 | * Resume transmission to the master. | ||
1043 | * | ||
1044 | * @param th Handle of the request that is being resumed. | ||
1045 | */ | ||
1046 | void | ||
1047 | GNUNET_PSYC_slave_transmit_resume (struct GNUNET_PSYC_SlaveTransmitHandle *th); | ||
1048 | |||
1049 | |||
1050 | /** | ||
1051 | * Abort transmission request to master. | ||
1052 | * | ||
1053 | * @param th Handle of the request that is being aborted. | ||
1054 | */ | ||
1055 | void | ||
1056 | GNUNET_PSYC_slave_transmit_cancel (struct GNUNET_PSYC_SlaveTransmitHandle *th); | ||
1057 | |||
1058 | |||
1059 | /** | ||
1060 | * Handle to access PSYC channel operations for both the master and slaves. | ||
1061 | */ | ||
1062 | struct GNUNET_PSYC_Channel; | ||
1063 | |||
1064 | |||
1065 | /** | ||
1066 | * Convert a channel @a master to a @e channel handle to access the @e channel | ||
1067 | * APIs. | ||
1068 | * | ||
1069 | * @param master Channel master handle. | ||
1070 | * @return Channel handle, valid for as long as @a master is valid. | ||
1071 | */ | ||
1072 | struct GNUNET_PSYC_Channel * | ||
1073 | GNUNET_PSYC_master_get_channel (struct GNUNET_PSYC_Master *master); | ||
1074 | |||
1075 | |||
1076 | /** | ||
1077 | * Convert @a slave to a @e channel handle to access the @e channel APIs. | ||
1078 | * | ||
1079 | * @param slave Slave handle. | ||
1080 | * @return Channel handle, valid for as long as @a slave is valid. | ||
1081 | */ | ||
1082 | struct GNUNET_PSYC_Channel * | ||
1083 | GNUNET_PSYC_slave_get_channel (struct GNUNET_PSYC_Slave *slave); | ||
1084 | |||
1085 | |||
1086 | /** | ||
1087 | * Add a slave to the channel's membership list. | ||
1088 | * | ||
1089 | * Note that this will NOT generate any PSYC traffic, it will merely update the | ||
1090 | * local database to modify how we react to <em>membership test</em> queries. | ||
1091 | * The channel master still needs to explicitly transmit a @e join message to | ||
1092 | * notify other channel members and they then also must still call this function | ||
1093 | * in their respective methods handling the @e join message. This way, how @e | ||
1094 | * join and @e part operations are exactly implemented is still up to the | ||
1095 | * application; for example, there might be a @e part_all method to kick out | ||
1096 | * everyone. | ||
1097 | * | ||
1098 | * Note that channel slaves are explicitly trusted to execute such methods | ||
1099 | * correctly; not doing so correctly will result in either denying other slaves | ||
1100 | * access or offering access to channel data to non-members. | ||
1101 | * | ||
1102 | * @param channel | ||
1103 | * Channel handle. | ||
1104 | * @param slave_pub_key | ||
1105 | * Identity of channel slave to add. | ||
1106 | * @param announced_at | ||
1107 | * ID of the message that announced the membership change. | ||
1108 | * @param effective_since | ||
1109 | * Addition of slave is in effect since this message ID. | ||
1110 | * @param result_cb | ||
1111 | * Function to call with the result of the operation. | ||
1112 | * The @e result_code argument is #GNUNET_OK on success, or | ||
1113 | * #GNUNET_SYSERR on error. In case of an error, the @e data argument | ||
1114 | * can contain an optional error message. | ||
1115 | * @param cls | ||
1116 | * Closure for @a result_cb. | ||
1117 | */ | ||
1118 | void | ||
1119 | GNUNET_PSYC_channel_slave_add (struct GNUNET_PSYC_Channel *channel, | ||
1120 | const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_pub_key, | ||
1121 | uint64_t announced_at, | ||
1122 | uint64_t effective_since, | ||
1123 | GNUNET_ResultCallback result_cb, | ||
1124 | void *cls); | ||
1125 | |||
1126 | |||
1127 | /** | ||
1128 | * Remove a slave from the channel's membership list. | ||
1129 | * | ||
1130 | * Note that this will NOT generate any PSYC traffic, it will merely update the | ||
1131 | * local database to modify how we react to <em>membership test</em> queries. | ||
1132 | * The channel master still needs to explicitly transmit a @e part message to | ||
1133 | * notify other channel members and they then also must still call this function | ||
1134 | * in their respective methods handling the @e part message. This way, how | ||
1135 | * @e join and @e part operations are exactly implemented is still up to the | ||
1136 | * application; for example, there might be a @e part_all message to kick out | ||
1137 | * everyone. | ||
1138 | * | ||
1139 | * Note that channel members are explicitly trusted to perform these | ||
1140 | * operations correctly; not doing so correctly will result in either | ||
1141 | * denying members access or offering access to channel data to | ||
1142 | * non-members. | ||
1143 | * | ||
1144 | * @param channel | ||
1145 | * Channel handle. | ||
1146 | * @param slave_pub_key | ||
1147 | * Identity of channel slave to remove. | ||
1148 | * @param announced_at | ||
1149 | * ID of the message that announced the membership change. | ||
1150 | * @param result_cb | ||
1151 | * Function to call with the result of the operation. | ||
1152 | * The @e result_code argument is #GNUNET_OK on success, or | ||
1153 | * #GNUNET_SYSERR on error. In case of an error, the @e data argument | ||
1154 | * can contain an optional error message. | ||
1155 | * @param cls | ||
1156 | * Closure for @a result_cb. | ||
1157 | */ | ||
1158 | void | ||
1159 | GNUNET_PSYC_channel_slave_remove (struct GNUNET_PSYC_Channel *channel, | ||
1160 | const struct GNUNET_CRYPTO_EcdsaPublicKey | ||
1161 | *slave_pub_key, | ||
1162 | uint64_t announced_at, | ||
1163 | GNUNET_ResultCallback result_cb, | ||
1164 | void *cls); | ||
1165 | |||
1166 | |||
1167 | /** | ||
1168 | * History request handle. | ||
1169 | */ | ||
1170 | struct GNUNET_PSYC_HistoryRequest; | ||
1171 | |||
1172 | |||
1173 | /** | ||
1174 | * Request to replay a part of the message history of the channel. | ||
1175 | * | ||
1176 | * Historic messages (but NOT the state at the time) will be replayed (given to | ||
1177 | * the normal method handlers) if available and if access is permitted. | ||
1178 | * | ||
1179 | * @param channel | ||
1180 | * Which channel should be replayed? | ||
1181 | * @param start_message_id | ||
1182 | * Earliest interesting point in history. | ||
1183 | * @param end_message_id | ||
1184 | * Last (inclusive) interesting point in history. | ||
1185 | * @param method_prefix | ||
1186 | * Retrieve only messages with a matching method prefix. | ||
1187 | * @param flags | ||
1188 | * OR'ed enum GNUNET_PSYC_HistoryReplayFlags | ||
1189 | * @param result_cb | ||
1190 | * Function to call when the requested history has been fully replayed. | ||
1191 | * Once this function has been called, the client must not call | ||
1192 | * GNUNET_PSYC_channel_history_replay_cancel() anymore. | ||
1193 | * @param cls | ||
1194 | * Closure for the callbacks. | ||
1195 | * | ||
1196 | * @return Handle to cancel history replay operation. | ||
1197 | */ | ||
1198 | struct GNUNET_PSYC_HistoryRequest * | ||
1199 | GNUNET_PSYC_channel_history_replay (struct GNUNET_PSYC_Channel *channel, | ||
1200 | uint64_t start_message_id, | ||
1201 | uint64_t end_message_id, | ||
1202 | const char *method_prefix, | ||
1203 | uint32_t flags, | ||
1204 | GNUNET_PSYC_MessageCallback message_cb, | ||
1205 | GNUNET_PSYC_MessagePartCallback message_part_cb, | ||
1206 | GNUNET_ResultCallback result_cb, | ||
1207 | void *cls); | ||
1208 | |||
1209 | |||
1210 | /** | ||
1211 | * Request to replay the latest messages from the message history of the channel. | ||
1212 | * | ||
1213 | * Historic messages (but NOT the state at the time) will be replayed (given to | ||
1214 | * the normal method handlers) if available and if access is permitted. | ||
1215 | * | ||
1216 | * @param channel | ||
1217 | * Which channel should be replayed? | ||
1218 | * @param message_limit | ||
1219 | * Maximum number of messages to replay. | ||
1220 | * @param flags | ||
1221 | * OR'ed enum GNUNET_PSYC_HistoryReplayFlags | ||
1222 | * @param finish_cb | ||
1223 | * Function to call when the requested history has been fully replayed | ||
1224 | * (counting message IDs might not suffice, as some messages might be | ||
1225 | * secret and thus the listener would not know the story is finished | ||
1226 | * without being told explicitly)o once this function has been called, the | ||
1227 | * client must not call GNUNET_PSYC_channel_history_replay_cancel() anymore. | ||
1228 | * @param cls | ||
1229 | * Closure for the callbacks. | ||
1230 | * | ||
1231 | * @return Handle to cancel history replay operation. | ||
1232 | */ | ||
1233 | struct GNUNET_PSYC_HistoryRequest * | ||
1234 | GNUNET_PSYC_channel_history_replay_latest (struct GNUNET_PSYC_Channel *channel, | ||
1235 | uint64_t message_limit, | ||
1236 | const char *method_prefix, | ||
1237 | uint32_t flags, | ||
1238 | GNUNET_PSYC_MessageCallback message_cb, | ||
1239 | GNUNET_PSYC_MessagePartCallback message_part_cb, | ||
1240 | GNUNET_ResultCallback result_cb, | ||
1241 | void *cls); | ||
1242 | |||
1243 | |||
1244 | void | ||
1245 | GNUNET_PSYC_channel_history_replay_cancel (struct GNUNET_PSYC_Channel *channel, | ||
1246 | struct GNUNET_PSYC_HistoryRequest *hr); | ||
1247 | |||
1248 | |||
1249 | /** | ||
1250 | * Function called to inform a member about stored state values for a channel. | ||
1251 | * | ||
1252 | * If @a full_value_size > value_size then this function is called multiple | ||
1253 | * times until the whole value arrived. | ||
1254 | * | ||
1255 | * @param cls | ||
1256 | * Closure. | ||
1257 | * @param name | ||
1258 | * Name of the state variable. | ||
1259 | * NULL if there are no more state variables to be returned. | ||
1260 | * @param value | ||
1261 | * Value of the state variable. | ||
1262 | * @param value_size | ||
1263 | * Number of bytes in @a value. | ||
1264 | * @param full_value_size | ||
1265 | * Number of bytes in the full value, including continuations. | ||
1266 | * Only set for the first part of a variable, | ||
1267 | * in case of a continuation it is 0. | ||
1268 | */ | ||
1269 | typedef void | ||
1270 | (*GNUNET_PSYC_StateVarCallback) (void *cls, | ||
1271 | const struct GNUNET_MessageHeader *mod, | ||
1272 | const char *name, | ||
1273 | const void *value, | ||
1274 | uint32_t value_size, | ||
1275 | uint32_t full_value_size); | ||
1276 | |||
1277 | |||
1278 | /** | ||
1279 | * State request handle. | ||
1280 | */ | ||
1281 | struct GNUNET_PSYC_StateRequest; | ||
1282 | |||
1283 | |||
1284 | /** | ||
1285 | * Retrieve the best matching channel state variable. | ||
1286 | * | ||
1287 | * If the requested variable name is not present in the state, the nearest | ||
1288 | * less-specific name is matched; for example, requesting "_a_b" will match "_a" | ||
1289 | * if "_a_b" does not exist. | ||
1290 | * | ||
1291 | * @param channel | ||
1292 | * Channel handle. | ||
1293 | * @param full_name | ||
1294 | * Full name of the requested variable. | ||
1295 | * The actual variable returned might have a shorter name. | ||
1296 | * @param var_cb | ||
1297 | * Function called once when a matching state variable is found. | ||
1298 | * Not called if there's no matching state variable. | ||
1299 | * @param result_cb | ||
1300 | * Function called after the operation finished. | ||
1301 | * (i.e. all state variables have been returned via @a state_cb) | ||
1302 | * @param cls | ||
1303 | * Closure for the callbacks. | ||
1304 | */ | ||
1305 | struct GNUNET_PSYC_StateRequest * | ||
1306 | GNUNET_PSYC_channel_state_get (struct GNUNET_PSYC_Channel *channel, | ||
1307 | const char *full_name, | ||
1308 | GNUNET_PSYC_StateVarCallback var_cb, | ||
1309 | GNUNET_ResultCallback result_cb, | ||
1310 | void *cls); | ||
1311 | |||
1312 | |||
1313 | /** | ||
1314 | * Return all channel state variables whose name matches a given prefix. | ||
1315 | * | ||
1316 | * A name matches if it starts with the given @a name_prefix, thus requesting | ||
1317 | * the empty prefix ("") will match all values; requesting "_a_b" will also | ||
1318 | * return values stored under "_a_b_c". | ||
1319 | * | ||
1320 | * The @a state_cb is invoked on all matching state variables asynchronously, as | ||
1321 | * the state is stored in and retrieved from the PSYCstore, | ||
1322 | * | ||
1323 | * @param channel | ||
1324 | * Channel handle. | ||
1325 | * @param name_prefix | ||
1326 | * Prefix of the state variable name to match. | ||
1327 | * @param var_cb | ||
1328 | * Function called once when a matching state variable is found. | ||
1329 | * Not called if there's no matching state variable. | ||
1330 | * @param result_cb | ||
1331 | * Function called after the operation finished. | ||
1332 | * (i.e. all state variables have been returned via @a state_cb) | ||
1333 | * @param cls | ||
1334 | * Closure for the callbacks. | ||
1335 | */ | ||
1336 | struct GNUNET_PSYC_StateRequest * | ||
1337 | GNUNET_PSYC_channel_state_get_prefix (struct GNUNET_PSYC_Channel *channel, | ||
1338 | const char *name_prefix, | ||
1339 | GNUNET_PSYC_StateVarCallback var_cb, | ||
1340 | GNUNET_ResultCallback result_cb, | ||
1341 | void *cls); | ||
1342 | |||
1343 | /** | ||
1344 | * Cancel a state request operation. | ||
1345 | * | ||
1346 | * @param sr | ||
1347 | * Handle for the operation to cancel. | ||
1348 | */ | ||
1349 | void | ||
1350 | GNUNET_PSYC_channel_state_get_cancel (struct GNUNET_PSYC_StateRequest *sr); | ||
1351 | |||
1352 | |||
1353 | |||
1354 | #if 0 /* keep Emacsens' auto-indent happy */ | ||
1355 | { | ||
1356 | #endif | ||
1357 | #ifdef __cplusplus | ||
1358 | } | ||
1359 | #endif | ||
1360 | |||
1361 | /* ifndef GNUNET_PSYC_SERVICE_H */ | ||
1362 | #endif | ||
1363 | |||
1364 | /** @} */ /* end of group */ | ||
diff --git a/src/include/gnunet_psyc_slicer.h b/src/include/gnunet_psyc_slicer.h deleted file mode 100644 index 87f66d7e8..000000000 --- a/src/include/gnunet_psyc_slicer.h +++ /dev/null | |||
@@ -1,378 +0,0 @@ | |||
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 | * @author Gabor X Toth | ||
23 | * @author Christian Grothoff | ||
24 | * | ||
25 | * @file | ||
26 | * PSYC Slicer library | ||
27 | * | ||
28 | * @defgroup psyc-util-slicer PSYC Utilities library: Slicer | ||
29 | * Try-and-slice processing of PSYC method names and environment. | ||
30 | * @{ | ||
31 | */ | ||
32 | |||
33 | #ifndef GNUNET_PSYC_SLICER_H | ||
34 | #define GNUNET_PSYC_SLICER_H | ||
35 | |||
36 | |||
37 | #ifdef __cplusplus | ||
38 | extern "C" | ||
39 | { | ||
40 | #if 0 /* keep Emacsens' auto-indent happy */ | ||
41 | } | ||
42 | #endif | ||
43 | #endif | ||
44 | |||
45 | #include "gnunet_util_lib.h" | ||
46 | |||
47 | |||
48 | /** | ||
49 | * Handle to an implementation of try-and-slice. | ||
50 | */ | ||
51 | struct GNUNET_PSYC_Slicer; | ||
52 | |||
53 | |||
54 | /** | ||
55 | * Function called upon receiving a message indicating a call to a @e method. | ||
56 | * | ||
57 | * This function is called one or more times for each message until all data | ||
58 | * fragments arrive from the network. | ||
59 | * | ||
60 | * @param cls | ||
61 | * Closure. | ||
62 | * @param msg | ||
63 | * Message part, as it arrived from the network. | ||
64 | * @param message_id | ||
65 | * Message counter, monotonically increasing from 1. | ||
66 | * @param flags | ||
67 | * OR'ed GNUNET_PSYC_MessageFlags | ||
68 | * @param fragment_offset | ||
69 | * Multicast message fragment offset. | ||
70 | * @param tmit_flags | ||
71 | * OR'ed GNUNET_PSYC_MasterTransmitFlags | ||
72 | * @param nym | ||
73 | * The sender of the message. | ||
74 | * Can be NULL if the message is not connected to a pseudonym. | ||
75 | * @param method_name | ||
76 | * Original method name from PSYC. | ||
77 | * May be more specific than the registered method name due to | ||
78 | * try-and-slice matching. | ||
79 | */ | ||
80 | typedef void | ||
81 | (*GNUNET_PSYC_MethodCallback) (void *cls, | ||
82 | const struct GNUNET_PSYC_MessageHeader *msg, | ||
83 | const struct GNUNET_PSYC_MessageMethod *meth, | ||
84 | uint64_t message_id, | ||
85 | const char *method_name); | ||
86 | |||
87 | |||
88 | /** | ||
89 | * Function called upon receiving a modifier of a message. | ||
90 | * | ||
91 | * @param cls | ||
92 | * Closure. | ||
93 | * @param message_id | ||
94 | * Message ID this data fragment belongs to. | ||
95 | * @param flags | ||
96 | * OR'ed GNUNET_PSYC_MessageFlags | ||
97 | * @param fragment_offset | ||
98 | * Multicast message fragment offset. | ||
99 | * @param msg | ||
100 | * Message part, as it arrived from the network. | ||
101 | * @param oper | ||
102 | * Operation to perform. | ||
103 | * 0 in case of a modifier continuation. | ||
104 | * @param name | ||
105 | * Name of the modifier. | ||
106 | * NULL in case of a modifier continuation. | ||
107 | * @param value | ||
108 | * Value of the modifier. | ||
109 | * @param value_size | ||
110 | * Size of @value. | ||
111 | */ | ||
112 | typedef void | ||
113 | (*GNUNET_PSYC_ModifierCallback) (void *cls, | ||
114 | const struct GNUNET_PSYC_MessageHeader *msg, | ||
115 | const struct GNUNET_MessageHeader *pmsg, | ||
116 | uint64_t message_id, | ||
117 | enum GNUNET_PSYC_Operator oper, | ||
118 | const char *name, | ||
119 | const void *value, | ||
120 | uint16_t value_size, | ||
121 | uint16_t full_value_size); | ||
122 | |||
123 | |||
124 | /** | ||
125 | * Function called upon receiving a data fragment of a message. | ||
126 | * | ||
127 | * @param cls | ||
128 | * Closure. | ||
129 | * @param msg | ||
130 | * Message part, as it arrived from the network. | ||
131 | * @param message_id | ||
132 | * Message ID this data fragment belongs to. | ||
133 | * @param flags | ||
134 | * OR'ed GNUNET_PSYC_MessageFlags | ||
135 | * @param fragment_offset | ||
136 | * Multicast message fragment offset. | ||
137 | * @param data | ||
138 | * Data stream given to the method. | ||
139 | * @param data_size | ||
140 | * Number of bytes in @a data. | ||
141 | * @param end | ||
142 | * End of message? | ||
143 | * #GNUNET_NO if there are further fragments, | ||
144 | * #GNUNET_YES if this is the last fragment, | ||
145 | * #GNUNET_SYSERR indicates the message was cancelled by the sender. | ||
146 | */ | ||
147 | typedef void | ||
148 | (*GNUNET_PSYC_DataCallback) (void *cls, | ||
149 | const struct GNUNET_PSYC_MessageHeader *msg, | ||
150 | const struct GNUNET_MessageHeader *pmsg, | ||
151 | uint64_t message_id, | ||
152 | const void *data, | ||
153 | uint16_t data_size); | ||
154 | |||
155 | |||
156 | /** | ||
157 | * End of message. | ||
158 | * | ||
159 | * @param cls | ||
160 | * Closure. | ||
161 | * @param msg | ||
162 | * Message part, as it arrived from the network. | ||
163 | * @param message_id | ||
164 | * Message ID this data fragment belongs to. | ||
165 | * @param flags | ||
166 | * OR'ed GNUNET_PSYC_MessageFlags | ||
167 | * @param fragment_offset | ||
168 | * Multicast message fragment offset. | ||
169 | * @param cancelled | ||
170 | * #GNUNET_YES if the message was cancelled, | ||
171 | * #GNUNET_NO if the message is complete. | ||
172 | */ | ||
173 | typedef void | ||
174 | (*GNUNET_PSYC_EndOfMessageCallback) (void *cls, | ||
175 | const struct GNUNET_PSYC_MessageHeader *msg, | ||
176 | const struct GNUNET_MessageHeader *pmsg, | ||
177 | uint64_t message_id, | ||
178 | uint8_t is_cancelled); | ||
179 | |||
180 | |||
181 | /** | ||
182 | * Create a try-and-slice instance. | ||
183 | * | ||
184 | * A slicer processes incoming messages and notifies callbacks about matching | ||
185 | * methods or modifiers encountered. | ||
186 | * | ||
187 | * @return A new try-and-slice construct. | ||
188 | */ | ||
189 | struct GNUNET_PSYC_Slicer * | ||
190 | GNUNET_PSYC_slicer_create (void); | ||
191 | |||
192 | |||
193 | /** | ||
194 | * Add a method to the try-and-slice instance. | ||
195 | * | ||
196 | * The callbacks are called for messages with a matching @a method_name prefix. | ||
197 | * | ||
198 | * @param slicer | ||
199 | * The try-and-slice instance to extend. | ||
200 | * @param method_name | ||
201 | * Name of the given method, use empty string to match all. | ||
202 | * @param method_cb | ||
203 | * Method handler invoked upon a matching message. | ||
204 | * @param modifier_cb | ||
205 | * Modifier handler, invoked after @a method_cb | ||
206 | * for each modifier in the message. | ||
207 | * @param data_cb | ||
208 | * Data handler, invoked after @a modifier_cb for each data fragment. | ||
209 | * @param eom_cb | ||
210 | * Invoked upon reaching the end of a matching message. | ||
211 | * @param cls | ||
212 | * Closure for the callbacks. | ||
213 | */ | ||
214 | void | ||
215 | GNUNET_PSYC_slicer_method_add (struct GNUNET_PSYC_Slicer *slicer, | ||
216 | const char *method_name, | ||
217 | GNUNET_PSYC_MessageCallback msg_cb, | ||
218 | GNUNET_PSYC_MethodCallback method_cb, | ||
219 | GNUNET_PSYC_ModifierCallback modifier_cb, | ||
220 | GNUNET_PSYC_DataCallback data_cb, | ||
221 | GNUNET_PSYC_EndOfMessageCallback eom_cb, | ||
222 | void *cls); | ||
223 | |||
224 | /** | ||
225 | * Remove a registered method from the try-and-slice instance. | ||
226 | * | ||
227 | * Removes one matching handler registered with the given | ||
228 | * @a method_name and callbacks. | ||
229 | * | ||
230 | * @param slicer | ||
231 | * The try-and-slice instance. | ||
232 | * @param method_name | ||
233 | * Name of the method to remove. | ||
234 | * @param method_cb | ||
235 | * Only remove matching method handler, or NULL. | ||
236 | * @param modifier_cb | ||
237 | * Only remove matching modifier handler, or NULL. | ||
238 | * @param data_cb | ||
239 | * Only remove matching data handler, or NULL. | ||
240 | * @param eom_cb | ||
241 | * Only remove matching End of Message handler, or NULL. | ||
242 | * | ||
243 | * @return #GNUNET_OK if a method handler was removed, | ||
244 | * #GNUNET_NO if no handler matched the given method name and callbacks. | ||
245 | */ | ||
246 | int | ||
247 | GNUNET_PSYC_slicer_method_remove (struct GNUNET_PSYC_Slicer *slicer, | ||
248 | const char *method_name, | ||
249 | GNUNET_PSYC_MessageCallback msg_cb, | ||
250 | GNUNET_PSYC_MethodCallback method_cb, | ||
251 | GNUNET_PSYC_ModifierCallback modifier_cb, | ||
252 | GNUNET_PSYC_DataCallback data_cb, | ||
253 | GNUNET_PSYC_EndOfMessageCallback eom_cb); | ||
254 | |||
255 | |||
256 | /** | ||
257 | * Watch a place for changed objects. | ||
258 | * | ||
259 | * @param slicer | ||
260 | * The try-and-slice instance. | ||
261 | * @param object_filter | ||
262 | * Object prefix to match. | ||
263 | * @param modifier_cb | ||
264 | * Function to call when encountering a state modifier. | ||
265 | * @param cls | ||
266 | * Closure for callback. | ||
267 | */ | ||
268 | void | ||
269 | GNUNET_PSYC_slicer_modifier_add (struct GNUNET_PSYC_Slicer *slicer, | ||
270 | const char *object_filter, | ||
271 | GNUNET_PSYC_ModifierCallback modifier_cb, | ||
272 | void *cls); | ||
273 | |||
274 | |||
275 | /** | ||
276 | * Remove a registered modifier from the try-and-slice instance. | ||
277 | * | ||
278 | * Removes one matching handler registered with the given | ||
279 | * @a object_filter and callback. | ||
280 | * | ||
281 | * @param slicer | ||
282 | * The try-and-slice instance. | ||
283 | * @param object_filter | ||
284 | * Object prefix to match. | ||
285 | * @param modifier_cb | ||
286 | * Function to call when encountering a state modifier changes. | ||
287 | */ | ||
288 | int | ||
289 | GNUNET_PSYC_slicer_modifier_remove (struct GNUNET_PSYC_Slicer *slicer, | ||
290 | const char *object_filter, | ||
291 | GNUNET_PSYC_ModifierCallback modifier_cb); | ||
292 | |||
293 | |||
294 | /** | ||
295 | * Process an incoming message and call matching handlers. | ||
296 | * | ||
297 | * @param slicer | ||
298 | * The slicer to use. | ||
299 | * @param msg | ||
300 | * The message as it arrived from the network. | ||
301 | */ | ||
302 | void | ||
303 | GNUNET_PSYC_slicer_message (struct GNUNET_PSYC_Slicer *slicer, | ||
304 | const struct GNUNET_PSYC_MessageHeader *msg); | ||
305 | |||
306 | |||
307 | /** | ||
308 | * Process an incoming message part and call matching handlers. | ||
309 | * | ||
310 | * @param slicer | ||
311 | * The slicer to use. | ||
312 | * @param message_id | ||
313 | * ID of the message. | ||
314 | * @param flags | ||
315 | * Flags for the message. | ||
316 | * @see enum GNUNET_PSYC_MessageFlags | ||
317 | * @param fragment offset | ||
318 | * Fragment offset of the message. | ||
319 | * @param msg | ||
320 | * The message part as it arrived from the network. | ||
321 | */ | ||
322 | void | ||
323 | GNUNET_PSYC_slicer_message_part (struct GNUNET_PSYC_Slicer *slicer, | ||
324 | const struct GNUNET_PSYC_MessageHeader *msg, | ||
325 | const struct GNUNET_MessageHeader *pmsg); | ||
326 | |||
327 | |||
328 | /** | ||
329 | * Remove all registered method handlers. | ||
330 | * | ||
331 | * @param slicer | ||
332 | * Slicer to clear. | ||
333 | */ | ||
334 | void | ||
335 | GNUNET_PSYC_slicer_method_clear (struct GNUNET_PSYC_Slicer *slicer); | ||
336 | |||
337 | |||
338 | /** | ||
339 | * Remove all registered modifier handlers. | ||
340 | * | ||
341 | * @param slicer | ||
342 | * Slicer to clear. | ||
343 | */ | ||
344 | void | ||
345 | GNUNET_PSYC_slicer_modifier_clear (struct GNUNET_PSYC_Slicer *slicer); | ||
346 | |||
347 | |||
348 | /** | ||
349 | * Remove all registered method & modifier handlers. | ||
350 | * | ||
351 | * @param slicer | ||
352 | * Slicer to clear. | ||
353 | */ | ||
354 | void | ||
355 | GNUNET_PSYC_slicer_clear (struct GNUNET_PSYC_Slicer *slicer); | ||
356 | |||
357 | |||
358 | /** | ||
359 | * Destroy a given try-and-slice instance. | ||
360 | * | ||
361 | * @param slicer | ||
362 | * Slicer to destroy | ||
363 | */ | ||
364 | void | ||
365 | GNUNET_PSYC_slicer_destroy (struct GNUNET_PSYC_Slicer *slicer); | ||
366 | |||
367 | |||
368 | #if 0 /* keep Emacsens' auto-indent happy */ | ||
369 | { | ||
370 | #endif | ||
371 | #ifdef __cplusplus | ||
372 | } | ||
373 | #endif | ||
374 | |||
375 | /* ifndef GNUNET_PSYC_SLICER_H */ | ||
376 | #endif | ||
377 | |||
378 | /** @} */ /* end of group */ | ||
diff --git a/src/include/gnunet_psyc_util_lib.h b/src/include/gnunet_psyc_util_lib.h deleted file mode 100644 index 57eec65c3..000000000 --- a/src/include/gnunet_psyc_util_lib.h +++ /dev/null | |||
@@ -1,53 +0,0 @@ | |||
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 | * | ||
24 | * @file | ||
25 | * PSYC utilities: messages, environment, slicer | ||
26 | */ | ||
27 | |||
28 | #ifndef GNUNET_PSYC_UTIL_LIB_H | ||
29 | #define GNUNET_PSYC_UTIL_LIB_H | ||
30 | |||
31 | #ifdef __cplusplus | ||
32 | extern "C" | ||
33 | { | ||
34 | #if 0 /* keep Emacsens' auto-indent happy */ | ||
35 | } | ||
36 | #endif | ||
37 | #endif | ||
38 | |||
39 | |||
40 | #include "gnunet_psyc_env.h" | ||
41 | #include "gnunet_psyc_message.h" | ||
42 | #include "gnunet_psyc_slicer.h" | ||
43 | |||
44 | |||
45 | #if 0 /* keep Emacsens' auto-indent happy */ | ||
46 | { | ||
47 | #endif | ||
48 | #ifdef __cplusplus | ||
49 | } | ||
50 | #endif | ||
51 | |||
52 | /* ifndef GNUNET_PSYC_UTIL_LIB_H */ | ||
53 | #endif | ||
diff --git a/src/include/gnunet_psycstore_plugin.h b/src/include/gnunet_psycstore_plugin.h deleted file mode 100644 index fac549f43..000000000 --- a/src/include/gnunet_psycstore_plugin.h +++ /dev/null | |||
@@ -1,383 +0,0 @@ | |||
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 | * @author Gabor X Toth | ||
23 | * | ||
24 | * @file | ||
25 | * Plugin API for the PSYCstore database backend | ||
26 | * | ||
27 | * @defgroup psycstore-plugin PSYC Store plugin API | ||
28 | * Plugin API for the PSYC Store database backend | ||
29 | * @{ | ||
30 | */ | ||
31 | #ifndef GNUNET_PSYCSTORE_PLUGIN_H | ||
32 | #define GNUNET_PSYCSTORE_PLUGIN_H | ||
33 | |||
34 | #include "gnunet_util_lib.h" | ||
35 | #include "gnunet_psycstore_service.h" | ||
36 | |||
37 | #ifdef __cplusplus | ||
38 | extern "C" | ||
39 | { | ||
40 | #if 0 /* keep Emacsens' auto-indent happy */ | ||
41 | } | ||
42 | #endif | ||
43 | #endif | ||
44 | |||
45 | |||
46 | /** | ||
47 | * Struct returned by the initialization function of the plugin. | ||
48 | */ | ||
49 | struct GNUNET_PSYCSTORE_PluginFunctions | ||
50 | { | ||
51 | |||
52 | /** | ||
53 | * Closure to pass to all plugin functions. | ||
54 | */ | ||
55 | void *cls; | ||
56 | |||
57 | /** | ||
58 | * Store join/leave events for a PSYC channel in order to be able to answer | ||
59 | * membership test queries later. | ||
60 | * | ||
61 | * @see GNUNET_PSYCSTORE_membership_store() | ||
62 | * | ||
63 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
64 | */ | ||
65 | int | ||
66 | (*membership_store) (void *cls, | ||
67 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
68 | const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, | ||
69 | int did_join, | ||
70 | uint64_t announced_at, | ||
71 | uint64_t effective_since, | ||
72 | uint64_t group_generation); | ||
73 | |||
74 | /** | ||
75 | * Test if a member was admitted to the channel at the given message ID. | ||
76 | * | ||
77 | * @see GNUNET_PSYCSTORE_membership_test() | ||
78 | * | ||
79 | * @return #GNUNET_YES if the member was admitted, #GNUNET_NO if not, | ||
80 | * #GNUNET_SYSERR if there was en error. | ||
81 | */ | ||
82 | int | ||
83 | (*membership_test) (void *cls, | ||
84 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
85 | const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, | ||
86 | uint64_t message_id); | ||
87 | |||
88 | /** | ||
89 | * Store a message fragment sent to a channel. | ||
90 | * | ||
91 | * @see GNUNET_PSYCSTORE_fragment_store() | ||
92 | * | ||
93 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
94 | */ | ||
95 | int | ||
96 | (*fragment_store) (void *cls, | ||
97 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
98 | const struct GNUNET_MULTICAST_MessageHeader *message, | ||
99 | uint32_t psycstore_flags); | ||
100 | |||
101 | /** | ||
102 | * Set additional flags for a given message. | ||
103 | * | ||
104 | * They are OR'd with any existing flags set. | ||
105 | * | ||
106 | * @param cls Closure. | ||
107 | * @param channel_key Public key of the channel. | ||
108 | * @param message_id ID of the message. | ||
109 | * @param psycstore_flags OR'd GNUNET_PSYCSTORE_MessageFlags. | ||
110 | * | ||
111 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
112 | */ | ||
113 | int | ||
114 | (*message_add_flags) (void *cls, | ||
115 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
116 | uint64_t message_id, | ||
117 | uint32_t psycstore_flags); | ||
118 | |||
119 | /** | ||
120 | * Retrieve a message fragment range by fragment ID. | ||
121 | * | ||
122 | * @see GNUNET_PSYCSTORE_fragment_get() | ||
123 | * | ||
124 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
125 | */ | ||
126 | int | ||
127 | (*fragment_get) (void *cls, | ||
128 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
129 | uint64_t first_fragment_id, | ||
130 | uint64_t last_fragment_id, | ||
131 | uint64_t *returned_fragments, | ||
132 | GNUNET_PSYCSTORE_FragmentCallback cb, | ||
133 | void *cb_cls); | ||
134 | |||
135 | /** | ||
136 | * Retrieve latest message fragments. | ||
137 | * | ||
138 | * @see GNUNET_PSYCSTORE_fragment_get() | ||
139 | * | ||
140 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
141 | */ | ||
142 | int | ||
143 | (*fragment_get_latest) (void *cls, | ||
144 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
145 | uint64_t fragment_limit, | ||
146 | uint64_t *returned_fragments, | ||
147 | GNUNET_PSYCSTORE_FragmentCallback cb, | ||
148 | void *cb_cls); | ||
149 | |||
150 | /** | ||
151 | * Retrieve all fragments of a message ID range. | ||
152 | * | ||
153 | * @see GNUNET_PSYCSTORE_message_get() | ||
154 | * | ||
155 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
156 | */ | ||
157 | int | ||
158 | (*message_get) (void *cls, | ||
159 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
160 | uint64_t first_fragment_id, | ||
161 | uint64_t last_fragment_id, | ||
162 | uint64_t fragment_limit, | ||
163 | uint64_t *returned_fragments, | ||
164 | GNUNET_PSYCSTORE_FragmentCallback cb, | ||
165 | void *cb_cls); | ||
166 | |||
167 | /** | ||
168 | * Retrieve all fragments of the latest messages. | ||
169 | * | ||
170 | * @see GNUNET_PSYCSTORE_message_get() | ||
171 | * | ||
172 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
173 | */ | ||
174 | int | ||
175 | (*message_get_latest) (void *cls, | ||
176 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
177 | uint64_t fragment_limit, | ||
178 | uint64_t *returned_fragments, | ||
179 | GNUNET_PSYCSTORE_FragmentCallback cb, | ||
180 | void *cb_cls); | ||
181 | |||
182 | /** | ||
183 | * Retrieve a fragment of message specified by its message ID and fragment | ||
184 | * offset. | ||
185 | * | ||
186 | * @see GNUNET_PSYCSTORE_message_get_fragment() | ||
187 | * | ||
188 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
189 | */ | ||
190 | int | ||
191 | (*message_get_fragment) (void *cls, | ||
192 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
193 | uint64_t message_id, | ||
194 | uint64_t fragment_offset, | ||
195 | GNUNET_PSYCSTORE_FragmentCallback cb, | ||
196 | void *cb_cls); | ||
197 | |||
198 | /** | ||
199 | * Retrieve the max. values of message counters for a channel. | ||
200 | * | ||
201 | * @see GNUNET_PSYCSTORE_counters_get() | ||
202 | * | ||
203 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
204 | */ | ||
205 | int | ||
206 | (*counters_message_get) (void *cls, | ||
207 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
208 | uint64_t *max_fragment_id, | ||
209 | uint64_t *max_message_id, | ||
210 | uint64_t *max_group_generation); | ||
211 | |||
212 | /** | ||
213 | * Retrieve the max. values of state counters for a channel. | ||
214 | * | ||
215 | * @see GNUNET_PSYCSTORE_counters_get() | ||
216 | * | ||
217 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
218 | */ | ||
219 | int | ||
220 | (*counters_state_get) (void *cls, | ||
221 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
222 | uint64_t *max_state_message_id); | ||
223 | |||
224 | |||
225 | /** | ||
226 | * Begin modifying current state. | ||
227 | * | ||
228 | * @see GNUNET_PSYCSTORE_state_modify() | ||
229 | * | ||
230 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
231 | */ | ||
232 | int | ||
233 | (*state_modify_begin) (void *cls, | ||
234 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
235 | uint64_t message_id, uint64_t state_delta); | ||
236 | |||
237 | /** | ||
238 | * Set the current value of a state variable. | ||
239 | * | ||
240 | * The state modification process is started with state_modify_begin(), | ||
241 | * which is followed by one or more calls to this function, | ||
242 | * and finished with state_modify_end(). | ||
243 | * | ||
244 | * @see GNUNET_PSYCSTORE_state_modify() | ||
245 | * | ||
246 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
247 | */ | ||
248 | int | ||
249 | (*state_modify_op) (void *cls, | ||
250 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
251 | enum GNUNET_PSYC_Operator op, | ||
252 | const char *name, const void *value, size_t value_size); | ||
253 | |||
254 | |||
255 | /** | ||
256 | * End modifying current state. | ||
257 | * | ||
258 | * @see GNUNET_PSYCSTORE_state_modify() | ||
259 | * | ||
260 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
261 | */ | ||
262 | int | ||
263 | (*state_modify_end) (void *cls, | ||
264 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
265 | uint64_t message_id); | ||
266 | |||
267 | |||
268 | /** | ||
269 | * Begin synchronizing state. | ||
270 | * | ||
271 | * @see GNUNET_PSYCSTORE_state_sync() | ||
272 | * | ||
273 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
274 | */ | ||
275 | int | ||
276 | (*state_sync_begin) (void *cls, | ||
277 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key); | ||
278 | |||
279 | /** | ||
280 | * Assign value of a state variable while synchronizing state. | ||
281 | * | ||
282 | * The state synchronization process is started with state_sync_begin(), | ||
283 | * which is followed by one or more calls to this function, | ||
284 | * and finished using state_sync_end(). | ||
285 | * | ||
286 | * @see GNUNET_PSYCSTORE_state_sync() | ||
287 | * | ||
288 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
289 | */ | ||
290 | int | ||
291 | (*state_sync_assign) (void *cls, | ||
292 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
293 | const char *name, const void *value, size_t value_size); | ||
294 | |||
295 | |||
296 | /** | ||
297 | * End synchronizing state. | ||
298 | * | ||
299 | * @see GNUNET_PSYCSTORE_state_sync() | ||
300 | * | ||
301 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
302 | */ | ||
303 | int | ||
304 | (*state_sync_end) (void *cls, | ||
305 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
306 | uint64_t max_state_message_id, | ||
307 | uint64_t state_hash_message_id); | ||
308 | |||
309 | |||
310 | /** | ||
311 | * Reset the state of a channel. | ||
312 | * | ||
313 | * Delete all state variables stored for the given channel. | ||
314 | * | ||
315 | * @see GNUNET_PSYCSTORE_state_reset() | ||
316 | * | ||
317 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
318 | */ | ||
319 | int | ||
320 | (*state_reset) (void *cls, | ||
321 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key); | ||
322 | |||
323 | /** | ||
324 | * Update signed state values from the current ones. | ||
325 | * | ||
326 | * Sets value_signed = value_current for each variable for the given channel. | ||
327 | */ | ||
328 | int | ||
329 | (*state_update_signed) (void *cls, | ||
330 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key); | ||
331 | |||
332 | |||
333 | /** | ||
334 | * Retrieve a state variable by name (exact match). | ||
335 | * | ||
336 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
337 | */ | ||
338 | int | ||
339 | (*state_get) (void *cls, | ||
340 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
341 | const char *name, | ||
342 | GNUNET_PSYCSTORE_StateCallback cb, | ||
343 | void *cb_cls); | ||
344 | |||
345 | /** | ||
346 | * Retrieve all state variables for a channel with the given prefix. | ||
347 | * | ||
348 | * @see GNUNET_PSYCSTORE_state_get_prefix() | ||
349 | * | ||
350 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
351 | */ | ||
352 | int | ||
353 | (*state_get_prefix) (void *cls, | ||
354 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
355 | const char *name, | ||
356 | GNUNET_PSYCSTORE_StateCallback cb, | ||
357 | void *cb_cls); | ||
358 | |||
359 | |||
360 | /** | ||
361 | * Retrieve all signed state variables for a channel. | ||
362 | * | ||
363 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
364 | */ | ||
365 | int | ||
366 | (*state_get_signed) (void *cls, | ||
367 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
368 | GNUNET_PSYCSTORE_StateCallback cb, | ||
369 | void *cb_cls); | ||
370 | |||
371 | }; | ||
372 | |||
373 | |||
374 | #if 0 /* keep Emacsens' auto-indent happy */ | ||
375 | { | ||
376 | #endif | ||
377 | #ifdef __cplusplus | ||
378 | } | ||
379 | #endif | ||
380 | |||
381 | #endif | ||
382 | |||
383 | /** @} */ /* end of group */ | ||
diff --git a/src/include/gnunet_psycstore_service.h b/src/include/gnunet_psycstore_service.h deleted file mode 100644 index 92516f447..000000000 --- a/src/include/gnunet_psycstore_service.h +++ /dev/null | |||
@@ -1,701 +0,0 @@ | |||
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 | * @author Gabor X Toth | ||
23 | * @author Christian Grothoff | ||
24 | * | ||
25 | * @file | ||
26 | * PSYCstore service; implements persistent storage for the PSYC service | ||
27 | * | ||
28 | * @defgroup psycstore PSYC Store service | ||
29 | * Persistent storage for the PSYC service. | ||
30 | * @{ | ||
31 | */ | ||
32 | #ifndef GNUNET_PSYCSTORE_SERVICE_H | ||
33 | #define GNUNET_PSYCSTORE_SERVICE_H | ||
34 | |||
35 | #ifdef __cplusplus | ||
36 | extern "C" | ||
37 | { | ||
38 | #if 0 /* keep Emacsens' auto-indent happy */ | ||
39 | } | ||
40 | #endif | ||
41 | #endif | ||
42 | |||
43 | #include "gnunet_util_lib.h" | ||
44 | #include "gnunet_psyc_util_lib.h" | ||
45 | #include "gnunet_multicast_service.h" | ||
46 | #include "gnunet_psyc_service.h" | ||
47 | |||
48 | /** | ||
49 | * Version number of GNUnet PSYCstore API. | ||
50 | */ | ||
51 | #define GNUNET_PSYCSTORE_VERSION 0x00000000 | ||
52 | |||
53 | /** | ||
54 | * Membership test failed. | ||
55 | */ | ||
56 | #define GNUNET_PSYCSTORE_MEMBERSHIP_TEST_FAILED -2 | ||
57 | |||
58 | /** | ||
59 | * Flags for stored messages. | ||
60 | */ | ||
61 | enum GNUNET_PSYCSTORE_MessageFlags | ||
62 | { | ||
63 | /** | ||
64 | * The message contains state modifiers. | ||
65 | */ | ||
66 | GNUNET_PSYCSTORE_MESSAGE_STATE = 1 << 0, | ||
67 | |||
68 | /** | ||
69 | * The state modifiers have been applied to the state store. | ||
70 | */ | ||
71 | GNUNET_PSYCSTORE_MESSAGE_STATE_APPLIED = 1 << 1, | ||
72 | |||
73 | /** | ||
74 | * The message contains a state hash. | ||
75 | */ | ||
76 | GNUNET_PSYCSTORE_MESSAGE_STATE_HASH = 1 << 2 | ||
77 | }; | ||
78 | |||
79 | |||
80 | /** | ||
81 | * Handle for a PSYCstore | ||
82 | */ | ||
83 | struct GNUNET_PSYCSTORE_Handle; | ||
84 | |||
85 | |||
86 | /** | ||
87 | * Connect to the PSYCstore service. | ||
88 | * | ||
89 | * @param cfg Configuration to use. | ||
90 | * | ||
91 | * @return Handle for the connecton. | ||
92 | */ | ||
93 | struct GNUNET_PSYCSTORE_Handle * | ||
94 | GNUNET_PSYCSTORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg); | ||
95 | |||
96 | |||
97 | /** | ||
98 | * Disconnect from the PSYCstore service. | ||
99 | * | ||
100 | * @param h Handle for the connection. | ||
101 | */ | ||
102 | void | ||
103 | GNUNET_PSYCSTORE_disconnect (struct GNUNET_PSYCSTORE_Handle *h); | ||
104 | |||
105 | |||
106 | /** | ||
107 | * Handle for an operation on the PSYCSTORE (useful to cancel the operation). | ||
108 | */ | ||
109 | struct GNUNET_PSYCSTORE_OperationHandle; | ||
110 | |||
111 | |||
112 | /** | ||
113 | * Function called with the result of an asynchronous operation. | ||
114 | * | ||
115 | * @param cls | ||
116 | * Closure. | ||
117 | * @param result | ||
118 | * Result of the operation. | ||
119 | * @param err_msg | ||
120 | * Error message, or NULL if there's no error. | ||
121 | * @param err_msg_size | ||
122 | * Size of @a err_msg | ||
123 | */ | ||
124 | typedef void | ||
125 | (*GNUNET_PSYCSTORE_ResultCallback) (void *cls, | ||
126 | int64_t result, | ||
127 | const char *err_msg, | ||
128 | uint16_t err_msg_size); | ||
129 | |||
130 | |||
131 | /** | ||
132 | * Store join/leave events for a PSYC channel in order to be able to answer | ||
133 | * membership test queries later. | ||
134 | * | ||
135 | * @param h | ||
136 | * Handle for the PSYCstore. | ||
137 | * @param channel_key | ||
138 | * The channel where the event happened. | ||
139 | * @param slave_key | ||
140 | * Public key of joining/leaving slave. | ||
141 | * @param did_join | ||
142 | * #GNUNET_YES on join, #GNUNET_NO on part. | ||
143 | * @param announced_at | ||
144 | * ID of the message that announced the membership change. | ||
145 | * @param effective_since | ||
146 | * Message ID this membership change is in effect since. | ||
147 | * For joins it is <= announced_at, for parts it is always 0. | ||
148 | * @param group_generation | ||
149 | * In case of a part, the last group generation the slave has access to. | ||
150 | * It has relevance when a larger message have fragments with different | ||
151 | * group generations. | ||
152 | * @param result_cb | ||
153 | * Callback to call with the result of the storage operation. | ||
154 | * @param cls | ||
155 | * Closure for the callback. | ||
156 | * | ||
157 | * @return Operation handle that can be used to cancel the operation. | ||
158 | */ | ||
159 | struct GNUNET_PSYCSTORE_OperationHandle * | ||
160 | GNUNET_PSYCSTORE_membership_store (struct GNUNET_PSYCSTORE_Handle *h, | ||
161 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
162 | const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, | ||
163 | int did_join, | ||
164 | uint64_t announced_at, | ||
165 | uint64_t effective_since, | ||
166 | uint64_t group_generation, | ||
167 | GNUNET_PSYCSTORE_ResultCallback result_cb, | ||
168 | void *cls); | ||
169 | |||
170 | |||
171 | /** | ||
172 | * Test if a member was admitted to the channel at the given message ID. | ||
173 | * | ||
174 | * This is useful when relaying and replaying messages to check if a particular | ||
175 | * slave has access to the message fragment with a given group generation. It | ||
176 | * is also used when handling join requests to determine whether the slave is | ||
177 | * currently admitted to the channel. | ||
178 | * | ||
179 | * @param h | ||
180 | * Handle for the PSYCstore. | ||
181 | * @param channel_key | ||
182 | * The channel we are interested in. | ||
183 | * @param slave_key | ||
184 | * Public key of slave whose membership to check. | ||
185 | * @param message_id | ||
186 | * Message ID for which to do the membership test. | ||
187 | * @param group_generation | ||
188 | * Group generation of the fragment of the message to test. | ||
189 | * It has relevance if the message consists of multiple fragments with | ||
190 | * different group generations. | ||
191 | * @param result_cb | ||
192 | * Callback to call with the test result. | ||
193 | * @param cls | ||
194 | * Closure for the callback. | ||
195 | * | ||
196 | * @return Operation handle that can be used to cancel the operation. | ||
197 | */ | ||
198 | struct GNUNET_PSYCSTORE_OperationHandle * | ||
199 | GNUNET_PSYCSTORE_membership_test (struct GNUNET_PSYCSTORE_Handle *h, | ||
200 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
201 | const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, | ||
202 | uint64_t message_id, | ||
203 | uint64_t group_generation, | ||
204 | GNUNET_PSYCSTORE_ResultCallback result_cb, | ||
205 | void *cls); | ||
206 | |||
207 | |||
208 | /** | ||
209 | * Store a message fragment sent to a channel. | ||
210 | * | ||
211 | * @param h Handle for the PSYCstore. | ||
212 | * @param channel_key The channel the message belongs to. | ||
213 | * @param msg Message to store. | ||
214 | * @param psycstore_flags Flags indicating whether the PSYC message contains | ||
215 | * state modifiers. | ||
216 | * @param result_cb Callback to call with the result of the operation. | ||
217 | * @param cls Closure for the callback. | ||
218 | * | ||
219 | * @return Handle that can be used to cancel the operation. | ||
220 | */ | ||
221 | struct GNUNET_PSYCSTORE_OperationHandle * | ||
222 | GNUNET_PSYCSTORE_fragment_store (struct GNUNET_PSYCSTORE_Handle *h, | ||
223 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
224 | const struct GNUNET_MULTICAST_MessageHeader *msg, | ||
225 | enum GNUNET_PSYCSTORE_MessageFlags psycstore_flags, | ||
226 | GNUNET_PSYCSTORE_ResultCallback result_cb, | ||
227 | void *cls); | ||
228 | |||
229 | |||
230 | /** | ||
231 | * Function called with one message fragment, as the result of a | ||
232 | * GNUNET_PSYCSTORE_fragment_get() or GNUNET_PSYCSTORE_message_get() call. | ||
233 | * | ||
234 | * @param cls Closure. | ||
235 | * @param message The retrieved message fragment. A NULL value indicates that | ||
236 | * there are no more results to be returned. | ||
237 | * @param psycstore_flags Flags stored with the message. | ||
238 | * | ||
239 | * @return #GNUNET_NO to stop calling this callback with further fragments, | ||
240 | * #GNUNET_YES to continue. | ||
241 | */ | ||
242 | typedef int | ||
243 | (*GNUNET_PSYCSTORE_FragmentCallback) (void *cls, | ||
244 | struct GNUNET_MULTICAST_MessageHeader *message, | ||
245 | enum GNUNET_PSYCSTORE_MessageFlags psycstore_flags); | ||
246 | |||
247 | |||
248 | /** | ||
249 | * Retrieve message fragments by fragment ID range. | ||
250 | * | ||
251 | * @param h | ||
252 | * Handle for the PSYCstore. | ||
253 | * @param channel_key | ||
254 | * The channel we are interested in. | ||
255 | * @param slave_key | ||
256 | * The slave requesting the fragment. If not NULL, a membership test is | ||
257 | * performed first and the fragment is only returned if the slave has | ||
258 | * access to it. | ||
259 | * @param first_fragment_id | ||
260 | * First fragment ID to retrieve. | ||
261 | * Use 0 to get the latest message fragment. | ||
262 | * @param last_fragment_id | ||
263 | * Last consecutive fragment ID to retrieve. | ||
264 | * Use 0 to get the latest message fragment. | ||
265 | * @param fragment_cb | ||
266 | * Callback to call with the retrieved fragments. | ||
267 | * @param result_cb | ||
268 | * Callback to call with the result of the operation. | ||
269 | * @param cls | ||
270 | * Closure for the callbacks. | ||
271 | * | ||
272 | * @return Handle that can be used to cancel the operation. | ||
273 | */ | ||
274 | struct GNUNET_PSYCSTORE_OperationHandle * | ||
275 | GNUNET_PSYCSTORE_fragment_get (struct GNUNET_PSYCSTORE_Handle *h, | ||
276 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
277 | const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, | ||
278 | uint64_t first_message_id, | ||
279 | uint64_t last_message_id, | ||
280 | GNUNET_PSYCSTORE_FragmentCallback fragment_cb, | ||
281 | GNUNET_PSYCSTORE_ResultCallback result_cb, | ||
282 | void *cls); | ||
283 | |||
284 | |||
285 | /** | ||
286 | * Retrieve latest message fragments. | ||
287 | * | ||
288 | * @param h | ||
289 | * Handle for the PSYCstore. | ||
290 | * @param channel_key | ||
291 | * The channel we are interested in. | ||
292 | * @param slave_key | ||
293 | * The slave requesting the fragment. If not NULL, a membership test is | ||
294 | * performed first and the fragment is only returned if the slave has | ||
295 | * access to it. | ||
296 | * @param first_fragment_id | ||
297 | * First fragment ID to retrieve. | ||
298 | * Use 0 to get the latest message fragment. | ||
299 | * @param last_fragment_id | ||
300 | * Last consecutive fragment ID to retrieve. | ||
301 | * Use 0 to get the latest message fragment. | ||
302 | * @param fragment_limit | ||
303 | * Maximum number of fragments to retrieve. | ||
304 | * @param fragment_cb | ||
305 | * Callback to call with the retrieved fragments. | ||
306 | * @param result_cb | ||
307 | * Callback to call with the result of the operation. | ||
308 | * @param cls | ||
309 | * Closure for the callbacks. | ||
310 | * | ||
311 | * @return Handle that can be used to cancel the operation. | ||
312 | */ | ||
313 | struct GNUNET_PSYCSTORE_OperationHandle * | ||
314 | GNUNET_PSYCSTORE_fragment_get_latest (struct GNUNET_PSYCSTORE_Handle *h, | ||
315 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
316 | const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, | ||
317 | uint64_t fragment_limit, | ||
318 | GNUNET_PSYCSTORE_FragmentCallback fragment_cb, | ||
319 | GNUNET_PSYCSTORE_ResultCallback result_cb, | ||
320 | void *cls); | ||
321 | |||
322 | |||
323 | /** | ||
324 | * Retrieve all fragments of messages in a message ID range. | ||
325 | * | ||
326 | * @param h | ||
327 | * Handle for the PSYCstore. | ||
328 | * @param channel_key | ||
329 | * The channel we are interested in. | ||
330 | * @param slave_key | ||
331 | * The slave requesting the message. | ||
332 | * If not NULL, a membership test is performed first | ||
333 | * and the message is only returned if the slave has access to it. | ||
334 | * @param first_message_id | ||
335 | * First message ID to retrieve. | ||
336 | * @param last_message_id | ||
337 | * Last consecutive message ID to retrieve. | ||
338 | * @param fragment_limit | ||
339 | * Maximum number of fragments to retrieve. | ||
340 | * @param method_prefix | ||
341 | * Retrieve only messages with a matching method prefix. | ||
342 | * @param fragment_cb | ||
343 | * Callback to call with the retrieved fragments. | ||
344 | * @param result_cb | ||
345 | * Callback to call with the result of the operation. | ||
346 | * @param cls | ||
347 | * Closure for the callbacks. | ||
348 | * | ||
349 | * @return Handle that can be used to cancel the operation. | ||
350 | */ | ||
351 | struct GNUNET_PSYCSTORE_OperationHandle * | ||
352 | GNUNET_PSYCSTORE_message_get (struct GNUNET_PSYCSTORE_Handle *h, | ||
353 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
354 | const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, | ||
355 | uint64_t first_message_id, | ||
356 | uint64_t last_message_id, | ||
357 | uint64_t fragment_limit, | ||
358 | const char *method_prefix, | ||
359 | GNUNET_PSYCSTORE_FragmentCallback fragment_cb, | ||
360 | GNUNET_PSYCSTORE_ResultCallback result_cb, | ||
361 | void *cls); | ||
362 | |||
363 | |||
364 | /** | ||
365 | * Retrieve all fragments of the latest messages. | ||
366 | * | ||
367 | * @param h | ||
368 | * Handle for the PSYCstore. | ||
369 | * @param channel_key | ||
370 | * The channel we are interested in. | ||
371 | * @param slave_key | ||
372 | * The slave requesting the message. | ||
373 | * If not NULL, a membership test is performed first | ||
374 | * and the message is only returned if the slave has access to it. | ||
375 | * @param message_limit | ||
376 | * Maximum number of messages to retrieve. | ||
377 | * @param method_prefix | ||
378 | * Retrieve only messages with a matching method prefix. | ||
379 | * @param fragment_cb | ||
380 | * Callback to call with the retrieved fragments. | ||
381 | * @param result_cb | ||
382 | * Callback to call with the result of the operation. | ||
383 | * @param cls | ||
384 | * Closure for the callbacks. | ||
385 | * | ||
386 | * @return Handle that can be used to cancel the operation. | ||
387 | */ | ||
388 | struct GNUNET_PSYCSTORE_OperationHandle * | ||
389 | GNUNET_PSYCSTORE_message_get_latest (struct GNUNET_PSYCSTORE_Handle *h, | ||
390 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
391 | const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, | ||
392 | uint64_t message_limit, | ||
393 | const char *method_prefix, | ||
394 | GNUNET_PSYCSTORE_FragmentCallback fragment_cb, | ||
395 | GNUNET_PSYCSTORE_ResultCallback result_cb, | ||
396 | void *cls); | ||
397 | |||
398 | |||
399 | /** | ||
400 | * Retrieve a fragment of message specified by its message ID and fragment | ||
401 | * offset. | ||
402 | * | ||
403 | * @param h | ||
404 | * Handle for the PSYCstore. | ||
405 | * @param channel_key | ||
406 | * The channel we are interested in. | ||
407 | * @param slave_key | ||
408 | * The slave requesting the message fragment. If not NULL, a membership | ||
409 | * test is performed first and the message fragment is only returned | ||
410 | * if the slave has access to it. | ||
411 | * @param message_id | ||
412 | * Message ID to retrieve. Use 0 to get the latest message. | ||
413 | * @param fragment_offset | ||
414 | * Offset of the fragment to retrieve. | ||
415 | * @param fragment_cb | ||
416 | * Callback to call with the retrieved fragments. | ||
417 | * @param result_cb | ||
418 | * Callback to call with the result of the operation. | ||
419 | * @param cls | ||
420 | * Closure for the callbacks. | ||
421 | * | ||
422 | * @return Handle that can be used to cancel the operation. | ||
423 | */ | ||
424 | struct GNUNET_PSYCSTORE_OperationHandle * | ||
425 | GNUNET_PSYCSTORE_message_get_fragment (struct GNUNET_PSYCSTORE_Handle *h, | ||
426 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
427 | const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, | ||
428 | uint64_t message_id, | ||
429 | uint64_t fragment_offset, | ||
430 | GNUNET_PSYCSTORE_FragmentCallback fragment_cb, | ||
431 | GNUNET_PSYCSTORE_ResultCallback result_cb, | ||
432 | void *cls); | ||
433 | |||
434 | |||
435 | /** | ||
436 | * Callback used to return the latest value of counters for the channel master. | ||
437 | * | ||
438 | * @see GNUNET_PSYCSTORE_counters_get() | ||
439 | * | ||
440 | * @param cls Closure. | ||
441 | * @param result_code | ||
442 | * Status code for the operation: | ||
443 | * #GNUNET_OK: success, counter values are returned. | ||
444 | * #GNUNET_NO: no message has been sent to the channel yet. | ||
445 | * #GNUNET_SYSERR: an error occurred. | ||
446 | * @param max_fragment_id | ||
447 | * Latest message fragment ID, used by multicast. | ||
448 | * @param max_message_id | ||
449 | * Latest message ID, used by PSYC. | ||
450 | * @param max_group_generation | ||
451 | * Latest group generation, used by PSYC. | ||
452 | * @param max_state_message_id | ||
453 | * Latest message ID containing state modifiers that | ||
454 | * was applied to the state store. Used for the state sync process. | ||
455 | */ | ||
456 | typedef void | ||
457 | (*GNUNET_PSYCSTORE_CountersCallback) (void *cls, | ||
458 | int result_code, | ||
459 | uint64_t max_fragment_id, | ||
460 | uint64_t max_message_id, | ||
461 | uint64_t max_group_generation, | ||
462 | uint64_t max_state_message_id); | ||
463 | |||
464 | |||
465 | /** | ||
466 | * Retrieve latest values of counters for a channel. | ||
467 | * | ||
468 | * The current value of counters are needed | ||
469 | * - when a channel master is restarted, so that it can continue incrementing | ||
470 | * the counters from their last value. | ||
471 | * - when a channel slave rejoins and starts the state synchronization process. | ||
472 | * | ||
473 | * @param h | ||
474 | * Handle for the PSYCstore. | ||
475 | * @param channel_key | ||
476 | * Public key that identifies the channel. | ||
477 | * @param counters_cb | ||
478 | * Callback to call with the result. | ||
479 | * @param cls | ||
480 | * Closure for the @a ccb callback. | ||
481 | * | ||
482 | * @return Handle that can be used to cancel the operation. | ||
483 | */ | ||
484 | struct GNUNET_PSYCSTORE_OperationHandle * | ||
485 | GNUNET_PSYCSTORE_counters_get (struct GNUNET_PSYCSTORE_Handle *h, | ||
486 | struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
487 | GNUNET_PSYCSTORE_CountersCallback counters_cb, | ||
488 | void *cls); | ||
489 | |||
490 | |||
491 | /** | ||
492 | * Apply modifiers of a message to the current channel state. | ||
493 | * | ||
494 | * An error is returned if there are missing messages containing state | ||
495 | * operations before the current one. | ||
496 | * | ||
497 | * @param h | ||
498 | * Handle for the PSYCstore. | ||
499 | * @param channel_key | ||
500 | * The channel we are interested in. | ||
501 | * @param message_id | ||
502 | * ID of the message that contains the @a modifiers. | ||
503 | * @param state_delta | ||
504 | * Value of the @e state_delta PSYC header variable of the message. | ||
505 | * @param result_cb | ||
506 | * Callback to call with the result of the operation. | ||
507 | * @param cls | ||
508 | * Closure for the @a result_cb callback. | ||
509 | * | ||
510 | * @return Handle that can be used to cancel the operation. | ||
511 | */ | ||
512 | struct GNUNET_PSYCSTORE_OperationHandle * | ||
513 | GNUNET_PSYCSTORE_state_modify (struct GNUNET_PSYCSTORE_Handle *h, | ||
514 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
515 | uint64_t message_id, | ||
516 | uint64_t state_delta, | ||
517 | GNUNET_PSYCSTORE_ResultCallback result_cb, | ||
518 | void *cls); | ||
519 | |||
520 | |||
521 | /** | ||
522 | * Store synchronized state. | ||
523 | * | ||
524 | * @param h | ||
525 | * Handle for the PSYCstore. | ||
526 | * @param channel_key | ||
527 | * The channel we are interested in. | ||
528 | * @param max_state_message_id | ||
529 | * ID of the last stateful message before @a state_hash_message_id. | ||
530 | * @param state_hash_message_id | ||
531 | * ID of the message that contains the state_hash PSYC header variable. | ||
532 | * @param modifier_count | ||
533 | * Number of elements in the @a modifiers array. | ||
534 | * @param modifiers | ||
535 | * Full state to store. | ||
536 | * @param result_cb | ||
537 | * Callback to call with the result of the operation. | ||
538 | * @param cls | ||
539 | * Closure for the callback. | ||
540 | * | ||
541 | * @return Handle that can be used to cancel the operation. | ||
542 | */ | ||
543 | struct GNUNET_PSYCSTORE_OperationHandle * | ||
544 | GNUNET_PSYCSTORE_state_sync (struct GNUNET_PSYCSTORE_Handle *h, | ||
545 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
546 | uint64_t max_state_message_id, | ||
547 | uint64_t state_hash_message_id, | ||
548 | size_t modifier_count, | ||
549 | const struct GNUNET_PSYC_Modifier *modifiers, | ||
550 | GNUNET_PSYCSTORE_ResultCallback result_cb, | ||
551 | void *cls); | ||
552 | |||
553 | |||
554 | |||
555 | /** | ||
556 | * Reset the state of a channel. | ||
557 | * | ||
558 | * Delete all state variables stored for the given channel. | ||
559 | * | ||
560 | * @param h | ||
561 | * Handle for the PSYCstore. | ||
562 | * @param channel_key | ||
563 | * The channel we are interested in. | ||
564 | * @param result_cb | ||
565 | * Callback to call with the result of the operation. | ||
566 | * @param cls | ||
567 | * Closure for the callback. | ||
568 | * | ||
569 | * @return Handle that can be used to cancel the operation. | ||
570 | */ | ||
571 | struct GNUNET_PSYCSTORE_OperationHandle * | ||
572 | GNUNET_PSYCSTORE_state_reset (struct GNUNET_PSYCSTORE_Handle *h, | ||
573 | const struct GNUNET_CRYPTO_EddsaPublicKey | ||
574 | *channel_key, | ||
575 | GNUNET_PSYCSTORE_ResultCallback result_cb, | ||
576 | void *cls); | ||
577 | |||
578 | |||
579 | /** | ||
580 | * Update signed values of state variables in the state store. | ||
581 | * | ||
582 | * @param h | ||
583 | * Handle for the PSYCstore. | ||
584 | * @param channel_key | ||
585 | * The channel we are interested in. | ||
586 | * @param message_id | ||
587 | * Message ID that contained the state @a hash. | ||
588 | * @param hash | ||
589 | * Hash of the serialized full state. | ||
590 | * @param result_cb | ||
591 | * Callback to call with the result of the operation. | ||
592 | * @param cls | ||
593 | * Closure for the callback. | ||
594 | * | ||
595 | */ | ||
596 | struct GNUNET_PSYCSTORE_OperationHandle * | ||
597 | GNUNET_PSYCSTORE_state_hash_update (struct GNUNET_PSYCSTORE_Handle *h, | ||
598 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
599 | uint64_t message_id, | ||
600 | const struct GNUNET_HashCode *hash, | ||
601 | GNUNET_PSYCSTORE_ResultCallback result_cb, | ||
602 | void *cls); | ||
603 | |||
604 | |||
605 | /** | ||
606 | * Function called with the value of a state variable. | ||
607 | * | ||
608 | * @param cls | ||
609 | * Closure. | ||
610 | * @param name | ||
611 | * Name of the state variable. A NULL value indicates that there are no more | ||
612 | * state variables to be returned. | ||
613 | * @param value | ||
614 | * Value of the state variable. | ||
615 | * @param value_size | ||
616 | * Number of bytes in @a value. | ||
617 | * | ||
618 | * @return #GNUNET_NO to stop calling this callback with further variables, | ||
619 | * #GNUNET_YES to continue. | ||
620 | */; | ||
621 | typedef int | ||
622 | (*GNUNET_PSYCSTORE_StateCallback) (void *cls, const char *name, | ||
623 | const void *value, uint32_t value_size); | ||
624 | |||
625 | |||
626 | /** | ||
627 | * Retrieve the best matching state variable. | ||
628 | * | ||
629 | * @param h | ||
630 | * Handle for the PSYCstore. | ||
631 | * @param channel_key | ||
632 | * The channel we are interested in. | ||
633 | * @param name | ||
634 | * Name of variable to match, the returned variable might be less specific. | ||
635 | * @param state_cb | ||
636 | * Callback to return the matching state variable. | ||
637 | * @param result_cb | ||
638 | * Callback to call with the result of the operation. | ||
639 | * @param cls | ||
640 | * Closure for the callbacks. | ||
641 | * | ||
642 | * @return Handle that can be used to cancel the operation. | ||
643 | */ | ||
644 | struct GNUNET_PSYCSTORE_OperationHandle * | ||
645 | GNUNET_PSYCSTORE_state_get (struct GNUNET_PSYCSTORE_Handle *h, | ||
646 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
647 | const char *name, | ||
648 | GNUNET_PSYCSTORE_StateCallback state_cb, | ||
649 | GNUNET_PSYCSTORE_ResultCallback result_cb, | ||
650 | void *cls); | ||
651 | |||
652 | |||
653 | /** | ||
654 | * Retrieve all state variables for a channel with the given prefix. | ||
655 | * | ||
656 | * @param h | ||
657 | * Handle for the PSYCstore. | ||
658 | * @param channel_key | ||
659 | * The channel we are interested in. | ||
660 | * @param name_prefix | ||
661 | * Prefix of state variable names to match. | ||
662 | * @param state_cb | ||
663 | * Callback to return matching state variables. | ||
664 | * @param result_cb | ||
665 | * Callback to call with the result of the operation. | ||
666 | * @param cls | ||
667 | * Closure for the callbacks. | ||
668 | * | ||
669 | * @return Handle that can be used to cancel the operation. | ||
670 | */ | ||
671 | struct GNUNET_PSYCSTORE_OperationHandle * | ||
672 | GNUNET_PSYCSTORE_state_get_prefix (struct GNUNET_PSYCSTORE_Handle *h, | ||
673 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
674 | const char *name_prefix, | ||
675 | GNUNET_PSYCSTORE_StateCallback state_cb, | ||
676 | GNUNET_PSYCSTORE_ResultCallback result_cb, | ||
677 | void *cls); | ||
678 | |||
679 | |||
680 | /** | ||
681 | * Cancel an operation. | ||
682 | * | ||
683 | * @param op Handle for the operation to cancel. | ||
684 | */ | ||
685 | int | ||
686 | GNUNET_PSYCSTORE_operation_cancel (struct GNUNET_PSYCSTORE_OperationHandle *op); | ||
687 | |||
688 | |||
689 | |||
690 | |||
691 | #if 0 /* keep Emacsens' auto-indent happy */ | ||
692 | { | ||
693 | #endif | ||
694 | #ifdef __cplusplus | ||
695 | } | ||
696 | #endif | ||
697 | |||
698 | /* ifndef GNUNET_PSYCSTORE_SERVICE_H */ | ||
699 | #endif | ||
700 | |||
701 | /** @} */ /* end of group */ | ||
diff --git a/src/include/gnunet_social_service.h b/src/include/gnunet_social_service.h deleted file mode 100644 index 7faa336d6..000000000 --- a/src/include/gnunet_social_service.h +++ /dev/null | |||
@@ -1,1344 +0,0 @@ | |||
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 | * @author Gabor X Toth | ||
23 | * @author Christian Grothoff | ||
24 | * | ||
25 | * @file | ||
26 | * Social service; implements social interactions through the PSYC service. | ||
27 | */ | ||
28 | |||
29 | /** @defgroup social Social service | ||
30 | Social interactions through the PSYC service. | ||
31 | |||
32 | # Overview | ||
33 | |||
34 | The social service provides an API for social interactions based on a one-to-many messaging model. | ||
35 | It manages subscriptions of applications to places, provides messaging functionality in places, | ||
36 | allows access to the local message history and manages the GNS zone of _egos_ (user identities). | ||
37 | |||
38 | The service stores private and public keys of subscribed places, as well as files received in subscribed places. | ||
39 | |||
40 | # Concepts and terminology | ||
41 | |||
42 | ## Ego, Nym | ||
43 | |||
44 | An _ego_ is an identity of a user, a private-public key pair. | ||
45 | A _nym_ is an identity of another user in the network, identified by its public key. | ||
46 | Each user can have multiple identities. | ||
47 | |||
48 | struct GNUNET_SOCIAL_Ego and struct GNUNET_SOCIAL_Nym represents one of these identities. | ||
49 | |||
50 | ## Place, Host, Guest | ||
51 | |||
52 | A _place_ is where social interactions happen. It is owned and created by an _ego_. | ||
53 | Creating a new place happens by an _ego_ entering a new place as a _host_, | ||
54 | where _guests_ can enter later to receive messages sent to the place. | ||
55 | |||
56 | A place is identified by its public key. | ||
57 | |||
58 | - struct GNUNET_SOCIAL_Host represents a place entered as host, | ||
59 | - struct GNUNET_SOCIAL_Guest is used for a place entered as guest. | ||
60 | - A struct GNUNET_SOCIAL_Place can be obtained for both a host and guest place | ||
61 | using GNUNET_SOCIAL_host_get_place() and GNUNET_SOCIAL_guest_get_place() | ||
62 | and can be used with API functions common to hosts and guests. | ||
63 | |||
64 | ## History | ||
65 | |||
66 | Messages sent to places are stored locally by the PSYCstore service, and can be queried any time. | ||
67 | GNUNET_SOCIAL_history_replay_latest() retrieves the latest N messages sent to the place, | ||
68 | while GNUNET_SOCIAL_history_replay() is used to query a given message ID range. | ||
69 | |||
70 | ## GNU Name System | ||
71 | |||
72 | The GNU Name System is used for assigning human-readable names to nyms and places. | ||
73 | There's a _GNS zone_ corresponding to each _nym_. | ||
74 | An _ego_ can publish PKEY and PLACE records in its own zone, pointing to nyms and places, respectively. | ||
75 | |||
76 | ## Announcement, talk request | ||
77 | |||
78 | The host can _announce_ messages to the place, using GNUNET_SOCIAL_host_announce(). | ||
79 | Guests can send _talk_ requests to the host, using GNUNET_SOCIAL_guest_talk(). | ||
80 | The host receives talk requests of guests and can _relay_ them to the place, | ||
81 | or process it using a message handler function. | ||
82 | |||
83 | # Using the API | ||
84 | |||
85 | ## Connecting to the service | ||
86 | |||
87 | A client first establishes an _application connection_ to the service using | ||
88 | GNUNET_SOCIAL_app_connect() providing its _application ID_, then receives the | ||
89 | public keys of subscribed places and available egos in response. | ||
90 | |||
91 | ## Reconnecting to places | ||
92 | |||
93 | Then the application can reconnect to its subscribed places by establishing | ||
94 | _place connections_ with GNUNET_SOCIAL_host_enter_reconnect() and | ||
95 | GNUNET_SOCIAL_guest_enter_reconnect(). | ||
96 | |||
97 | ## Subscribing to a place | ||
98 | |||
99 | Entering and subscribing a new host or guest place is done using | ||
100 | GNUNET_SOCIAL_host_enter() and GNUNET_SOCIAL_guest_enter(). | ||
101 | |||
102 | ## Disconnecting from a place | ||
103 | |||
104 | An application can disconnect from a place while the social service keeps its | ||
105 | network connection active, using GNUNET_SOCIAL_host_disconnect() and | ||
106 | GNUNET_SOCIAL_guest_disconnect(). | ||
107 | |||
108 | ## Leaving a place | ||
109 | |||
110 | To permanently leave a place, see GNUNET_SOCIAL_host_leave() and GNUNET_SOCIAL_guest_leave(). | ||
111 | When leaving a place its network connections are closed and all applications are unsubscribed from the place. | ||
112 | |||
113 | # Message methods | ||
114 | |||
115 | ## _converse | ||
116 | |||
117 | Human conversation in a private or public place. | ||
118 | |||
119 | ### Environment | ||
120 | |||
121 | #### _id_reply | ||
122 | Message ID this message is in reply to. | ||
123 | |||
124 | #### _id_thread | ||
125 | Thread ID, the first message ID in the thread. | ||
126 | |||
127 | #### _nym_author | ||
128 | Nym of the author. | ||
129 | |||
130 | FIXME: Are nyms a different data type from egos and person entities? | ||
131 | Do they have a different format than any other entity address? | ||
132 | Questions and thoughts on how to fix this in "questions.org" | ||
133 | |||
134 | #### _sig_author | ||
135 | Signature of the message body and its variables by the author. | ||
136 | |||
137 | ### Data | ||
138 | |||
139 | Message body. | ||
140 | |||
141 | ## _notice_place | ||
142 | |||
143 | Notification about a place. | ||
144 | |||
145 | TODO: Applications can decide to auto-subscribe to certain places, | ||
146 | e.g. files under a given size. | ||
147 | |||
148 | ### Environment | ||
149 | |||
150 | #### Using GNS | ||
151 | |||
152 | ##### _gns_place | ||
153 | GNS name of the place in a globally unique .zkey zone | ||
154 | |||
155 | FIXME: A custom _gns PSYC data type should be avoidable by parsing | ||
156 | and interpreting PSYC uniforms appropriately. | ||
157 | Thoughts on this in "questions.org" | ||
158 | |||
159 | #### Without GNS | ||
160 | |||
161 | ##### _key_pub_place | ||
162 | Public key of place | ||
163 | |||
164 | FIXME: _key_pub can't be the data type for GNUnet-specific cryptographic | ||
165 | addressing. Questions and thoughts on how to fix this in "questions.org" | ||
166 | |||
167 | ##### _peer_origin | ||
168 | Peer ID of origin | ||
169 | |||
170 | ##### _list_peer_relays | ||
171 | List of peer IDs of relays | ||
172 | |||
173 | ## _notice_place_file | ||
174 | |||
175 | Notification about a place hosting a file. | ||
176 | |||
177 | ### Environment | ||
178 | |||
179 | The environment of _notice_place above, plus the following: | ||
180 | |||
181 | #### _size_file | ||
182 | Size of file | ||
183 | |||
184 | #### _type_file | ||
185 | MIME type of file | ||
186 | |||
187 | #### _name_file | ||
188 | Name of file | ||
189 | |||
190 | #### _description_file | ||
191 | Description of file | ||
192 | |||
193 | ## _file | ||
194 | |||
195 | Messages with a _file method contain a file, | ||
196 | which is saved to disk upon reception at the following location: | ||
197 | $GNUNET_DATA_HOME/social/files/<H(place_pub)>/<H(message_id)> | ||
198 | |||
199 | ### Environment | ||
200 | |||
201 | #### _size_file | ||
202 | Size of file | ||
203 | |||
204 | #### _type_file | ||
205 | MIME type of file | ||
206 | |||
207 | #### _name_file | ||
208 | Name of file | ||
209 | |||
210 | #### _description_file | ||
211 | Description of file | ||
212 | |||
213 | @{ | ||
214 | */ | ||
215 | |||
216 | |||
217 | #ifndef GNUNET_SOCIAL_SERVICE_H | ||
218 | #define GNUNET_SOCIAL_SERVICE_H | ||
219 | |||
220 | #ifdef __cplusplus | ||
221 | extern "C" | ||
222 | { | ||
223 | #if 0 /* keep Emacsens' auto-indent happy */ | ||
224 | } | ||
225 | #endif | ||
226 | #endif | ||
227 | |||
228 | #include <stdint.h> | ||
229 | #include "gnunet_util_lib.h" | ||
230 | #include "gnunet_psyc_util_lib.h" | ||
231 | #include "gnunet_identity_service.h" | ||
232 | #include "gnunet_namestore_service.h" | ||
233 | #include "gnunet_psyc_service.h" | ||
234 | |||
235 | |||
236 | /** | ||
237 | * Version number of GNUnet Social API. | ||
238 | */ | ||
239 | #define GNUNET_SOCIAL_VERSION 0x00000000 | ||
240 | |||
241 | /** | ||
242 | * Maximum size of client ID including '\0' terminator. | ||
243 | */ | ||
244 | #define GNUNET_SOCIAL_APP_MAX_ID_SIZE 256 | ||
245 | |||
246 | enum GNUNET_SOCIAL_MsgProcFlags { | ||
247 | GNUNET_SOCIAL_MSG_PROC_NONE = 0, | ||
248 | GNUNET_SOCIAL_MSG_PROC_RELAY = 1, | ||
249 | GNUNET_SOCIAL_MSG_PROC_SAVE= 2, | ||
250 | }; | ||
251 | |||
252 | /** | ||
253 | * Handle for an application. | ||
254 | */ | ||
255 | struct GNUNET_SOCIAL_App; | ||
256 | |||
257 | /** | ||
258 | * Handle for an ego (own identity) | ||
259 | */ | ||
260 | struct GNUNET_SOCIAL_Ego; | ||
261 | |||
262 | /** | ||
263 | * Handle for a pseudonym of another user in the network. | ||
264 | */ | ||
265 | struct GNUNET_SOCIAL_Nym; | ||
266 | |||
267 | /** | ||
268 | * Handle for a place where social interactions happen. | ||
269 | */ | ||
270 | struct GNUNET_SOCIAL_Place; | ||
271 | |||
272 | /** | ||
273 | * Host handle for a place that we entered. | ||
274 | */ | ||
275 | struct GNUNET_SOCIAL_Host; | ||
276 | |||
277 | /** | ||
278 | * Guest handle for place that we entered. | ||
279 | */ | ||
280 | struct GNUNET_SOCIAL_Guest; | ||
281 | |||
282 | /** | ||
283 | * Handle that can be used to reconnect to a place as host. | ||
284 | */ | ||
285 | struct GNUNET_SOCIAL_HostConnection; | ||
286 | |||
287 | /** | ||
288 | * Handle that can be used to reconnect to a place as guest. | ||
289 | */ | ||
290 | struct GNUNET_SOCIAL_GuestConnection; | ||
291 | |||
292 | /** | ||
293 | * Notification about an available identity. | ||
294 | * | ||
295 | * @param cls | ||
296 | * Closure. | ||
297 | * @param pub_key | ||
298 | * Public key of ego. | ||
299 | * @param name | ||
300 | * Name of ego. | ||
301 | */ | ||
302 | typedef void | ||
303 | (*GNUNET_SOCIAL_AppEgoCallback) (void *cls, | ||
304 | struct GNUNET_SOCIAL_Ego *ego, | ||
305 | const struct GNUNET_CRYPTO_EcdsaPublicKey *ego_pub_key, | ||
306 | const char *name); | ||
307 | |||
308 | |||
309 | /** | ||
310 | * Entry status of a place per application. | ||
311 | */ | ||
312 | enum GNUNET_SOCIAL_AppPlaceState | ||
313 | { | ||
314 | /** | ||
315 | * The place was once entered by the ego, but left since. | ||
316 | * It's possible to establish a local connection to the place | ||
317 | * without re-entering to fetch history from the PSYCstore. | ||
318 | * @see enum GNUNET_PSYC_SlaveJoinFlags and GNUNET_SOCIAL_guest_enter() | ||
319 | */ | ||
320 | GNUNET_SOCIAL_PLACE_STATE_ARCHIVED = 0, | ||
321 | |||
322 | /** | ||
323 | * The place is entered by the ego, | ||
324 | * but this application is not subscribed to it. | ||
325 | */ | ||
326 | GNUNET_SOCIAL_PLACE_STATE_ENTERED = 1, | ||
327 | |||
328 | /** | ||
329 | * The place is entered by the ego and | ||
330 | * and this application is subscribed to it. | ||
331 | */ | ||
332 | GNUNET_SOCIAL_PLACE_STATE_SUBSCRIBED = 2, | ||
333 | }; | ||
334 | |||
335 | |||
336 | /** | ||
337 | * Called after receiving initial list of egos and places. | ||
338 | */ | ||
339 | typedef void | ||
340 | (*GNUNET_SOCIAL_AppConnectedCallback) (void *cls); | ||
341 | |||
342 | |||
343 | /** | ||
344 | * Notification about a home. | ||
345 | * | ||
346 | * @param cls | ||
347 | * Closure. | ||
348 | * @param hconn | ||
349 | * Host connection, to be used with GNUNET_SOCIAL_host_enter_reconnect() | ||
350 | * @param ego | ||
351 | * Ego used to enter the place. | ||
352 | * @param place_pub_key | ||
353 | * Public key of the place. | ||
354 | * @param place_state | ||
355 | * @see enum GNUNET_SOCIAL_AppPlaceState | ||
356 | */ | ||
357 | typedef void | ||
358 | (*GNUNET_SOCIAL_AppHostPlaceCallback) (void *cls, | ||
359 | struct GNUNET_SOCIAL_HostConnection *hconn, | ||
360 | struct GNUNET_SOCIAL_Ego *ego, | ||
361 | const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key, | ||
362 | enum GNUNET_SOCIAL_AppPlaceState place_state); | ||
363 | |||
364 | /** | ||
365 | * Notification about a place. | ||
366 | * | ||
367 | * @param cls | ||
368 | * Closure. | ||
369 | * @param gconn | ||
370 | * Guest connection, to be used with GNUNET_SOCIAL_guest_enter_reconnect() | ||
371 | * @param ego | ||
372 | * Ego used to enter the place. | ||
373 | * @param place_pub_key | ||
374 | * Public key of the place. | ||
375 | * @param place_state | ||
376 | * @see enum GNUNET_SOCIAL_AppPlaceState | ||
377 | */ | ||
378 | typedef void | ||
379 | (*GNUNET_SOCIAL_AppGuestPlaceCallback) (void *cls, | ||
380 | struct GNUNET_SOCIAL_GuestConnection *gconn, | ||
381 | struct GNUNET_SOCIAL_Ego *ego, | ||
382 | const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key, | ||
383 | enum GNUNET_SOCIAL_AppPlaceState place_state); | ||
384 | |||
385 | |||
386 | /** | ||
387 | * Establish application connection to the social service. | ||
388 | * | ||
389 | * The @host_cb and @guest_cb functions are | ||
390 | * initially called for each entered places, | ||
391 | * then later each time a new place is entered with the current app ID. | ||
392 | * | ||
393 | * @param cfg | ||
394 | * Configuration. | ||
395 | * @param ego_cb | ||
396 | * Function to notify about an available ego. | ||
397 | * @param host_cb | ||
398 | * Function to notify about a place entered as host. | ||
399 | * @param guest_cb | ||
400 | * Function to notify about a place entered as guest. | ||
401 | * @param cls | ||
402 | * Closure for the callbacks. | ||
403 | * | ||
404 | * @return Handle that can be used to stop listening. | ||
405 | */ | ||
406 | struct GNUNET_SOCIAL_App * | ||
407 | GNUNET_SOCIAL_app_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
408 | const char *id, | ||
409 | GNUNET_SOCIAL_AppEgoCallback ego_cb, | ||
410 | GNUNET_SOCIAL_AppHostPlaceCallback host_cb, | ||
411 | GNUNET_SOCIAL_AppGuestPlaceCallback guest_cb, | ||
412 | GNUNET_SOCIAL_AppConnectedCallback connected_cb, | ||
413 | void *cls); | ||
414 | |||
415 | |||
416 | /** | ||
417 | * Disconnect app. | ||
418 | * | ||
419 | * @param app | ||
420 | * Application handle. | ||
421 | * @param disconnect_cb | ||
422 | * Disconnect callback. | ||
423 | * @param disconnect_cls | ||
424 | * Disconnect closure. | ||
425 | */ | ||
426 | void | ||
427 | GNUNET_SOCIAL_app_disconnect (struct GNUNET_SOCIAL_App *app, | ||
428 | GNUNET_ContinuationCallback disconnect_cb, | ||
429 | void *disconnect_cls); | ||
430 | |||
431 | |||
432 | /** | ||
433 | * Get the public key of @a ego. | ||
434 | * | ||
435 | * @param ego | ||
436 | * Ego. | ||
437 | * | ||
438 | * @return Public key of ego. | ||
439 | */ | ||
440 | const struct GNUNET_CRYPTO_EcdsaPublicKey * | ||
441 | GNUNET_SOCIAL_ego_get_pub_key (const struct GNUNET_SOCIAL_Ego *ego); | ||
442 | |||
443 | |||
444 | /** | ||
445 | * Get the name of @a ego. | ||
446 | * | ||
447 | * @param ego | ||
448 | * Ego. | ||
449 | * | ||
450 | * @return Public key of @a ego. | ||
451 | */ | ||
452 | const char * | ||
453 | GNUNET_SOCIAL_ego_get_name (const struct GNUNET_SOCIAL_Ego *ego); | ||
454 | |||
455 | |||
456 | /** | ||
457 | * Get the public key of a @a nym. | ||
458 | * | ||
459 | * Suitable, for example, to be used with GNUNET_SOCIAL_zone_add_nym(). | ||
460 | * | ||
461 | * @param nym | ||
462 | * Pseudonym to map to a cryptographic identifier. | ||
463 | * | ||
464 | * @return Public key of nym. | ||
465 | */ | ||
466 | const struct GNUNET_CRYPTO_EcdsaPublicKey * | ||
467 | GNUNET_SOCIAL_nym_get_pub_key (const struct GNUNET_SOCIAL_Nym *nym); | ||
468 | |||
469 | |||
470 | /** | ||
471 | * Get the hash of the public key of a @a nym. | ||
472 | * | ||
473 | * @param nym | ||
474 | * Pseudonym to map to a cryptographic identifier. | ||
475 | * | ||
476 | * @return Hash of the public key of nym. | ||
477 | */ | ||
478 | const struct GNUNET_HashCode * | ||
479 | GNUNET_SOCIAL_nym_get_pub_key_hash (const struct GNUNET_SOCIAL_Nym *nym); | ||
480 | |||
481 | |||
482 | /** | ||
483 | * Function called asking for nym to be admitted to the place. | ||
484 | * | ||
485 | * Should call either GNUNET_SOCIAL_host_admit() or | ||
486 | * GNUNET_SOCIAL_host_reject_entry() (possibly asynchronously). If this host | ||
487 | * cannot decide, it is fine to call neither function, in which case hopefully | ||
488 | * some other host of the place exists that will make the decision. The @a nym | ||
489 | * reference remains valid until the #GNUNET_SOCIAL_FarewellCallback is invoked | ||
490 | * for it. | ||
491 | * | ||
492 | * @param cls | ||
493 | * Closure. | ||
494 | * @param nym | ||
495 | * Handle for the user who wants to enter. | ||
496 | * @param method_name | ||
497 | * Method name in the entry request. | ||
498 | * @param variable_count | ||
499 | * Number of elements in the @a variables array. | ||
500 | * @param variables | ||
501 | * Variables present in the message. | ||
502 | * @param data | ||
503 | * Payload given on enter (e.g. a password). | ||
504 | * @param data_size | ||
505 | * Number of bytes in @a data. | ||
506 | */ | ||
507 | typedef void | ||
508 | (*GNUNET_SOCIAL_AnswerDoorCallback) (void *cls, | ||
509 | struct GNUNET_SOCIAL_Nym *nym, | ||
510 | const char *method_name, | ||
511 | struct GNUNET_PSYC_Environment *env, | ||
512 | const void *data, | ||
513 | size_t data_size); | ||
514 | |||
515 | |||
516 | /** | ||
517 | * Function called when a @a nym leaves the place. | ||
518 | * | ||
519 | * This is also called if the @a nym was never given permission to enter | ||
520 | * (i.e. the @a nym stopped asking to get in). | ||
521 | * | ||
522 | * @param cls | ||
523 | * Closure. | ||
524 | * @param nym | ||
525 | * Handle for the user who left. | ||
526 | */ | ||
527 | typedef void | ||
528 | (*GNUNET_SOCIAL_FarewellCallback) (void *cls, | ||
529 | const struct GNUNET_SOCIAL_Nym *nym, | ||
530 | struct GNUNET_PSYC_Environment *env); | ||
531 | |||
532 | |||
533 | /** | ||
534 | * Function called after the host entered a home. | ||
535 | * | ||
536 | * @param cls | ||
537 | * Closure. | ||
538 | * @param result | ||
539 | * #GNUNET_OK on success, or | ||
540 | * #GNUNET_SYSERR on error. | ||
541 | * @param place_pub_key | ||
542 | * Public key of home. | ||
543 | * @param max_message_id | ||
544 | * Last message ID sent to the channel. | ||
545 | * Or 0 if no messages have been sent to the place yet. | ||
546 | */ | ||
547 | typedef void | ||
548 | (*GNUNET_SOCIAL_HostEnterCallback) (void *cls, int result, | ||
549 | const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key, | ||
550 | uint64_t max_message_id); | ||
551 | |||
552 | |||
553 | /** | ||
554 | * Enter a place as host. | ||
555 | * | ||
556 | * A place is created upon first entering, and it is active until permanently | ||
557 | * left using GNUNET_SOCIAL_host_leave(). | ||
558 | * | ||
559 | * @param cfg | ||
560 | * Configuration to contact the social service. | ||
561 | * @param ego | ||
562 | * Identity of the host. | ||
563 | * @param place_key | ||
564 | * Private-public key pair of the place. | ||
565 | * NULL for ephemeral places. | ||
566 | * @param policy | ||
567 | * Policy specifying entry and history restrictions for the place. | ||
568 | * @param slicer | ||
569 | * Slicer to handle incoming messages. | ||
570 | * @param enter_cb | ||
571 | * Function called when the place is entered and ready to use. | ||
572 | * @param answer_door_cb | ||
573 | * Function to handle new nyms that want to enter. | ||
574 | * @param farewell_cb | ||
575 | * Function to handle departing nyms. | ||
576 | * @param cls | ||
577 | * Closure for the callbacks. | ||
578 | * | ||
579 | * @return Handle for the host. | ||
580 | */ | ||
581 | struct GNUNET_SOCIAL_Host * | ||
582 | GNUNET_SOCIAL_host_enter (const struct GNUNET_SOCIAL_App *app, | ||
583 | const struct GNUNET_SOCIAL_Ego *ego, | ||
584 | enum GNUNET_PSYC_Policy policy, | ||
585 | struct GNUNET_PSYC_Slicer *slicer, | ||
586 | GNUNET_SOCIAL_HostEnterCallback enter_cb, | ||
587 | GNUNET_SOCIAL_AnswerDoorCallback answer_door_cb, | ||
588 | GNUNET_SOCIAL_FarewellCallback farewell_cb, | ||
589 | void *cls); | ||
590 | |||
591 | |||
592 | /** | ||
593 | * Reconnect to an already entered place as host. | ||
594 | * | ||
595 | * @param hconn | ||
596 | * Host connection handle. | ||
597 | * @see GNUNET_SOCIAL_app_connect() & GNUNET_SOCIAL_AppHostPlaceCallback() | ||
598 | * @param slicer | ||
599 | * Slicer to handle incoming messages. | ||
600 | * @param enter_cb | ||
601 | * Function called when the place is entered and ready to use. | ||
602 | * @param answer_door_cb | ||
603 | * Function to handle new nyms that want to enter. | ||
604 | * @param farewell_cb | ||
605 | * Function to handle departing nyms. | ||
606 | * @param cls | ||
607 | * Closure for the callbacks. | ||
608 | * | ||
609 | * @return Handle for the host. | ||
610 | */ | ||
611 | struct GNUNET_SOCIAL_Host * | ||
612 | GNUNET_SOCIAL_host_enter_reconnect (struct GNUNET_SOCIAL_HostConnection *hconn, | ||
613 | struct GNUNET_PSYC_Slicer *slicer, | ||
614 | GNUNET_SOCIAL_HostEnterCallback enter_cb, | ||
615 | GNUNET_SOCIAL_AnswerDoorCallback answer_door_cb, | ||
616 | GNUNET_SOCIAL_FarewellCallback farewell_cb, | ||
617 | void *cls); | ||
618 | |||
619 | |||
620 | /** | ||
621 | * Decision whether to admit @a nym into the place or refuse entry. | ||
622 | * | ||
623 | * @param hst | ||
624 | * Host of the place. | ||
625 | * @param nym | ||
626 | * Handle for the entity that wanted to enter. | ||
627 | * @param is_admitted | ||
628 | * #GNUNET_YES if @a nym is admitted, | ||
629 | * #GNUNET_NO if @a nym is refused entry, | ||
630 | * #GNUNET_SYSERR if we cannot answer the request. | ||
631 | * @param entry_resp | ||
632 | * Entry response message, or NULL. | ||
633 | * @return #GNUNET_OK on success, | ||
634 | * #GNUNET_SYSERR if the message is too large. | ||
635 | */ | ||
636 | int | ||
637 | GNUNET_SOCIAL_host_entry_decision (struct GNUNET_SOCIAL_Host *hst, | ||
638 | struct GNUNET_SOCIAL_Nym *nym, | ||
639 | int is_admitted, | ||
640 | const struct GNUNET_PSYC_Message *entry_resp); | ||
641 | |||
642 | |||
643 | /** | ||
644 | * Throw @a nym out of the place. | ||
645 | * | ||
646 | * Sends a _notice_place_leave announcement to the home. | ||
647 | * | ||
648 | * The @a nym reference will remain valid until the | ||
649 | * #GNUNET_SOCIAL_FarewellCallback is invoked, | ||
650 | * which should be very soon after this call. | ||
651 | * | ||
652 | * @param host | ||
653 | * Host of the place. | ||
654 | * @param nym | ||
655 | * Handle for the entity to be ejected. | ||
656 | * @param env | ||
657 | * Environment for the message or NULL. | ||
658 | * _nym is set to @e nym regardless whether an @e env is provided. | ||
659 | */ | ||
660 | void | ||
661 | GNUNET_SOCIAL_host_eject (struct GNUNET_SOCIAL_Host *host, | ||
662 | const struct GNUNET_SOCIAL_Nym *nym, | ||
663 | struct GNUNET_PSYC_Environment *env); | ||
664 | |||
665 | |||
666 | /** | ||
667 | * Flags for announcements by a host. | ||
668 | */ | ||
669 | enum GNUNET_SOCIAL_AnnounceFlags | ||
670 | { | ||
671 | GNUNET_SOCIAL_ANNOUNCE_NONE = 0, | ||
672 | |||
673 | /** | ||
674 | * Whether this announcement removes all objects from the place. | ||
675 | * | ||
676 | * New objects can be still added to the now empty place using the @e env | ||
677 | * parameter of the same announcement. | ||
678 | */ | ||
679 | GNUNET_SOCIAL_ANNOUNCE_CLEAR_OBJECTS = 1 << 0 | ||
680 | }; | ||
681 | |||
682 | |||
683 | /** | ||
684 | * Handle for an announcement request. | ||
685 | */ | ||
686 | struct GNUNET_SOCIAL_Announcement; | ||
687 | |||
688 | |||
689 | /** | ||
690 | * Send a message to all nyms that are present in the place. | ||
691 | * | ||
692 | * This function is restricted to the host. Nyms can only send requests | ||
693 | * to the host who can decide to relay it to everyone in the place. | ||
694 | * | ||
695 | * @param host | ||
696 | * Host of the place. | ||
697 | * @param method_name | ||
698 | * Method to use for the announcement. | ||
699 | * @param env | ||
700 | * Environment containing variables for the message and operations | ||
701 | * on objects of the place. | ||
702 | * Has to remain available until the first call to @a notify_data. | ||
703 | * Can be NULL. | ||
704 | * @param notify_data | ||
705 | * Function to call to get the payload of the announcement. | ||
706 | * @param notify_data_cls | ||
707 | * Closure for @a notify. | ||
708 | * @param flags | ||
709 | * Flags for this announcement. | ||
710 | * | ||
711 | * @return NULL on error (another announcement already in progress?). | ||
712 | */ | ||
713 | struct GNUNET_SOCIAL_Announcement * | ||
714 | GNUNET_SOCIAL_host_announce (struct GNUNET_SOCIAL_Host *host, | ||
715 | const char *method_name, | ||
716 | const struct GNUNET_PSYC_Environment *env, | ||
717 | GNUNET_PSYC_TransmitNotifyData notify_data, | ||
718 | void *notify_data_cls, | ||
719 | enum GNUNET_SOCIAL_AnnounceFlags flags); | ||
720 | |||
721 | |||
722 | /** | ||
723 | * Resume transmitting announcement. | ||
724 | * | ||
725 | * @param a | ||
726 | * The announcement to resume. | ||
727 | */ | ||
728 | void | ||
729 | GNUNET_SOCIAL_host_announce_resume (struct GNUNET_SOCIAL_Announcement *a); | ||
730 | |||
731 | |||
732 | /** | ||
733 | * Cancel announcement. | ||
734 | * | ||
735 | * @param a | ||
736 | * The announcement to cancel. | ||
737 | */ | ||
738 | void | ||
739 | GNUNET_SOCIAL_host_announce_cancel (struct GNUNET_SOCIAL_Announcement *a); | ||
740 | |||
741 | |||
742 | /** | ||
743 | * Allow relaying messages from guests matching a given @a method_prefix. | ||
744 | * | ||
745 | * @param host | ||
746 | * The host. | ||
747 | * @param method_prefix | ||
748 | * Method prefix to allow. | ||
749 | */ | ||
750 | void | ||
751 | GNUNET_SOCIAL_host_relay_allow_method (struct GNUNET_SOCIAL_Host *host, | ||
752 | const char *method_prefix); | ||
753 | |||
754 | |||
755 | /** | ||
756 | * Allow relaying changes to objects of the place. | ||
757 | * | ||
758 | * Only applies to messages with an allowed method name. | ||
759 | * @see GNUNET_SCOIAL_host_relay_allow_method() | ||
760 | * | ||
761 | * @param host | ||
762 | * The host. | ||
763 | * @param object_prefix | ||
764 | * Object prefix to allow modifying. | ||
765 | */ | ||
766 | void | ||
767 | GNUNET_SOCIAL_host_relay_allow_method (struct GNUNET_SOCIAL_Host *host, | ||
768 | const char *object_prefix); | ||
769 | |||
770 | |||
771 | /** | ||
772 | * Stop relaying messages from guests. | ||
773 | * | ||
774 | * Remove all allowed relay rules. | ||
775 | * | ||
776 | * | ||
777 | * | ||
778 | */ | ||
779 | void | ||
780 | GNUNET_SOCIAL_host_relay_stop (struct GNUNET_SOCIAL_Host *host); | ||
781 | |||
782 | |||
783 | /** | ||
784 | * Obtain handle for a hosted place. | ||
785 | * | ||
786 | * The returned handle can be used to access the place API. | ||
787 | * | ||
788 | * @param host | ||
789 | * Handle for the host. | ||
790 | * | ||
791 | * @return Handle for the hosted place, valid as long as @a host is valid. | ||
792 | */ | ||
793 | struct GNUNET_SOCIAL_Place * | ||
794 | GNUNET_SOCIAL_host_get_place (struct GNUNET_SOCIAL_Host *host); | ||
795 | |||
796 | |||
797 | /** | ||
798 | * Disconnect from a home. | ||
799 | * | ||
800 | * Invalidates host handle. | ||
801 | * | ||
802 | * @param hst | ||
803 | * The host to disconnect. | ||
804 | * @param disconnect_cb | ||
805 | * Function called after disconnected from the service. | ||
806 | * @param cls | ||
807 | * Closure for @a disconnect_cb. | ||
808 | */ | ||
809 | void | ||
810 | GNUNET_SOCIAL_host_disconnect (struct GNUNET_SOCIAL_Host *hst, | ||
811 | GNUNET_ContinuationCallback disconnect_cb, | ||
812 | void *cls); | ||
813 | |||
814 | |||
815 | /** | ||
816 | * Stop hosting a home. | ||
817 | * | ||
818 | * Sends a _notice_place_closing announcement to the home. | ||
819 | * Invalidates host handle. | ||
820 | * | ||
821 | * @param hst | ||
822 | * Host leaving. | ||
823 | * @param env | ||
824 | * Environment for the message or NULL. | ||
825 | * @param disconnect_cb | ||
826 | * Function called after the host left the place | ||
827 | * and disconnected from the service. | ||
828 | * @param cls | ||
829 | * Closure for @a disconnect_cb. | ||
830 | */ | ||
831 | void | ||
832 | GNUNET_SOCIAL_host_leave (struct GNUNET_SOCIAL_Host *hst, | ||
833 | const struct GNUNET_PSYC_Environment *env, | ||
834 | GNUNET_ContinuationCallback disconnect_cb, | ||
835 | void *cls); | ||
836 | |||
837 | |||
838 | /** | ||
839 | * Function called after the guest entered the local copy of the place. | ||
840 | * | ||
841 | * History and object query functions can be used after this call, | ||
842 | * but new messages can't be sent or received. | ||
843 | * | ||
844 | * @param cls | ||
845 | * Closure. | ||
846 | * @param result | ||
847 | * #GNUNET_OK on success, or | ||
848 | * #GNUNET_SYSERR on error, e.g. could not connect to the service, or | ||
849 | * could not resolve GNS name. | ||
850 | * @param place_pub_key | ||
851 | * Public key of place. | ||
852 | * @param max_message_id | ||
853 | * Last message ID sent to the place. | ||
854 | * Or 0 if no messages have been sent to the place yet. | ||
855 | */ | ||
856 | typedef void | ||
857 | (*GNUNET_SOCIAL_GuestEnterCallback) (void *cls, int result, | ||
858 | const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key, | ||
859 | uint64_t max_message_id); | ||
860 | |||
861 | |||
862 | /** | ||
863 | * Function called upon a guest receives a decision about entry to the place. | ||
864 | * | ||
865 | * @param is_admitted | ||
866 | * Is the guest admitted to the place? | ||
867 | * #GNUNET_YES if admitted, | ||
868 | * #GNUNET_NO if refused entry, | ||
869 | * #GNUNET_SYSERR if the request could not be answered. | ||
870 | * @param data | ||
871 | * Entry response message. | ||
872 | */ | ||
873 | typedef void | ||
874 | (*GNUNET_SOCIAL_EntryDecisionCallback) (void *cls, | ||
875 | int is_admitted, | ||
876 | const struct GNUNET_PSYC_Message *entry_resp); | ||
877 | |||
878 | |||
879 | /** | ||
880 | * Request entry to a place as a guest. | ||
881 | * | ||
882 | * @param app | ||
883 | * Application handle. | ||
884 | * @param ego | ||
885 | * Identity of the guest. | ||
886 | * @param place_pub_key | ||
887 | * Public key of the place to enter. | ||
888 | * @param flags | ||
889 | * Flags for the entry. | ||
890 | * @param origin | ||
891 | * Peer identity of the origin of the underlying multicast group. | ||
892 | * @param relay_count | ||
893 | * Number of elements in the @a relays array. | ||
894 | * @param relays | ||
895 | * Relays for the underlying multicast group. | ||
896 | * @param entry_msg | ||
897 | * Entry message. | ||
898 | * @param slicer | ||
899 | * Slicer to use for processing incoming requests from guests. | ||
900 | * | ||
901 | * @return NULL on errors, otherwise handle for the guest. | ||
902 | */ | ||
903 | struct GNUNET_SOCIAL_Guest * | ||
904 | GNUNET_SOCIAL_guest_enter (const struct GNUNET_SOCIAL_App *app, | ||
905 | const struct GNUNET_SOCIAL_Ego *ego, | ||
906 | const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key, | ||
907 | enum GNUNET_PSYC_SlaveJoinFlags flags, | ||
908 | const struct GNUNET_PeerIdentity *origin, | ||
909 | uint32_t relay_count, | ||
910 | const struct GNUNET_PeerIdentity *relays, | ||
911 | const struct GNUNET_PSYC_Message *entry_msg, | ||
912 | struct GNUNET_PSYC_Slicer *slicer, | ||
913 | GNUNET_SOCIAL_GuestEnterCallback local_enter_cb, | ||
914 | GNUNET_SOCIAL_EntryDecisionCallback entry_dcsn_cb, | ||
915 | void *cls); | ||
916 | |||
917 | |||
918 | /** | ||
919 | * Request entry to a place by name as a guest. | ||
920 | * | ||
921 | * @param app | ||
922 | * Application handle. | ||
923 | * @param ego | ||
924 | * Identity of the guest. | ||
925 | * @param gns_name | ||
926 | * GNS name of the place to enter. Either in the form of | ||
927 | * 'room.friend.gnu', or 'NYMPUBKEY.zkey'. This latter case refers to | ||
928 | * the 'PLACE' record of the empty label ("+") in the GNS zone with the | ||
929 | * nym's public key 'NYMPUBKEY', and can be used to request entry to a | ||
930 | * pseudonym's place directly. | ||
931 | * @param password | ||
932 | * Password to decrypt the record, or NULL for cleartext records. | ||
933 | * @param join_msg | ||
934 | * Entry request message. | ||
935 | * @param slicer | ||
936 | * Slicer to use for processing incoming requests from guests. | ||
937 | * @param local_enter_cb | ||
938 | * Called upon connection established to the social service. | ||
939 | * @param entry_decision_cb | ||
940 | * Called upon receiving entry decision. | ||
941 | * | ||
942 | * @return NULL on errors, otherwise handle for the guest. | ||
943 | */ | ||
944 | struct GNUNET_SOCIAL_Guest * | ||
945 | GNUNET_SOCIAL_guest_enter_by_name (const struct GNUNET_SOCIAL_App *app, | ||
946 | const struct GNUNET_SOCIAL_Ego *ego, | ||
947 | const char *gns_name, | ||
948 | const char *password, | ||
949 | const struct GNUNET_PSYC_Message *join_msg, | ||
950 | struct GNUNET_PSYC_Slicer *slicer, | ||
951 | GNUNET_SOCIAL_GuestEnterCallback local_enter_cb, | ||
952 | GNUNET_SOCIAL_EntryDecisionCallback entry_decision_cb, | ||
953 | void *cls); | ||
954 | |||
955 | |||
956 | /** | ||
957 | * Reconnect to an already entered place as guest. | ||
958 | * | ||
959 | * @param gconn | ||
960 | * Guest connection handle. | ||
961 | * @see GNUNET_SOCIAL_app_connect() & GNUNET_SOCIAL_AppGuestPlaceCallback() | ||
962 | * @param flags | ||
963 | * Flags for the entry. | ||
964 | * @param slicer | ||
965 | * Slicer to use for processing incoming requests from guests. | ||
966 | * @param local_enter_cb | ||
967 | * Called upon connection established to the social service. | ||
968 | * @param entry_decision_cb | ||
969 | * Called upon receiving entry decision. | ||
970 | * | ||
971 | * @return NULL on errors, otherwise handle for the guest. | ||
972 | */ | ||
973 | struct GNUNET_SOCIAL_Guest * | ||
974 | GNUNET_SOCIAL_guest_enter_reconnect (struct GNUNET_SOCIAL_GuestConnection *gconn, | ||
975 | enum GNUNET_PSYC_SlaveJoinFlags flags, | ||
976 | struct GNUNET_PSYC_Slicer *slicer, | ||
977 | GNUNET_SOCIAL_GuestEnterCallback local_enter_cb, | ||
978 | void *cls); | ||
979 | |||
980 | |||
981 | /** | ||
982 | * Flags for talking to the host of a place. | ||
983 | */ | ||
984 | enum GNUNET_SOCIAL_TalkFlags | ||
985 | { | ||
986 | GNUNET_SOCIAL_TALK_NONE = 0 | ||
987 | }; | ||
988 | |||
989 | |||
990 | /** | ||
991 | * A talk request. | ||
992 | */ | ||
993 | struct GNUNET_SOCIAL_TalkRequest; | ||
994 | |||
995 | |||
996 | /** | ||
997 | * Talk to the host of the place. | ||
998 | * | ||
999 | * @param place | ||
1000 | * Place where we want to talk to the host. | ||
1001 | * @param method_name | ||
1002 | * Method to invoke on the host. | ||
1003 | * @param env | ||
1004 | * Environment containing variables for the message, or NULL. | ||
1005 | * @param notify_data | ||
1006 | * Function to use to get the payload for the method. | ||
1007 | * @param notify_data_cls | ||
1008 | * Closure for @a notify_data. | ||
1009 | * @param flags | ||
1010 | * Flags for the message being sent. | ||
1011 | * | ||
1012 | * @return NULL if we are already trying to talk to the host, | ||
1013 | * otherwise handle to cancel the request. | ||
1014 | */ | ||
1015 | struct GNUNET_SOCIAL_TalkRequest * | ||
1016 | GNUNET_SOCIAL_guest_talk (struct GNUNET_SOCIAL_Guest *guest, | ||
1017 | const char *method_name, | ||
1018 | const struct GNUNET_PSYC_Environment *env, | ||
1019 | GNUNET_PSYC_TransmitNotifyData notify_data, | ||
1020 | void *notify_data_cls, | ||
1021 | enum GNUNET_SOCIAL_TalkFlags flags); | ||
1022 | |||
1023 | |||
1024 | /** | ||
1025 | * Resume talking to the host of the place. | ||
1026 | * | ||
1027 | * @param tr | ||
1028 | * Talk request to resume. | ||
1029 | */ | ||
1030 | void | ||
1031 | GNUNET_SOCIAL_guest_talk_resume (struct GNUNET_SOCIAL_TalkRequest *tr); | ||
1032 | |||
1033 | |||
1034 | /** | ||
1035 | * Cancel talking to the host of the place. | ||
1036 | * | ||
1037 | * @param tr | ||
1038 | * Talk request to cancel. | ||
1039 | */ | ||
1040 | void | ||
1041 | GNUNET_SOCIAL_guest_talk_cancel (struct GNUNET_SOCIAL_TalkRequest *tr); | ||
1042 | |||
1043 | |||
1044 | /** | ||
1045 | * Disconnect from a place. | ||
1046 | * | ||
1047 | * Invalidates guest handle. | ||
1048 | * | ||
1049 | * @param gst | ||
1050 | * The guest to disconnect. | ||
1051 | * @param disconnect_cb | ||
1052 | * Function called after disconnected from the service. | ||
1053 | * @param cls | ||
1054 | * Closure for @a disconnect_cb. | ||
1055 | */ | ||
1056 | void | ||
1057 | GNUNET_SOCIAL_guest_disconnect (struct GNUNET_SOCIAL_Guest *gst, | ||
1058 | GNUNET_ContinuationCallback disconnect_cb, | ||
1059 | void *cls); | ||
1060 | |||
1061 | |||
1062 | /** | ||
1063 | * Leave a place temporarily or permanently. | ||
1064 | * | ||
1065 | * Notifies the owner of the place about leaving, and destroys the place handle. | ||
1066 | * | ||
1067 | * @param place | ||
1068 | * Place to leave. | ||
1069 | * @param env | ||
1070 | * Optional environment for the leave message if @a keep_active | ||
1071 | * is #GNUNET_NO. NULL if not needed. | ||
1072 | * @param disconnect_cb | ||
1073 | * Called upon disconnecting from the social service. | ||
1074 | */ | ||
1075 | void | ||
1076 | GNUNET_SOCIAL_guest_leave (struct GNUNET_SOCIAL_Guest *gst, | ||
1077 | struct GNUNET_PSYC_Environment *env, | ||
1078 | GNUNET_ContinuationCallback disconnect_cb, | ||
1079 | void *leave_cls); | ||
1080 | |||
1081 | |||
1082 | /** | ||
1083 | * Obtain handle for a place entered as guest. | ||
1084 | * | ||
1085 | * The returned handle can be used to access the place API. | ||
1086 | * | ||
1087 | * @param guest Handle for the guest. | ||
1088 | * | ||
1089 | * @return Handle for the place, valid as long as @a guest is valid. | ||
1090 | */ | ||
1091 | struct GNUNET_SOCIAL_Place * | ||
1092 | GNUNET_SOCIAL_guest_get_place (struct GNUNET_SOCIAL_Guest *guest); | ||
1093 | |||
1094 | |||
1095 | /** | ||
1096 | * A history request. | ||
1097 | */ | ||
1098 | struct GNUNET_SOCIAL_HistoryRequest; | ||
1099 | |||
1100 | |||
1101 | /** | ||
1102 | * Get the public key of a place. | ||
1103 | * | ||
1104 | * @param plc | ||
1105 | * Place. | ||
1106 | * | ||
1107 | * @return Public key of the place. | ||
1108 | */ | ||
1109 | const struct GNUNET_CRYPTO_EddsaPublicKey * | ||
1110 | GNUNET_SOCIAL_place_get_pub_key (const struct GNUNET_SOCIAL_Place *plc); | ||
1111 | |||
1112 | |||
1113 | /** | ||
1114 | * Set message processing @a flags for a @a method_prefix. | ||
1115 | * | ||
1116 | * @param plc | ||
1117 | * Place. | ||
1118 | * @param method_prefix | ||
1119 | * Method prefix @a flags apply to. | ||
1120 | * @param flags | ||
1121 | * The flags that apply to a matching @a method_prefix. | ||
1122 | */ | ||
1123 | void | ||
1124 | GNUNET_SOCIAL_place_msg_proc_set (struct GNUNET_SOCIAL_Place *plc, | ||
1125 | const char *method_prefix, | ||
1126 | enum GNUNET_SOCIAL_MsgProcFlags flags); | ||
1127 | |||
1128 | /** | ||
1129 | * Clear all message processing flags previously set for this place. | ||
1130 | */ | ||
1131 | void | ||
1132 | GNUNET_SOCIAL_place_msg_proc_clear (struct GNUNET_SOCIAL_Place *plc); | ||
1133 | |||
1134 | |||
1135 | /** | ||
1136 | * Learn about the history of a place. | ||
1137 | * | ||
1138 | * Messages are returned through the @a slicer function | ||
1139 | * and have the #GNUNET_PSYC_MESSAGE_HISTORIC flag set. | ||
1140 | * | ||
1141 | * @param place | ||
1142 | * Place we want to learn more about. | ||
1143 | * @param start_message_id | ||
1144 | * First historic message we are interested in. | ||
1145 | * @param end_message_id | ||
1146 | * Last historic message we are interested in (inclusive). | ||
1147 | * @param method_prefix | ||
1148 | * Only retrieve messages with this method prefix. | ||
1149 | * @param flags | ||
1150 | * OR'ed GNUNET_PSYC_HistoryReplayFlags | ||
1151 | * @param slicer | ||
1152 | * Slicer to use for retrieved messages. | ||
1153 | * Can be the same as the slicer of the place. | ||
1154 | * @param result_cb | ||
1155 | * Function called after all messages retrieved. | ||
1156 | * NULL if not needed. | ||
1157 | * @param cls Closure for @a result_cb. | ||
1158 | */ | ||
1159 | struct GNUNET_SOCIAL_HistoryRequest * | ||
1160 | GNUNET_SOCIAL_place_history_replay (struct GNUNET_SOCIAL_Place *plc, | ||
1161 | uint64_t start_message_id, | ||
1162 | uint64_t end_message_id, | ||
1163 | const char *method_prefix, | ||
1164 | uint32_t flags, | ||
1165 | struct GNUNET_PSYC_Slicer *slicer, | ||
1166 | GNUNET_ResultCallback result_cb, | ||
1167 | void *cls); | ||
1168 | |||
1169 | |||
1170 | /** | ||
1171 | * Learn about the history of a place. | ||
1172 | * | ||
1173 | * Sends messages through the slicer function of the place where | ||
1174 | * start_message_id <= message_id <= end_message_id. | ||
1175 | * The messages will have the #GNUNET_PSYC_MESSAGE_HISTORIC flag set. | ||
1176 | * | ||
1177 | * To get the latest message, use 0 for both the start and end message ID. | ||
1178 | * | ||
1179 | * @param place | ||
1180 | * Place we want to learn more about. | ||
1181 | * @param message_limit | ||
1182 | * Maximum number of historic messages we are interested in. | ||
1183 | * @param result_cb | ||
1184 | * Function called after all messages retrieved. | ||
1185 | * NULL if not needed. | ||
1186 | * @param cls Closure for @a result_cb. | ||
1187 | */ | ||
1188 | struct GNUNET_SOCIAL_HistoryRequest * | ||
1189 | GNUNET_SOCIAL_place_history_replay_latest (struct GNUNET_SOCIAL_Place *plc, | ||
1190 | uint64_t message_limit, | ||
1191 | const char *method_prefix, | ||
1192 | uint32_t flags, | ||
1193 | struct GNUNET_PSYC_Slicer *slicer, | ||
1194 | GNUNET_ResultCallback result_cb, | ||
1195 | void *cls); | ||
1196 | |||
1197 | /** | ||
1198 | * Cancel learning about the history of a place. | ||
1199 | * | ||
1200 | * @param hist | ||
1201 | * History lesson to cancel. | ||
1202 | */ | ||
1203 | void | ||
1204 | GNUNET_SOCIAL_place_history_replay_cancel (struct GNUNET_SOCIAL_HistoryRequest *hist); | ||
1205 | |||
1206 | |||
1207 | struct GNUNET_SOCIAL_LookHandle; | ||
1208 | |||
1209 | |||
1210 | /** | ||
1211 | * Look at a particular object in the place. | ||
1212 | * | ||
1213 | * The best matching object is returned (its name might be less specific than | ||
1214 | * what was requested). | ||
1215 | * | ||
1216 | * @param place | ||
1217 | * The place to look the object at. | ||
1218 | * @param full_name | ||
1219 | * Full name of the object. | ||
1220 | * | ||
1221 | * @return NULL if there is no such object at this place. | ||
1222 | */ | ||
1223 | struct GNUNET_SOCIAL_LookHandle * | ||
1224 | GNUNET_SOCIAL_place_look_at (struct GNUNET_SOCIAL_Place *plc, | ||
1225 | const char *full_name, | ||
1226 | GNUNET_PSYC_StateVarCallback var_cb, | ||
1227 | GNUNET_ResultCallback result_cb, | ||
1228 | void *cls); | ||
1229 | |||
1230 | /** | ||
1231 | * Look for objects in the place with a matching name prefix. | ||
1232 | * | ||
1233 | * @param place | ||
1234 | * The place to look its objects at. | ||
1235 | * @param name_prefix | ||
1236 | * Look at objects with names beginning with this value. | ||
1237 | * @param var_cb | ||
1238 | * Function to call for each object found. | ||
1239 | * @param cls | ||
1240 | * Closure for callback function. | ||
1241 | * | ||
1242 | * @return Handle that can be used to stop looking at objects. | ||
1243 | */ | ||
1244 | struct GNUNET_SOCIAL_LookHandle * | ||
1245 | GNUNET_SOCIAL_place_look_for (struct GNUNET_SOCIAL_Place *plc, | ||
1246 | const char *name_prefix, | ||
1247 | GNUNET_PSYC_StateVarCallback var_cb, | ||
1248 | GNUNET_ResultCallback result_cb, | ||
1249 | void *cls); | ||
1250 | |||
1251 | |||
1252 | /** | ||
1253 | * Stop looking at objects. | ||
1254 | * | ||
1255 | * @param lh Look handle to stop. | ||
1256 | */ | ||
1257 | void | ||
1258 | GNUNET_SOCIAL_place_look_cancel (struct GNUNET_SOCIAL_LookHandle *lh); | ||
1259 | |||
1260 | |||
1261 | /** | ||
1262 | * Advertise a @e place in the GNS zone of @a ego. | ||
1263 | * | ||
1264 | * @param app | ||
1265 | * Application handle. | ||
1266 | * @param ego | ||
1267 | * Ego. | ||
1268 | * @param place_pub_key | ||
1269 | * Public key of place to add. | ||
1270 | * @param name | ||
1271 | * The name for the PLACE record to put in the zone. | ||
1272 | * @param password | ||
1273 | * Password used to encrypt the record or NULL to keep it cleartext. | ||
1274 | * @param relay_count | ||
1275 | * Number of elements in the @a relays array. | ||
1276 | * @param relays | ||
1277 | * List of relays to put in the PLACE record to advertise | ||
1278 | * as entry points to the place in addition to the origin. | ||
1279 | * @param expiration_time | ||
1280 | * Expiration time of the record, use 0 to remove the record. | ||
1281 | * @param result_cb | ||
1282 | * Function called with the result of the operation. | ||
1283 | * @param result_cls | ||
1284 | * Closure for @a result_cb | ||
1285 | * | ||
1286 | * @return #GNUNET_OK if the request was sent, | ||
1287 | * #GNUNET_SYSERR on error, e.g. the name/password is too long. | ||
1288 | */ | ||
1289 | int | ||
1290 | GNUNET_SOCIAL_zone_add_place (const struct GNUNET_SOCIAL_App *app, | ||
1291 | const struct GNUNET_SOCIAL_Ego *ego, | ||
1292 | const char *name, | ||
1293 | const char *password, | ||
1294 | const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key, | ||
1295 | const struct GNUNET_PeerIdentity *origin, | ||
1296 | uint32_t relay_count, | ||
1297 | const struct GNUNET_PeerIdentity *relays, | ||
1298 | struct GNUNET_TIME_Absolute expiration_time, | ||
1299 | GNUNET_ResultCallback result_cb, | ||
1300 | void *result_cls); | ||
1301 | |||
1302 | |||
1303 | /** | ||
1304 | * Add public key to the GNS zone of the @e ego. | ||
1305 | * | ||
1306 | * @param cfg | ||
1307 | * Configuration. | ||
1308 | * @param ego | ||
1309 | * Ego. | ||
1310 | * @param name | ||
1311 | * The name for the PKEY record to put in the zone. | ||
1312 | * @param nym_pub_key | ||
1313 | * Public key of nym to add. | ||
1314 | * @param expiration_time | ||
1315 | * Expiration time of the record, use 0 to remove the record. | ||
1316 | * @param result_cb | ||
1317 | * Function called with the result of the operation. | ||
1318 | * @param result_cls | ||
1319 | * Closure for @a result_cb | ||
1320 | * | ||
1321 | * @return #GNUNET_OK if the request was sent, | ||
1322 | * #GNUNET_SYSERR on error, e.g. the name is too long. | ||
1323 | */ | ||
1324 | int | ||
1325 | GNUNET_SOCIAL_zone_add_nym (const struct GNUNET_SOCIAL_App *app, | ||
1326 | const struct GNUNET_SOCIAL_Ego *ego, | ||
1327 | const char *name, | ||
1328 | const struct GNUNET_CRYPTO_EcdsaPublicKey *nym_pub_key, | ||
1329 | struct GNUNET_TIME_Absolute expiration_time, | ||
1330 | GNUNET_ResultCallback result_cb, | ||
1331 | void *result_cls); | ||
1332 | |||
1333 | |||
1334 | #if 0 /* keep Emacsens' auto-indent happy */ | ||
1335 | { | ||
1336 | #endif | ||
1337 | #ifdef __cplusplus | ||
1338 | } | ||
1339 | #endif | ||
1340 | |||
1341 | /* ifndef GNUNET_SOCIAL_SERVICE_H */ | ||
1342 | #endif | ||
1343 | |||
1344 | /** @} */ /* end of group */ | ||
diff --git a/src/multicast/.gitignore b/src/multicast/.gitignore deleted file mode 100644 index a97844e81..000000000 --- a/src/multicast/.gitignore +++ /dev/null | |||
@@ -1,7 +0,0 @@ | |||
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 deleted file mode 100644 index 61a9f8bf6..000000000 --- a/src/multicast/Makefile.am +++ /dev/null | |||
@@ -1,79 +0,0 @@ | |||
1 | # This Makefile.am is in the public domain | ||
2 | AM_CPPFLAGS = -I$(top_srcdir)/src/include | ||
3 | |||
4 | pkgcfgdir= $(pkgdatadir)/config.d/ | ||
5 | |||
6 | libexecdir= $(pkglibdir)/libexec/ | ||
7 | |||
8 | pkgcfg_DATA = \ | ||
9 | multicast.conf | ||
10 | |||
11 | if MINGW | ||
12 | WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols | ||
13 | endif | ||
14 | |||
15 | if USE_COVERAGE | ||
16 | AM_CFLAGS = -fprofile-arcs -ftest-coverage | ||
17 | endif | ||
18 | |||
19 | lib_LTLIBRARIES = libgnunetmulticast.la | ||
20 | |||
21 | libgnunetmulticast_la_SOURCES = \ | ||
22 | multicast_api.c multicast.h | ||
23 | libgnunetmulticast_la_LIBADD = \ | ||
24 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
25 | $(GN_LIBINTL) $(XLIB) | ||
26 | libgnunetmulticast_la_LDFLAGS = \ | ||
27 | $(GN_LIB_LDFLAGS) $(WINFLAGS) \ | ||
28 | -version-info 0:0:0 | ||
29 | |||
30 | |||
31 | bin_PROGRAMS = \ | ||
32 | gnunet-multicast | ||
33 | |||
34 | libexec_PROGRAMS = \ | ||
35 | gnunet-service-multicast \ | ||
36 | $(EXP_LIBEXEC) | ||
37 | |||
38 | gnunet_multicast_SOURCES = \ | ||
39 | gnunet-multicast.c | ||
40 | gnunet_multicast_LDADD = \ | ||
41 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
42 | $(GN_LIBINTL) | ||
43 | |||
44 | gnunet_service_multicast_SOURCES = \ | ||
45 | gnunet-service-multicast.c | ||
46 | gnunet_service_multicast_LDADD = \ | ||
47 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
48 | $(top_builddir)/src/cadet/libgnunetcadet.la \ | ||
49 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ | ||
50 | $(GN_LIBINTL) | ||
51 | |||
52 | check_PROGRAMS = \ | ||
53 | test_multicast \ | ||
54 | test_multicast_multipeer_star \ | ||
55 | test_multicast_multipeer_line | ||
56 | |||
57 | if ENABLE_TEST_RUN | ||
58 | AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@}; export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH; unset XDG_DATA_HOME; unset XDG_CONFIG_HOME; | ||
59 | TESTS = $(check_PROGRAMS) | ||
60 | endif | ||
61 | |||
62 | test_multicast_SOURCES = \ | ||
63 | test_multicast.c | ||
64 | test_multicast_LDADD = \ | ||
65 | libgnunetmulticast.la \ | ||
66 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
67 | $(top_builddir)/src/util/libgnunetutil.la | ||
68 | test_multicast_multipeer_star_SOURCES = \ | ||
69 | test_multicast_multipeer.c | ||
70 | test_multicast_multipeer_star_LDADD = \ | ||
71 | libgnunetmulticast.la \ | ||
72 | $(top_builddir)/src/testbed/libgnunettestbed.la \ | ||
73 | $(top_builddir)/src/util/libgnunetutil.la | ||
74 | test_multicast_multipeer_line_SOURCES = \ | ||
75 | test_multicast_multipeer.c | ||
76 | test_multicast_multipeer_line_LDADD = \ | ||
77 | libgnunetmulticast.la \ | ||
78 | $(top_builddir)/src/testbed/libgnunettestbed.la \ | ||
79 | $(top_builddir)/src/util/libgnunetutil.la | ||
diff --git a/src/multicast/gnunet-multicast.c b/src/multicast/gnunet-multicast.c deleted file mode 100644 index 63e1d52aa..000000000 --- a/src/multicast/gnunet-multicast.c +++ /dev/null | |||
@@ -1,79 +0,0 @@ | |||
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 | 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 deleted file mode 100644 index 18c366118..000000000 --- a/src/multicast/gnunet-service-multicast.c +++ /dev/null | |||
@@ -1,2234 +0,0 @@ | |||
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 | #include "platform.h" | ||
27 | #include "gnunet_util_lib.h" | ||
28 | #include "gnunet_signatures.h" | ||
29 | #include "gnunet_applications.h" | ||
30 | #include "gnunet_statistics_service.h" | ||
31 | #include "gnunet_cadet_service.h" | ||
32 | #include "gnunet_multicast_service.h" | ||
33 | #include "multicast.h" | ||
34 | |||
35 | /** | ||
36 | * Handle to our current configuration. | ||
37 | */ | ||
38 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
39 | |||
40 | /** | ||
41 | * Service handle. | ||
42 | */ | ||
43 | static struct GNUNET_SERVICE_Handle *service; | ||
44 | |||
45 | /** | ||
46 | * CADET handle. | ||
47 | */ | ||
48 | static struct GNUNET_CADET_Handle *cadet; | ||
49 | |||
50 | /** | ||
51 | * Identity of this peer. | ||
52 | */ | ||
53 | static struct GNUNET_PeerIdentity this_peer; | ||
54 | |||
55 | /** | ||
56 | * Handle to the statistics service. | ||
57 | */ | ||
58 | static struct GNUNET_STATISTICS_Handle *stats; | ||
59 | |||
60 | /** | ||
61 | * All connected origin clients. | ||
62 | * Group's pub_key_hash -> struct Origin * (uniq) | ||
63 | */ | ||
64 | static struct GNUNET_CONTAINER_MultiHashMap *origins; | ||
65 | |||
66 | /** | ||
67 | * All connected member clients. | ||
68 | * Group's pub_key_hash -> struct Member * (multi) | ||
69 | */ | ||
70 | static struct GNUNET_CONTAINER_MultiHashMap *members; | ||
71 | |||
72 | /** | ||
73 | * Connected member clients per group. | ||
74 | * Group's pub_key_hash -> Member's pub_key_hash (uniq) -> struct Member * (uniq) | ||
75 | */ | ||
76 | static struct GNUNET_CONTAINER_MultiHashMap *group_members; | ||
77 | |||
78 | /** | ||
79 | * Incoming CADET channels with connected children in the tree. | ||
80 | * Group's pub_key_hash -> struct Channel * (multi) | ||
81 | */ | ||
82 | static struct GNUNET_CONTAINER_MultiHashMap *channels_in; | ||
83 | |||
84 | /** | ||
85 | * Outgoing CADET channels connecting to parents in the tree. | ||
86 | * Group's pub_key_hash -> struct Channel * (multi) | ||
87 | */ | ||
88 | static struct GNUNET_CONTAINER_MultiHashMap *channels_out; | ||
89 | |||
90 | /** | ||
91 | * Incoming replay requests from CADET. | ||
92 | * Group's pub_key_hash -> | ||
93 | * H(fragment_id, message_id, fragment_offset, flags) -> struct Channel * | ||
94 | */ | ||
95 | static struct GNUNET_CONTAINER_MultiHashMap *replay_req_cadet; | ||
96 | |||
97 | /** | ||
98 | * Incoming replay requests from clients. | ||
99 | * Group's pub_key_hash -> | ||
100 | * H(fragment_id, message_id, fragment_offset, flags) -> struct GNUNET_SERVICE_Client * | ||
101 | */ | ||
102 | static struct GNUNET_CONTAINER_MultiHashMap *replay_req_client; | ||
103 | |||
104 | |||
105 | /** | ||
106 | * Join status of a remote peer. | ||
107 | */ | ||
108 | enum JoinStatus | ||
109 | { | ||
110 | JOIN_REFUSED = -1, | ||
111 | JOIN_NOT_ASKED = 0, | ||
112 | JOIN_WAITING = 1, | ||
113 | JOIN_ADMITTED = 2, | ||
114 | }; | ||
115 | |||
116 | enum ChannelDirection | ||
117 | { | ||
118 | DIR_INCOMING = 0, | ||
119 | DIR_OUTGOING = 1, | ||
120 | }; | ||
121 | |||
122 | |||
123 | /** | ||
124 | * Context for a CADET channel. | ||
125 | */ | ||
126 | struct Channel | ||
127 | { | ||
128 | /** | ||
129 | * Group the channel belongs to. | ||
130 | * | ||
131 | * Only set for outgoing channels. | ||
132 | */ | ||
133 | struct Group *group; | ||
134 | |||
135 | /** | ||
136 | * CADET channel. | ||
137 | */ | ||
138 | struct GNUNET_CADET_Channel *channel; | ||
139 | |||
140 | // FIXME: not used | ||
141 | /** | ||
142 | * CADET transmission handle. | ||
143 | */ | ||
144 | struct GNUNET_CADET_TransmitHandle *tmit_handle; | ||
145 | |||
146 | /** | ||
147 | * Public key of the target group. | ||
148 | */ | ||
149 | struct GNUNET_CRYPTO_EddsaPublicKey group_pub_key; | ||
150 | |||
151 | /** | ||
152 | * Hash of @a group_pub_key. | ||
153 | */ | ||
154 | struct GNUNET_HashCode group_pub_hash; | ||
155 | |||
156 | /** | ||
157 | * Public key of the joining member. | ||
158 | */ | ||
159 | struct GNUNET_CRYPTO_EcdsaPublicKey member_pub_key; | ||
160 | |||
161 | /** | ||
162 | * Remote peer identity. | ||
163 | */ | ||
164 | struct GNUNET_PeerIdentity peer; | ||
165 | |||
166 | /** | ||
167 | * Current window size, set by cadet_notify_window_change() | ||
168 | */ | ||
169 | int32_t window_size; | ||
170 | |||
171 | /** | ||
172 | * Is the connection established? | ||
173 | */ | ||
174 | int8_t is_connected; | ||
175 | |||
176 | /** | ||
177 | * Is the remote peer admitted to the group? | ||
178 | * @see enum JoinStatus | ||
179 | */ | ||
180 | int8_t join_status; | ||
181 | |||
182 | /** | ||
183 | * Number of messages waiting to be sent to CADET. | ||
184 | */ | ||
185 | uint8_t msgs_pending; | ||
186 | |||
187 | /** | ||
188 | * Channel direction. | ||
189 | * @see enum ChannelDirection | ||
190 | */ | ||
191 | uint8_t direction; | ||
192 | }; | ||
193 | |||
194 | |||
195 | /** | ||
196 | * List of connected clients. | ||
197 | */ | ||
198 | struct ClientList | ||
199 | { | ||
200 | struct ClientList *prev; | ||
201 | struct ClientList *next; | ||
202 | struct GNUNET_SERVICE_Client *client; | ||
203 | }; | ||
204 | |||
205 | |||
206 | /** | ||
207 | * Client context for an origin or member. | ||
208 | */ | ||
209 | struct Group | ||
210 | { | ||
211 | struct ClientList *clients_head; | ||
212 | struct ClientList *clients_tail; | ||
213 | |||
214 | /** | ||
215 | * Public key of the group. | ||
216 | */ | ||
217 | struct GNUNET_CRYPTO_EddsaPublicKey pub_key; | ||
218 | |||
219 | /** | ||
220 | * Hash of @a pub_key. | ||
221 | */ | ||
222 | struct GNUNET_HashCode pub_key_hash; | ||
223 | |||
224 | /** | ||
225 | * CADET port hash. | ||
226 | */ | ||
227 | struct GNUNET_HashCode cadet_port_hash; | ||
228 | |||
229 | /** | ||
230 | * Is the client disconnected? #GNUNET_YES or #GNUNET_NO | ||
231 | */ | ||
232 | uint8_t is_disconnected; | ||
233 | |||
234 | /** | ||
235 | * Is this an origin (#GNUNET_YES), or member (#GNUNET_NO)? | ||
236 | */ | ||
237 | uint8_t is_origin; | ||
238 | |||
239 | union { | ||
240 | struct Origin *origin; | ||
241 | struct Member *member; | ||
242 | }; | ||
243 | }; | ||
244 | |||
245 | |||
246 | /** | ||
247 | * Client context for a group's origin. | ||
248 | */ | ||
249 | struct Origin | ||
250 | { | ||
251 | struct Group group; | ||
252 | |||
253 | /** | ||
254 | * Private key of the group. | ||
255 | */ | ||
256 | struct GNUNET_CRYPTO_EddsaPrivateKey priv_key; | ||
257 | |||
258 | /** | ||
259 | * CADET port. | ||
260 | */ | ||
261 | struct GNUNET_CADET_Port *cadet_port; | ||
262 | |||
263 | /** | ||
264 | * Last message fragment ID sent to the group. | ||
265 | */ | ||
266 | uint64_t max_fragment_id; | ||
267 | }; | ||
268 | |||
269 | |||
270 | /** | ||
271 | * Client context for a group member. | ||
272 | */ | ||
273 | struct Member | ||
274 | { | ||
275 | struct Group group; | ||
276 | |||
277 | /** | ||
278 | * Private key of the member. | ||
279 | */ | ||
280 | struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key; | ||
281 | |||
282 | /** | ||
283 | * Public key of the member. | ||
284 | */ | ||
285 | struct GNUNET_CRYPTO_EcdsaPublicKey pub_key; | ||
286 | |||
287 | /** | ||
288 | * Hash of @a pub_key. | ||
289 | */ | ||
290 | struct GNUNET_HashCode pub_key_hash; | ||
291 | |||
292 | /** | ||
293 | * Join request sent to the origin / members. | ||
294 | */ | ||
295 | struct MulticastJoinRequestMessage *join_req; | ||
296 | |||
297 | /** | ||
298 | * Join decision sent in reply to our request. | ||
299 | * | ||
300 | * Only a positive decision is stored here, in case of a negative decision the | ||
301 | * client is disconnected. | ||
302 | */ | ||
303 | struct MulticastJoinDecisionMessageHeader *join_dcsn; | ||
304 | |||
305 | /** | ||
306 | * CADET channel to the origin. | ||
307 | */ | ||
308 | struct Channel *origin_channel; | ||
309 | |||
310 | /** | ||
311 | * Peer identity of origin. | ||
312 | */ | ||
313 | struct GNUNET_PeerIdentity origin; | ||
314 | |||
315 | /** | ||
316 | * Peer identity of relays (other members to connect). | ||
317 | */ | ||
318 | struct GNUNET_PeerIdentity *relays; | ||
319 | |||
320 | /** | ||
321 | * Last request fragment ID sent to the origin. | ||
322 | */ | ||
323 | uint64_t max_fragment_id; | ||
324 | |||
325 | /** | ||
326 | * Number of @a relays. | ||
327 | */ | ||
328 | uint32_t relay_count; | ||
329 | }; | ||
330 | |||
331 | |||
332 | /** | ||
333 | * Client context. | ||
334 | */ | ||
335 | struct Client { | ||
336 | struct GNUNET_SERVICE_Client *client; | ||
337 | struct Group *group; | ||
338 | }; | ||
339 | |||
340 | |||
341 | struct ReplayRequestKey | ||
342 | { | ||
343 | uint64_t fragment_id; | ||
344 | uint64_t message_id; | ||
345 | uint64_t fragment_offset; | ||
346 | uint64_t flags; | ||
347 | }; | ||
348 | |||
349 | |||
350 | static struct Channel * | ||
351 | cadet_channel_create (struct Group *grp, struct GNUNET_PeerIdentity *peer); | ||
352 | |||
353 | static void | ||
354 | cadet_channel_destroy (struct Channel *chn); | ||
355 | |||
356 | static void | ||
357 | client_send_join_decision (struct Member *mem, | ||
358 | const struct MulticastJoinDecisionMessageHeader *hdcsn); | ||
359 | |||
360 | |||
361 | /** | ||
362 | * Task run during shutdown. | ||
363 | * | ||
364 | * @param cls unused | ||
365 | */ | ||
366 | static void | ||
367 | shutdown_task (void *cls) | ||
368 | { | ||
369 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
370 | "shutting down\n"); | ||
371 | if (NULL != cadet) | ||
372 | { | ||
373 | GNUNET_CADET_disconnect (cadet); | ||
374 | cadet = NULL; | ||
375 | } | ||
376 | if (NULL != stats) | ||
377 | { | ||
378 | GNUNET_STATISTICS_destroy (stats, GNUNET_YES); | ||
379 | stats = NULL; | ||
380 | } | ||
381 | /* FIXME: do more clean up here */ | ||
382 | } | ||
383 | |||
384 | |||
385 | /** | ||
386 | * Clean up origin data structures after a client disconnected. | ||
387 | */ | ||
388 | static void | ||
389 | cleanup_origin (struct Origin *orig) | ||
390 | { | ||
391 | struct Group *grp = &orig->group; | ||
392 | GNUNET_CONTAINER_multihashmap_remove (origins, &grp->pub_key_hash, orig); | ||
393 | if (NULL != orig->cadet_port) | ||
394 | { | ||
395 | GNUNET_CADET_close_port (orig->cadet_port); | ||
396 | orig->cadet_port = NULL; | ||
397 | } | ||
398 | GNUNET_free (orig); | ||
399 | } | ||
400 | |||
401 | |||
402 | /** | ||
403 | * Clean up member data structures after a client disconnected. | ||
404 | */ | ||
405 | static void | ||
406 | cleanup_member (struct Member *mem) | ||
407 | { | ||
408 | struct Group *grp = &mem->group; | ||
409 | struct GNUNET_CONTAINER_MultiHashMap * | ||
410 | grp_mem = GNUNET_CONTAINER_multihashmap_get (group_members, | ||
411 | &grp->pub_key_hash); | ||
412 | GNUNET_assert (NULL != grp_mem); | ||
413 | GNUNET_CONTAINER_multihashmap_remove (grp_mem, &mem->pub_key_hash, mem); | ||
414 | |||
415 | if (0 == GNUNET_CONTAINER_multihashmap_size (grp_mem)) | ||
416 | { | ||
417 | GNUNET_CONTAINER_multihashmap_remove (group_members, &grp->pub_key_hash, | ||
418 | grp_mem); | ||
419 | GNUNET_CONTAINER_multihashmap_destroy (grp_mem); | ||
420 | } | ||
421 | if (NULL != mem->join_dcsn) | ||
422 | { | ||
423 | GNUNET_free (mem->join_dcsn); | ||
424 | mem->join_dcsn = NULL; | ||
425 | } | ||
426 | if (NULL != mem->origin_channel) | ||
427 | { | ||
428 | GNUNET_CADET_channel_destroy (mem->origin_channel->channel); | ||
429 | mem->origin_channel = NULL; | ||
430 | } | ||
431 | GNUNET_CONTAINER_multihashmap_remove (members, &grp->pub_key_hash, mem); | ||
432 | GNUNET_free (mem); | ||
433 | } | ||
434 | |||
435 | |||
436 | /** | ||
437 | * Clean up group data structures after a client disconnected. | ||
438 | */ | ||
439 | static void | ||
440 | cleanup_group (struct Group *grp) | ||
441 | { | ||
442 | (GNUNET_YES == grp->is_origin) | ||
443 | ? cleanup_origin (grp->origin) | ||
444 | : cleanup_member (grp->member); | ||
445 | } | ||
446 | |||
447 | |||
448 | void | ||
449 | replay_key_hash (uint64_t fragment_id, uint64_t message_id, | ||
450 | uint64_t fragment_offset, uint64_t flags, | ||
451 | struct GNUNET_HashCode *key_hash) | ||
452 | { | ||
453 | struct ReplayRequestKey key = { | ||
454 | .fragment_id = fragment_id, | ||
455 | .message_id = message_id, | ||
456 | .fragment_offset = fragment_offset, | ||
457 | .flags = flags, | ||
458 | }; | ||
459 | GNUNET_CRYPTO_hash (&key, sizeof (key), key_hash); | ||
460 | } | ||
461 | |||
462 | |||
463 | /** | ||
464 | * Remove channel from replay request hashmap. | ||
465 | * | ||
466 | * @param chn | ||
467 | * Channel to remove. | ||
468 | * | ||
469 | * @return #GNUNET_YES if there are more entries to process, | ||
470 | * #GNUNET_NO when reached end of hashmap. | ||
471 | */ | ||
472 | static int | ||
473 | replay_req_remove_cadet (struct Channel *chn) | ||
474 | { | ||
475 | if (NULL == chn || NULL == chn->group) | ||
476 | return GNUNET_SYSERR; | ||
477 | |||
478 | struct GNUNET_CONTAINER_MultiHashMap * | ||
479 | grp_replay_req = GNUNET_CONTAINER_multihashmap_get (replay_req_cadet, | ||
480 | &chn->group->pub_key_hash); | ||
481 | if (NULL == grp_replay_req) | ||
482 | return GNUNET_NO; | ||
483 | |||
484 | struct GNUNET_CONTAINER_MultiHashMapIterator * | ||
485 | it = GNUNET_CONTAINER_multihashmap_iterator_create (grp_replay_req); | ||
486 | struct GNUNET_HashCode key; | ||
487 | const struct Channel *c; | ||
488 | while (GNUNET_YES | ||
489 | == GNUNET_CONTAINER_multihashmap_iterator_next (it, &key, | ||
490 | (const void **) &c)) | ||
491 | { | ||
492 | if (c == chn) | ||
493 | { | ||
494 | GNUNET_CONTAINER_multihashmap_remove (grp_replay_req, &key, chn); | ||
495 | GNUNET_CONTAINER_multihashmap_iterator_destroy (it); | ||
496 | return GNUNET_YES; | ||
497 | } | ||
498 | } | ||
499 | GNUNET_CONTAINER_multihashmap_iterator_destroy (it); | ||
500 | return GNUNET_NO; | ||
501 | } | ||
502 | |||
503 | |||
504 | /** | ||
505 | * Remove client from replay request hashmap. | ||
506 | * | ||
507 | * @param client | ||
508 | * Client to remove. | ||
509 | * | ||
510 | * @return #GNUNET_YES if there are more entries to process, | ||
511 | * #GNUNET_NO when reached end of hashmap. | ||
512 | */ | ||
513 | static int | ||
514 | replay_req_remove_client (struct Group *grp, struct GNUNET_SERVICE_Client *client) | ||
515 | { | ||
516 | struct GNUNET_CONTAINER_MultiHashMap * | ||
517 | grp_replay_req = GNUNET_CONTAINER_multihashmap_get (replay_req_client, | ||
518 | &grp->pub_key_hash); | ||
519 | if (NULL == grp_replay_req) | ||
520 | return GNUNET_NO; | ||
521 | |||
522 | struct GNUNET_CONTAINER_MultiHashMapIterator * | ||
523 | it = GNUNET_CONTAINER_multihashmap_iterator_create (grp_replay_req); | ||
524 | struct GNUNET_HashCode key; | ||
525 | const struct GNUNET_SERVICE_Client *c; | ||
526 | while (GNUNET_YES | ||
527 | == GNUNET_CONTAINER_multihashmap_iterator_next (it, &key, | ||
528 | (const void **) &c)) | ||
529 | { | ||
530 | if (c == client) | ||
531 | { | ||
532 | GNUNET_CONTAINER_multihashmap_remove (grp_replay_req, &key, client); | ||
533 | GNUNET_CONTAINER_multihashmap_iterator_destroy (it); | ||
534 | return GNUNET_YES; | ||
535 | } | ||
536 | } | ||
537 | GNUNET_CONTAINER_multihashmap_iterator_destroy (it); | ||
538 | return GNUNET_NO; | ||
539 | } | ||
540 | |||
541 | |||
542 | /** | ||
543 | * Send message to a client. | ||
544 | */ | ||
545 | static void | ||
546 | client_send (struct GNUNET_SERVICE_Client *client, | ||
547 | const struct GNUNET_MessageHeader *msg) | ||
548 | { | ||
549 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
550 | "%p Sending message to client.\n", client); | ||
551 | |||
552 | struct GNUNET_MQ_Envelope * | ||
553 | env = GNUNET_MQ_msg_copy (msg); | ||
554 | |||
555 | GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), | ||
556 | env); | ||
557 | } | ||
558 | |||
559 | |||
560 | /** | ||
561 | * Send message to all clients connected to the group. | ||
562 | */ | ||
563 | static void | ||
564 | client_send_group_keep_envelope (const struct Group *grp, | ||
565 | struct GNUNET_MQ_Envelope *env) | ||
566 | { | ||
567 | struct ClientList *cli = grp->clients_head; | ||
568 | |||
569 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
570 | "%p Sending message to all clients of the group.\n", | ||
571 | grp); | ||
572 | while (NULL != cli) | ||
573 | { | ||
574 | GNUNET_MQ_send_copy (GNUNET_SERVICE_client_get_mq (cli->client), | ||
575 | env); | ||
576 | cli = cli->next; | ||
577 | } | ||
578 | } | ||
579 | |||
580 | |||
581 | /** | ||
582 | * Send message to all clients connected to the group and | ||
583 | * takes care of freeing @env. | ||
584 | */ | ||
585 | static void | ||
586 | client_send_group (const struct Group *grp, | ||
587 | struct GNUNET_MQ_Envelope *env) | ||
588 | { | ||
589 | client_send_group_keep_envelope (grp, env); | ||
590 | GNUNET_MQ_discard (env); | ||
591 | } | ||
592 | |||
593 | |||
594 | /** | ||
595 | * Iterator callback for sending a message to origin clients. | ||
596 | */ | ||
597 | static int | ||
598 | client_send_origin_cb (void *cls, const struct GNUNET_HashCode *pub_key_hash, | ||
599 | void *origin) | ||
600 | { | ||
601 | struct GNUNET_MQ_Envelope *env = cls; | ||
602 | struct Member *orig = origin; | ||
603 | |||
604 | client_send_group_keep_envelope (&orig->group, env); | ||
605 | return GNUNET_YES; | ||
606 | } | ||
607 | |||
608 | |||
609 | /** | ||
610 | * Iterator callback for sending a message to member clients. | ||
611 | */ | ||
612 | static int | ||
613 | client_send_member_cb (void *cls, const struct GNUNET_HashCode *pub_key_hash, | ||
614 | void *member) | ||
615 | { | ||
616 | struct GNUNET_MQ_Envelope *env = cls; | ||
617 | struct Member *mem = member; | ||
618 | |||
619 | if (NULL != mem->join_dcsn) | ||
620 | { /* Only send message to admitted members */ | ||
621 | client_send_group_keep_envelope (&mem->group, env); | ||
622 | } | ||
623 | return GNUNET_YES; | ||
624 | } | ||
625 | |||
626 | |||
627 | /** | ||
628 | * Send message to all origin and member clients connected to the group. | ||
629 | * | ||
630 | * @param pub_key_hash | ||
631 | * H(key_pub) of the group. | ||
632 | * @param msg | ||
633 | * Message to send. | ||
634 | */ | ||
635 | static int | ||
636 | client_send_all (struct GNUNET_HashCode *pub_key_hash, | ||
637 | struct GNUNET_MQ_Envelope *env) | ||
638 | { | ||
639 | int n = 0; | ||
640 | n += GNUNET_CONTAINER_multihashmap_get_multiple (origins, pub_key_hash, | ||
641 | client_send_origin_cb, | ||
642 | (void *) env); | ||
643 | n += GNUNET_CONTAINER_multihashmap_get_multiple (members, pub_key_hash, | ||
644 | client_send_member_cb, | ||
645 | (void *) env); | ||
646 | GNUNET_MQ_discard (env); | ||
647 | return n; | ||
648 | } | ||
649 | |||
650 | |||
651 | /** | ||
652 | * Send message to a random origin client or a random member client. | ||
653 | * | ||
654 | * @param grp The group to send @a msg to. | ||
655 | * @param msg Message to send. | ||
656 | */ | ||
657 | static int | ||
658 | client_send_random (struct GNUNET_HashCode *pub_key_hash, | ||
659 | struct GNUNET_MQ_Envelope *env) | ||
660 | { | ||
661 | int n = 0; | ||
662 | n = GNUNET_CONTAINER_multihashmap_get_random (origins, client_send_origin_cb, | ||
663 | (void *) env); | ||
664 | if (n <= 0) | ||
665 | n = GNUNET_CONTAINER_multihashmap_get_random (members, client_send_member_cb, | ||
666 | (void *) env); | ||
667 | GNUNET_MQ_discard (env); | ||
668 | return n; | ||
669 | } | ||
670 | |||
671 | |||
672 | /** | ||
673 | * Send message to all origin clients connected to the group. | ||
674 | * | ||
675 | * @param pub_key_hash | ||
676 | * H(key_pub) of the group. | ||
677 | * @param msg | ||
678 | * Message to send. | ||
679 | */ | ||
680 | static int | ||
681 | client_send_origin (struct GNUNET_HashCode *pub_key_hash, | ||
682 | struct GNUNET_MQ_Envelope *env) | ||
683 | { | ||
684 | int n = 0; | ||
685 | n += GNUNET_CONTAINER_multihashmap_get_multiple (origins, pub_key_hash, | ||
686 | client_send_origin_cb, | ||
687 | (void *) env); | ||
688 | return n; | ||
689 | } | ||
690 | |||
691 | |||
692 | /** | ||
693 | * Send fragment acknowledgement to all clients of the channel. | ||
694 | * | ||
695 | * @param pub_key_hash | ||
696 | * H(key_pub) of the group. | ||
697 | */ | ||
698 | static void | ||
699 | client_send_ack (struct GNUNET_HashCode *pub_key_hash) | ||
700 | { | ||
701 | struct GNUNET_MQ_Envelope *env; | ||
702 | |||
703 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
704 | "Sending message ACK to client.\n"); | ||
705 | env = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_MULTICAST_FRAGMENT_ACK); | ||
706 | client_send_all (pub_key_hash, env); | ||
707 | } | ||
708 | |||
709 | |||
710 | struct CadetTransmitClosure | ||
711 | { | ||
712 | struct Channel *chn; | ||
713 | const struct GNUNET_MessageHeader *msg; | ||
714 | }; | ||
715 | |||
716 | |||
717 | /** | ||
718 | * Send a message to a CADET channel. | ||
719 | * | ||
720 | * @param chn Channel. | ||
721 | * @param msg Message. | ||
722 | */ | ||
723 | static void | ||
724 | cadet_send_channel (struct Channel *chn, const struct GNUNET_MessageHeader *msg) | ||
725 | { | ||
726 | struct GNUNET_MQ_Envelope * | ||
727 | env = GNUNET_MQ_msg_copy (msg); | ||
728 | |||
729 | GNUNET_MQ_send (GNUNET_CADET_get_mq (chn->channel), env); | ||
730 | |||
731 | if (0 < chn->window_size) | ||
732 | { | ||
733 | client_send_ack (&chn->group_pub_hash); | ||
734 | } | ||
735 | else | ||
736 | { | ||
737 | chn->msgs_pending++; | ||
738 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
739 | "%p Queuing message. Pending messages: %u\n", | ||
740 | chn, chn->msgs_pending); | ||
741 | } | ||
742 | } | ||
743 | |||
744 | |||
745 | /** | ||
746 | * Create CADET channel and send a join request. | ||
747 | */ | ||
748 | static void | ||
749 | cadet_send_join_request (struct Member *mem) | ||
750 | { | ||
751 | mem->origin_channel = cadet_channel_create (&mem->group, &mem->origin); | ||
752 | cadet_send_channel (mem->origin_channel, &mem->join_req->header); | ||
753 | |||
754 | uint32_t i; | ||
755 | for (i = 0; i < mem->relay_count; i++) | ||
756 | { | ||
757 | struct Channel * | ||
758 | chn = cadet_channel_create (&mem->group, &mem->relays[i]); | ||
759 | cadet_send_channel (chn, &mem->join_req->header); | ||
760 | } | ||
761 | } | ||
762 | |||
763 | |||
764 | static int | ||
765 | cadet_send_join_decision_cb (void *cls, | ||
766 | const struct GNUNET_HashCode *group_pub_hash, | ||
767 | void *channel) | ||
768 | { | ||
769 | const struct MulticastJoinDecisionMessageHeader *hdcsn = cls; | ||
770 | struct Channel *chn = channel; | ||
771 | |||
772 | const struct MulticastJoinDecisionMessage *dcsn = | ||
773 | (struct MulticastJoinDecisionMessage *) &hdcsn[1]; | ||
774 | |||
775 | if (0 == memcmp (&hdcsn->member_pub_key, &chn->member_pub_key, sizeof (chn->member_pub_key)) | ||
776 | && 0 == memcmp (&hdcsn->peer, &chn->peer, sizeof (chn->peer))) | ||
777 | { | ||
778 | if (GNUNET_YES == ntohl (dcsn->is_admitted)) | ||
779 | { | ||
780 | chn->join_status = JOIN_ADMITTED; | ||
781 | } | ||
782 | else | ||
783 | { | ||
784 | chn->join_status = JOIN_REFUSED; | ||
785 | } | ||
786 | cadet_send_channel (chn, &hdcsn->header); | ||
787 | return GNUNET_YES; | ||
788 | } | ||
789 | |||
790 | // return GNUNET_YES to continue the multihashmap_get iteration | ||
791 | return GNUNET_YES; | ||
792 | } | ||
793 | |||
794 | |||
795 | /** | ||
796 | * Send join decision to a remote peer. | ||
797 | */ | ||
798 | static void | ||
799 | cadet_send_join_decision (struct Group *grp, | ||
800 | const struct MulticastJoinDecisionMessageHeader *hdcsn) | ||
801 | { | ||
802 | GNUNET_CONTAINER_multihashmap_get_multiple (channels_in, &grp->pub_key_hash, | ||
803 | &cadet_send_join_decision_cb, | ||
804 | (void *) hdcsn); | ||
805 | } | ||
806 | |||
807 | |||
808 | /** | ||
809 | * Iterator callback for sending a message to origin clients. | ||
810 | */ | ||
811 | static int | ||
812 | cadet_send_cb (void *cls, const struct GNUNET_HashCode *pub_key_hash, | ||
813 | void *channel) | ||
814 | { | ||
815 | const struct GNUNET_MessageHeader *msg = cls; | ||
816 | struct Channel *chn = channel; | ||
817 | if (JOIN_ADMITTED == chn->join_status) | ||
818 | cadet_send_channel (chn, msg); | ||
819 | return GNUNET_YES; | ||
820 | } | ||
821 | |||
822 | |||
823 | /** | ||
824 | * Send message to all connected children. | ||
825 | */ | ||
826 | static int | ||
827 | cadet_send_children (struct GNUNET_HashCode *pub_key_hash, | ||
828 | const struct GNUNET_MessageHeader *msg) | ||
829 | { | ||
830 | int n = 0; | ||
831 | if (channels_in != NULL) | ||
832 | n += GNUNET_CONTAINER_multihashmap_get_multiple (channels_in, pub_key_hash, | ||
833 | cadet_send_cb, (void *) msg); | ||
834 | return n; | ||
835 | } | ||
836 | |||
837 | |||
838 | #if 0 // unused as yet | ||
839 | /** | ||
840 | * Send message to all connected parents. | ||
841 | */ | ||
842 | static int | ||
843 | cadet_send_parents (struct GNUNET_HashCode *pub_key_hash, | ||
844 | const struct GNUNET_MessageHeader *msg) | ||
845 | { | ||
846 | int n = 0; | ||
847 | if (channels_in != NULL) | ||
848 | n += GNUNET_CONTAINER_multihashmap_get_multiple (channels_out, pub_key_hash, | ||
849 | cadet_send_cb, (void *) msg); | ||
850 | return n; | ||
851 | } | ||
852 | #endif | ||
853 | |||
854 | |||
855 | /** | ||
856 | * CADET channel connect handler. | ||
857 | * | ||
858 | * @see GNUNET_CADET_ConnectEventHandler() | ||
859 | */ | ||
860 | static void * | ||
861 | cadet_notify_connect (void *cls, | ||
862 | struct GNUNET_CADET_Channel *channel, | ||
863 | const struct GNUNET_PeerIdentity *source) | ||
864 | { | ||
865 | struct Channel *chn = GNUNET_malloc (sizeof (struct Channel)); | ||
866 | chn->group = cls; | ||
867 | chn->channel = channel; | ||
868 | chn->direction = DIR_INCOMING; | ||
869 | chn->join_status = JOIN_NOT_ASKED; | ||
870 | |||
871 | GNUNET_CONTAINER_multihashmap_put (channels_in, &chn->group->pub_key_hash, chn, | ||
872 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
873 | return chn; | ||
874 | } | ||
875 | |||
876 | |||
877 | /** | ||
878 | * CADET window size change handler. | ||
879 | * | ||
880 | * @see GNUNET_CADET_WindowSizeEventHandler() | ||
881 | */ | ||
882 | static void | ||
883 | cadet_notify_window_change (void *cls, | ||
884 | const struct GNUNET_CADET_Channel *channel, | ||
885 | int window_size) | ||
886 | { | ||
887 | struct Channel *chn = cls; | ||
888 | |||
889 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
890 | "%p Window size changed to %d. Pending messages: %u\n", | ||
891 | chn, window_size, chn->msgs_pending); | ||
892 | |||
893 | chn->is_connected = GNUNET_YES; | ||
894 | chn->window_size = (int32_t) window_size; | ||
895 | |||
896 | for (int i = 0; i < window_size; i++) | ||
897 | { | ||
898 | if (0 < chn->msgs_pending) | ||
899 | { | ||
900 | client_send_ack (&chn->group_pub_hash); | ||
901 | chn->msgs_pending--; | ||
902 | } | ||
903 | else | ||
904 | { | ||
905 | break; | ||
906 | } | ||
907 | } | ||
908 | } | ||
909 | |||
910 | |||
911 | /** | ||
912 | * CADET channel disconnect handler. | ||
913 | * | ||
914 | * @see GNUNET_CADET_DisconnectEventHandler() | ||
915 | */ | ||
916 | static void | ||
917 | cadet_notify_disconnect (void *cls, | ||
918 | const struct GNUNET_CADET_Channel *channel) | ||
919 | { | ||
920 | if (NULL == cls) | ||
921 | return; | ||
922 | |||
923 | struct Channel *chn = cls; | ||
924 | if (NULL != chn->group) | ||
925 | { | ||
926 | if (GNUNET_NO == chn->group->is_origin) | ||
927 | { | ||
928 | struct Member *mem = (struct Member *) chn->group; | ||
929 | if (chn == mem->origin_channel) | ||
930 | mem->origin_channel = NULL; | ||
931 | } | ||
932 | } | ||
933 | |||
934 | int ret; | ||
935 | do | ||
936 | { | ||
937 | ret = replay_req_remove_cadet (chn); | ||
938 | } | ||
939 | while (GNUNET_YES == ret); | ||
940 | |||
941 | GNUNET_free (chn); | ||
942 | } | ||
943 | |||
944 | |||
945 | static int | ||
946 | check_cadet_join_request (void *cls, | ||
947 | const struct MulticastJoinRequestMessage *req) | ||
948 | { | ||
949 | struct Channel *chn = cls; | ||
950 | |||
951 | if (NULL == chn | ||
952 | || JOIN_NOT_ASKED != chn->join_status) | ||
953 | { | ||
954 | return GNUNET_SYSERR; | ||
955 | } | ||
956 | |||
957 | uint16_t size = ntohs (req->header.size); | ||
958 | if (size < sizeof (*req)) | ||
959 | { | ||
960 | GNUNET_break_op (0); | ||
961 | return GNUNET_SYSERR; | ||
962 | } | ||
963 | if (ntohl (req->purpose.size) != (size | ||
964 | - sizeof (req->header) | ||
965 | - sizeof (req->reserved) | ||
966 | - sizeof (req->signature))) | ||
967 | { | ||
968 | GNUNET_break_op (0); | ||
969 | return GNUNET_SYSERR; | ||
970 | } | ||
971 | if (GNUNET_OK != | ||
972 | GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_MULTICAST_REQUEST, | ||
973 | &req->purpose, &req->signature, | ||
974 | &req->member_pub_key)) | ||
975 | { | ||
976 | GNUNET_break_op (0); | ||
977 | return GNUNET_SYSERR; | ||
978 | } | ||
979 | |||
980 | return GNUNET_OK; | ||
981 | } | ||
982 | |||
983 | |||
984 | /** | ||
985 | * Incoming join request message from CADET. | ||
986 | */ | ||
987 | static void | ||
988 | handle_cadet_join_request (void *cls, | ||
989 | const struct MulticastJoinRequestMessage *req) | ||
990 | { | ||
991 | struct Channel *chn = cls; | ||
992 | GNUNET_CADET_receive_done (chn->channel); | ||
993 | |||
994 | struct GNUNET_HashCode group_pub_hash; | ||
995 | GNUNET_CRYPTO_hash (&req->group_pub_key, sizeof (req->group_pub_key), &group_pub_hash); | ||
996 | chn->group_pub_key = req->group_pub_key; | ||
997 | chn->group_pub_hash = group_pub_hash; | ||
998 | chn->member_pub_key = req->member_pub_key; | ||
999 | chn->peer = req->peer; | ||
1000 | chn->join_status = JOIN_WAITING; | ||
1001 | |||
1002 | client_send_all (&group_pub_hash, | ||
1003 | GNUNET_MQ_msg_copy (&req->header)); | ||
1004 | } | ||
1005 | |||
1006 | |||
1007 | static int | ||
1008 | check_cadet_join_decision (void *cls, | ||
1009 | const struct MulticastJoinDecisionMessageHeader *hdcsn) | ||
1010 | { | ||
1011 | uint16_t size = ntohs (hdcsn->header.size); | ||
1012 | if (size < sizeof (struct MulticastJoinDecisionMessageHeader) + | ||
1013 | sizeof (struct MulticastJoinDecisionMessage)) | ||
1014 | { | ||
1015 | GNUNET_break_op (0); | ||
1016 | return GNUNET_SYSERR; | ||
1017 | } | ||
1018 | |||
1019 | struct Channel *chn = cls; | ||
1020 | if (NULL == chn) | ||
1021 | { | ||
1022 | GNUNET_break (0); | ||
1023 | return GNUNET_SYSERR; | ||
1024 | } | ||
1025 | if (NULL == chn->group || GNUNET_NO != chn->group->is_origin) | ||
1026 | { | ||
1027 | GNUNET_break (0); | ||
1028 | return GNUNET_SYSERR; | ||
1029 | } | ||
1030 | switch (chn->join_status) | ||
1031 | { | ||
1032 | case JOIN_REFUSED: | ||
1033 | return GNUNET_SYSERR; | ||
1034 | |||
1035 | case JOIN_ADMITTED: | ||
1036 | return GNUNET_OK; | ||
1037 | |||
1038 | case JOIN_NOT_ASKED: | ||
1039 | case JOIN_WAITING: | ||
1040 | break; | ||
1041 | } | ||
1042 | |||
1043 | return GNUNET_OK; | ||
1044 | } | ||
1045 | |||
1046 | |||
1047 | /** | ||
1048 | * Incoming join decision message from CADET. | ||
1049 | */ | ||
1050 | static void | ||
1051 | handle_cadet_join_decision (void *cls, | ||
1052 | const struct MulticastJoinDecisionMessageHeader *hdcsn) | ||
1053 | { | ||
1054 | const struct MulticastJoinDecisionMessage * | ||
1055 | dcsn = (const struct MulticastJoinDecisionMessage *) &hdcsn[1]; | ||
1056 | |||
1057 | struct Channel *chn = cls; | ||
1058 | GNUNET_CADET_receive_done (chn->channel); | ||
1059 | |||
1060 | // FIXME: do we need to copy chn->peer or compare it with hdcsn->peer? | ||
1061 | struct Member *mem = (struct Member *) chn->group; | ||
1062 | client_send_join_decision (mem, hdcsn); | ||
1063 | if (GNUNET_YES == ntohl (dcsn->is_admitted)) | ||
1064 | { | ||
1065 | chn->join_status = JOIN_ADMITTED; | ||
1066 | } | ||
1067 | else | ||
1068 | { | ||
1069 | chn->join_status = JOIN_REFUSED; | ||
1070 | cadet_channel_destroy (chn); | ||
1071 | } | ||
1072 | } | ||
1073 | |||
1074 | |||
1075 | static int | ||
1076 | check_cadet_message (void *cls, | ||
1077 | const struct GNUNET_MULTICAST_MessageHeader *msg) | ||
1078 | { | ||
1079 | uint16_t size = ntohs (msg->header.size); | ||
1080 | if (size < sizeof (*msg)) | ||
1081 | { | ||
1082 | GNUNET_break_op (0); | ||
1083 | return GNUNET_SYSERR; | ||
1084 | } | ||
1085 | |||
1086 | struct Channel *chn = cls; | ||
1087 | if (NULL == chn) | ||
1088 | { | ||
1089 | GNUNET_break (0); | ||
1090 | return GNUNET_SYSERR; | ||
1091 | } | ||
1092 | if (ntohl (msg->purpose.size) != (size | ||
1093 | - sizeof (msg->header) | ||
1094 | - sizeof (msg->hop_counter) | ||
1095 | - sizeof (msg->signature))) | ||
1096 | { | ||
1097 | GNUNET_break_op (0); | ||
1098 | return GNUNET_SYSERR; | ||
1099 | } | ||
1100 | if (GNUNET_OK != | ||
1101 | GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_MULTICAST_MESSAGE, | ||
1102 | &msg->purpose, &msg->signature, | ||
1103 | &chn->group_pub_key)) | ||
1104 | { | ||
1105 | GNUNET_break_op (0); | ||
1106 | return GNUNET_SYSERR; | ||
1107 | } | ||
1108 | |||
1109 | return GNUNET_OK; | ||
1110 | } | ||
1111 | |||
1112 | |||
1113 | /** | ||
1114 | * Incoming multicast message from CADET. | ||
1115 | */ | ||
1116 | static void | ||
1117 | handle_cadet_message (void *cls, | ||
1118 | const struct GNUNET_MULTICAST_MessageHeader *msg) | ||
1119 | { | ||
1120 | struct Channel *chn = cls; | ||
1121 | GNUNET_CADET_receive_done (chn->channel); | ||
1122 | client_send_all (&chn->group_pub_hash, | ||
1123 | GNUNET_MQ_msg_copy (&msg->header)); | ||
1124 | } | ||
1125 | |||
1126 | |||
1127 | static int | ||
1128 | check_cadet_request (void *cls, | ||
1129 | const struct GNUNET_MULTICAST_RequestHeader *req) | ||
1130 | { | ||
1131 | uint16_t size = ntohs (req->header.size); | ||
1132 | if (size < sizeof (*req)) | ||
1133 | { | ||
1134 | GNUNET_break_op (0); | ||
1135 | return GNUNET_SYSERR; | ||
1136 | } | ||
1137 | |||
1138 | struct Channel *chn = cls; | ||
1139 | if (NULL == chn) | ||
1140 | { | ||
1141 | GNUNET_break (0); | ||
1142 | return GNUNET_SYSERR; | ||
1143 | } | ||
1144 | if (ntohl (req->purpose.size) != (size | ||
1145 | - sizeof (req->header) | ||
1146 | - sizeof (req->member_pub_key) | ||
1147 | - sizeof (req->signature))) | ||
1148 | { | ||
1149 | GNUNET_break_op (0); | ||
1150 | return GNUNET_SYSERR; | ||
1151 | } | ||
1152 | if (GNUNET_OK != | ||
1153 | GNUNET_CRYPTO_ecdsa_verify (GNUNET_SIGNATURE_PURPOSE_MULTICAST_REQUEST, | ||
1154 | &req->purpose, &req->signature, | ||
1155 | &req->member_pub_key)) | ||
1156 | { | ||
1157 | GNUNET_break_op (0); | ||
1158 | return GNUNET_SYSERR; | ||
1159 | } | ||
1160 | |||
1161 | return GNUNET_OK; | ||
1162 | } | ||
1163 | |||
1164 | |||
1165 | /** | ||
1166 | * Incoming multicast request message from CADET. | ||
1167 | */ | ||
1168 | static void | ||
1169 | handle_cadet_request (void *cls, | ||
1170 | const struct GNUNET_MULTICAST_RequestHeader *req) | ||
1171 | { | ||
1172 | struct Channel *chn = cls; | ||
1173 | GNUNET_CADET_receive_done (chn->channel); | ||
1174 | client_send_origin (&chn->group_pub_hash, | ||
1175 | GNUNET_MQ_msg_copy (&req->header)); | ||
1176 | } | ||
1177 | |||
1178 | |||
1179 | // FIXME: do checks in handle_cadet_replay_request | ||
1180 | //static int | ||
1181 | //check_cadet_replay_request (void *cls, | ||
1182 | // const struct MulticastReplayRequestMessage *req) | ||
1183 | //{ | ||
1184 | // uint16_t size = ntohs (req->header.size); | ||
1185 | // if (size < sizeof (*req)) | ||
1186 | // { | ||
1187 | // GNUNET_break_op (0); | ||
1188 | // return GNUNET_SYSERR; | ||
1189 | // } | ||
1190 | // | ||
1191 | // struct Channel *chn = cls; | ||
1192 | // if (NULL == chn) | ||
1193 | // { | ||
1194 | // GNUNET_break_op (0); | ||
1195 | // return GNUNET_SYSERR; | ||
1196 | // } | ||
1197 | // | ||
1198 | // return GNUNET_OK; | ||
1199 | //} | ||
1200 | |||
1201 | |||
1202 | /** | ||
1203 | * Incoming multicast replay request from CADET. | ||
1204 | */ | ||
1205 | static void | ||
1206 | handle_cadet_replay_request (void *cls, | ||
1207 | const struct MulticastReplayRequestMessage *req) | ||
1208 | { | ||
1209 | struct Channel *chn = cls; | ||
1210 | |||
1211 | GNUNET_CADET_receive_done (chn->channel); | ||
1212 | |||
1213 | struct MulticastReplayRequestMessage rep = *req; | ||
1214 | GNUNET_memcpy (&rep.member_pub_key, &chn->member_pub_key, sizeof (chn->member_pub_key)); | ||
1215 | |||
1216 | struct GNUNET_CONTAINER_MultiHashMap * | ||
1217 | grp_replay_req = GNUNET_CONTAINER_multihashmap_get (replay_req_cadet, | ||
1218 | &chn->group->pub_key_hash); | ||
1219 | if (NULL == grp_replay_req) | ||
1220 | { | ||
1221 | grp_replay_req = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); | ||
1222 | GNUNET_CONTAINER_multihashmap_put (replay_req_cadet, | ||
1223 | &chn->group->pub_key_hash, grp_replay_req, | ||
1224 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); | ||
1225 | } | ||
1226 | struct GNUNET_HashCode key_hash; | ||
1227 | replay_key_hash (rep.fragment_id, | ||
1228 | rep.message_id, | ||
1229 | rep.fragment_offset, | ||
1230 | rep.flags, | ||
1231 | &key_hash); | ||
1232 | GNUNET_CONTAINER_multihashmap_put (grp_replay_req, &key_hash, chn, | ||
1233 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
1234 | |||
1235 | client_send_random (&chn->group_pub_hash, | ||
1236 | GNUNET_MQ_msg_copy (&rep.header)); | ||
1237 | } | ||
1238 | |||
1239 | |||
1240 | static int | ||
1241 | check_cadet_replay_response (void *cls, | ||
1242 | const struct MulticastReplayResponseMessage *res) | ||
1243 | { | ||
1244 | struct Channel *chn = cls; | ||
1245 | if (NULL == chn) | ||
1246 | { | ||
1247 | GNUNET_break (0); | ||
1248 | return GNUNET_SYSERR; | ||
1249 | } | ||
1250 | return GNUNET_OK; | ||
1251 | } | ||
1252 | |||
1253 | |||
1254 | /** | ||
1255 | * Incoming multicast replay response from CADET. | ||
1256 | */ | ||
1257 | static void | ||
1258 | handle_cadet_replay_response (void *cls, | ||
1259 | const struct MulticastReplayResponseMessage *res) | ||
1260 | { | ||
1261 | struct Channel *chn = cls; | ||
1262 | GNUNET_CADET_receive_done (chn->channel); | ||
1263 | |||
1264 | /* @todo FIXME: got replay error response, send request to other members */ | ||
1265 | } | ||
1266 | |||
1267 | |||
1268 | static void | ||
1269 | group_set_cadet_port_hash (struct Group *grp) | ||
1270 | { | ||
1271 | struct CadetPort { | ||
1272 | struct GNUNET_CRYPTO_EddsaPublicKey pub_key; | ||
1273 | uint32_t app_type; | ||
1274 | } port = { | ||
1275 | grp->pub_key, | ||
1276 | GNUNET_APPLICATION_TYPE_MULTICAST, | ||
1277 | }; | ||
1278 | GNUNET_CRYPTO_hash (&port, sizeof (port), &grp->cadet_port_hash); | ||
1279 | } | ||
1280 | |||
1281 | |||
1282 | |||
1283 | /** | ||
1284 | * Create new outgoing CADET channel. | ||
1285 | * | ||
1286 | * @param peer | ||
1287 | * Peer to connect to. | ||
1288 | * @param group_pub_key | ||
1289 | * Public key of group the channel belongs to. | ||
1290 | * @param group_pub_hash | ||
1291 | * Hash of @a group_pub_key. | ||
1292 | * | ||
1293 | * @return Channel. | ||
1294 | */ | ||
1295 | static struct Channel * | ||
1296 | cadet_channel_create (struct Group *grp, struct GNUNET_PeerIdentity *peer) | ||
1297 | { | ||
1298 | struct Channel *chn = GNUNET_malloc (sizeof (*chn)); | ||
1299 | chn->group = grp; | ||
1300 | chn->group_pub_key = grp->pub_key; | ||
1301 | chn->group_pub_hash = grp->pub_key_hash; | ||
1302 | chn->peer = *peer; | ||
1303 | chn->direction = DIR_OUTGOING; | ||
1304 | chn->is_connected = GNUNET_NO; | ||
1305 | chn->join_status = JOIN_WAITING; | ||
1306 | |||
1307 | struct GNUNET_MQ_MessageHandler cadet_handlers[] = { | ||
1308 | GNUNET_MQ_hd_var_size (cadet_message, | ||
1309 | GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE, | ||
1310 | struct GNUNET_MULTICAST_MessageHeader, | ||
1311 | chn), | ||
1312 | |||
1313 | GNUNET_MQ_hd_var_size (cadet_join_decision, | ||
1314 | GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION, | ||
1315 | struct MulticastJoinDecisionMessageHeader, | ||
1316 | chn), | ||
1317 | |||
1318 | GNUNET_MQ_hd_fixed_size (cadet_replay_request, | ||
1319 | GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_REQUEST, | ||
1320 | struct MulticastReplayRequestMessage, | ||
1321 | chn), | ||
1322 | |||
1323 | GNUNET_MQ_hd_var_size (cadet_replay_response, | ||
1324 | GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE, | ||
1325 | struct MulticastReplayResponseMessage, | ||
1326 | chn), | ||
1327 | |||
1328 | GNUNET_MQ_handler_end () | ||
1329 | }; | ||
1330 | |||
1331 | chn->channel = GNUNET_CADET_channel_create (cadet, chn, &chn->peer, | ||
1332 | &grp->cadet_port_hash, | ||
1333 | GNUNET_CADET_OPTION_RELIABLE, | ||
1334 | cadet_notify_window_change, | ||
1335 | cadet_notify_disconnect, | ||
1336 | cadet_handlers); | ||
1337 | GNUNET_CONTAINER_multihashmap_put (channels_out, &chn->group_pub_hash, chn, | ||
1338 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
1339 | return chn; | ||
1340 | } | ||
1341 | |||
1342 | |||
1343 | /** | ||
1344 | * Destroy outgoing CADET channel. | ||
1345 | */ | ||
1346 | static void | ||
1347 | cadet_channel_destroy (struct Channel *chn) | ||
1348 | { | ||
1349 | GNUNET_CADET_channel_destroy (chn->channel); | ||
1350 | GNUNET_CONTAINER_multihashmap_remove_all (channels_out, &chn->group_pub_hash); | ||
1351 | GNUNET_free (chn); | ||
1352 | } | ||
1353 | |||
1354 | /** | ||
1355 | * Handle a connecting client starting an origin. | ||
1356 | */ | ||
1357 | static void | ||
1358 | handle_client_origin_start (void *cls, | ||
1359 | const struct MulticastOriginStartMessage *msg) | ||
1360 | { | ||
1361 | struct Client *c = cls; | ||
1362 | struct GNUNET_SERVICE_Client *client = c->client; | ||
1363 | |||
1364 | struct GNUNET_CRYPTO_EddsaPublicKey pub_key; | ||
1365 | struct GNUNET_HashCode pub_key_hash; | ||
1366 | |||
1367 | GNUNET_CRYPTO_eddsa_key_get_public (&msg->group_key, &pub_key); | ||
1368 | GNUNET_CRYPTO_hash (&pub_key, sizeof (pub_key), &pub_key_hash); | ||
1369 | |||
1370 | struct Origin * | ||
1371 | orig = GNUNET_CONTAINER_multihashmap_get (origins, &pub_key_hash); | ||
1372 | struct Group *grp; | ||
1373 | |||
1374 | if (NULL == orig) | ||
1375 | { | ||
1376 | orig = GNUNET_new (struct Origin); | ||
1377 | orig->priv_key = msg->group_key; | ||
1378 | orig->max_fragment_id = GNUNET_ntohll (msg->max_fragment_id); | ||
1379 | |||
1380 | grp = c->group = &orig->group; | ||
1381 | grp->origin = orig; | ||
1382 | grp->is_origin = GNUNET_YES; | ||
1383 | grp->pub_key = pub_key; | ||
1384 | grp->pub_key_hash = pub_key_hash; | ||
1385 | grp->is_disconnected = GNUNET_NO; | ||
1386 | |||
1387 | GNUNET_CONTAINER_multihashmap_put (origins, &grp->pub_key_hash, orig, | ||
1388 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); | ||
1389 | |||
1390 | group_set_cadet_port_hash (grp); | ||
1391 | |||
1392 | struct GNUNET_MQ_MessageHandler cadet_handlers[] = { | ||
1393 | GNUNET_MQ_hd_var_size (cadet_message, | ||
1394 | GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE, | ||
1395 | struct GNUNET_MULTICAST_MessageHeader, | ||
1396 | grp), | ||
1397 | |||
1398 | GNUNET_MQ_hd_var_size (cadet_request, | ||
1399 | GNUNET_MESSAGE_TYPE_MULTICAST_REQUEST, | ||
1400 | struct GNUNET_MULTICAST_RequestHeader, | ||
1401 | grp), | ||
1402 | |||
1403 | GNUNET_MQ_hd_var_size (cadet_join_request, | ||
1404 | GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_REQUEST, | ||
1405 | struct MulticastJoinRequestMessage, | ||
1406 | grp), | ||
1407 | |||
1408 | GNUNET_MQ_hd_fixed_size (cadet_replay_request, | ||
1409 | GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_REQUEST, | ||
1410 | struct MulticastReplayRequestMessage, | ||
1411 | grp), | ||
1412 | |||
1413 | GNUNET_MQ_hd_var_size (cadet_replay_response, | ||
1414 | GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE, | ||
1415 | struct MulticastReplayResponseMessage, | ||
1416 | grp), | ||
1417 | |||
1418 | GNUNET_MQ_handler_end () | ||
1419 | }; | ||
1420 | |||
1421 | |||
1422 | orig->cadet_port = GNUNET_CADET_open_port (cadet, | ||
1423 | &grp->cadet_port_hash, | ||
1424 | cadet_notify_connect, | ||
1425 | grp, | ||
1426 | cadet_notify_window_change, | ||
1427 | cadet_notify_disconnect, | ||
1428 | cadet_handlers); | ||
1429 | } | ||
1430 | else | ||
1431 | { | ||
1432 | grp = &orig->group; | ||
1433 | } | ||
1434 | |||
1435 | struct ClientList *cl = GNUNET_new (struct ClientList); | ||
1436 | cl->client = client; | ||
1437 | GNUNET_CONTAINER_DLL_insert (grp->clients_head, grp->clients_tail, cl); | ||
1438 | |||
1439 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1440 | "%p Client connected as origin to group %s.\n", | ||
1441 | orig, GNUNET_h2s (&grp->pub_key_hash)); | ||
1442 | GNUNET_SERVICE_client_continue (client); | ||
1443 | } | ||
1444 | |||
1445 | |||
1446 | static int | ||
1447 | check_client_member_join (void *cls, | ||
1448 | const struct MulticastMemberJoinMessage *msg) | ||
1449 | { | ||
1450 | uint16_t msg_size = ntohs (msg->header.size); | ||
1451 | struct GNUNET_PeerIdentity *relays = (struct GNUNET_PeerIdentity *) &msg[1]; | ||
1452 | uint32_t relay_count = ntohl (msg->relay_count); | ||
1453 | |||
1454 | if (0 != relay_count) | ||
1455 | { | ||
1456 | if (UINT32_MAX / relay_count < sizeof (*relays)){ | ||
1457 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1458 | "relay_count (%lu) * sizeof (*relays) (%lu) exceeds UINT32_MAX!\n", | ||
1459 | (unsigned long)relay_count, | ||
1460 | sizeof (*relays)); | ||
1461 | return GNUNET_SYSERR; | ||
1462 | } | ||
1463 | } | ||
1464 | uint32_t relay_size = relay_count * sizeof (*relays); | ||
1465 | struct GNUNET_MessageHeader *join_msg = NULL; | ||
1466 | uint16_t join_msg_size = 0; | ||
1467 | if (sizeof (*msg) + relay_size + sizeof (struct GNUNET_MessageHeader) | ||
1468 | <= msg_size) | ||
1469 | { | ||
1470 | join_msg = (struct GNUNET_MessageHeader *) | ||
1471 | (((char *) &msg[1]) + relay_size); | ||
1472 | join_msg_size = ntohs (join_msg->size); | ||
1473 | if (UINT16_MAX - join_msg_size < sizeof (struct MulticastJoinRequestMessage)){ | ||
1474 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1475 | "join_msg_size (%u) + sizeof (struct MulticastJoinRequestMessage) (%lu) exceeds UINT16_MAX!\n", | ||
1476 | (unsigned)join_msg_size, | ||
1477 | (unsigned long)sizeof (struct MulticastJoinRequestMessage)); | ||
1478 | return GNUNET_SYSERR; | ||
1479 | } | ||
1480 | } | ||
1481 | if (msg_size != (sizeof (*msg) + relay_size + join_msg_size)){ | ||
1482 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1483 | "msg_size does not match real size of message!\n"); | ||
1484 | return GNUNET_SYSERR; | ||
1485 | }else{ | ||
1486 | return GNUNET_OK; | ||
1487 | } | ||
1488 | } | ||
1489 | |||
1490 | |||
1491 | /** | ||
1492 | * Handle a connecting client joining a group. | ||
1493 | */ | ||
1494 | static void | ||
1495 | handle_client_member_join (void *cls, | ||
1496 | const struct MulticastMemberJoinMessage *msg) | ||
1497 | { | ||
1498 | struct Client *c = cls; | ||
1499 | struct GNUNET_SERVICE_Client *client = c->client; | ||
1500 | |||
1501 | uint16_t msg_size = ntohs (msg->header.size); | ||
1502 | |||
1503 | struct GNUNET_CRYPTO_EcdsaPublicKey mem_pub_key; | ||
1504 | struct GNUNET_HashCode pub_key_hash, mem_pub_key_hash; | ||
1505 | |||
1506 | GNUNET_CRYPTO_ecdsa_key_get_public (&msg->member_key, &mem_pub_key); | ||
1507 | GNUNET_CRYPTO_hash (&mem_pub_key, sizeof (mem_pub_key), &mem_pub_key_hash); | ||
1508 | GNUNET_CRYPTO_hash (&msg->group_pub_key, sizeof (msg->group_pub_key), &pub_key_hash); | ||
1509 | |||
1510 | struct GNUNET_CONTAINER_MultiHashMap * | ||
1511 | grp_mem = GNUNET_CONTAINER_multihashmap_get (group_members, &pub_key_hash); | ||
1512 | struct Member *mem = NULL; | ||
1513 | struct Group *grp; | ||
1514 | |||
1515 | if (NULL != grp_mem) | ||
1516 | { | ||
1517 | mem = GNUNET_CONTAINER_multihashmap_get (grp_mem, &mem_pub_key_hash); | ||
1518 | } | ||
1519 | |||
1520 | if (NULL == mem) | ||
1521 | { | ||
1522 | mem = GNUNET_new (struct Member); | ||
1523 | mem->origin = msg->origin; | ||
1524 | mem->priv_key = msg->member_key; | ||
1525 | mem->pub_key = mem_pub_key; | ||
1526 | mem->pub_key_hash = mem_pub_key_hash; | ||
1527 | mem->max_fragment_id = 0; // FIXME | ||
1528 | |||
1529 | grp = c->group = &mem->group; | ||
1530 | grp->member = mem; | ||
1531 | grp->is_origin = GNUNET_NO; | ||
1532 | grp->pub_key = msg->group_pub_key; | ||
1533 | grp->pub_key_hash = pub_key_hash; | ||
1534 | grp->is_disconnected = GNUNET_NO; | ||
1535 | group_set_cadet_port_hash (grp); | ||
1536 | |||
1537 | if (NULL == grp_mem) | ||
1538 | { | ||
1539 | grp_mem = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES); | ||
1540 | GNUNET_CONTAINER_multihashmap_put (group_members, &grp->pub_key_hash, grp_mem, | ||
1541 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); | ||
1542 | } | ||
1543 | GNUNET_CONTAINER_multihashmap_put (grp_mem, &mem->pub_key_hash, mem, | ||
1544 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); | ||
1545 | |||
1546 | // FIXME: should the members hash map have option UNIQUE_FAST? | ||
1547 | GNUNET_CONTAINER_multihashmap_put (members, &grp->pub_key_hash, mem, | ||
1548 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
1549 | } | ||
1550 | else | ||
1551 | { | ||
1552 | grp = &mem->group; | ||
1553 | } | ||
1554 | |||
1555 | struct ClientList *cl = GNUNET_new (struct ClientList); | ||
1556 | cl->client = client; | ||
1557 | GNUNET_CONTAINER_DLL_insert (grp->clients_head, grp->clients_tail, cl); | ||
1558 | |||
1559 | char *str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&mem->pub_key); | ||
1560 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1561 | "Client connected to group %s as member %s (%s). size = %d\n", | ||
1562 | GNUNET_h2s (&grp->pub_key_hash), | ||
1563 | GNUNET_h2s2 (&mem->pub_key_hash), | ||
1564 | str, | ||
1565 | GNUNET_CONTAINER_multihashmap_size (members)); | ||
1566 | GNUNET_free (str); | ||
1567 | |||
1568 | if (NULL != mem->join_dcsn) | ||
1569 | { /* Already got a join decision, send it to client. */ | ||
1570 | struct GNUNET_MQ_Envelope * | ||
1571 | env = GNUNET_MQ_msg_copy (&mem->join_dcsn->header); | ||
1572 | |||
1573 | GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), | ||
1574 | env); | ||
1575 | } | ||
1576 | else | ||
1577 | { /* First client of the group, send join request. */ | ||
1578 | struct GNUNET_PeerIdentity *relays = (struct GNUNET_PeerIdentity *) &msg[1]; | ||
1579 | uint32_t relay_count = ntohl (msg->relay_count); | ||
1580 | uint16_t relay_size = relay_count * sizeof (*relays); | ||
1581 | struct GNUNET_MessageHeader *join_msg = NULL; | ||
1582 | uint16_t join_msg_size = 0; | ||
1583 | if (sizeof (*msg) + relay_size + sizeof (struct GNUNET_MessageHeader) | ||
1584 | <= msg_size) | ||
1585 | { | ||
1586 | join_msg = (struct GNUNET_MessageHeader *) | ||
1587 | (((char *) &msg[1]) + relay_size); | ||
1588 | join_msg_size = ntohs (join_msg->size); | ||
1589 | } | ||
1590 | |||
1591 | uint16_t req_msg_size = sizeof (struct MulticastJoinRequestMessage) + join_msg_size; | ||
1592 | struct MulticastJoinRequestMessage * | ||
1593 | req = GNUNET_malloc (req_msg_size); | ||
1594 | req->header.size = htons (req_msg_size); | ||
1595 | req->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_REQUEST); | ||
1596 | req->group_pub_key = grp->pub_key; | ||
1597 | req->peer = this_peer; | ||
1598 | GNUNET_CRYPTO_ecdsa_key_get_public (&mem->priv_key, &req->member_pub_key); | ||
1599 | if (0 < join_msg_size) | ||
1600 | GNUNET_memcpy (&req[1], join_msg, join_msg_size); | ||
1601 | |||
1602 | req->member_pub_key = mem->pub_key; | ||
1603 | req->purpose.size = htonl (req_msg_size | ||
1604 | - sizeof (req->header) | ||
1605 | - sizeof (req->reserved) | ||
1606 | - sizeof (req->signature)); | ||
1607 | req->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_MULTICAST_REQUEST); | ||
1608 | |||
1609 | if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_sign (&mem->priv_key, &req->purpose, | ||
1610 | &req->signature)) | ||
1611 | { | ||
1612 | /* FIXME: handle error */ | ||
1613 | GNUNET_assert (0); | ||
1614 | } | ||
1615 | |||
1616 | if (NULL != mem->join_req) | ||
1617 | GNUNET_free (mem->join_req); | ||
1618 | mem->join_req = req; | ||
1619 | |||
1620 | if (0 == | ||
1621 | client_send_origin (&grp->pub_key_hash, | ||
1622 | GNUNET_MQ_msg_copy (&mem->join_req->header))) | ||
1623 | { /* No local origins, send to remote origin */ | ||
1624 | cadet_send_join_request (mem); | ||
1625 | } | ||
1626 | } | ||
1627 | GNUNET_SERVICE_client_continue (client); | ||
1628 | } | ||
1629 | |||
1630 | |||
1631 | static void | ||
1632 | client_send_join_decision (struct Member *mem, | ||
1633 | const struct MulticastJoinDecisionMessageHeader *hdcsn) | ||
1634 | { | ||
1635 | client_send_group (&mem->group, GNUNET_MQ_msg_copy (&hdcsn->header)); | ||
1636 | |||
1637 | const struct MulticastJoinDecisionMessage * | ||
1638 | dcsn = (const struct MulticastJoinDecisionMessage *) &hdcsn[1]; | ||
1639 | if (GNUNET_YES == ntohl (dcsn->is_admitted)) | ||
1640 | { /* Member admitted, store join_decision. */ | ||
1641 | uint16_t dcsn_size = ntohs (dcsn->header.size); | ||
1642 | mem->join_dcsn = GNUNET_malloc (dcsn_size); | ||
1643 | GNUNET_memcpy (mem->join_dcsn, dcsn, dcsn_size); | ||
1644 | } | ||
1645 | else | ||
1646 | { /* Refused entry, but replay would be still possible for past members. */ | ||
1647 | } | ||
1648 | } | ||
1649 | |||
1650 | |||
1651 | static int | ||
1652 | check_client_join_decision (void *cls, | ||
1653 | const struct MulticastJoinDecisionMessageHeader *hdcsn) | ||
1654 | { | ||
1655 | return GNUNET_OK; | ||
1656 | } | ||
1657 | |||
1658 | |||
1659 | /** | ||
1660 | * Join decision from client. | ||
1661 | */ | ||
1662 | static void | ||
1663 | handle_client_join_decision (void *cls, | ||
1664 | const struct MulticastJoinDecisionMessageHeader *hdcsn) | ||
1665 | { | ||
1666 | struct Client *c = cls; | ||
1667 | struct GNUNET_SERVICE_Client *client = c->client; | ||
1668 | struct Group *grp = c->group; | ||
1669 | |||
1670 | if (NULL == grp) | ||
1671 | { | ||
1672 | GNUNET_break (0); | ||
1673 | GNUNET_SERVICE_client_drop (client); | ||
1674 | return; | ||
1675 | } | ||
1676 | GNUNET_assert (GNUNET_NO == grp->is_disconnected); | ||
1677 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1678 | "%p got join decision from client for group %s..\n", | ||
1679 | grp, GNUNET_h2s (&grp->pub_key_hash)); | ||
1680 | |||
1681 | struct GNUNET_CONTAINER_MultiHashMap * | ||
1682 | grp_mem = GNUNET_CONTAINER_multihashmap_get (group_members, | ||
1683 | &grp->pub_key_hash); | ||
1684 | struct Member *mem = NULL; | ||
1685 | if (NULL != grp_mem) | ||
1686 | { | ||
1687 | struct GNUNET_HashCode member_key_hash; | ||
1688 | GNUNET_CRYPTO_hash (&hdcsn->member_pub_key, sizeof (hdcsn->member_pub_key), | ||
1689 | &member_key_hash); | ||
1690 | mem = GNUNET_CONTAINER_multihashmap_get (grp_mem, &member_key_hash); | ||
1691 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1692 | "%p ..and member %s: %p\n", | ||
1693 | grp, GNUNET_h2s (&member_key_hash), mem); | ||
1694 | } | ||
1695 | |||
1696 | if (NULL != mem) | ||
1697 | { /* Found local member */ | ||
1698 | client_send_join_decision (mem, hdcsn); | ||
1699 | } | ||
1700 | else | ||
1701 | { /* Look for remote member */ | ||
1702 | cadet_send_join_decision (grp, hdcsn); | ||
1703 | } | ||
1704 | GNUNET_SERVICE_client_continue (client); | ||
1705 | } | ||
1706 | |||
1707 | |||
1708 | static void | ||
1709 | handle_client_part_request (void *cls, | ||
1710 | const struct GNUNET_MessageHeader *msg) | ||
1711 | { | ||
1712 | struct Client *c = cls; | ||
1713 | struct GNUNET_SERVICE_Client *client = c->client; | ||
1714 | struct Group *grp = c->group; | ||
1715 | struct GNUNET_MQ_Envelope *env; | ||
1716 | |||
1717 | if (NULL == grp) | ||
1718 | { | ||
1719 | GNUNET_break (0); | ||
1720 | GNUNET_SERVICE_client_drop (client); | ||
1721 | return; | ||
1722 | } | ||
1723 | GNUNET_assert (GNUNET_NO == grp->is_disconnected); | ||
1724 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1725 | "%p got part request from client for group %s.\n", | ||
1726 | grp, GNUNET_h2s (&grp->pub_key_hash)); | ||
1727 | grp->is_disconnected = GNUNET_YES; | ||
1728 | env = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_MULTICAST_PART_ACK); | ||
1729 | client_send_group (grp, env); | ||
1730 | GNUNET_SERVICE_client_continue (client); | ||
1731 | } | ||
1732 | |||
1733 | |||
1734 | static int | ||
1735 | check_client_multicast_message (void *cls, | ||
1736 | const struct GNUNET_MULTICAST_MessageHeader *msg) | ||
1737 | { | ||
1738 | return GNUNET_OK; | ||
1739 | } | ||
1740 | |||
1741 | |||
1742 | /** | ||
1743 | * Incoming message from a client. | ||
1744 | */ | ||
1745 | static void | ||
1746 | handle_client_multicast_message (void *cls, | ||
1747 | const struct GNUNET_MULTICAST_MessageHeader *msg) | ||
1748 | { | ||
1749 | // FIXME: what if GNUNET_YES == grp->is_disconnected? Do we allow sending messages? | ||
1750 | struct Client *c = cls; | ||
1751 | struct GNUNET_SERVICE_Client *client = c->client; | ||
1752 | struct Group *grp = c->group; | ||
1753 | |||
1754 | if (NULL == grp) | ||
1755 | { | ||
1756 | GNUNET_break (0); | ||
1757 | GNUNET_SERVICE_client_drop (client); | ||
1758 | return; | ||
1759 | } | ||
1760 | GNUNET_assert (GNUNET_YES == grp->is_origin); | ||
1761 | struct Origin *orig = grp->origin; | ||
1762 | |||
1763 | // FIXME: use GNUNET_MQ_msg_copy | ||
1764 | /* FIXME: yucky, should use separate message structs for P2P and CS! */ | ||
1765 | struct GNUNET_MULTICAST_MessageHeader * | ||
1766 | out = (struct GNUNET_MULTICAST_MessageHeader *) GNUNET_copy_message (&msg->header); | ||
1767 | out->fragment_id = GNUNET_htonll (++orig->max_fragment_id); | ||
1768 | out->purpose.size = htonl (ntohs (out->header.size) | ||
1769 | - sizeof (out->header) | ||
1770 | - sizeof (out->hop_counter) | ||
1771 | - sizeof (out->signature)); | ||
1772 | out->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_MULTICAST_MESSAGE); | ||
1773 | |||
1774 | if (GNUNET_OK != GNUNET_CRYPTO_eddsa_sign (&orig->priv_key, &out->purpose, | ||
1775 | &out->signature)) | ||
1776 | { | ||
1777 | GNUNET_assert (0); | ||
1778 | } | ||
1779 | |||
1780 | client_send_all (&grp->pub_key_hash, GNUNET_MQ_msg_copy (&out->header)); | ||
1781 | cadet_send_children (&grp->pub_key_hash, &out->header); | ||
1782 | client_send_ack (&grp->pub_key_hash); | ||
1783 | GNUNET_free (out); | ||
1784 | |||
1785 | GNUNET_SERVICE_client_continue (client); | ||
1786 | } | ||
1787 | |||
1788 | |||
1789 | static int | ||
1790 | check_client_multicast_request (void *cls, | ||
1791 | const struct GNUNET_MULTICAST_RequestHeader *req) | ||
1792 | { | ||
1793 | return GNUNET_OK; | ||
1794 | } | ||
1795 | |||
1796 | |||
1797 | /** | ||
1798 | * Incoming request from a client. | ||
1799 | */ | ||
1800 | static void | ||
1801 | handle_client_multicast_request (void *cls, | ||
1802 | const struct GNUNET_MULTICAST_RequestHeader *req) | ||
1803 | { | ||
1804 | struct Client *c = cls; | ||
1805 | struct GNUNET_SERVICE_Client *client = c->client; | ||
1806 | struct Group *grp = c->group; | ||
1807 | |||
1808 | if (NULL == grp) | ||
1809 | { | ||
1810 | GNUNET_break (0); | ||
1811 | GNUNET_SERVICE_client_drop (client); | ||
1812 | return; | ||
1813 | } | ||
1814 | GNUNET_assert (GNUNET_NO == grp->is_disconnected); | ||
1815 | GNUNET_assert (GNUNET_NO == grp->is_origin); | ||
1816 | struct Member *mem = grp->member; | ||
1817 | |||
1818 | /* FIXME: yucky, should use separate message structs for P2P and CS! */ | ||
1819 | struct GNUNET_MULTICAST_RequestHeader * | ||
1820 | out = (struct GNUNET_MULTICAST_RequestHeader *) GNUNET_copy_message (&req->header); | ||
1821 | out->member_pub_key = mem->pub_key; | ||
1822 | out->fragment_id = GNUNET_ntohll (++mem->max_fragment_id); | ||
1823 | out->purpose.size = htonl (ntohs (out->header.size) | ||
1824 | - sizeof (out->header) | ||
1825 | - sizeof (out->member_pub_key) | ||
1826 | - sizeof (out->signature)); | ||
1827 | out->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_MULTICAST_REQUEST); | ||
1828 | |||
1829 | if (GNUNET_OK != GNUNET_CRYPTO_ecdsa_sign (&mem->priv_key, &out->purpose, | ||
1830 | &out->signature)) | ||
1831 | { | ||
1832 | GNUNET_assert (0); | ||
1833 | } | ||
1834 | |||
1835 | uint8_t send_ack = GNUNET_YES; | ||
1836 | if (0 == | ||
1837 | client_send_origin (&grp->pub_key_hash, | ||
1838 | GNUNET_MQ_msg_copy (&out->header))) | ||
1839 | { /* No local origins, send to remote origin */ | ||
1840 | if (NULL != mem->origin_channel) | ||
1841 | { | ||
1842 | cadet_send_channel (mem->origin_channel, &out->header); | ||
1843 | send_ack = GNUNET_NO; | ||
1844 | } | ||
1845 | else | ||
1846 | { | ||
1847 | /* FIXME: not yet connected to origin */ | ||
1848 | GNUNET_SERVICE_client_drop (client); | ||
1849 | GNUNET_free (out); | ||
1850 | return; | ||
1851 | } | ||
1852 | } | ||
1853 | if (GNUNET_YES == send_ack) | ||
1854 | { | ||
1855 | client_send_ack (&grp->pub_key_hash); | ||
1856 | } | ||
1857 | GNUNET_free (out); | ||
1858 | GNUNET_SERVICE_client_continue (client); | ||
1859 | } | ||
1860 | |||
1861 | |||
1862 | /** | ||
1863 | * Incoming replay request from a client. | ||
1864 | */ | ||
1865 | static void | ||
1866 | handle_client_replay_request (void *cls, | ||
1867 | const struct MulticastReplayRequestMessage *rep) | ||
1868 | { | ||
1869 | struct Client *c = cls; | ||
1870 | struct GNUNET_SERVICE_Client *client = c->client; | ||
1871 | struct Group *grp = c->group; | ||
1872 | |||
1873 | if (NULL == grp) | ||
1874 | { | ||
1875 | GNUNET_break (0); | ||
1876 | GNUNET_SERVICE_client_drop (client); | ||
1877 | return; | ||
1878 | } | ||
1879 | GNUNET_assert (GNUNET_NO == grp->is_disconnected); | ||
1880 | GNUNET_assert (GNUNET_NO == grp->is_origin); | ||
1881 | struct Member *mem = grp->member; | ||
1882 | |||
1883 | struct GNUNET_CONTAINER_MultiHashMap * | ||
1884 | grp_replay_req = GNUNET_CONTAINER_multihashmap_get (replay_req_client, | ||
1885 | &grp->pub_key_hash); | ||
1886 | if (NULL == grp_replay_req) | ||
1887 | { | ||
1888 | grp_replay_req = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); | ||
1889 | GNUNET_CONTAINER_multihashmap_put (replay_req_client, | ||
1890 | &grp->pub_key_hash, grp_replay_req, | ||
1891 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); | ||
1892 | } | ||
1893 | |||
1894 | struct GNUNET_HashCode key_hash; | ||
1895 | replay_key_hash (rep->fragment_id, rep->message_id, rep->fragment_offset, | ||
1896 | rep->flags, &key_hash); | ||
1897 | GNUNET_CONTAINER_multihashmap_put (grp_replay_req, &key_hash, client, | ||
1898 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
1899 | |||
1900 | if (0 == | ||
1901 | client_send_origin (&grp->pub_key_hash, | ||
1902 | GNUNET_MQ_msg_copy (&rep->header))) | ||
1903 | { /* No local origin, replay from remote members / origin. */ | ||
1904 | if (NULL != mem->origin_channel) | ||
1905 | { | ||
1906 | cadet_send_channel (mem->origin_channel, &rep->header); | ||
1907 | } | ||
1908 | else | ||
1909 | { | ||
1910 | /* FIXME: not yet connected to origin */ | ||
1911 | |||
1912 | GNUNET_assert (0); | ||
1913 | GNUNET_SERVICE_client_drop (client); | ||
1914 | return; | ||
1915 | } | ||
1916 | } | ||
1917 | GNUNET_SERVICE_client_continue (client); | ||
1918 | } | ||
1919 | |||
1920 | |||
1921 | static int | ||
1922 | cadet_send_replay_response_cb (void *cls, | ||
1923 | const struct GNUNET_HashCode *key_hash, | ||
1924 | void *value) | ||
1925 | { | ||
1926 | struct Channel *chn = value; | ||
1927 | struct GNUNET_MessageHeader *msg = cls; | ||
1928 | |||
1929 | cadet_send_channel (chn, msg); | ||
1930 | return GNUNET_OK; | ||
1931 | } | ||
1932 | |||
1933 | |||
1934 | static int | ||
1935 | client_send_replay_response_cb (void *cls, | ||
1936 | const struct GNUNET_HashCode *key_hash, | ||
1937 | void *value) | ||
1938 | { | ||
1939 | struct GNUNET_SERVICE_Client *client = value; | ||
1940 | struct GNUNET_MessageHeader *msg = cls; | ||
1941 | |||
1942 | client_send (client, msg); | ||
1943 | return GNUNET_OK; | ||
1944 | } | ||
1945 | |||
1946 | |||
1947 | static int | ||
1948 | check_client_replay_response_end (void *cls, | ||
1949 | const struct MulticastReplayResponseMessage *res) | ||
1950 | { | ||
1951 | return GNUNET_OK; | ||
1952 | } | ||
1953 | |||
1954 | |||
1955 | /** | ||
1956 | * End of replay response from a client. | ||
1957 | */ | ||
1958 | static void | ||
1959 | handle_client_replay_response_end (void *cls, | ||
1960 | const struct MulticastReplayResponseMessage *res) | ||
1961 | { | ||
1962 | struct Client *c = cls; | ||
1963 | struct GNUNET_SERVICE_Client *client = c->client; | ||
1964 | struct Group *grp = c->group; | ||
1965 | |||
1966 | if (NULL == grp) | ||
1967 | { | ||
1968 | GNUNET_break (0); | ||
1969 | GNUNET_SERVICE_client_drop (client); | ||
1970 | return; | ||
1971 | } | ||
1972 | GNUNET_assert (GNUNET_NO == grp->is_disconnected); | ||
1973 | |||
1974 | struct GNUNET_HashCode key_hash; | ||
1975 | replay_key_hash (res->fragment_id, res->message_id, res->fragment_offset, | ||
1976 | res->flags, &key_hash); | ||
1977 | |||
1978 | struct GNUNET_CONTAINER_MultiHashMap * | ||
1979 | grp_replay_req_cadet = GNUNET_CONTAINER_multihashmap_get (replay_req_cadet, | ||
1980 | &grp->pub_key_hash); | ||
1981 | if (NULL != grp_replay_req_cadet) | ||
1982 | { | ||
1983 | GNUNET_CONTAINER_multihashmap_remove_all (grp_replay_req_cadet, &key_hash); | ||
1984 | } | ||
1985 | struct GNUNET_CONTAINER_MultiHashMap * | ||
1986 | grp_replay_req_client = GNUNET_CONTAINER_multihashmap_get (replay_req_client, | ||
1987 | &grp->pub_key_hash); | ||
1988 | if (NULL != grp_replay_req_client) | ||
1989 | { | ||
1990 | GNUNET_CONTAINER_multihashmap_remove_all (grp_replay_req_client, &key_hash); | ||
1991 | } | ||
1992 | GNUNET_SERVICE_client_continue (client); | ||
1993 | } | ||
1994 | |||
1995 | |||
1996 | static int | ||
1997 | check_client_replay_response (void *cls, | ||
1998 | const struct MulticastReplayResponseMessage *res) | ||
1999 | { | ||
2000 | const struct GNUNET_MessageHeader *msg; | ||
2001 | if (GNUNET_MULTICAST_REC_OK == res->error_code) | ||
2002 | { | ||
2003 | msg = GNUNET_MQ_extract_nested_mh (res); | ||
2004 | if (NULL == msg) | ||
2005 | { | ||
2006 | return GNUNET_SYSERR; | ||
2007 | } | ||
2008 | } | ||
2009 | return GNUNET_OK; | ||
2010 | } | ||
2011 | |||
2012 | |||
2013 | /** | ||
2014 | * Incoming replay response from a client. | ||
2015 | * | ||
2016 | * Respond with a multicast message on success, or otherwise with an error code. | ||
2017 | */ | ||
2018 | static void | ||
2019 | handle_client_replay_response (void *cls, | ||
2020 | const struct MulticastReplayResponseMessage *res) | ||
2021 | { | ||
2022 | struct Client *c = cls; | ||
2023 | struct GNUNET_SERVICE_Client *client = c->client; | ||
2024 | struct Group *grp = c->group; | ||
2025 | |||
2026 | if (NULL == grp) | ||
2027 | { | ||
2028 | GNUNET_break (0); | ||
2029 | GNUNET_SERVICE_client_drop (client); | ||
2030 | return; | ||
2031 | } | ||
2032 | GNUNET_assert (GNUNET_NO == grp->is_disconnected); | ||
2033 | |||
2034 | const struct GNUNET_MessageHeader *msg = &res->header; | ||
2035 | if (GNUNET_MULTICAST_REC_OK == res->error_code) | ||
2036 | { | ||
2037 | msg = GNUNET_MQ_extract_nested_mh (res); | ||
2038 | } | ||
2039 | |||
2040 | struct GNUNET_HashCode key_hash; | ||
2041 | replay_key_hash (res->fragment_id, res->message_id, res->fragment_offset, | ||
2042 | res->flags, &key_hash); | ||
2043 | |||
2044 | struct GNUNET_CONTAINER_MultiHashMap * | ||
2045 | grp_replay_req_cadet = GNUNET_CONTAINER_multihashmap_get (replay_req_cadet, | ||
2046 | &grp->pub_key_hash); | ||
2047 | if (NULL != grp_replay_req_cadet) | ||
2048 | { | ||
2049 | GNUNET_CONTAINER_multihashmap_get_multiple (grp_replay_req_cadet, &key_hash, | ||
2050 | cadet_send_replay_response_cb, | ||
2051 | (void *) msg); | ||
2052 | } | ||
2053 | if (GNUNET_MULTICAST_REC_OK == res->error_code) | ||
2054 | { | ||
2055 | struct GNUNET_CONTAINER_MultiHashMap * | ||
2056 | grp_replay_req_client = GNUNET_CONTAINER_multihashmap_get (replay_req_client, | ||
2057 | &grp->pub_key_hash); | ||
2058 | if (NULL != grp_replay_req_client) | ||
2059 | { | ||
2060 | GNUNET_CONTAINER_multihashmap_get_multiple (grp_replay_req_client, &key_hash, | ||
2061 | client_send_replay_response_cb, | ||
2062 | (void *) msg); | ||
2063 | } | ||
2064 | } | ||
2065 | else | ||
2066 | { | ||
2067 | handle_client_replay_response_end (c, res); | ||
2068 | return; | ||
2069 | } | ||
2070 | GNUNET_SERVICE_client_continue (client); | ||
2071 | } | ||
2072 | |||
2073 | |||
2074 | /** | ||
2075 | * A new client connected. | ||
2076 | * | ||
2077 | * @param cls NULL | ||
2078 | * @param client client to add | ||
2079 | * @param mq message queue for @a client | ||
2080 | * @return @a client | ||
2081 | */ | ||
2082 | static void * | ||
2083 | client_notify_connect (void *cls, | ||
2084 | struct GNUNET_SERVICE_Client *client, | ||
2085 | struct GNUNET_MQ_Handle *mq) | ||
2086 | { | ||
2087 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client connected: %p\n", client); | ||
2088 | /* FIXME: send connect ACK */ | ||
2089 | |||
2090 | struct Client *c = GNUNET_new (struct Client); | ||
2091 | c->client = client; | ||
2092 | |||
2093 | return c; | ||
2094 | } | ||
2095 | |||
2096 | |||
2097 | /** | ||
2098 | * Called whenever a client is disconnected. | ||
2099 | * Frees our resources associated with that client. | ||
2100 | * | ||
2101 | * @param cls closure | ||
2102 | * @param client identification of the client | ||
2103 | * @param app_ctx must match @a client | ||
2104 | */ | ||
2105 | static void | ||
2106 | client_notify_disconnect (void *cls, | ||
2107 | struct GNUNET_SERVICE_Client *client, | ||
2108 | void *app_ctx) | ||
2109 | { | ||
2110 | struct Client *c = app_ctx; | ||
2111 | struct Group *grp = c->group; | ||
2112 | GNUNET_free (c); | ||
2113 | |||
2114 | if (NULL == grp) | ||
2115 | { | ||
2116 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
2117 | "%p User context is NULL in client_disconnect()\n", grp); | ||
2118 | GNUNET_break (0); | ||
2119 | return; | ||
2120 | } | ||
2121 | |||
2122 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2123 | "%p Client (%s) disconnected from group %s\n", | ||
2124 | grp, (GNUNET_YES == grp->is_origin) ? "origin" : "member", | ||
2125 | GNUNET_h2s (&grp->pub_key_hash)); | ||
2126 | |||
2127 | // FIXME (due to protocol change): here we must not remove all clients, | ||
2128 | // only the one we were notified about! | ||
2129 | struct ClientList *cl = grp->clients_head; | ||
2130 | while (NULL != cl) | ||
2131 | { | ||
2132 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2133 | "iterating clients for group %p\n", | ||
2134 | grp); | ||
2135 | if (cl->client == client) | ||
2136 | { | ||
2137 | GNUNET_CONTAINER_DLL_remove (grp->clients_head, grp->clients_tail, cl); | ||
2138 | GNUNET_free (cl); | ||
2139 | break; | ||
2140 | } | ||
2141 | cl = cl->next; | ||
2142 | } | ||
2143 | |||
2144 | while (GNUNET_YES == replay_req_remove_client (grp, client)); | ||
2145 | |||
2146 | if (NULL == grp->clients_head) | ||
2147 | { /* Last client disconnected. */ | ||
2148 | cleanup_group (grp); | ||
2149 | } | ||
2150 | } | ||
2151 | |||
2152 | |||
2153 | /** | ||
2154 | * Service started. | ||
2155 | * | ||
2156 | * @param cls closure | ||
2157 | * @param server the initialized server | ||
2158 | * @param cfg configuration to use | ||
2159 | */ | ||
2160 | static void | ||
2161 | run (void *cls, | ||
2162 | const struct GNUNET_CONFIGURATION_Handle *c, | ||
2163 | struct GNUNET_SERVICE_Handle *svc) | ||
2164 | { | ||
2165 | cfg = c; | ||
2166 | service = svc; | ||
2167 | GNUNET_CRYPTO_get_peer_identity (cfg, &this_peer); | ||
2168 | |||
2169 | stats = GNUNET_STATISTICS_create ("multicast", cfg); | ||
2170 | origins = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES); | ||
2171 | members = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES); | ||
2172 | group_members = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); | ||
2173 | channels_in = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES); | ||
2174 | channels_out = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES); | ||
2175 | replay_req_cadet = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); | ||
2176 | replay_req_client = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); | ||
2177 | |||
2178 | cadet = GNUNET_CADET_connect (cfg); | ||
2179 | |||
2180 | GNUNET_assert (NULL != cadet); | ||
2181 | |||
2182 | GNUNET_SCHEDULER_add_shutdown (&shutdown_task, | ||
2183 | NULL); | ||
2184 | } | ||
2185 | |||
2186 | |||
2187 | /** | ||
2188 | * Define "main" method using service macro. | ||
2189 | */ | ||
2190 | GNUNET_SERVICE_MAIN | ||
2191 | ("multicast", | ||
2192 | GNUNET_SERVICE_OPTION_NONE, | ||
2193 | &run, | ||
2194 | &client_notify_connect, | ||
2195 | &client_notify_disconnect, | ||
2196 | NULL, | ||
2197 | GNUNET_MQ_hd_fixed_size (client_origin_start, | ||
2198 | GNUNET_MESSAGE_TYPE_MULTICAST_ORIGIN_START, | ||
2199 | struct MulticastOriginStartMessage, | ||
2200 | NULL), | ||
2201 | GNUNET_MQ_hd_var_size (client_member_join, | ||
2202 | GNUNET_MESSAGE_TYPE_MULTICAST_MEMBER_JOIN, | ||
2203 | struct MulticastMemberJoinMessage, | ||
2204 | NULL), | ||
2205 | GNUNET_MQ_hd_var_size (client_join_decision, | ||
2206 | GNUNET_MESSAGE_TYPE_MULTICAST_JOIN_DECISION, | ||
2207 | struct MulticastJoinDecisionMessageHeader, | ||
2208 | NULL), | ||
2209 | GNUNET_MQ_hd_fixed_size (client_part_request, | ||
2210 | GNUNET_MESSAGE_TYPE_MULTICAST_PART_REQUEST, | ||
2211 | struct GNUNET_MessageHeader, | ||
2212 | NULL), | ||
2213 | GNUNET_MQ_hd_var_size (client_multicast_message, | ||
2214 | GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE, | ||
2215 | struct GNUNET_MULTICAST_MessageHeader, | ||
2216 | NULL), | ||
2217 | GNUNET_MQ_hd_var_size (client_multicast_request, | ||
2218 | GNUNET_MESSAGE_TYPE_MULTICAST_REQUEST, | ||
2219 | struct GNUNET_MULTICAST_RequestHeader, | ||
2220 | NULL), | ||
2221 | GNUNET_MQ_hd_fixed_size (client_replay_request, | ||
2222 | GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_REQUEST, | ||
2223 | struct MulticastReplayRequestMessage, | ||
2224 | NULL), | ||
2225 | GNUNET_MQ_hd_var_size (client_replay_response, | ||
2226 | GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE, | ||
2227 | struct MulticastReplayResponseMessage, | ||
2228 | NULL), | ||
2229 | GNUNET_MQ_hd_var_size (client_replay_response_end, | ||
2230 | GNUNET_MESSAGE_TYPE_MULTICAST_REPLAY_RESPONSE_END, | ||
2231 | struct MulticastReplayResponseMessage, | ||
2232 | NULL)); | ||
2233 | |||
2234 | /* end of gnunet-service-multicast.c */ | ||
diff --git a/src/multicast/multicast.conf.in b/src/multicast/multicast.conf.in deleted file mode 100644 index 97a541336..000000000 --- a/src/multicast/multicast.conf.in +++ /dev/null | |||
@@ -1,22 +0,0 @@ | |||
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 | @UNIXONLY@PORT = 2109 | ||
10 | HOSTNAME = localhost | ||
11 | ACCEPT_FROM = 127.0.0.1; | ||
12 | ACCEPT_FROM6 = ::1; | ||
13 | |||
14 | # DISABLE_SOCKET_FORWARDING = NO | ||
15 | # USERNAME = | ||
16 | # MAXBUF = | ||
17 | # TIMEOUT = | ||
18 | # DISABLEV6 = | ||
19 | # BINDTO = | ||
20 | # REJECT_FROM = | ||
21 | # REJECT_FROM6 = | ||
22 | # PREFIX = | ||
diff --git a/src/multicast/multicast.h b/src/multicast/multicast.h deleted file mode 100644 index 8a3ca14c8..000000000 --- a/src/multicast/multicast.h +++ /dev/null | |||
@@ -1,303 +0,0 @@ | |||
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 deleted file mode 100644 index e5e830225..000000000 --- a/src/multicast/multicast_api.c +++ /dev/null | |||
@@ -1,1399 +0,0 @@ | |||
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 deleted file mode 100644 index 70efdcbfb..000000000 --- a/src/multicast/test_multicast.c +++ /dev/null | |||
@@ -1,758 +0,0 @@ | |||
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 "platform.h" | ||
30 | #include "gnunet_crypto_lib.h" | ||
31 | #include "gnunet_common.h" | ||
32 | #include "gnunet_util_lib.h" | ||
33 | #include "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.conf b/src/multicast/test_multicast.conf deleted file mode 100644 index b2f1a764b..000000000 --- a/src/multicast/test_multicast.conf +++ /dev/null | |||
@@ -1,56 +0,0 @@ | |||
1 | [testbed] | ||
2 | HOSTNAME = localhost | ||
3 | |||
4 | [arm] | ||
5 | GLOBAL_POSTFIX=-L ERROR | ||
6 | |||
7 | [multicast] | ||
8 | #PREFIX = tmux new-window gdb -x ./cmd.gdb --args | ||
9 | #PREFIX = valgrind --leak-check=full | ||
10 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-multicast.sock | ||
11 | |||
12 | [vpn] | ||
13 | START_ON_DEMAND = NO | ||
14 | |||
15 | [peerinfo] | ||
16 | # Do not use shipped gnunet HELLOs | ||
17 | USE_INCLUDED_HELLOS = NO | ||
18 | |||
19 | # Option to disable all disk IO; only useful for testbed runs | ||
20 | # (large-scale experiments); disables persistence of HELLOs! | ||
21 | NO_IO = YES | ||
22 | |||
23 | [hostlist] | ||
24 | IMMEDIATE_START = NO | ||
25 | START_ON_DEMAND = NO | ||
26 | |||
27 | [nat] | ||
28 | ENABLE_UPNP = NO | ||
29 | |||
30 | [fs] | ||
31 | IMMEDIATE_START = NO | ||
32 | START_ON_DEMAND = NO | ||
33 | |||
34 | [vpn] | ||
35 | IMMEDIATE_START = NO | ||
36 | START_ON_DEMAND = NO | ||
37 | |||
38 | [revocation] | ||
39 | IMMEDIATE_START = NO | ||
40 | START_ON_DEMAND = NO | ||
41 | |||
42 | [gns] | ||
43 | IMMEDIATE_START = NO | ||
44 | START_ON_DEMAND = NO | ||
45 | |||
46 | [namestore] | ||
47 | IMMEDIATE_START = NO | ||
48 | START_ON_DEMAND = NO | ||
49 | |||
50 | [namecache] | ||
51 | IMMEDIATE_START = NO | ||
52 | START_ON_DEMAND = NO | ||
53 | |||
54 | [topology] | ||
55 | IMMEDIATE_START = NO | ||
56 | START_ON_DEMAND = NO | ||
diff --git a/src/multicast/test_multicast_2peers.c b/src/multicast/test_multicast_2peers.c deleted file mode 100644 index ea996026c..000000000 --- a/src/multicast/test_multicast_2peers.c +++ /dev/null | |||
@@ -1,520 +0,0 @@ | |||
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 "platform.h" | ||
31 | #include "gnunet_crypto_lib.h" | ||
32 | #include "gnunet_common.h" | ||
33 | #include "gnunet_util_lib.h" | ||
34 | #include "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_line.conf b/src/multicast/test_multicast_line.conf deleted file mode 100644 index c1ce7c63f..000000000 --- a/src/multicast/test_multicast_line.conf +++ /dev/null | |||
@@ -1,63 +0,0 @@ | |||
1 | [testbed] | ||
2 | HOSTNAME = localhost | ||
3 | OVERLAY_TOPOLOGY = LINE | ||
4 | |||
5 | [arm] | ||
6 | GLOBAL_POSTFIX=-L ERROR | ||
7 | |||
8 | [multicast] | ||
9 | #PREFIX = tmux new-window gdb -x ./cmd.gdb --args | ||
10 | #PREFIX = valgrind --leak-check=full | ||
11 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-multicast.sock | ||
12 | |||
13 | [vpn] | ||
14 | START_ON_DEMAND = NO | ||
15 | |||
16 | [peerinfo] | ||
17 | # Do not use shipped gnunet HELLOs | ||
18 | USE_INCLUDED_HELLOS = NO | ||
19 | |||
20 | # Option to disable all disk IO; only useful for testbed runs | ||
21 | # (large-scale experiments); disables persistence of HELLOs! | ||
22 | NO_IO = YES | ||
23 | |||
24 | [cadet] | ||
25 | ID_ANNOUNCE_TIME = 5 s | ||
26 | |||
27 | [hostlist] | ||
28 | IMMEDIATE_START = NO | ||
29 | START_ON_DEMAND = NO | ||
30 | |||
31 | [nat] | ||
32 | ENABLE_UPNP = NO | ||
33 | |||
34 | [fs] | ||
35 | IMMEDIATE_START = NO | ||
36 | START_ON_DEMAND = NO | ||
37 | |||
38 | [vpn] | ||
39 | IMMEDIATE_START = NO | ||
40 | START_ON_DEMAND = NO | ||
41 | |||
42 | [revocation] | ||
43 | IMMEDIATE_START = NO | ||
44 | START_ON_DEMAND = NO | ||
45 | |||
46 | [gns] | ||
47 | IMMEDIATE_START = NO | ||
48 | START_ON_DEMAND = NO | ||
49 | |||
50 | [namestore] | ||
51 | IMMEDIATE_START = NO | ||
52 | START_ON_DEMAND = NO | ||
53 | |||
54 | [namecache] | ||
55 | IMMEDIATE_START = NO | ||
56 | START_ON_DEMAND = NO | ||
57 | |||
58 | [topology] | ||
59 | IMMEDIATE_START = NO | ||
60 | START_ON_DEMAND = NO | ||
61 | |||
62 | [nse] | ||
63 | WORKBITS = 0 | ||
diff --git a/src/multicast/test_multicast_multipeer.c b/src/multicast/test_multicast_multipeer.c deleted file mode 100644 index 9b44e05db..000000000 --- a/src/multicast/test_multicast_multipeer.c +++ /dev/null | |||
@@ -1,643 +0,0 @@ | |||
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 "platform.h" | ||
30 | #include "gnunet_crypto_lib.h" | ||
31 | #include "gnunet_common.h" | ||
32 | #include "gnunet_util_lib.h" | ||
33 | #include "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 */ | ||
diff --git a/src/multicast/test_multicast_star.conf b/src/multicast/test_multicast_star.conf deleted file mode 100644 index 516c0e302..000000000 --- a/src/multicast/test_multicast_star.conf +++ /dev/null | |||
@@ -1,64 +0,0 @@ | |||
1 | [testbed] | ||
2 | HOSTNAME = localhost | ||
3 | OVERLAY_TOPOLOGY = STAR | ||
4 | |||
5 | [arm] | ||
6 | GLOBAL_POSTFIX=-L ERROR | ||
7 | |||
8 | [multicast] | ||
9 | #PREFIX = tmux new-window gdb -x ./cmd.gdb --args | ||
10 | #PREFIX = valgrind --leak-check=full | ||
11 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-multicast.sock | ||
12 | |||
13 | [vpn] | ||
14 | START_ON_DEMAND = NO | ||
15 | |||
16 | [peerinfo] | ||
17 | # Do not use shipped gnunet HELLOs | ||
18 | USE_INCLUDED_HELLOS = NO | ||
19 | |||
20 | # Option to disable all disk IO; only useful for testbed runs | ||
21 | # (large-scale experiments); disables persistence of HELLOs! | ||
22 | NO_IO = YES | ||
23 | |||
24 | [cadet] | ||
25 | ID_ANNOUNCE_TIME = 5 s | ||
26 | |||
27 | [hostlist] | ||
28 | IMMEDIATE_START = NO | ||
29 | START_ON_DEMAND = NO | ||
30 | |||
31 | [nat] | ||
32 | ENABLE_UPNP = NO | ||
33 | |||
34 | [fs] | ||
35 | IMMEDIATE_START = NO | ||
36 | START_ON_DEMAND = NO | ||
37 | |||
38 | [vpn] | ||
39 | IMMEDIATE_START = NO | ||
40 | START_ON_DEMAND = NO | ||
41 | |||
42 | [revocation] | ||
43 | IMMEDIATE_START = NO | ||
44 | START_ON_DEMAND = NO | ||
45 | |||
46 | [gns] | ||
47 | IMMEDIATE_START = NO | ||
48 | START_ON_DEMAND = NO | ||
49 | |||
50 | [namestore] | ||
51 | IMMEDIATE_START = NO | ||
52 | START_ON_DEMAND = NO | ||
53 | |||
54 | [namecache] | ||
55 | IMMEDIATE_START = NO | ||
56 | START_ON_DEMAND = NO | ||
57 | |||
58 | [topology] | ||
59 | IMMEDIATE_START = NO | ||
60 | START_ON_DEMAND = NO | ||
61 | |||
62 | [nse] | ||
63 | WORKBITS = 0 | ||
64 | |||
diff --git a/src/psyc/.gitignore b/src/psyc/.gitignore deleted file mode 100644 index 14a175367..000000000 --- a/src/psyc/.gitignore +++ /dev/null | |||
@@ -1,2 +0,0 @@ | |||
1 | gnunet-service-psyc | ||
2 | test_psyc | ||
diff --git a/src/psyc/Makefile.am b/src/psyc/Makefile.am deleted file mode 100644 index 511e3e3f7..000000000 --- a/src/psyc/Makefile.am +++ /dev/null | |||
@@ -1,77 +0,0 @@ | |||
1 | # This Makefile.am is in the public domain | ||
2 | AM_CPPFLAGS = -I$(top_srcdir)/src/include | ||
3 | |||
4 | pkgcfgdir= $(pkgdatadir)/config.d/ | ||
5 | |||
6 | libexecdir= $(pkglibdir)/libexec/ | ||
7 | |||
8 | pkgcfg_DATA = \ | ||
9 | psyc.conf | ||
10 | |||
11 | |||
12 | if MINGW | ||
13 | WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols | ||
14 | endif | ||
15 | |||
16 | if USE_COVERAGE | ||
17 | AM_CFLAGS = --coverage -O0 | ||
18 | XLIB = -lgcov | ||
19 | endif | ||
20 | |||
21 | lib_LTLIBRARIES = libgnunetpsyc.la | ||
22 | |||
23 | libgnunetpsyc_la_SOURCES = \ | ||
24 | psyc_api.c psyc.h | ||
25 | libgnunetpsyc_la_LIBADD = \ | ||
26 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
27 | $(top_builddir)/src/psycutil/libgnunetpsycutil.la \ | ||
28 | $(GN_LIBINTL) $(XLIB) | ||
29 | libgnunetpsyc_la_LDFLAGS = \ | ||
30 | $(GN_LIB_LDFLAGS) $(WINFLAGS) \ | ||
31 | -version-info 0:0:0 | ||
32 | |||
33 | bin_PROGRAMS = | ||
34 | |||
35 | libexec_PROGRAMS = \ | ||
36 | gnunet-service-psyc | ||
37 | |||
38 | gnunet_service_psyc_SOURCES = \ | ||
39 | gnunet-service-psyc.c | ||
40 | gnunet_service_psyc_LDADD = \ | ||
41 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
42 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ | ||
43 | $(top_builddir)/src/multicast/libgnunetmulticast.la \ | ||
44 | $(top_builddir)/src/psycstore/libgnunetpsycstore.la \ | ||
45 | $(top_builddir)/src/psycutil/libgnunetpsycutil.la \ | ||
46 | $(GN_LIBINTL) | ||
47 | gnunet_service_psyc_CFLAGS = $(AM_CFLAGS) | ||
48 | |||
49 | |||
50 | if HAVE_TESTING | ||
51 | check_PROGRAMS = \ | ||
52 | test_psyc | ||
53 | # test_psyc2 | ||
54 | endif | ||
55 | |||
56 | if ENABLE_TEST_RUN | ||
57 | AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME; | ||
58 | TESTS = $(check_PROGRAMS) | ||
59 | endif | ||
60 | |||
61 | test_psyc_SOURCES = \ | ||
62 | test_psyc.c | ||
63 | test_psyc_LDADD = \ | ||
64 | libgnunetpsyc.la \ | ||
65 | $(top_builddir)/src/psycutil/libgnunetpsycutil.la \ | ||
66 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
67 | $(top_builddir)/src/util/libgnunetutil.la | ||
68 | #test_psyc2_SOURCES = \ | ||
69 | # test_psyc2.c | ||
70 | #test_psyc2_LDADD = \ | ||
71 | # libgnunetpsyc.la \ | ||
72 | # $(top_builddir)/src/psycutil/libgnunetpsycutil.la \ | ||
73 | # $(top_builddir)/src/testbed/libgnunettestbed.la \ | ||
74 | # $(top_builddir)/src/util/libgnunetutil.la | ||
75 | |||
76 | EXTRA_DIST = \ | ||
77 | test_psyc.conf | ||
diff --git a/src/psyc/gnunet-service-psyc.c b/src/psyc/gnunet-service-psyc.c deleted file mode 100644 index 6f2f7a999..000000000 --- a/src/psyc/gnunet-service-psyc.c +++ /dev/null | |||
@@ -1,2860 +0,0 @@ | |||
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 psyc/gnunet-service-psyc.c | ||
23 | * @brief PSYC service | ||
24 | * @author Gabor X Toth | ||
25 | */ | ||
26 | |||
27 | #include <inttypes.h> | ||
28 | |||
29 | #include "platform.h" | ||
30 | #include "gnunet_util_lib.h" | ||
31 | #include "gnunet_constants.h" | ||
32 | #include "gnunet_protocols.h" | ||
33 | #include "gnunet_statistics_service.h" | ||
34 | #include "gnunet_multicast_service.h" | ||
35 | #include "gnunet_psycstore_service.h" | ||
36 | #include "gnunet_psyc_service.h" | ||
37 | #include "gnunet_psyc_util_lib.h" | ||
38 | #include "psyc.h" | ||
39 | |||
40 | |||
41 | /** | ||
42 | * Handle to our current configuration. | ||
43 | */ | ||
44 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
45 | |||
46 | /** | ||
47 | * Service handle. | ||
48 | */ | ||
49 | static struct GNUNET_SERVICE_Handle *service; | ||
50 | |||
51 | /** | ||
52 | * Handle to the statistics service. | ||
53 | */ | ||
54 | static struct GNUNET_STATISTICS_Handle *stats; | ||
55 | |||
56 | /** | ||
57 | * Handle to the PSYCstore. | ||
58 | */ | ||
59 | static struct GNUNET_PSYCSTORE_Handle *store; | ||
60 | |||
61 | /** | ||
62 | * All connected masters. | ||
63 | * Channel's pub_key_hash -> struct Master | ||
64 | */ | ||
65 | static struct GNUNET_CONTAINER_MultiHashMap *masters; | ||
66 | |||
67 | /** | ||
68 | * All connected slaves. | ||
69 | * Channel's pub_key_hash -> struct Slave | ||
70 | */ | ||
71 | static struct GNUNET_CONTAINER_MultiHashMap *slaves; | ||
72 | |||
73 | /** | ||
74 | * Connected slaves per channel. | ||
75 | * Channel's pub_key_hash -> Slave's pub_key -> struct Slave | ||
76 | */ | ||
77 | static struct GNUNET_CONTAINER_MultiHashMap *channel_slaves; | ||
78 | |||
79 | |||
80 | /** | ||
81 | * Message in the transmission queue. | ||
82 | */ | ||
83 | struct TransmitMessage | ||
84 | { | ||
85 | struct TransmitMessage *prev; | ||
86 | struct TransmitMessage *next; | ||
87 | |||
88 | struct GNUNET_SERVICE_Client *client; | ||
89 | |||
90 | /** | ||
91 | * ID assigned to the message. | ||
92 | */ | ||
93 | uint64_t id; | ||
94 | |||
95 | /** | ||
96 | * Size of message. | ||
97 | */ | ||
98 | uint16_t size; | ||
99 | |||
100 | /** | ||
101 | * Type of first message part. | ||
102 | */ | ||
103 | uint16_t first_ptype; | ||
104 | |||
105 | /** | ||
106 | * Type of last message part. | ||
107 | */ | ||
108 | uint16_t last_ptype; | ||
109 | |||
110 | /* Followed by message */ | ||
111 | }; | ||
112 | |||
113 | |||
114 | /** | ||
115 | * Cache for received message fragments. | ||
116 | * Message fragments are only sent to clients after all modifiers arrived. | ||
117 | * | ||
118 | * chan_key -> MultiHashMap chan_msgs | ||
119 | */ | ||
120 | static struct GNUNET_CONTAINER_MultiHashMap *recv_cache; | ||
121 | |||
122 | |||
123 | /** | ||
124 | * Entry in the chan_msgs hashmap of @a recv_cache: | ||
125 | * fragment_id -> RecvCacheEntry | ||
126 | */ | ||
127 | struct RecvCacheEntry | ||
128 | { | ||
129 | struct GNUNET_MULTICAST_MessageHeader *mmsg; | ||
130 | uint16_t ref_count; | ||
131 | }; | ||
132 | |||
133 | |||
134 | /** | ||
135 | * Entry in the @a recv_frags hash map of a @a Channel. | ||
136 | * message_id -> FragmentQueue | ||
137 | */ | ||
138 | struct FragmentQueue | ||
139 | { | ||
140 | /** | ||
141 | * Fragment IDs stored in @a recv_cache. | ||
142 | */ | ||
143 | struct GNUNET_CONTAINER_Heap *fragments; | ||
144 | |||
145 | /** | ||
146 | * Total size of received fragments. | ||
147 | */ | ||
148 | uint64_t size; | ||
149 | |||
150 | /** | ||
151 | * Total size of received header fragments (METHOD & MODIFIERs) | ||
152 | */ | ||
153 | uint64_t header_size; | ||
154 | |||
155 | /** | ||
156 | * The @a state_delta field from struct GNUNET_PSYC_MessageMethod. | ||
157 | */ | ||
158 | uint64_t state_delta; | ||
159 | |||
160 | /** | ||
161 | * The @a flags field from struct GNUNET_PSYC_MessageMethod. | ||
162 | */ | ||
163 | uint32_t flags; | ||
164 | |||
165 | /** | ||
166 | * Receive state of message. | ||
167 | * | ||
168 | * @see MessageFragmentState | ||
169 | */ | ||
170 | uint8_t state; | ||
171 | |||
172 | /** | ||
173 | * Whether the state is already modified in PSYCstore. | ||
174 | */ | ||
175 | uint8_t state_is_modified; | ||
176 | |||
177 | /** | ||
178 | * Is the message queued for delivery to the client? | ||
179 | * i.e. added to the recv_msgs queue | ||
180 | */ | ||
181 | uint8_t is_queued; | ||
182 | }; | ||
183 | |||
184 | |||
185 | /** | ||
186 | * List of connected clients. | ||
187 | */ | ||
188 | struct ClientList | ||
189 | { | ||
190 | struct ClientList *prev; | ||
191 | struct ClientList *next; | ||
192 | |||
193 | struct GNUNET_SERVICE_Client *client; | ||
194 | }; | ||
195 | |||
196 | |||
197 | struct Operation | ||
198 | { | ||
199 | struct Operation *prev; | ||
200 | struct Operation *next; | ||
201 | |||
202 | struct GNUNET_SERVICE_Client *client; | ||
203 | struct Channel *channel; | ||
204 | uint64_t op_id; | ||
205 | uint32_t flags; | ||
206 | }; | ||
207 | |||
208 | |||
209 | /** | ||
210 | * Common part of the client context for both a channel master and slave. | ||
211 | */ | ||
212 | struct Channel | ||
213 | { | ||
214 | struct ClientList *clients_head; | ||
215 | struct ClientList *clients_tail; | ||
216 | |||
217 | struct Operation *op_head; | ||
218 | struct Operation *op_tail; | ||
219 | |||
220 | struct TransmitMessage *tmit_head; | ||
221 | struct TransmitMessage *tmit_tail; | ||
222 | |||
223 | /** | ||
224 | * Current PSYCstore operation. | ||
225 | */ | ||
226 | struct GNUNET_PSYCSTORE_OperationHandle *store_op; | ||
227 | |||
228 | /** | ||
229 | * Received fragments not yet sent to the client. | ||
230 | * message_id -> FragmentQueue | ||
231 | */ | ||
232 | struct GNUNET_CONTAINER_MultiHashMap *recv_frags; | ||
233 | |||
234 | /** | ||
235 | * Received message IDs not yet sent to the client. | ||
236 | */ | ||
237 | struct GNUNET_CONTAINER_Heap *recv_msgs; | ||
238 | |||
239 | /** | ||
240 | * Public key of the channel. | ||
241 | */ | ||
242 | struct GNUNET_CRYPTO_EddsaPublicKey pub_key; | ||
243 | |||
244 | /** | ||
245 | * Hash of @a pub_key. | ||
246 | */ | ||
247 | struct GNUNET_HashCode pub_key_hash; | ||
248 | |||
249 | /** | ||
250 | * Last message ID sent to the client. | ||
251 | * 0 if there is no such message. | ||
252 | */ | ||
253 | uint64_t max_message_id; | ||
254 | |||
255 | /** | ||
256 | * ID of the last stateful message, where the state operations has been | ||
257 | * processed and saved to PSYCstore and which has been sent to the client. | ||
258 | * 0 if there is no such message. | ||
259 | */ | ||
260 | uint64_t max_state_message_id; | ||
261 | |||
262 | /** | ||
263 | * Expected value size for the modifier being received from the PSYC service. | ||
264 | */ | ||
265 | uint32_t tmit_mod_value_size_expected; | ||
266 | |||
267 | /** | ||
268 | * Actual value size for the modifier being received from the PSYC service. | ||
269 | */ | ||
270 | uint32_t tmit_mod_value_size; | ||
271 | |||
272 | /** | ||
273 | * Is this channel ready to receive messages from client? | ||
274 | * #GNUNET_YES or #GNUNET_NO | ||
275 | */ | ||
276 | uint8_t is_ready; | ||
277 | |||
278 | /** | ||
279 | * Is the client disconnected? | ||
280 | * #GNUNET_YES or #GNUNET_NO | ||
281 | */ | ||
282 | uint8_t is_disconnecting; | ||
283 | |||
284 | /** | ||
285 | * Is this a channel master (#GNUNET_YES), or slave (#GNUNET_NO)? | ||
286 | */ | ||
287 | uint8_t is_master; | ||
288 | |||
289 | union { | ||
290 | struct Master *master; | ||
291 | struct Slave *slave; | ||
292 | }; | ||
293 | }; | ||
294 | |||
295 | |||
296 | /** | ||
297 | * Client context for a channel master. | ||
298 | */ | ||
299 | struct Master | ||
300 | { | ||
301 | /** | ||
302 | * Channel struct common for Master and Slave | ||
303 | */ | ||
304 | struct Channel channel; | ||
305 | |||
306 | /** | ||
307 | * Private key of the channel. | ||
308 | */ | ||
309 | struct GNUNET_CRYPTO_EddsaPrivateKey priv_key; | ||
310 | |||
311 | /** | ||
312 | * Handle for the multicast origin. | ||
313 | */ | ||
314 | struct GNUNET_MULTICAST_Origin *origin; | ||
315 | |||
316 | /** | ||
317 | * Transmit handle for multicast. | ||
318 | */ | ||
319 | struct GNUNET_MULTICAST_OriginTransmitHandle *tmit_handle; | ||
320 | |||
321 | /** | ||
322 | * Incoming join requests from multicast. | ||
323 | * member_pub_key -> struct GNUNET_MULTICAST_JoinHandle * | ||
324 | */ | ||
325 | struct GNUNET_CONTAINER_MultiHashMap *join_reqs; | ||
326 | |||
327 | /** | ||
328 | * Last message ID transmitted to this channel. | ||
329 | * | ||
330 | * Incremented before sending a message, thus the message_id in messages sent | ||
331 | * starts from 1. | ||
332 | */ | ||
333 | uint64_t max_message_id; | ||
334 | |||
335 | /** | ||
336 | * ID of the last message with state operations transmitted to the channel. | ||
337 | * 0 if there is no such message. | ||
338 | */ | ||
339 | uint64_t max_state_message_id; | ||
340 | |||
341 | /** | ||
342 | * Maximum group generation transmitted to the channel. | ||
343 | */ | ||
344 | uint64_t max_group_generation; | ||
345 | |||
346 | /** | ||
347 | * @see enum GNUNET_PSYC_Policy | ||
348 | */ | ||
349 | enum GNUNET_PSYC_Policy policy; | ||
350 | }; | ||
351 | |||
352 | |||
353 | /** | ||
354 | * Client context for a channel slave. | ||
355 | */ | ||
356 | struct Slave | ||
357 | { | ||
358 | /** | ||
359 | * Channel struct common for Master and Slave | ||
360 | */ | ||
361 | struct Channel channel; | ||
362 | |||
363 | /** | ||
364 | * Private key of the slave. | ||
365 | */ | ||
366 | struct GNUNET_CRYPTO_EcdsaPrivateKey priv_key; | ||
367 | |||
368 | /** | ||
369 | * Public key of the slave. | ||
370 | */ | ||
371 | struct GNUNET_CRYPTO_EcdsaPublicKey pub_key; | ||
372 | |||
373 | /** | ||
374 | * Hash of @a pub_key. | ||
375 | */ | ||
376 | struct GNUNET_HashCode pub_key_hash; | ||
377 | |||
378 | /** | ||
379 | * Handle for the multicast member. | ||
380 | */ | ||
381 | struct GNUNET_MULTICAST_Member *member; | ||
382 | |||
383 | /** | ||
384 | * Transmit handle for multicast. | ||
385 | */ | ||
386 | struct GNUNET_MULTICAST_MemberTransmitHandle *tmit_handle; | ||
387 | |||
388 | /** | ||
389 | * Peer identity of the origin. | ||
390 | */ | ||
391 | struct GNUNET_PeerIdentity origin; | ||
392 | |||
393 | /** | ||
394 | * Number of items in @a relays. | ||
395 | */ | ||
396 | uint32_t relay_count; | ||
397 | |||
398 | /** | ||
399 | * Relays that multicast can use to connect. | ||
400 | */ | ||
401 | struct GNUNET_PeerIdentity *relays; | ||
402 | |||
403 | /** | ||
404 | * Join request to be transmitted to the master on join. | ||
405 | */ | ||
406 | struct GNUNET_PSYC_Message *join_msg; | ||
407 | |||
408 | /** | ||
409 | * Join decision received from multicast. | ||
410 | */ | ||
411 | struct GNUNET_PSYC_JoinDecisionMessage *join_dcsn; | ||
412 | |||
413 | /** | ||
414 | * Maximum request ID for this channel. | ||
415 | */ | ||
416 | uint64_t max_request_id; | ||
417 | |||
418 | /** | ||
419 | * Join flags. | ||
420 | */ | ||
421 | enum GNUNET_PSYC_SlaveJoinFlags join_flags; | ||
422 | }; | ||
423 | |||
424 | |||
425 | /** | ||
426 | * Client context. | ||
427 | */ | ||
428 | struct Client { | ||
429 | struct GNUNET_SERVICE_Client *client; | ||
430 | struct Channel *channel; | ||
431 | }; | ||
432 | |||
433 | |||
434 | struct ReplayRequestKey | ||
435 | { | ||
436 | uint64_t fragment_id; | ||
437 | uint64_t message_id; | ||
438 | uint64_t fragment_offset; | ||
439 | uint64_t flags; | ||
440 | }; | ||
441 | |||
442 | |||
443 | static void | ||
444 | transmit_message (struct Channel *chn); | ||
445 | |||
446 | static uint64_t | ||
447 | message_queue_run (struct Channel *chn); | ||
448 | |||
449 | static uint64_t | ||
450 | message_queue_drop (struct Channel *chn); | ||
451 | |||
452 | |||
453 | static void | ||
454 | schedule_transmit_message (void *cls) | ||
455 | { | ||
456 | struct Channel *chn = cls; | ||
457 | |||
458 | transmit_message (chn); | ||
459 | } | ||
460 | |||
461 | |||
462 | /** | ||
463 | * Task run during shutdown. | ||
464 | * | ||
465 | * @param cls unused | ||
466 | */ | ||
467 | static void | ||
468 | shutdown_task (void *cls) | ||
469 | { | ||
470 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
471 | "shutting down...\n"); | ||
472 | GNUNET_PSYCSTORE_disconnect (store); | ||
473 | if (NULL != stats) | ||
474 | { | ||
475 | GNUNET_STATISTICS_destroy (stats, GNUNET_YES); | ||
476 | stats = NULL; | ||
477 | } | ||
478 | } | ||
479 | |||
480 | |||
481 | static struct Operation * | ||
482 | op_add (struct Channel *chn, struct GNUNET_SERVICE_Client *client, | ||
483 | uint64_t op_id, uint32_t flags) | ||
484 | { | ||
485 | struct Operation *op = GNUNET_malloc (sizeof (*op)); | ||
486 | op->client = client; | ||
487 | op->channel = chn; | ||
488 | op->op_id = op_id; | ||
489 | op->flags = flags; | ||
490 | GNUNET_CONTAINER_DLL_insert (chn->op_head, chn->op_tail, op); | ||
491 | return op; | ||
492 | } | ||
493 | |||
494 | |||
495 | static void | ||
496 | op_remove (struct Operation *op) | ||
497 | { | ||
498 | GNUNET_CONTAINER_DLL_remove (op->channel->op_head, op->channel->op_tail, op); | ||
499 | GNUNET_free (op); | ||
500 | } | ||
501 | |||
502 | |||
503 | /** | ||
504 | * Clean up master data structures after a client disconnected. | ||
505 | */ | ||
506 | static void | ||
507 | cleanup_master (struct Master *mst) | ||
508 | { | ||
509 | struct Channel *chn = &mst->channel; | ||
510 | |||
511 | GNUNET_CONTAINER_multihashmap_destroy (mst->join_reqs); | ||
512 | GNUNET_CONTAINER_multihashmap_remove (masters, &chn->pub_key_hash, mst); | ||
513 | } | ||
514 | |||
515 | |||
516 | /** | ||
517 | * Clean up slave data structures after a client disconnected. | ||
518 | */ | ||
519 | static void | ||
520 | cleanup_slave (struct Slave *slv) | ||
521 | { | ||
522 | struct Channel *chn = &slv->channel; | ||
523 | struct GNUNET_CONTAINER_MultiHashMap * | ||
524 | chn_slv = GNUNET_CONTAINER_multihashmap_get (channel_slaves, | ||
525 | &chn->pub_key_hash); | ||
526 | GNUNET_assert (NULL != chn_slv); | ||
527 | GNUNET_CONTAINER_multihashmap_remove (chn_slv, &slv->pub_key_hash, slv); | ||
528 | |||
529 | if (0 == GNUNET_CONTAINER_multihashmap_size (chn_slv)) | ||
530 | { | ||
531 | GNUNET_CONTAINER_multihashmap_remove (channel_slaves, &chn->pub_key_hash, | ||
532 | chn_slv); | ||
533 | GNUNET_CONTAINER_multihashmap_destroy (chn_slv); | ||
534 | } | ||
535 | GNUNET_CONTAINER_multihashmap_remove (slaves, &chn->pub_key_hash, slv); | ||
536 | |||
537 | if (NULL != slv->join_msg) | ||
538 | { | ||
539 | GNUNET_free (slv->join_msg); | ||
540 | slv->join_msg = NULL; | ||
541 | } | ||
542 | if (NULL != slv->relays) | ||
543 | { | ||
544 | GNUNET_free (slv->relays); | ||
545 | slv->relays = NULL; | ||
546 | } | ||
547 | GNUNET_CONTAINER_multihashmap_remove (slaves, &chn->pub_key_hash, slv); | ||
548 | } | ||
549 | |||
550 | |||
551 | /** | ||
552 | * Clean up channel data structures after a client disconnected. | ||
553 | */ | ||
554 | static void | ||
555 | cleanup_channel (struct Channel *chn) | ||
556 | { | ||
557 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
558 | "%p Cleaning up channel %s. master? %u\n", | ||
559 | chn, | ||
560 | GNUNET_h2s (&chn->pub_key_hash), | ||
561 | chn->is_master); | ||
562 | message_queue_drop (chn); | ||
563 | GNUNET_CONTAINER_multihashmap_destroy (chn->recv_frags); | ||
564 | chn->recv_frags = NULL; | ||
565 | |||
566 | if (NULL != chn->store_op) | ||
567 | { | ||
568 | GNUNET_PSYCSTORE_operation_cancel (chn->store_op); | ||
569 | chn->store_op = NULL; | ||
570 | } | ||
571 | |||
572 | (GNUNET_YES == chn->is_master) | ||
573 | ? cleanup_master (chn->master) | ||
574 | : cleanup_slave (chn->slave); | ||
575 | GNUNET_free (chn); | ||
576 | } | ||
577 | |||
578 | |||
579 | /** | ||
580 | * Called whenever a client is disconnected. | ||
581 | * Frees our resources associated with that client. | ||
582 | * | ||
583 | * @param cls closure | ||
584 | * @param client identification of the client | ||
585 | * @param app_ctx must match @a client | ||
586 | */ | ||
587 | static void | ||
588 | client_notify_disconnect (void *cls, | ||
589 | struct GNUNET_SERVICE_Client *client, | ||
590 | void *app_ctx) | ||
591 | { | ||
592 | struct Client *c = app_ctx; | ||
593 | struct Channel *chn = c->channel; | ||
594 | GNUNET_free (c); | ||
595 | |||
596 | if (NULL == chn) | ||
597 | { | ||
598 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
599 | "%p User context is NULL in client_notify_disconnect ()\n", | ||
600 | chn); | ||
601 | GNUNET_break (0); | ||
602 | return; | ||
603 | } | ||
604 | |||
605 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
606 | "%p Client %p (%s) disconnected from channel %s\n", | ||
607 | chn, | ||
608 | client, | ||
609 | (GNUNET_YES == chn->is_master) ? "master" : "slave", | ||
610 | GNUNET_h2s (&chn->pub_key_hash)); | ||
611 | |||
612 | struct ClientList *cli = chn->clients_head; | ||
613 | while (NULL != cli) | ||
614 | { | ||
615 | if (cli->client == client) | ||
616 | { | ||
617 | GNUNET_CONTAINER_DLL_remove (chn->clients_head, chn->clients_tail, cli); | ||
618 | GNUNET_free (cli); | ||
619 | break; | ||
620 | } | ||
621 | cli = cli->next; | ||
622 | } | ||
623 | |||
624 | struct Operation *op = chn->op_head; | ||
625 | while (NULL != op) | ||
626 | { | ||
627 | if (op->client == client) | ||
628 | { | ||
629 | op->client = NULL; | ||
630 | break; | ||
631 | } | ||
632 | op = op->next; | ||
633 | } | ||
634 | |||
635 | if (NULL == chn->clients_head) | ||
636 | { /* Last client disconnected. */ | ||
637 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
638 | "%p Last client (%s) disconnected from channel %s\n", | ||
639 | chn, | ||
640 | (GNUNET_YES == chn->is_master) ? "master" : "slave", | ||
641 | GNUNET_h2s (&chn->pub_key_hash)); | ||
642 | chn->is_disconnecting = GNUNET_YES; | ||
643 | cleanup_channel (chn); | ||
644 | } | ||
645 | } | ||
646 | |||
647 | |||
648 | /** | ||
649 | * A new client connected. | ||
650 | * | ||
651 | * @param cls NULL | ||
652 | * @param client client to add | ||
653 | * @param mq message queue for @a client | ||
654 | * @return @a client | ||
655 | */ | ||
656 | static void * | ||
657 | client_notify_connect (void *cls, | ||
658 | struct GNUNET_SERVICE_Client *client, | ||
659 | struct GNUNET_MQ_Handle *mq) | ||
660 | { | ||
661 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client connected: %p\n", client); | ||
662 | |||
663 | struct Client *c = GNUNET_malloc (sizeof (*c)); | ||
664 | c->client = client; | ||
665 | |||
666 | return c; | ||
667 | } | ||
668 | |||
669 | |||
670 | /** | ||
671 | * Send message to all clients connected to the channel. | ||
672 | */ | ||
673 | static void | ||
674 | client_send_msg (const struct Channel *chn, | ||
675 | const struct GNUNET_MessageHeader *msg) | ||
676 | { | ||
677 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
678 | "Sending message to clients of channel %p.\n", | ||
679 | chn); | ||
680 | |||
681 | struct ClientList *cli = chn->clients_head; | ||
682 | while (NULL != cli) | ||
683 | { | ||
684 | struct GNUNET_MQ_Envelope * | ||
685 | env = GNUNET_MQ_msg_copy (msg); | ||
686 | |||
687 | GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (cli->client), | ||
688 | env); | ||
689 | cli = cli->next; | ||
690 | } | ||
691 | } | ||
692 | |||
693 | |||
694 | /** | ||
695 | * Send a result code back to the client. | ||
696 | * | ||
697 | * @param client | ||
698 | * Client that should receive the result code. | ||
699 | * @param result_code | ||
700 | * Code to transmit. | ||
701 | * @param op_id | ||
702 | * Operation ID in network byte order. | ||
703 | * @param data | ||
704 | * Data payload or NULL. | ||
705 | * @param data_size | ||
706 | * Size of @a data. | ||
707 | */ | ||
708 | static void | ||
709 | client_send_result (struct GNUNET_SERVICE_Client *client, uint64_t op_id, | ||
710 | int64_t result_code, const void *data, uint16_t data_size) | ||
711 | { | ||
712 | struct GNUNET_OperationResultMessage *res; | ||
713 | struct GNUNET_MQ_Envelope * | ||
714 | env = GNUNET_MQ_msg_extra (res, | ||
715 | data_size, | ||
716 | GNUNET_MESSAGE_TYPE_PSYC_RESULT_CODE); | ||
717 | res->result_code = GNUNET_htonll (result_code); | ||
718 | res->op_id = op_id; | ||
719 | if (0 < data_size) | ||
720 | GNUNET_memcpy (&res[1], data, data_size); | ||
721 | |||
722 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
723 | "%p Sending result to client for OP ID %" PRIu64 ": %" PRId64 " (size: %u)\n", | ||
724 | client, | ||
725 | GNUNET_ntohll (op_id), | ||
726 | result_code, | ||
727 | data_size); | ||
728 | |||
729 | GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), env); | ||
730 | } | ||
731 | |||
732 | |||
733 | /** | ||
734 | * Closure for join_mem_test_cb() | ||
735 | */ | ||
736 | struct JoinMemTestClosure | ||
737 | { | ||
738 | struct GNUNET_CRYPTO_EcdsaPublicKey slave_pub_key; | ||
739 | struct Channel *channel; | ||
740 | struct GNUNET_MULTICAST_JoinHandle *join_handle; | ||
741 | struct GNUNET_PSYC_JoinRequestMessage *join_msg; | ||
742 | }; | ||
743 | |||
744 | |||
745 | /** | ||
746 | * Membership test result callback used for join requests. | ||
747 | */ | ||
748 | static void | ||
749 | join_mem_test_cb (void *cls, int64_t result, | ||
750 | const char *err_msg, uint16_t err_msg_size) | ||
751 | { | ||
752 | struct JoinMemTestClosure *jcls = cls; | ||
753 | |||
754 | if (GNUNET_NO == result && GNUNET_YES == jcls->channel->is_master) | ||
755 | { /* Pass on join request to client if this is a master channel */ | ||
756 | struct Master *mst = jcls->channel->master; | ||
757 | struct GNUNET_HashCode slave_pub_hash; | ||
758 | GNUNET_CRYPTO_hash (&jcls->slave_pub_key, sizeof (jcls->slave_pub_key), | ||
759 | &slave_pub_hash); | ||
760 | GNUNET_CONTAINER_multihashmap_put (mst->join_reqs, &slave_pub_hash, jcls->join_handle, | ||
761 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
762 | client_send_msg (jcls->channel, &jcls->join_msg->header); | ||
763 | } | ||
764 | else | ||
765 | { | ||
766 | if (GNUNET_SYSERR == result) | ||
767 | { | ||
768 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
769 | "Could not perform membership test (%.*s)\n", | ||
770 | err_msg_size, err_msg); | ||
771 | } | ||
772 | // FIXME: add relays | ||
773 | GNUNET_MULTICAST_join_decision (jcls->join_handle, result, 0, NULL, NULL); | ||
774 | } | ||
775 | GNUNET_free (jcls->join_msg); | ||
776 | GNUNET_free (jcls); | ||
777 | } | ||
778 | |||
779 | |||
780 | /** | ||
781 | * Incoming join request from multicast. | ||
782 | */ | ||
783 | static void | ||
784 | mcast_recv_join_request (void *cls, | ||
785 | const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_pub_key, | ||
786 | const struct GNUNET_MessageHeader *join_msg, | ||
787 | struct GNUNET_MULTICAST_JoinHandle *jh) | ||
788 | { | ||
789 | struct Channel *chn = cls; | ||
790 | uint16_t join_msg_size = 0; | ||
791 | |||
792 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
793 | "%p Got join request.\n", | ||
794 | chn); | ||
795 | if (NULL != join_msg) | ||
796 | { | ||
797 | if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE == ntohs (join_msg->type)) | ||
798 | { | ||
799 | join_msg_size = ntohs (join_msg->size); | ||
800 | } | ||
801 | else | ||
802 | { | ||
803 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
804 | "%p Got join message with invalid type %u.\n", | ||
805 | chn, | ||
806 | ntohs (join_msg->type)); | ||
807 | } | ||
808 | } | ||
809 | |||
810 | struct GNUNET_PSYC_JoinRequestMessage * | ||
811 | req = GNUNET_malloc (sizeof (*req) + join_msg_size); | ||
812 | req->header.size = htons (sizeof (*req) + join_msg_size); | ||
813 | req->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_JOIN_REQUEST); | ||
814 | req->slave_pub_key = *slave_pub_key; | ||
815 | if (0 < join_msg_size) | ||
816 | GNUNET_memcpy (&req[1], join_msg, join_msg_size); | ||
817 | |||
818 | struct JoinMemTestClosure *jcls = GNUNET_malloc (sizeof (*jcls)); | ||
819 | jcls->slave_pub_key = *slave_pub_key; | ||
820 | jcls->channel = chn; | ||
821 | jcls->join_handle = jh; | ||
822 | jcls->join_msg = req; | ||
823 | |||
824 | GNUNET_PSYCSTORE_membership_test (store, &chn->pub_key, slave_pub_key, | ||
825 | chn->max_message_id, 0, | ||
826 | &join_mem_test_cb, jcls); | ||
827 | } | ||
828 | |||
829 | |||
830 | /** | ||
831 | * Join decision received from multicast. | ||
832 | */ | ||
833 | static void | ||
834 | mcast_recv_join_decision (void *cls, int is_admitted, | ||
835 | const struct GNUNET_PeerIdentity *peer, | ||
836 | uint16_t relay_count, | ||
837 | const struct GNUNET_PeerIdentity *relays, | ||
838 | const struct GNUNET_MessageHeader *join_resp) | ||
839 | { | ||
840 | struct Slave *slv = cls; | ||
841 | struct Channel *chn = &slv->channel; | ||
842 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
843 | "%p Got join decision: %d\n", | ||
844 | slv, | ||
845 | is_admitted); | ||
846 | if (GNUNET_YES == chn->is_ready) | ||
847 | { | ||
848 | /* Already admitted */ | ||
849 | return; | ||
850 | } | ||
851 | |||
852 | uint16_t join_resp_size = (NULL != join_resp) ? ntohs (join_resp->size) : 0; | ||
853 | struct GNUNET_PSYC_JoinDecisionMessage * | ||
854 | dcsn = slv->join_dcsn = GNUNET_malloc (sizeof (*dcsn) + join_resp_size); | ||
855 | dcsn->header.size = htons (sizeof (*dcsn) + join_resp_size); | ||
856 | dcsn->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION); | ||
857 | dcsn->is_admitted = htonl (is_admitted); | ||
858 | if (0 < join_resp_size) | ||
859 | GNUNET_memcpy (&dcsn[1], join_resp, join_resp_size); | ||
860 | |||
861 | client_send_msg (chn, &dcsn->header); | ||
862 | |||
863 | if (GNUNET_YES == is_admitted | ||
864 | && ! (GNUNET_PSYC_SLAVE_JOIN_LOCAL & slv->join_flags)) | ||
865 | { | ||
866 | chn->is_ready = GNUNET_YES; | ||
867 | } | ||
868 | } | ||
869 | |||
870 | |||
871 | static int | ||
872 | store_recv_fragment_replay (void *cls, | ||
873 | struct GNUNET_MULTICAST_MessageHeader *msg, | ||
874 | enum GNUNET_PSYCSTORE_MessageFlags flags) | ||
875 | { | ||
876 | struct GNUNET_MULTICAST_ReplayHandle *rh = cls; | ||
877 | |||
878 | GNUNET_MULTICAST_replay_response (rh, &msg->header, GNUNET_MULTICAST_REC_OK); | ||
879 | return GNUNET_YES; | ||
880 | } | ||
881 | |||
882 | |||
883 | /** | ||
884 | * Received result of GNUNET_PSYCSTORE_fragment_get() for multicast replay. | ||
885 | */ | ||
886 | static void | ||
887 | store_recv_fragment_replay_result (void *cls, | ||
888 | int64_t result, | ||
889 | const char *err_msg, | ||
890 | uint16_t err_msg_size) | ||
891 | { | ||
892 | struct GNUNET_MULTICAST_ReplayHandle *rh = cls; | ||
893 | |||
894 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
895 | "%p Fragment replay: PSYCSTORE returned %" PRId64 " (%.*s)\n", | ||
896 | rh, | ||
897 | result, | ||
898 | err_msg_size, | ||
899 | err_msg); | ||
900 | switch (result) | ||
901 | { | ||
902 | case GNUNET_YES: | ||
903 | break; | ||
904 | |||
905 | case GNUNET_NO: | ||
906 | GNUNET_MULTICAST_replay_response (rh, NULL, | ||
907 | GNUNET_MULTICAST_REC_NOT_FOUND); | ||
908 | return; | ||
909 | |||
910 | case GNUNET_PSYCSTORE_MEMBERSHIP_TEST_FAILED: | ||
911 | GNUNET_MULTICAST_replay_response (rh, NULL, | ||
912 | GNUNET_MULTICAST_REC_ACCESS_DENIED); | ||
913 | return; | ||
914 | |||
915 | case GNUNET_SYSERR: | ||
916 | GNUNET_MULTICAST_replay_response (rh, NULL, | ||
917 | GNUNET_MULTICAST_REC_INTERNAL_ERROR); | ||
918 | return; | ||
919 | } | ||
920 | /* GNUNET_MULTICAST_replay_response frees 'rh' when passed | ||
921 | * an error code, so it must be ensured no further processing | ||
922 | * is attempted on 'rh'. Maybe this should be refactored as | ||
923 | * it doesn't look very intuitive. --lynX | ||
924 | */ | ||
925 | GNUNET_MULTICAST_replay_response_end (rh); | ||
926 | } | ||
927 | |||
928 | |||
929 | /** | ||
930 | * Incoming fragment replay request from multicast. | ||
931 | */ | ||
932 | static void | ||
933 | mcast_recv_replay_fragment (void *cls, | ||
934 | const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_pub_key, | ||
935 | uint64_t fragment_id, uint64_t flags, | ||
936 | struct GNUNET_MULTICAST_ReplayHandle *rh) | ||
937 | |||
938 | { | ||
939 | struct Channel *chn = cls; | ||
940 | GNUNET_PSYCSTORE_fragment_get (store, &chn->pub_key, slave_pub_key, | ||
941 | fragment_id, fragment_id, | ||
942 | &store_recv_fragment_replay, | ||
943 | &store_recv_fragment_replay_result, rh); | ||
944 | } | ||
945 | |||
946 | |||
947 | /** | ||
948 | * Incoming message replay request from multicast. | ||
949 | */ | ||
950 | static void | ||
951 | mcast_recv_replay_message (void *cls, | ||
952 | const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_pub_key, | ||
953 | uint64_t message_id, | ||
954 | uint64_t fragment_offset, | ||
955 | uint64_t flags, | ||
956 | struct GNUNET_MULTICAST_ReplayHandle *rh) | ||
957 | { | ||
958 | struct Channel *chn = cls; | ||
959 | GNUNET_PSYCSTORE_message_get (store, &chn->pub_key, slave_pub_key, | ||
960 | message_id, message_id, 1, NULL, | ||
961 | &store_recv_fragment_replay, | ||
962 | &store_recv_fragment_replay_result, rh); | ||
963 | } | ||
964 | |||
965 | |||
966 | /** | ||
967 | * Convert an uint64_t in network byte order to a HashCode | ||
968 | * that can be used as key in a MultiHashMap | ||
969 | */ | ||
970 | static inline void | ||
971 | hash_key_from_nll (struct GNUNET_HashCode *key, uint64_t n) | ||
972 | { | ||
973 | /* use little-endian order, as idx_of MultiHashMap casts key to unsigned int */ | ||
974 | /* TODO: use built-in byte swap functions if available */ | ||
975 | |||
976 | n = ((n << 8) & 0xFF00FF00FF00FF00ULL) | ((n >> 8) & 0x00FF00FF00FF00FFULL); | ||
977 | n = ((n << 16) & 0xFFFF0000FFFF0000ULL) | ((n >> 16) & 0x0000FFFF0000FFFFULL); | ||
978 | |||
979 | *key = (struct GNUNET_HashCode) {}; | ||
980 | *((uint64_t *) key) | ||
981 | = (n << 32) | (n >> 32); | ||
982 | } | ||
983 | |||
984 | |||
985 | /** | ||
986 | * Convert an uint64_t in host byte order to a HashCode | ||
987 | * that can be used as key in a MultiHashMap | ||
988 | */ | ||
989 | static inline void | ||
990 | hash_key_from_hll (struct GNUNET_HashCode *key, uint64_t n) | ||
991 | { | ||
992 | #if __BYTE_ORDER == __BIG_ENDIAN | ||
993 | hash_key_from_nll (key, n); | ||
994 | #elif __BYTE_ORDER == __LITTLE_ENDIAN | ||
995 | *key = (struct GNUNET_HashCode) {}; | ||
996 | *((uint64_t *) key) = n; | ||
997 | #else | ||
998 | #error byteorder undefined | ||
999 | #endif | ||
1000 | } | ||
1001 | |||
1002 | |||
1003 | /** | ||
1004 | * Initialize PSYC message header. | ||
1005 | */ | ||
1006 | static inline void | ||
1007 | psyc_msg_init (struct GNUNET_PSYC_MessageHeader *pmsg, | ||
1008 | const struct GNUNET_MULTICAST_MessageHeader *mmsg, uint32_t flags) | ||
1009 | { | ||
1010 | uint16_t size = ntohs (mmsg->header.size); | ||
1011 | uint16_t psize = sizeof (*pmsg) + size - sizeof (*mmsg); | ||
1012 | |||
1013 | pmsg->header.size = htons (psize); | ||
1014 | pmsg->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE); | ||
1015 | pmsg->message_id = mmsg->message_id; | ||
1016 | pmsg->fragment_offset = mmsg->fragment_offset; | ||
1017 | pmsg->flags = htonl (flags); | ||
1018 | |||
1019 | GNUNET_memcpy (&pmsg[1], &mmsg[1], size - sizeof (*mmsg)); | ||
1020 | } | ||
1021 | |||
1022 | |||
1023 | /** | ||
1024 | * Create a new PSYC message from a multicast message for sending it to clients. | ||
1025 | */ | ||
1026 | static inline struct GNUNET_PSYC_MessageHeader * | ||
1027 | psyc_msg_new (const struct GNUNET_MULTICAST_MessageHeader *mmsg, uint32_t flags) | ||
1028 | { | ||
1029 | struct GNUNET_PSYC_MessageHeader *pmsg; | ||
1030 | uint16_t size = ntohs (mmsg->header.size); | ||
1031 | uint16_t psize = sizeof (*pmsg) + size - sizeof (*mmsg); | ||
1032 | |||
1033 | pmsg = GNUNET_malloc (psize); | ||
1034 | psyc_msg_init (pmsg, mmsg, flags); | ||
1035 | return pmsg; | ||
1036 | } | ||
1037 | |||
1038 | |||
1039 | /** | ||
1040 | * Send multicast message to all clients connected to the channel. | ||
1041 | */ | ||
1042 | static void | ||
1043 | client_send_mcast_msg (struct Channel *chn, | ||
1044 | const struct GNUNET_MULTICAST_MessageHeader *mmsg, | ||
1045 | uint32_t flags) | ||
1046 | { | ||
1047 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1048 | "%p Sending multicast message to client. fragment_id: %" PRIu64 ", message_id: %" PRIu64 "\n", | ||
1049 | chn, | ||
1050 | GNUNET_ntohll (mmsg->fragment_id), | ||
1051 | GNUNET_ntohll (mmsg->message_id)); | ||
1052 | |||
1053 | struct GNUNET_PSYC_MessageHeader * | ||
1054 | pmsg = GNUNET_PSYC_message_header_create (mmsg, flags); | ||
1055 | client_send_msg (chn, &pmsg->header); | ||
1056 | GNUNET_free (pmsg); | ||
1057 | } | ||
1058 | |||
1059 | |||
1060 | /** | ||
1061 | * Send multicast request to all clients connected to the channel. | ||
1062 | */ | ||
1063 | static void | ||
1064 | client_send_mcast_req (struct Master *mst, | ||
1065 | const struct GNUNET_MULTICAST_RequestHeader *req) | ||
1066 | { | ||
1067 | struct Channel *chn = &mst->channel; | ||
1068 | |||
1069 | struct GNUNET_PSYC_MessageHeader *pmsg; | ||
1070 | uint16_t size = ntohs (req->header.size); | ||
1071 | uint16_t psize = sizeof (*pmsg) + size - sizeof (*req); | ||
1072 | |||
1073 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1074 | "%p Sending multicast request to client. fragment_id: %" PRIu64 ", message_id: %" PRIu64 "\n", | ||
1075 | chn, | ||
1076 | GNUNET_ntohll (req->fragment_id), | ||
1077 | GNUNET_ntohll (req->request_id)); | ||
1078 | |||
1079 | pmsg = GNUNET_malloc (psize); | ||
1080 | pmsg->header.size = htons (psize); | ||
1081 | pmsg->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE); | ||
1082 | pmsg->message_id = req->request_id; | ||
1083 | pmsg->fragment_offset = req->fragment_offset; | ||
1084 | pmsg->flags = htonl (GNUNET_PSYC_MESSAGE_REQUEST); | ||
1085 | pmsg->slave_pub_key = req->member_pub_key; | ||
1086 | GNUNET_memcpy (&pmsg[1], &req[1], size - sizeof (*req)); | ||
1087 | |||
1088 | client_send_msg (chn, &pmsg->header); | ||
1089 | |||
1090 | /* FIXME: save req to PSYCstore so that it can be resent later to clients */ | ||
1091 | |||
1092 | GNUNET_free (pmsg); | ||
1093 | } | ||
1094 | |||
1095 | |||
1096 | /** | ||
1097 | * Insert a multicast message fragment into the queue belonging to the message. | ||
1098 | * | ||
1099 | * @param chn Channel. | ||
1100 | * @param mmsg Multicast message fragment. | ||
1101 | * @param msg_id_hash Message ID of @a mmsg in a struct GNUNET_HashCode. | ||
1102 | * @param first_ptype First PSYC message part type in @a mmsg. | ||
1103 | * @param last_ptype Last PSYC message part type in @a mmsg. | ||
1104 | */ | ||
1105 | static void | ||
1106 | fragment_queue_insert (struct Channel *chn, | ||
1107 | const struct GNUNET_MULTICAST_MessageHeader *mmsg, | ||
1108 | uint16_t first_ptype, uint16_t last_ptype) | ||
1109 | { | ||
1110 | const uint16_t size = ntohs (mmsg->header.size); | ||
1111 | const uint64_t frag_offset = GNUNET_ntohll (mmsg->fragment_offset); | ||
1112 | struct GNUNET_CONTAINER_MultiHashMap | ||
1113 | *chan_msgs = GNUNET_CONTAINER_multihashmap_get (recv_cache, | ||
1114 | &chn->pub_key_hash); | ||
1115 | |||
1116 | struct GNUNET_HashCode msg_id_hash; | ||
1117 | hash_key_from_nll (&msg_id_hash, mmsg->message_id); | ||
1118 | |||
1119 | struct FragmentQueue | ||
1120 | *fragq = GNUNET_CONTAINER_multihashmap_get (chn->recv_frags, &msg_id_hash); | ||
1121 | |||
1122 | if (NULL == fragq) | ||
1123 | { | ||
1124 | fragq = GNUNET_malloc (sizeof (*fragq)); | ||
1125 | fragq->state = MSG_FRAG_STATE_HEADER; | ||
1126 | fragq->fragments | ||
1127 | = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); | ||
1128 | |||
1129 | GNUNET_CONTAINER_multihashmap_put (chn->recv_frags, &msg_id_hash, fragq, | ||
1130 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); | ||
1131 | |||
1132 | if (NULL == chan_msgs) | ||
1133 | { | ||
1134 | chan_msgs = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); | ||
1135 | GNUNET_CONTAINER_multihashmap_put (recv_cache, &chn->pub_key_hash, chan_msgs, | ||
1136 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); | ||
1137 | } | ||
1138 | } | ||
1139 | |||
1140 | struct GNUNET_HashCode frag_id_hash; | ||
1141 | hash_key_from_nll (&frag_id_hash, mmsg->fragment_id); | ||
1142 | struct RecvCacheEntry | ||
1143 | *cache_entry = GNUNET_CONTAINER_multihashmap_get (chan_msgs, &frag_id_hash); | ||
1144 | if (NULL == cache_entry) | ||
1145 | { | ||
1146 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1147 | "%p Adding message fragment to cache. message_id: %" PRIu64 ", fragment_id: %" PRIu64 "\n", | ||
1148 | chn, | ||
1149 | GNUNET_ntohll (mmsg->message_id), | ||
1150 | GNUNET_ntohll (mmsg->fragment_id)); | ||
1151 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1152 | "%p header_size: %" PRIu64 " + %u\n", | ||
1153 | chn, | ||
1154 | fragq->header_size, | ||
1155 | size); | ||
1156 | cache_entry = GNUNET_malloc (sizeof (*cache_entry)); | ||
1157 | cache_entry->ref_count = 1; | ||
1158 | cache_entry->mmsg = GNUNET_malloc (size); | ||
1159 | GNUNET_memcpy (cache_entry->mmsg, mmsg, size); | ||
1160 | GNUNET_CONTAINER_multihashmap_put (chan_msgs, &frag_id_hash, cache_entry, | ||
1161 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); | ||
1162 | } | ||
1163 | else | ||
1164 | { | ||
1165 | cache_entry->ref_count++; | ||
1166 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1167 | "%p Message fragment is already in cache. message_id: %" PRIu64 ", fragment_id: %" PRIu64 ", ref_count: %u\n", | ||
1168 | chn, | ||
1169 | GNUNET_ntohll (mmsg->message_id), | ||
1170 | GNUNET_ntohll (mmsg->fragment_id), | ||
1171 | cache_entry->ref_count); | ||
1172 | } | ||
1173 | |||
1174 | if (MSG_FRAG_STATE_HEADER == fragq->state) | ||
1175 | { | ||
1176 | if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD == first_ptype) | ||
1177 | { | ||
1178 | struct GNUNET_PSYC_MessageMethod * | ||
1179 | pmeth = (struct GNUNET_PSYC_MessageMethod *) &mmsg[1]; | ||
1180 | fragq->state_delta = GNUNET_ntohll (pmeth->state_delta); | ||
1181 | fragq->flags = ntohl (pmeth->flags); | ||
1182 | } | ||
1183 | |||
1184 | if (last_ptype < GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA) | ||
1185 | { | ||
1186 | fragq->header_size += size; | ||
1187 | } | ||
1188 | else if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD == first_ptype | ||
1189 | || frag_offset == fragq->header_size) | ||
1190 | { /* header is now complete */ | ||
1191 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1192 | "%p Header of message %" PRIu64 " is complete.\n", | ||
1193 | chn, | ||
1194 | GNUNET_ntohll (mmsg->message_id)); | ||
1195 | |||
1196 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1197 | "%p Adding message %" PRIu64 " to queue.\n", | ||
1198 | chn, | ||
1199 | GNUNET_ntohll (mmsg->message_id)); | ||
1200 | fragq->state = MSG_FRAG_STATE_DATA; | ||
1201 | } | ||
1202 | else | ||
1203 | { | ||
1204 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1205 | "%p Header of message %" PRIu64 " is NOT complete yet: %" PRIu64 " != %" PRIu64 "\n", | ||
1206 | chn, | ||
1207 | GNUNET_ntohll (mmsg->message_id), | ||
1208 | frag_offset, | ||
1209 | fragq->header_size); | ||
1210 | } | ||
1211 | } | ||
1212 | |||
1213 | switch (last_ptype) | ||
1214 | { | ||
1215 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END: | ||
1216 | if (frag_offset == fragq->size) | ||
1217 | fragq->state = MSG_FRAG_STATE_END; | ||
1218 | else | ||
1219 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1220 | "%p Message %" PRIu64 " is NOT complete yet: %" PRIu64 " != %" PRIu64 "\n", | ||
1221 | chn, | ||
1222 | GNUNET_ntohll (mmsg->message_id), | ||
1223 | frag_offset, | ||
1224 | fragq->size); | ||
1225 | break; | ||
1226 | |||
1227 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL: | ||
1228 | /* Drop message without delivering to client if it's a single fragment */ | ||
1229 | fragq->state = | ||
1230 | (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD == first_ptype) | ||
1231 | ? MSG_FRAG_STATE_DROP | ||
1232 | : MSG_FRAG_STATE_CANCEL; | ||
1233 | } | ||
1234 | |||
1235 | switch (fragq->state) | ||
1236 | { | ||
1237 | case MSG_FRAG_STATE_DATA: | ||
1238 | case MSG_FRAG_STATE_END: | ||
1239 | case MSG_FRAG_STATE_CANCEL: | ||
1240 | if (GNUNET_NO == fragq->is_queued) | ||
1241 | { | ||
1242 | GNUNET_CONTAINER_heap_insert (chn->recv_msgs, NULL, | ||
1243 | GNUNET_ntohll (mmsg->message_id)); | ||
1244 | fragq->is_queued = GNUNET_YES; | ||
1245 | } | ||
1246 | } | ||
1247 | |||
1248 | fragq->size += size; | ||
1249 | GNUNET_CONTAINER_heap_insert (fragq->fragments, NULL, | ||
1250 | GNUNET_ntohll (mmsg->fragment_id)); | ||
1251 | } | ||
1252 | |||
1253 | |||
1254 | /** | ||
1255 | * Run fragment queue of a message. | ||
1256 | * | ||
1257 | * Send fragments of a message in order to client, after all modifiers arrived | ||
1258 | * from multicast. | ||
1259 | * | ||
1260 | * @param chn | ||
1261 | * Channel. | ||
1262 | * @param msg_id | ||
1263 | * ID of the message @a fragq belongs to. | ||
1264 | * @param fragq | ||
1265 | * Fragment queue of the message. | ||
1266 | * @param drop | ||
1267 | * Drop message without delivering to client? | ||
1268 | * #GNUNET_YES or #GNUNET_NO. | ||
1269 | */ | ||
1270 | static void | ||
1271 | fragment_queue_run (struct Channel *chn, uint64_t msg_id, | ||
1272 | struct FragmentQueue *fragq, uint8_t drop) | ||
1273 | { | ||
1274 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1275 | "%p Running message fragment queue for message %" PRIu64 " (state: %u).\n", | ||
1276 | chn, | ||
1277 | msg_id, | ||
1278 | fragq->state); | ||
1279 | |||
1280 | struct GNUNET_CONTAINER_MultiHashMap | ||
1281 | *chan_msgs = GNUNET_CONTAINER_multihashmap_get (recv_cache, | ||
1282 | &chn->pub_key_hash); | ||
1283 | GNUNET_assert (NULL != chan_msgs); | ||
1284 | uint64_t frag_id; | ||
1285 | |||
1286 | while (GNUNET_YES == GNUNET_CONTAINER_heap_peek2 (fragq->fragments, NULL, | ||
1287 | &frag_id)) | ||
1288 | { | ||
1289 | struct GNUNET_HashCode frag_id_hash; | ||
1290 | hash_key_from_hll (&frag_id_hash, frag_id); | ||
1291 | struct RecvCacheEntry *cache_entry | ||
1292 | = GNUNET_CONTAINER_multihashmap_get (chan_msgs, &frag_id_hash); | ||
1293 | if (cache_entry != NULL) | ||
1294 | { | ||
1295 | if (GNUNET_NO == drop) | ||
1296 | { | ||
1297 | client_send_mcast_msg (chn, cache_entry->mmsg, 0); | ||
1298 | } | ||
1299 | if (cache_entry->ref_count <= 1) | ||
1300 | { | ||
1301 | GNUNET_CONTAINER_multihashmap_remove (chan_msgs, &frag_id_hash, | ||
1302 | cache_entry); | ||
1303 | GNUNET_free (cache_entry->mmsg); | ||
1304 | GNUNET_free (cache_entry); | ||
1305 | } | ||
1306 | else | ||
1307 | { | ||
1308 | cache_entry->ref_count--; | ||
1309 | } | ||
1310 | } | ||
1311 | #if CACHE_AGING_IMPLEMENTED | ||
1312 | else if (GNUNET_NO == drop) | ||
1313 | { | ||
1314 | /* TODO: fragment not in cache anymore, retrieve it from PSYCstore */ | ||
1315 | } | ||
1316 | #endif | ||
1317 | |||
1318 | GNUNET_CONTAINER_heap_remove_root (fragq->fragments); | ||
1319 | } | ||
1320 | |||
1321 | if (MSG_FRAG_STATE_END <= fragq->state) | ||
1322 | { | ||
1323 | struct GNUNET_HashCode msg_id_hash; | ||
1324 | hash_key_from_hll (&msg_id_hash, msg_id); | ||
1325 | |||
1326 | GNUNET_CONTAINER_multihashmap_remove (chn->recv_frags, &msg_id_hash, fragq); | ||
1327 | GNUNET_CONTAINER_heap_destroy (fragq->fragments); | ||
1328 | GNUNET_free (fragq); | ||
1329 | } | ||
1330 | else | ||
1331 | { | ||
1332 | fragq->is_queued = GNUNET_NO; | ||
1333 | } | ||
1334 | } | ||
1335 | |||
1336 | |||
1337 | struct StateModifyClosure | ||
1338 | { | ||
1339 | struct Channel *channel; | ||
1340 | uint64_t msg_id; | ||
1341 | struct GNUNET_HashCode msg_id_hash; | ||
1342 | }; | ||
1343 | |||
1344 | |||
1345 | void | ||
1346 | store_recv_state_modify_result (void *cls, int64_t result, | ||
1347 | const char *err_msg, uint16_t err_msg_size) | ||
1348 | { | ||
1349 | struct StateModifyClosure *mcls = cls; | ||
1350 | struct Channel *chn = mcls->channel; | ||
1351 | uint64_t msg_id = mcls->msg_id; | ||
1352 | |||
1353 | struct FragmentQueue * | ||
1354 | fragq = GNUNET_CONTAINER_multihashmap_get (chn->recv_frags, &mcls->msg_id_hash); | ||
1355 | |||
1356 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1357 | "%p GNUNET_PSYCSTORE_state_modify() returned %" PRId64 " (%.*s)\n", | ||
1358 | chn, result, err_msg_size, err_msg); | ||
1359 | |||
1360 | switch (result) | ||
1361 | { | ||
1362 | case GNUNET_OK: | ||
1363 | case GNUNET_NO: | ||
1364 | if (NULL != fragq) | ||
1365 | fragq->state_is_modified = GNUNET_YES; | ||
1366 | if (chn->max_state_message_id < msg_id) | ||
1367 | chn->max_state_message_id = msg_id; | ||
1368 | if (chn->max_message_id < msg_id) | ||
1369 | chn->max_message_id = msg_id; | ||
1370 | |||
1371 | if (NULL != fragq) | ||
1372 | fragment_queue_run (chn, msg_id, fragq, MSG_FRAG_STATE_DROP == fragq->state); | ||
1373 | GNUNET_CONTAINER_heap_remove_root (chn->recv_msgs); | ||
1374 | message_queue_run (chn); | ||
1375 | break; | ||
1376 | |||
1377 | default: | ||
1378 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1379 | "%p GNUNET_PSYCSTORE_state_modify() failed with error %" PRId64 " (%.*s)\n", | ||
1380 | chn, result, err_msg_size, err_msg); | ||
1381 | /** @todo FIXME: handle state_modify error */ | ||
1382 | } | ||
1383 | } | ||
1384 | |||
1385 | |||
1386 | /** | ||
1387 | * Run message queue. | ||
1388 | * | ||
1389 | * Send messages in queue to client in order after a message has arrived from | ||
1390 | * multicast, according to the following: | ||
1391 | * - A message is only sent if all of its modifiers arrived. | ||
1392 | * - A stateful message is only sent if the previous stateful message | ||
1393 | * has already been delivered to the client. | ||
1394 | * | ||
1395 | * @param chn Channel. | ||
1396 | * | ||
1397 | * @return Number of messages removed from queue and sent to client. | ||
1398 | */ | ||
1399 | static uint64_t | ||
1400 | message_queue_run (struct Channel *chn) | ||
1401 | { | ||
1402 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1403 | "%p Running message queue.\n", chn); | ||
1404 | uint64_t n = 0; | ||
1405 | uint64_t msg_id; | ||
1406 | |||
1407 | while (GNUNET_YES == GNUNET_CONTAINER_heap_peek2 (chn->recv_msgs, NULL, | ||
1408 | &msg_id)) | ||
1409 | { | ||
1410 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1411 | "%p Processing message %" PRIu64 " in queue.\n", chn, msg_id); | ||
1412 | struct GNUNET_HashCode msg_id_hash; | ||
1413 | hash_key_from_hll (&msg_id_hash, msg_id); | ||
1414 | |||
1415 | struct FragmentQueue * | ||
1416 | fragq = GNUNET_CONTAINER_multihashmap_get (chn->recv_frags, &msg_id_hash); | ||
1417 | |||
1418 | if (NULL == fragq || fragq->state <= MSG_FRAG_STATE_HEADER) | ||
1419 | { | ||
1420 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1421 | "%p No fragq (%p) or header not complete.\n", | ||
1422 | chn, fragq); | ||
1423 | break; | ||
1424 | } | ||
1425 | |||
1426 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1427 | "%p Fragment queue entry: state: %u, state delta: " | ||
1428 | "%" PRIu64 " - %" PRIu64 " ?= %" PRIu64 "\n", | ||
1429 | chn, fragq->state, msg_id, fragq->state_delta, chn->max_state_message_id); | ||
1430 | |||
1431 | if (MSG_FRAG_STATE_DATA <= fragq->state) | ||
1432 | { | ||
1433 | /* Check if there's a missing message before the current one */ | ||
1434 | if (GNUNET_PSYC_STATE_NOT_MODIFIED == fragq->state_delta) | ||
1435 | { | ||
1436 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%p state NOT modified\n", chn); | ||
1437 | |||
1438 | if (!(fragq->flags & GNUNET_PSYC_MESSAGE_ORDER_ANY) | ||
1439 | && (chn->max_message_id != msg_id - 1 | ||
1440 | && chn->max_message_id != msg_id)) | ||
1441 | { | ||
1442 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1443 | "%p Out of order message. " | ||
1444 | "(%" PRIu64 " != %" PRIu64 " - 1)\n", | ||
1445 | chn, chn->max_message_id, msg_id); | ||
1446 | break; | ||
1447 | // FIXME: keep track of messages processed in this queue run, | ||
1448 | // and only stop after reaching the end | ||
1449 | } | ||
1450 | } | ||
1451 | else | ||
1452 | { | ||
1453 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%p state modified\n", chn); | ||
1454 | if (GNUNET_YES != fragq->state_is_modified) | ||
1455 | { | ||
1456 | if (msg_id - fragq->state_delta != chn->max_state_message_id) | ||
1457 | { | ||
1458 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1459 | "%p Out of order stateful message. " | ||
1460 | "(%" PRIu64 " - %" PRIu64 " != %" PRIu64 ")\n", | ||
1461 | chn, msg_id, fragq->state_delta, chn->max_state_message_id); | ||
1462 | break; | ||
1463 | // FIXME: keep track of messages processed in this queue run, | ||
1464 | // and only stop after reaching the end | ||
1465 | } | ||
1466 | |||
1467 | struct StateModifyClosure *mcls = GNUNET_malloc (sizeof (*mcls)); | ||
1468 | mcls->channel = chn; | ||
1469 | mcls->msg_id = msg_id; | ||
1470 | mcls->msg_id_hash = msg_id_hash; | ||
1471 | |||
1472 | /* Apply modifiers to state in PSYCstore */ | ||
1473 | GNUNET_PSYCSTORE_state_modify (store, &chn->pub_key, msg_id, | ||
1474 | fragq->state_delta, | ||
1475 | store_recv_state_modify_result, mcls); | ||
1476 | break; // continue after asynchronous state modify result | ||
1477 | } | ||
1478 | } | ||
1479 | chn->max_message_id = msg_id; | ||
1480 | } | ||
1481 | fragment_queue_run (chn, msg_id, fragq, MSG_FRAG_STATE_DROP == fragq->state); | ||
1482 | GNUNET_CONTAINER_heap_remove_root (chn->recv_msgs); | ||
1483 | n++; | ||
1484 | } | ||
1485 | |||
1486 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1487 | "%p Removed %" PRIu64 " messages from queue.\n", chn, n); | ||
1488 | return n; | ||
1489 | } | ||
1490 | |||
1491 | |||
1492 | /** | ||
1493 | * Drop message queue of a channel. | ||
1494 | * | ||
1495 | * Remove all messages in queue without sending it to clients. | ||
1496 | * | ||
1497 | * @param chn Channel. | ||
1498 | * | ||
1499 | * @return Number of messages removed from queue. | ||
1500 | */ | ||
1501 | static uint64_t | ||
1502 | message_queue_drop (struct Channel *chn) | ||
1503 | { | ||
1504 | uint64_t n = 0; | ||
1505 | uint64_t msg_id; | ||
1506 | while (GNUNET_YES == GNUNET_CONTAINER_heap_peek2 (chn->recv_msgs, NULL, | ||
1507 | &msg_id)) | ||
1508 | { | ||
1509 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1510 | "%p Dropping message %" PRIu64 " from queue.\n", chn, msg_id); | ||
1511 | struct GNUNET_HashCode msg_id_hash; | ||
1512 | hash_key_from_hll (&msg_id_hash, msg_id); | ||
1513 | |||
1514 | struct FragmentQueue * | ||
1515 | fragq = GNUNET_CONTAINER_multihashmap_get (chn->recv_frags, &msg_id_hash); | ||
1516 | GNUNET_assert (NULL != fragq); | ||
1517 | fragment_queue_run (chn, msg_id, fragq, GNUNET_YES); | ||
1518 | GNUNET_CONTAINER_heap_remove_root (chn->recv_msgs); | ||
1519 | n++; | ||
1520 | } | ||
1521 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1522 | "%p Removed %" PRIu64 " messages from queue.\n", chn, n); | ||
1523 | return n; | ||
1524 | } | ||
1525 | |||
1526 | |||
1527 | /** | ||
1528 | * Received result of GNUNET_PSYCSTORE_fragment_store(). | ||
1529 | */ | ||
1530 | static void | ||
1531 | store_recv_fragment_store_result (void *cls, int64_t result, | ||
1532 | const char *err_msg, uint16_t err_msg_size) | ||
1533 | { | ||
1534 | struct Channel *chn = cls; | ||
1535 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1536 | "%p GNUNET_PSYCSTORE_fragment_store() returned %" PRId64 " (%.*s)\n", | ||
1537 | chn, result, err_msg_size, err_msg); | ||
1538 | } | ||
1539 | |||
1540 | |||
1541 | /** | ||
1542 | * Handle incoming message fragment from multicast. | ||
1543 | * | ||
1544 | * Store it using PSYCstore and send it to the clients of the channel in order. | ||
1545 | */ | ||
1546 | static void | ||
1547 | mcast_recv_message (void *cls, const struct GNUNET_MULTICAST_MessageHeader *mmsg) | ||
1548 | { | ||
1549 | struct Channel *chn = cls; | ||
1550 | uint16_t size = ntohs (mmsg->header.size); | ||
1551 | |||
1552 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1553 | "%p Received multicast message of size %u. " | ||
1554 | "fragment_id=%" PRIu64 ", message_id=%" PRIu64 | ||
1555 | ", fragment_offset=%" PRIu64 ", flags=%" PRIu64 "\n", | ||
1556 | chn, size, | ||
1557 | GNUNET_ntohll (mmsg->fragment_id), | ||
1558 | GNUNET_ntohll (mmsg->message_id), | ||
1559 | GNUNET_ntohll (mmsg->fragment_offset), | ||
1560 | GNUNET_ntohll (mmsg->flags)); | ||
1561 | |||
1562 | GNUNET_PSYCSTORE_fragment_store (store, &chn->pub_key, mmsg, 0, | ||
1563 | &store_recv_fragment_store_result, chn); | ||
1564 | |||
1565 | uint16_t first_ptype = 0, last_ptype = 0; | ||
1566 | int check = GNUNET_PSYC_receive_check_parts (size - sizeof (*mmsg), | ||
1567 | (const char *) &mmsg[1], | ||
1568 | &first_ptype, &last_ptype); | ||
1569 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1570 | "%p Message check result %d, first part type %u, last part type %u\n", | ||
1571 | chn, check, first_ptype, last_ptype); | ||
1572 | if (GNUNET_SYSERR == check) | ||
1573 | { | ||
1574 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1575 | "%p Dropping incoming multicast message with invalid parts.\n", | ||
1576 | chn); | ||
1577 | GNUNET_break_op (0); | ||
1578 | return; | ||
1579 | } | ||
1580 | |||
1581 | fragment_queue_insert (chn, mmsg, first_ptype, last_ptype); | ||
1582 | message_queue_run (chn); | ||
1583 | } | ||
1584 | |||
1585 | |||
1586 | /** | ||
1587 | * Incoming request fragment from multicast for a master. | ||
1588 | * | ||
1589 | * @param cls Master. | ||
1590 | * @param req The request. | ||
1591 | */ | ||
1592 | static void | ||
1593 | mcast_recv_request (void *cls, | ||
1594 | const struct GNUNET_MULTICAST_RequestHeader *req) | ||
1595 | { | ||
1596 | struct Master *mst = cls; | ||
1597 | uint16_t size = ntohs (req->header.size); | ||
1598 | |||
1599 | char *str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&req->member_pub_key); | ||
1600 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1601 | "%p Received multicast request of size %u from %s.\n", | ||
1602 | mst, size, str); | ||
1603 | GNUNET_free (str); | ||
1604 | |||
1605 | uint16_t first_ptype = 0, last_ptype = 0; | ||
1606 | if (GNUNET_SYSERR | ||
1607 | == GNUNET_PSYC_receive_check_parts (size - sizeof (*req), | ||
1608 | (const char *) &req[1], | ||
1609 | &first_ptype, &last_ptype)) | ||
1610 | { | ||
1611 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1612 | "%p Dropping incoming multicast request with invalid parts.\n", | ||
1613 | mst); | ||
1614 | GNUNET_break_op (0); | ||
1615 | return; | ||
1616 | } | ||
1617 | |||
1618 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1619 | "Message parts: first: type %u, last: type %u\n", | ||
1620 | first_ptype, last_ptype); | ||
1621 | |||
1622 | /* FIXME: in-order delivery */ | ||
1623 | client_send_mcast_req (mst, req); | ||
1624 | } | ||
1625 | |||
1626 | |||
1627 | /** | ||
1628 | * Response from PSYCstore with the current counter values for a channel master. | ||
1629 | */ | ||
1630 | static void | ||
1631 | store_recv_master_counters (void *cls, int result, uint64_t max_fragment_id, | ||
1632 | uint64_t max_message_id, uint64_t max_group_generation, | ||
1633 | uint64_t max_state_message_id) | ||
1634 | { | ||
1635 | struct Master *mst = cls; | ||
1636 | struct Channel *chn = &mst->channel; | ||
1637 | chn->store_op = NULL; | ||
1638 | |||
1639 | struct GNUNET_PSYC_CountersResultMessage res; | ||
1640 | res.header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MASTER_START_ACK); | ||
1641 | res.header.size = htons (sizeof (res)); | ||
1642 | res.result_code = htonl (result); | ||
1643 | res.max_message_id = GNUNET_htonll (max_message_id); | ||
1644 | |||
1645 | if (GNUNET_OK == result || GNUNET_NO == result) | ||
1646 | { | ||
1647 | mst->max_message_id = max_message_id; | ||
1648 | chn->max_message_id = max_message_id; | ||
1649 | chn->max_state_message_id = max_state_message_id; | ||
1650 | mst->max_group_generation = max_group_generation; | ||
1651 | mst->origin | ||
1652 | = GNUNET_MULTICAST_origin_start (cfg, &mst->priv_key, max_fragment_id, | ||
1653 | mcast_recv_join_request, | ||
1654 | mcast_recv_replay_fragment, | ||
1655 | mcast_recv_replay_message, | ||
1656 | mcast_recv_request, | ||
1657 | mcast_recv_message, chn); | ||
1658 | chn->is_ready = GNUNET_YES; | ||
1659 | } | ||
1660 | else | ||
1661 | { | ||
1662 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1663 | "%p GNUNET_PSYCSTORE_counters_get() " | ||
1664 | "returned %d for channel %s.\n", | ||
1665 | chn, result, GNUNET_h2s (&chn->pub_key_hash)); | ||
1666 | } | ||
1667 | |||
1668 | client_send_msg (chn, &res.header); | ||
1669 | } | ||
1670 | |||
1671 | |||
1672 | /** | ||
1673 | * Response from PSYCstore with the current counter values for a channel slave. | ||
1674 | */ | ||
1675 | void | ||
1676 | store_recv_slave_counters (void *cls, int result, uint64_t max_fragment_id, | ||
1677 | uint64_t max_message_id, uint64_t max_group_generation, | ||
1678 | uint64_t max_state_message_id) | ||
1679 | { | ||
1680 | struct Slave *slv = cls; | ||
1681 | struct Channel *chn = &slv->channel; | ||
1682 | chn->store_op = NULL; | ||
1683 | |||
1684 | struct GNUNET_PSYC_CountersResultMessage res; | ||
1685 | res.header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_SLAVE_JOIN_ACK); | ||
1686 | res.header.size = htons (sizeof (res)); | ||
1687 | res.result_code = htonl (result); | ||
1688 | res.max_message_id = GNUNET_htonll (max_message_id); | ||
1689 | |||
1690 | if (GNUNET_YES == result || GNUNET_NO == result) | ||
1691 | { | ||
1692 | chn->max_message_id = max_message_id; | ||
1693 | chn->max_state_message_id = max_state_message_id; | ||
1694 | slv->member | ||
1695 | = GNUNET_MULTICAST_member_join (cfg, &chn->pub_key, &slv->priv_key, | ||
1696 | &slv->origin, | ||
1697 | slv->relay_count, slv->relays, | ||
1698 | &slv->join_msg->header, | ||
1699 | mcast_recv_join_request, | ||
1700 | mcast_recv_join_decision, | ||
1701 | mcast_recv_replay_fragment, | ||
1702 | mcast_recv_replay_message, | ||
1703 | mcast_recv_message, chn); | ||
1704 | if (NULL != slv->join_msg) | ||
1705 | { | ||
1706 | GNUNET_free (slv->join_msg); | ||
1707 | slv->join_msg = NULL; | ||
1708 | } | ||
1709 | } | ||
1710 | else | ||
1711 | { | ||
1712 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1713 | "%p GNUNET_PSYCSTORE_counters_get() " | ||
1714 | "returned %d for channel %s.\n", | ||
1715 | chn, result, GNUNET_h2s (&chn->pub_key_hash)); | ||
1716 | } | ||
1717 | |||
1718 | client_send_msg (chn, &res.header); | ||
1719 | } | ||
1720 | |||
1721 | |||
1722 | static void | ||
1723 | channel_init (struct Channel *chn) | ||
1724 | { | ||
1725 | chn->recv_msgs | ||
1726 | = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN); | ||
1727 | chn->recv_frags = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); | ||
1728 | } | ||
1729 | |||
1730 | |||
1731 | /** | ||
1732 | * Handle a connecting client starting a channel master. | ||
1733 | */ | ||
1734 | static void | ||
1735 | handle_client_master_start (void *cls, | ||
1736 | const struct MasterStartRequest *req) | ||
1737 | { | ||
1738 | struct Client *c = cls; | ||
1739 | struct GNUNET_SERVICE_Client *client = c->client; | ||
1740 | |||
1741 | struct GNUNET_CRYPTO_EddsaPublicKey pub_key; | ||
1742 | struct GNUNET_HashCode pub_key_hash; | ||
1743 | |||
1744 | GNUNET_CRYPTO_eddsa_key_get_public (&req->channel_key, &pub_key); | ||
1745 | GNUNET_CRYPTO_hash (&pub_key, sizeof (pub_key), &pub_key_hash); | ||
1746 | |||
1747 | struct Master * | ||
1748 | mst = GNUNET_CONTAINER_multihashmap_get (masters, &pub_key_hash); | ||
1749 | struct Channel *chn; | ||
1750 | |||
1751 | if (NULL == mst) | ||
1752 | { | ||
1753 | mst = GNUNET_malloc (sizeof (*mst)); | ||
1754 | mst->policy = ntohl (req->policy); | ||
1755 | mst->priv_key = req->channel_key; | ||
1756 | mst->join_reqs = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); | ||
1757 | |||
1758 | chn = c->channel = &mst->channel; | ||
1759 | chn->master = mst; | ||
1760 | chn->is_master = GNUNET_YES; | ||
1761 | chn->pub_key = pub_key; | ||
1762 | chn->pub_key_hash = pub_key_hash; | ||
1763 | channel_init (chn); | ||
1764 | |||
1765 | GNUNET_CONTAINER_multihashmap_put (masters, &chn->pub_key_hash, chn, | ||
1766 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
1767 | chn->store_op = GNUNET_PSYCSTORE_counters_get (store, &chn->pub_key, | ||
1768 | store_recv_master_counters, mst); | ||
1769 | } | ||
1770 | else | ||
1771 | { | ||
1772 | chn = &mst->channel; | ||
1773 | |||
1774 | struct GNUNET_PSYC_CountersResultMessage *res; | ||
1775 | struct GNUNET_MQ_Envelope * | ||
1776 | env = GNUNET_MQ_msg (res, GNUNET_MESSAGE_TYPE_PSYC_MASTER_START_ACK); | ||
1777 | res->result_code = htonl (GNUNET_OK); | ||
1778 | res->max_message_id = GNUNET_htonll (mst->max_message_id); | ||
1779 | |||
1780 | GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), env); | ||
1781 | } | ||
1782 | |||
1783 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1784 | "%p Client connected as master to channel %s.\n", | ||
1785 | mst, GNUNET_h2s (&chn->pub_key_hash)); | ||
1786 | |||
1787 | struct ClientList *cli = GNUNET_malloc (sizeof (*cli)); | ||
1788 | cli->client = client; | ||
1789 | GNUNET_CONTAINER_DLL_insert (chn->clients_head, chn->clients_tail, cli); | ||
1790 | |||
1791 | GNUNET_SERVICE_client_continue (client); | ||
1792 | } | ||
1793 | |||
1794 | |||
1795 | static int | ||
1796 | check_client_slave_join (void *cls, | ||
1797 | const struct SlaveJoinRequest *req) | ||
1798 | { | ||
1799 | return GNUNET_OK; | ||
1800 | } | ||
1801 | |||
1802 | |||
1803 | /** | ||
1804 | * Handle a connecting client joining as a channel slave. | ||
1805 | */ | ||
1806 | static void | ||
1807 | handle_client_slave_join (void *cls, | ||
1808 | const struct SlaveJoinRequest *req) | ||
1809 | { | ||
1810 | struct Client *c = cls; | ||
1811 | struct GNUNET_SERVICE_Client *client = c->client; | ||
1812 | |||
1813 | uint16_t req_size = ntohs (req->header.size); | ||
1814 | |||
1815 | struct GNUNET_CRYPTO_EcdsaPublicKey slv_pub_key; | ||
1816 | struct GNUNET_HashCode pub_key_hash, slv_pub_hash; | ||
1817 | |||
1818 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1819 | "got join request from client %p\n", | ||
1820 | client); | ||
1821 | GNUNET_CRYPTO_ecdsa_key_get_public (&req->slave_key, &slv_pub_key); | ||
1822 | GNUNET_CRYPTO_hash (&slv_pub_key, sizeof (slv_pub_key), &slv_pub_hash); | ||
1823 | GNUNET_CRYPTO_hash (&req->channel_pub_key, sizeof (req->channel_pub_key), &pub_key_hash); | ||
1824 | |||
1825 | struct GNUNET_CONTAINER_MultiHashMap * | ||
1826 | chn_slv = GNUNET_CONTAINER_multihashmap_get (channel_slaves, &pub_key_hash); | ||
1827 | struct Slave *slv = NULL; | ||
1828 | struct Channel *chn; | ||
1829 | |||
1830 | if (NULL != chn_slv) | ||
1831 | { | ||
1832 | slv = GNUNET_CONTAINER_multihashmap_get (chn_slv, &slv_pub_hash); | ||
1833 | } | ||
1834 | if (NULL == slv) | ||
1835 | { | ||
1836 | slv = GNUNET_malloc (sizeof (*slv)); | ||
1837 | slv->priv_key = req->slave_key; | ||
1838 | slv->pub_key = slv_pub_key; | ||
1839 | slv->pub_key_hash = slv_pub_hash; | ||
1840 | slv->origin = req->origin; | ||
1841 | slv->relay_count = ntohl (req->relay_count); | ||
1842 | slv->join_flags = ntohl (req->flags); | ||
1843 | |||
1844 | const struct GNUNET_PeerIdentity * | ||
1845 | relays = (const struct GNUNET_PeerIdentity *) &req[1]; | ||
1846 | uint16_t relay_size = slv->relay_count * sizeof (*relays); | ||
1847 | uint16_t join_msg_size = 0; | ||
1848 | |||
1849 | if (sizeof (*req) + relay_size + sizeof (struct GNUNET_MessageHeader) | ||
1850 | <= req_size) | ||
1851 | { | ||
1852 | struct GNUNET_PSYC_Message * | ||
1853 | join_msg = (struct GNUNET_PSYC_Message *) (((char *) &req[1]) + relay_size); | ||
1854 | join_msg_size = ntohs (join_msg->header.size); | ||
1855 | slv->join_msg = GNUNET_malloc (join_msg_size); | ||
1856 | GNUNET_memcpy (slv->join_msg, join_msg, join_msg_size); | ||
1857 | } | ||
1858 | if (sizeof (*req) + relay_size + join_msg_size != req_size) | ||
1859 | { | ||
1860 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1861 | "%u + %u + %u != %u\n", | ||
1862 | (unsigned int) sizeof (*req), | ||
1863 | relay_size, | ||
1864 | join_msg_size, | ||
1865 | req_size); | ||
1866 | GNUNET_break (0); | ||
1867 | GNUNET_SERVICE_client_drop (client); | ||
1868 | GNUNET_free (slv); | ||
1869 | return; | ||
1870 | } | ||
1871 | if (0 < slv->relay_count) | ||
1872 | { | ||
1873 | slv->relays = GNUNET_malloc (relay_size); | ||
1874 | GNUNET_memcpy (slv->relays, &req[1], relay_size); | ||
1875 | } | ||
1876 | |||
1877 | chn = c->channel = &slv->channel; | ||
1878 | chn->slave = slv; | ||
1879 | chn->is_master = GNUNET_NO; | ||
1880 | chn->pub_key = req->channel_pub_key; | ||
1881 | chn->pub_key_hash = pub_key_hash; | ||
1882 | channel_init (chn); | ||
1883 | |||
1884 | if (NULL == chn_slv) | ||
1885 | { | ||
1886 | chn_slv = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES); | ||
1887 | GNUNET_CONTAINER_multihashmap_put (channel_slaves, &chn->pub_key_hash, chn_slv, | ||
1888 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); | ||
1889 | } | ||
1890 | GNUNET_CONTAINER_multihashmap_put (chn_slv, &slv->pub_key_hash, chn, | ||
1891 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); | ||
1892 | GNUNET_CONTAINER_multihashmap_put (slaves, &chn->pub_key_hash, chn, | ||
1893 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
1894 | chn->store_op = GNUNET_PSYCSTORE_counters_get (store, &chn->pub_key, | ||
1895 | &store_recv_slave_counters, slv); | ||
1896 | } | ||
1897 | else | ||
1898 | { | ||
1899 | chn = &slv->channel; | ||
1900 | |||
1901 | struct GNUNET_PSYC_CountersResultMessage *res; | ||
1902 | |||
1903 | struct GNUNET_MQ_Envelope * | ||
1904 | env = GNUNET_MQ_msg (res, GNUNET_MESSAGE_TYPE_PSYC_SLAVE_JOIN_ACK); | ||
1905 | res->result_code = htonl (GNUNET_OK); | ||
1906 | res->max_message_id = GNUNET_htonll (chn->max_message_id); | ||
1907 | |||
1908 | GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), env); | ||
1909 | |||
1910 | if (GNUNET_PSYC_SLAVE_JOIN_LOCAL & slv->join_flags) | ||
1911 | { | ||
1912 | mcast_recv_join_decision (slv, GNUNET_YES, | ||
1913 | NULL, 0, NULL, NULL); | ||
1914 | } | ||
1915 | else if (NULL == slv->member) | ||
1916 | { | ||
1917 | slv->member | ||
1918 | = GNUNET_MULTICAST_member_join (cfg, &chn->pub_key, &slv->priv_key, | ||
1919 | &slv->origin, | ||
1920 | slv->relay_count, slv->relays, | ||
1921 | &slv->join_msg->header, | ||
1922 | &mcast_recv_join_request, | ||
1923 | &mcast_recv_join_decision, | ||
1924 | &mcast_recv_replay_fragment, | ||
1925 | &mcast_recv_replay_message, | ||
1926 | &mcast_recv_message, chn); | ||
1927 | if (NULL != slv->join_msg) | ||
1928 | { | ||
1929 | GNUNET_free (slv->join_msg); | ||
1930 | slv->join_msg = NULL; | ||
1931 | } | ||
1932 | } | ||
1933 | else if (NULL != slv->join_dcsn) | ||
1934 | { | ||
1935 | struct GNUNET_MQ_Envelope * | ||
1936 | env = GNUNET_MQ_msg_copy (&slv->join_dcsn->header); | ||
1937 | GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), env); | ||
1938 | } | ||
1939 | } | ||
1940 | |||
1941 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1942 | "Client %p connected as slave to channel %s.\n", | ||
1943 | client, | ||
1944 | GNUNET_h2s (&chn->pub_key_hash)); | ||
1945 | |||
1946 | struct ClientList *cli = GNUNET_malloc (sizeof (*cli)); | ||
1947 | cli->client = client; | ||
1948 | GNUNET_CONTAINER_DLL_insert (chn->clients_head, chn->clients_tail, cli); | ||
1949 | |||
1950 | GNUNET_SERVICE_client_continue (client); | ||
1951 | } | ||
1952 | |||
1953 | |||
1954 | struct JoinDecisionClosure | ||
1955 | { | ||
1956 | int32_t is_admitted; | ||
1957 | struct GNUNET_MessageHeader *msg; | ||
1958 | }; | ||
1959 | |||
1960 | |||
1961 | /** | ||
1962 | * Iterator callback for sending join decisions to multicast. | ||
1963 | */ | ||
1964 | static int | ||
1965 | mcast_send_join_decision (void *cls, const struct GNUNET_HashCode *pub_key_hash, | ||
1966 | void *value) | ||
1967 | { | ||
1968 | struct JoinDecisionClosure *jcls = cls; | ||
1969 | struct GNUNET_MULTICAST_JoinHandle *jh = value; | ||
1970 | // FIXME: add relays | ||
1971 | GNUNET_MULTICAST_join_decision (jh, jcls->is_admitted, 0, NULL, jcls->msg); | ||
1972 | return GNUNET_YES; | ||
1973 | } | ||
1974 | |||
1975 | |||
1976 | static int | ||
1977 | check_client_join_decision (void *cls, | ||
1978 | const struct GNUNET_PSYC_JoinDecisionMessage *dcsn) | ||
1979 | { | ||
1980 | return GNUNET_OK; | ||
1981 | } | ||
1982 | |||
1983 | |||
1984 | /** | ||
1985 | * Join decision from client. | ||
1986 | */ | ||
1987 | static void | ||
1988 | handle_client_join_decision (void *cls, | ||
1989 | const struct GNUNET_PSYC_JoinDecisionMessage *dcsn) | ||
1990 | { | ||
1991 | struct Client *c = cls; | ||
1992 | struct GNUNET_SERVICE_Client *client = c->client; | ||
1993 | struct Channel *chn = c->channel; | ||
1994 | if (NULL == chn) | ||
1995 | { | ||
1996 | GNUNET_break (0); | ||
1997 | GNUNET_SERVICE_client_drop (client); | ||
1998 | return; | ||
1999 | } | ||
2000 | GNUNET_assert (GNUNET_YES == chn->is_master); | ||
2001 | struct Master *mst = chn->master; | ||
2002 | |||
2003 | struct JoinDecisionClosure jcls; | ||
2004 | jcls.is_admitted = ntohl (dcsn->is_admitted); | ||
2005 | jcls.msg | ||
2006 | = (sizeof (*dcsn) + sizeof (*jcls.msg) <= ntohs (dcsn->header.size)) | ||
2007 | ? (struct GNUNET_MessageHeader *) &dcsn[1] | ||
2008 | : NULL; | ||
2009 | |||
2010 | struct GNUNET_HashCode slave_pub_hash; | ||
2011 | GNUNET_CRYPTO_hash (&dcsn->slave_pub_key, sizeof (dcsn->slave_pub_key), | ||
2012 | &slave_pub_hash); | ||
2013 | |||
2014 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2015 | "%p Got join decision (%d) from client for channel %s..\n", | ||
2016 | mst, jcls.is_admitted, GNUNET_h2s (&chn->pub_key_hash)); | ||
2017 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2018 | "%p ..and slave %s.\n", | ||
2019 | mst, GNUNET_h2s (&slave_pub_hash)); | ||
2020 | |||
2021 | GNUNET_CONTAINER_multihashmap_get_multiple (mst->join_reqs, &slave_pub_hash, | ||
2022 | &mcast_send_join_decision, &jcls); | ||
2023 | GNUNET_CONTAINER_multihashmap_remove_all (mst->join_reqs, &slave_pub_hash); | ||
2024 | GNUNET_SERVICE_client_continue (client); | ||
2025 | } | ||
2026 | |||
2027 | |||
2028 | static void | ||
2029 | channel_part_cb (void *cls) | ||
2030 | { | ||
2031 | struct GNUNET_SERVICE_Client *client = cls; | ||
2032 | struct GNUNET_MQ_Envelope *env; | ||
2033 | |||
2034 | env = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_PSYC_PART_ACK); | ||
2035 | GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), | ||
2036 | env); | ||
2037 | } | ||
2038 | |||
2039 | |||
2040 | static void | ||
2041 | handle_client_part_request (void *cls, | ||
2042 | const struct GNUNET_MessageHeader *msg) | ||
2043 | { | ||
2044 | struct Client *c = cls; | ||
2045 | |||
2046 | c->channel->is_disconnecting = GNUNET_YES; | ||
2047 | if (GNUNET_YES == c->channel->is_master) | ||
2048 | { | ||
2049 | struct Master *mst = (struct Master *) c->channel; | ||
2050 | |||
2051 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2052 | "Got part request from master %p\n", | ||
2053 | mst); | ||
2054 | GNUNET_assert (NULL != mst->origin); | ||
2055 | GNUNET_MULTICAST_origin_stop (mst->origin, channel_part_cb, c->client); | ||
2056 | } | ||
2057 | else | ||
2058 | { | ||
2059 | struct Slave *slv = (struct Slave *) c->channel; | ||
2060 | |||
2061 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2062 | "Got part request from slave %p\n", | ||
2063 | slv); | ||
2064 | GNUNET_assert (NULL != slv->member); | ||
2065 | GNUNET_MULTICAST_member_part (slv->member, channel_part_cb, c->client); | ||
2066 | } | ||
2067 | GNUNET_SERVICE_client_continue (c->client); | ||
2068 | } | ||
2069 | |||
2070 | |||
2071 | /** | ||
2072 | * Send acknowledgement to a client. | ||
2073 | * | ||
2074 | * Sent after a message fragment has been passed on to multicast. | ||
2075 | * | ||
2076 | * @param chn The channel struct for the client. | ||
2077 | */ | ||
2078 | static void | ||
2079 | send_message_ack (struct Channel *chn, struct GNUNET_SERVICE_Client *client) | ||
2080 | { | ||
2081 | struct GNUNET_MessageHeader *res; | ||
2082 | struct GNUNET_MQ_Envelope * | ||
2083 | env = GNUNET_MQ_msg (res, GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_ACK); | ||
2084 | |||
2085 | /* FIXME? */ | ||
2086 | GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), env); | ||
2087 | } | ||
2088 | |||
2089 | |||
2090 | /** | ||
2091 | * Callback for the transmit functions of multicast. | ||
2092 | */ | ||
2093 | static int | ||
2094 | transmit_notify (void *cls, size_t *data_size, void *data) | ||
2095 | { | ||
2096 | struct Channel *chn = cls; | ||
2097 | struct TransmitMessage *tmit_msg = chn->tmit_head; | ||
2098 | |||
2099 | if (NULL == tmit_msg || *data_size < tmit_msg->size) | ||
2100 | { | ||
2101 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2102 | "%p transmit_notify: nothing to send.\n", chn); | ||
2103 | if (NULL != tmit_msg && *data_size < tmit_msg->size) | ||
2104 | GNUNET_break (0); | ||
2105 | *data_size = 0; | ||
2106 | return GNUNET_NO; | ||
2107 | } | ||
2108 | |||
2109 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2110 | "%p transmit_notify: sending %u bytes.\n", chn, tmit_msg->size); | ||
2111 | |||
2112 | *data_size = tmit_msg->size; | ||
2113 | GNUNET_memcpy (data, &tmit_msg[1], *data_size); | ||
2114 | |||
2115 | int ret | ||
2116 | = (tmit_msg->last_ptype < GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END) | ||
2117 | ? GNUNET_NO | ||
2118 | : GNUNET_YES; | ||
2119 | |||
2120 | /* FIXME: handle disconnecting clients */ | ||
2121 | if (NULL != tmit_msg->client) | ||
2122 | send_message_ack (chn, tmit_msg->client); | ||
2123 | |||
2124 | GNUNET_CONTAINER_DLL_remove (chn->tmit_head, chn->tmit_tail, tmit_msg); | ||
2125 | |||
2126 | if (NULL != chn->tmit_head) | ||
2127 | { | ||
2128 | GNUNET_SCHEDULER_add_now (&schedule_transmit_message, chn); | ||
2129 | } | ||
2130 | else if (GNUNET_YES == chn->is_disconnecting | ||
2131 | && tmit_msg->last_ptype < GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END) | ||
2132 | { | ||
2133 | /* FIXME: handle partial message (when still in_transmit) */ | ||
2134 | GNUNET_free (tmit_msg); | ||
2135 | return GNUNET_SYSERR; | ||
2136 | } | ||
2137 | GNUNET_free (tmit_msg); | ||
2138 | return ret; | ||
2139 | } | ||
2140 | |||
2141 | |||
2142 | /** | ||
2143 | * Callback for the transmit functions of multicast. | ||
2144 | */ | ||
2145 | static int | ||
2146 | master_transmit_notify (void *cls, size_t *data_size, void *data) | ||
2147 | { | ||
2148 | int ret = transmit_notify (cls, data_size, data); | ||
2149 | |||
2150 | if (GNUNET_YES == ret) | ||
2151 | { | ||
2152 | struct Master *mst = cls; | ||
2153 | mst->tmit_handle = NULL; | ||
2154 | } | ||
2155 | return ret; | ||
2156 | } | ||
2157 | |||
2158 | |||
2159 | /** | ||
2160 | * Callback for the transmit functions of multicast. | ||
2161 | */ | ||
2162 | static int | ||
2163 | slave_transmit_notify (void *cls, size_t *data_size, void *data) | ||
2164 | { | ||
2165 | int ret = transmit_notify (cls, data_size, data); | ||
2166 | |||
2167 | if (GNUNET_YES == ret) | ||
2168 | { | ||
2169 | struct Slave *slv = cls; | ||
2170 | slv->tmit_handle = NULL; | ||
2171 | } | ||
2172 | return ret; | ||
2173 | } | ||
2174 | |||
2175 | |||
2176 | /** | ||
2177 | * Transmit a message from a channel master to the multicast group. | ||
2178 | */ | ||
2179 | static void | ||
2180 | master_transmit_message (struct Master *mst) | ||
2181 | { | ||
2182 | struct Channel *chn = &mst->channel; | ||
2183 | struct TransmitMessage *tmit_msg = chn->tmit_head; | ||
2184 | if (NULL == tmit_msg) | ||
2185 | return; | ||
2186 | if (NULL == mst->tmit_handle) | ||
2187 | { | ||
2188 | mst->tmit_handle = GNUNET_MULTICAST_origin_to_all (mst->origin, | ||
2189 | tmit_msg->id, | ||
2190 | mst->max_group_generation, | ||
2191 | &master_transmit_notify, | ||
2192 | mst); | ||
2193 | } | ||
2194 | else | ||
2195 | { | ||
2196 | GNUNET_MULTICAST_origin_to_all_resume (mst->tmit_handle); | ||
2197 | } | ||
2198 | } | ||
2199 | |||
2200 | |||
2201 | /** | ||
2202 | * Transmit a message from a channel slave to the multicast group. | ||
2203 | */ | ||
2204 | static void | ||
2205 | slave_transmit_message (struct Slave *slv) | ||
2206 | { | ||
2207 | if (NULL == slv->channel.tmit_head) | ||
2208 | return; | ||
2209 | if (NULL == slv->tmit_handle) | ||
2210 | { | ||
2211 | slv->tmit_handle = GNUNET_MULTICAST_member_to_origin (slv->member, | ||
2212 | slv->channel.tmit_head->id, | ||
2213 | &slave_transmit_notify, | ||
2214 | slv); | ||
2215 | } | ||
2216 | else | ||
2217 | { | ||
2218 | GNUNET_MULTICAST_member_to_origin_resume (slv->tmit_handle); | ||
2219 | } | ||
2220 | } | ||
2221 | |||
2222 | |||
2223 | static void | ||
2224 | transmit_message (struct Channel *chn) | ||
2225 | { | ||
2226 | chn->is_master | ||
2227 | ? master_transmit_message (chn->master) | ||
2228 | : slave_transmit_message (chn->slave); | ||
2229 | } | ||
2230 | |||
2231 | |||
2232 | /** | ||
2233 | * Queue a message from a channel master for sending to the multicast group. | ||
2234 | */ | ||
2235 | static void | ||
2236 | master_queue_message (struct Master *mst, struct TransmitMessage *tmit_msg) | ||
2237 | { | ||
2238 | if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD == tmit_msg->first_ptype) | ||
2239 | { | ||
2240 | tmit_msg->id = ++mst->max_message_id; | ||
2241 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2242 | "%p master_queue_message: message_id=%" PRIu64 "\n", | ||
2243 | mst, tmit_msg->id); | ||
2244 | struct GNUNET_PSYC_MessageMethod *pmeth | ||
2245 | = (struct GNUNET_PSYC_MessageMethod *) &tmit_msg[1]; | ||
2246 | |||
2247 | if (pmeth->flags & GNUNET_PSYC_MASTER_TRANSMIT_STATE_RESET) | ||
2248 | { | ||
2249 | pmeth->state_delta = GNUNET_htonll (GNUNET_PSYC_STATE_RESET); | ||
2250 | } | ||
2251 | else if (pmeth->flags & GNUNET_PSYC_MASTER_TRANSMIT_STATE_MODIFY) | ||
2252 | { | ||
2253 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2254 | "%p master_queue_message: state_delta=%" PRIu64 "\n", | ||
2255 | mst, tmit_msg->id - mst->max_state_message_id); | ||
2256 | pmeth->state_delta = GNUNET_htonll (tmit_msg->id | ||
2257 | - mst->max_state_message_id); | ||
2258 | mst->max_state_message_id = tmit_msg->id; | ||
2259 | } | ||
2260 | else | ||
2261 | { | ||
2262 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2263 | "%p master_queue_message: state not modified\n", mst); | ||
2264 | pmeth->state_delta = GNUNET_htonll (GNUNET_PSYC_STATE_NOT_MODIFIED); | ||
2265 | } | ||
2266 | |||
2267 | if (pmeth->flags & GNUNET_PSYC_MASTER_TRANSMIT_STATE_HASH) | ||
2268 | { | ||
2269 | /// @todo add state_hash to PSYC header | ||
2270 | } | ||
2271 | } | ||
2272 | } | ||
2273 | |||
2274 | |||
2275 | /** | ||
2276 | * Queue a message from a channel slave for sending to the multicast group. | ||
2277 | */ | ||
2278 | static void | ||
2279 | slave_queue_message (struct Slave *slv, struct TransmitMessage *tmit_msg) | ||
2280 | { | ||
2281 | if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD == tmit_msg->first_ptype) | ||
2282 | { | ||
2283 | struct GNUNET_PSYC_MessageMethod *pmeth | ||
2284 | = (struct GNUNET_PSYC_MessageMethod *) &tmit_msg[1]; | ||
2285 | pmeth->state_delta = GNUNET_htonll (GNUNET_PSYC_STATE_NOT_MODIFIED); | ||
2286 | tmit_msg->id = ++slv->max_request_id; | ||
2287 | } | ||
2288 | } | ||
2289 | |||
2290 | |||
2291 | /** | ||
2292 | * Queue PSYC message parts for sending to multicast. | ||
2293 | * | ||
2294 | * @param chn | ||
2295 | * Channel to send to. | ||
2296 | * @param client | ||
2297 | * Client the message originates from. | ||
2298 | * @param data_size | ||
2299 | * Size of @a data. | ||
2300 | * @param data | ||
2301 | * Concatenated message parts. | ||
2302 | * @param first_ptype | ||
2303 | * First message part type in @a data. | ||
2304 | * @param last_ptype | ||
2305 | * Last message part type in @a data. | ||
2306 | */ | ||
2307 | static struct TransmitMessage * | ||
2308 | queue_message (struct Channel *chn, | ||
2309 | struct GNUNET_SERVICE_Client *client, | ||
2310 | size_t data_size, | ||
2311 | const void *data, | ||
2312 | uint16_t first_ptype, uint16_t last_ptype) | ||
2313 | { | ||
2314 | struct TransmitMessage * | ||
2315 | tmit_msg = GNUNET_malloc (sizeof (*tmit_msg) + data_size); | ||
2316 | GNUNET_memcpy (&tmit_msg[1], data, data_size); | ||
2317 | tmit_msg->client = client; | ||
2318 | tmit_msg->size = data_size; | ||
2319 | tmit_msg->first_ptype = first_ptype; | ||
2320 | tmit_msg->last_ptype = last_ptype; | ||
2321 | |||
2322 | /* FIXME: separate queue per message ID */ | ||
2323 | |||
2324 | GNUNET_CONTAINER_DLL_insert_tail (chn->tmit_head, chn->tmit_tail, tmit_msg); | ||
2325 | |||
2326 | chn->is_master | ||
2327 | ? master_queue_message (chn->master, tmit_msg) | ||
2328 | : slave_queue_message (chn->slave, tmit_msg); | ||
2329 | return tmit_msg; | ||
2330 | } | ||
2331 | |||
2332 | |||
2333 | /** | ||
2334 | * Cancel transmission of current message. | ||
2335 | * | ||
2336 | * @param chn Channel to send to. | ||
2337 | * @param client Client the message originates from. | ||
2338 | */ | ||
2339 | static void | ||
2340 | transmit_cancel (struct Channel *chn, struct GNUNET_SERVICE_Client *client) | ||
2341 | { | ||
2342 | uint16_t type = GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL; | ||
2343 | |||
2344 | struct GNUNET_MessageHeader msg; | ||
2345 | msg.size = htons (sizeof (msg)); | ||
2346 | msg.type = htons (type); | ||
2347 | |||
2348 | queue_message (chn, client, sizeof (msg), &msg, type, type); | ||
2349 | transmit_message (chn); | ||
2350 | |||
2351 | /* FIXME: cleanup */ | ||
2352 | } | ||
2353 | |||
2354 | |||
2355 | static int | ||
2356 | check_client_psyc_message (void *cls, | ||
2357 | const struct GNUNET_MessageHeader *msg) | ||
2358 | { | ||
2359 | return GNUNET_OK; | ||
2360 | } | ||
2361 | |||
2362 | |||
2363 | /** | ||
2364 | * Incoming message from a master or slave client. | ||
2365 | */ | ||
2366 | static void | ||
2367 | handle_client_psyc_message (void *cls, | ||
2368 | const struct GNUNET_MessageHeader *msg) | ||
2369 | { | ||
2370 | struct Client *c = cls; | ||
2371 | struct GNUNET_SERVICE_Client *client = c->client; | ||
2372 | struct Channel *chn = c->channel; | ||
2373 | if (NULL == chn) | ||
2374 | { | ||
2375 | GNUNET_break (0); | ||
2376 | GNUNET_SERVICE_client_drop (client); | ||
2377 | return; | ||
2378 | } | ||
2379 | |||
2380 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2381 | "%p Received message from client.\n", chn); | ||
2382 | GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, msg); | ||
2383 | |||
2384 | if (GNUNET_YES != chn->is_ready) | ||
2385 | { | ||
2386 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
2387 | "%p Channel is not ready yet, disconnecting client %p.\n", | ||
2388 | chn, | ||
2389 | client); | ||
2390 | GNUNET_break (0); | ||
2391 | GNUNET_SERVICE_client_drop (client); | ||
2392 | return; | ||
2393 | } | ||
2394 | |||
2395 | uint16_t size = ntohs (msg->size); | ||
2396 | if (GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD < size - sizeof (*msg)) | ||
2397 | { | ||
2398 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
2399 | "%p Message payload too large: %u < %u.\n", | ||
2400 | chn, | ||
2401 | (unsigned int) GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD, | ||
2402 | (unsigned int) (size - sizeof (*msg))); | ||
2403 | GNUNET_break (0); | ||
2404 | transmit_cancel (chn, client); | ||
2405 | GNUNET_SERVICE_client_drop (client); | ||
2406 | return; | ||
2407 | } | ||
2408 | |||
2409 | uint16_t first_ptype = 0, last_ptype = 0; | ||
2410 | if (GNUNET_SYSERR | ||
2411 | == GNUNET_PSYC_receive_check_parts (size - sizeof (*msg), | ||
2412 | (const char *) &msg[1], | ||
2413 | &first_ptype, &last_ptype)) | ||
2414 | { | ||
2415 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
2416 | "%p Received invalid message part from client.\n", chn); | ||
2417 | GNUNET_break (0); | ||
2418 | transmit_cancel (chn, client); | ||
2419 | GNUNET_SERVICE_client_drop (client); | ||
2420 | return; | ||
2421 | } | ||
2422 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2423 | "%p Received message with first part type %u and last part type %u.\n", | ||
2424 | chn, first_ptype, last_ptype); | ||
2425 | |||
2426 | queue_message (chn, client, size - sizeof (*msg), &msg[1], | ||
2427 | first_ptype, last_ptype); | ||
2428 | transmit_message (chn); | ||
2429 | /* FIXME: send a few ACKs even before transmit_notify is called */ | ||
2430 | |||
2431 | GNUNET_SERVICE_client_continue (client); | ||
2432 | }; | ||
2433 | |||
2434 | |||
2435 | /** | ||
2436 | * Received result of GNUNET_PSYCSTORE_membership_store() | ||
2437 | */ | ||
2438 | static void | ||
2439 | store_recv_membership_store_result (void *cls, | ||
2440 | int64_t result, | ||
2441 | const char *err_msg, | ||
2442 | uint16_t err_msg_size) | ||
2443 | { | ||
2444 | struct Operation *op = cls; | ||
2445 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2446 | "%p GNUNET_PSYCSTORE_membership_store() returned %" PRId64 " (%.*s)\n", | ||
2447 | op->channel, | ||
2448 | result, | ||
2449 | (int) err_msg_size, | ||
2450 | err_msg); | ||
2451 | |||
2452 | if (NULL != op->client) | ||
2453 | client_send_result (op->client, op->op_id, result, err_msg, err_msg_size); | ||
2454 | op_remove (op); | ||
2455 | } | ||
2456 | |||
2457 | |||
2458 | /** | ||
2459 | * Client requests to add/remove a slave in the membership database. | ||
2460 | */ | ||
2461 | static void | ||
2462 | handle_client_membership_store (void *cls, | ||
2463 | const struct ChannelMembershipStoreRequest *req) | ||
2464 | { | ||
2465 | struct Client *c = cls; | ||
2466 | struct GNUNET_SERVICE_Client *client = c->client; | ||
2467 | struct Channel *chn = c->channel; | ||
2468 | if (NULL == chn) | ||
2469 | { | ||
2470 | GNUNET_break (0); | ||
2471 | GNUNET_SERVICE_client_drop (client); | ||
2472 | return; | ||
2473 | } | ||
2474 | |||
2475 | struct Operation *op = op_add (chn, client, req->op_id, 0); | ||
2476 | |||
2477 | uint64_t announced_at = GNUNET_ntohll (req->announced_at); | ||
2478 | uint64_t effective_since = GNUNET_ntohll (req->effective_since); | ||
2479 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2480 | "%p Received membership store request from client.\n", chn); | ||
2481 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2482 | "%p did_join: %u, announced_at: %" PRIu64 ", effective_since: %" PRIu64 "\n", | ||
2483 | chn, req->did_join, announced_at, effective_since); | ||
2484 | |||
2485 | GNUNET_PSYCSTORE_membership_store (store, &chn->pub_key, &req->slave_pub_key, | ||
2486 | req->did_join, announced_at, effective_since, | ||
2487 | 0, /* FIXME: group_generation */ | ||
2488 | &store_recv_membership_store_result, op); | ||
2489 | GNUNET_SERVICE_client_continue (client); | ||
2490 | } | ||
2491 | |||
2492 | |||
2493 | /** | ||
2494 | * Received a fragment for GNUNET_PSYCSTORE_fragment_get(), | ||
2495 | * in response to a history request from a client. | ||
2496 | */ | ||
2497 | static int | ||
2498 | store_recv_fragment_history (void *cls, | ||
2499 | struct GNUNET_MULTICAST_MessageHeader *mmsg, | ||
2500 | enum GNUNET_PSYCSTORE_MessageFlags flags) | ||
2501 | { | ||
2502 | struct Operation *op = cls; | ||
2503 | if (NULL == op->client) | ||
2504 | { /* Requesting client already disconnected. */ | ||
2505 | return GNUNET_NO; | ||
2506 | } | ||
2507 | struct Channel *chn = op->channel; | ||
2508 | |||
2509 | struct GNUNET_PSYC_MessageHeader *pmsg; | ||
2510 | uint16_t msize = ntohs (mmsg->header.size); | ||
2511 | uint16_t psize = sizeof (*pmsg) + msize - sizeof (*mmsg); | ||
2512 | |||
2513 | struct GNUNET_OperationResultMessage * | ||
2514 | res = GNUNET_malloc (sizeof (*res) + psize); | ||
2515 | res->header.size = htons (sizeof (*res) + psize); | ||
2516 | res->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_HISTORY_RESULT); | ||
2517 | res->op_id = op->op_id; | ||
2518 | res->result_code = GNUNET_htonll (GNUNET_OK); | ||
2519 | |||
2520 | pmsg = (struct GNUNET_PSYC_MessageHeader *) &res[1]; | ||
2521 | GNUNET_PSYC_message_header_init (pmsg, mmsg, flags | GNUNET_PSYC_MESSAGE_HISTORIC); | ||
2522 | GNUNET_memcpy (&res[1], pmsg, psize); | ||
2523 | |||
2524 | /** @todo FIXME: send only to requesting client */ | ||
2525 | client_send_msg (chn, &res->header); | ||
2526 | |||
2527 | GNUNET_free (res); | ||
2528 | return GNUNET_YES; | ||
2529 | } | ||
2530 | |||
2531 | |||
2532 | /** | ||
2533 | * Received the result of GNUNET_PSYCSTORE_fragment_get(), | ||
2534 | * in response to a history request from a client. | ||
2535 | */ | ||
2536 | static void | ||
2537 | store_recv_fragment_history_result (void *cls, int64_t result, | ||
2538 | const char *err_msg, uint16_t err_msg_size) | ||
2539 | { | ||
2540 | struct Operation *op = cls; | ||
2541 | if (NULL == op->client) | ||
2542 | { /* Requesting client already disconnected. */ | ||
2543 | return; | ||
2544 | } | ||
2545 | |||
2546 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2547 | "%p History replay #%" PRIu64 ": " | ||
2548 | "PSYCSTORE returned %" PRId64 " (%.*s)\n", | ||
2549 | op->channel, GNUNET_ntohll (op->op_id), result, err_msg_size, err_msg); | ||
2550 | |||
2551 | if (op->flags & GNUNET_PSYC_HISTORY_REPLAY_REMOTE) | ||
2552 | { | ||
2553 | /** @todo Multicast replay request for messages not found locally. */ | ||
2554 | } | ||
2555 | |||
2556 | client_send_result (op->client, op->op_id, result, err_msg, err_msg_size); | ||
2557 | op_remove (op); | ||
2558 | } | ||
2559 | |||
2560 | |||
2561 | static int | ||
2562 | check_client_history_replay (void *cls, | ||
2563 | const struct GNUNET_PSYC_HistoryRequestMessage *req) | ||
2564 | { | ||
2565 | return GNUNET_OK; | ||
2566 | } | ||
2567 | |||
2568 | |||
2569 | /** | ||
2570 | * Client requests channel history. | ||
2571 | */ | ||
2572 | static void | ||
2573 | handle_client_history_replay (void *cls, | ||
2574 | const struct GNUNET_PSYC_HistoryRequestMessage *req) | ||
2575 | { | ||
2576 | struct Client *c = cls; | ||
2577 | struct GNUNET_SERVICE_Client *client = c->client; | ||
2578 | struct Channel *chn = c->channel; | ||
2579 | if (NULL == chn) | ||
2580 | { | ||
2581 | GNUNET_break (0); | ||
2582 | GNUNET_SERVICE_client_drop (client); | ||
2583 | return; | ||
2584 | } | ||
2585 | |||
2586 | uint16_t size = ntohs (req->header.size); | ||
2587 | const char *method_prefix = (const char *) &req[1]; | ||
2588 | |||
2589 | if (size < sizeof (*req) + 1 | ||
2590 | || '\0' != method_prefix[size - sizeof (*req) - 1]) | ||
2591 | { | ||
2592 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
2593 | "%p History replay #%" PRIu64 ": " | ||
2594 | "invalid method prefix. size: %u < %u?\n", | ||
2595 | chn, | ||
2596 | GNUNET_ntohll (req->op_id), | ||
2597 | size, | ||
2598 | (unsigned int) sizeof (*req) + 1); | ||
2599 | GNUNET_break (0); | ||
2600 | GNUNET_SERVICE_client_drop (client); | ||
2601 | return; | ||
2602 | } | ||
2603 | |||
2604 | struct Operation *op = op_add (chn, client, req->op_id, ntohl (req->flags)); | ||
2605 | |||
2606 | if (0 == req->message_limit) | ||
2607 | { | ||
2608 | GNUNET_PSYCSTORE_message_get (store, &chn->pub_key, NULL, | ||
2609 | GNUNET_ntohll (req->start_message_id), | ||
2610 | GNUNET_ntohll (req->end_message_id), | ||
2611 | 0, method_prefix, | ||
2612 | &store_recv_fragment_history, | ||
2613 | &store_recv_fragment_history_result, op); | ||
2614 | } | ||
2615 | else | ||
2616 | { | ||
2617 | GNUNET_PSYCSTORE_message_get_latest (store, &chn->pub_key, NULL, | ||
2618 | GNUNET_ntohll (req->message_limit), | ||
2619 | method_prefix, | ||
2620 | &store_recv_fragment_history, | ||
2621 | &store_recv_fragment_history_result, | ||
2622 | op); | ||
2623 | } | ||
2624 | GNUNET_SERVICE_client_continue (client); | ||
2625 | } | ||
2626 | |||
2627 | |||
2628 | /** | ||
2629 | * Received state var from PSYCstore, send it to client. | ||
2630 | */ | ||
2631 | static int | ||
2632 | store_recv_state_var (void *cls, const char *name, | ||
2633 | const void *value, uint32_t value_size) | ||
2634 | { | ||
2635 | struct Operation *op = cls; | ||
2636 | struct GNUNET_OperationResultMessage *res; | ||
2637 | struct GNUNET_MQ_Envelope *env; | ||
2638 | |||
2639 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2640 | "%p state_get #%" PRIu64 " - received var from PSYCstore: %s\n", | ||
2641 | op->channel, GNUNET_ntohll (op->op_id), name); | ||
2642 | |||
2643 | if (NULL != name) /* First part */ | ||
2644 | { | ||
2645 | uint16_t name_size = strnlen (name, GNUNET_PSYC_MODIFIER_MAX_PAYLOAD) + 1; | ||
2646 | struct GNUNET_PSYC_MessageModifier *mod; | ||
2647 | env = GNUNET_MQ_msg_extra (res, | ||
2648 | sizeof (*mod) + name_size + value_size, | ||
2649 | GNUNET_MESSAGE_TYPE_PSYC_STATE_RESULT); | ||
2650 | res->op_id = op->op_id; | ||
2651 | |||
2652 | mod = (struct GNUNET_PSYC_MessageModifier *) &res[1]; | ||
2653 | mod->header.size = htons (sizeof (*mod) + name_size + value_size); | ||
2654 | mod->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER); | ||
2655 | mod->name_size = htons (name_size); | ||
2656 | mod->value_size = htonl (value_size); | ||
2657 | mod->oper = htons (GNUNET_PSYC_OP_ASSIGN); | ||
2658 | GNUNET_memcpy (&mod[1], name, name_size); | ||
2659 | GNUNET_memcpy (((char *) &mod[1]) + name_size, value, value_size); | ||
2660 | } | ||
2661 | else /* Continuation */ | ||
2662 | { | ||
2663 | struct GNUNET_MessageHeader *mod; | ||
2664 | env = GNUNET_MQ_msg_extra (res, | ||
2665 | sizeof (*mod) + value_size, | ||
2666 | GNUNET_MESSAGE_TYPE_PSYC_STATE_RESULT); | ||
2667 | res->op_id = op->op_id; | ||
2668 | |||
2669 | mod = (struct GNUNET_MessageHeader *) &res[1]; | ||
2670 | mod->size = htons (sizeof (*mod) + value_size); | ||
2671 | mod->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT); | ||
2672 | GNUNET_memcpy (&mod[1], value, value_size); | ||
2673 | } | ||
2674 | |||
2675 | // FIXME: client might have been disconnected | ||
2676 | GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (op->client), env); | ||
2677 | return GNUNET_YES; | ||
2678 | } | ||
2679 | |||
2680 | |||
2681 | /** | ||
2682 | * Received result of GNUNET_PSYCSTORE_state_get() | ||
2683 | * or GNUNET_PSYCSTORE_state_get_prefix() | ||
2684 | */ | ||
2685 | static void | ||
2686 | store_recv_state_result (void *cls, int64_t result, | ||
2687 | const char *err_msg, uint16_t err_msg_size) | ||
2688 | { | ||
2689 | struct Operation *op = cls; | ||
2690 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2691 | "%p state_get #%" PRIu64 ": " | ||
2692 | "PSYCSTORE returned %" PRId64 " (%.*s)\n", | ||
2693 | op->channel, GNUNET_ntohll (op->op_id), result, err_msg_size, err_msg); | ||
2694 | |||
2695 | // FIXME: client might have been disconnected | ||
2696 | client_send_result (op->client, op->op_id, result, err_msg, err_msg_size); | ||
2697 | op_remove (op); | ||
2698 | } | ||
2699 | |||
2700 | |||
2701 | static int | ||
2702 | check_client_state_get (void *cls, | ||
2703 | const struct StateRequest *req) | ||
2704 | { | ||
2705 | struct Client *c = cls; | ||
2706 | struct Channel *chn = c->channel; | ||
2707 | if (NULL == chn) | ||
2708 | { | ||
2709 | GNUNET_break (0); | ||
2710 | return GNUNET_SYSERR; | ||
2711 | } | ||
2712 | |||
2713 | uint16_t name_size = ntohs (req->header.size) - sizeof (*req); | ||
2714 | const char *name = (const char *) &req[1]; | ||
2715 | if (0 == name_size || '\0' != name[name_size - 1]) | ||
2716 | { | ||
2717 | GNUNET_break (0); | ||
2718 | return GNUNET_SYSERR; | ||
2719 | } | ||
2720 | |||
2721 | return GNUNET_OK; | ||
2722 | } | ||
2723 | |||
2724 | |||
2725 | /** | ||
2726 | * Client requests best matching state variable from PSYCstore. | ||
2727 | */ | ||
2728 | static void | ||
2729 | handle_client_state_get (void *cls, | ||
2730 | const struct StateRequest *req) | ||
2731 | { | ||
2732 | struct Client *c = cls; | ||
2733 | struct GNUNET_SERVICE_Client *client = c->client; | ||
2734 | struct Channel *chn = c->channel; | ||
2735 | |||
2736 | const char *name = (const char *) &req[1]; | ||
2737 | struct Operation *op = op_add (chn, client, req->op_id, 0); | ||
2738 | GNUNET_PSYCSTORE_state_get (store, &chn->pub_key, name, | ||
2739 | &store_recv_state_var, | ||
2740 | &store_recv_state_result, op); | ||
2741 | GNUNET_SERVICE_client_continue (client); | ||
2742 | } | ||
2743 | |||
2744 | |||
2745 | static int | ||
2746 | check_client_state_get_prefix (void *cls, | ||
2747 | const struct StateRequest *req) | ||
2748 | { | ||
2749 | struct Client *c = cls; | ||
2750 | struct Channel *chn = c->channel; | ||
2751 | if (NULL == chn) | ||
2752 | { | ||
2753 | GNUNET_break (0); | ||
2754 | return GNUNET_SYSERR; | ||
2755 | } | ||
2756 | |||
2757 | uint16_t name_size = ntohs (req->header.size) - sizeof (*req); | ||
2758 | const char *name = (const char *) &req[1]; | ||
2759 | if (0 == name_size || '\0' != name[name_size - 1]) | ||
2760 | { | ||
2761 | GNUNET_break (0); | ||
2762 | return GNUNET_SYSERR; | ||
2763 | } | ||
2764 | |||
2765 | return GNUNET_OK; | ||
2766 | } | ||
2767 | |||
2768 | |||
2769 | /** | ||
2770 | * Client requests state variables with a given prefix from PSYCstore. | ||
2771 | */ | ||
2772 | static void | ||
2773 | handle_client_state_get_prefix (void *cls, | ||
2774 | const struct StateRequest *req) | ||
2775 | { | ||
2776 | struct Client *c = cls; | ||
2777 | struct GNUNET_SERVICE_Client *client = c->client; | ||
2778 | struct Channel *chn = c->channel; | ||
2779 | |||
2780 | const char *name = (const char *) &req[1]; | ||
2781 | struct Operation *op = op_add (chn, client, req->op_id, 0); | ||
2782 | GNUNET_PSYCSTORE_state_get_prefix (store, &chn->pub_key, name, | ||
2783 | &store_recv_state_var, | ||
2784 | &store_recv_state_result, op); | ||
2785 | GNUNET_SERVICE_client_continue (client); | ||
2786 | } | ||
2787 | |||
2788 | |||
2789 | /** | ||
2790 | * Initialize the PSYC service. | ||
2791 | * | ||
2792 | * @param cls Closure. | ||
2793 | * @param server The initialized server. | ||
2794 | * @param c Configuration to use. | ||
2795 | */ | ||
2796 | static void | ||
2797 | run (void *cls, | ||
2798 | const struct GNUNET_CONFIGURATION_Handle *c, | ||
2799 | struct GNUNET_SERVICE_Handle *svc) | ||
2800 | { | ||
2801 | cfg = c; | ||
2802 | service = svc; | ||
2803 | store = GNUNET_PSYCSTORE_connect (cfg); | ||
2804 | stats = GNUNET_STATISTICS_create ("psyc", cfg); | ||
2805 | masters = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES); | ||
2806 | slaves = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES); | ||
2807 | channel_slaves = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); | ||
2808 | recv_cache = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); | ||
2809 | GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); | ||
2810 | } | ||
2811 | |||
2812 | |||
2813 | /** | ||
2814 | * Define "main" method using service macro. | ||
2815 | */ | ||
2816 | GNUNET_SERVICE_MAIN | ||
2817 | ("psyc", | ||
2818 | GNUNET_SERVICE_OPTION_NONE, | ||
2819 | &run, | ||
2820 | &client_notify_connect, | ||
2821 | &client_notify_disconnect, | ||
2822 | NULL, | ||
2823 | GNUNET_MQ_hd_fixed_size (client_master_start, | ||
2824 | GNUNET_MESSAGE_TYPE_PSYC_MASTER_START, | ||
2825 | struct MasterStartRequest, | ||
2826 | NULL), | ||
2827 | GNUNET_MQ_hd_var_size (client_slave_join, | ||
2828 | GNUNET_MESSAGE_TYPE_PSYC_SLAVE_JOIN, | ||
2829 | struct SlaveJoinRequest, | ||
2830 | NULL), | ||
2831 | GNUNET_MQ_hd_var_size (client_join_decision, | ||
2832 | GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION, | ||
2833 | struct GNUNET_PSYC_JoinDecisionMessage, | ||
2834 | NULL), | ||
2835 | GNUNET_MQ_hd_fixed_size (client_part_request, | ||
2836 | GNUNET_MESSAGE_TYPE_PSYC_PART_REQUEST, | ||
2837 | struct GNUNET_MessageHeader, | ||
2838 | NULL), | ||
2839 | GNUNET_MQ_hd_var_size (client_psyc_message, | ||
2840 | GNUNET_MESSAGE_TYPE_PSYC_MESSAGE, | ||
2841 | struct GNUNET_MessageHeader, | ||
2842 | NULL), | ||
2843 | GNUNET_MQ_hd_fixed_size (client_membership_store, | ||
2844 | GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_MEMBERSHIP_STORE, | ||
2845 | struct ChannelMembershipStoreRequest, | ||
2846 | NULL), | ||
2847 | GNUNET_MQ_hd_var_size (client_history_replay, | ||
2848 | GNUNET_MESSAGE_TYPE_PSYC_HISTORY_REPLAY, | ||
2849 | struct GNUNET_PSYC_HistoryRequestMessage, | ||
2850 | NULL), | ||
2851 | GNUNET_MQ_hd_var_size (client_state_get, | ||
2852 | GNUNET_MESSAGE_TYPE_PSYC_STATE_GET, | ||
2853 | struct StateRequest, | ||
2854 | NULL), | ||
2855 | GNUNET_MQ_hd_var_size (client_state_get_prefix, | ||
2856 | GNUNET_MESSAGE_TYPE_PSYC_STATE_GET_PREFIX, | ||
2857 | struct StateRequest, | ||
2858 | NULL)); | ||
2859 | |||
2860 | /* end of gnunet-service-psyc.c */ | ||
diff --git a/src/psyc/psyc.conf.in b/src/psyc/psyc.conf.in deleted file mode 100644 index 764ccfa84..000000000 --- a/src/psyc/psyc.conf.in +++ /dev/null | |||
@@ -1,12 +0,0 @@ | |||
1 | [psyc] | ||
2 | START_ON_DEMAND = @START_ON_DEMAND@ | ||
3 | BINARY = gnunet-service-psyc | ||
4 | |||
5 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-psyc.sock | ||
6 | UNIX_MATCH_UID = YES | ||
7 | UNIX_MATCH_GID = YES | ||
8 | |||
9 | @UNIXONLY@PORT = 2115 | ||
10 | HOSTNAME = localhost | ||
11 | ACCEPT_FROM = 127.0.0.1; | ||
12 | ACCEPT_FROM6 = ::1; | ||
diff --git a/src/psyc/psyc.h b/src/psyc/psyc.h deleted file mode 100644 index 74bbf3edc..000000000 --- a/src/psyc/psyc.h +++ /dev/null | |||
@@ -1,178 +0,0 @@ | |||
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 psyc/psyc.h | ||
23 | * @brief Common type definitions for the PSYC service and API. | ||
24 | * @author Gabor X Toth | ||
25 | */ | ||
26 | |||
27 | #ifndef PSYC_H | ||
28 | #define PSYC_H | ||
29 | |||
30 | #include "platform.h" | ||
31 | #include "gnunet_psyc_service.h" | ||
32 | |||
33 | |||
34 | int | ||
35 | GNUNET_PSYC_check_message_parts (uint16_t data_size, const char *data, | ||
36 | uint16_t *first_ptype, uint16_t *last_ptype); | ||
37 | |||
38 | void | ||
39 | GNUNET_PSYC_log_message (enum GNUNET_ErrorType kind, | ||
40 | const struct GNUNET_MessageHeader *msg); | ||
41 | |||
42 | |||
43 | enum MessageState | ||
44 | { | ||
45 | MSG_STATE_START = 0, | ||
46 | MSG_STATE_HEADER = 1, | ||
47 | MSG_STATE_METHOD = 2, | ||
48 | MSG_STATE_MODIFIER = 3, | ||
49 | MSG_STATE_MOD_CONT = 4, | ||
50 | MSG_STATE_DATA = 5, | ||
51 | MSG_STATE_END = 6, | ||
52 | MSG_STATE_CANCEL = 7, | ||
53 | MSG_STATE_ERROR = 8, | ||
54 | }; | ||
55 | |||
56 | |||
57 | enum MessageFragmentState | ||
58 | { | ||
59 | MSG_FRAG_STATE_START = 0, | ||
60 | MSG_FRAG_STATE_HEADER = 1, | ||
61 | MSG_FRAG_STATE_DATA = 2, | ||
62 | MSG_FRAG_STATE_END = 3, | ||
63 | MSG_FRAG_STATE_CANCEL = 4, | ||
64 | MSG_FRAG_STATE_DROP = 5, | ||
65 | }; | ||
66 | |||
67 | |||
68 | GNUNET_NETWORK_STRUCT_BEGIN | ||
69 | |||
70 | |||
71 | /**** library -> service ****/ | ||
72 | |||
73 | |||
74 | struct MasterStartRequest | ||
75 | { | ||
76 | /** | ||
77 | * Type: GNUNET_MESSAGE_TYPE_PSYC_MASTER_START | ||
78 | */ | ||
79 | struct GNUNET_MessageHeader header; | ||
80 | |||
81 | uint32_t policy GNUNET_PACKED; | ||
82 | |||
83 | struct GNUNET_CRYPTO_EddsaPrivateKey channel_key; | ||
84 | }; | ||
85 | |||
86 | |||
87 | struct SlaveJoinRequest | ||
88 | { | ||
89 | /** | ||
90 | * Type: GNUNET_MESSAGE_TYPE_PSYC_SLAVE_JOIN | ||
91 | */ | ||
92 | struct GNUNET_MessageHeader header; | ||
93 | |||
94 | uint32_t relay_count GNUNET_PACKED; | ||
95 | |||
96 | struct GNUNET_CRYPTO_EddsaPublicKey channel_pub_key; | ||
97 | |||
98 | struct GNUNET_CRYPTO_EcdsaPrivateKey slave_key; | ||
99 | |||
100 | struct GNUNET_PeerIdentity origin; | ||
101 | |||
102 | uint32_t flags GNUNET_PACKED; | ||
103 | |||
104 | /* Followed by struct GNUNET_PeerIdentity relays[relay_count] */ | ||
105 | |||
106 | /* Followed by struct GNUNET_MessageHeader join_msg */ | ||
107 | }; | ||
108 | |||
109 | |||
110 | struct ChannelMembershipStoreRequest | ||
111 | { | ||
112 | /** | ||
113 | * Type: GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_MEMBERSHIP_STORE | ||
114 | */ | ||
115 | struct GNUNET_MessageHeader header; | ||
116 | |||
117 | uint32_t reserved GNUNET_PACKED; | ||
118 | |||
119 | uint64_t op_id GNUNET_PACKED; | ||
120 | |||
121 | struct GNUNET_CRYPTO_EcdsaPublicKey slave_pub_key; | ||
122 | |||
123 | uint64_t announced_at GNUNET_PACKED; | ||
124 | |||
125 | uint64_t effective_since GNUNET_PACKED; | ||
126 | |||
127 | uint8_t did_join; | ||
128 | }; | ||
129 | |||
130 | |||
131 | struct HistoryRequest | ||
132 | { | ||
133 | /** | ||
134 | * Type: GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_HISTORY_REQUEST | ||
135 | */ | ||
136 | struct GNUNET_MessageHeader header; | ||
137 | |||
138 | uint32_t reserved GNUNET_PACKED; | ||
139 | |||
140 | /** | ||
141 | * ID for this operation. | ||
142 | */ | ||
143 | uint64_t op_id GNUNET_PACKED; | ||
144 | |||
145 | uint64_t start_message_id GNUNET_PACKED; | ||
146 | |||
147 | uint64_t end_message_id GNUNET_PACKED; | ||
148 | |||
149 | uint64_t message_limit GNUNET_PACKED; | ||
150 | }; | ||
151 | |||
152 | |||
153 | struct StateRequest | ||
154 | { | ||
155 | /** | ||
156 | * Types: | ||
157 | * - GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_STATE_GET | ||
158 | * - GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_STATE_GET_PREFIX | ||
159 | */ | ||
160 | struct GNUNET_MessageHeader header; | ||
161 | |||
162 | uint32_t reserved GNUNET_PACKED; | ||
163 | |||
164 | /** | ||
165 | * ID for this operation. | ||
166 | */ | ||
167 | uint64_t op_id GNUNET_PACKED; | ||
168 | |||
169 | /* Followed by NUL-terminated name. */ | ||
170 | }; | ||
171 | |||
172 | |||
173 | /**** service -> library ****/ | ||
174 | |||
175 | |||
176 | GNUNET_NETWORK_STRUCT_END | ||
177 | |||
178 | #endif | ||
diff --git a/src/psyc/psyc_api.c b/src/psyc/psyc_api.c deleted file mode 100644 index 37ea112cb..000000000 --- a/src/psyc/psyc_api.c +++ /dev/null | |||
@@ -1,1584 +0,0 @@ | |||
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 psyc/psyc_api.c | ||
23 | * @brief PSYC service; high-level access to the PSYC protocol | ||
24 | * note that clients of this API are NOT expected to | ||
25 | * understand the PSYC message format, only the semantics! | ||
26 | * Parsing (and serializing) the PSYC stream format is done | ||
27 | * within the implementation of the libgnunetpsyc library, | ||
28 | * and this API deliberately exposes as little as possible | ||
29 | * of the actual data stream format to the application! | ||
30 | * @author Gabor X Toth | ||
31 | */ | ||
32 | |||
33 | #include <inttypes.h> | ||
34 | |||
35 | #include "platform.h" | ||
36 | #include "gnunet_util_lib.h" | ||
37 | #include "gnunet_multicast_service.h" | ||
38 | #include "gnunet_psyc_service.h" | ||
39 | #include "gnunet_psyc_util_lib.h" | ||
40 | #include "psyc.h" | ||
41 | |||
42 | #define LOG(kind,...) GNUNET_log_from (kind, "psyc-api",__VA_ARGS__) | ||
43 | |||
44 | |||
45 | /** | ||
46 | * Handle to access PSYC channel operations for both the master and slaves. | ||
47 | */ | ||
48 | struct GNUNET_PSYC_Channel | ||
49 | { | ||
50 | /** | ||
51 | * Configuration to use. | ||
52 | */ | ||
53 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
54 | |||
55 | /** | ||
56 | * Client connection to the service. | ||
57 | */ | ||
58 | struct GNUNET_MQ_Handle *mq; | ||
59 | |||
60 | /** | ||
61 | * Message to send on connect. | ||
62 | */ | ||
63 | struct GNUNET_MQ_Envelope *connect_env; | ||
64 | |||
65 | /** | ||
66 | * Time to wait until we try to reconnect on failure. | ||
67 | */ | ||
68 | struct GNUNET_TIME_Relative reconnect_delay; | ||
69 | |||
70 | /** | ||
71 | * Task for reconnecting when the listener fails. | ||
72 | */ | ||
73 | struct GNUNET_SCHEDULER_Task *reconnect_task; | ||
74 | |||
75 | /** | ||
76 | * Async operations. | ||
77 | */ | ||
78 | struct GNUNET_OP_Handle *op; | ||
79 | |||
80 | /** | ||
81 | * Transmission handle; | ||
82 | */ | ||
83 | struct GNUNET_PSYC_TransmitHandle *tmit; | ||
84 | |||
85 | /** | ||
86 | * Receipt handle; | ||
87 | */ | ||
88 | struct GNUNET_PSYC_ReceiveHandle *recv; | ||
89 | |||
90 | /** | ||
91 | * Function called after disconnected from the service. | ||
92 | */ | ||
93 | GNUNET_ContinuationCallback disconnect_cb; | ||
94 | |||
95 | /** | ||
96 | * Closure for @a disconnect_cb. | ||
97 | */ | ||
98 | void *disconnect_cls; | ||
99 | |||
100 | /** | ||
101 | * Are we polling for incoming messages right now? | ||
102 | */ | ||
103 | uint8_t in_receive; | ||
104 | |||
105 | /** | ||
106 | * Is this a master or slave channel? | ||
107 | */ | ||
108 | uint8_t is_master; | ||
109 | |||
110 | /** | ||
111 | * Is this channel in the process of disconnecting from the service? | ||
112 | * #GNUNET_YES or #GNUNET_NO | ||
113 | */ | ||
114 | uint8_t is_disconnecting; | ||
115 | }; | ||
116 | |||
117 | |||
118 | /** | ||
119 | * Handle for the master of a PSYC channel. | ||
120 | */ | ||
121 | struct GNUNET_PSYC_Master | ||
122 | { | ||
123 | struct GNUNET_PSYC_Channel chn; | ||
124 | |||
125 | GNUNET_PSYC_MasterStartCallback start_cb; | ||
126 | |||
127 | /** | ||
128 | * Join request callback. | ||
129 | */ | ||
130 | GNUNET_PSYC_JoinRequestCallback join_req_cb; | ||
131 | |||
132 | /** | ||
133 | * Closure for the callbacks. | ||
134 | */ | ||
135 | void *cb_cls; | ||
136 | }; | ||
137 | |||
138 | |||
139 | /** | ||
140 | * Handle for a PSYC channel slave. | ||
141 | */ | ||
142 | struct GNUNET_PSYC_Slave | ||
143 | { | ||
144 | struct GNUNET_PSYC_Channel chn; | ||
145 | |||
146 | GNUNET_PSYC_SlaveConnectCallback connect_cb; | ||
147 | |||
148 | GNUNET_PSYC_JoinDecisionCallback join_dcsn_cb; | ||
149 | |||
150 | /** | ||
151 | * Closure for the callbacks. | ||
152 | */ | ||
153 | void *cb_cls; | ||
154 | }; | ||
155 | |||
156 | |||
157 | /** | ||
158 | * Handle that identifies a join request. | ||
159 | * | ||
160 | * Used to match calls to #GNUNET_PSYC_JoinRequestCallback to the | ||
161 | * corresponding calls to GNUNET_PSYC_join_decision(). | ||
162 | */ | ||
163 | struct GNUNET_PSYC_JoinHandle | ||
164 | { | ||
165 | struct GNUNET_PSYC_Master *mst; | ||
166 | struct GNUNET_CRYPTO_EcdsaPublicKey slave_pub_key; | ||
167 | }; | ||
168 | |||
169 | |||
170 | /** | ||
171 | * Handle for a pending PSYC transmission operation. | ||
172 | */ | ||
173 | struct GNUNET_PSYC_SlaveTransmitHandle | ||
174 | { | ||
175 | |||
176 | }; | ||
177 | |||
178 | |||
179 | struct GNUNET_PSYC_HistoryRequest | ||
180 | { | ||
181 | /** | ||
182 | * Channel. | ||
183 | */ | ||
184 | struct GNUNET_PSYC_Channel *chn; | ||
185 | |||
186 | /** | ||
187 | * Operation ID. | ||
188 | */ | ||
189 | uint64_t op_id; | ||
190 | |||
191 | /** | ||
192 | * Message handler. | ||
193 | */ | ||
194 | struct GNUNET_PSYC_ReceiveHandle *recv; | ||
195 | |||
196 | /** | ||
197 | * Function to call when the operation finished. | ||
198 | */ | ||
199 | GNUNET_ResultCallback result_cb; | ||
200 | |||
201 | /** | ||
202 | * Closure for @a result_cb. | ||
203 | */ | ||
204 | void *cls; | ||
205 | }; | ||
206 | |||
207 | |||
208 | struct GNUNET_PSYC_StateRequest | ||
209 | { | ||
210 | /** | ||
211 | * Channel. | ||
212 | */ | ||
213 | struct GNUNET_PSYC_Channel *chn; | ||
214 | |||
215 | /** | ||
216 | * Operation ID. | ||
217 | */ | ||
218 | uint64_t op_id; | ||
219 | |||
220 | /** | ||
221 | * State variable result callback. | ||
222 | */ | ||
223 | GNUNET_PSYC_StateVarCallback var_cb; | ||
224 | |||
225 | /** | ||
226 | * Function to call when the operation finished. | ||
227 | */ | ||
228 | GNUNET_ResultCallback result_cb; | ||
229 | |||
230 | /** | ||
231 | * Closure for @a result_cb. | ||
232 | */ | ||
233 | void *cls; | ||
234 | }; | ||
235 | |||
236 | |||
237 | static int | ||
238 | check_channel_result (void *cls, | ||
239 | const struct GNUNET_OperationResultMessage *res) | ||
240 | { | ||
241 | return GNUNET_OK; | ||
242 | } | ||
243 | |||
244 | |||
245 | static void | ||
246 | handle_channel_result (void *cls, | ||
247 | const struct GNUNET_OperationResultMessage *res) | ||
248 | { | ||
249 | struct GNUNET_PSYC_Channel *chn = cls; | ||
250 | |||
251 | uint16_t size = ntohs (res->header.size); | ||
252 | if (size < sizeof (*res)) | ||
253 | { /* Error, message too small. */ | ||
254 | GNUNET_break (0); | ||
255 | return; | ||
256 | } | ||
257 | |||
258 | uint16_t data_size = size - sizeof (*res); | ||
259 | const char *data = (0 < data_size) ? (void *) &res[1] : NULL; | ||
260 | GNUNET_OP_result (chn->op, GNUNET_ntohll (res->op_id), | ||
261 | GNUNET_ntohll (res->result_code), | ||
262 | data, data_size, NULL); | ||
263 | |||
264 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
265 | "handle_channel_result: Received result message with OP ID %" PRIu64 "\n", | ||
266 | GNUNET_ntohll (res->op_id)); | ||
267 | } | ||
268 | |||
269 | |||
270 | static void | ||
271 | op_recv_history_result (void *cls, int64_t result, | ||
272 | const void *data, uint16_t data_size) | ||
273 | { | ||
274 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
275 | "Received history replay result: %" PRId64 ".\n", result); | ||
276 | |||
277 | struct GNUNET_PSYC_HistoryRequest *hist = cls; | ||
278 | |||
279 | if (NULL != hist->result_cb) | ||
280 | hist->result_cb (hist->cls, result, data, data_size); | ||
281 | |||
282 | GNUNET_PSYC_receive_destroy (hist->recv); | ||
283 | GNUNET_free (hist); | ||
284 | } | ||
285 | |||
286 | |||
287 | static void | ||
288 | op_recv_state_result (void *cls, int64_t result, | ||
289 | const void *data, uint16_t data_size) | ||
290 | { | ||
291 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
292 | "Received state request result: %" PRId64 ".\n", result); | ||
293 | |||
294 | struct GNUNET_PSYC_StateRequest *sr = cls; | ||
295 | |||
296 | if (NULL != sr->result_cb) | ||
297 | sr->result_cb (sr->cls, result, data, data_size); | ||
298 | |||
299 | GNUNET_free (sr); | ||
300 | } | ||
301 | |||
302 | |||
303 | static int | ||
304 | check_channel_history_result (void *cls, | ||
305 | const struct GNUNET_OperationResultMessage *res) | ||
306 | { | ||
307 | struct GNUNET_PSYC_MessageHeader * | ||
308 | pmsg = (struct GNUNET_PSYC_MessageHeader *) GNUNET_MQ_extract_nested_mh (res); | ||
309 | uint16_t size = ntohs (res->header.size); | ||
310 | |||
311 | if ( (NULL == pmsg) || | ||
312 | (size < sizeof (*res) + sizeof (*pmsg)) ) | ||
313 | { /* Error, message too small. */ | ||
314 | GNUNET_break_op (0); | ||
315 | return GNUNET_SYSERR; | ||
316 | } | ||
317 | return GNUNET_OK; | ||
318 | } | ||
319 | |||
320 | |||
321 | static void | ||
322 | handle_channel_history_result (void *cls, | ||
323 | const struct GNUNET_OperationResultMessage *res) | ||
324 | { | ||
325 | struct GNUNET_PSYC_Channel *chn = cls; | ||
326 | struct GNUNET_PSYC_MessageHeader * | ||
327 | pmsg = (struct GNUNET_PSYC_MessageHeader *) GNUNET_MQ_extract_nested_mh (res); | ||
328 | GNUNET_ResultCallback result_cb = NULL; | ||
329 | struct GNUNET_PSYC_HistoryRequest *hist = NULL; | ||
330 | |||
331 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
332 | "%p Received historic fragment for message #%" PRIu64 ".\n", | ||
333 | chn, | ||
334 | GNUNET_ntohll (pmsg->message_id)); | ||
335 | |||
336 | if (GNUNET_YES != GNUNET_OP_get (chn->op, | ||
337 | GNUNET_ntohll (res->op_id), | ||
338 | &result_cb, (void *) &hist, NULL)) | ||
339 | { /* Operation not found. */ | ||
340 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
341 | "%p Replay operation not found for historic fragment of message #%" | ||
342 | PRIu64 ".\n", | ||
343 | chn, GNUNET_ntohll (pmsg->message_id)); | ||
344 | return; | ||
345 | } | ||
346 | |||
347 | GNUNET_PSYC_receive_message (hist->recv, | ||
348 | (const struct GNUNET_PSYC_MessageHeader *) pmsg); | ||
349 | } | ||
350 | |||
351 | |||
352 | static int | ||
353 | check_channel_state_result (void *cls, | ||
354 | const struct GNUNET_OperationResultMessage *res) | ||
355 | { | ||
356 | const struct GNUNET_MessageHeader *mod = GNUNET_MQ_extract_nested_mh (res); | ||
357 | uint16_t mod_size; | ||
358 | uint16_t size; | ||
359 | |||
360 | if (NULL == mod) | ||
361 | { | ||
362 | GNUNET_break_op (0); | ||
363 | return GNUNET_SYSERR; | ||
364 | } | ||
365 | mod_size = ntohs (mod->size); | ||
366 | size = ntohs (res->header.size); | ||
367 | if (size - sizeof (*res) != mod_size) | ||
368 | { | ||
369 | GNUNET_break_op (0); | ||
370 | return GNUNET_SYSERR; | ||
371 | } | ||
372 | return GNUNET_OK; | ||
373 | } | ||
374 | |||
375 | |||
376 | static void | ||
377 | handle_channel_state_result (void *cls, | ||
378 | const struct GNUNET_OperationResultMessage *res) | ||
379 | { | ||
380 | struct GNUNET_PSYC_Channel *chn = cls; | ||
381 | |||
382 | GNUNET_ResultCallback result_cb = NULL; | ||
383 | struct GNUNET_PSYC_StateRequest *sr = NULL; | ||
384 | |||
385 | if (GNUNET_YES != GNUNET_OP_get (chn->op, | ||
386 | GNUNET_ntohll (res->op_id), | ||
387 | &result_cb, (void *) &sr, NULL)) | ||
388 | { /* Operation not found. */ | ||
389 | return; | ||
390 | } | ||
391 | |||
392 | const struct GNUNET_MessageHeader *mod = GNUNET_MQ_extract_nested_mh (res); | ||
393 | if (NULL == mod) | ||
394 | { | ||
395 | GNUNET_break_op (0); | ||
396 | return; | ||
397 | } | ||
398 | uint16_t mod_size = ntohs (mod->size); | ||
399 | |||
400 | switch (ntohs (mod->type)) | ||
401 | { | ||
402 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER: | ||
403 | { | ||
404 | const struct GNUNET_PSYC_MessageModifier * | ||
405 | pmod = (const struct GNUNET_PSYC_MessageModifier *) mod; | ||
406 | |||
407 | const char *name = (const char *) &pmod[1]; | ||
408 | uint16_t name_size = ntohs (pmod->name_size); | ||
409 | if (0 == name_size | ||
410 | || mod_size - sizeof (*pmod) < name_size | ||
411 | || '\0' != name[name_size - 1]) | ||
412 | { | ||
413 | GNUNET_break_op (0); | ||
414 | return; | ||
415 | } | ||
416 | sr->var_cb (sr->cls, mod, name, name + name_size, | ||
417 | ntohs (pmod->header.size) - sizeof (*pmod), | ||
418 | ntohs (pmod->value_size)); | ||
419 | break; | ||
420 | } | ||
421 | |||
422 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT: | ||
423 | sr->var_cb (sr->cls, mod, NULL, (const char *) &mod[1], | ||
424 | mod_size - sizeof (*mod), 0); | ||
425 | break; | ||
426 | } | ||
427 | } | ||
428 | |||
429 | |||
430 | static int | ||
431 | check_channel_message (void *cls, | ||
432 | const struct GNUNET_PSYC_MessageHeader *pmsg) | ||
433 | { | ||
434 | return GNUNET_OK; | ||
435 | } | ||
436 | |||
437 | |||
438 | static void | ||
439 | handle_channel_message (void *cls, | ||
440 | const struct GNUNET_PSYC_MessageHeader *pmsg) | ||
441 | { | ||
442 | struct GNUNET_PSYC_Channel *chn = cls; | ||
443 | |||
444 | GNUNET_PSYC_receive_message (chn->recv, pmsg); | ||
445 | } | ||
446 | |||
447 | |||
448 | static void | ||
449 | handle_channel_message_ack (void *cls, | ||
450 | const struct GNUNET_MessageHeader *msg) | ||
451 | { | ||
452 | struct GNUNET_PSYC_Channel *chn = cls; | ||
453 | |||
454 | GNUNET_PSYC_transmit_got_ack (chn->tmit); | ||
455 | } | ||
456 | |||
457 | |||
458 | static void | ||
459 | handle_master_start_ack (void *cls, | ||
460 | const struct GNUNET_PSYC_CountersResultMessage *cres) | ||
461 | { | ||
462 | struct GNUNET_PSYC_Master *mst = cls; | ||
463 | |||
464 | int32_t result = ntohl (cres->result_code); | ||
465 | if (GNUNET_OK != result && GNUNET_NO != result) | ||
466 | { | ||
467 | LOG (GNUNET_ERROR_TYPE_ERROR, "Could not start master: %ld\n", result); | ||
468 | GNUNET_break (0); | ||
469 | /* FIXME: disconnect */ | ||
470 | } | ||
471 | if (NULL != mst->start_cb) | ||
472 | mst->start_cb (mst->cb_cls, result, GNUNET_ntohll (cres->max_message_id)); | ||
473 | } | ||
474 | |||
475 | |||
476 | static int | ||
477 | check_master_join_request (void *cls, | ||
478 | const struct GNUNET_PSYC_JoinRequestMessage *req) | ||
479 | { | ||
480 | if ( ((sizeof (*req) + sizeof (struct GNUNET_PSYC_Message)) <= ntohs (req->header.size)) && | ||
481 | (NULL == GNUNET_MQ_extract_nested_mh (req)) ) | ||
482 | { | ||
483 | GNUNET_break_op (0); | ||
484 | return GNUNET_SYSERR; | ||
485 | } | ||
486 | return GNUNET_OK; | ||
487 | } | ||
488 | |||
489 | |||
490 | static void | ||
491 | handle_master_join_request (void *cls, | ||
492 | const struct GNUNET_PSYC_JoinRequestMessage *req) | ||
493 | { | ||
494 | struct GNUNET_PSYC_Master *mst = cls; | ||
495 | |||
496 | if (NULL == mst->join_req_cb) | ||
497 | return; | ||
498 | |||
499 | const struct GNUNET_PSYC_Message *join_msg = NULL; | ||
500 | if (sizeof (*req) + sizeof (*join_msg) <= ntohs (req->header.size)) | ||
501 | { | ||
502 | join_msg = (struct GNUNET_PSYC_Message *) GNUNET_MQ_extract_nested_mh (req); | ||
503 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
504 | "Received join_msg of type %u and size %u.\n", | ||
505 | ntohs (join_msg->header.type), | ||
506 | ntohs (join_msg->header.size)); | ||
507 | } | ||
508 | |||
509 | struct GNUNET_PSYC_JoinHandle *jh = GNUNET_malloc (sizeof (*jh)); | ||
510 | jh->mst = mst; | ||
511 | jh->slave_pub_key = req->slave_pub_key; | ||
512 | |||
513 | if (NULL != mst->join_req_cb) | ||
514 | mst->join_req_cb (mst->cb_cls, req, &req->slave_pub_key, join_msg, jh); | ||
515 | } | ||
516 | |||
517 | |||
518 | static void | ||
519 | handle_slave_join_ack (void *cls, | ||
520 | const struct GNUNET_PSYC_CountersResultMessage *cres) | ||
521 | { | ||
522 | struct GNUNET_PSYC_Slave *slv = cls; | ||
523 | |||
524 | int32_t result = ntohl (cres->result_code); | ||
525 | if (GNUNET_YES != result && GNUNET_NO != result) | ||
526 | { | ||
527 | LOG (GNUNET_ERROR_TYPE_ERROR, "Could not join slave.\n"); | ||
528 | GNUNET_break (0); | ||
529 | /* FIXME: disconnect */ | ||
530 | } | ||
531 | if (NULL != slv->connect_cb) | ||
532 | slv->connect_cb (slv->cb_cls, result, GNUNET_ntohll (cres->max_message_id)); | ||
533 | } | ||
534 | |||
535 | |||
536 | static int | ||
537 | check_slave_join_decision (void *cls, | ||
538 | const struct GNUNET_PSYC_JoinDecisionMessage *dcsn) | ||
539 | { | ||
540 | return GNUNET_OK; | ||
541 | } | ||
542 | |||
543 | |||
544 | static void | ||
545 | handle_slave_join_decision (void *cls, | ||
546 | const struct GNUNET_PSYC_JoinDecisionMessage *dcsn) | ||
547 | { | ||
548 | struct GNUNET_PSYC_Slave *slv = cls; | ||
549 | |||
550 | struct GNUNET_PSYC_Message *pmsg = NULL; | ||
551 | if (ntohs (dcsn->header.size) <= sizeof (*dcsn) + sizeof (*pmsg)) | ||
552 | pmsg = (struct GNUNET_PSYC_Message *) &dcsn[1]; | ||
553 | |||
554 | if (NULL != slv->join_dcsn_cb) | ||
555 | slv->join_dcsn_cb (slv->cb_cls, dcsn, ntohl (dcsn->is_admitted), pmsg); | ||
556 | } | ||
557 | |||
558 | |||
559 | static void | ||
560 | channel_cleanup (struct GNUNET_PSYC_Channel *chn) | ||
561 | { | ||
562 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
563 | "cleaning up channel %p\n", | ||
564 | chn); | ||
565 | if (NULL != chn->tmit) | ||
566 | { | ||
567 | GNUNET_PSYC_transmit_destroy (chn->tmit); | ||
568 | chn->tmit = NULL; | ||
569 | } | ||
570 | if (NULL != chn->recv) | ||
571 | { | ||
572 | |||
573 | GNUNET_PSYC_receive_destroy (chn->recv); | ||
574 | chn->recv = NULL; | ||
575 | } | ||
576 | if (NULL != chn->connect_env) | ||
577 | { | ||
578 | GNUNET_MQ_discard (chn->connect_env); | ||
579 | chn->connect_env = NULL; | ||
580 | } | ||
581 | if (NULL != chn->mq) | ||
582 | { | ||
583 | GNUNET_MQ_destroy (chn->mq); | ||
584 | chn->mq = NULL; | ||
585 | } | ||
586 | if (NULL != chn->disconnect_cb) | ||
587 | { | ||
588 | chn->disconnect_cb (chn->disconnect_cls); | ||
589 | chn->disconnect_cb = NULL; | ||
590 | } | ||
591 | GNUNET_free (chn); | ||
592 | } | ||
593 | |||
594 | |||
595 | static void | ||
596 | handle_channel_part_ack (void *cls, | ||
597 | const struct GNUNET_MessageHeader *msg) | ||
598 | { | ||
599 | struct GNUNET_PSYC_Channel *chn = cls; | ||
600 | |||
601 | channel_cleanup (chn); | ||
602 | } | ||
603 | |||
604 | |||
605 | /*** MASTER ***/ | ||
606 | |||
607 | |||
608 | static void | ||
609 | master_connect (struct GNUNET_PSYC_Master *mst); | ||
610 | |||
611 | |||
612 | static void | ||
613 | master_reconnect (void *cls) | ||
614 | { | ||
615 | master_connect (cls); | ||
616 | } | ||
617 | |||
618 | |||
619 | /** | ||
620 | * Master client disconnected from service. | ||
621 | * | ||
622 | * Reconnect after backoff period. | ||
623 | */ | ||
624 | static void | ||
625 | master_disconnected (void *cls, enum GNUNET_MQ_Error error) | ||
626 | { | ||
627 | struct GNUNET_PSYC_Master *mst = cls; | ||
628 | struct GNUNET_PSYC_Channel *chn = &mst->chn; | ||
629 | |||
630 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
631 | "Master client disconnected (%d), re-connecting\n", | ||
632 | (int) error); | ||
633 | if (NULL != chn->tmit) | ||
634 | { | ||
635 | GNUNET_PSYC_transmit_destroy (chn->tmit); | ||
636 | chn->tmit = NULL; | ||
637 | } | ||
638 | if (NULL != chn->mq) | ||
639 | { | ||
640 | GNUNET_MQ_destroy (chn->mq); | ||
641 | chn->mq = NULL; | ||
642 | } | ||
643 | chn->reconnect_task = GNUNET_SCHEDULER_add_delayed (chn->reconnect_delay, | ||
644 | master_reconnect, | ||
645 | mst); | ||
646 | chn->reconnect_delay = GNUNET_TIME_STD_BACKOFF (chn->reconnect_delay); | ||
647 | } | ||
648 | |||
649 | |||
650 | static void | ||
651 | master_connect (struct GNUNET_PSYC_Master *mst) | ||
652 | { | ||
653 | struct GNUNET_PSYC_Channel *chn = &mst->chn; | ||
654 | |||
655 | struct GNUNET_MQ_MessageHandler handlers[] = { | ||
656 | GNUNET_MQ_hd_fixed_size (master_start_ack, | ||
657 | GNUNET_MESSAGE_TYPE_PSYC_MASTER_START_ACK, | ||
658 | struct GNUNET_PSYC_CountersResultMessage, | ||
659 | mst), | ||
660 | GNUNET_MQ_hd_var_size (master_join_request, | ||
661 | GNUNET_MESSAGE_TYPE_PSYC_JOIN_REQUEST, | ||
662 | struct GNUNET_PSYC_JoinRequestMessage, | ||
663 | mst), | ||
664 | GNUNET_MQ_hd_fixed_size (channel_part_ack, | ||
665 | GNUNET_MESSAGE_TYPE_PSYC_PART_ACK, | ||
666 | struct GNUNET_MessageHeader, | ||
667 | chn), | ||
668 | GNUNET_MQ_hd_var_size (channel_message, | ||
669 | GNUNET_MESSAGE_TYPE_PSYC_MESSAGE, | ||
670 | struct GNUNET_PSYC_MessageHeader, | ||
671 | chn), | ||
672 | GNUNET_MQ_hd_fixed_size (channel_message_ack, | ||
673 | GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_ACK, | ||
674 | struct GNUNET_MessageHeader, | ||
675 | chn), | ||
676 | GNUNET_MQ_hd_var_size (channel_history_result, | ||
677 | GNUNET_MESSAGE_TYPE_PSYC_HISTORY_RESULT, | ||
678 | struct GNUNET_OperationResultMessage, | ||
679 | chn), | ||
680 | GNUNET_MQ_hd_var_size (channel_state_result, | ||
681 | GNUNET_MESSAGE_TYPE_PSYC_STATE_RESULT, | ||
682 | struct GNUNET_OperationResultMessage, | ||
683 | chn), | ||
684 | GNUNET_MQ_hd_var_size (channel_result, | ||
685 | GNUNET_MESSAGE_TYPE_PSYC_RESULT_CODE, | ||
686 | struct GNUNET_OperationResultMessage, | ||
687 | chn), | ||
688 | GNUNET_MQ_handler_end () | ||
689 | }; | ||
690 | |||
691 | chn->mq = GNUNET_CLIENT_connect (chn->cfg, | ||
692 | "psyc", | ||
693 | handlers, | ||
694 | &master_disconnected, | ||
695 | mst); | ||
696 | GNUNET_assert (NULL != chn->mq); | ||
697 | chn->tmit = GNUNET_PSYC_transmit_create (chn->mq); | ||
698 | |||
699 | GNUNET_MQ_send_copy (chn->mq, chn->connect_env); | ||
700 | } | ||
701 | |||
702 | |||
703 | /** | ||
704 | * Start a PSYC master channel. | ||
705 | * | ||
706 | * Will start a multicast group identified by the given ECC key. Messages | ||
707 | * received from group members will be given to the respective handler methods. | ||
708 | * If a new member wants to join a group, the "join" method handler will be | ||
709 | * invoked; the join handler must then generate a "join" message to approve the | ||
710 | * joining of the new member. The channel can also change group membership | ||
711 | * without explicit requests. Note that PSYC doesn't itself "understand" join | ||
712 | * or part messages, the respective methods must call other PSYC functions to | ||
713 | * inform PSYC about the meaning of the respective events. | ||
714 | * | ||
715 | * @param cfg Configuration to use (to connect to PSYC service). | ||
716 | * @param channel_key ECC key that will be used to sign messages for this | ||
717 | * PSYC session. The public key is used to identify the PSYC channel. | ||
718 | * Note that end-users will usually not use the private key directly, but | ||
719 | * rather look it up in GNS for places managed by other users, or select | ||
720 | * a file with the private key(s) when setting up their own channels | ||
721 | * FIXME: we'll likely want to use NOT the p521 curve here, but a cheaper | ||
722 | * one in the future. | ||
723 | * @param policy Channel policy specifying join and history restrictions. | ||
724 | * Used to automate join decisions. | ||
725 | * @param message_cb Function to invoke on message parts received from slaves. | ||
726 | * @param join_request_cb Function to invoke when a slave wants to join. | ||
727 | * @param master_start_cb Function to invoke after the channel master started. | ||
728 | * @param cls Closure for @a method and @a join_cb. | ||
729 | * | ||
730 | * @return Handle for the channel master, NULL on error. | ||
731 | */ | ||
732 | struct GNUNET_PSYC_Master * | ||
733 | GNUNET_PSYC_master_start (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
734 | const struct GNUNET_CRYPTO_EddsaPrivateKey *channel_key, | ||
735 | enum GNUNET_PSYC_Policy policy, | ||
736 | GNUNET_PSYC_MasterStartCallback start_cb, | ||
737 | GNUNET_PSYC_JoinRequestCallback join_request_cb, | ||
738 | GNUNET_PSYC_MessageCallback message_cb, | ||
739 | GNUNET_PSYC_MessagePartCallback message_part_cb, | ||
740 | void *cls) | ||
741 | { | ||
742 | struct GNUNET_PSYC_Master *mst = GNUNET_new (struct GNUNET_PSYC_Master); | ||
743 | struct GNUNET_PSYC_Channel *chn = &mst->chn; | ||
744 | struct MasterStartRequest *req; | ||
745 | |||
746 | chn->connect_env = GNUNET_MQ_msg (req, | ||
747 | GNUNET_MESSAGE_TYPE_PSYC_MASTER_START); | ||
748 | req->channel_key = *channel_key; | ||
749 | req->policy = policy; | ||
750 | |||
751 | chn->cfg = cfg; | ||
752 | chn->is_master = GNUNET_YES; | ||
753 | chn->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS; | ||
754 | |||
755 | chn->op = GNUNET_OP_create (); | ||
756 | chn->recv = GNUNET_PSYC_receive_create (message_cb, message_part_cb, cls); | ||
757 | |||
758 | mst->start_cb = start_cb; | ||
759 | mst->join_req_cb = join_request_cb; | ||
760 | mst->cb_cls = cls; | ||
761 | |||
762 | master_connect (mst); | ||
763 | return mst; | ||
764 | } | ||
765 | |||
766 | |||
767 | /** | ||
768 | * Stop a PSYC master channel. | ||
769 | * | ||
770 | * @param master PSYC channel master to stop. | ||
771 | * @param keep_active FIXME | ||
772 | */ | ||
773 | void | ||
774 | GNUNET_PSYC_master_stop (struct GNUNET_PSYC_Master *mst, | ||
775 | int keep_active, | ||
776 | GNUNET_ContinuationCallback stop_cb, | ||
777 | void *stop_cls) | ||
778 | { | ||
779 | struct GNUNET_PSYC_Channel *chn = &mst->chn; | ||
780 | struct GNUNET_MQ_Envelope *env; | ||
781 | |||
782 | chn->is_disconnecting = GNUNET_YES; | ||
783 | chn->disconnect_cb = stop_cb; | ||
784 | chn->disconnect_cls = stop_cls; | ||
785 | env = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_PSYC_PART_REQUEST); | ||
786 | GNUNET_MQ_send (chn->mq, env); | ||
787 | } | ||
788 | |||
789 | |||
790 | /** | ||
791 | * Function to call with the decision made for a join request. | ||
792 | * | ||
793 | * Must be called once and only once in response to an invocation of the | ||
794 | * #GNUNET_PSYC_JoinCallback. | ||
795 | * | ||
796 | * @param jh Join request handle. | ||
797 | * @param is_admitted #GNUNET_YES if the join is approved, | ||
798 | * #GNUNET_NO if it is disapproved, | ||
799 | * #GNUNET_SYSERR if we cannot answer the request. | ||
800 | * @param relay_count Number of relays given. | ||
801 | * @param relays Array of suggested peers that might be useful relays to use | ||
802 | * when joining the multicast group (essentially a list of peers that | ||
803 | * are already part of the multicast group and might thus be willing | ||
804 | * to help with routing). If empty, only this local peer (which must | ||
805 | * be the multicast origin) is a good candidate for building the | ||
806 | * multicast tree. Note that it is unnecessary to specify our own | ||
807 | * peer identity in this array. | ||
808 | * @param join_resp Application-dependent join response message. | ||
809 | * | ||
810 | * @return #GNUNET_OK on success, | ||
811 | * #GNUNET_SYSERR if the message is too large. | ||
812 | */ | ||
813 | int | ||
814 | GNUNET_PSYC_join_decision (struct GNUNET_PSYC_JoinHandle *jh, | ||
815 | int is_admitted, | ||
816 | uint32_t relay_count, | ||
817 | const struct GNUNET_PeerIdentity *relays, | ||
818 | const struct GNUNET_PSYC_Message *join_resp) | ||
819 | { | ||
820 | struct GNUNET_PSYC_Channel *chn = &jh->mst->chn; | ||
821 | struct GNUNET_PSYC_JoinDecisionMessage *dcsn; | ||
822 | uint16_t join_resp_size | ||
823 | = (NULL != join_resp) ? ntohs (join_resp->header.size) : 0; | ||
824 | uint16_t relay_size = relay_count * sizeof (*relays); | ||
825 | |||
826 | if (GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD | ||
827 | < sizeof (*dcsn) + relay_size + join_resp_size) | ||
828 | return GNUNET_SYSERR; | ||
829 | |||
830 | struct GNUNET_MQ_Envelope * | ||
831 | env = GNUNET_MQ_msg_extra (dcsn, relay_size + join_resp_size, | ||
832 | GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION); | ||
833 | dcsn->is_admitted = htonl (is_admitted); | ||
834 | dcsn->slave_pub_key = jh->slave_pub_key; | ||
835 | |||
836 | if (0 < join_resp_size) | ||
837 | GNUNET_memcpy (&dcsn[1], join_resp, join_resp_size); | ||
838 | |||
839 | GNUNET_MQ_send (chn->mq, env); | ||
840 | GNUNET_free (jh); | ||
841 | return GNUNET_OK; | ||
842 | } | ||
843 | |||
844 | |||
845 | /** | ||
846 | * Send a message to call a method to all members in the PSYC channel. | ||
847 | * | ||
848 | * @param master Handle to the PSYC channel. | ||
849 | * @param method_name Which method should be invoked. | ||
850 | * @param notify_mod Function to call to obtain modifiers. | ||
851 | * @param notify_data Function to call to obtain fragments of the data. | ||
852 | * @param notify_cls Closure for @a notify_mod and @a notify_data. | ||
853 | * @param flags Flags for the message being transmitted. | ||
854 | * | ||
855 | * @return Transmission handle, NULL on error (i.e. more than one request queued). | ||
856 | */ | ||
857 | struct GNUNET_PSYC_MasterTransmitHandle * | ||
858 | GNUNET_PSYC_master_transmit (struct GNUNET_PSYC_Master *mst, | ||
859 | const char *method_name, | ||
860 | GNUNET_PSYC_TransmitNotifyModifier notify_mod, | ||
861 | GNUNET_PSYC_TransmitNotifyData notify_data, | ||
862 | void *notify_cls, | ||
863 | enum GNUNET_PSYC_MasterTransmitFlags flags) | ||
864 | { | ||
865 | if (GNUNET_OK | ||
866 | == GNUNET_PSYC_transmit_message (mst->chn.tmit, method_name, NULL, | ||
867 | notify_mod, notify_data, notify_cls, | ||
868 | flags)) | ||
869 | return (struct GNUNET_PSYC_MasterTransmitHandle *) mst->chn.tmit; | ||
870 | else | ||
871 | return NULL; | ||
872 | } | ||
873 | |||
874 | |||
875 | /** | ||
876 | * Resume transmission to the channel. | ||
877 | * | ||
878 | * @param tmit Handle of the request that is being resumed. | ||
879 | */ | ||
880 | void | ||
881 | GNUNET_PSYC_master_transmit_resume (struct GNUNET_PSYC_MasterTransmitHandle *tmit) | ||
882 | { | ||
883 | GNUNET_PSYC_transmit_resume ((struct GNUNET_PSYC_TransmitHandle *) tmit); | ||
884 | } | ||
885 | |||
886 | |||
887 | /** | ||
888 | * Abort transmission request to the channel. | ||
889 | * | ||
890 | * @param tmit Handle of the request that is being aborted. | ||
891 | */ | ||
892 | void | ||
893 | GNUNET_PSYC_master_transmit_cancel (struct GNUNET_PSYC_MasterTransmitHandle *tmit) | ||
894 | { | ||
895 | GNUNET_PSYC_transmit_cancel ((struct GNUNET_PSYC_TransmitHandle *) tmit); | ||
896 | } | ||
897 | |||
898 | |||
899 | /** | ||
900 | * Convert a channel @a master to a @e channel handle to access the @e channel | ||
901 | * APIs. | ||
902 | * | ||
903 | * @param master Channel master handle. | ||
904 | * | ||
905 | * @return Channel handle, valid for as long as @a master is valid. | ||
906 | */ | ||
907 | struct GNUNET_PSYC_Channel * | ||
908 | GNUNET_PSYC_master_get_channel (struct GNUNET_PSYC_Master *master) | ||
909 | { | ||
910 | return &master->chn; | ||
911 | } | ||
912 | |||
913 | |||
914 | /*** SLAVE ***/ | ||
915 | |||
916 | |||
917 | static void | ||
918 | slave_connect (struct GNUNET_PSYC_Slave *slv); | ||
919 | |||
920 | |||
921 | static void | ||
922 | slave_reconnect (void *cls) | ||
923 | { | ||
924 | slave_connect (cls); | ||
925 | } | ||
926 | |||
927 | |||
928 | /** | ||
929 | * Slave client disconnected from service. | ||
930 | * | ||
931 | * Reconnect after backoff period. | ||
932 | */ | ||
933 | static void | ||
934 | slave_disconnected (void *cls, | ||
935 | enum GNUNET_MQ_Error error) | ||
936 | { | ||
937 | struct GNUNET_PSYC_Slave *slv = cls; | ||
938 | struct GNUNET_PSYC_Channel *chn = &slv->chn; | ||
939 | |||
940 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
941 | "Slave client disconnected (%d), re-connecting\n", | ||
942 | (int) error); | ||
943 | if (NULL != chn->tmit) | ||
944 | { | ||
945 | GNUNET_PSYC_transmit_destroy (chn->tmit); | ||
946 | chn->tmit = NULL; | ||
947 | } | ||
948 | if (NULL != chn->mq) | ||
949 | { | ||
950 | GNUNET_MQ_destroy (chn->mq); | ||
951 | chn->mq = NULL; | ||
952 | } | ||
953 | chn->reconnect_task = GNUNET_SCHEDULER_add_delayed (chn->reconnect_delay, | ||
954 | &slave_reconnect, | ||
955 | slv); | ||
956 | chn->reconnect_delay = GNUNET_TIME_STD_BACKOFF (chn->reconnect_delay); | ||
957 | } | ||
958 | |||
959 | |||
960 | static void | ||
961 | slave_connect (struct GNUNET_PSYC_Slave *slv) | ||
962 | { | ||
963 | struct GNUNET_PSYC_Channel *chn = &slv->chn; | ||
964 | |||
965 | struct GNUNET_MQ_MessageHandler handlers[] = { | ||
966 | GNUNET_MQ_hd_fixed_size (slave_join_ack, | ||
967 | GNUNET_MESSAGE_TYPE_PSYC_SLAVE_JOIN_ACK, | ||
968 | struct GNUNET_PSYC_CountersResultMessage, | ||
969 | slv), | ||
970 | GNUNET_MQ_hd_var_size (slave_join_decision, | ||
971 | GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION, | ||
972 | struct GNUNET_PSYC_JoinDecisionMessage, | ||
973 | slv), | ||
974 | GNUNET_MQ_hd_fixed_size (channel_part_ack, | ||
975 | GNUNET_MESSAGE_TYPE_PSYC_PART_ACK, | ||
976 | struct GNUNET_MessageHeader, | ||
977 | chn), | ||
978 | GNUNET_MQ_hd_var_size (channel_message, | ||
979 | GNUNET_MESSAGE_TYPE_PSYC_MESSAGE, | ||
980 | struct GNUNET_PSYC_MessageHeader, | ||
981 | chn), | ||
982 | GNUNET_MQ_hd_fixed_size (channel_message_ack, | ||
983 | GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_ACK, | ||
984 | struct GNUNET_MessageHeader, | ||
985 | chn), | ||
986 | GNUNET_MQ_hd_var_size (channel_history_result, | ||
987 | GNUNET_MESSAGE_TYPE_PSYC_HISTORY_RESULT, | ||
988 | struct GNUNET_OperationResultMessage, | ||
989 | chn), | ||
990 | GNUNET_MQ_hd_var_size (channel_state_result, | ||
991 | GNUNET_MESSAGE_TYPE_PSYC_STATE_RESULT, | ||
992 | struct GNUNET_OperationResultMessage, | ||
993 | chn), | ||
994 | GNUNET_MQ_hd_var_size (channel_result, | ||
995 | GNUNET_MESSAGE_TYPE_PSYC_RESULT_CODE, | ||
996 | struct GNUNET_OperationResultMessage, | ||
997 | chn), | ||
998 | GNUNET_MQ_handler_end () | ||
999 | }; | ||
1000 | |||
1001 | chn->mq = GNUNET_CLIENT_connect (chn->cfg, | ||
1002 | "psyc", | ||
1003 | handlers, | ||
1004 | &slave_disconnected, | ||
1005 | slv); | ||
1006 | if (NULL == chn->mq) | ||
1007 | { | ||
1008 | chn->reconnect_task = GNUNET_SCHEDULER_add_delayed (chn->reconnect_delay, | ||
1009 | &slave_reconnect, | ||
1010 | slv); | ||
1011 | chn->reconnect_delay = GNUNET_TIME_STD_BACKOFF (chn->reconnect_delay); | ||
1012 | return; | ||
1013 | } | ||
1014 | chn->tmit = GNUNET_PSYC_transmit_create (chn->mq); | ||
1015 | |||
1016 | GNUNET_MQ_send_copy (chn->mq, chn->connect_env); | ||
1017 | } | ||
1018 | |||
1019 | |||
1020 | /** | ||
1021 | * Join a PSYC channel. | ||
1022 | * | ||
1023 | * The entity joining is always the local peer. The user must immediately use | ||
1024 | * the GNUNET_PSYC_slave_transmit() functions to transmit a @e join_msg to the | ||
1025 | * channel; if the join request succeeds, the channel state (and @e recent | ||
1026 | * method calls) will be replayed to the joining member. There is no explicit | ||
1027 | * notification on failure (as the channel may simply take days to approve, | ||
1028 | * and disapproval is simply being ignored). | ||
1029 | * | ||
1030 | * @param cfg | ||
1031 | * Configuration to use. | ||
1032 | * @param channel_key ECC public key that identifies the channel we wish to join. | ||
1033 | * @param slave_key ECC private-public key pair that identifies the slave, and | ||
1034 | * used by multicast to sign the join request and subsequent unicast | ||
1035 | * requests sent to the master. | ||
1036 | * @param origin Peer identity of the origin. | ||
1037 | * @param relay_count Number of peers in the @a relays array. | ||
1038 | * @param relays Peer identities of members of the multicast group, which serve | ||
1039 | * as relays and used to join the group at. | ||
1040 | * @param message_cb Function to invoke on message parts received from the | ||
1041 | * channel, typically at least contains method handlers for @e join and | ||
1042 | * @e part. | ||
1043 | * @param slave_connect_cb Function invoked once we have connected to the | ||
1044 | * PSYC service. | ||
1045 | * @param join_decision_cb Function invoked once we have received a join | ||
1046 | * decision. | ||
1047 | * @param cls Closure for @a message_cb and @a slave_joined_cb. | ||
1048 | * @param method_name Method name for the join request. | ||
1049 | * @param env Environment containing transient variables for the request, or NULL. | ||
1050 | * @param data Payload for the join message. | ||
1051 | * @param data_size Number of bytes in @a data. | ||
1052 | * | ||
1053 | * @return Handle for the slave, NULL on error. | ||
1054 | */ | ||
1055 | struct GNUNET_PSYC_Slave * | ||
1056 | GNUNET_PSYC_slave_join (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
1057 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_pub_key, | ||
1058 | const struct GNUNET_CRYPTO_EcdsaPrivateKey *slave_key, | ||
1059 | enum GNUNET_PSYC_SlaveJoinFlags flags, | ||
1060 | const struct GNUNET_PeerIdentity *origin, | ||
1061 | uint32_t relay_count, | ||
1062 | const struct GNUNET_PeerIdentity *relays, | ||
1063 | GNUNET_PSYC_MessageCallback message_cb, | ||
1064 | GNUNET_PSYC_MessagePartCallback message_part_cb, | ||
1065 | GNUNET_PSYC_SlaveConnectCallback connect_cb, | ||
1066 | GNUNET_PSYC_JoinDecisionCallback join_decision_cb, | ||
1067 | void *cls, | ||
1068 | const struct GNUNET_PSYC_Message *join_msg) | ||
1069 | { | ||
1070 | struct GNUNET_PSYC_Slave *slv = GNUNET_malloc (sizeof (*slv)); | ||
1071 | struct GNUNET_PSYC_Channel *chn = &slv->chn; | ||
1072 | uint16_t relay_size = relay_count * sizeof (*relays); | ||
1073 | uint16_t join_msg_size; | ||
1074 | if (NULL == join_msg) | ||
1075 | join_msg_size = 0; | ||
1076 | else | ||
1077 | join_msg_size = ntohs (join_msg->header.size); | ||
1078 | |||
1079 | struct SlaveJoinRequest *req; | ||
1080 | chn->connect_env = GNUNET_MQ_msg_extra (req, relay_size + join_msg_size, | ||
1081 | GNUNET_MESSAGE_TYPE_PSYC_SLAVE_JOIN); | ||
1082 | req->channel_pub_key = *channel_pub_key; | ||
1083 | req->slave_key = *slave_key; | ||
1084 | req->origin = *origin; | ||
1085 | req->relay_count = htonl (relay_count); | ||
1086 | req->flags = htonl (flags); | ||
1087 | |||
1088 | if (0 < relay_size) | ||
1089 | GNUNET_memcpy (&req[1], relays, relay_size); | ||
1090 | |||
1091 | if (NULL != join_msg) | ||
1092 | GNUNET_memcpy ((char *) &req[1] + relay_size, join_msg, join_msg_size); | ||
1093 | |||
1094 | chn->cfg = cfg; | ||
1095 | chn->is_master = GNUNET_NO; | ||
1096 | chn->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS; | ||
1097 | |||
1098 | chn->op = GNUNET_OP_create (); | ||
1099 | chn->recv = GNUNET_PSYC_receive_create (message_cb, message_part_cb, cls); | ||
1100 | |||
1101 | slv->connect_cb = connect_cb; | ||
1102 | slv->join_dcsn_cb = join_decision_cb; | ||
1103 | slv->cb_cls = cls; | ||
1104 | |||
1105 | slave_connect (slv); | ||
1106 | return slv; | ||
1107 | } | ||
1108 | |||
1109 | |||
1110 | /** | ||
1111 | * Part a PSYC channel. | ||
1112 | * | ||
1113 | * Will terminate the connection to the PSYC service. Polite clients should | ||
1114 | * first explicitly send a part request (via GNUNET_PSYC_slave_transmit()). | ||
1115 | * | ||
1116 | * @param slave Slave handle. | ||
1117 | */ | ||
1118 | void | ||
1119 | GNUNET_PSYC_slave_part (struct GNUNET_PSYC_Slave *slv, | ||
1120 | int keep_active, | ||
1121 | GNUNET_ContinuationCallback part_cb, | ||
1122 | void *part_cls) | ||
1123 | { | ||
1124 | struct GNUNET_PSYC_Channel *chn = &slv->chn; | ||
1125 | struct GNUNET_MQ_Envelope *env; | ||
1126 | |||
1127 | chn->is_disconnecting = GNUNET_YES; | ||
1128 | chn->disconnect_cb = part_cb; | ||
1129 | chn->disconnect_cls = part_cls; | ||
1130 | env = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_PSYC_PART_REQUEST); | ||
1131 | GNUNET_MQ_send (chn->mq, env); | ||
1132 | } | ||
1133 | |||
1134 | |||
1135 | /** | ||
1136 | * Request a message to be sent to the channel master. | ||
1137 | * | ||
1138 | * @param slave Slave handle. | ||
1139 | * @param method_name Which (PSYC) method should be invoked (on host). | ||
1140 | * @param notify_mod Function to call to obtain modifiers. | ||
1141 | * @param notify_data Function to call to obtain fragments of the data. | ||
1142 | * @param notify_cls Closure for @a notify. | ||
1143 | * @param flags Flags for the message being transmitted. | ||
1144 | * | ||
1145 | * @return Transmission handle, NULL on error (i.e. more than one request | ||
1146 | * queued). | ||
1147 | */ | ||
1148 | struct GNUNET_PSYC_SlaveTransmitHandle * | ||
1149 | GNUNET_PSYC_slave_transmit (struct GNUNET_PSYC_Slave *slv, | ||
1150 | const char *method_name, | ||
1151 | GNUNET_PSYC_TransmitNotifyModifier notify_mod, | ||
1152 | GNUNET_PSYC_TransmitNotifyData notify_data, | ||
1153 | void *notify_cls, | ||
1154 | enum GNUNET_PSYC_SlaveTransmitFlags flags) | ||
1155 | |||
1156 | { | ||
1157 | if (GNUNET_OK | ||
1158 | == GNUNET_PSYC_transmit_message (slv->chn.tmit, method_name, NULL, | ||
1159 | notify_mod, notify_data, notify_cls, | ||
1160 | flags)) | ||
1161 | return (struct GNUNET_PSYC_SlaveTransmitHandle *) slv->chn.tmit; | ||
1162 | else | ||
1163 | return NULL; | ||
1164 | } | ||
1165 | |||
1166 | |||
1167 | /** | ||
1168 | * Resume transmission to the master. | ||
1169 | * | ||
1170 | * @param tmit Handle of the request that is being resumed. | ||
1171 | */ | ||
1172 | void | ||
1173 | GNUNET_PSYC_slave_transmit_resume (struct GNUNET_PSYC_SlaveTransmitHandle *tmit) | ||
1174 | { | ||
1175 | GNUNET_PSYC_transmit_resume ((struct GNUNET_PSYC_TransmitHandle *) tmit); | ||
1176 | } | ||
1177 | |||
1178 | |||
1179 | /** | ||
1180 | * Abort transmission request to master. | ||
1181 | * | ||
1182 | * @param tmit Handle of the request that is being aborted. | ||
1183 | */ | ||
1184 | void | ||
1185 | GNUNET_PSYC_slave_transmit_cancel (struct GNUNET_PSYC_SlaveTransmitHandle *tmit) | ||
1186 | { | ||
1187 | GNUNET_PSYC_transmit_cancel ((struct GNUNET_PSYC_TransmitHandle *) tmit); | ||
1188 | } | ||
1189 | |||
1190 | |||
1191 | /** | ||
1192 | * Convert @a slave to a @e channel handle to access the @e channel APIs. | ||
1193 | * | ||
1194 | * @param slv Slave handle. | ||
1195 | * | ||
1196 | * @return Channel handle, valid for as long as @a slave is valid. | ||
1197 | */ | ||
1198 | struct GNUNET_PSYC_Channel * | ||
1199 | GNUNET_PSYC_slave_get_channel (struct GNUNET_PSYC_Slave *slv) | ||
1200 | { | ||
1201 | return &slv->chn; | ||
1202 | } | ||
1203 | |||
1204 | |||
1205 | /** | ||
1206 | * Add a slave to the channel's membership list. | ||
1207 | * | ||
1208 | * Note that this will NOT generate any PSYC traffic, it will merely update the | ||
1209 | * local database to modify how we react to <em>membership test</em> queries. | ||
1210 | * The channel master still needs to explicitly transmit a @e join message to | ||
1211 | * notify other channel members and they then also must still call this function | ||
1212 | * in their respective methods handling the @e join message. This way, how @e | ||
1213 | * join and @e part operations are exactly implemented is still up to the | ||
1214 | * application; for example, there might be a @e part_all method to kick out | ||
1215 | * everyone. | ||
1216 | * | ||
1217 | * Note that channel slaves are explicitly trusted to execute such methods | ||
1218 | * correctly; not doing so correctly will result in either denying other slaves | ||
1219 | * access or offering access to channel data to non-members. | ||
1220 | * | ||
1221 | * @param chn | ||
1222 | * Channel handle. | ||
1223 | * @param slave_pub_key | ||
1224 | * Identity of channel slave to add. | ||
1225 | * @param announced_at | ||
1226 | * ID of the message that announced the membership change. | ||
1227 | * @param effective_since | ||
1228 | * Addition of slave is in effect since this message ID. | ||
1229 | * @param result_cb | ||
1230 | * Function to call with the result of the operation. | ||
1231 | * The @e result_code argument is #GNUNET_OK on success, or | ||
1232 | * #GNUNET_SYSERR on error. In case of an error, the @e data argument | ||
1233 | * can contain an optional error message. | ||
1234 | * @param cls | ||
1235 | * Closure for @a result_cb. | ||
1236 | */ | ||
1237 | void | ||
1238 | GNUNET_PSYC_channel_slave_add (struct GNUNET_PSYC_Channel *chn, | ||
1239 | const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_pub_key, | ||
1240 | uint64_t announced_at, | ||
1241 | uint64_t effective_since, | ||
1242 | GNUNET_ResultCallback result_cb, | ||
1243 | void *cls) | ||
1244 | { | ||
1245 | struct ChannelMembershipStoreRequest *req; | ||
1246 | struct GNUNET_MQ_Envelope * | ||
1247 | env = GNUNET_MQ_msg (req, GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_MEMBERSHIP_STORE); | ||
1248 | req->slave_pub_key = *slave_pub_key; | ||
1249 | req->announced_at = GNUNET_htonll (announced_at); | ||
1250 | req->effective_since = GNUNET_htonll (effective_since); | ||
1251 | req->did_join = GNUNET_YES; | ||
1252 | req->op_id = GNUNET_htonll (GNUNET_OP_add (chn->op, result_cb, cls, NULL)); | ||
1253 | |||
1254 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1255 | "GNUNET_PSYC_channel_slave_add, OP ID: %" PRIu64 "\n", | ||
1256 | GNUNET_ntohll (req->op_id)); | ||
1257 | GNUNET_MQ_send (chn->mq, env); | ||
1258 | } | ||
1259 | |||
1260 | |||
1261 | /** | ||
1262 | * Remove a slave from the channel's membership list. | ||
1263 | * | ||
1264 | * Note that this will NOT generate any PSYC traffic, it will merely update the | ||
1265 | * local database to modify how we react to <em>membership test</em> queries. | ||
1266 | * The channel master still needs to explicitly transmit a @e part message to | ||
1267 | * notify other channel members and they then also must still call this function | ||
1268 | * in their respective methods handling the @e part message. This way, how | ||
1269 | * @e join and @e part operations are exactly implemented is still up to the | ||
1270 | * application; for example, there might be a @e part_all message to kick out | ||
1271 | * everyone. | ||
1272 | * | ||
1273 | * Note that channel members are explicitly trusted to perform these | ||
1274 | * operations correctly; not doing so correctly will result in either | ||
1275 | * denying members access or offering access to channel data to | ||
1276 | * non-members. | ||
1277 | * | ||
1278 | * @param chn | ||
1279 | * Channel handle. | ||
1280 | * @param slave_pub_key | ||
1281 | * Identity of channel slave to remove. | ||
1282 | * @param announced_at | ||
1283 | * ID of the message that announced the membership change. | ||
1284 | * @param result_cb | ||
1285 | * Function to call with the result of the operation. | ||
1286 | * The @e result_code argument is #GNUNET_OK on success, or | ||
1287 | * #GNUNET_SYSERR on error. In case of an error, the @e data argument | ||
1288 | * can contain an optional error message. | ||
1289 | * @param cls | ||
1290 | * Closure for @a result_cb. | ||
1291 | */ | ||
1292 | void | ||
1293 | GNUNET_PSYC_channel_slave_remove (struct GNUNET_PSYC_Channel *chn, | ||
1294 | const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_pub_key, | ||
1295 | uint64_t announced_at, | ||
1296 | GNUNET_ResultCallback result_cb, | ||
1297 | void *cls) | ||
1298 | { | ||
1299 | struct ChannelMembershipStoreRequest *req; | ||
1300 | struct GNUNET_MQ_Envelope * | ||
1301 | env = GNUNET_MQ_msg (req, GNUNET_MESSAGE_TYPE_PSYC_CHANNEL_MEMBERSHIP_STORE); | ||
1302 | req->slave_pub_key = *slave_pub_key; | ||
1303 | req->announced_at = GNUNET_htonll (announced_at); | ||
1304 | req->did_join = GNUNET_NO; | ||
1305 | req->op_id = GNUNET_htonll (GNUNET_OP_add (chn->op, result_cb, cls, NULL)); | ||
1306 | |||
1307 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1308 | "GNUNET_PSYC_channel_slave_remove, OP ID: %" PRIu64 "\n", | ||
1309 | GNUNET_ntohll (req->op_id)); | ||
1310 | GNUNET_MQ_send (chn->mq, env); | ||
1311 | } | ||
1312 | |||
1313 | |||
1314 | static struct GNUNET_PSYC_HistoryRequest * | ||
1315 | channel_history_replay (struct GNUNET_PSYC_Channel *chn, | ||
1316 | uint64_t start_message_id, | ||
1317 | uint64_t end_message_id, | ||
1318 | uint64_t message_limit, | ||
1319 | const char *method_prefix, | ||
1320 | uint32_t flags, | ||
1321 | GNUNET_PSYC_MessageCallback message_cb, | ||
1322 | GNUNET_PSYC_MessagePartCallback message_part_cb, | ||
1323 | GNUNET_ResultCallback result_cb, | ||
1324 | void *cls) | ||
1325 | { | ||
1326 | struct GNUNET_PSYC_HistoryRequestMessage *req; | ||
1327 | struct GNUNET_PSYC_HistoryRequest *hist = GNUNET_malloc (sizeof (*hist)); | ||
1328 | hist->chn = chn; | ||
1329 | hist->recv = GNUNET_PSYC_receive_create (message_cb, message_part_cb, cls); | ||
1330 | hist->result_cb = result_cb; | ||
1331 | hist->cls = cls; | ||
1332 | hist->op_id = GNUNET_OP_add (chn->op, op_recv_history_result, hist, NULL); | ||
1333 | |||
1334 | GNUNET_assert (NULL != method_prefix); | ||
1335 | uint16_t method_size = strnlen (method_prefix, | ||
1336 | GNUNET_MAX_MESSAGE_SIZE | ||
1337 | - sizeof (*req)) + 1; | ||
1338 | GNUNET_assert ('\0' == method_prefix[method_size - 1]); | ||
1339 | |||
1340 | struct GNUNET_MQ_Envelope * | ||
1341 | env = GNUNET_MQ_msg_extra (req, method_size, | ||
1342 | GNUNET_MESSAGE_TYPE_PSYC_HISTORY_REPLAY); | ||
1343 | req->start_message_id = GNUNET_htonll (start_message_id); | ||
1344 | req->end_message_id = GNUNET_htonll (end_message_id); | ||
1345 | req->message_limit = GNUNET_htonll (message_limit); | ||
1346 | req->flags = htonl (flags); | ||
1347 | req->op_id = GNUNET_htonll (hist->op_id); | ||
1348 | |||
1349 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1350 | "channel_history_replay, OP ID: %" PRIu64 "\n", | ||
1351 | GNUNET_ntohll (req->op_id)); | ||
1352 | GNUNET_memcpy (&req[1], method_prefix, method_size); | ||
1353 | |||
1354 | GNUNET_MQ_send (chn->mq, env); | ||
1355 | return hist; | ||
1356 | } | ||
1357 | |||
1358 | |||
1359 | /** | ||
1360 | * Request to replay a part of the message history of the channel. | ||
1361 | * | ||
1362 | * Historic messages (but NOT the state at the time) will be replayed and given | ||
1363 | * to the normal method handlers with a #GNUNET_PSYC_MESSAGE_HISTORIC flag set. | ||
1364 | * | ||
1365 | * Messages are retrieved from the local PSYCstore if available, | ||
1366 | * otherwise requested from the network. | ||
1367 | * | ||
1368 | * @param channel | ||
1369 | * Which channel should be replayed? | ||
1370 | * @param start_message_id | ||
1371 | * Earliest interesting point in history. | ||
1372 | * @param end_message_id | ||
1373 | * Last (inclusive) interesting point in history. | ||
1374 | * @param method_prefix | ||
1375 | * Retrieve only messages with a matching method prefix. | ||
1376 | * @param flags | ||
1377 | * OR'ed enum GNUNET_PSYC_HistoryReplayFlags | ||
1378 | * @param result_cb | ||
1379 | * Function to call when the requested history has been fully replayed. | ||
1380 | * @param cls | ||
1381 | * Closure for the callbacks. | ||
1382 | * | ||
1383 | * @return Handle to cancel history replay operation. | ||
1384 | */ | ||
1385 | struct GNUNET_PSYC_HistoryRequest * | ||
1386 | GNUNET_PSYC_channel_history_replay (struct GNUNET_PSYC_Channel *chn, | ||
1387 | uint64_t start_message_id, | ||
1388 | uint64_t end_message_id, | ||
1389 | const char *method_prefix, | ||
1390 | uint32_t flags, | ||
1391 | GNUNET_PSYC_MessageCallback message_cb, | ||
1392 | GNUNET_PSYC_MessagePartCallback message_part_cb, | ||
1393 | GNUNET_ResultCallback result_cb, | ||
1394 | void *cls) | ||
1395 | { | ||
1396 | return channel_history_replay (chn, start_message_id, end_message_id, 0, | ||
1397 | method_prefix, flags, | ||
1398 | message_cb, message_part_cb, result_cb, cls); | ||
1399 | } | ||
1400 | |||
1401 | |||
1402 | /** | ||
1403 | * Request to replay the latest messages from the message history of the channel. | ||
1404 | * | ||
1405 | * Historic messages (but NOT the state at the time) will be replayed (given to | ||
1406 | * the normal method handlers) if available and if access is permitted. | ||
1407 | * | ||
1408 | * @param channel | ||
1409 | * Which channel should be replayed? | ||
1410 | * @param message_limit | ||
1411 | * Maximum number of messages to replay. | ||
1412 | * @param method_prefix | ||
1413 | * Retrieve only messages with a matching method prefix. | ||
1414 | * Use NULL or "" to retrieve all. | ||
1415 | * @param flags | ||
1416 | * OR'ed enum GNUNET_PSYC_HistoryReplayFlags | ||
1417 | * @param result_cb | ||
1418 | * Function to call when the requested history has been fully replayed. | ||
1419 | * @param cls | ||
1420 | * Closure for the callbacks. | ||
1421 | * | ||
1422 | * @return Handle to cancel history replay operation. | ||
1423 | */ | ||
1424 | struct GNUNET_PSYC_HistoryRequest * | ||
1425 | GNUNET_PSYC_channel_history_replay_latest (struct GNUNET_PSYC_Channel *chn, | ||
1426 | uint64_t message_limit, | ||
1427 | const char *method_prefix, | ||
1428 | uint32_t flags, | ||
1429 | GNUNET_PSYC_MessageCallback message_cb, | ||
1430 | GNUNET_PSYC_MessagePartCallback message_part_cb, | ||
1431 | GNUNET_ResultCallback result_cb, | ||
1432 | void *cls) | ||
1433 | { | ||
1434 | return channel_history_replay (chn, 0, 0, message_limit, method_prefix, flags, | ||
1435 | message_cb, message_part_cb, result_cb, cls); | ||
1436 | } | ||
1437 | |||
1438 | |||
1439 | void | ||
1440 | GNUNET_PSYC_channel_history_replay_cancel (struct GNUNET_PSYC_Channel *channel, | ||
1441 | struct GNUNET_PSYC_HistoryRequest *hist) | ||
1442 | { | ||
1443 | GNUNET_PSYC_receive_destroy (hist->recv); | ||
1444 | GNUNET_OP_remove (hist->chn->op, hist->op_id); | ||
1445 | GNUNET_free (hist); | ||
1446 | } | ||
1447 | |||
1448 | |||
1449 | /** | ||
1450 | * Retrieve the best matching channel state variable. | ||
1451 | * | ||
1452 | * If the requested variable name is not present in the state, the nearest | ||
1453 | * less-specific name is matched; for example, requesting "_a_b" will match "_a" | ||
1454 | * if "_a_b" does not exist. | ||
1455 | * | ||
1456 | * @param channel | ||
1457 | * Channel handle. | ||
1458 | * @param full_name | ||
1459 | * Full name of the requested variable. | ||
1460 | * The actual variable returned might have a shorter name. | ||
1461 | * @param var_cb | ||
1462 | * Function called once when a matching state variable is found. | ||
1463 | * Not called if there's no matching state variable. | ||
1464 | * @param result_cb | ||
1465 | * Function called after the operation finished. | ||
1466 | * (i.e. all state variables have been returned via @a state_cb) | ||
1467 | * @param cls | ||
1468 | * Closure for the callbacks. | ||
1469 | */ | ||
1470 | static struct GNUNET_PSYC_StateRequest * | ||
1471 | channel_state_get (struct GNUNET_PSYC_Channel *chn, | ||
1472 | uint16_t type, const char *name, | ||
1473 | GNUNET_PSYC_StateVarCallback var_cb, | ||
1474 | GNUNET_ResultCallback result_cb, void *cls) | ||
1475 | { | ||
1476 | struct StateRequest *req; | ||
1477 | struct GNUNET_PSYC_StateRequest *sr = GNUNET_malloc (sizeof (*sr)); | ||
1478 | sr->chn = chn; | ||
1479 | sr->var_cb = var_cb; | ||
1480 | sr->result_cb = result_cb; | ||
1481 | sr->cls = cls; | ||
1482 | sr->op_id = GNUNET_OP_add (chn->op, op_recv_state_result, sr, NULL); | ||
1483 | |||
1484 | GNUNET_assert (NULL != name); | ||
1485 | size_t name_size = strnlen (name, GNUNET_MAX_MESSAGE_SIZE | ||
1486 | - sizeof (*req)) + 1; | ||
1487 | struct GNUNET_MQ_Envelope * | ||
1488 | env = GNUNET_MQ_msg_extra (req, name_size, type); | ||
1489 | req->op_id = GNUNET_htonll (sr->op_id); | ||
1490 | |||
1491 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1492 | "channel_state_get, OP ID: %" PRIu64 "\n", | ||
1493 | GNUNET_ntohll (req->op_id)); | ||
1494 | |||
1495 | GNUNET_memcpy (&req[1], name, name_size); | ||
1496 | |||
1497 | GNUNET_MQ_send (chn->mq, env); | ||
1498 | return sr; | ||
1499 | } | ||
1500 | |||
1501 | |||
1502 | /** | ||
1503 | * Retrieve the best matching channel state variable. | ||
1504 | * | ||
1505 | * If the requested variable name is not present in the state, the nearest | ||
1506 | * less-specific name is matched; for example, requesting "_a_b" will match "_a" | ||
1507 | * if "_a_b" does not exist. | ||
1508 | * | ||
1509 | * @param channel | ||
1510 | * Channel handle. | ||
1511 | * @param full_name | ||
1512 | * Full name of the requested variable. | ||
1513 | * The actual variable returned might have a shorter name. | ||
1514 | * @param var_cb | ||
1515 | * Function called once when a matching state variable is found. | ||
1516 | * Not called if there's no matching state variable. | ||
1517 | * @param result_cb | ||
1518 | * Function called after the operation finished. | ||
1519 | * (i.e. all state variables have been returned via @a state_cb) | ||
1520 | * @param cls | ||
1521 | * Closure for the callbacks. | ||
1522 | */ | ||
1523 | struct GNUNET_PSYC_StateRequest * | ||
1524 | GNUNET_PSYC_channel_state_get (struct GNUNET_PSYC_Channel *chn, | ||
1525 | const char *full_name, | ||
1526 | GNUNET_PSYC_StateVarCallback var_cb, | ||
1527 | GNUNET_ResultCallback result_cb, | ||
1528 | void *cls) | ||
1529 | { | ||
1530 | return channel_state_get (chn, GNUNET_MESSAGE_TYPE_PSYC_STATE_GET, | ||
1531 | full_name, var_cb, result_cb, cls); | ||
1532 | |||
1533 | } | ||
1534 | |||
1535 | |||
1536 | /** | ||
1537 | * Return all channel state variables whose name matches a given prefix. | ||
1538 | * | ||
1539 | * A name matches if it starts with the given @a name_prefix, thus requesting | ||
1540 | * the empty prefix ("") will match all values; requesting "_a_b" will also | ||
1541 | * return values stored under "_a_b_c". | ||
1542 | * | ||
1543 | * The @a state_cb is invoked on all matching state variables asynchronously, as | ||
1544 | * the state is stored in and retrieved from the PSYCstore, | ||
1545 | * | ||
1546 | * @param channel | ||
1547 | * Channel handle. | ||
1548 | * @param name_prefix | ||
1549 | * Prefix of the state variable name to match. | ||
1550 | * @param var_cb | ||
1551 | * Function called once when a matching state variable is found. | ||
1552 | * Not called if there's no matching state variable. | ||
1553 | * @param result_cb | ||
1554 | * Function called after the operation finished. | ||
1555 | * (i.e. all state variables have been returned via @a state_cb) | ||
1556 | * @param cls | ||
1557 | * Closure for the callbacks. | ||
1558 | */ | ||
1559 | struct GNUNET_PSYC_StateRequest * | ||
1560 | GNUNET_PSYC_channel_state_get_prefix (struct GNUNET_PSYC_Channel *chn, | ||
1561 | const char *name_prefix, | ||
1562 | GNUNET_PSYC_StateVarCallback var_cb, | ||
1563 | GNUNET_ResultCallback result_cb, | ||
1564 | void *cls) | ||
1565 | { | ||
1566 | return channel_state_get (chn, GNUNET_MESSAGE_TYPE_PSYC_STATE_GET_PREFIX, | ||
1567 | name_prefix, var_cb, result_cb, cls); | ||
1568 | } | ||
1569 | |||
1570 | |||
1571 | /** | ||
1572 | * Cancel a state request operation. | ||
1573 | * | ||
1574 | * @param sr | ||
1575 | * Handle for the operation to cancel. | ||
1576 | */ | ||
1577 | void | ||
1578 | GNUNET_PSYC_channel_state_get_cancel (struct GNUNET_PSYC_StateRequest *sr) | ||
1579 | { | ||
1580 | GNUNET_OP_remove (sr->chn->op, sr->op_id); | ||
1581 | GNUNET_free (sr); | ||
1582 | } | ||
1583 | |||
1584 | /* end of psyc_api.c */ | ||
diff --git a/src/psyc/psyc_test_lib.h b/src/psyc/psyc_test_lib.h deleted file mode 100644 index 0ad991061..000000000 --- a/src/psyc/psyc_test_lib.h +++ /dev/null | |||
@@ -1,67 +0,0 @@ | |||
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 psyc/test_psyc_api_join.c | ||
23 | * @brief library for writing psyc tests | ||
24 | * @author xrs | ||
25 | */ | ||
26 | |||
27 | #define MAX_TESTBED_OPS 32 | ||
28 | |||
29 | struct pctx | ||
30 | { | ||
31 | int idx; | ||
32 | |||
33 | struct GNUNET_TESTBED_Peer *testbed_peer; | ||
34 | |||
35 | const struct GNUNET_PeerIdentity *peer_id; | ||
36 | |||
37 | const struct GNUNET_PeerIdentity *peer_id_master; | ||
38 | |||
39 | /** | ||
40 | * Used to simulate egos (not peerid) | ||
41 | */ | ||
42 | const struct GNUNET_CRYPTO_EcdsaPrivateKey *id_key; | ||
43 | |||
44 | const struct GNUNET_CRYPTO_EcdsaPublicKey *id_pub_key; | ||
45 | |||
46 | /** | ||
47 | * Used to store either GNUNET_PSYC_Master or GNUNET_PSYC_Slave handle | ||
48 | */ | ||
49 | void *psyc; | ||
50 | |||
51 | struct GNUNET_PSYC_Channel *channel; | ||
52 | |||
53 | const struct GNUNET_CRYPTO_EddsaPrivateKey *channel_key; | ||
54 | |||
55 | struct GNUNET_CRYPTO_EddsaPublicKey *channel_pub_key; | ||
56 | |||
57 | int test_ok; | ||
58 | }; | ||
59 | |||
60 | static struct GNUNET_SCHEDULER_Task *timeout_task_id; | ||
61 | |||
62 | static int result = GNUNET_SYSERR; | ||
63 | |||
64 | static struct GNUNET_TESTBED_Operation *op[MAX_TESTBED_OPS]; | ||
65 | |||
66 | static int op_cnt = 0; | ||
67 | |||
diff --git a/src/psyc/test_psyc.c b/src/psyc/test_psyc.c deleted file mode 100644 index b6e27bbab..000000000 --- a/src/psyc/test_psyc.c +++ /dev/null | |||
@@ -1,1018 +0,0 @@ | |||
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 psyc/test_psyc.c | ||
23 | * @brief Tests for the PSYC API. | ||
24 | * @author Gabor X Toth | ||
25 | * @author Christian Grothoff | ||
26 | */ | ||
27 | |||
28 | #include <inttypes.h> | ||
29 | |||
30 | #include "platform.h" | ||
31 | #include "gnunet_crypto_lib.h" | ||
32 | #include "gnunet_common.h" | ||
33 | #include "gnunet_util_lib.h" | ||
34 | #include "gnunet_testing_lib.h" | ||
35 | #include "gnunet_psyc_util_lib.h" | ||
36 | #include "gnunet_psyc_service.h" | ||
37 | |||
38 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) | ||
39 | |||
40 | /** | ||
41 | * Return value from 'main'. | ||
42 | */ | ||
43 | static int res; | ||
44 | |||
45 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
46 | |||
47 | static struct GNUNET_PeerIdentity this_peer; | ||
48 | |||
49 | /** | ||
50 | * Handle for task for timeout termination. | ||
51 | */ | ||
52 | static struct GNUNET_SCHEDULER_Task * end_badly_task; | ||
53 | |||
54 | static struct GNUNET_PSYC_Master *mst; | ||
55 | static struct GNUNET_PSYC_Slave *slv; | ||
56 | |||
57 | static struct GNUNET_PSYC_Channel *mst_chn, *slv_chn; | ||
58 | |||
59 | static struct GNUNET_CRYPTO_EddsaPrivateKey *channel_key; | ||
60 | static struct GNUNET_CRYPTO_EcdsaPrivateKey *slave_key; | ||
61 | |||
62 | static struct GNUNET_CRYPTO_EddsaPublicKey channel_pub_key; | ||
63 | static struct GNUNET_CRYPTO_EcdsaPublicKey slave_pub_key; | ||
64 | |||
65 | struct TransmitClosure | ||
66 | { | ||
67 | struct GNUNET_PSYC_MasterTransmitHandle *mst_tmit; | ||
68 | struct GNUNET_PSYC_SlaveTransmitHandle *slv_tmit; | ||
69 | struct GNUNET_PSYC_Environment *env; | ||
70 | struct GNUNET_PSYC_Modifier *mod; | ||
71 | char *data[16]; | ||
72 | const char *mod_value; | ||
73 | size_t mod_value_size; | ||
74 | uint8_t data_delay[16]; | ||
75 | uint8_t data_count; | ||
76 | uint8_t paused; | ||
77 | uint8_t n; | ||
78 | }; | ||
79 | |||
80 | static struct TransmitClosure *tmit; | ||
81 | |||
82 | static uint8_t join_req_count, end_count; | ||
83 | |||
84 | enum | ||
85 | { | ||
86 | TEST_NONE = 0, | ||
87 | TEST_MASTER_START = 1, | ||
88 | TEST_SLAVE_JOIN_REJECT = 2, | ||
89 | TEST_SLAVE_JOIN_ACCEPT = 3, | ||
90 | TEST_SLAVE_ADD = 4, | ||
91 | TEST_SLAVE_REMOVE = 5, | ||
92 | TEST_SLAVE_TRANSMIT = 6, | ||
93 | TEST_MASTER_TRANSMIT = 7, | ||
94 | TEST_MASTER_HISTORY_REPLAY_LATEST = 8, | ||
95 | TEST_SLAVE_HISTORY_REPLAY_LATEST = 9, | ||
96 | TEST_MASTER_HISTORY_REPLAY = 10, | ||
97 | TEST_SLAVE_HISTORY_REPLAY = 11, | ||
98 | TEST_MASTER_STATE_GET = 12, | ||
99 | TEST_SLAVE_STATE_GET = 13, | ||
100 | TEST_MASTER_STATE_GET_PREFIX = 14, | ||
101 | TEST_SLAVE_STATE_GET_PREFIX = 15, | ||
102 | } test; | ||
103 | |||
104 | |||
105 | static void | ||
106 | master_transmit (); | ||
107 | |||
108 | static void | ||
109 | master_history_replay_latest (); | ||
110 | |||
111 | |||
112 | static void | ||
113 | master_stopped (void *cls) | ||
114 | { | ||
115 | if (NULL != tmit) | ||
116 | { | ||
117 | GNUNET_PSYC_env_destroy (tmit->env); | ||
118 | GNUNET_free (tmit); | ||
119 | tmit = NULL; | ||
120 | } | ||
121 | GNUNET_SCHEDULER_shutdown (); | ||
122 | } | ||
123 | |||
124 | |||
125 | static void | ||
126 | slave_parted (void *cls) | ||
127 | { | ||
128 | if (NULL != mst) | ||
129 | { | ||
130 | GNUNET_PSYC_master_stop (mst, GNUNET_NO, &master_stopped, NULL); | ||
131 | mst = NULL; | ||
132 | } | ||
133 | else | ||
134 | master_stopped (NULL); | ||
135 | } | ||
136 | |||
137 | |||
138 | /** | ||
139 | * Clean up all resources used. | ||
140 | */ | ||
141 | static void | ||
142 | cleanup () | ||
143 | { | ||
144 | if (NULL != slv) | ||
145 | { | ||
146 | GNUNET_PSYC_slave_part (slv, GNUNET_NO, &slave_parted, NULL); | ||
147 | slv = NULL; | ||
148 | } | ||
149 | else | ||
150 | slave_parted (NULL); | ||
151 | } | ||
152 | |||
153 | |||
154 | /** | ||
155 | * Terminate the test case (failure). | ||
156 | * | ||
157 | * @param cls NULL | ||
158 | */ | ||
159 | static void | ||
160 | end_badly (void *cls) | ||
161 | { | ||
162 | res = 1; | ||
163 | cleanup (); | ||
164 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Test FAILED.\n"); | ||
165 | } | ||
166 | |||
167 | |||
168 | /** | ||
169 | * Terminate the test case (success). | ||
170 | * | ||
171 | * @param cls NULL | ||
172 | */ | ||
173 | static void | ||
174 | end_normally (void *cls) | ||
175 | { | ||
176 | res = 0; | ||
177 | cleanup (); | ||
178 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Test PASSED.\n"); | ||
179 | } | ||
180 | |||
181 | |||
182 | /** | ||
183 | * Finish the test case (successfully). | ||
184 | */ | ||
185 | static void | ||
186 | end () | ||
187 | { | ||
188 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Ending tests.\n"); | ||
189 | |||
190 | if (end_badly_task != NULL) | ||
191 | { | ||
192 | GNUNET_SCHEDULER_cancel (end_badly_task); | ||
193 | end_badly_task = NULL; | ||
194 | } | ||
195 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS, | ||
196 | &end_normally, NULL); | ||
197 | } | ||
198 | |||
199 | |||
200 | static void | ||
201 | master_message_cb (void *cls, const struct GNUNET_PSYC_MessageHeader *msg) | ||
202 | { | ||
203 | GNUNET_assert (NULL != msg); | ||
204 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
205 | "Test #%d: Master got PSYC message fragment of size %u " | ||
206 | "belonging to message ID %" PRIu64 " with flags %x\n", | ||
207 | test, ntohs (msg->header.size), | ||
208 | GNUNET_ntohll (msg->message_id), ntohl (msg->flags)); | ||
209 | // FIXME | ||
210 | } | ||
211 | |||
212 | |||
213 | static void | ||
214 | master_message_part_cb (void *cls, const struct GNUNET_PSYC_MessageHeader *msg, | ||
215 | const struct GNUNET_MessageHeader *pmsg) | ||
216 | { | ||
217 | GNUNET_assert (NULL != msg && NULL != pmsg); | ||
218 | |||
219 | uint64_t message_id = GNUNET_ntohll (msg->message_id); | ||
220 | uint32_t flags = ntohl (msg->flags); | ||
221 | |||
222 | uint16_t type = ntohs (pmsg->type); | ||
223 | uint16_t size = ntohs (pmsg->size); | ||
224 | |||
225 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
226 | "Test #%d: Master got message part of type %u and size %u " | ||
227 | "belonging to message ID %" PRIu64 " with flags %x\n", | ||
228 | test, type, size, message_id, flags); | ||
229 | |||
230 | switch (test) | ||
231 | { | ||
232 | case TEST_SLAVE_TRANSMIT: | ||
233 | if (GNUNET_PSYC_MESSAGE_REQUEST != flags) | ||
234 | { | ||
235 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
236 | "Test #%d: Unexpected request flags: %x" PRIu32 "\n", | ||
237 | test, flags); | ||
238 | GNUNET_assert (0); | ||
239 | return; | ||
240 | } | ||
241 | // FIXME: check rest of message | ||
242 | |||
243 | if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END == type) | ||
244 | master_transmit (); | ||
245 | break; | ||
246 | |||
247 | case TEST_MASTER_TRANSMIT: | ||
248 | if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END == type && 2 == ++end_count) | ||
249 | master_history_replay_latest (); | ||
250 | break; | ||
251 | |||
252 | case TEST_MASTER_HISTORY_REPLAY: | ||
253 | case TEST_MASTER_HISTORY_REPLAY_LATEST: | ||
254 | if (GNUNET_PSYC_MESSAGE_HISTORIC != flags) | ||
255 | { | ||
256 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
257 | "Test #%d: Unexpected flags for historic message: %x" PRIu32 "\n", | ||
258 | test, flags); | ||
259 | GNUNET_assert (0); | ||
260 | return; | ||
261 | } | ||
262 | break; | ||
263 | |||
264 | default: | ||
265 | GNUNET_assert (0); | ||
266 | } | ||
267 | } | ||
268 | |||
269 | |||
270 | static void | ||
271 | slave_message_cb (void *cls, const struct GNUNET_PSYC_MessageHeader *msg) | ||
272 | { | ||
273 | GNUNET_assert (NULL != msg); | ||
274 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
275 | "Test #%d: Slave got PSYC message fragment of size %u " | ||
276 | "belonging to message ID %" PRIu64 " with flags %x\n", | ||
277 | test, ntohs (msg->header.size), | ||
278 | GNUNET_ntohll (msg->message_id), ntohl (msg->flags)); | ||
279 | // FIXME | ||
280 | } | ||
281 | |||
282 | |||
283 | static void | ||
284 | slave_message_part_cb (void *cls, | ||
285 | const struct GNUNET_PSYC_MessageHeader *msg, | ||
286 | const struct GNUNET_MessageHeader *pmsg) | ||
287 | { | ||
288 | GNUNET_assert (NULL != msg && NULL != pmsg); | ||
289 | |||
290 | uint64_t message_id = GNUNET_ntohll (msg->message_id); | ||
291 | uint32_t flags = ntohl (msg->flags); | ||
292 | |||
293 | uint16_t type = ntohs (pmsg->type); | ||
294 | uint16_t size = ntohs (pmsg->size); | ||
295 | |||
296 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
297 | "Test #%d: Slave got message part of type %u and size %u " | ||
298 | "belonging to message ID %" PRIu64 " with flags %x\n", | ||
299 | test, type, size, message_id, flags); | ||
300 | |||
301 | switch (test) | ||
302 | { | ||
303 | case TEST_MASTER_TRANSMIT: | ||
304 | if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END == type && 2 == ++end_count) | ||
305 | master_history_replay_latest (); | ||
306 | break; | ||
307 | |||
308 | case TEST_SLAVE_HISTORY_REPLAY: | ||
309 | case TEST_SLAVE_HISTORY_REPLAY_LATEST: | ||
310 | if (GNUNET_PSYC_MESSAGE_HISTORIC != flags) | ||
311 | { | ||
312 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
313 | "Test #%d: Unexpected flags for historic message: %x" PRIu32 "\n", | ||
314 | test, flags); | ||
315 | GNUNET_assert (0); | ||
316 | return; | ||
317 | } | ||
318 | break; | ||
319 | |||
320 | default: | ||
321 | GNUNET_assert (0); | ||
322 | } | ||
323 | } | ||
324 | |||
325 | |||
326 | static void | ||
327 | state_get_var (void *cls, const struct GNUNET_MessageHeader *mod, | ||
328 | const char *name, const void *value, | ||
329 | uint32_t value_size, uint32_t full_value_size) | ||
330 | { | ||
331 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
332 | "Got state var: %s\n%.*s\n", | ||
333 | name, | ||
334 | (int) value_size, | ||
335 | (const char *) value); | ||
336 | } | ||
337 | |||
338 | |||
339 | /*** Slave state_get_prefix() ***/ | ||
340 | |||
341 | static void | ||
342 | slave_state_get_prefix_result (void *cls, int64_t result, | ||
343 | const void *err_msg, uint16_t err_msg_size) | ||
344 | { | ||
345 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
346 | "Test #%d: slave_state_get_prefix:\t%" PRId64 " (%.*s)\n", | ||
347 | test, result, | ||
348 | (int) err_msg_size, | ||
349 | (const char *) err_msg); | ||
350 | // FIXME: GNUNET_assert (2 == result); | ||
351 | end (); | ||
352 | } | ||
353 | |||
354 | |||
355 | static void | ||
356 | slave_state_get_prefix () | ||
357 | { | ||
358 | test = TEST_SLAVE_STATE_GET_PREFIX; | ||
359 | GNUNET_PSYC_channel_state_get_prefix (slv_chn, "_foo", state_get_var, | ||
360 | slave_state_get_prefix_result, NULL); | ||
361 | } | ||
362 | |||
363 | |||
364 | /*** Master state_get_prefix() ***/ | ||
365 | |||
366 | |||
367 | static void | ||
368 | master_state_get_prefix_result (void *cls, int64_t result, | ||
369 | const void *err_msg, uint16_t err_msg_size) | ||
370 | { | ||
371 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
372 | "Test #%d: master_state_get_prefix:\t%" PRId64 " (%s)\n", | ||
373 | test, result, (char *) err_msg); | ||
374 | // FIXME: GNUNET_assert (2 == result); | ||
375 | slave_state_get_prefix (); | ||
376 | } | ||
377 | |||
378 | |||
379 | static void | ||
380 | master_state_get_prefix () | ||
381 | { | ||
382 | test = TEST_MASTER_STATE_GET_PREFIX; | ||
383 | GNUNET_PSYC_channel_state_get_prefix (mst_chn, "_foo", state_get_var, | ||
384 | master_state_get_prefix_result, NULL); | ||
385 | } | ||
386 | |||
387 | |||
388 | /*** Slave state_get() ***/ | ||
389 | |||
390 | |||
391 | static void | ||
392 | slave_state_get_result (void *cls, int64_t result, | ||
393 | const void *err_msg, uint16_t err_msg_size) | ||
394 | { | ||
395 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
396 | "Test #%d: slave_state_get:\t%" PRId64 " (%.*s)\n", | ||
397 | test, result, err_msg_size, (char *) err_msg); | ||
398 | // FIXME: GNUNET_assert (2 == result); | ||
399 | master_state_get_prefix (); | ||
400 | } | ||
401 | |||
402 | |||
403 | static void | ||
404 | slave_state_get () | ||
405 | { | ||
406 | test = TEST_SLAVE_STATE_GET; | ||
407 | GNUNET_PSYC_channel_state_get (slv_chn, "_foo_bar_baz", state_get_var, | ||
408 | slave_state_get_result, NULL); | ||
409 | } | ||
410 | |||
411 | |||
412 | /*** Master state_get() ***/ | ||
413 | |||
414 | |||
415 | static void | ||
416 | master_state_get_result (void *cls, int64_t result, | ||
417 | const void *err_msg, uint16_t err_msg_size) | ||
418 | { | ||
419 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
420 | "Test #%d: master_state_get:\t%" PRId64 " (%.*s)\n", | ||
421 | test, result, err_msg_size, (char *) err_msg); | ||
422 | // FIXME: GNUNET_assert (1 == result); | ||
423 | slave_state_get (); | ||
424 | } | ||
425 | |||
426 | |||
427 | static void | ||
428 | master_state_get () | ||
429 | { | ||
430 | test = TEST_MASTER_STATE_GET; | ||
431 | GNUNET_PSYC_channel_state_get (mst_chn, "_foo_bar_baz", state_get_var, | ||
432 | master_state_get_result, NULL); | ||
433 | } | ||
434 | |||
435 | |||
436 | /*** Slave history_replay() ***/ | ||
437 | |||
438 | static void | ||
439 | slave_history_replay_result (void *cls, int64_t result, | ||
440 | const void *err_msg, uint16_t err_msg_size) | ||
441 | { | ||
442 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
443 | "Test #%d: slave_history_replay:\t%" PRId64 " (%.*s)\n", | ||
444 | test, result, | ||
445 | (int) err_msg_size, | ||
446 | (const char *) err_msg); | ||
447 | GNUNET_assert (9 == result); | ||
448 | |||
449 | master_state_get (); | ||
450 | } | ||
451 | |||
452 | |||
453 | static void | ||
454 | slave_history_replay () | ||
455 | { | ||
456 | test = TEST_SLAVE_HISTORY_REPLAY; | ||
457 | GNUNET_PSYC_channel_history_replay (slv_chn, 1, 1, "", | ||
458 | GNUNET_PSYC_HISTORY_REPLAY_LOCAL, | ||
459 | slave_message_cb, | ||
460 | slave_message_part_cb, | ||
461 | slave_history_replay_result, NULL); | ||
462 | } | ||
463 | |||
464 | |||
465 | /*** Master history_replay() ***/ | ||
466 | |||
467 | |||
468 | static void | ||
469 | master_history_replay_result (void *cls, int64_t result, | ||
470 | const void *err_msg, uint16_t err_msg_size) | ||
471 | { | ||
472 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
473 | "Test #%d: master_history_replay:\t%" PRId64 " (%.*s)\n", | ||
474 | test, result, | ||
475 | (int) err_msg_size, | ||
476 | (const char *) err_msg); | ||
477 | GNUNET_assert (9 == result); | ||
478 | |||
479 | slave_history_replay (); | ||
480 | } | ||
481 | |||
482 | |||
483 | static void | ||
484 | master_history_replay () | ||
485 | { | ||
486 | test = TEST_MASTER_HISTORY_REPLAY; | ||
487 | GNUNET_PSYC_channel_history_replay (mst_chn, 1, 1, "", | ||
488 | GNUNET_PSYC_HISTORY_REPLAY_LOCAL, | ||
489 | master_message_cb, | ||
490 | master_message_part_cb, | ||
491 | master_history_replay_result, NULL); | ||
492 | } | ||
493 | |||
494 | |||
495 | /*** Slave history_replay_latest() ***/ | ||
496 | |||
497 | |||
498 | static void | ||
499 | slave_history_replay_latest_result (void *cls, int64_t result, | ||
500 | const void *err_msg, uint16_t err_msg_size) | ||
501 | { | ||
502 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
503 | "Test #%d: slave_history_replay_latest:\t%" PRId64 " (%.*s)\n", | ||
504 | test, result, | ||
505 | (int) err_msg_size, | ||
506 | (const char *) err_msg); | ||
507 | GNUNET_assert (9 == result); | ||
508 | |||
509 | master_history_replay (); | ||
510 | } | ||
511 | |||
512 | |||
513 | static void | ||
514 | slave_history_replay_latest () | ||
515 | { | ||
516 | test = TEST_SLAVE_HISTORY_REPLAY_LATEST; | ||
517 | GNUNET_PSYC_channel_history_replay_latest (slv_chn, 1, "", | ||
518 | GNUNET_PSYC_HISTORY_REPLAY_LOCAL, | ||
519 | &slave_message_cb, | ||
520 | &slave_message_part_cb, | ||
521 | &slave_history_replay_latest_result, | ||
522 | NULL); | ||
523 | } | ||
524 | |||
525 | |||
526 | /*** Master history_replay_latest() ***/ | ||
527 | |||
528 | |||
529 | static void | ||
530 | master_history_replay_latest_result (void *cls, int64_t result, | ||
531 | const void *err_msg, uint16_t err_msg_size) | ||
532 | { | ||
533 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
534 | "Test #%d: master_history_replay_latest:\t%" PRId64 " (%.*s)\n", | ||
535 | test, result, err_msg_size, (char *) err_msg); | ||
536 | GNUNET_assert (9 == result); | ||
537 | |||
538 | slave_history_replay_latest (); | ||
539 | } | ||
540 | |||
541 | |||
542 | static void | ||
543 | master_history_replay_latest () | ||
544 | { | ||
545 | test = TEST_MASTER_HISTORY_REPLAY_LATEST; | ||
546 | GNUNET_PSYC_channel_history_replay_latest (mst_chn, 1, "", | ||
547 | GNUNET_PSYC_HISTORY_REPLAY_LOCAL, | ||
548 | &master_message_cb, | ||
549 | &master_message_part_cb, | ||
550 | &master_history_replay_latest_result, | ||
551 | NULL); | ||
552 | } | ||
553 | |||
554 | |||
555 | static void | ||
556 | transmit_resume (void *cls) | ||
557 | { | ||
558 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
559 | "Test #%d: Transmission resumed.\n", test); | ||
560 | struct TransmitClosure *tmit = cls; | ||
561 | if (NULL != tmit->mst_tmit) | ||
562 | GNUNET_PSYC_master_transmit_resume (tmit->mst_tmit); | ||
563 | else | ||
564 | GNUNET_PSYC_slave_transmit_resume (tmit->slv_tmit); | ||
565 | } | ||
566 | |||
567 | |||
568 | static int | ||
569 | tmit_notify_data (void *cls, uint16_t *data_size, void *data) | ||
570 | { | ||
571 | struct TransmitClosure *tmit = cls; | ||
572 | if (0 == tmit->data_count) | ||
573 | { | ||
574 | *data_size = 0; | ||
575 | return GNUNET_YES; | ||
576 | } | ||
577 | |||
578 | uint16_t size = strlen (tmit->data[tmit->n]); | ||
579 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
580 | "Test #%d: Transmit notify data: %u bytes available, " | ||
581 | "processing fragment %u/%u (size %u).\n", | ||
582 | test, *data_size, tmit->n + 1, tmit->data_count, size); | ||
583 | if (*data_size < size) | ||
584 | { | ||
585 | *data_size = 0; | ||
586 | GNUNET_assert (0); | ||
587 | return GNUNET_SYSERR; | ||
588 | } | ||
589 | |||
590 | if (GNUNET_YES != tmit->paused && 0 < tmit->data_delay[tmit->n]) | ||
591 | { | ||
592 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
593 | "Test #%d: Transmission paused.\n", test); | ||
594 | tmit->paused = GNUNET_YES; | ||
595 | GNUNET_SCHEDULER_add_delayed ( | ||
596 | GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, | ||
597 | tmit->data_delay[tmit->n]), | ||
598 | &transmit_resume, tmit); | ||
599 | *data_size = 0; | ||
600 | return GNUNET_NO; | ||
601 | } | ||
602 | tmit->paused = GNUNET_NO; | ||
603 | |||
604 | *data_size = size; | ||
605 | GNUNET_memcpy (data, tmit->data[tmit->n], size); | ||
606 | |||
607 | return ++tmit->n < tmit->data_count ? GNUNET_NO : GNUNET_YES; | ||
608 | } | ||
609 | |||
610 | |||
611 | static int | ||
612 | tmit_notify_mod (void *cls, uint16_t *data_size, void *data, uint8_t *oper, | ||
613 | uint32_t *full_value_size) | ||
614 | { | ||
615 | struct TransmitClosure *tmit = cls; | ||
616 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
617 | "Test #%d: Transmit notify modifier: %u bytes available, " | ||
618 | "%u modifiers left to process.\n", | ||
619 | test, *data_size, (unsigned int) GNUNET_PSYC_env_get_count (tmit->env)); | ||
620 | |||
621 | uint16_t name_size = 0; | ||
622 | size_t value_size = 0; | ||
623 | const char *value = NULL; | ||
624 | |||
625 | if (NULL != oper && NULL != tmit->mod) | ||
626 | { /* New modifier */ | ||
627 | tmit->mod = tmit->mod->next; | ||
628 | if (NULL == tmit->mod) | ||
629 | { /* No more modifiers, continue with data */ | ||
630 | *data_size = 0; | ||
631 | return GNUNET_YES; | ||
632 | } | ||
633 | |||
634 | GNUNET_assert (tmit->mod->value_size < UINT32_MAX); | ||
635 | *full_value_size = tmit->mod->value_size; | ||
636 | *oper = tmit->mod->oper; | ||
637 | name_size = strlen (tmit->mod->name); | ||
638 | |||
639 | if (name_size + 1 + tmit->mod->value_size <= *data_size) | ||
640 | { | ||
641 | *data_size = name_size + 1 + tmit->mod->value_size; | ||
642 | } | ||
643 | else | ||
644 | { | ||
645 | tmit->mod_value_size = tmit->mod->value_size; | ||
646 | value_size = *data_size - name_size - 1; | ||
647 | tmit->mod_value_size -= value_size; | ||
648 | tmit->mod_value = tmit->mod->value + value_size; | ||
649 | } | ||
650 | |||
651 | GNUNET_memcpy (data, tmit->mod->name, name_size); | ||
652 | ((char *)data)[name_size] = '\0'; | ||
653 | GNUNET_memcpy ((char *)data + name_size + 1, tmit->mod->value, value_size); | ||
654 | } | ||
655 | else if (NULL != tmit->mod_value && 0 < tmit->mod_value_size) | ||
656 | { /* Modifier continuation */ | ||
657 | value = tmit->mod_value; | ||
658 | if (tmit->mod_value_size <= *data_size) | ||
659 | { | ||
660 | value_size = tmit->mod_value_size; | ||
661 | tmit->mod_value = NULL; | ||
662 | } | ||
663 | else | ||
664 | { | ||
665 | value_size = *data_size; | ||
666 | tmit->mod_value += value_size; | ||
667 | } | ||
668 | tmit->mod_value_size -= value_size; | ||
669 | |||
670 | if (*data_size < value_size) | ||
671 | { | ||
672 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
673 | "value larger than buffer: %u < %zu\n", | ||
674 | *data_size, value_size); | ||
675 | *data_size = 0; | ||
676 | return GNUNET_NO; | ||
677 | } | ||
678 | |||
679 | *data_size = value_size; | ||
680 | GNUNET_memcpy (data, value, value_size); | ||
681 | } | ||
682 | |||
683 | return GNUNET_NO; | ||
684 | } | ||
685 | |||
686 | |||
687 | static void | ||
688 | slave_join (); | ||
689 | |||
690 | |||
691 | static void | ||
692 | slave_transmit () | ||
693 | { | ||
694 | test = TEST_SLAVE_TRANSMIT; | ||
695 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
696 | "Test #%d: Slave sending request to master.\n", test); | ||
697 | |||
698 | tmit = GNUNET_new (struct TransmitClosure); | ||
699 | tmit->env = GNUNET_PSYC_env_create (); | ||
700 | GNUNET_PSYC_env_add (tmit->env, GNUNET_PSYC_OP_ASSIGN, | ||
701 | "_abc", "abc def", 7); | ||
702 | GNUNET_PSYC_env_add (tmit->env, GNUNET_PSYC_OP_ASSIGN, | ||
703 | "_abc_def", "abc def ghi", 11); | ||
704 | tmit->mod = GNUNET_PSYC_env_head (tmit->env); | ||
705 | tmit->n = 0; | ||
706 | tmit->data[0] = "slave test"; | ||
707 | tmit->data_count = 1; | ||
708 | tmit->slv_tmit | ||
709 | = GNUNET_PSYC_slave_transmit (slv, "_request_test", &tmit_notify_mod, | ||
710 | &tmit_notify_data, tmit, | ||
711 | GNUNET_PSYC_SLAVE_TRANSMIT_NONE); | ||
712 | } | ||
713 | |||
714 | |||
715 | static void | ||
716 | slave_remove_cb (void *cls, int64_t result, | ||
717 | const void *err_msg, uint16_t err_msg_size) | ||
718 | { | ||
719 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
720 | "Test #%d: slave_remove:\t%" PRId64 " (%.*s)\n", | ||
721 | test, result, err_msg_size, (char *) err_msg); | ||
722 | |||
723 | slave_transmit (); | ||
724 | } | ||
725 | |||
726 | |||
727 | static void | ||
728 | slave_remove () | ||
729 | { | ||
730 | test = TEST_SLAVE_REMOVE; | ||
731 | struct GNUNET_PSYC_Channel *chn = GNUNET_PSYC_master_get_channel (mst); | ||
732 | GNUNET_PSYC_channel_slave_remove (chn, &slave_pub_key, 2, | ||
733 | &slave_remove_cb, chn); | ||
734 | } | ||
735 | |||
736 | |||
737 | static void | ||
738 | slave_add_cb (void *cls, int64_t result, | ||
739 | const void *err_msg, uint16_t err_msg_size) | ||
740 | { | ||
741 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
742 | "Test #%d: slave_add:\t%" PRId64 " (%.*s)\n", | ||
743 | test, result, err_msg_size, (char *) err_msg); | ||
744 | slave_remove (); | ||
745 | } | ||
746 | |||
747 | |||
748 | static void | ||
749 | slave_add () | ||
750 | { | ||
751 | test = TEST_SLAVE_ADD; | ||
752 | struct GNUNET_PSYC_Channel *chn = GNUNET_PSYC_master_get_channel (mst); | ||
753 | GNUNET_PSYC_channel_slave_add (chn, &slave_pub_key, 2, 2, &slave_add_cb, chn); | ||
754 | } | ||
755 | |||
756 | |||
757 | static void | ||
758 | schedule_second_slave_join (void *cls) | ||
759 | { | ||
760 | slave_join (TEST_SLAVE_JOIN_ACCEPT); | ||
761 | } | ||
762 | |||
763 | |||
764 | static void | ||
765 | first_slave_parted (void *cls) | ||
766 | { | ||
767 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "First slave parted.\n"); | ||
768 | GNUNET_SCHEDULER_add_now (&schedule_second_slave_join, NULL); | ||
769 | } | ||
770 | |||
771 | |||
772 | static void | ||
773 | schedule_first_slave_part (void *cls) | ||
774 | { | ||
775 | GNUNET_PSYC_slave_part (slv, GNUNET_NO, &first_slave_parted, NULL); | ||
776 | } | ||
777 | |||
778 | |||
779 | static void | ||
780 | join_decision_cb (void *cls, | ||
781 | const struct GNUNET_PSYC_JoinDecisionMessage *dcsn, | ||
782 | int is_admitted, | ||
783 | const struct GNUNET_PSYC_Message *join_msg) | ||
784 | { | ||
785 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
786 | "Test #%d: Slave got join decision: %d\n", test, is_admitted); | ||
787 | |||
788 | switch (test) | ||
789 | { | ||
790 | case TEST_SLAVE_JOIN_REJECT: | ||
791 | GNUNET_assert (0 == is_admitted); | ||
792 | GNUNET_assert (1 == join_req_count); | ||
793 | GNUNET_SCHEDULER_add_now (&schedule_first_slave_part, NULL); | ||
794 | break; | ||
795 | |||
796 | case TEST_SLAVE_JOIN_ACCEPT: | ||
797 | GNUNET_assert (1 == is_admitted); | ||
798 | GNUNET_assert (2 == join_req_count); | ||
799 | slave_add (); | ||
800 | break; | ||
801 | |||
802 | default: | ||
803 | GNUNET_break (0); | ||
804 | } | ||
805 | } | ||
806 | |||
807 | |||
808 | static void | ||
809 | join_request_cb (void *cls, | ||
810 | const struct GNUNET_PSYC_JoinRequestMessage *req, | ||
811 | const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, | ||
812 | const struct GNUNET_PSYC_Message *join_msg, | ||
813 | struct GNUNET_PSYC_JoinHandle *jh) | ||
814 | { | ||
815 | struct GNUNET_HashCode slave_key_hash; | ||
816 | GNUNET_CRYPTO_hash (slave_key, sizeof (*slave_key), &slave_key_hash); | ||
817 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
818 | "Test #%d: Got join request #%u from %s.\n", | ||
819 | test, join_req_count, GNUNET_h2s (&slave_key_hash)); | ||
820 | |||
821 | /* Reject first request */ | ||
822 | int is_admitted = (0 < join_req_count++) ? GNUNET_YES : GNUNET_NO; | ||
823 | GNUNET_PSYC_join_decision (jh, is_admitted, 0, NULL, NULL); | ||
824 | } | ||
825 | |||
826 | |||
827 | static void | ||
828 | slave_connect_cb (void *cls, int result, uint64_t max_message_id) | ||
829 | { | ||
830 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
831 | "Test #%d: Slave connected: %d, max_message_id: %" PRIu64 "\n", | ||
832 | test, result, max_message_id); | ||
833 | GNUNET_assert (TEST_SLAVE_JOIN_REJECT == test || TEST_SLAVE_JOIN_ACCEPT == test); | ||
834 | GNUNET_assert (GNUNET_OK == result || GNUNET_NO == result); | ||
835 | } | ||
836 | |||
837 | |||
838 | static void | ||
839 | slave_join (int t) | ||
840 | { | ||
841 | test = t; | ||
842 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
843 | "Test #%d: Joining slave.\n", t); | ||
844 | |||
845 | struct GNUNET_PeerIdentity origin = this_peer; | ||
846 | struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create (); | ||
847 | GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_ASSIGN, | ||
848 | "_foo", "bar baz", 7); | ||
849 | GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_ASSIGN, | ||
850 | "_foo_bar", "foo bar baz", 11); | ||
851 | struct GNUNET_PSYC_Message * | ||
852 | join_msg = GNUNET_PSYC_message_create ("_request_join", env, "some data", 9); | ||
853 | |||
854 | slv = GNUNET_PSYC_slave_join (cfg, | ||
855 | &channel_pub_key, | ||
856 | slave_key, | ||
857 | GNUNET_PSYC_SLAVE_JOIN_NONE, | ||
858 | &origin, | ||
859 | 0, | ||
860 | NULL, | ||
861 | &slave_message_cb, | ||
862 | &slave_message_part_cb, | ||
863 | &slave_connect_cb, | ||
864 | &join_decision_cb, | ||
865 | NULL, | ||
866 | join_msg); | ||
867 | GNUNET_free (join_msg); | ||
868 | slv_chn = GNUNET_PSYC_slave_get_channel (slv); | ||
869 | GNUNET_PSYC_env_destroy (env); | ||
870 | } | ||
871 | |||
872 | |||
873 | static void | ||
874 | master_transmit () | ||
875 | { | ||
876 | test = TEST_MASTER_TRANSMIT; | ||
877 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
878 | "Test #%d: Master sending message to all.\n", test); | ||
879 | end_count = 0; | ||
880 | |||
881 | uint32_t i, j; | ||
882 | |||
883 | char *name_max = "_test_max"; | ||
884 | uint8_t name_max_size = sizeof ("_test_max"); | ||
885 | char *val_max = GNUNET_malloc (GNUNET_PSYC_MODIFIER_MAX_PAYLOAD); | ||
886 | for (i = 0; i < GNUNET_PSYC_MODIFIER_MAX_PAYLOAD; i++) | ||
887 | val_max[i] = (0 == i % 10000) ? '0' + i / 10000 : '.'; | ||
888 | |||
889 | char *name_cont = "_test_cont"; | ||
890 | uint8_t name_cont_size = sizeof ("_test_cont"); | ||
891 | char *val_cont = GNUNET_malloc (GNUNET_PSYC_MODIFIER_MAX_PAYLOAD | ||
892 | + GNUNET_PSYC_MOD_CONT_MAX_PAYLOAD); | ||
893 | for (i = 0; i < GNUNET_PSYC_MODIFIER_MAX_PAYLOAD - name_cont_size; i++) | ||
894 | val_cont[i] = (0 == i % 10000) ? '0' + i / 10000 : ':'; | ||
895 | for (j = 0; j < GNUNET_PSYC_MOD_CONT_MAX_PAYLOAD; j++, i++) | ||
896 | val_cont[i] = (0 == j % 10000) ? '0' + j / 10000 : '!'; | ||
897 | |||
898 | tmit = GNUNET_new (struct TransmitClosure); | ||
899 | tmit->env = GNUNET_PSYC_env_create (); | ||
900 | GNUNET_PSYC_env_add (tmit->env, GNUNET_PSYC_OP_ASSIGN, | ||
901 | "_foo", "bar baz", 7); | ||
902 | GNUNET_PSYC_env_add (tmit->env, GNUNET_PSYC_OP_ASSIGN, | ||
903 | name_max, val_max, | ||
904 | GNUNET_PSYC_MODIFIER_MAX_PAYLOAD | ||
905 | - name_max_size); | ||
906 | GNUNET_PSYC_env_add (tmit->env, GNUNET_PSYC_OP_ASSIGN, | ||
907 | "_foo_bar", "foo bar baz", 11); | ||
908 | GNUNET_PSYC_env_add (tmit->env, GNUNET_PSYC_OP_ASSIGN, | ||
909 | name_cont, val_cont, | ||
910 | GNUNET_PSYC_MODIFIER_MAX_PAYLOAD - name_cont_size | ||
911 | + GNUNET_PSYC_MOD_CONT_MAX_PAYLOAD); | ||
912 | tmit->mod = GNUNET_PSYC_env_head (tmit->env); | ||
913 | tmit->data[0] = "foo"; | ||
914 | tmit->data[1] = GNUNET_malloc (GNUNET_PSYC_DATA_MAX_PAYLOAD + 1); | ||
915 | for (i = 0; i < GNUNET_PSYC_DATA_MAX_PAYLOAD; i++) | ||
916 | tmit->data[1][i] = (0 == i % 10000) ? '0' + i / 10000 : '_'; | ||
917 | tmit->data[2] = "foo bar"; | ||
918 | tmit->data[3] = "foo bar baz"; | ||
919 | tmit->data_delay[1] = 3; | ||
920 | tmit->data_count = 4; | ||
921 | tmit->mst_tmit | ||
922 | = GNUNET_PSYC_master_transmit (mst, "_notice_test", &tmit_notify_mod, | ||
923 | &tmit_notify_data, tmit, | ||
924 | GNUNET_PSYC_MASTER_TRANSMIT_INC_GROUP_GEN); | ||
925 | } | ||
926 | |||
927 | |||
928 | static void | ||
929 | master_start_cb (void *cls, int result, uint64_t max_message_id) | ||
930 | { | ||
931 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
932 | "Test #%d: Master started: %d, max_message_id: %" PRIu64 "\n", | ||
933 | test, result, max_message_id); | ||
934 | GNUNET_assert (TEST_MASTER_START == test); | ||
935 | GNUNET_assert (GNUNET_OK == result || GNUNET_NO == result); | ||
936 | slave_join (TEST_SLAVE_JOIN_REJECT); | ||
937 | } | ||
938 | |||
939 | |||
940 | static void | ||
941 | master_start () | ||
942 | { | ||
943 | test = TEST_MASTER_START; | ||
944 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
945 | "Test #%d: Starting master.\n", test); | ||
946 | mst = GNUNET_PSYC_master_start (cfg, channel_key, GNUNET_PSYC_CHANNEL_PRIVATE, | ||
947 | &master_start_cb, &join_request_cb, | ||
948 | &master_message_cb, &master_message_part_cb, | ||
949 | NULL); | ||
950 | mst_chn = GNUNET_PSYC_master_get_channel (mst); | ||
951 | } | ||
952 | |||
953 | |||
954 | static void | ||
955 | schedule_master_start (void *cls) | ||
956 | { | ||
957 | master_start (); | ||
958 | } | ||
959 | |||
960 | |||
961 | /** | ||
962 | * Main function of the test, run from scheduler. | ||
963 | * | ||
964 | * @param cls NULL | ||
965 | * @param cfg configuration we use (also to connect to PSYC service) | ||
966 | * @param peer handle to access more of the peer (not used) | ||
967 | */ | ||
968 | static void | ||
969 | #if DEBUG_TEST_PSYC | ||
970 | run (void *cls, char *const *args, const char *cfgfile, | ||
971 | const struct GNUNET_CONFIGURATION_Handle *c) | ||
972 | #else | ||
973 | run (void *cls, | ||
974 | const struct GNUNET_CONFIGURATION_Handle *c, | ||
975 | struct GNUNET_TESTING_Peer *peer) | ||
976 | #endif | ||
977 | { | ||
978 | cfg = c; | ||
979 | end_badly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL); | ||
980 | |||
981 | GNUNET_CRYPTO_get_peer_identity (cfg, &this_peer); | ||
982 | |||
983 | channel_key = GNUNET_CRYPTO_eddsa_key_create (); | ||
984 | slave_key = GNUNET_CRYPTO_ecdsa_key_create (); | ||
985 | |||
986 | GNUNET_CRYPTO_eddsa_key_get_public (channel_key, &channel_pub_key); | ||
987 | GNUNET_CRYPTO_ecdsa_key_get_public (slave_key, &slave_pub_key); | ||
988 | |||
989 | #if DEBUG_TEST_PSYC | ||
990 | master_start (); | ||
991 | #else | ||
992 | /* Allow some time for the services to initialize. */ | ||
993 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, | ||
994 | &schedule_master_start, NULL); | ||
995 | #endif | ||
996 | } | ||
997 | |||
998 | |||
999 | int | ||
1000 | main (int argc, char *argv[]) | ||
1001 | { | ||
1002 | res = 1; | ||
1003 | #if DEBUG_TEST_PSYC | ||
1004 | const struct GNUNET_GETOPT_CommandLineOption opts[] = { | ||
1005 | GNUNET_GETOPT_OPTION_END | ||
1006 | }; | ||
1007 | if (GNUNET_OK != GNUNET_PROGRAM_run (argc, argv, "test-psyc", | ||
1008 | "test-psyc [options]", | ||
1009 | opts, &run, NULL)) | ||
1010 | return 1; | ||
1011 | #else | ||
1012 | if (0 != GNUNET_TESTING_peer_run ("test-psyc", "test_psyc.conf", &run, NULL)) | ||
1013 | return 1; | ||
1014 | #endif | ||
1015 | return res; | ||
1016 | } | ||
1017 | |||
1018 | /* end of test_psyc.c */ | ||
diff --git a/src/psyc/test_psyc.conf b/src/psyc/test_psyc.conf deleted file mode 100644 index 6ff031f0d..000000000 --- a/src/psyc/test_psyc.conf +++ /dev/null | |||
@@ -1,28 +0,0 @@ | |||
1 | @INLINE@ ../../contrib/conf/gnunet/no_forcestart.conf | ||
2 | |||
3 | [testbed] | ||
4 | HOSTNAME = localhost | ||
5 | OVERLAY_TOPOLOGY = STAR | ||
6 | |||
7 | [peerinfo] | ||
8 | # Option to disable all disk IO; only useful for testbed runs | ||
9 | # (large-scale experiments); disables persistence of HELLOs! | ||
10 | NO_IO = YES | ||
11 | |||
12 | [cadet] | ||
13 | ID_ANNOUNCE_TIME = 5 s | ||
14 | |||
15 | [nat] | ||
16 | ENABLE_UPNP = NO | ||
17 | |||
18 | [psyc] | ||
19 | IMMEDIATE_START = YES | ||
20 | START_ON_DEMAND = YES | ||
21 | |||
22 | [multicast] | ||
23 | IMMEDIATE_START = YES | ||
24 | START_ON_DEMAND = YES | ||
25 | |||
26 | [psycstore] | ||
27 | IMMEDIATE_START = YES | ||
28 | START_ON_DEMAND = YES | ||
diff --git a/src/psyc/test_psyc2.c b/src/psyc/test_psyc2.c deleted file mode 100644 index c6e7237ab..000000000 --- a/src/psyc/test_psyc2.c +++ /dev/null | |||
@@ -1,284 +0,0 @@ | |||
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 psyc/test_psyc2.c | ||
23 | * @brief Testbed test for the PSYC API. | ||
24 | * @author xrs | ||
25 | */ | ||
26 | |||
27 | #include "platform.h" | ||
28 | #include "gnunet_crypto_lib.h" | ||
29 | #include "gnunet_common.h" | ||
30 | #include "gnunet_util_lib.h" | ||
31 | #include "gnunet_testbed_service.h" | ||
32 | #include "gnunet_psyc_util_lib.h" | ||
33 | #include "gnunet_psyc_service.h" | ||
34 | |||
35 | #define PEERS_REQUESTED 2 | ||
36 | |||
37 | static int result; | ||
38 | |||
39 | static struct GNUNET_SCHEDULER_Task *timeout_tid; | ||
40 | static struct pctx **pctx; | ||
41 | |||
42 | static struct GNUNET_CRYPTO_EddsaPrivateKey *channel_key; | ||
43 | static struct GNUNET_CRYPTO_EddsaPublicKey channel_pub_key; | ||
44 | |||
45 | static struct GNUNET_CRYPTO_EcdsaPrivateKey *slave_key; | ||
46 | static struct GNUNET_CRYPTO_EcdsaPublicKey slave_pub_key; | ||
47 | |||
48 | /** | ||
49 | * Task To perform tests | ||
50 | */ | ||
51 | static struct GNUNET_SCHEDULER_Task *test_task; | ||
52 | |||
53 | /** | ||
54 | * Peer id couter | ||
55 | */ | ||
56 | static unsigned int pids; | ||
57 | |||
58 | struct pctx | ||
59 | { | ||
60 | int idx; | ||
61 | struct GNUNET_TESTBED_Peer *peer; | ||
62 | const struct GNUNET_PeerIdentity *id; | ||
63 | |||
64 | struct GNUNET_TESTBED_Operation *op; | ||
65 | |||
66 | /** | ||
67 | * psyc service handle | ||
68 | */ | ||
69 | void *psyc; | ||
70 | struct GNUNET_PSYC_Master *mst; | ||
71 | struct GNUNET_PSYC_Slave *slv; | ||
72 | |||
73 | /** | ||
74 | * result for test on peer | ||
75 | */ | ||
76 | int test_ok; | ||
77 | }; | ||
78 | |||
79 | static void | ||
80 | shutdown_task (void *cls) | ||
81 | { | ||
82 | if (NULL != pctx) | ||
83 | { | ||
84 | if (NULL != pctx[0]->mst) | ||
85 | GNUNET_PSYC_master_stop (pctx[0]->mst, GNUNET_NO, NULL, NULL); | ||
86 | |||
87 | for (int i=0; i < PEERS_REQUESTED; i++) | ||
88 | { | ||
89 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Operation done.\n"); | ||
90 | GNUNET_TESTBED_operation_done (pctx[i]->op); | ||
91 | GNUNET_free_non_null (pctx[i]); | ||
92 | } | ||
93 | GNUNET_free (pctx); | ||
94 | } | ||
95 | |||
96 | if (NULL != timeout_tid) | ||
97 | GNUNET_SCHEDULER_cancel (timeout_tid); | ||
98 | } | ||
99 | |||
100 | static void | ||
101 | timeout_task (void *cls) | ||
102 | { | ||
103 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Timeout!\n"); | ||
104 | result = GNUNET_SYSERR; | ||
105 | GNUNET_SCHEDULER_shutdown (); | ||
106 | } | ||
107 | |||
108 | static void | ||
109 | start_test (void *cls) | ||
110 | { | ||
111 | } | ||
112 | |||
113 | static void | ||
114 | pinfo_cb (void *cls, | ||
115 | struct GNUNET_TESTBED_Operation *operation, | ||
116 | const struct GNUNET_TESTBED_PeerInformation *pinfo, | ||
117 | const char *emsg) | ||
118 | { | ||
119 | struct pctx *pc = (struct pctx*) cls; | ||
120 | |||
121 | pc->id = pinfo->result.id; | ||
122 | |||
123 | pids++; | ||
124 | if (pids < (PEERS_REQUESTED - 1)) | ||
125 | return; | ||
126 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got all IDs, starting test\n"); | ||
127 | test_task = GNUNET_SCHEDULER_add_now (&start_test, NULL); | ||
128 | } | ||
129 | |||
130 | static void | ||
131 | mst_start_cb () | ||
132 | { | ||
133 | } | ||
134 | |||
135 | static void | ||
136 | join_request_cb () | ||
137 | { | ||
138 | } | ||
139 | |||
140 | static void | ||
141 | mst_message_cb () | ||
142 | { | ||
143 | } | ||
144 | |||
145 | static void | ||
146 | mst_message_part_cb () | ||
147 | { | ||
148 | } | ||
149 | |||
150 | static void | ||
151 | slv_message_cb () | ||
152 | { | ||
153 | } | ||
154 | |||
155 | static void | ||
156 | slv_message_part_cb () | ||
157 | { | ||
158 | } | ||
159 | |||
160 | static void | ||
161 | slv_connect_cb () | ||
162 | { | ||
163 | } | ||
164 | |||
165 | static void | ||
166 | join_decision_cb () | ||
167 | { | ||
168 | } | ||
169 | |||
170 | static void * | ||
171 | psyc_ca (void *cls, | ||
172 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
173 | { | ||
174 | struct GNUNET_PSYC_Message *join_msg = NULL; | ||
175 | struct pctx *pc = (struct pctx *) cls; | ||
176 | |||
177 | if (0 == pc->idx) | ||
178 | { | ||
179 | pc->mst = GNUNET_PSYC_master_start (cfg, channel_key, | ||
180 | GNUNET_PSYC_CHANNEL_PRIVATE, | ||
181 | &mst_start_cb, &join_request_cb, | ||
182 | &mst_message_cb, &mst_message_part_cb, | ||
183 | NULL); | ||
184 | return pc->mst; | ||
185 | } | ||
186 | |||
187 | pc->slv = GNUNET_PSYC_slave_join (cfg, &channel_pub_key, slave_key, | ||
188 | GNUNET_PSYC_SLAVE_JOIN_NONE, | ||
189 | &pid, 0, NULL, &slv_message_cb, | ||
190 | &slv_message_part_cb, | ||
191 | &slv_connect_cb, &join_decision_cb, | ||
192 | NULL, join_msg); | ||
193 | return pc->slv; | ||
194 | } | ||
195 | |||
196 | static void | ||
197 | psyc_da (void *cls, | ||
198 | void *op_result) | ||
199 | { | ||
200 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Disconnected from service.\n"); | ||
201 | } | ||
202 | |||
203 | static void | ||
204 | service_connect (void *cls, | ||
205 | struct GNUNET_TESTBED_Operation *op, | ||
206 | void *ca_result, | ||
207 | const char *emsg) | ||
208 | { | ||
209 | struct pctx *pc = (struct pctx *) cls; | ||
210 | |||
211 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
212 | "Connected to service\n"); | ||
213 | |||
214 | GNUNET_assert (NULL != ca_result); | ||
215 | |||
216 | // FIXME: we need a simple service handle to connect to the service, then | ||
217 | // get peer information and AFTER that make PSYC ops. Compare to CADET. | ||
218 | pc->psyc = ca_result; | ||
219 | |||
220 | GNUNET_TESTBED_peer_get_information (pc->peer, | ||
221 | GNUNET_TESTBED_PIT_IDENTITY, | ||
222 | pinfo_cb, pc); | ||
223 | } | ||
224 | |||
225 | static void | ||
226 | testbed_master (void *cls, | ||
227 | struct GNUNET_TESTBED_RunHandle *h, | ||
228 | unsigned int num_peers, | ||
229 | struct GNUNET_TESTBED_Peer **p, | ||
230 | unsigned int links_succeeded, | ||
231 | unsigned int links_failed) | ||
232 | { | ||
233 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connected to testbed_master()\n"); | ||
234 | |||
235 | // Create ctx for peers | ||
236 | pctx = GNUNET_new_array (PEERS_REQUESTED, struct pctx*); | ||
237 | for (int i = 0; i<PEERS_REQUESTED; i++) | ||
238 | { | ||
239 | pctx[i] = GNUNET_new (struct pctx); | ||
240 | pctx[i]->idx = i; | ||
241 | pctx[i]->peer = p[i]; | ||
242 | pctx[i]->id = NULL; | ||
243 | pctx[i]->mst = NULL; | ||
244 | pctx[i]->op = NULL; | ||
245 | pctx[i]->test_ok = GNUNET_NO; | ||
246 | } | ||
247 | |||
248 | channel_key = GNUNET_CRYPTO_eddsa_key_create (); | ||
249 | slave_key = GNUNET_CRYPTO_ecdsa_key_create (); | ||
250 | |||
251 | GNUNET_CRYPTO_eddsa_key_get_public (channel_key, &channel_pub_key); | ||
252 | GNUNET_CRYPTO_ecdsa_key_get_public (slave_key, &slave_pub_key); | ||
253 | |||
254 | pctx[0]->op = | ||
255 | GNUNET_TESTBED_service_connect (NULL, p[0], "psyc", service_connect, | ||
256 | pctx[0], psyc_ca, psyc_da, pctx[0]); | ||
257 | |||
258 | GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); | ||
259 | |||
260 | timeout_tid = | ||
261 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 5), | ||
262 | &timeout_task, NULL); | ||
263 | } | ||
264 | |||
265 | int | ||
266 | main (int argc, char *argv[]) | ||
267 | { | ||
268 | int ret; | ||
269 | |||
270 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "test\n"); | ||
271 | |||
272 | result = GNUNET_SYSERR; | ||
273 | |||
274 | ret = GNUNET_TESTBED_test_run ("test-psyc2", "test_psyc.conf", | ||
275 | PEERS_REQUESTED, 0LL, NULL, NULL, | ||
276 | testbed_master, NULL); | ||
277 | |||
278 | if ((GNUNET_OK != ret) || (GNUNET_OK != result)) | ||
279 | return 1; | ||
280 | |||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | /* end of test-psyc2.c */ | ||
diff --git a/src/psyc/test_psyc_api_join.c b/src/psyc/test_psyc_api_join.c deleted file mode 100644 index 419fa11c1..000000000 --- a/src/psyc/test_psyc_api_join.c +++ /dev/null | |||
@@ -1,282 +0,0 @@ | |||
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 psyc/test_psyc_api_join.c | ||
23 | * @brief Testbed test for the PSYC API. | ||
24 | * @author xrs | ||
25 | */ | ||
26 | |||
27 | /** | ||
28 | * Lessons Learned: | ||
29 | * - define topology in config | ||
30 | * - psyc slave join needs part to end (same with master) | ||
31 | * - GNUNET_SCHEDULER_add_delayed return value will outdate at call time | ||
32 | * - main can not contain GNUNET_log() | ||
33 | */ | ||
34 | |||
35 | #include "platform.h" | ||
36 | #include "gnunet_crypto_lib.h" | ||
37 | #include "gnunet_common.h" | ||
38 | #include "gnunet_util_lib.h" | ||
39 | #include "gnunet_testbed_service.h" | ||
40 | #include "gnunet_psyc_util_lib.h" | ||
41 | #include "gnunet_psyc_service.h" | ||
42 | #include "psyc_test_lib.h" | ||
43 | |||
44 | static struct pctx PEERS[2]; | ||
45 | |||
46 | static int pids; | ||
47 | |||
48 | |||
49 | static void | ||
50 | shutdown_task (void *cls) | ||
51 | { | ||
52 | if (NULL != timeout_task_id) { | ||
53 | GNUNET_SCHEDULER_cancel (timeout_task_id); | ||
54 | timeout_task_id = NULL; | ||
55 | } | ||
56 | |||
57 | for (int i=0;i<2;i++) { | ||
58 | GNUNET_free (PEERS[i].channel_pub_key); | ||
59 | |||
60 | if (NULL != PEERS[i].psyc) | ||
61 | { | ||
62 | if (0 == i) | ||
63 | GNUNET_PSYC_master_stop (PEERS[i].psyc, GNUNET_NO, NULL, NULL); | ||
64 | else | ||
65 | GNUNET_PSYC_slave_part (PEERS[i].psyc, GNUNET_NO, NULL, NULL); | ||
66 | } | ||
67 | } | ||
68 | |||
69 | for (int i=0;i<MAX_TESTBED_OPS;i++) | ||
70 | if (NULL != op[i]) | ||
71 | GNUNET_TESTBED_operation_done (op[i]); | ||
72 | |||
73 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shut down!\n"); | ||
74 | } | ||
75 | |||
76 | static void | ||
77 | timeout_task (void *cls) | ||
78 | { | ||
79 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Timeout!\n"); | ||
80 | |||
81 | timeout_task_id = NULL; | ||
82 | |||
83 | result = GNUNET_SYSERR; | ||
84 | GNUNET_SCHEDULER_shutdown (); | ||
85 | } | ||
86 | |||
87 | static void | ||
88 | join_decision_cb (void *cls, | ||
89 | const struct GNUNET_PSYC_JoinDecisionMessage *dcsn, | ||
90 | int is_admitted, | ||
91 | const struct GNUNET_PSYC_Message *join_msg) | ||
92 | { | ||
93 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
94 | "slave: got join decision: %s\n", | ||
95 | (GNUNET_YES == is_admitted) ? "admitted":"rejected"); | ||
96 | |||
97 | result = (GNUNET_YES == is_admitted) ? GNUNET_OK : GNUNET_SYSERR; | ||
98 | |||
99 | GNUNET_SCHEDULER_shutdown (); | ||
100 | } | ||
101 | |||
102 | static void | ||
103 | join_request_cb (void *cls, | ||
104 | const struct GNUNET_PSYC_JoinRequestMessage *req, | ||
105 | const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, | ||
106 | const struct GNUNET_PSYC_Message *join_msg, | ||
107 | struct GNUNET_PSYC_JoinHandle *jh) | ||
108 | { | ||
109 | struct GNUNET_HashCode slave_key_hash; | ||
110 | |||
111 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "master: got join request.\n"); | ||
112 | |||
113 | GNUNET_CRYPTO_hash (slave_key, sizeof (*slave_key), &slave_key_hash); | ||
114 | |||
115 | GNUNET_PSYC_join_decision (jh, GNUNET_YES, 0, NULL, NULL); | ||
116 | } | ||
117 | |||
118 | static void | ||
119 | psyc_da () | ||
120 | { | ||
121 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "disconnect form PSYC service\n"); | ||
122 | } | ||
123 | |||
124 | static void * | ||
125 | psyc_ca (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
126 | { | ||
127 | struct pctx *peer = (struct pctx*) cls; | ||
128 | |||
129 | // Case: master role | ||
130 | if (0 == peer->idx) { | ||
131 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connecting to PSYC as master ...\n"); | ||
132 | |||
133 | peer->psyc = (struct GNUNET_PSYC_Master *) | ||
134 | GNUNET_PSYC_master_start (cfg, | ||
135 | peer->channel_key, | ||
136 | GNUNET_PSYC_CHANNEL_PRIVATE, | ||
137 | NULL, | ||
138 | join_request_cb, | ||
139 | NULL, | ||
140 | NULL, | ||
141 | cls); | ||
142 | return peer->psyc; | ||
143 | } | ||
144 | |||
145 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connecting to PSYC as slave ...\n"); | ||
146 | |||
147 | struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create (); | ||
148 | GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_ASSIGN, "_foo", "bar baz", 7); | ||
149 | GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_ASSIGN, "_foo_bar", "foo bar baz", 11); | ||
150 | |||
151 | struct GNUNET_PSYC_Message * | ||
152 | join_msg = GNUNET_PSYC_message_create ("_request_join", env, "some data", 40); | ||
153 | |||
154 | peer->psyc = (struct GNUNET_PSYC_Slave *) | ||
155 | GNUNET_PSYC_slave_join (cfg, | ||
156 | peer->channel_pub_key, | ||
157 | peer->id_key, | ||
158 | GNUNET_PSYC_SLAVE_JOIN_NONE, | ||
159 | peer->peer_id_master, | ||
160 | 0, | ||
161 | NULL, | ||
162 | NULL, | ||
163 | NULL, | ||
164 | NULL, | ||
165 | join_decision_cb, | ||
166 | cls, | ||
167 | join_msg); | ||
168 | |||
169 | GNUNET_free (join_msg); | ||
170 | peer->channel = GNUNET_PSYC_slave_get_channel (peer->psyc); | ||
171 | GNUNET_PSYC_env_destroy (env); | ||
172 | |||
173 | return peer->psyc; | ||
174 | } | ||
175 | |||
176 | static void | ||
177 | service_connect (void *cls, | ||
178 | struct GNUNET_TESTBED_Operation *op, | ||
179 | void *ca_result, | ||
180 | const char *emsg) | ||
181 | { | ||
182 | GNUNET_assert (NULL != ca_result); | ||
183 | |||
184 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connected to the service\n"); | ||
185 | } | ||
186 | |||
187 | static void | ||
188 | connect_to_services (void *cls) | ||
189 | { | ||
190 | for (int i = 0; i < 2; i++) | ||
191 | { | ||
192 | PEERS[i].peer_id_master = PEERS[0].peer_id; | ||
193 | |||
194 | op[op_cnt++] = | ||
195 | GNUNET_TESTBED_service_connect (NULL, PEERS[i].testbed_peer, "psyc", | ||
196 | &service_connect, &PEERS[i], &psyc_ca, | ||
197 | &psyc_da, &PEERS[i]); | ||
198 | } | ||
199 | } | ||
200 | |||
201 | static void | ||
202 | pinfo_cb (void *cls, | ||
203 | struct GNUNET_TESTBED_Operation *operation, | ||
204 | const struct GNUNET_TESTBED_PeerInformation *pinfo, | ||
205 | const char *emsg) | ||
206 | { | ||
207 | struct pctx *peer = (struct pctx*) cls; | ||
208 | |||
209 | peer->peer_id = pinfo->result.id; | ||
210 | |||
211 | pids++; | ||
212 | if (pids < 2) | ||
213 | return; | ||
214 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Got all IDs, starting test\n"); | ||
215 | |||
216 | GNUNET_SCHEDULER_add_now (&connect_to_services, NULL); | ||
217 | } | ||
218 | |||
219 | static void | ||
220 | testbed_master (void *cls, | ||
221 | struct GNUNET_TESTBED_RunHandle *h, | ||
222 | unsigned int num_peers, | ||
223 | struct GNUNET_TESTBED_Peer **p, | ||
224 | unsigned int links_succeeded, | ||
225 | unsigned int links_failed) | ||
226 | { | ||
227 | struct GNUNET_CRYPTO_EddsaPrivateKey *channel_key = NULL; | ||
228 | |||
229 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Connected to testbed_master\n"); | ||
230 | |||
231 | // Set up shutdown logic | ||
232 | GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); | ||
233 | timeout_task_id = | ||
234 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 15), | ||
235 | &timeout_task, NULL); | ||
236 | GNUNET_assert (NULL != timeout_task_id); | ||
237 | |||
238 | // Set up channel key | ||
239 | channel_key = GNUNET_CRYPTO_eddsa_key_create (); | ||
240 | GNUNET_assert (NULL != channel_key); | ||
241 | |||
242 | // Set up information contexts for peers | ||
243 | for (int i=0 ; i < 2 ; i++) | ||
244 | { | ||
245 | PEERS[i].idx = i; | ||
246 | PEERS[i].testbed_peer = p[i]; | ||
247 | |||
248 | // Create "egos" | ||
249 | PEERS[i].id_key = GNUNET_CRYPTO_ecdsa_key_create (); | ||
250 | |||
251 | // Set up channel keys shared by master and slave | ||
252 | PEERS[i].channel_key = channel_key; | ||
253 | |||
254 | PEERS[i].channel_pub_key = | ||
255 | GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_EddsaPublicKey)); | ||
256 | // Get public key | ||
257 | GNUNET_CRYPTO_eddsa_key_get_public (PEERS[i].channel_key, | ||
258 | PEERS[i].channel_pub_key); | ||
259 | // Get peerinfo | ||
260 | op[op_cnt++] = | ||
261 | GNUNET_TESTBED_peer_get_information (p[i], | ||
262 | GNUNET_TESTBED_PIT_IDENTITY, | ||
263 | pinfo_cb, &PEERS[i]); | ||
264 | } | ||
265 | } | ||
266 | |||
267 | int | ||
268 | main (int argc, char *argv[]) | ||
269 | { | ||
270 | int ret; | ||
271 | |||
272 | ret = GNUNET_TESTBED_test_run ("test_psyc_api_join", "test_psyc.conf", | ||
273 | 2, 0LL, NULL, NULL, | ||
274 | &testbed_master, NULL); | ||
275 | |||
276 | if ( (GNUNET_OK != ret) || (GNUNET_OK != result) ) | ||
277 | return 1; | ||
278 | |||
279 | return 0; | ||
280 | } | ||
281 | |||
282 | /* end of test_psyc_api_join.c */ | ||
diff --git a/src/psycstore/.gitignore b/src/psycstore/.gitignore deleted file mode 100644 index 5ec783202..000000000 --- a/src/psycstore/.gitignore +++ /dev/null | |||
@@ -1,5 +0,0 @@ | |||
1 | gnunet-service-psycstore | ||
2 | test_plugin_psycstore_mysql | ||
3 | test_plugin_psycstore_sqlite | ||
4 | test_plugin_psycstore_postgres | ||
5 | test_psycstore | ||
diff --git a/src/psycstore/Makefile.am b/src/psycstore/Makefile.am deleted file mode 100644 index 557bb42b5..000000000 --- a/src/psycstore/Makefile.am +++ /dev/null | |||
@@ -1,155 +0,0 @@ | |||
1 | # This Makefile.am is in the public domain | ||
2 | AM_CPPFLAGS = -I$(top_srcdir)/src/include | ||
3 | |||
4 | plugindir = $(libdir)/gnunet | ||
5 | |||
6 | pkgcfgdir= $(pkgdatadir)/config.d/ | ||
7 | |||
8 | libexecdir= $(pkglibdir)/libexec/ | ||
9 | |||
10 | pkgcfg_DATA = \ | ||
11 | psycstore.conf | ||
12 | |||
13 | |||
14 | if MINGW | ||
15 | WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols | ||
16 | endif | ||
17 | |||
18 | if USE_COVERAGE | ||
19 | AM_CFLAGS = --coverage -O0 | ||
20 | XLIB = -lgcov | ||
21 | endif | ||
22 | |||
23 | if HAVE_MYSQL | ||
24 | MYSQL_PLUGIN = libgnunet_plugin_psycstore_mysql.la | ||
25 | if HAVE_TESTING | ||
26 | MYSQL_TESTS = test_plugin_psycstore_mysql | ||
27 | endif | ||
28 | endif | ||
29 | |||
30 | if HAVE_POSTGRESQL | ||
31 | POSTGRES_PLUGIN = libgnunet_plugin_psycstore_postgres.la | ||
32 | if HAVE_TESTING | ||
33 | POSTGRES_TESTS = test_plugin_psycstore_postgres | ||
34 | endif | ||
35 | endif | ||
36 | |||
37 | if HAVE_SQLITE | ||
38 | SQLITE_PLUGIN = libgnunet_plugin_psycstore_sqlite.la | ||
39 | if HAVE_TESTING | ||
40 | SQLITE_TESTS = test_plugin_psycstore_sqlite | ||
41 | endif | ||
42 | endif | ||
43 | |||
44 | lib_LTLIBRARIES = libgnunetpsycstore.la | ||
45 | |||
46 | libgnunetpsycstore_la_SOURCES = \ | ||
47 | psycstore_api.c \ | ||
48 | psycstore.h | ||
49 | libgnunetpsycstore_la_LIBADD = \ | ||
50 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
51 | $(GN_LIBINTL) $(XLIB) | ||
52 | libgnunetpsycstore_la_LDFLAGS = \ | ||
53 | $(GN_LIB_LDFLAGS) $(WINFLAGS) \ | ||
54 | -version-info 0:0:0 | ||
55 | |||
56 | bin_PROGRAMS = | ||
57 | |||
58 | libexec_PROGRAMS = \ | ||
59 | gnunet-service-psycstore | ||
60 | |||
61 | gnunet_service_psycstore_SOURCES = \ | ||
62 | gnunet-service-psycstore.c | ||
63 | gnunet_service_psycstore_LDADD = \ | ||
64 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ | ||
65 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
66 | $(top_builddir)/src/psycutil/libgnunetpsycutil.la \ | ||
67 | $(GN_LIBINTL) | ||
68 | |||
69 | plugin_LTLIBRARIES = \ | ||
70 | $(SQLITE_PLUGIN) \ | ||
71 | $(MYSQL_PLUGIN) \ | ||
72 | $(POSTGRES_PLUGIN) | ||
73 | |||
74 | |||
75 | libgnunet_plugin_psycstore_mysql_la_SOURCES = \ | ||
76 | plugin_psycstore_mysql.c | ||
77 | libgnunet_plugin_psycstore_mysql_la_LIBADD = \ | ||
78 | libgnunetpsycstore.la \ | ||
79 | $(top_builddir)/src/my/libgnunetmy.la \ | ||
80 | $(top_builddir)/src/mysql/libgnunetmysql.la \ | ||
81 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ | ||
82 | $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) \ | ||
83 | $(LTLIBINTL) | ||
84 | libgnunet_plugin_psycstore_mysql_la_LDFLAGS = \ | ||
85 | $(GN_PLUGIN_LDFLAGS) | ||
86 | |||
87 | libgnunet_plugin_psycstore_postgres_la_SOURCES = \ | ||
88 | plugin_psycstore_postgres.c | ||
89 | libgnunet_plugin_psycstore_postgres_la_LIBADD = \ | ||
90 | libgnunetpsycstore.la \ | ||
91 | $(top_builddir)/src/pq/libgnunetpq.la \ | ||
92 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ | ||
93 | $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lpq \ | ||
94 | $(LTLIBINTL) | ||
95 | libgnunet_plugin_psycstore_postgres_la_LDFLAGS = \ | ||
96 | $(GN_PLUGIN_LDFLAGS) $(POSTGRESQL_LDFLAGS) | ||
97 | libgnunet_plugin_psycstore_postgres_la_CPPFLAGS = \ | ||
98 | $(POSTGRESQL_CPPFLAGS) $(AM_CPPFLAGS) | ||
99 | |||
100 | |||
101 | libgnunet_plugin_psycstore_sqlite_la_SOURCES = \ | ||
102 | plugin_psycstore_sqlite.c | ||
103 | libgnunet_plugin_psycstore_sqlite_la_LIBADD = \ | ||
104 | libgnunetpsycstore.la \ | ||
105 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ | ||
106 | $(top_builddir)/src/util/libgnunetutil.la $(XLIBS) -lsqlite3 \ | ||
107 | $(LTLIBINTL) | ||
108 | libgnunet_plugin_psycstore_sqlite_la_LDFLAGS = \ | ||
109 | $(GN_PLUGIN_LDFLAGS) | ||
110 | |||
111 | |||
112 | if HAVE_SQLITE | ||
113 | if HAVE_TESTING | ||
114 | check_PROGRAMS = \ | ||
115 | $(SQLITE_TESTS) \ | ||
116 | $(MYSQL_TESTS) \ | ||
117 | $(POSTGRES_TESTS) \ | ||
118 | test_psycstore | ||
119 | endif | ||
120 | endif | ||
121 | |||
122 | if ENABLE_TEST_RUN | ||
123 | AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME; | ||
124 | TESTS = $(check_PROGRAMS) | ||
125 | endif | ||
126 | |||
127 | test_psycstore_SOURCES = \ | ||
128 | test_psycstore.c | ||
129 | test_psycstore_LDADD = \ | ||
130 | libgnunetpsycstore.la \ | ||
131 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
132 | $(top_builddir)/src/util/libgnunetutil.la | ||
133 | |||
134 | EXTRA_DIST = \ | ||
135 | test_psycstore.conf | ||
136 | |||
137 | |||
138 | test_plugin_psycstore_sqlite_SOURCES = \ | ||
139 | test_plugin_psycstore.c | ||
140 | test_plugin_psycstore_sqlite_LDADD = \ | ||
141 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
142 | $(top_builddir)/src/util/libgnunetutil.la | ||
143 | |||
144 | test_plugin_psycstore_mysql_SOURCES = \ | ||
145 | test_plugin_psycstore.c | ||
146 | test_plugin_psycstore_mysql_LDADD = \ | ||
147 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
148 | $(top_builddir)/src/util/libgnunetutil.la | ||
149 | |||
150 | test_plugin_psycstore_postgres_SOURCES = \ | ||
151 | test_plugin_psycstore.c | ||
152 | test_plugin_psycstore_postgres_LDADD = \ | ||
153 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
154 | $(top_builddir)/src/util/libgnunetutil.la | ||
155 | |||
diff --git a/src/psycstore/gnunet-service-psycstore.c b/src/psycstore/gnunet-service-psycstore.c deleted file mode 100644 index 9aebd3e97..000000000 --- a/src/psycstore/gnunet-service-psycstore.c +++ /dev/null | |||
@@ -1,1049 +0,0 @@ | |||
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 psycstore/gnunet-service-psycstore.c | ||
23 | * @brief PSYCstore service | ||
24 | * @author Gabor X Toth | ||
25 | * @author Christian Grothoff | ||
26 | */ | ||
27 | |||
28 | #include <inttypes.h> | ||
29 | |||
30 | #include "platform.h" | ||
31 | #include "gnunet_util_lib.h" | ||
32 | #include "gnunet_constants.h" | ||
33 | #include "gnunet_protocols.h" | ||
34 | #include "gnunet_statistics_service.h" | ||
35 | #include "gnunet_psyc_util_lib.h" | ||
36 | #include "gnunet_psycstore_service.h" | ||
37 | #include "gnunet_psycstore_plugin.h" | ||
38 | #include "psycstore.h" | ||
39 | |||
40 | |||
41 | /** | ||
42 | * Handle to our current configuration. | ||
43 | */ | ||
44 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
45 | |||
46 | /** | ||
47 | * Service handle. | ||
48 | */ | ||
49 | static struct GNUNET_SERVICE_Handle *service; | ||
50 | |||
51 | /** | ||
52 | * Handle to the statistics service. | ||
53 | */ | ||
54 | static struct GNUNET_STATISTICS_Handle *stats; | ||
55 | |||
56 | /** | ||
57 | * Database handle | ||
58 | */ | ||
59 | static struct GNUNET_PSYCSTORE_PluginFunctions *db; | ||
60 | |||
61 | /** | ||
62 | * Name of the database plugin | ||
63 | */ | ||
64 | static char *db_lib_name; | ||
65 | |||
66 | |||
67 | /** | ||
68 | * Task run during shutdown. | ||
69 | * | ||
70 | * @param cls unused | ||
71 | */ | ||
72 | static void | ||
73 | shutdown_task (void *cls) | ||
74 | { | ||
75 | if (NULL != stats) | ||
76 | { | ||
77 | GNUNET_STATISTICS_destroy (stats, GNUNET_NO); | ||
78 | stats = NULL; | ||
79 | } | ||
80 | GNUNET_break (NULL == GNUNET_PLUGIN_unload (db_lib_name, db)); | ||
81 | GNUNET_free (db_lib_name); | ||
82 | db_lib_name = NULL; | ||
83 | } | ||
84 | |||
85 | |||
86 | /** | ||
87 | * Send a result code back to the client. | ||
88 | * | ||
89 | * @param client | ||
90 | * Client that should receive the result code. | ||
91 | * @param result_code | ||
92 | * Code to transmit. | ||
93 | * @param op_id | ||
94 | * Operation ID in network byte order. | ||
95 | * @param err_msg | ||
96 | * Error message to include (or NULL for none). | ||
97 | */ | ||
98 | static void | ||
99 | send_result_code (struct GNUNET_SERVICE_Client *client, | ||
100 | uint64_t op_id, | ||
101 | int64_t result_code, | ||
102 | const char *err_msg) | ||
103 | { | ||
104 | struct OperationResult *res; | ||
105 | size_t err_size = 0; | ||
106 | |||
107 | if (NULL != err_msg) | ||
108 | err_size = strnlen (err_msg, | ||
109 | GNUNET_MAX_MESSAGE_SIZE - sizeof (*res) - 1) + 1; | ||
110 | struct GNUNET_MQ_Envelope * | ||
111 | env = GNUNET_MQ_msg_extra (res, err_size, | ||
112 | GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_CODE); | ||
113 | res->result_code = GNUNET_htonll (result_code - INT64_MIN); | ||
114 | res->op_id = op_id; | ||
115 | if (0 < err_size) | ||
116 | { | ||
117 | GNUNET_memcpy (&res[1], err_msg, err_size); | ||
118 | ((char *) &res[1])[err_size - 1] = '\0'; | ||
119 | } | ||
120 | |||
121 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
122 | "Sending result to client: %" PRId64 " (%s)\n", | ||
123 | result_code, err_msg); | ||
124 | GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), env); | ||
125 | } | ||
126 | |||
127 | |||
128 | enum | ||
129 | { | ||
130 | MEMBERSHIP_TEST_NOT_NEEDED = 0, | ||
131 | MEMBERSHIP_TEST_NEEDED = 1, | ||
132 | MEMBERSHIP_TEST_DONE = 2, | ||
133 | } MessageMembershipTest; | ||
134 | |||
135 | |||
136 | struct SendClosure | ||
137 | { | ||
138 | struct GNUNET_SERVICE_Client *client; | ||
139 | |||
140 | /** | ||
141 | * Channel's public key. | ||
142 | */ | ||
143 | struct GNUNET_CRYPTO_EddsaPublicKey channel_key; | ||
144 | |||
145 | /** | ||
146 | * Slave's public key. | ||
147 | */ | ||
148 | struct GNUNET_CRYPTO_EcdsaPublicKey slave_key; | ||
149 | |||
150 | /** | ||
151 | * Operation ID. | ||
152 | */ | ||
153 | uint64_t op_id; | ||
154 | |||
155 | /** | ||
156 | * Membership test result. | ||
157 | */ | ||
158 | int membership_test_result; | ||
159 | |||
160 | /** | ||
161 | * Do membership test with @a slave_key before returning fragment? | ||
162 | * @see enum MessageMembershipTest | ||
163 | */ | ||
164 | uint8_t membership_test; | ||
165 | }; | ||
166 | |||
167 | |||
168 | static int | ||
169 | send_fragment (void *cls, struct GNUNET_MULTICAST_MessageHeader *msg, | ||
170 | enum GNUNET_PSYCSTORE_MessageFlags flags) | ||
171 | { | ||
172 | struct SendClosure *sc = cls; | ||
173 | struct FragmentResult *res; | ||
174 | |||
175 | if (MEMBERSHIP_TEST_NEEDED == sc->membership_test) | ||
176 | { | ||
177 | sc->membership_test = MEMBERSHIP_TEST_DONE; | ||
178 | sc->membership_test_result | ||
179 | = db->membership_test (db->cls, &sc->channel_key, &sc->slave_key, | ||
180 | GNUNET_ntohll (msg->message_id)); | ||
181 | switch (sc->membership_test_result) | ||
182 | { | ||
183 | case GNUNET_YES: | ||
184 | break; | ||
185 | |||
186 | case GNUNET_NO: | ||
187 | case GNUNET_SYSERR: | ||
188 | return GNUNET_NO; | ||
189 | } | ||
190 | } | ||
191 | |||
192 | size_t msg_size = ntohs (msg->header.size); | ||
193 | |||
194 | struct GNUNET_MQ_Envelope * | ||
195 | env = GNUNET_MQ_msg_extra (res, msg_size, | ||
196 | GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_FRAGMENT); | ||
197 | res->op_id = sc->op_id; | ||
198 | res->psycstore_flags = htonl (flags); | ||
199 | GNUNET_memcpy (&res[1], msg, msg_size); | ||
200 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
201 | "Sending fragment %llu to client\n", | ||
202 | (unsigned long long) GNUNET_ntohll (msg->fragment_id)); | ||
203 | GNUNET_free (msg); | ||
204 | |||
205 | GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (sc->client), env); | ||
206 | return GNUNET_YES; | ||
207 | } | ||
208 | |||
209 | |||
210 | static int | ||
211 | send_state_var (void *cls, const char *name, | ||
212 | const void *value, uint32_t value_size) | ||
213 | { | ||
214 | struct SendClosure *sc = cls; | ||
215 | struct StateResult *res; | ||
216 | size_t name_size = strlen (name) + 1; | ||
217 | |||
218 | /** @todo FIXME: split up value into 64k chunks */ | ||
219 | |||
220 | struct GNUNET_MQ_Envelope * | ||
221 | env = GNUNET_MQ_msg_extra (res, name_size + value_size, | ||
222 | GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_STATE); | ||
223 | res->op_id = sc->op_id; | ||
224 | res->name_size = htons (name_size); | ||
225 | GNUNET_memcpy (&res[1], name, name_size); | ||
226 | GNUNET_memcpy ((char *) &res[1] + name_size, value, value_size); | ||
227 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
228 | "Sending state variable %s to client\n", name); | ||
229 | |||
230 | GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (sc->client), env); | ||
231 | return GNUNET_OK; | ||
232 | } | ||
233 | |||
234 | |||
235 | static void | ||
236 | handle_client_membership_store (void *cls, | ||
237 | const struct MembershipStoreRequest *req) | ||
238 | { | ||
239 | struct GNUNET_SERVICE_Client *client = cls; | ||
240 | |||
241 | int ret = db->membership_store (db->cls, &req->channel_key, &req->slave_key, | ||
242 | req->did_join, | ||
243 | GNUNET_ntohll (req->announced_at), | ||
244 | GNUNET_ntohll (req->effective_since), | ||
245 | GNUNET_ntohll (req->group_generation)); | ||
246 | |||
247 | if (ret != GNUNET_OK) | ||
248 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
249 | _("Failed to store membership information!\n")); | ||
250 | |||
251 | send_result_code (client, req->op_id, ret, NULL); | ||
252 | GNUNET_SERVICE_client_continue (client); | ||
253 | } | ||
254 | |||
255 | |||
256 | static void | ||
257 | handle_client_membership_test (void *cls, | ||
258 | const struct MembershipTestRequest *req) | ||
259 | { | ||
260 | struct GNUNET_SERVICE_Client *client = cls; | ||
261 | |||
262 | int ret = db->membership_test (db->cls, &req->channel_key, &req->slave_key, | ||
263 | GNUNET_ntohll (req->message_id)); | ||
264 | switch (ret) | ||
265 | { | ||
266 | case GNUNET_YES: | ||
267 | case GNUNET_NO: | ||
268 | break; | ||
269 | default: | ||
270 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
271 | _("Failed to test membership!\n")); | ||
272 | } | ||
273 | |||
274 | send_result_code (client, req->op_id, ret, NULL); | ||
275 | GNUNET_SERVICE_client_continue (client); | ||
276 | } | ||
277 | |||
278 | |||
279 | static int | ||
280 | check_client_fragment_store (void *cls, | ||
281 | const struct FragmentStoreRequest *req) | ||
282 | { | ||
283 | return GNUNET_OK; | ||
284 | } | ||
285 | |||
286 | |||
287 | static void | ||
288 | handle_client_fragment_store (void *cls, | ||
289 | const struct FragmentStoreRequest *req) | ||
290 | { | ||
291 | struct GNUNET_SERVICE_Client *client = cls; | ||
292 | |||
293 | const struct GNUNET_MessageHeader * | ||
294 | msg = GNUNET_MQ_extract_nested_mh (req); | ||
295 | if (NULL == msg | ||
296 | || ntohs (msg->size) < sizeof (struct GNUNET_MULTICAST_MessageHeader)) | ||
297 | { | ||
298 | GNUNET_break (0); | ||
299 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
300 | _("Dropping invalid fragment\n")); | ||
301 | GNUNET_SERVICE_client_drop (client); | ||
302 | return; | ||
303 | } | ||
304 | |||
305 | int ret = db->fragment_store (db->cls, &req->channel_key, | ||
306 | (const struct GNUNET_MULTICAST_MessageHeader *) | ||
307 | msg, ntohl (req->psycstore_flags)); | ||
308 | |||
309 | if (ret != GNUNET_OK) | ||
310 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
311 | _("Failed to store fragment\n")); | ||
312 | |||
313 | send_result_code (client, req->op_id, ret, NULL); | ||
314 | GNUNET_SERVICE_client_continue (client); | ||
315 | } | ||
316 | |||
317 | |||
318 | static void | ||
319 | handle_client_fragment_get (void *cls, | ||
320 | const struct FragmentGetRequest *req) | ||
321 | { | ||
322 | struct GNUNET_SERVICE_Client *client = cls; | ||
323 | |||
324 | struct SendClosure | ||
325 | sc = { .op_id = req->op_id, | ||
326 | .client = client, | ||
327 | .channel_key = req->channel_key, | ||
328 | .slave_key = req->slave_key, | ||
329 | .membership_test = req->do_membership_test }; | ||
330 | |||
331 | int64_t ret; | ||
332 | uint64_t ret_frags = 0; | ||
333 | uint64_t first_fragment_id = GNUNET_ntohll (req->first_fragment_id); | ||
334 | uint64_t last_fragment_id = GNUNET_ntohll (req->last_fragment_id); | ||
335 | uint64_t limit = GNUNET_ntohll (req->fragment_limit); | ||
336 | |||
337 | if (0 == limit) | ||
338 | ret = db->fragment_get (db->cls, &req->channel_key, | ||
339 | first_fragment_id, last_fragment_id, | ||
340 | &ret_frags, send_fragment, &sc); | ||
341 | else | ||
342 | ret = db->fragment_get_latest (db->cls, &req->channel_key, limit, | ||
343 | &ret_frags, send_fragment, &sc); | ||
344 | |||
345 | switch (ret) | ||
346 | { | ||
347 | case GNUNET_YES: | ||
348 | case GNUNET_NO: | ||
349 | if (MEMBERSHIP_TEST_DONE == sc.membership_test) | ||
350 | { | ||
351 | switch (sc.membership_test_result) | ||
352 | { | ||
353 | case GNUNET_YES: | ||
354 | break; | ||
355 | |||
356 | case GNUNET_NO: | ||
357 | ret = GNUNET_PSYCSTORE_MEMBERSHIP_TEST_FAILED; | ||
358 | break; | ||
359 | |||
360 | case GNUNET_SYSERR: | ||
361 | ret = GNUNET_SYSERR; | ||
362 | break; | ||
363 | } | ||
364 | } | ||
365 | break; | ||
366 | default: | ||
367 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
368 | _("Failed to get fragment!\n")); | ||
369 | } | ||
370 | send_result_code (client, req->op_id, (ret < 0) ? ret : ret_frags, NULL); | ||
371 | GNUNET_SERVICE_client_continue (client); | ||
372 | } | ||
373 | |||
374 | |||
375 | static int | ||
376 | check_client_message_get (void *cls, | ||
377 | const struct MessageGetRequest *req) | ||
378 | { | ||
379 | return GNUNET_OK; | ||
380 | } | ||
381 | |||
382 | |||
383 | static void | ||
384 | handle_client_message_get (void *cls, | ||
385 | const struct MessageGetRequest *req) | ||
386 | { | ||
387 | struct GNUNET_SERVICE_Client *client = cls; | ||
388 | |||
389 | uint16_t size = ntohs (req->header.size); | ||
390 | const char *method_prefix = (const char *) &req[1]; | ||
391 | |||
392 | if (size < sizeof (*req) + 1 | ||
393 | || '\0' != method_prefix[size - sizeof (*req) - 1]) | ||
394 | { | ||
395 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
396 | "Message get: invalid method prefix. size: %u < %u?\n", | ||
397 | size, | ||
398 | (unsigned int) (sizeof (*req) + 1)); | ||
399 | GNUNET_break (0); | ||
400 | GNUNET_SERVICE_client_drop (client); | ||
401 | return; | ||
402 | } | ||
403 | |||
404 | struct SendClosure | ||
405 | sc = { .op_id = req->op_id, | ||
406 | .client = client, | ||
407 | .channel_key = req->channel_key, | ||
408 | .slave_key = req->slave_key, | ||
409 | .membership_test = req->do_membership_test }; | ||
410 | |||
411 | int64_t ret; | ||
412 | uint64_t ret_frags = 0; | ||
413 | uint64_t first_message_id = GNUNET_ntohll (req->first_message_id); | ||
414 | uint64_t last_message_id = GNUNET_ntohll (req->last_message_id); | ||
415 | uint64_t msg_limit = GNUNET_ntohll (req->message_limit); | ||
416 | uint64_t frag_limit = GNUNET_ntohll (req->fragment_limit); | ||
417 | |||
418 | /** @todo method_prefix */ | ||
419 | if (0 == msg_limit) | ||
420 | ret = db->message_get (db->cls, &req->channel_key, | ||
421 | first_message_id, last_message_id, frag_limit, | ||
422 | &ret_frags, send_fragment, &sc); | ||
423 | else | ||
424 | ret = db->message_get_latest (db->cls, &req->channel_key, msg_limit, | ||
425 | &ret_frags, send_fragment, &sc); | ||
426 | |||
427 | switch (ret) | ||
428 | { | ||
429 | case GNUNET_YES: | ||
430 | case GNUNET_NO: | ||
431 | break; | ||
432 | default: | ||
433 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
434 | _("Failed to get message!\n")); | ||
435 | } | ||
436 | |||
437 | send_result_code (client, req->op_id, (ret < 0) ? ret : ret_frags, NULL); | ||
438 | GNUNET_SERVICE_client_continue (client); | ||
439 | } | ||
440 | |||
441 | |||
442 | static void | ||
443 | handle_client_message_get_fragment (void *cls, | ||
444 | const struct MessageGetFragmentRequest *req) | ||
445 | { | ||
446 | struct GNUNET_SERVICE_Client *client = cls; | ||
447 | |||
448 | struct SendClosure | ||
449 | sc = { .op_id = req->op_id, .client = client, | ||
450 | .channel_key = req->channel_key, .slave_key = req->slave_key, | ||
451 | .membership_test = req->do_membership_test }; | ||
452 | |||
453 | int ret = db->message_get_fragment (db->cls, &req->channel_key, | ||
454 | GNUNET_ntohll (req->message_id), | ||
455 | GNUNET_ntohll (req->fragment_offset), | ||
456 | &send_fragment, &sc); | ||
457 | switch (ret) | ||
458 | { | ||
459 | case GNUNET_YES: | ||
460 | case GNUNET_NO: | ||
461 | break; | ||
462 | default: | ||
463 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
464 | _("Failed to get message fragment!\n")); | ||
465 | } | ||
466 | |||
467 | send_result_code (client, req->op_id, ret, NULL); | ||
468 | GNUNET_SERVICE_client_continue (client); | ||
469 | } | ||
470 | |||
471 | |||
472 | static void | ||
473 | handle_client_counters_get (void *cls, | ||
474 | const struct OperationRequest *req) | ||
475 | { | ||
476 | struct GNUNET_SERVICE_Client *client = cls; | ||
477 | |||
478 | struct CountersResult *res; | ||
479 | struct GNUNET_MQ_Envelope * | ||
480 | env = GNUNET_MQ_msg (res, GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_COUNTERS); | ||
481 | |||
482 | int ret = db->counters_message_get (db->cls, &req->channel_key, | ||
483 | &res->max_fragment_id, &res->max_message_id, | ||
484 | &res->max_group_generation); | ||
485 | switch (ret) | ||
486 | { | ||
487 | case GNUNET_OK: | ||
488 | ret = db->counters_state_get (db->cls, &req->channel_key, | ||
489 | &res->max_state_message_id); | ||
490 | case GNUNET_NO: | ||
491 | break; | ||
492 | default: | ||
493 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
494 | _("Failed to get master counters!\n")); | ||
495 | } | ||
496 | |||
497 | res->result_code = htonl (ret); | ||
498 | res->op_id = req->op_id; | ||
499 | res->max_fragment_id = GNUNET_htonll (res->max_fragment_id); | ||
500 | res->max_message_id = GNUNET_htonll (res->max_message_id); | ||
501 | res->max_group_generation = GNUNET_htonll (res->max_group_generation); | ||
502 | res->max_state_message_id = GNUNET_htonll (res->max_state_message_id); | ||
503 | |||
504 | GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), env); | ||
505 | GNUNET_SERVICE_client_continue (client); | ||
506 | } | ||
507 | |||
508 | |||
509 | struct StateModifyClosure | ||
510 | { | ||
511 | const struct GNUNET_CRYPTO_EddsaPublicKey channel_key; | ||
512 | struct GNUNET_PSYC_ReceiveHandle *recv; | ||
513 | enum GNUNET_PSYC_MessageState msg_state; | ||
514 | char mod_oper; | ||
515 | char *mod_name; | ||
516 | char *mod_value; | ||
517 | uint32_t mod_value_size; | ||
518 | uint32_t mod_value_remaining; | ||
519 | }; | ||
520 | |||
521 | |||
522 | static void | ||
523 | recv_state_message_part (void *cls, | ||
524 | const struct GNUNET_PSYC_MessageHeader *msg, | ||
525 | const struct GNUNET_MessageHeader *pmsg) | ||
526 | { | ||
527 | struct StateModifyClosure *scls = cls; | ||
528 | uint16_t psize; | ||
529 | |||
530 | if (NULL == msg) | ||
531 | { // FIXME: error on unknown message | ||
532 | return; | ||
533 | } | ||
534 | |||
535 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
536 | "recv_state_message_part() message_id: %" PRIu64 | ||
537 | ", fragment_offset: %" PRIu64 ", flags: %u\n", | ||
538 | GNUNET_ntohll (msg->message_id), | ||
539 | GNUNET_ntohll (msg->fragment_offset), | ||
540 | ntohl (msg->flags)); | ||
541 | |||
542 | if (NULL == pmsg) | ||
543 | { | ||
544 | scls->msg_state = GNUNET_PSYC_MESSAGE_STATE_ERROR; | ||
545 | return; | ||
546 | } | ||
547 | |||
548 | switch (ntohs (pmsg->type)) | ||
549 | { | ||
550 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD: | ||
551 | { | ||
552 | scls->msg_state = GNUNET_PSYC_MESSAGE_STATE_METHOD; | ||
553 | break; | ||
554 | } | ||
555 | |||
556 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER: | ||
557 | { | ||
558 | struct GNUNET_PSYC_MessageModifier * | ||
559 | pmod = (struct GNUNET_PSYC_MessageModifier *) pmsg; | ||
560 | psize = ntohs (pmod->header.size); | ||
561 | uint16_t name_size = ntohs (pmod->name_size); | ||
562 | uint32_t value_size = ntohl (pmod->value_size); | ||
563 | |||
564 | const char *name = (const char *) &pmod[1]; | ||
565 | const void *value = name + name_size; | ||
566 | |||
567 | if (GNUNET_PSYC_OP_SET != pmod->oper) | ||
568 | { // Apply non-transient operation. | ||
569 | if (psize == sizeof (*pmod) + name_size + value_size) | ||
570 | { | ||
571 | db->state_modify_op (db->cls, &scls->channel_key, | ||
572 | pmod->oper, name, value, value_size); | ||
573 | } | ||
574 | else | ||
575 | { | ||
576 | scls->mod_oper = pmod->oper; | ||
577 | scls->mod_name = GNUNET_malloc (name_size); | ||
578 | GNUNET_memcpy (scls->mod_name, name, name_size); | ||
579 | |||
580 | scls->mod_value_size = value_size; | ||
581 | scls->mod_value = GNUNET_malloc (scls->mod_value_size); | ||
582 | scls->mod_value_remaining | ||
583 | = scls->mod_value_size - (psize - sizeof (*pmod) - name_size); | ||
584 | GNUNET_memcpy (scls->mod_value, value, value_size - scls->mod_value_remaining); | ||
585 | } | ||
586 | } | ||
587 | scls->msg_state = GNUNET_PSYC_MESSAGE_STATE_MODIFIER; | ||
588 | break; | ||
589 | } | ||
590 | |||
591 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT: | ||
592 | if (GNUNET_PSYC_OP_SET != scls->mod_oper) | ||
593 | { | ||
594 | if (scls->mod_value_remaining == 0) | ||
595 | { | ||
596 | GNUNET_break_op (0); | ||
597 | scls->msg_state = GNUNET_PSYC_MESSAGE_STATE_ERROR; | ||
598 | } | ||
599 | psize = ntohs (pmsg->size); | ||
600 | GNUNET_memcpy (scls->mod_value + (scls->mod_value_size - scls->mod_value_remaining), | ||
601 | &pmsg[1], psize - sizeof (*pmsg)); | ||
602 | scls->mod_value_remaining -= psize - sizeof (*pmsg); | ||
603 | if (0 == scls->mod_value_remaining) | ||
604 | { | ||
605 | db->state_modify_op (db->cls, &scls->channel_key, | ||
606 | scls->mod_oper, scls->mod_name, | ||
607 | scls->mod_value, scls->mod_value_size); | ||
608 | GNUNET_free (scls->mod_name); | ||
609 | GNUNET_free (scls->mod_value); | ||
610 | scls->mod_oper = 0; | ||
611 | scls->mod_name = NULL; | ||
612 | scls->mod_value = NULL; | ||
613 | scls->mod_value_size = 0; | ||
614 | } | ||
615 | } | ||
616 | scls->msg_state = GNUNET_PSYC_MESSAGE_STATE_MOD_CONT; | ||
617 | break; | ||
618 | |||
619 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA: | ||
620 | scls->msg_state = GNUNET_PSYC_MESSAGE_STATE_DATA; | ||
621 | break; | ||
622 | |||
623 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END: | ||
624 | scls->msg_state = GNUNET_PSYC_MESSAGE_STATE_END; | ||
625 | break; | ||
626 | |||
627 | default: | ||
628 | scls->msg_state = GNUNET_PSYC_MESSAGE_STATE_ERROR; | ||
629 | } | ||
630 | } | ||
631 | |||
632 | |||
633 | static int | ||
634 | recv_state_fragment (void *cls, struct GNUNET_MULTICAST_MessageHeader *msg, | ||
635 | enum GNUNET_PSYCSTORE_MessageFlags flags) | ||
636 | { | ||
637 | struct StateModifyClosure *scls = cls; | ||
638 | |||
639 | if (NULL == scls->recv) | ||
640 | { | ||
641 | scls->recv = GNUNET_PSYC_receive_create (NULL, recv_state_message_part, | ||
642 | scls); | ||
643 | } | ||
644 | |||
645 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
646 | "recv_state_fragment: %" PRIu64 "\n", GNUNET_ntohll (msg->fragment_id)); | ||
647 | |||
648 | struct GNUNET_PSYC_MessageHeader * | ||
649 | pmsg = GNUNET_PSYC_message_header_create (msg, flags); | ||
650 | GNUNET_PSYC_receive_message (scls->recv, pmsg); | ||
651 | GNUNET_free (pmsg); | ||
652 | |||
653 | return GNUNET_YES; | ||
654 | } | ||
655 | |||
656 | |||
657 | static void | ||
658 | handle_client_state_modify (void *cls, | ||
659 | const struct StateModifyRequest *req) | ||
660 | { | ||
661 | struct GNUNET_SERVICE_Client *client = cls; | ||
662 | |||
663 | uint64_t message_id = GNUNET_ntohll (req->message_id); | ||
664 | uint64_t state_delta = GNUNET_ntohll (req->state_delta); | ||
665 | uint64_t ret_frags = 0; | ||
666 | struct StateModifyClosure | ||
667 | scls = { .channel_key = req->channel_key }; | ||
668 | |||
669 | int ret = db->state_modify_begin (db->cls, &req->channel_key, | ||
670 | message_id, state_delta); | ||
671 | |||
672 | if (GNUNET_OK != ret) | ||
673 | { | ||
674 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
675 | _("Failed to begin modifying state: %d\n"), ret); | ||
676 | } | ||
677 | else | ||
678 | { | ||
679 | ret = db->message_get (db->cls, &req->channel_key, | ||
680 | message_id, message_id, 0, | ||
681 | &ret_frags, recv_state_fragment, &scls); | ||
682 | if (GNUNET_OK != ret) | ||
683 | { | ||
684 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
685 | _("Failed to modify state: %d\n"), ret); | ||
686 | GNUNET_break (0); | ||
687 | } | ||
688 | else | ||
689 | { | ||
690 | if (GNUNET_OK != db->state_modify_end (db->cls, &req->channel_key, message_id)) | ||
691 | { | ||
692 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
693 | _("Failed to end modifying state!\n")); | ||
694 | GNUNET_break (0); | ||
695 | } | ||
696 | } | ||
697 | if (NULL != scls.recv) | ||
698 | { | ||
699 | GNUNET_PSYC_receive_destroy (scls.recv); | ||
700 | } | ||
701 | } | ||
702 | |||
703 | send_result_code (client, req->op_id, ret, NULL); | ||
704 | GNUNET_SERVICE_client_continue (client); | ||
705 | } | ||
706 | |||
707 | |||
708 | static int | ||
709 | check_client_state_sync (void *cls, | ||
710 | const struct StateSyncRequest *req) | ||
711 | { | ||
712 | return GNUNET_OK; | ||
713 | } | ||
714 | |||
715 | |||
716 | /** @todo FIXME: stop processing further state sync messages after an error */ | ||
717 | static void | ||
718 | handle_client_state_sync (void *cls, | ||
719 | const struct StateSyncRequest *req) | ||
720 | { | ||
721 | struct GNUNET_SERVICE_Client *client = cls; | ||
722 | |||
723 | int ret = GNUNET_SYSERR; | ||
724 | const char *name = (const char *) &req[1]; | ||
725 | uint16_t name_size = ntohs (req->name_size); | ||
726 | |||
727 | if (name_size <= 2 || '\0' != name[name_size - 1]) | ||
728 | { | ||
729 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
730 | _("Tried to set invalid state variable name!\n")); | ||
731 | GNUNET_break_op (0); | ||
732 | } | ||
733 | else | ||
734 | { | ||
735 | ret = GNUNET_OK; | ||
736 | |||
737 | if (req->flags & STATE_OP_FIRST) | ||
738 | { | ||
739 | ret = db->state_sync_begin (db->cls, &req->channel_key); | ||
740 | } | ||
741 | if (ret != GNUNET_OK) | ||
742 | { | ||
743 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
744 | _("Failed to begin synchronizing state!\n")); | ||
745 | } | ||
746 | else | ||
747 | { | ||
748 | ret = db->state_sync_assign (db->cls, &req->channel_key, name, | ||
749 | name + ntohs (req->name_size), | ||
750 | ntohs (req->header.size) - sizeof (*req) | ||
751 | - ntohs (req->name_size)); | ||
752 | } | ||
753 | |||
754 | if (GNUNET_OK == ret && req->flags & STATE_OP_LAST) | ||
755 | { | ||
756 | ret = db->state_sync_end (db->cls, &req->channel_key, | ||
757 | GNUNET_ntohll (req->max_state_message_id), | ||
758 | GNUNET_ntohll (req->state_hash_message_id)); | ||
759 | if (ret != GNUNET_OK) | ||
760 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
761 | _("Failed to end synchronizing state!\n")); | ||
762 | } | ||
763 | } | ||
764 | send_result_code (client, req->op_id, ret, NULL); | ||
765 | GNUNET_SERVICE_client_continue (client); | ||
766 | } | ||
767 | |||
768 | |||
769 | static void | ||
770 | handle_client_state_reset (void *cls, | ||
771 | const struct OperationRequest *req) | ||
772 | { | ||
773 | struct GNUNET_SERVICE_Client *client = cls; | ||
774 | |||
775 | int ret = db->state_reset (db->cls, &req->channel_key); | ||
776 | |||
777 | if (ret != GNUNET_OK) | ||
778 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
779 | _("Failed to reset state!\n")); | ||
780 | |||
781 | send_result_code (client, req->op_id, ret, NULL); | ||
782 | GNUNET_SERVICE_client_continue (client); | ||
783 | } | ||
784 | |||
785 | |||
786 | static void | ||
787 | handle_client_state_hash_update (void *cls, | ||
788 | const struct StateHashUpdateRequest *req) | ||
789 | { | ||
790 | struct GNUNET_SERVICE_Client *client = cls; | ||
791 | |||
792 | int ret = db->state_reset (db->cls, &req->channel_key); | ||
793 | if (ret != GNUNET_OK) | ||
794 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
795 | _("Failed to reset state!\n")); | ||
796 | |||
797 | send_result_code (client, req->op_id, ret, NULL); | ||
798 | GNUNET_SERVICE_client_continue (client); | ||
799 | } | ||
800 | |||
801 | |||
802 | static int | ||
803 | check_client_state_get (void *cls, | ||
804 | const struct OperationRequest *req) | ||
805 | { | ||
806 | return GNUNET_OK; | ||
807 | } | ||
808 | |||
809 | |||
810 | static void | ||
811 | handle_client_state_get (void *cls, | ||
812 | const struct OperationRequest *req) | ||
813 | { | ||
814 | struct GNUNET_SERVICE_Client *client = cls; | ||
815 | |||
816 | struct SendClosure sc = { .op_id = req->op_id, .client = client }; | ||
817 | int64_t ret = GNUNET_SYSERR; | ||
818 | const char *name = (const char *) &req[1]; | ||
819 | uint16_t name_size = ntohs (req->header.size) - sizeof (*req); | ||
820 | |||
821 | if (name_size <= 2 || '\0' != name[name_size - 1]) | ||
822 | { | ||
823 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
824 | _("Tried to get invalid state variable name!\n")); | ||
825 | GNUNET_break (0); | ||
826 | } | ||
827 | else | ||
828 | { | ||
829 | ret = db->state_get (db->cls, &req->channel_key, name, | ||
830 | &send_state_var, &sc); | ||
831 | if (GNUNET_NO == ret && name_size >= 5) /* min: _a_b\0 */ | ||
832 | { | ||
833 | char *p, *n = GNUNET_malloc (name_size); | ||
834 | GNUNET_memcpy (n, name, name_size); | ||
835 | while (&n[1] < (p = strrchr (n, '_')) && GNUNET_NO == ret) | ||
836 | { | ||
837 | *p = '\0'; | ||
838 | ret = db->state_get (db->cls, &req->channel_key, n, | ||
839 | &send_state_var, &sc); | ||
840 | } | ||
841 | GNUNET_free (n); | ||
842 | } | ||
843 | } | ||
844 | switch (ret) | ||
845 | { | ||
846 | case GNUNET_OK: | ||
847 | case GNUNET_NO: | ||
848 | break; | ||
849 | default: | ||
850 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
851 | _("Failed to get state variable!\n")); | ||
852 | } | ||
853 | |||
854 | send_result_code (client, req->op_id, ret, NULL); | ||
855 | GNUNET_SERVICE_client_continue (client); | ||
856 | } | ||
857 | |||
858 | |||
859 | static int | ||
860 | check_client_state_get_prefix (void *cls, | ||
861 | const struct OperationRequest *req) | ||
862 | { | ||
863 | return GNUNET_OK; | ||
864 | } | ||
865 | |||
866 | |||
867 | static void | ||
868 | handle_client_state_get_prefix (void *cls, | ||
869 | const struct OperationRequest *req) | ||
870 | { | ||
871 | struct GNUNET_SERVICE_Client *client = cls; | ||
872 | |||
873 | struct SendClosure sc = { .op_id = req->op_id, .client = client }; | ||
874 | int64_t ret = GNUNET_SYSERR; | ||
875 | const char *name = (const char *) &req[1]; | ||
876 | uint16_t name_size = ntohs (req->header.size) - sizeof (*req); | ||
877 | |||
878 | if (name_size <= 1 || '\0' != name[name_size - 1]) | ||
879 | { | ||
880 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
881 | _("Tried to get invalid state variable name!\n")); | ||
882 | GNUNET_break (0); | ||
883 | } | ||
884 | else | ||
885 | { | ||
886 | ret = db->state_get_prefix (db->cls, &req->channel_key, name, | ||
887 | &send_state_var, &sc); | ||
888 | } | ||
889 | switch (ret) | ||
890 | { | ||
891 | case GNUNET_OK: | ||
892 | case GNUNET_NO: | ||
893 | break; | ||
894 | default: | ||
895 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
896 | _("Failed to get state variable!\n")); | ||
897 | } | ||
898 | |||
899 | send_result_code (client, req->op_id, ret, NULL); | ||
900 | GNUNET_SERVICE_client_continue (client); | ||
901 | } | ||
902 | |||
903 | |||
904 | /** | ||
905 | * A new client connected. | ||
906 | * | ||
907 | * @param cls NULL | ||
908 | * @param client client to add | ||
909 | * @param mq message queue for @a client | ||
910 | * @return @a client | ||
911 | */ | ||
912 | static void * | ||
913 | client_notify_connect (void *cls, | ||
914 | struct GNUNET_SERVICE_Client *client, | ||
915 | struct GNUNET_MQ_Handle *mq) | ||
916 | { | ||
917 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client connected: %p\n", client); | ||
918 | |||
919 | return client; | ||
920 | } | ||
921 | |||
922 | |||
923 | /** | ||
924 | * Called whenever a client is disconnected. | ||
925 | * Frees our resources associated with that client. | ||
926 | * | ||
927 | * @param cls closure | ||
928 | * @param client identification of the client | ||
929 | * @param app_ctx must match @a client | ||
930 | */ | ||
931 | static void | ||
932 | client_notify_disconnect (void *cls, | ||
933 | struct GNUNET_SERVICE_Client *client, | ||
934 | void *app_ctx) | ||
935 | { | ||
936 | } | ||
937 | |||
938 | |||
939 | /** | ||
940 | * Initialize the PSYCstore service. | ||
941 | * | ||
942 | * @param cls Closure. | ||
943 | * @param server The initialized server. | ||
944 | * @param c Configuration to use. | ||
945 | */ | ||
946 | static void | ||
947 | run (void *cls, | ||
948 | const struct GNUNET_CONFIGURATION_Handle *c, | ||
949 | struct GNUNET_SERVICE_Handle *svc) | ||
950 | { | ||
951 | cfg = c; | ||
952 | service = svc; | ||
953 | |||
954 | /* Loading database plugin */ | ||
955 | char *database; | ||
956 | if (GNUNET_OK != | ||
957 | GNUNET_CONFIGURATION_get_value_string (cfg, "psycstore", "database", | ||
958 | &database)) | ||
959 | { | ||
960 | GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, | ||
961 | "psycstore", | ||
962 | "database"); | ||
963 | } | ||
964 | else | ||
965 | { | ||
966 | GNUNET_asprintf (&db_lib_name, | ||
967 | "libgnunet_plugin_psycstore_%s", | ||
968 | database); | ||
969 | db = GNUNET_PLUGIN_load (db_lib_name, (void *) cfg); | ||
970 | GNUNET_free (database); | ||
971 | } | ||
972 | if (NULL == db) | ||
973 | { | ||
974 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
975 | "Could not load database backend `%s'\n", | ||
976 | db_lib_name); | ||
977 | GNUNET_SCHEDULER_add_now (&shutdown_task, NULL); | ||
978 | return; | ||
979 | } | ||
980 | |||
981 | stats = GNUNET_STATISTICS_create ("psycstore", cfg); | ||
982 | GNUNET_SCHEDULER_add_shutdown (shutdown_task, | ||
983 | NULL); | ||
984 | } | ||
985 | |||
986 | /** | ||
987 | * Define "main" method using service macro. | ||
988 | */ | ||
989 | GNUNET_SERVICE_MAIN | ||
990 | ("psycstore", | ||
991 | GNUNET_SERVICE_OPTION_NONE, | ||
992 | run, | ||
993 | client_notify_connect, | ||
994 | client_notify_disconnect, | ||
995 | NULL, | ||
996 | GNUNET_MQ_hd_fixed_size (client_membership_store, | ||
997 | GNUNET_MESSAGE_TYPE_PSYCSTORE_MEMBERSHIP_STORE, | ||
998 | struct MembershipStoreRequest, | ||
999 | NULL), | ||
1000 | GNUNET_MQ_hd_fixed_size (client_membership_test, | ||
1001 | GNUNET_MESSAGE_TYPE_PSYCSTORE_MEMBERSHIP_TEST, | ||
1002 | struct MembershipTestRequest, | ||
1003 | NULL), | ||
1004 | GNUNET_MQ_hd_var_size (client_fragment_store, | ||
1005 | GNUNET_MESSAGE_TYPE_PSYCSTORE_FRAGMENT_STORE, | ||
1006 | struct FragmentStoreRequest, | ||
1007 | NULL), | ||
1008 | GNUNET_MQ_hd_fixed_size (client_fragment_get, | ||
1009 | GNUNET_MESSAGE_TYPE_PSYCSTORE_FRAGMENT_GET, | ||
1010 | struct FragmentGetRequest, | ||
1011 | NULL), | ||
1012 | GNUNET_MQ_hd_var_size (client_message_get, | ||
1013 | GNUNET_MESSAGE_TYPE_PSYCSTORE_MESSAGE_GET, | ||
1014 | struct MessageGetRequest, | ||
1015 | NULL), | ||
1016 | GNUNET_MQ_hd_fixed_size (client_message_get_fragment, | ||
1017 | GNUNET_MESSAGE_TYPE_PSYCSTORE_MESSAGE_GET_FRAGMENT, | ||
1018 | struct MessageGetFragmentRequest, | ||
1019 | NULL), | ||
1020 | GNUNET_MQ_hd_fixed_size (client_counters_get, | ||
1021 | GNUNET_MESSAGE_TYPE_PSYCSTORE_COUNTERS_GET, | ||
1022 | struct OperationRequest, | ||
1023 | NULL), | ||
1024 | GNUNET_MQ_hd_fixed_size (client_state_modify, | ||
1025 | GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_MODIFY, | ||
1026 | struct StateModifyRequest, | ||
1027 | NULL), | ||
1028 | GNUNET_MQ_hd_var_size (client_state_sync, | ||
1029 | GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_SYNC, | ||
1030 | struct StateSyncRequest, | ||
1031 | NULL), | ||
1032 | GNUNET_MQ_hd_fixed_size (client_state_reset, | ||
1033 | GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_RESET, | ||
1034 | struct OperationRequest, | ||
1035 | NULL), | ||
1036 | GNUNET_MQ_hd_fixed_size (client_state_hash_update, | ||
1037 | GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_HASH_UPDATE, | ||
1038 | struct StateHashUpdateRequest, | ||
1039 | NULL), | ||
1040 | GNUNET_MQ_hd_var_size (client_state_get, | ||
1041 | GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_GET, | ||
1042 | struct OperationRequest, | ||
1043 | NULL), | ||
1044 | GNUNET_MQ_hd_var_size (client_state_get_prefix, | ||
1045 | GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_GET_PREFIX, | ||
1046 | struct OperationRequest, | ||
1047 | NULL)); | ||
1048 | |||
1049 | /* end of gnunet-service-psycstore.c */ | ||
diff --git a/src/psycstore/plugin_psycstore_mysql.c b/src/psycstore/plugin_psycstore_mysql.c deleted file mode 100644 index c36b6f7a3..000000000 --- a/src/psycstore/plugin_psycstore_mysql.c +++ /dev/null | |||
@@ -1,1960 +0,0 @@ | |||
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 psycstore/plugin_psycstore_mysql.c | ||
23 | * @brief mysql-based psycstore backend | ||
24 | * @author Gabor X Toth | ||
25 | * @author Christian Grothoff | ||
26 | * @author Christophe Genevey | ||
27 | */ | ||
28 | |||
29 | #include "platform.h" | ||
30 | #include "gnunet_psycstore_plugin.h" | ||
31 | #include "gnunet_psycstore_service.h" | ||
32 | #include "gnunet_multicast_service.h" | ||
33 | #include "gnunet_crypto_lib.h" | ||
34 | #include "gnunet_psyc_util_lib.h" | ||
35 | #include "psycstore.h" | ||
36 | #include "gnunet_my_lib.h" | ||
37 | #include "gnunet_mysql_lib.h" | ||
38 | #include <mysql/mysql.h> | ||
39 | |||
40 | /** | ||
41 | * After how many ms "busy" should a DB operation fail for good? A | ||
42 | * low value makes sure that we are more responsive to requests | ||
43 | * (especially PUTs). A high value guarantees a higher success rate | ||
44 | * (SELECTs in iterate can take several seconds despite LIMIT=1). | ||
45 | * | ||
46 | * The default value of 1s should ensure that users do not experience | ||
47 | * huge latencies while at the same time allowing operations to | ||
48 | * succeed with reasonable probability. | ||
49 | */ | ||
50 | #define BUSY_TIMEOUT_MS 1000 | ||
51 | |||
52 | #define DEBUG_PSYCSTORE GNUNET_EXTRA_LOGGING | ||
53 | |||
54 | /** | ||
55 | * Log an error message at log-level 'level' that indicates | ||
56 | * a failure of the command 'cmd' on file 'filename' | ||
57 | * with the message given by strerror(errno). | ||
58 | */ | ||
59 | #define LOG_MYSQL(db, level, cmd, stmt) \ | ||
60 | do { \ | ||
61 | GNUNET_log_from (level, "psycstore-mysql", \ | ||
62 | _("`%s' failed at %s:%d with error: %s\n"), \ | ||
63 | cmd, __FILE__, __LINE__, \ | ||
64 | mysql_stmt_error (GNUNET_MYSQL_statement_get_stmt(stmt))); \ | ||
65 | } while (0) | ||
66 | |||
67 | #define LOG(kind,...) GNUNET_log_from (kind, "psycstore-mysql", __VA_ARGS__) | ||
68 | |||
69 | enum Transactions { | ||
70 | TRANSACTION_NONE = 0, | ||
71 | TRANSACTION_STATE_MODIFY, | ||
72 | TRANSACTION_STATE_SYNC, | ||
73 | }; | ||
74 | |||
75 | /** | ||
76 | * Context for all functions in this plugin. | ||
77 | */ | ||
78 | struct Plugin | ||
79 | { | ||
80 | |||
81 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
82 | |||
83 | /** | ||
84 | * MySQL context. | ||
85 | */ | ||
86 | struct GNUNET_MYSQL_Context *mc; | ||
87 | |||
88 | /** | ||
89 | * Current transaction. | ||
90 | */ | ||
91 | enum Transactions transaction; | ||
92 | |||
93 | /** | ||
94 | * Precompiled SQL for channel_key_store() | ||
95 | */ | ||
96 | struct GNUNET_MYSQL_StatementHandle *insert_channel_key; | ||
97 | |||
98 | /** | ||
99 | * Precompiled SQL for slave_key_store() | ||
100 | */ | ||
101 | struct GNUNET_MYSQL_StatementHandle *insert_slave_key; | ||
102 | |||
103 | /** | ||
104 | * Precompiled SQL for membership_store() | ||
105 | */ | ||
106 | struct GNUNET_MYSQL_StatementHandle *insert_membership; | ||
107 | |||
108 | /** | ||
109 | * Precompiled SQL for membership_test() | ||
110 | */ | ||
111 | struct GNUNET_MYSQL_StatementHandle *select_membership; | ||
112 | |||
113 | /** | ||
114 | * Precompiled SQL for fragment_store() | ||
115 | */ | ||
116 | struct GNUNET_MYSQL_StatementHandle *insert_fragment; | ||
117 | |||
118 | /** | ||
119 | * Precompiled SQL for message_add_flags() | ||
120 | */ | ||
121 | struct GNUNET_MYSQL_StatementHandle *update_message_flags; | ||
122 | |||
123 | /** | ||
124 | * Precompiled SQL for fragment_get() | ||
125 | */ | ||
126 | struct GNUNET_MYSQL_StatementHandle *select_fragments; | ||
127 | |||
128 | /** | ||
129 | * Precompiled SQL for fragment_get() | ||
130 | */ | ||
131 | struct GNUNET_MYSQL_StatementHandle *select_latest_fragments; | ||
132 | |||
133 | /** | ||
134 | * Precompiled SQL for message_get() | ||
135 | */ | ||
136 | struct GNUNET_MYSQL_StatementHandle *select_messages; | ||
137 | |||
138 | /** | ||
139 | * Precompiled SQL for message_get() | ||
140 | */ | ||
141 | struct GNUNET_MYSQL_StatementHandle *select_latest_messages; | ||
142 | |||
143 | /** | ||
144 | * Precompiled SQL for message_get_fragment() | ||
145 | */ | ||
146 | struct GNUNET_MYSQL_StatementHandle *select_message_fragment; | ||
147 | |||
148 | /** | ||
149 | * Precompiled SQL for counters_get_message() | ||
150 | */ | ||
151 | struct GNUNET_MYSQL_StatementHandle *select_counters_message; | ||
152 | |||
153 | /** | ||
154 | * Precompiled SQL for counters_get_state() | ||
155 | */ | ||
156 | struct GNUNET_MYSQL_StatementHandle *select_counters_state; | ||
157 | |||
158 | /** | ||
159 | * Precompiled SQL for state_modify_end() | ||
160 | */ | ||
161 | struct GNUNET_MYSQL_StatementHandle *update_state_hash_message_id; | ||
162 | |||
163 | /** | ||
164 | * Precompiled SQL for state_sync_end() | ||
165 | */ | ||
166 | struct GNUNET_MYSQL_StatementHandle *update_max_state_message_id; | ||
167 | |||
168 | /** | ||
169 | * Precompiled SQL for state_modify_op() | ||
170 | */ | ||
171 | struct GNUNET_MYSQL_StatementHandle *insert_state_current; | ||
172 | |||
173 | /** | ||
174 | * Precompiled SQL for state_modify_end() | ||
175 | */ | ||
176 | struct GNUNET_MYSQL_StatementHandle *delete_state_empty; | ||
177 | |||
178 | /** | ||
179 | * Precompiled SQL for state_set_signed() | ||
180 | */ | ||
181 | struct GNUNET_MYSQL_StatementHandle *update_state_signed; | ||
182 | |||
183 | /** | ||
184 | * Precompiled SQL for state_sync() | ||
185 | */ | ||
186 | struct GNUNET_MYSQL_StatementHandle *insert_state_sync; | ||
187 | |||
188 | /** | ||
189 | * Precompiled SQL for state_sync() | ||
190 | */ | ||
191 | struct GNUNET_MYSQL_StatementHandle *delete_state; | ||
192 | |||
193 | /** | ||
194 | * Precompiled SQL for state_sync() | ||
195 | */ | ||
196 | struct GNUNET_MYSQL_StatementHandle *insert_state_from_sync; | ||
197 | |||
198 | /** | ||
199 | * Precompiled SQL for state_sync() | ||
200 | */ | ||
201 | struct GNUNET_MYSQL_StatementHandle *delete_state_sync; | ||
202 | |||
203 | /** | ||
204 | * Precompiled SQL for state_get_signed() | ||
205 | */ | ||
206 | struct GNUNET_MYSQL_StatementHandle *select_state_signed; | ||
207 | |||
208 | /** | ||
209 | * Precompiled SQL for state_get() | ||
210 | */ | ||
211 | struct GNUNET_MYSQL_StatementHandle *select_state_one; | ||
212 | |||
213 | /** | ||
214 | * Precompiled SQL for state_get_prefix() | ||
215 | */ | ||
216 | struct GNUNET_MYSQL_StatementHandle *select_state_prefix; | ||
217 | |||
218 | }; | ||
219 | |||
220 | #if DEBUG_PSYCSTORE | ||
221 | |||
222 | static void | ||
223 | mysql_trace (void *cls, const char *sql) | ||
224 | { | ||
225 | LOG(GNUNET_ERROR_TYPE_DEBUG, "MYSQL query:\n%s\n", sql); | ||
226 | } | ||
227 | |||
228 | #endif | ||
229 | |||
230 | |||
231 | /** | ||
232 | * @brief Prepare a SQL statement | ||
233 | * | ||
234 | * @param dbh handle to the database | ||
235 | * @param sql SQL statement, UTF-8 encoded | ||
236 | * @param stmt set to the prepared statement | ||
237 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure | ||
238 | */ | ||
239 | static int | ||
240 | mysql_prepare (struct GNUNET_MYSQL_Context *mc, | ||
241 | const char *sql, | ||
242 | struct GNUNET_MYSQL_StatementHandle **stmt) | ||
243 | { | ||
244 | *stmt = GNUNET_MYSQL_statement_prepare (mc, | ||
245 | sql); | ||
246 | |||
247 | if (NULL == *stmt) | ||
248 | { | ||
249 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
250 | _("Error preparing SQL query: %s\n %s\n"), | ||
251 | mysql_stmt_error (GNUNET_MYSQL_statement_get_stmt (*stmt)), | ||
252 | sql); | ||
253 | return GNUNET_SYSERR; | ||
254 | } | ||
255 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
256 | "Prepared `%s' / %p\n", | ||
257 | sql, | ||
258 | stmt); | ||
259 | return GNUNET_OK; | ||
260 | } | ||
261 | |||
262 | |||
263 | /** | ||
264 | * Initialize the database connections and associated | ||
265 | * data structures (create tables and indices | ||
266 | * as needed as well). | ||
267 | * | ||
268 | * @param plugin the plugin context (state for this module) | ||
269 | * @return #GNUNET_OK on success | ||
270 | */ | ||
271 | static int | ||
272 | database_setup (struct Plugin *plugin) | ||
273 | { | ||
274 | /* Open database and precompile statements */ | ||
275 | plugin->mc = GNUNET_MYSQL_context_create (plugin->cfg, | ||
276 | "psycstore-mysql"); | ||
277 | |||
278 | if (NULL == plugin->mc) | ||
279 | { | ||
280 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
281 | _("Unable to initialize Mysql.\n")); | ||
282 | return GNUNET_SYSERR; | ||
283 | } | ||
284 | |||
285 | #define STMT_RUN(sql) \ | ||
286 | if (GNUNET_OK != \ | ||
287 | GNUNET_MYSQL_statement_run (plugin->mc, \ | ||
288 | sql)) \ | ||
289 | { \ | ||
290 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, \ | ||
291 | _("Failed to run SQL statement `%s'\n"), \ | ||
292 | sql); \ | ||
293 | return GNUNET_SYSERR; \ | ||
294 | } | ||
295 | |||
296 | /* Create tables */ | ||
297 | STMT_RUN ("CREATE TABLE IF NOT EXISTS channels (\n" | ||
298 | " id BIGINT UNSIGNED AUTO_INCREMENT,\n" | ||
299 | " pub_key BLOB(32),\n" | ||
300 | " max_state_message_id BIGINT UNSIGNED,\n" | ||
301 | " state_hash_message_id BIGINT UNSIGNED,\n" | ||
302 | " PRIMARY KEY(id),\n" | ||
303 | " UNIQUE KEY(pub_key(32))\n" | ||
304 | ");"); | ||
305 | |||
306 | STMT_RUN ("CREATE TABLE IF NOT EXISTS slaves (\n" | ||
307 | " id BIGINT UNSIGNED AUTO_INCREMENT,\n" | ||
308 | " pub_key BLOB(32),\n" | ||
309 | " PRIMARY KEY(id),\n" | ||
310 | " UNIQUE KEY(pub_key(32))\n" | ||
311 | ");"); | ||
312 | |||
313 | STMT_RUN ("CREATE TABLE IF NOT EXISTS membership (\n" | ||
314 | " channel_id BIGINT UNSIGNED NOT NULL REFERENCES channels(id),\n" | ||
315 | " slave_id BIGINT UNSIGNED NOT NULL REFERENCES slaves(id),\n" | ||
316 | " did_join TINYINT NOT NULL,\n" | ||
317 | " announced_at BIGINT UNSIGNED NOT NULL,\n" | ||
318 | " effective_since BIGINT UNSIGNED NOT NULL,\n" | ||
319 | " group_generation BIGINT UNSIGNED NOT NULL\n" | ||
320 | ");"); | ||
321 | |||
322 | /*** FIX because IF NOT EXISTS doesn't work ***/ | ||
323 | GNUNET_MYSQL_statement_run (plugin->mc, | ||
324 | "CREATE INDEX idx_membership_channel_id_slave_id " | ||
325 | "ON membership (channel_id, slave_id);"); | ||
326 | |||
327 | /** @todo messages table: add method_name column */ | ||
328 | STMT_RUN ("CREATE TABLE IF NOT EXISTS messages (\n" | ||
329 | " channel_id BIGINT UNSIGNED NOT NULL REFERENCES channels(id),\n" | ||
330 | " hop_counter BIGINT UNSIGNED NOT NULL,\n" | ||
331 | " signature BLOB,\n" | ||
332 | " purpose BLOB,\n" | ||
333 | " fragment_id BIGINT UNSIGNED NOT NULL,\n" | ||
334 | " fragment_offset BIGINT UNSIGNED NOT NULL,\n" | ||
335 | " message_id BIGINT UNSIGNED NOT NULL,\n" | ||
336 | " group_generation BIGINT UNSIGNED NOT NULL,\n" | ||
337 | " multicast_flags BIGINT UNSIGNED NOT NULL,\n" | ||
338 | " psycstore_flags BIGINT UNSIGNED NOT NULL,\n" | ||
339 | " data BLOB,\n" | ||
340 | " PRIMARY KEY (channel_id, fragment_id),\n" | ||
341 | " UNIQUE KEY(channel_id, message_id, fragment_offset)\n" | ||
342 | ");"); | ||
343 | |||
344 | STMT_RUN ("CREATE TABLE IF NOT EXISTS state (\n" | ||
345 | " channel_id BIGINT UNSIGNED NOT NULL REFERENCES channels(id),\n" | ||
346 | " name TEXT NOT NULL,\n" | ||
347 | " value_current BLOB,\n" | ||
348 | " value_signed BLOB\n" | ||
349 | //" PRIMARY KEY (channel_id, name(255))\n" | ||
350 | ");"); | ||
351 | |||
352 | STMT_RUN ("CREATE TABLE IF NOT EXISTS state_sync (\n" | ||
353 | " channel_id BIGINT UNSIGNED NOT NULL REFERENCES channels(id),\n" | ||
354 | " name TEXT NOT NULL,\n" | ||
355 | " value BLOB\n" | ||
356 | //" PRIMARY KEY (channel_id, name(255))\n" | ||
357 | ");"); | ||
358 | #undef STMT_RUN | ||
359 | |||
360 | /* Prepare statements */ | ||
361 | #define PREP(stmt,handle) \ | ||
362 | if (GNUNET_OK != mysql_prepare (plugin->mc, stmt, handle)) \ | ||
363 | { \ | ||
364 | GNUNET_break (0); \ | ||
365 | return GNUNET_SYSERR; \ | ||
366 | } | ||
367 | PREP ("INSERT IGNORE INTO channels (pub_key) VALUES (?);", | ||
368 | &plugin->insert_channel_key); | ||
369 | PREP ("INSERT IGNORE INTO slaves (pub_key) VALUES (?);", | ||
370 | &plugin->insert_slave_key); | ||
371 | PREP ("INSERT INTO membership\n" | ||
372 | " (channel_id, slave_id, did_join, announced_at,\n" | ||
373 | " effective_since, group_generation)\n" | ||
374 | "VALUES ((SELECT id FROM channels WHERE pub_key = ?),\n" | ||
375 | " (SELECT id FROM slaves WHERE pub_key = ?),\n" | ||
376 | " ?, ?, ?, ?);", | ||
377 | &plugin->insert_membership); | ||
378 | PREP ("SELECT did_join FROM membership\n" | ||
379 | "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" | ||
380 | " AND slave_id = (SELECT id FROM slaves WHERE pub_key = ?)\n" | ||
381 | " AND effective_since <= ? AND did_join = 1\n" | ||
382 | "ORDER BY announced_at DESC LIMIT 1;", | ||
383 | &plugin->select_membership); | ||
384 | |||
385 | PREP ("INSERT IGNORE INTO messages\n" | ||
386 | " (channel_id, hop_counter, signature, purpose,\n" | ||
387 | " fragment_id, fragment_offset, message_id,\n" | ||
388 | " group_generation, multicast_flags, psycstore_flags, data)\n" | ||
389 | "VALUES ((SELECT id FROM channels WHERE pub_key = ?),\n" | ||
390 | " ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);", | ||
391 | &plugin->insert_fragment); | ||
392 | |||
393 | PREP ("UPDATE messages\n" | ||
394 | "SET psycstore_flags = psycstore_flags | ?\n" | ||
395 | "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" | ||
396 | " AND message_id = ? AND fragment_offset = 0;", | ||
397 | &plugin->update_message_flags); | ||
398 | |||
399 | PREP ("SELECT hop_counter, signature, purpose, fragment_id,\n" | ||
400 | " fragment_offset, message_id, group_generation,\n" | ||
401 | " multicast_flags, psycstore_flags, data\n" | ||
402 | "FROM messages\n" | ||
403 | "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" | ||
404 | " AND ? <= fragment_id AND fragment_id <= ? LIMIT 1;", | ||
405 | &plugin->select_fragments); | ||
406 | |||
407 | /** @todo select_messages: add method_prefix filter */ | ||
408 | PREP ("SELECT hop_counter, signature, purpose, fragment_id,\n" | ||
409 | " fragment_offset, message_id, group_generation,\n" | ||
410 | " multicast_flags, psycstore_flags, data\n" | ||
411 | "FROM messages\n" | ||
412 | "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" | ||
413 | " AND ? <= message_id AND message_id <= ?\n" | ||
414 | "LIMIT ?;", | ||
415 | &plugin->select_messages); | ||
416 | |||
417 | PREP ("SELECT * FROM\n" | ||
418 | "(SELECT hop_counter, signature, purpose, fragment_id,\n" | ||
419 | " fragment_offset, message_id, group_generation,\n" | ||
420 | " multicast_flags, psycstore_flags, data\n" | ||
421 | " FROM messages\n" | ||
422 | " WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" | ||
423 | " ORDER BY fragment_id DESC\n" | ||
424 | " LIMIT ?)\n" | ||
425 | "ORDER BY fragment_id;", | ||
426 | &plugin->select_latest_fragments); | ||
427 | |||
428 | /** @todo select_latest_messages: add method_prefix filter */ | ||
429 | PREP ("SELECT hop_counter, signature, purpose, fragment_id,\n" | ||
430 | " fragment_offset, message_id, group_generation,\n" | ||
431 | " multicast_flags, psycstore_flags, data\n" | ||
432 | "FROM messages\n" | ||
433 | "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" | ||
434 | " AND message_id IN\n" | ||
435 | " (SELECT message_id\n" | ||
436 | " FROM messages\n" | ||
437 | " WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" | ||
438 | " GROUP BY message_id\n" | ||
439 | " ORDER BY message_id\n" | ||
440 | " DESC LIMIT ?)\n" | ||
441 | "ORDER BY fragment_id;", | ||
442 | &plugin->select_latest_messages); | ||
443 | |||
444 | PREP ("SELECT hop_counter, signature, purpose, fragment_id,\n" | ||
445 | " fragment_offset, message_id, group_generation,\n" | ||
446 | " multicast_flags, psycstore_flags, data\n" | ||
447 | "FROM messages\n" | ||
448 | "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" | ||
449 | " AND message_id = ? AND fragment_offset = ?;", | ||
450 | &plugin->select_message_fragment); | ||
451 | |||
452 | PREP ("SELECT fragment_id, message_id, group_generation\n" | ||
453 | "FROM messages\n" | ||
454 | "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" | ||
455 | "ORDER BY fragment_id DESC LIMIT 1;", | ||
456 | &plugin->select_counters_message); | ||
457 | |||
458 | PREP ("SELECT max_state_message_id\n" | ||
459 | "FROM channels\n" | ||
460 | "WHERE pub_key = ? AND max_state_message_id IS NOT NULL;", | ||
461 | &plugin->select_counters_state); | ||
462 | |||
463 | PREP ("UPDATE channels\n" | ||
464 | "SET max_state_message_id = ?\n" | ||
465 | "WHERE pub_key = ?;", | ||
466 | &plugin->update_max_state_message_id); | ||
467 | |||
468 | PREP ("UPDATE channels\n" | ||
469 | "SET state_hash_message_id = ?\n" | ||
470 | "WHERE pub_key = ?;", | ||
471 | &plugin->update_state_hash_message_id); | ||
472 | |||
473 | PREP ("REPLACE INTO state\n" | ||
474 | " (channel_id, name, value_current, value_signed)\n" | ||
475 | "SELECT new.channel_id, new.name, new.value_current, old.value_signed\n" | ||
476 | "FROM (SELECT (SELECT id FROM channels WHERE pub_key = ?) AS channel_id,\n" | ||
477 | " (SELECT ?) AS name,\n" | ||
478 | " (SELECT ?) AS value_current\n" | ||
479 | " ) AS new\n" | ||
480 | "LEFT JOIN (SELECT channel_id, name, value_signed\n" | ||
481 | " FROM state) AS old\n" | ||
482 | "ON new.channel_id = old.channel_id AND new.name = old.name;", | ||
483 | &plugin->insert_state_current); | ||
484 | |||
485 | PREP ("DELETE FROM state\n" | ||
486 | "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" | ||
487 | " AND (value_current IS NULL OR length(value_current) = 0)\n" | ||
488 | " AND (value_signed IS NULL OR length(value_signed) = 0);", | ||
489 | &plugin->delete_state_empty); | ||
490 | |||
491 | PREP ("UPDATE state\n" | ||
492 | "SET value_signed = value_current\n" | ||
493 | "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?);", | ||
494 | &plugin->update_state_signed); | ||
495 | |||
496 | PREP ("DELETE FROM state\n" | ||
497 | "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?);", | ||
498 | &plugin->delete_state); | ||
499 | |||
500 | PREP ("INSERT INTO state_sync (channel_id, name, value)\n" | ||
501 | "VALUES ((SELECT id FROM channels WHERE pub_key = ?), ?, ?);", | ||
502 | &plugin->insert_state_sync); | ||
503 | |||
504 | PREP ("INSERT INTO state\n" | ||
505 | " (channel_id, name, value_current, value_signed)\n" | ||
506 | "SELECT channel_id, name, value, value\n" | ||
507 | "FROM state_sync\n" | ||
508 | "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?);", | ||
509 | &plugin->insert_state_from_sync); | ||
510 | |||
511 | PREP ("DELETE FROM state_sync\n" | ||
512 | "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?);", | ||
513 | &plugin->delete_state_sync); | ||
514 | |||
515 | PREP ("SELECT value_current\n" | ||
516 | "FROM state\n" | ||
517 | "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" | ||
518 | " AND name = ?;", | ||
519 | &plugin->select_state_one); | ||
520 | |||
521 | PREP ("SELECT name, value_current\n" | ||
522 | "FROM state\n" | ||
523 | "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" | ||
524 | " AND (name = ? OR substr(name, 1, ?) = ?);", | ||
525 | &plugin->select_state_prefix); | ||
526 | |||
527 | PREP ("SELECT name, value_signed\n" | ||
528 | "FROM state\n" | ||
529 | "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)" | ||
530 | " AND value_signed IS NOT NULL;", | ||
531 | &plugin->select_state_signed); | ||
532 | #undef PREP | ||
533 | |||
534 | return GNUNET_OK; | ||
535 | } | ||
536 | |||
537 | |||
538 | /** | ||
539 | * Shutdown database connection and associate data | ||
540 | * structures. | ||
541 | * @param plugin the plugin context (state for this module) | ||
542 | */ | ||
543 | static void | ||
544 | database_shutdown (struct Plugin *plugin) | ||
545 | { | ||
546 | GNUNET_MYSQL_context_destroy (plugin->mc); | ||
547 | } | ||
548 | |||
549 | |||
550 | /** | ||
551 | * Execute a prepared statement with a @a channel_key argument. | ||
552 | * | ||
553 | * @param plugin Plugin handle. | ||
554 | * @param stmt Statement to execute. | ||
555 | * @param channel_key Public key of the channel. | ||
556 | * | ||
557 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
558 | */ | ||
559 | static int | ||
560 | exec_channel (struct Plugin *plugin, struct GNUNET_MYSQL_StatementHandle *stmt, | ||
561 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key) | ||
562 | { | ||
563 | struct GNUNET_MY_QueryParam params[] = { | ||
564 | GNUNET_MY_query_param_auto_from_type (channel_key), | ||
565 | GNUNET_MY_query_param_end | ||
566 | }; | ||
567 | |||
568 | if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc, stmt, params)) | ||
569 | { | ||
570 | LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
571 | "mysql exec_channel", stmt); | ||
572 | } | ||
573 | |||
574 | if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt))) | ||
575 | { | ||
576 | LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
577 | "mysql_stmt_reset", stmt); | ||
578 | return GNUNET_SYSERR; | ||
579 | } | ||
580 | |||
581 | return GNUNET_OK; | ||
582 | } | ||
583 | |||
584 | |||
585 | /** | ||
586 | * Begin a transaction. | ||
587 | */ | ||
588 | static int | ||
589 | transaction_begin (struct Plugin *plugin, enum Transactions transaction) | ||
590 | { | ||
591 | if (GNUNET_OK != GNUNET_MYSQL_statement_run (plugin->mc, "BEGIN")) | ||
592 | { | ||
593 | LOG(GNUNET_ERROR_TYPE_ERROR, "transaction_begin failed"); | ||
594 | return GNUNET_SYSERR; | ||
595 | } | ||
596 | |||
597 | plugin->transaction = transaction; | ||
598 | return GNUNET_OK; | ||
599 | } | ||
600 | |||
601 | |||
602 | /** | ||
603 | * Commit current transaction. | ||
604 | */ | ||
605 | static int | ||
606 | transaction_commit (struct Plugin *plugin) | ||
607 | { | ||
608 | if (GNUNET_OK != GNUNET_MYSQL_statement_run (plugin->mc, "COMMIT")) | ||
609 | { | ||
610 | LOG(GNUNET_ERROR_TYPE_ERROR, "transaction_commit failed"); | ||
611 | return GNUNET_SYSERR; | ||
612 | } | ||
613 | |||
614 | plugin->transaction = TRANSACTION_NONE; | ||
615 | return GNUNET_OK; | ||
616 | } | ||
617 | |||
618 | |||
619 | /** | ||
620 | * Roll back current transaction. | ||
621 | */ | ||
622 | static int | ||
623 | transaction_rollback (struct Plugin *plugin) | ||
624 | { | ||
625 | if (GNUNET_OK != GNUNET_MYSQL_statement_run (plugin->mc, "ROLLBACK")) | ||
626 | { | ||
627 | LOG(GNUNET_ERROR_TYPE_ERROR, "transaction_rollback failed"); | ||
628 | return GNUNET_SYSERR; | ||
629 | } | ||
630 | |||
631 | plugin->transaction = TRANSACTION_NONE; | ||
632 | return GNUNET_OK; | ||
633 | } | ||
634 | |||
635 | |||
636 | static int | ||
637 | channel_key_store (struct Plugin *plugin, | ||
638 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key) | ||
639 | { | ||
640 | struct GNUNET_MYSQL_StatementHandle *stmt = plugin->insert_channel_key; | ||
641 | |||
642 | struct GNUNET_MY_QueryParam params[] = { | ||
643 | GNUNET_MY_query_param_auto_from_type (channel_key), | ||
644 | GNUNET_MY_query_param_end | ||
645 | }; | ||
646 | |||
647 | if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc, stmt, params)) | ||
648 | { | ||
649 | LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
650 | "mysql exec_prepared", stmt); | ||
651 | return GNUNET_SYSERR; | ||
652 | } | ||
653 | |||
654 | if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt))) | ||
655 | { | ||
656 | LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
657 | "mysql_stmt_reset", stmt); | ||
658 | return GNUNET_SYSERR; | ||
659 | } | ||
660 | |||
661 | return GNUNET_OK; | ||
662 | } | ||
663 | |||
664 | |||
665 | static int | ||
666 | slave_key_store (struct Plugin *plugin, | ||
667 | const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key) | ||
668 | { | ||
669 | struct GNUNET_MYSQL_StatementHandle *stmt = plugin->insert_slave_key; | ||
670 | |||
671 | struct GNUNET_MY_QueryParam params[] = { | ||
672 | GNUNET_MY_query_param_auto_from_type (slave_key), | ||
673 | GNUNET_MY_query_param_end | ||
674 | }; | ||
675 | |||
676 | if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc, stmt, params)) | ||
677 | { | ||
678 | LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
679 | "mysql exec_prepared", stmt); | ||
680 | return GNUNET_SYSERR; | ||
681 | } | ||
682 | |||
683 | if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt))) | ||
684 | { | ||
685 | LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
686 | "mysql_stmt_reset", stmt); | ||
687 | return GNUNET_SYSERR; | ||
688 | } | ||
689 | |||
690 | return GNUNET_OK; | ||
691 | } | ||
692 | |||
693 | |||
694 | /** | ||
695 | * Store join/leave events for a PSYC channel in order to be able to answer | ||
696 | * membership test queries later. | ||
697 | * | ||
698 | * @see GNUNET_PSYCSTORE_membership_store() | ||
699 | * | ||
700 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
701 | */ | ||
702 | static int | ||
703 | mysql_membership_store (void *cls, | ||
704 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
705 | const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, | ||
706 | int did_join, | ||
707 | uint64_t announced_at, | ||
708 | uint64_t effective_since, | ||
709 | uint64_t group_generation) | ||
710 | { | ||
711 | struct Plugin *plugin = cls; | ||
712 | |||
713 | uint32_t idid_join = (uint32_t)did_join; | ||
714 | |||
715 | struct GNUNET_MYSQL_StatementHandle *stmt = plugin->insert_membership; | ||
716 | |||
717 | GNUNET_assert (TRANSACTION_NONE == plugin->transaction); | ||
718 | |||
719 | if (announced_at > INT64_MAX || | ||
720 | effective_since > INT64_MAX || | ||
721 | group_generation > INT64_MAX) | ||
722 | { | ||
723 | GNUNET_break (0); | ||
724 | return GNUNET_SYSERR; | ||
725 | } | ||
726 | |||
727 | if (GNUNET_OK != channel_key_store (plugin, channel_key) | ||
728 | || GNUNET_OK != slave_key_store (plugin, slave_key)) | ||
729 | return GNUNET_SYSERR; | ||
730 | |||
731 | struct GNUNET_MY_QueryParam params[] = { | ||
732 | GNUNET_MY_query_param_auto_from_type (channel_key), | ||
733 | GNUNET_MY_query_param_auto_from_type (slave_key), | ||
734 | GNUNET_MY_query_param_uint32 (&idid_join), | ||
735 | GNUNET_MY_query_param_uint64 (&announced_at), | ||
736 | GNUNET_MY_query_param_uint64 (&effective_since), | ||
737 | GNUNET_MY_query_param_uint64 (&group_generation), | ||
738 | GNUNET_MY_query_param_end | ||
739 | }; | ||
740 | |||
741 | if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc, stmt, params)) | ||
742 | { | ||
743 | LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
744 | "mysql exec_prepared", stmt); | ||
745 | return GNUNET_SYSERR; | ||
746 | } | ||
747 | |||
748 | if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt))) | ||
749 | { | ||
750 | LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
751 | "mysql_stmt_reset", stmt); | ||
752 | return GNUNET_SYSERR; | ||
753 | } | ||
754 | return GNUNET_OK; | ||
755 | } | ||
756 | |||
757 | /** | ||
758 | * Test if a member was admitted to the channel at the given message ID. | ||
759 | * | ||
760 | * @see GNUNET_PSYCSTORE_membership_test() | ||
761 | * | ||
762 | * @return #GNUNET_YES if the member was admitted, #GNUNET_NO if not, | ||
763 | * #GNUNET_SYSERR if there was en error. | ||
764 | */ | ||
765 | static int | ||
766 | membership_test (void *cls, | ||
767 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
768 | const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, | ||
769 | uint64_t message_id) | ||
770 | { | ||
771 | struct Plugin *plugin = cls; | ||
772 | |||
773 | struct GNUNET_MYSQL_StatementHandle *stmt = plugin->select_membership; | ||
774 | |||
775 | uint32_t did_join = 0; | ||
776 | |||
777 | int ret = GNUNET_SYSERR; | ||
778 | |||
779 | struct GNUNET_MY_QueryParam params_select[] = { | ||
780 | GNUNET_MY_query_param_auto_from_type (channel_key), | ||
781 | GNUNET_MY_query_param_auto_from_type (slave_key), | ||
782 | GNUNET_MY_query_param_uint64 (&message_id), | ||
783 | GNUNET_MY_query_param_end | ||
784 | }; | ||
785 | |||
786 | if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc, stmt, params_select)) | ||
787 | { | ||
788 | LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
789 | "mysql execute prepared", stmt); | ||
790 | return GNUNET_SYSERR; | ||
791 | } | ||
792 | |||
793 | struct GNUNET_MY_ResultSpec results_select[] = { | ||
794 | GNUNET_MY_result_spec_uint32 (&did_join), | ||
795 | GNUNET_MY_result_spec_end | ||
796 | }; | ||
797 | |||
798 | switch (GNUNET_MY_extract_result (stmt, results_select)) | ||
799 | { | ||
800 | case GNUNET_NO: | ||
801 | ret = GNUNET_NO; | ||
802 | break; | ||
803 | case GNUNET_OK: | ||
804 | ret = GNUNET_YES; | ||
805 | break; | ||
806 | default: | ||
807 | LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
808 | "mysql extract_result", stmt); | ||
809 | return GNUNET_SYSERR; | ||
810 | } | ||
811 | |||
812 | if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt))) | ||
813 | { | ||
814 | LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
815 | "mysql_stmt_reset", stmt); | ||
816 | return GNUNET_SYSERR; | ||
817 | } | ||
818 | |||
819 | return ret; | ||
820 | } | ||
821 | |||
822 | /** | ||
823 | * Store a message fragment sent to a channel. | ||
824 | * | ||
825 | * @see GNUNET_PSYCSTORE_fragment_store() | ||
826 | * | ||
827 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
828 | */ | ||
829 | static int | ||
830 | fragment_store (void *cls, | ||
831 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
832 | const struct GNUNET_MULTICAST_MessageHeader *msg, | ||
833 | uint32_t psycstore_flags) | ||
834 | { | ||
835 | struct Plugin *plugin = cls; | ||
836 | |||
837 | struct GNUNET_MYSQL_StatementHandle *stmt = plugin->insert_fragment; | ||
838 | |||
839 | GNUNET_assert (TRANSACTION_NONE == plugin->transaction); | ||
840 | |||
841 | uint64_t fragment_id = GNUNET_ntohll (msg->fragment_id); | ||
842 | |||
843 | uint64_t fragment_offset = GNUNET_ntohll (msg->fragment_offset); | ||
844 | uint64_t message_id = GNUNET_ntohll (msg->message_id); | ||
845 | uint64_t group_generation = GNUNET_ntohll (msg->group_generation); | ||
846 | |||
847 | uint64_t hop_counter = ntohl(msg->hop_counter); | ||
848 | uint64_t flags = ntohl(msg->flags); | ||
849 | |||
850 | if (fragment_id > INT64_MAX || fragment_offset > INT64_MAX || | ||
851 | message_id > INT64_MAX || group_generation > INT64_MAX) | ||
852 | { | ||
853 | LOG(GNUNET_ERROR_TYPE_ERROR, | ||
854 | "Tried to store fragment with a field > INT64_MAX: " | ||
855 | "%lu, %lu, %lu, %lu\n", fragment_id, fragment_offset, | ||
856 | message_id, group_generation); | ||
857 | GNUNET_break (0); | ||
858 | return GNUNET_SYSERR; | ||
859 | } | ||
860 | |||
861 | if (GNUNET_OK != channel_key_store (plugin, channel_key)) | ||
862 | return GNUNET_SYSERR; | ||
863 | |||
864 | struct GNUNET_MY_QueryParam params_insert[] = { | ||
865 | GNUNET_MY_query_param_auto_from_type (channel_key), | ||
866 | GNUNET_MY_query_param_uint64 (&hop_counter), | ||
867 | GNUNET_MY_query_param_auto_from_type (&msg->signature), | ||
868 | GNUNET_MY_query_param_auto_from_type (&msg->purpose), | ||
869 | GNUNET_MY_query_param_uint64 (&fragment_id), | ||
870 | GNUNET_MY_query_param_uint64 (&fragment_offset), | ||
871 | GNUNET_MY_query_param_uint64 (&message_id), | ||
872 | GNUNET_MY_query_param_uint64 (&group_generation), | ||
873 | GNUNET_MY_query_param_uint64 (&flags), | ||
874 | GNUNET_MY_query_param_uint32 (&psycstore_flags), | ||
875 | GNUNET_MY_query_param_fixed_size (&msg[1], ntohs (msg->header.size) | ||
876 | - sizeof (*msg)), | ||
877 | GNUNET_MY_query_param_end | ||
878 | }; | ||
879 | |||
880 | if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc, stmt, params_insert)) | ||
881 | { | ||
882 | LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
883 | "mysql execute prepared", stmt); | ||
884 | return GNUNET_SYSERR; | ||
885 | } | ||
886 | |||
887 | if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt))) | ||
888 | { | ||
889 | LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
890 | "mysql_stmt_reset", stmt); | ||
891 | return GNUNET_SYSERR; | ||
892 | } | ||
893 | |||
894 | return GNUNET_OK; | ||
895 | } | ||
896 | |||
897 | /** | ||
898 | * Set additional flags for a given message. | ||
899 | * | ||
900 | * They are OR'd with any existing flags set. | ||
901 | * | ||
902 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
903 | */ | ||
904 | static int | ||
905 | message_add_flags (void *cls, | ||
906 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
907 | uint64_t message_id, | ||
908 | uint32_t psycstore_flags) | ||
909 | { | ||
910 | struct Plugin *plugin = cls; | ||
911 | struct GNUNET_MYSQL_StatementHandle *stmt = plugin->update_message_flags; | ||
912 | |||
913 | int sql_ret; | ||
914 | int ret = GNUNET_SYSERR; | ||
915 | |||
916 | struct GNUNET_MY_QueryParam params_update[] = { | ||
917 | GNUNET_MY_query_param_uint32 (&psycstore_flags), | ||
918 | GNUNET_MY_query_param_auto_from_type (channel_key), | ||
919 | GNUNET_MY_query_param_uint64 (&message_id), | ||
920 | GNUNET_MY_query_param_end | ||
921 | }; | ||
922 | |||
923 | sql_ret = GNUNET_MY_exec_prepared (plugin->mc, stmt, params_update); | ||
924 | switch (sql_ret) | ||
925 | { | ||
926 | case GNUNET_OK: | ||
927 | ret = GNUNET_OK; | ||
928 | break; | ||
929 | |||
930 | default: | ||
931 | LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
932 | "mysql execute prepared", stmt); | ||
933 | } | ||
934 | |||
935 | if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt))) | ||
936 | { | ||
937 | LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
938 | "mysql_stmt_reset", stmt); | ||
939 | return GNUNET_SYSERR; | ||
940 | } | ||
941 | |||
942 | return ret; | ||
943 | } | ||
944 | |||
945 | |||
946 | static int | ||
947 | fragment_row (struct GNUNET_MYSQL_StatementHandle *stmt, | ||
948 | GNUNET_PSYCSTORE_FragmentCallback cb, | ||
949 | void *cb_cls, | ||
950 | uint64_t *returned_fragments) | ||
951 | { | ||
952 | |||
953 | uint32_t hop_counter; | ||
954 | void *signature = NULL; | ||
955 | void *purpose = NULL; | ||
956 | size_t signature_size; | ||
957 | size_t purpose_size; | ||
958 | uint64_t fragment_id; | ||
959 | uint64_t fragment_offset; | ||
960 | uint64_t message_id; | ||
961 | uint64_t group_generation; | ||
962 | uint64_t flags; | ||
963 | void *buf; | ||
964 | size_t buf_size; | ||
965 | int ret = GNUNET_SYSERR; | ||
966 | int sql_ret; | ||
967 | struct GNUNET_MULTICAST_MessageHeader *mp; | ||
968 | uint64_t msg_flags; | ||
969 | struct GNUNET_MY_ResultSpec results[] = { | ||
970 | GNUNET_MY_result_spec_uint32 (&hop_counter), | ||
971 | GNUNET_MY_result_spec_variable_size (&signature, &signature_size), | ||
972 | GNUNET_MY_result_spec_variable_size (&purpose, &purpose_size), | ||
973 | GNUNET_MY_result_spec_uint64 (&fragment_id), | ||
974 | GNUNET_MY_result_spec_uint64 (&fragment_offset), | ||
975 | GNUNET_MY_result_spec_uint64 (&message_id), | ||
976 | GNUNET_MY_result_spec_uint64 (&group_generation), | ||
977 | GNUNET_MY_result_spec_uint64 (&msg_flags), | ||
978 | GNUNET_MY_result_spec_uint64 (&flags), | ||
979 | GNUNET_MY_result_spec_variable_size (&buf, | ||
980 | &buf_size), | ||
981 | GNUNET_MY_result_spec_end | ||
982 | }; | ||
983 | |||
984 | do | ||
985 | { | ||
986 | sql_ret = GNUNET_MY_extract_result (stmt, results); | ||
987 | switch (sql_ret) | ||
988 | { | ||
989 | case GNUNET_NO: | ||
990 | if (ret != GNUNET_YES) | ||
991 | ret = GNUNET_NO; | ||
992 | break; | ||
993 | |||
994 | case GNUNET_YES: | ||
995 | mp = GNUNET_malloc (sizeof (*mp) + buf_size); | ||
996 | |||
997 | mp->header.size = htons (sizeof (*mp) + buf_size); | ||
998 | mp->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE); | ||
999 | mp->hop_counter = htonl (hop_counter); | ||
1000 | GNUNET_memcpy (&mp->signature, | ||
1001 | signature, | ||
1002 | signature_size); | ||
1003 | GNUNET_memcpy (&mp->purpose, | ||
1004 | purpose, | ||
1005 | purpose_size); | ||
1006 | mp->fragment_id = GNUNET_htonll (fragment_id); | ||
1007 | mp->fragment_offset = GNUNET_htonll (fragment_offset); | ||
1008 | mp->message_id = GNUNET_htonll (message_id); | ||
1009 | mp->group_generation = GNUNET_htonll (group_generation); | ||
1010 | mp->flags = htonl(msg_flags); | ||
1011 | |||
1012 | GNUNET_memcpy (&mp[1], | ||
1013 | buf, | ||
1014 | buf_size); | ||
1015 | ret = cb (cb_cls, mp, (enum GNUNET_PSYCSTORE_MessageFlags) flags); | ||
1016 | if (NULL != returned_fragments) | ||
1017 | (*returned_fragments)++; | ||
1018 | GNUNET_MY_cleanup_result (results); | ||
1019 | break; | ||
1020 | |||
1021 | default: | ||
1022 | LOG_MYSQL (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1023 | "mysql extract_result", stmt); | ||
1024 | } | ||
1025 | } | ||
1026 | while (GNUNET_YES == sql_ret); | ||
1027 | |||
1028 | // for debugging | ||
1029 | if (GNUNET_NO == ret) | ||
1030 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, | ||
1031 | "Empty result set\n"); | ||
1032 | |||
1033 | return ret; | ||
1034 | } | ||
1035 | |||
1036 | |||
1037 | static int | ||
1038 | fragment_select (struct Plugin *plugin, | ||
1039 | struct GNUNET_MYSQL_StatementHandle *stmt, | ||
1040 | struct GNUNET_MY_QueryParam *params, | ||
1041 | uint64_t *returned_fragments, | ||
1042 | GNUNET_PSYCSTORE_FragmentCallback cb, | ||
1043 | void *cb_cls) | ||
1044 | { | ||
1045 | int ret = GNUNET_SYSERR; | ||
1046 | int sql_ret; | ||
1047 | |||
1048 | sql_ret = GNUNET_MY_exec_prepared (plugin->mc, stmt, params); | ||
1049 | switch (sql_ret) | ||
1050 | { | ||
1051 | case GNUNET_NO: | ||
1052 | if (ret != GNUNET_YES) | ||
1053 | ret = GNUNET_NO; | ||
1054 | break; | ||
1055 | |||
1056 | case GNUNET_YES: | ||
1057 | ret = fragment_row (stmt, cb, cb_cls, returned_fragments); | ||
1058 | break; | ||
1059 | |||
1060 | default: | ||
1061 | LOG_MYSQL (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1062 | "mysql exec_prepared", stmt); | ||
1063 | } | ||
1064 | return ret; | ||
1065 | } | ||
1066 | |||
1067 | |||
1068 | /** | ||
1069 | * Retrieve a message fragment range by fragment ID. | ||
1070 | * | ||
1071 | * @see GNUNET_PSYCSTORE_fragment_get() | ||
1072 | * | ||
1073 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
1074 | */ | ||
1075 | static int | ||
1076 | fragment_get (void *cls, | ||
1077 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1078 | uint64_t first_fragment_id, | ||
1079 | uint64_t last_fragment_id, | ||
1080 | uint64_t *returned_fragments, | ||
1081 | GNUNET_PSYCSTORE_FragmentCallback cb, | ||
1082 | void *cb_cls) | ||
1083 | { | ||
1084 | struct Plugin *plugin = cls; | ||
1085 | struct GNUNET_MYSQL_StatementHandle *stmt = plugin->select_fragments; | ||
1086 | int ret = GNUNET_SYSERR; | ||
1087 | struct GNUNET_MY_QueryParam params_select[] = { | ||
1088 | GNUNET_MY_query_param_auto_from_type (channel_key), | ||
1089 | GNUNET_MY_query_param_uint64 (&first_fragment_id), | ||
1090 | GNUNET_MY_query_param_uint64 (&last_fragment_id), | ||
1091 | GNUNET_MY_query_param_end | ||
1092 | }; | ||
1093 | |||
1094 | *returned_fragments = 0; | ||
1095 | ret = fragment_select (plugin, stmt, params_select, returned_fragments, cb, cb_cls); | ||
1096 | |||
1097 | if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt))) | ||
1098 | { | ||
1099 | LOG_MYSQL (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1100 | "mysql_stmt_reset", stmt); | ||
1101 | return GNUNET_SYSERR; | ||
1102 | } | ||
1103 | |||
1104 | return ret; | ||
1105 | } | ||
1106 | |||
1107 | |||
1108 | /** | ||
1109 | * Retrieve a message fragment range by fragment ID. | ||
1110 | * | ||
1111 | * @see GNUNET_PSYCSTORE_fragment_get_latest() | ||
1112 | * | ||
1113 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
1114 | */ | ||
1115 | static int | ||
1116 | fragment_get_latest (void *cls, | ||
1117 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1118 | uint64_t fragment_limit, | ||
1119 | uint64_t *returned_fragments, | ||
1120 | GNUNET_PSYCSTORE_FragmentCallback cb, | ||
1121 | void *cb_cls) | ||
1122 | { | ||
1123 | struct Plugin *plugin = cls; | ||
1124 | |||
1125 | struct GNUNET_MYSQL_StatementHandle *stmt = plugin->select_latest_fragments; | ||
1126 | |||
1127 | int ret = GNUNET_SYSERR; | ||
1128 | *returned_fragments = 0; | ||
1129 | |||
1130 | struct GNUNET_MY_QueryParam params_select[] = { | ||
1131 | GNUNET_MY_query_param_auto_from_type (channel_key), | ||
1132 | GNUNET_MY_query_param_uint64 (&fragment_limit), | ||
1133 | GNUNET_MY_query_param_end | ||
1134 | }; | ||
1135 | |||
1136 | ret = fragment_select (plugin, stmt, params_select, returned_fragments, cb, cb_cls); | ||
1137 | |||
1138 | if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt))) | ||
1139 | { | ||
1140 | LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1141 | "mysql_stmt_reset", stmt); | ||
1142 | return GNUNET_SYSERR; | ||
1143 | } | ||
1144 | |||
1145 | return ret; | ||
1146 | } | ||
1147 | |||
1148 | |||
1149 | /** | ||
1150 | * Retrieve all fragments of a message ID range. | ||
1151 | * | ||
1152 | * @see GNUNET_PSYCSTORE_message_get() | ||
1153 | * | ||
1154 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
1155 | */ | ||
1156 | static int | ||
1157 | message_get (void *cls, | ||
1158 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1159 | uint64_t first_message_id, | ||
1160 | uint64_t last_message_id, | ||
1161 | uint64_t fragment_limit, | ||
1162 | uint64_t *returned_fragments, | ||
1163 | GNUNET_PSYCSTORE_FragmentCallback cb, | ||
1164 | void *cb_cls) | ||
1165 | { | ||
1166 | struct Plugin *plugin = cls; | ||
1167 | struct GNUNET_MYSQL_StatementHandle *stmt = plugin->select_messages; | ||
1168 | int ret; | ||
1169 | |||
1170 | if (0 == fragment_limit) | ||
1171 | fragment_limit = UINT64_MAX; | ||
1172 | |||
1173 | struct GNUNET_MY_QueryParam params_select[] = { | ||
1174 | GNUNET_MY_query_param_auto_from_type (channel_key), | ||
1175 | GNUNET_MY_query_param_uint64 (&first_message_id), | ||
1176 | GNUNET_MY_query_param_uint64 (&last_message_id), | ||
1177 | GNUNET_MY_query_param_uint64 (&fragment_limit), | ||
1178 | GNUNET_MY_query_param_end | ||
1179 | }; | ||
1180 | |||
1181 | *returned_fragments = 0; | ||
1182 | ret = fragment_select (plugin, stmt, params_select, returned_fragments, cb, cb_cls); | ||
1183 | |||
1184 | if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt))) | ||
1185 | { | ||
1186 | LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1187 | "mysql_stmt_reset", stmt); | ||
1188 | return GNUNET_SYSERR; | ||
1189 | } | ||
1190 | |||
1191 | return ret; | ||
1192 | } | ||
1193 | |||
1194 | |||
1195 | /** | ||
1196 | * Retrieve all fragments of the latest messages. | ||
1197 | * | ||
1198 | * @see GNUNET_PSYCSTORE_message_get_latest() | ||
1199 | * | ||
1200 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
1201 | */ | ||
1202 | static int | ||
1203 | message_get_latest (void *cls, | ||
1204 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1205 | uint64_t message_limit, | ||
1206 | uint64_t *returned_fragments, | ||
1207 | GNUNET_PSYCSTORE_FragmentCallback cb, | ||
1208 | void *cb_cls) | ||
1209 | { | ||
1210 | struct Plugin *plugin = cls; | ||
1211 | |||
1212 | struct GNUNET_MYSQL_StatementHandle *stmt = plugin->select_latest_messages; | ||
1213 | |||
1214 | int ret = GNUNET_SYSERR; | ||
1215 | *returned_fragments = 0; | ||
1216 | |||
1217 | struct GNUNET_MY_QueryParam params_select[] = { | ||
1218 | GNUNET_MY_query_param_auto_from_type (channel_key), | ||
1219 | GNUNET_MY_query_param_auto_from_type (channel_key), | ||
1220 | GNUNET_MY_query_param_uint64 (&message_limit), | ||
1221 | GNUNET_MY_query_param_end | ||
1222 | }; | ||
1223 | |||
1224 | ret = fragment_select (plugin, stmt, params_select, returned_fragments, cb, cb_cls); | ||
1225 | |||
1226 | if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt))) | ||
1227 | { | ||
1228 | LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1229 | "mysql_stmt_reset", stmt); | ||
1230 | return GNUNET_SYSERR; | ||
1231 | } | ||
1232 | |||
1233 | return ret; | ||
1234 | } | ||
1235 | |||
1236 | |||
1237 | /** | ||
1238 | * Retrieve a fragment of message specified by its message ID and fragment | ||
1239 | * offset. | ||
1240 | * | ||
1241 | * @see GNUNET_PSYCSTORE_message_get_fragment() | ||
1242 | * | ||
1243 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
1244 | */ | ||
1245 | static int | ||
1246 | message_get_fragment (void *cls, | ||
1247 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1248 | uint64_t message_id, | ||
1249 | uint64_t fragment_offset, | ||
1250 | GNUNET_PSYCSTORE_FragmentCallback cb, | ||
1251 | void *cb_cls) | ||
1252 | { | ||
1253 | struct Plugin *plugin = cls; | ||
1254 | struct GNUNET_MYSQL_StatementHandle *stmt = plugin->select_message_fragment; | ||
1255 | int sql_ret; | ||
1256 | int ret = GNUNET_SYSERR; | ||
1257 | |||
1258 | struct GNUNET_MY_QueryParam params_select[] = { | ||
1259 | GNUNET_MY_query_param_auto_from_type (channel_key), | ||
1260 | GNUNET_MY_query_param_uint64 (&message_id), | ||
1261 | GNUNET_MY_query_param_uint64 (&fragment_offset), | ||
1262 | GNUNET_MY_query_param_end | ||
1263 | }; | ||
1264 | |||
1265 | sql_ret = GNUNET_MY_exec_prepared (plugin->mc, stmt, params_select); | ||
1266 | switch (sql_ret) | ||
1267 | { | ||
1268 | case GNUNET_NO: | ||
1269 | ret = GNUNET_NO; | ||
1270 | break; | ||
1271 | |||
1272 | case GNUNET_OK: | ||
1273 | ret = fragment_row (stmt, cb, cb_cls, NULL); | ||
1274 | break; | ||
1275 | |||
1276 | default: | ||
1277 | LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1278 | "mysql execute prepared", stmt); | ||
1279 | } | ||
1280 | |||
1281 | if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt))) | ||
1282 | { | ||
1283 | LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1284 | "mysql_stmt_reset", stmt); | ||
1285 | return GNUNET_SYSERR; | ||
1286 | } | ||
1287 | |||
1288 | return ret; | ||
1289 | } | ||
1290 | |||
1291 | /** | ||
1292 | * Retrieve the max. values of message counters for a channel. | ||
1293 | * | ||
1294 | * @see GNUNET_PSYCSTORE_counters_get() | ||
1295 | * | ||
1296 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
1297 | */ | ||
1298 | static int | ||
1299 | counters_message_get (void *cls, | ||
1300 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1301 | uint64_t *max_fragment_id, | ||
1302 | uint64_t *max_message_id, | ||
1303 | uint64_t *max_group_generation) | ||
1304 | { | ||
1305 | struct Plugin *plugin = cls; | ||
1306 | |||
1307 | struct GNUNET_MYSQL_StatementHandle *stmt = plugin->select_counters_message; | ||
1308 | |||
1309 | int ret = GNUNET_SYSERR; | ||
1310 | |||
1311 | struct GNUNET_MY_QueryParam params_select[] = { | ||
1312 | GNUNET_MY_query_param_auto_from_type (channel_key), | ||
1313 | GNUNET_MY_query_param_end | ||
1314 | }; | ||
1315 | |||
1316 | if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc, stmt, params_select)) | ||
1317 | { | ||
1318 | LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1319 | "mysql execute prepared", stmt); | ||
1320 | return GNUNET_SYSERR; | ||
1321 | } | ||
1322 | |||
1323 | struct GNUNET_MY_ResultSpec results_select[] = { | ||
1324 | GNUNET_MY_result_spec_uint64 (max_fragment_id), | ||
1325 | GNUNET_MY_result_spec_uint64 (max_message_id), | ||
1326 | GNUNET_MY_result_spec_uint64 (max_group_generation), | ||
1327 | GNUNET_MY_result_spec_end | ||
1328 | }; | ||
1329 | |||
1330 | ret = GNUNET_MY_extract_result (stmt, results_select); | ||
1331 | |||
1332 | if (GNUNET_OK != ret) | ||
1333 | { | ||
1334 | LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1335 | "mysql extract_result", stmt); | ||
1336 | return GNUNET_SYSERR; | ||
1337 | } | ||
1338 | |||
1339 | if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt))) | ||
1340 | { | ||
1341 | LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1342 | "mysql_stmt_reset", stmt); | ||
1343 | return GNUNET_SYSERR; | ||
1344 | } | ||
1345 | |||
1346 | return ret; | ||
1347 | } | ||
1348 | |||
1349 | /** | ||
1350 | * Retrieve the max. values of state counters for a channel. | ||
1351 | * | ||
1352 | * @see GNUNET_PSYCSTORE_counters_get() | ||
1353 | * | ||
1354 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
1355 | */ | ||
1356 | static int | ||
1357 | counters_state_get (void *cls, | ||
1358 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1359 | uint64_t *max_state_message_id) | ||
1360 | { | ||
1361 | struct Plugin *plugin = cls; | ||
1362 | |||
1363 | struct GNUNET_MYSQL_StatementHandle *stmt = plugin->select_counters_state; | ||
1364 | |||
1365 | int ret = GNUNET_SYSERR; | ||
1366 | |||
1367 | struct GNUNET_MY_QueryParam params_select[] = { | ||
1368 | GNUNET_MY_query_param_auto_from_type (channel_key), | ||
1369 | GNUNET_MY_query_param_end | ||
1370 | }; | ||
1371 | |||
1372 | if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc, stmt, params_select)) | ||
1373 | { | ||
1374 | LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1375 | "mysql execute prepared", stmt); | ||
1376 | return GNUNET_SYSERR; | ||
1377 | } | ||
1378 | |||
1379 | struct GNUNET_MY_ResultSpec results_select[] = { | ||
1380 | GNUNET_MY_result_spec_uint64 (max_state_message_id), | ||
1381 | GNUNET_MY_result_spec_end | ||
1382 | }; | ||
1383 | |||
1384 | ret = GNUNET_MY_extract_result (stmt, results_select); | ||
1385 | |||
1386 | if (GNUNET_OK != ret) | ||
1387 | { | ||
1388 | LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1389 | "mysql extract_result", stmt); | ||
1390 | return GNUNET_SYSERR; | ||
1391 | } | ||
1392 | |||
1393 | if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt))) | ||
1394 | { | ||
1395 | LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1396 | "mysql_stmt_reset", stmt); | ||
1397 | return GNUNET_SYSERR; | ||
1398 | } | ||
1399 | |||
1400 | return ret; | ||
1401 | } | ||
1402 | |||
1403 | |||
1404 | /** | ||
1405 | * Assign a value to a state variable. | ||
1406 | * | ||
1407 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
1408 | */ | ||
1409 | static int | ||
1410 | state_assign (struct Plugin *plugin, struct GNUNET_MYSQL_StatementHandle *stmt, | ||
1411 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1412 | const char *name, const void *value, size_t value_size) | ||
1413 | { | ||
1414 | int ret = GNUNET_SYSERR; | ||
1415 | |||
1416 | struct GNUNET_MY_QueryParam params[] = { | ||
1417 | GNUNET_MY_query_param_auto_from_type (channel_key), | ||
1418 | GNUNET_MY_query_param_string (name), | ||
1419 | GNUNET_MY_query_param_fixed_size(value, value_size), | ||
1420 | GNUNET_MY_query_param_end | ||
1421 | }; | ||
1422 | |||
1423 | ret = GNUNET_MY_exec_prepared (plugin->mc, stmt, params); | ||
1424 | if (GNUNET_OK != ret) | ||
1425 | { | ||
1426 | LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1427 | "mysql exec_prepared", stmt); | ||
1428 | return GNUNET_SYSERR; | ||
1429 | } | ||
1430 | |||
1431 | if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt))) | ||
1432 | { | ||
1433 | LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1434 | "mysql_stmt_reset", stmt); | ||
1435 | return GNUNET_SYSERR; | ||
1436 | } | ||
1437 | |||
1438 | return ret; | ||
1439 | } | ||
1440 | |||
1441 | |||
1442 | static int | ||
1443 | update_message_id (struct Plugin *plugin, struct GNUNET_MYSQL_StatementHandle *stmt, | ||
1444 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1445 | uint64_t message_id) | ||
1446 | { | ||
1447 | struct GNUNET_MY_QueryParam params[] = { | ||
1448 | GNUNET_MY_query_param_uint64 (&message_id), | ||
1449 | GNUNET_MY_query_param_auto_from_type (channel_key), | ||
1450 | GNUNET_MY_query_param_end | ||
1451 | }; | ||
1452 | |||
1453 | if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc, | ||
1454 | stmt, | ||
1455 | params)) | ||
1456 | { | ||
1457 | LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1458 | "mysql execute prepared", stmt); | ||
1459 | return GNUNET_SYSERR; | ||
1460 | } | ||
1461 | |||
1462 | if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt))) | ||
1463 | { | ||
1464 | LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1465 | "mysql_stmt_reset", stmt); | ||
1466 | return GNUNET_SYSERR; | ||
1467 | } | ||
1468 | |||
1469 | return GNUNET_OK; | ||
1470 | } | ||
1471 | |||
1472 | |||
1473 | /** | ||
1474 | * Begin modifying current state. | ||
1475 | */ | ||
1476 | static int | ||
1477 | state_modify_begin (void *cls, | ||
1478 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1479 | uint64_t message_id, uint64_t state_delta) | ||
1480 | { | ||
1481 | struct Plugin *plugin = cls; | ||
1482 | |||
1483 | if (state_delta > 0) | ||
1484 | { | ||
1485 | /** | ||
1486 | * We can only apply state modifiers in the current message if modifiers in | ||
1487 | * the previous stateful message (message_id - state_delta) were already | ||
1488 | * applied. | ||
1489 | */ | ||
1490 | |||
1491 | uint64_t max_state_message_id = 0; | ||
1492 | int ret = counters_state_get (plugin, channel_key, &max_state_message_id); | ||
1493 | switch (ret) | ||
1494 | { | ||
1495 | case GNUNET_OK: | ||
1496 | case GNUNET_NO: // no state yet | ||
1497 | ret = GNUNET_OK; | ||
1498 | break; | ||
1499 | default: | ||
1500 | return ret; | ||
1501 | } | ||
1502 | |||
1503 | if (max_state_message_id < message_id - state_delta) | ||
1504 | return GNUNET_NO; /* some stateful messages not yet applied */ | ||
1505 | else if (message_id - state_delta < max_state_message_id) | ||
1506 | return GNUNET_NO; /* changes already applied */ | ||
1507 | } | ||
1508 | |||
1509 | if (TRANSACTION_NONE != plugin->transaction) | ||
1510 | { | ||
1511 | /** @todo FIXME: wait for other transaction to finish */ | ||
1512 | return GNUNET_SYSERR; | ||
1513 | } | ||
1514 | return transaction_begin (plugin, TRANSACTION_STATE_MODIFY); | ||
1515 | } | ||
1516 | |||
1517 | |||
1518 | /** | ||
1519 | * Set the current value of state variable. | ||
1520 | * | ||
1521 | * @see GNUNET_PSYCSTORE_state_modify() | ||
1522 | * | ||
1523 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
1524 | */ | ||
1525 | static int | ||
1526 | state_modify_op (void *cls, | ||
1527 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1528 | enum GNUNET_PSYC_Operator op, | ||
1529 | const char *name, const void *value, size_t value_size) | ||
1530 | { | ||
1531 | struct Plugin *plugin = cls; | ||
1532 | GNUNET_assert (TRANSACTION_STATE_MODIFY == plugin->transaction); | ||
1533 | |||
1534 | switch (op) | ||
1535 | { | ||
1536 | case GNUNET_PSYC_OP_ASSIGN: | ||
1537 | return state_assign (plugin, plugin->insert_state_current, | ||
1538 | channel_key, name, value, value_size); | ||
1539 | |||
1540 | default: /** @todo implement more state operations */ | ||
1541 | GNUNET_break (0); | ||
1542 | return GNUNET_SYSERR; | ||
1543 | } | ||
1544 | } | ||
1545 | |||
1546 | |||
1547 | /** | ||
1548 | * End modifying current state. | ||
1549 | */ | ||
1550 | static int | ||
1551 | state_modify_end (void *cls, | ||
1552 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1553 | uint64_t message_id) | ||
1554 | { | ||
1555 | struct Plugin *plugin = cls; | ||
1556 | GNUNET_assert (TRANSACTION_STATE_MODIFY == plugin->transaction); | ||
1557 | |||
1558 | return | ||
1559 | GNUNET_OK == exec_channel (plugin, plugin->delete_state_empty, channel_key) | ||
1560 | && GNUNET_OK == update_message_id (plugin, | ||
1561 | plugin->update_max_state_message_id, | ||
1562 | channel_key, message_id) | ||
1563 | && GNUNET_OK == transaction_commit (plugin) | ||
1564 | ? GNUNET_OK : GNUNET_SYSERR; | ||
1565 | } | ||
1566 | |||
1567 | |||
1568 | /** | ||
1569 | * Begin state synchronization. | ||
1570 | */ | ||
1571 | static int | ||
1572 | state_sync_begin (void *cls, | ||
1573 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key) | ||
1574 | { | ||
1575 | struct Plugin *plugin = cls; | ||
1576 | return exec_channel (plugin, plugin->delete_state_sync, channel_key); | ||
1577 | } | ||
1578 | |||
1579 | |||
1580 | /** | ||
1581 | * Assign current value of a state variable. | ||
1582 | * | ||
1583 | * @see GNUNET_PSYCSTORE_state_modify() | ||
1584 | * | ||
1585 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
1586 | */ | ||
1587 | static int | ||
1588 | state_sync_assign (void *cls, | ||
1589 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1590 | const char *name, const void *value, size_t value_size) | ||
1591 | { | ||
1592 | struct Plugin *plugin = cls; | ||
1593 | return state_assign (cls, plugin->insert_state_sync, | ||
1594 | channel_key, name, value, value_size); | ||
1595 | } | ||
1596 | |||
1597 | |||
1598 | /** | ||
1599 | * End modifying current state. | ||
1600 | */ | ||
1601 | static int | ||
1602 | state_sync_end (void *cls, | ||
1603 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1604 | uint64_t max_state_message_id, | ||
1605 | uint64_t state_hash_message_id) | ||
1606 | { | ||
1607 | struct Plugin *plugin = cls; | ||
1608 | int ret = GNUNET_SYSERR; | ||
1609 | |||
1610 | if (TRANSACTION_NONE != plugin->transaction) | ||
1611 | { | ||
1612 | /** @todo FIXME: wait for other transaction to finish */ | ||
1613 | return GNUNET_SYSERR; | ||
1614 | } | ||
1615 | |||
1616 | GNUNET_OK == transaction_begin (plugin, TRANSACTION_STATE_SYNC) | ||
1617 | && GNUNET_OK == exec_channel (plugin, plugin->delete_state, channel_key) | ||
1618 | && GNUNET_OK == exec_channel (plugin, plugin->insert_state_from_sync, | ||
1619 | channel_key) | ||
1620 | && GNUNET_OK == exec_channel (plugin, plugin->delete_state_sync, | ||
1621 | channel_key) | ||
1622 | && GNUNET_OK == update_message_id (plugin, | ||
1623 | plugin->update_state_hash_message_id, | ||
1624 | channel_key, state_hash_message_id) | ||
1625 | && GNUNET_OK == update_message_id (plugin, | ||
1626 | plugin->update_max_state_message_id, | ||
1627 | channel_key, max_state_message_id) | ||
1628 | && GNUNET_OK == transaction_commit (plugin) | ||
1629 | ? ret = GNUNET_OK | ||
1630 | : transaction_rollback (plugin); | ||
1631 | return ret; | ||
1632 | } | ||
1633 | |||
1634 | |||
1635 | /** | ||
1636 | * Delete the whole state. | ||
1637 | * | ||
1638 | * @see GNUNET_PSYCSTORE_state_reset() | ||
1639 | * | ||
1640 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
1641 | */ | ||
1642 | static int | ||
1643 | state_reset (void *cls, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key) | ||
1644 | { | ||
1645 | struct Plugin *plugin = cls; | ||
1646 | return exec_channel (plugin, plugin->delete_state, channel_key); | ||
1647 | } | ||
1648 | |||
1649 | |||
1650 | /** | ||
1651 | * Update signed values of state variables in the state store. | ||
1652 | * | ||
1653 | * @see GNUNET_PSYCSTORE_state_hash_update() | ||
1654 | * | ||
1655 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
1656 | */ | ||
1657 | static int | ||
1658 | state_update_signed (void *cls, | ||
1659 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key) | ||
1660 | { | ||
1661 | struct Plugin *plugin = cls; | ||
1662 | return exec_channel (plugin, plugin->update_state_signed, channel_key); | ||
1663 | } | ||
1664 | |||
1665 | |||
1666 | /** | ||
1667 | * Retrieve a state variable by name. | ||
1668 | * | ||
1669 | * @see GNUNET_PSYCSTORE_state_get() | ||
1670 | * | ||
1671 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
1672 | */ | ||
1673 | static int | ||
1674 | state_get (void *cls, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1675 | const char *name, GNUNET_PSYCSTORE_StateCallback cb, void *cb_cls) | ||
1676 | { | ||
1677 | struct Plugin *plugin = cls; | ||
1678 | int ret = GNUNET_SYSERR; | ||
1679 | int sql_ret ; | ||
1680 | |||
1681 | struct GNUNET_MYSQL_StatementHandle *stmt = plugin->select_state_one; | ||
1682 | |||
1683 | struct GNUNET_MY_QueryParam params_select[] = { | ||
1684 | GNUNET_MY_query_param_auto_from_type (channel_key), | ||
1685 | GNUNET_MY_query_param_string (name), | ||
1686 | GNUNET_MY_query_param_end | ||
1687 | }; | ||
1688 | |||
1689 | void *value_current = NULL; | ||
1690 | size_t value_size = 0; | ||
1691 | |||
1692 | struct GNUNET_MY_ResultSpec results[] = { | ||
1693 | GNUNET_MY_result_spec_variable_size (&value_current, &value_size), | ||
1694 | GNUNET_MY_result_spec_end | ||
1695 | }; | ||
1696 | |||
1697 | if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc, stmt, params_select)) | ||
1698 | { | ||
1699 | LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1700 | "mysql exec_prepared", stmt); | ||
1701 | } | ||
1702 | else | ||
1703 | { | ||
1704 | sql_ret = GNUNET_MY_extract_result (stmt, results); | ||
1705 | switch (sql_ret) | ||
1706 | { | ||
1707 | case GNUNET_NO: | ||
1708 | ret = GNUNET_NO; | ||
1709 | break; | ||
1710 | |||
1711 | case GNUNET_YES: | ||
1712 | ret = cb (cb_cls, name, value_current, value_size); | ||
1713 | break; | ||
1714 | |||
1715 | default: | ||
1716 | LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1717 | "mysql extract_result", stmt); | ||
1718 | } | ||
1719 | } | ||
1720 | |||
1721 | if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt))) | ||
1722 | { | ||
1723 | LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1724 | "mysql_stmt_reset", stmt); | ||
1725 | return GNUNET_SYSERR; | ||
1726 | } | ||
1727 | |||
1728 | return ret; | ||
1729 | } | ||
1730 | |||
1731 | |||
1732 | /** | ||
1733 | * Retrieve all state variables for a channel with the given prefix. | ||
1734 | * | ||
1735 | * @see GNUNET_PSYCSTORE_state_get_prefix() | ||
1736 | * | ||
1737 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
1738 | */ | ||
1739 | static int | ||
1740 | state_get_prefix (void *cls, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1741 | const char *name, GNUNET_PSYCSTORE_StateCallback cb, | ||
1742 | void *cb_cls) | ||
1743 | { | ||
1744 | struct Plugin *plugin = cls; | ||
1745 | int ret = GNUNET_SYSERR; | ||
1746 | |||
1747 | struct GNUNET_MYSQL_StatementHandle *stmt = plugin->select_state_prefix; | ||
1748 | |||
1749 | uint32_t name_len = (uint32_t) strlen (name); | ||
1750 | |||
1751 | struct GNUNET_MY_QueryParam params_select[] = { | ||
1752 | GNUNET_MY_query_param_auto_from_type (channel_key), | ||
1753 | GNUNET_MY_query_param_string (name), | ||
1754 | GNUNET_MY_query_param_uint32 (&name_len), | ||
1755 | GNUNET_MY_query_param_string (name), | ||
1756 | GNUNET_MY_query_param_end | ||
1757 | }; | ||
1758 | |||
1759 | char *name2 = ""; | ||
1760 | void *value_current = NULL; | ||
1761 | size_t value_size = 0; | ||
1762 | |||
1763 | struct GNUNET_MY_ResultSpec results[] = { | ||
1764 | GNUNET_MY_result_spec_string (&name2), | ||
1765 | GNUNET_MY_result_spec_variable_size (&value_current, &value_size), | ||
1766 | GNUNET_MY_result_spec_end | ||
1767 | };; | ||
1768 | |||
1769 | int sql_ret; | ||
1770 | |||
1771 | if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc, stmt, params_select)) | ||
1772 | { | ||
1773 | LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1774 | "mysql exec_prepared", stmt); | ||
1775 | return GNUNET_SYSERR; | ||
1776 | } | ||
1777 | |||
1778 | do | ||
1779 | { | ||
1780 | sql_ret = GNUNET_MY_extract_result (stmt, results); | ||
1781 | switch (sql_ret) | ||
1782 | { | ||
1783 | case GNUNET_NO: | ||
1784 | if (ret != GNUNET_YES) | ||
1785 | ret = GNUNET_NO; | ||
1786 | break; | ||
1787 | |||
1788 | case GNUNET_YES: | ||
1789 | ret = cb (cb_cls, (const char *) name2, value_current, value_size); | ||
1790 | |||
1791 | if (ret != GNUNET_YES) | ||
1792 | sql_ret = GNUNET_NO; | ||
1793 | break; | ||
1794 | |||
1795 | default: | ||
1796 | LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1797 | "mysql extract_result", stmt); | ||
1798 | } | ||
1799 | } | ||
1800 | while (sql_ret == GNUNET_YES); | ||
1801 | |||
1802 | if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt))) | ||
1803 | { | ||
1804 | LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1805 | "mysql_stmt_reset", stmt); | ||
1806 | return GNUNET_SYSERR; | ||
1807 | } | ||
1808 | |||
1809 | return ret; | ||
1810 | } | ||
1811 | |||
1812 | |||
1813 | /** | ||
1814 | * Retrieve all signed state variables for a channel. | ||
1815 | * | ||
1816 | * @see GNUNET_PSYCSTORE_state_get_signed() | ||
1817 | * | ||
1818 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
1819 | */ | ||
1820 | static int | ||
1821 | state_get_signed (void *cls, | ||
1822 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1823 | GNUNET_PSYCSTORE_StateCallback cb, void *cb_cls) | ||
1824 | { | ||
1825 | struct Plugin *plugin = cls; | ||
1826 | int ret = GNUNET_SYSERR; | ||
1827 | |||
1828 | struct GNUNET_MYSQL_StatementHandle *stmt = plugin->select_state_signed; | ||
1829 | |||
1830 | struct GNUNET_MY_QueryParam params_select[] = { | ||
1831 | GNUNET_MY_query_param_auto_from_type (channel_key), | ||
1832 | GNUNET_MY_query_param_end | ||
1833 | }; | ||
1834 | |||
1835 | int sql_ret; | ||
1836 | |||
1837 | char *name = ""; | ||
1838 | void *value_signed = NULL; | ||
1839 | size_t value_size = 0; | ||
1840 | |||
1841 | struct GNUNET_MY_ResultSpec results[] = { | ||
1842 | GNUNET_MY_result_spec_string (&name), | ||
1843 | GNUNET_MY_result_spec_variable_size (&value_signed, &value_size), | ||
1844 | GNUNET_MY_result_spec_end | ||
1845 | }; | ||
1846 | |||
1847 | if (GNUNET_OK != GNUNET_MY_exec_prepared (plugin->mc, stmt, params_select)) | ||
1848 | { | ||
1849 | LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1850 | "mysql exec_prepared", stmt); | ||
1851 | return GNUNET_SYSERR; | ||
1852 | } | ||
1853 | |||
1854 | do | ||
1855 | { | ||
1856 | sql_ret = GNUNET_MY_extract_result (stmt, results); | ||
1857 | switch (sql_ret) | ||
1858 | { | ||
1859 | case GNUNET_NO: | ||
1860 | if (ret != GNUNET_YES) | ||
1861 | ret = GNUNET_NO; | ||
1862 | break; | ||
1863 | |||
1864 | case GNUNET_YES: | ||
1865 | ret = cb (cb_cls, (const char *) name, value_signed, value_size); | ||
1866 | |||
1867 | if (ret != GNUNET_YES) | ||
1868 | sql_ret = GNUNET_NO; | ||
1869 | break; | ||
1870 | |||
1871 | default: | ||
1872 | LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1873 | "mysql extract_result", stmt); | ||
1874 | } | ||
1875 | } | ||
1876 | while (sql_ret == GNUNET_YES); | ||
1877 | |||
1878 | if (0 != mysql_stmt_reset (GNUNET_MYSQL_statement_get_stmt (stmt))) | ||
1879 | { | ||
1880 | LOG_MYSQL(plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1881 | "mysql_stmt_reset", stmt); | ||
1882 | return GNUNET_SYSERR; | ||
1883 | } | ||
1884 | |||
1885 | return ret; | ||
1886 | } | ||
1887 | |||
1888 | |||
1889 | /** | ||
1890 | * Entry point for the plugin. | ||
1891 | * | ||
1892 | * @param cls The struct GNUNET_CONFIGURATION_Handle. | ||
1893 | * @return NULL on error, otherwise the plugin context | ||
1894 | */ | ||
1895 | void * | ||
1896 | libgnunet_plugin_psycstore_mysql_init (void *cls) | ||
1897 | { | ||
1898 | static struct Plugin plugin; | ||
1899 | const struct GNUNET_CONFIGURATION_Handle *cfg = cls; | ||
1900 | struct GNUNET_PSYCSTORE_PluginFunctions *api; | ||
1901 | |||
1902 | if (NULL != plugin.cfg) | ||
1903 | return NULL; /* can only initialize once! */ | ||
1904 | memset (&plugin, 0, sizeof (struct Plugin)); | ||
1905 | plugin.cfg = cfg; | ||
1906 | if (GNUNET_OK != database_setup (&plugin)) | ||
1907 | { | ||
1908 | database_shutdown (&plugin); | ||
1909 | return NULL; | ||
1910 | } | ||
1911 | api = GNUNET_new (struct GNUNET_PSYCSTORE_PluginFunctions); | ||
1912 | api->cls = &plugin; | ||
1913 | api->membership_store = &mysql_membership_store; | ||
1914 | api->membership_test = &membership_test; | ||
1915 | api->fragment_store = &fragment_store; | ||
1916 | api->message_add_flags = &message_add_flags; | ||
1917 | api->fragment_get = &fragment_get; | ||
1918 | api->fragment_get_latest = &fragment_get_latest; | ||
1919 | api->message_get = &message_get; | ||
1920 | api->message_get_latest = &message_get_latest; | ||
1921 | api->message_get_fragment = &message_get_fragment; | ||
1922 | api->counters_message_get = &counters_message_get; | ||
1923 | api->counters_state_get = &counters_state_get; | ||
1924 | api->state_modify_begin = &state_modify_begin; | ||
1925 | api->state_modify_op = &state_modify_op; | ||
1926 | api->state_modify_end = &state_modify_end; | ||
1927 | api->state_sync_begin = &state_sync_begin; | ||
1928 | api->state_sync_assign = &state_sync_assign; | ||
1929 | api->state_sync_end = &state_sync_end; | ||
1930 | api->state_reset = &state_reset; | ||
1931 | api->state_update_signed = &state_update_signed; | ||
1932 | api->state_get = &state_get; | ||
1933 | api->state_get_prefix = &state_get_prefix; | ||
1934 | api->state_get_signed = &state_get_signed; | ||
1935 | |||
1936 | LOG (GNUNET_ERROR_TYPE_INFO, _("Mysql database running\n")); | ||
1937 | return api; | ||
1938 | } | ||
1939 | |||
1940 | |||
1941 | /** | ||
1942 | * Exit point from the plugin. | ||
1943 | * | ||
1944 | * @param cls The plugin context (as returned by "init") | ||
1945 | * @return Always NULL | ||
1946 | */ | ||
1947 | void * | ||
1948 | libgnunet_plugin_psycstore_mysql_done (void *cls) | ||
1949 | { | ||
1950 | struct GNUNET_PSYCSTORE_PluginFunctions *api = cls; | ||
1951 | struct Plugin *plugin = api->cls; | ||
1952 | |||
1953 | database_shutdown (plugin); | ||
1954 | plugin->cfg = NULL; | ||
1955 | GNUNET_free (api); | ||
1956 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Mysql plugin is finished\n"); | ||
1957 | return NULL; | ||
1958 | } | ||
1959 | |||
1960 | /* end of plugin_psycstore_mysql.c */ | ||
diff --git a/src/psycstore/plugin_psycstore_postgres.c b/src/psycstore/plugin_psycstore_postgres.c deleted file mode 100644 index 33c9960b2..000000000 --- a/src/psycstore/plugin_psycstore_postgres.c +++ /dev/null | |||
@@ -1,1530 +0,0 @@ | |||
1 | /* | ||
2 | * This file is part of GNUnet | ||
3 | * Copyright (C) 2016 GNUnet e.V. | ||
4 | * | ||
5 | * GNUnet is free software: you can redistribute it and/or modify it | ||
6 | * under the terms of the GNU Affero General Public License as published | ||
7 | * by the Free Software Foundation, either version 3 of the License, | ||
8 | * or (at your option) any later version. | ||
9 | * | ||
10 | * GNUnet is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * Affero General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Affero General Public License | ||
16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file psycstore/plugin_psycstore_postgres.c | ||
23 | * @brief PostgresQL-based psycstore backend | ||
24 | * @author Daniel Golle | ||
25 | * @author Gabor X Toth | ||
26 | * @author Christian Grothoff | ||
27 | * @author Christophe Genevey | ||
28 | * @author Jeffrey Burdges | ||
29 | */ | ||
30 | |||
31 | #include "platform.h" | ||
32 | #include "gnunet_psycstore_plugin.h" | ||
33 | #include "gnunet_psycstore_service.h" | ||
34 | #include "gnunet_multicast_service.h" | ||
35 | #include "gnunet_crypto_lib.h" | ||
36 | #include "gnunet_psyc_util_lib.h" | ||
37 | #include "psycstore.h" | ||
38 | #include "gnunet_pq_lib.h" | ||
39 | |||
40 | /** | ||
41 | * After how many ms "busy" should a DB operation fail for good? A | ||
42 | * low value makes sure that we are more responsive to requests | ||
43 | * (especially PUTs). A high value guarantees a higher success rate | ||
44 | * (SELECTs in iterate can take several seconds despite LIMIT=1). | ||
45 | * | ||
46 | * The default value of 1s should ensure that users do not experience | ||
47 | * huge latencies while at the same time allowing operations to | ||
48 | * succeed with reasonable probability. | ||
49 | */ | ||
50 | #define BUSY_TIMEOUT_MS 1000 | ||
51 | |||
52 | #define DEBUG_PSYCSTORE GNUNET_EXTRA_LOGGING | ||
53 | |||
54 | #define LOG(kind,...) GNUNET_log_from (kind, "psycstore-postgres", __VA_ARGS__) | ||
55 | |||
56 | enum Transactions { | ||
57 | TRANSACTION_NONE = 0, | ||
58 | TRANSACTION_STATE_MODIFY, | ||
59 | TRANSACTION_STATE_SYNC, | ||
60 | }; | ||
61 | |||
62 | /** | ||
63 | * Context for all functions in this plugin. | ||
64 | */ | ||
65 | struct Plugin | ||
66 | { | ||
67 | |||
68 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
69 | |||
70 | /** | ||
71 | * Native Postgres database handle. | ||
72 | */ | ||
73 | PGconn *dbh; | ||
74 | |||
75 | enum Transactions transaction; | ||
76 | |||
77 | void *cls; | ||
78 | }; | ||
79 | |||
80 | |||
81 | /** | ||
82 | * Initialize the database connections and associated | ||
83 | * data structures (create tables and indices | ||
84 | * as needed as well). | ||
85 | * | ||
86 | * @param plugin the plugin context (state for this module) | ||
87 | * @return #GNUNET_OK on success | ||
88 | */ | ||
89 | static int | ||
90 | database_setup (struct Plugin *plugin) | ||
91 | { | ||
92 | struct GNUNET_PQ_ExecuteStatement es[] = { | ||
93 | GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS channels (\n" | ||
94 | " id SERIAL,\n" | ||
95 | " pub_key BYTEA NOT NULL CHECK (LENGTH(pub_key)=32),\n" | ||
96 | " max_state_message_id BIGINT,\n" | ||
97 | " state_hash_message_id BIGINT,\n" | ||
98 | " PRIMARY KEY(id)\n" | ||
99 | ")" | ||
100 | "WITH OIDS"), | ||
101 | GNUNET_PQ_make_execute ("CREATE UNIQUE INDEX IF NOT EXISTS channel_pub_key_idx \n" | ||
102 | " ON channels (pub_key)"), | ||
103 | GNUNET_PQ_make_execute ("CREATE OR REPLACE FUNCTION get_chan_id(BYTEA) RETURNS INTEGER AS \n" | ||
104 | " 'SELECT id FROM channels WHERE pub_key=$1;' LANGUAGE SQL STABLE \n" | ||
105 | "RETURNS NULL ON NULL INPUT"), | ||
106 | GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS slaves (\n" | ||
107 | " id SERIAL,\n" | ||
108 | " pub_key BYTEA NOT NULL CHECK (LENGTH(pub_key)=32),\n" | ||
109 | " PRIMARY KEY(id)\n" | ||
110 | ")" | ||
111 | "WITH OIDS"), | ||
112 | GNUNET_PQ_make_execute ("CREATE UNIQUE INDEX IF NOT EXISTS slaves_pub_key_idx \n" | ||
113 | " ON slaves (pub_key)"), | ||
114 | GNUNET_PQ_make_execute ("CREATE OR REPLACE FUNCTION get_slave_id(BYTEA) RETURNS INTEGER AS \n" | ||
115 | " 'SELECT id FROM slaves WHERE pub_key=$1;' LANGUAGE SQL STABLE \n" | ||
116 | "RETURNS NULL ON NULL INPUT"), | ||
117 | GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS membership (\n" | ||
118 | " channel_id BIGINT NOT NULL REFERENCES channels(id),\n" | ||
119 | " slave_id BIGINT NOT NULL REFERENCES slaves(id),\n" | ||
120 | " did_join INT NOT NULL,\n" | ||
121 | " announced_at BIGINT NOT NULL,\n" | ||
122 | " effective_since BIGINT NOT NULL,\n" | ||
123 | " group_generation BIGINT NOT NULL\n" | ||
124 | ")" | ||
125 | "WITH OIDS"), | ||
126 | GNUNET_PQ_make_execute ("CREATE INDEX IF NOT EXISTS idx_membership_channel_id_slave_id " | ||
127 | "ON membership (channel_id, slave_id)"), | ||
128 | /** @todo messages table: add method_name column */ | ||
129 | GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS messages (\n" | ||
130 | " channel_id BIGINT NOT NULL REFERENCES channels(id),\n" | ||
131 | " hop_counter INT NOT NULL,\n" | ||
132 | " signature BYTEA CHECK (LENGTH(signature)=64),\n" | ||
133 | " purpose BYTEA CHECK (LENGTH(purpose)=8),\n" | ||
134 | " fragment_id BIGINT NOT NULL,\n" | ||
135 | " fragment_offset BIGINT NOT NULL,\n" | ||
136 | " message_id BIGINT NOT NULL,\n" | ||
137 | " group_generation BIGINT NOT NULL,\n" | ||
138 | " multicast_flags INT NOT NULL,\n" | ||
139 | " psycstore_flags INT NOT NULL,\n" | ||
140 | " data BYTEA,\n" | ||
141 | " PRIMARY KEY (channel_id, fragment_id),\n" | ||
142 | " UNIQUE (channel_id, message_id, fragment_offset)\n" | ||
143 | ")" | ||
144 | "WITH OIDS"), | ||
145 | GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS state (\n" | ||
146 | " channel_id BIGINT NOT NULL REFERENCES channels(id),\n" | ||
147 | " name TEXT NOT NULL,\n" | ||
148 | " value_current BYTEA,\n" | ||
149 | " value_signed BYTEA,\n" | ||
150 | " PRIMARY KEY (channel_id, name)\n" | ||
151 | ")" | ||
152 | "WITH OIDS"), | ||
153 | GNUNET_PQ_make_execute ("CREATE TABLE IF NOT EXISTS state_sync (\n" | ||
154 | " channel_id BIGINT NOT NULL REFERENCES channels(id),\n" | ||
155 | " name TEXT NOT NULL,\n" | ||
156 | " value BYTEA,\n" | ||
157 | " PRIMARY KEY (channel_id, name)\n" | ||
158 | ")" | ||
159 | "WITH OIDS"), | ||
160 | GNUNET_PQ_EXECUTE_STATEMENT_END | ||
161 | }; | ||
162 | |||
163 | /* Open database and precompile statements */ | ||
164 | plugin->dbh = GNUNET_PQ_connect_with_cfg (plugin->cfg, | ||
165 | "psycstore-postgres"); | ||
166 | if (NULL == plugin->dbh) | ||
167 | return GNUNET_SYSERR; | ||
168 | if (GNUNET_OK != | ||
169 | GNUNET_PQ_exec_statements (plugin->dbh, | ||
170 | es)) | ||
171 | { | ||
172 | PQfinish (plugin->dbh); | ||
173 | plugin->dbh = NULL; | ||
174 | return GNUNET_SYSERR; | ||
175 | } | ||
176 | |||
177 | /* Prepare statements */ | ||
178 | { | ||
179 | struct GNUNET_PQ_PreparedStatement ps[] = { | ||
180 | GNUNET_PQ_make_prepare ("transaction_begin", | ||
181 | "BEGIN", 0), | ||
182 | GNUNET_PQ_make_prepare ("transaction_commit", | ||
183 | "COMMIT", 0), | ||
184 | GNUNET_PQ_make_prepare ("transaction_rollback", | ||
185 | "ROLLBACK", 0), | ||
186 | GNUNET_PQ_make_prepare ("insert_channel_key", | ||
187 | "INSERT INTO channels (pub_key) VALUES ($1)" | ||
188 | " ON CONFLICT DO NOTHING", 1), | ||
189 | GNUNET_PQ_make_prepare ("insert_slave_key", | ||
190 | "INSERT INTO slaves (pub_key) VALUES ($1)" | ||
191 | " ON CONFLICT DO NOTHING", 1), | ||
192 | GNUNET_PQ_make_prepare ("insert_membership", | ||
193 | "INSERT INTO membership\n" | ||
194 | " (channel_id, slave_id, did_join, announced_at,\n" | ||
195 | " effective_since, group_generation)\n" | ||
196 | "VALUES (get_chan_id($1),\n" | ||
197 | " get_slave_id($2),\n" | ||
198 | " $3, $4, $5, $6)", 6), | ||
199 | GNUNET_PQ_make_prepare ("select_membership", | ||
200 | "SELECT did_join FROM membership\n" | ||
201 | "WHERE channel_id = get_chan_id($1)\n" | ||
202 | " AND slave_id = get_slave_id($2)\n" | ||
203 | " AND effective_since <= $3 AND did_join = 1\n" | ||
204 | "ORDER BY announced_at DESC LIMIT 1", 3), | ||
205 | GNUNET_PQ_make_prepare ("insert_fragment", | ||
206 | "INSERT INTO messages\n" | ||
207 | " (channel_id, hop_counter, signature, purpose,\n" | ||
208 | " fragment_id, fragment_offset, message_id,\n" | ||
209 | " group_generation, multicast_flags, psycstore_flags, data)\n" | ||
210 | "VALUES (get_chan_id($1),\n" | ||
211 | " $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)" | ||
212 | "ON CONFLICT DO NOTHING", 11), | ||
213 | GNUNET_PQ_make_prepare ("update_message_flags", | ||
214 | "UPDATE messages\n" | ||
215 | "SET psycstore_flags = psycstore_flags | $1\n" | ||
216 | "WHERE channel_id = get_chan_id($2) \n" | ||
217 | " AND message_id = $3 AND fragment_offset = 0", 3), | ||
218 | GNUNET_PQ_make_prepare ("select_fragments", | ||
219 | "SELECT hop_counter, signature, purpose, fragment_id,\n" | ||
220 | " fragment_offset, message_id, group_generation,\n" | ||
221 | " multicast_flags, psycstore_flags, data\n" | ||
222 | "FROM messages\n" | ||
223 | "WHERE channel_id = get_chan_id($1) \n" | ||
224 | " AND $2 <= fragment_id AND fragment_id <= $3", 3), | ||
225 | /** @todo select_messages: add method_prefix filter */ | ||
226 | GNUNET_PQ_make_prepare ("select_messages", | ||
227 | "SELECT hop_counter, signature, purpose, fragment_id,\n" | ||
228 | " fragment_offset, message_id, group_generation,\n" | ||
229 | " multicast_flags, psycstore_flags, data\n" | ||
230 | "FROM messages\n" | ||
231 | "WHERE channel_id = get_chan_id($1) \n" | ||
232 | " AND $2 <= message_id AND message_id <= $3\n" | ||
233 | "LIMIT $4;", 4), | ||
234 | /** @todo select_latest_messages: add method_prefix filter */ | ||
235 | GNUNET_PQ_make_prepare ("select_latest_fragments", | ||
236 | "SELECT rev.hop_counter AS hop_counter,\n" | ||
237 | " rev.signature AS signature,\n" | ||
238 | " rev.purpose AS purpose,\n" | ||
239 | " rev.fragment_id AS fragment_id,\n" | ||
240 | " rev.fragment_offset AS fragment_offset,\n" | ||
241 | " rev.message_id AS message_id,\n" | ||
242 | " rev.group_generation AS group_generation,\n" | ||
243 | " rev.multicast_flags AS multicast_flags,\n" | ||
244 | " rev.psycstore_flags AS psycstore_flags,\n" | ||
245 | " rev.data AS data\n" | ||
246 | " FROM\n" | ||
247 | " (SELECT hop_counter, signature, purpose, fragment_id,\n" | ||
248 | " fragment_offset, message_id, group_generation,\n" | ||
249 | " multicast_flags, psycstore_flags, data \n" | ||
250 | " FROM messages\n" | ||
251 | " WHERE channel_id = get_chan_id($1) \n" | ||
252 | " ORDER BY fragment_id DESC\n" | ||
253 | " LIMIT $2) AS rev\n" | ||
254 | " ORDER BY rev.fragment_id;", 2), | ||
255 | GNUNET_PQ_make_prepare ("select_latest_messages", | ||
256 | "SELECT hop_counter, signature, purpose, fragment_id,\n" | ||
257 | " fragment_offset, message_id, group_generation,\n" | ||
258 | " multicast_flags, psycstore_flags, data\n" | ||
259 | "FROM messages\n" | ||
260 | "WHERE channel_id = get_chan_id($1)\n" | ||
261 | " AND message_id IN\n" | ||
262 | " (SELECT message_id\n" | ||
263 | " FROM messages\n" | ||
264 | " WHERE channel_id = get_chan_id($2) \n" | ||
265 | " GROUP BY message_id\n" | ||
266 | " ORDER BY message_id\n" | ||
267 | " DESC LIMIT $3)\n" | ||
268 | "ORDER BY fragment_id", 3), | ||
269 | GNUNET_PQ_make_prepare ("select_message_fragment", | ||
270 | "SELECT hop_counter, signature, purpose, fragment_id,\n" | ||
271 | " fragment_offset, message_id, group_generation,\n" | ||
272 | " multicast_flags, psycstore_flags, data\n" | ||
273 | "FROM messages\n" | ||
274 | "WHERE channel_id = get_chan_id($1) \n" | ||
275 | " AND message_id = $2 AND fragment_offset = $3", 3), | ||
276 | GNUNET_PQ_make_prepare ("select_counters_message", | ||
277 | "SELECT fragment_id, message_id, group_generation\n" | ||
278 | "FROM messages\n" | ||
279 | "WHERE channel_id = get_chan_id($1)\n" | ||
280 | "ORDER BY fragment_id DESC LIMIT 1", 1), | ||
281 | GNUNET_PQ_make_prepare ("select_counters_state", | ||
282 | "SELECT max_state_message_id\n" | ||
283 | "FROM channels\n" | ||
284 | "WHERE pub_key = $1 AND max_state_message_id IS NOT NULL", 1), | ||
285 | GNUNET_PQ_make_prepare ("update_max_state_message_id", | ||
286 | "UPDATE channels\n" | ||
287 | "SET max_state_message_id = $1\n" | ||
288 | "WHERE pub_key = $2", 2), | ||
289 | |||
290 | GNUNET_PQ_make_prepare ("update_state_hash_message_id", | ||
291 | "UPDATE channels\n" | ||
292 | "SET state_hash_message_id = $1\n" | ||
293 | "WHERE pub_key = $2", 2), | ||
294 | GNUNET_PQ_make_prepare ("insert_state_current", | ||
295 | "INSERT INTO state\n" | ||
296 | " (channel_id, name, value_current, value_signed)\n" | ||
297 | "SELECT new.channel_id, new.name,\n" | ||
298 | " new.value_current, old.value_signed\n" | ||
299 | "FROM (SELECT get_chan_id($1) AS channel_id,\n" | ||
300 | " $2::TEXT AS name, $3::BYTEA AS value_current) AS new\n" | ||
301 | "LEFT JOIN (SELECT channel_id, name, value_signed\n" | ||
302 | " FROM state) AS old\n" | ||
303 | "ON new.channel_id = old.channel_id AND new.name = old.name\n" | ||
304 | "ON CONFLICT (channel_id, name)\n" | ||
305 | " DO UPDATE SET value_current = EXCLUDED.value_current,\n" | ||
306 | " value_signed = EXCLUDED.value_signed", 3), | ||
307 | GNUNET_PQ_make_prepare ("delete_state_empty", | ||
308 | "DELETE FROM state\n" | ||
309 | "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = $1)\n" | ||
310 | " AND (value_current IS NULL OR length(value_current) = 0)\n" | ||
311 | " AND (value_signed IS NULL OR length(value_signed) = 0)", 1), | ||
312 | GNUNET_PQ_make_prepare ("update_state_signed", | ||
313 | "UPDATE state\n" | ||
314 | "SET value_signed = value_current\n" | ||
315 | "WHERE channel_id = get_chan_id($1) ", 1), | ||
316 | GNUNET_PQ_make_prepare ("delete_state", | ||
317 | "DELETE FROM state\n" | ||
318 | "WHERE channel_id = get_chan_id($1) ", 1), | ||
319 | GNUNET_PQ_make_prepare ("insert_state_sync", | ||
320 | "INSERT INTO state_sync (channel_id, name, value)\n" | ||
321 | "VALUES (get_chan_id($1), $2, $3)", 3), | ||
322 | GNUNET_PQ_make_prepare ("insert_state_from_sync", | ||
323 | "INSERT INTO state\n" | ||
324 | " (channel_id, name, value_current, value_signed)\n" | ||
325 | "SELECT channel_id, name, value, value\n" | ||
326 | "FROM state_sync\n" | ||
327 | "WHERE channel_id = get_chan_id($1)", 1), | ||
328 | GNUNET_PQ_make_prepare ("delete_state_sync", | ||
329 | "DELETE FROM state_sync\n" | ||
330 | "WHERE channel_id = get_chan_id($1)", 1), | ||
331 | GNUNET_PQ_make_prepare ("select_state_one", | ||
332 | "SELECT value_current\n" | ||
333 | "FROM state\n" | ||
334 | "WHERE channel_id = get_chan_id($1)\n" | ||
335 | " AND name = $2", 2), | ||
336 | GNUNET_PQ_make_prepare ("select_state_prefix", | ||
337 | "SELECT name, value_current\n" | ||
338 | "FROM state\n" | ||
339 | "WHERE channel_id = get_chan_id($1)\n" | ||
340 | " AND (name = $2 OR substr(name, 1, $3) = $4)", 4), | ||
341 | GNUNET_PQ_make_prepare ("select_state_signed", | ||
342 | "SELECT name, value_signed\n" | ||
343 | "FROM state\n" | ||
344 | "WHERE channel_id = get_chan_id($1)\n" | ||
345 | " AND value_signed IS NOT NULL", 1), | ||
346 | GNUNET_PQ_PREPARED_STATEMENT_END | ||
347 | }; | ||
348 | |||
349 | if (GNUNET_OK != | ||
350 | GNUNET_PQ_prepare_statements (plugin->dbh, | ||
351 | ps)) | ||
352 | { | ||
353 | PQfinish (plugin->dbh); | ||
354 | plugin->dbh = NULL; | ||
355 | return GNUNET_SYSERR; | ||
356 | } | ||
357 | } | ||
358 | |||
359 | return GNUNET_OK; | ||
360 | } | ||
361 | |||
362 | |||
363 | /** | ||
364 | * Shutdown database connection and associate data | ||
365 | * structures. | ||
366 | * @param plugin the plugin context (state for this module) | ||
367 | */ | ||
368 | static void | ||
369 | database_shutdown (struct Plugin *plugin) | ||
370 | { | ||
371 | PQfinish (plugin->dbh); | ||
372 | plugin->dbh = NULL; | ||
373 | } | ||
374 | |||
375 | |||
376 | /** | ||
377 | * Execute a prepared statement with a @a channel_key argument. | ||
378 | * | ||
379 | * @param plugin Plugin handle. | ||
380 | * @param stmt Statement to execute. | ||
381 | * @param channel_key Public key of the channel. | ||
382 | * | ||
383 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
384 | */ | ||
385 | static int | ||
386 | exec_channel (struct Plugin *plugin, const char *stmt, | ||
387 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key) | ||
388 | { | ||
389 | struct GNUNET_PQ_QueryParam params[] = { | ||
390 | GNUNET_PQ_query_param_auto_from_type (channel_key), | ||
391 | GNUNET_PQ_query_param_end | ||
392 | }; | ||
393 | |||
394 | if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != | ||
395 | GNUNET_PQ_eval_prepared_non_select (plugin->dbh, stmt, params)) | ||
396 | return GNUNET_SYSERR; | ||
397 | |||
398 | return GNUNET_OK; | ||
399 | } | ||
400 | |||
401 | |||
402 | /** | ||
403 | * Begin a transaction. | ||
404 | */ | ||
405 | static int | ||
406 | transaction_begin (struct Plugin *plugin, enum Transactions transaction) | ||
407 | { | ||
408 | struct GNUNET_PQ_QueryParam params[] = { | ||
409 | GNUNET_PQ_query_param_end | ||
410 | }; | ||
411 | |||
412 | if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != | ||
413 | GNUNET_PQ_eval_prepared_non_select (plugin->dbh, "transaction_begin", params)) | ||
414 | return GNUNET_SYSERR; | ||
415 | |||
416 | plugin->transaction = transaction; | ||
417 | return GNUNET_OK; | ||
418 | } | ||
419 | |||
420 | |||
421 | /** | ||
422 | * Commit current transaction. | ||
423 | */ | ||
424 | static int | ||
425 | transaction_commit (struct Plugin *plugin) | ||
426 | { | ||
427 | struct GNUNET_PQ_QueryParam params[] = { | ||
428 | GNUNET_PQ_query_param_end | ||
429 | }; | ||
430 | |||
431 | if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != | ||
432 | GNUNET_PQ_eval_prepared_non_select (plugin->dbh, "transaction_commit", params)) | ||
433 | return GNUNET_SYSERR; | ||
434 | |||
435 | plugin->transaction = TRANSACTION_NONE; | ||
436 | return GNUNET_OK; | ||
437 | } | ||
438 | |||
439 | |||
440 | /** | ||
441 | * Roll back current transaction. | ||
442 | */ | ||
443 | static int | ||
444 | transaction_rollback (struct Plugin *plugin) | ||
445 | { | ||
446 | struct GNUNET_PQ_QueryParam params[] = { | ||
447 | GNUNET_PQ_query_param_end | ||
448 | }; | ||
449 | |||
450 | if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != | ||
451 | GNUNET_PQ_eval_prepared_non_select (plugin->dbh, "transaction_rollback", params)) | ||
452 | return GNUNET_SYSERR; | ||
453 | |||
454 | plugin->transaction = TRANSACTION_NONE; | ||
455 | return GNUNET_OK; | ||
456 | } | ||
457 | |||
458 | |||
459 | static int | ||
460 | channel_key_store (struct Plugin *plugin, | ||
461 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key) | ||
462 | { | ||
463 | struct GNUNET_PQ_QueryParam params[] = { | ||
464 | GNUNET_PQ_query_param_auto_from_type (channel_key), | ||
465 | GNUNET_PQ_query_param_end | ||
466 | }; | ||
467 | |||
468 | if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != | ||
469 | GNUNET_PQ_eval_prepared_non_select (plugin->dbh, | ||
470 | "insert_channel_key", | ||
471 | params)) | ||
472 | return GNUNET_SYSERR; | ||
473 | |||
474 | return GNUNET_OK; | ||
475 | } | ||
476 | |||
477 | |||
478 | static int | ||
479 | slave_key_store (struct Plugin *plugin, | ||
480 | const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key) | ||
481 | { | ||
482 | struct GNUNET_PQ_QueryParam params[] = { | ||
483 | GNUNET_PQ_query_param_auto_from_type (slave_key), | ||
484 | GNUNET_PQ_query_param_end | ||
485 | }; | ||
486 | |||
487 | if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != | ||
488 | GNUNET_PQ_eval_prepared_non_select (plugin->dbh, "insert_slave_key", params)) | ||
489 | return GNUNET_SYSERR; | ||
490 | |||
491 | return GNUNET_OK; | ||
492 | } | ||
493 | |||
494 | |||
495 | /** | ||
496 | * Store join/leave events for a PSYC channel in order to be able to answer | ||
497 | * membership test queries later. | ||
498 | * | ||
499 | * @see GNUNET_PSYCSTORE_membership_store() | ||
500 | * | ||
501 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
502 | */ | ||
503 | static int | ||
504 | postgres_membership_store (void *cls, | ||
505 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
506 | const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, | ||
507 | int did_join, | ||
508 | uint64_t announced_at, | ||
509 | uint64_t effective_since, | ||
510 | uint64_t group_generation) | ||
511 | { | ||
512 | struct Plugin *plugin = cls; | ||
513 | uint32_t idid_join = (uint32_t) did_join; | ||
514 | |||
515 | GNUNET_assert (TRANSACTION_NONE == plugin->transaction); | ||
516 | |||
517 | if ( (announced_at > INT64_MAX) || | ||
518 | (effective_since > INT64_MAX) || | ||
519 | (group_generation > INT64_MAX) ) | ||
520 | { | ||
521 | GNUNET_break (0); | ||
522 | return GNUNET_SYSERR; | ||
523 | } | ||
524 | |||
525 | if ( (GNUNET_OK != | ||
526 | channel_key_store (plugin, channel_key)) || | ||
527 | (GNUNET_OK != | ||
528 | slave_key_store (plugin, slave_key)) ) | ||
529 | return GNUNET_SYSERR; | ||
530 | |||
531 | struct GNUNET_PQ_QueryParam params[] = { | ||
532 | GNUNET_PQ_query_param_auto_from_type (channel_key), | ||
533 | GNUNET_PQ_query_param_auto_from_type (slave_key), | ||
534 | GNUNET_PQ_query_param_uint32 (&idid_join), | ||
535 | GNUNET_PQ_query_param_uint64 (&announced_at), | ||
536 | GNUNET_PQ_query_param_uint64 (&effective_since), | ||
537 | GNUNET_PQ_query_param_uint64 (&group_generation), | ||
538 | GNUNET_PQ_query_param_end | ||
539 | }; | ||
540 | |||
541 | if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != | ||
542 | GNUNET_PQ_eval_prepared_non_select (plugin->dbh, | ||
543 | "insert_membership", | ||
544 | params)) | ||
545 | return GNUNET_SYSERR; | ||
546 | |||
547 | return GNUNET_OK; | ||
548 | } | ||
549 | |||
550 | /** | ||
551 | * Test if a member was admitted to the channel at the given message ID. | ||
552 | * | ||
553 | * @see GNUNET_PSYCSTORE_membership_test() | ||
554 | * | ||
555 | * @return #GNUNET_YES if the member was admitted, #GNUNET_NO if not, | ||
556 | * #GNUNET_SYSERR if there was en error. | ||
557 | */ | ||
558 | static int | ||
559 | membership_test (void *cls, | ||
560 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
561 | const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, | ||
562 | uint64_t message_id) | ||
563 | { | ||
564 | struct Plugin *plugin = cls; | ||
565 | |||
566 | uint32_t did_join = 0; | ||
567 | |||
568 | struct GNUNET_PQ_QueryParam params_select[] = { | ||
569 | GNUNET_PQ_query_param_auto_from_type (channel_key), | ||
570 | GNUNET_PQ_query_param_auto_from_type (slave_key), | ||
571 | GNUNET_PQ_query_param_uint64 (&message_id), | ||
572 | GNUNET_PQ_query_param_end | ||
573 | }; | ||
574 | |||
575 | struct GNUNET_PQ_ResultSpec results_select[] = { | ||
576 | GNUNET_PQ_result_spec_uint32 ("did_join", &did_join), | ||
577 | GNUNET_PQ_result_spec_end | ||
578 | }; | ||
579 | |||
580 | if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != | ||
581 | GNUNET_PQ_eval_prepared_singleton_select (plugin->dbh, "select_membership", | ||
582 | params_select, results_select)) | ||
583 | return GNUNET_SYSERR; | ||
584 | |||
585 | return GNUNET_OK; | ||
586 | } | ||
587 | |||
588 | /** | ||
589 | * Store a message fragment sent to a channel. | ||
590 | * | ||
591 | * @see GNUNET_PSYCSTORE_fragment_store() | ||
592 | * | ||
593 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
594 | */ | ||
595 | static int | ||
596 | fragment_store (void *cls, | ||
597 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
598 | const struct GNUNET_MULTICAST_MessageHeader *msg, | ||
599 | uint32_t psycstore_flags) | ||
600 | { | ||
601 | struct Plugin *plugin = cls; | ||
602 | |||
603 | GNUNET_assert (TRANSACTION_NONE == plugin->transaction); | ||
604 | |||
605 | uint64_t fragment_id = GNUNET_ntohll (msg->fragment_id); | ||
606 | |||
607 | uint64_t fragment_offset = GNUNET_ntohll (msg->fragment_offset); | ||
608 | uint64_t message_id = GNUNET_ntohll (msg->message_id); | ||
609 | uint64_t group_generation = GNUNET_ntohll (msg->group_generation); | ||
610 | |||
611 | uint32_t hop_counter = ntohl(msg->hop_counter); | ||
612 | uint32_t flags = ntohl(msg->flags); | ||
613 | |||
614 | if (fragment_id > INT64_MAX || fragment_offset > INT64_MAX || | ||
615 | message_id > INT64_MAX || group_generation > INT64_MAX) | ||
616 | { | ||
617 | LOG(GNUNET_ERROR_TYPE_ERROR, | ||
618 | "Tried to store fragment with a field > INT64_MAX: " | ||
619 | "%lu, %lu, %lu, %lu\n", fragment_id, fragment_offset, | ||
620 | message_id, group_generation); | ||
621 | GNUNET_break (0); | ||
622 | return GNUNET_SYSERR; | ||
623 | } | ||
624 | |||
625 | if (GNUNET_OK != channel_key_store (plugin, channel_key)) | ||
626 | return GNUNET_SYSERR; | ||
627 | |||
628 | struct GNUNET_PQ_QueryParam params_insert[] = { | ||
629 | GNUNET_PQ_query_param_auto_from_type (channel_key), | ||
630 | GNUNET_PQ_query_param_uint32 (&hop_counter), | ||
631 | GNUNET_PQ_query_param_auto_from_type (&msg->signature), | ||
632 | GNUNET_PQ_query_param_auto_from_type (&msg->purpose), | ||
633 | GNUNET_PQ_query_param_uint64 (&fragment_id), | ||
634 | GNUNET_PQ_query_param_uint64 (&fragment_offset), | ||
635 | GNUNET_PQ_query_param_uint64 (&message_id), | ||
636 | GNUNET_PQ_query_param_uint64 (&group_generation), | ||
637 | GNUNET_PQ_query_param_uint32 (&flags), | ||
638 | GNUNET_PQ_query_param_uint32 (&psycstore_flags), | ||
639 | GNUNET_PQ_query_param_fixed_size (&msg[1], ntohs (msg->header.size) - sizeof (*msg)), | ||
640 | GNUNET_PQ_query_param_end | ||
641 | }; | ||
642 | |||
643 | if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != | ||
644 | GNUNET_PQ_eval_prepared_non_select (plugin->dbh, "insert_fragment", params_insert)) | ||
645 | return GNUNET_SYSERR; | ||
646 | |||
647 | return GNUNET_OK; | ||
648 | } | ||
649 | |||
650 | /** | ||
651 | * Set additional flags for a given message. | ||
652 | * | ||
653 | * They are OR'd with any existing flags set. | ||
654 | * | ||
655 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
656 | */ | ||
657 | static int | ||
658 | message_add_flags (void *cls, | ||
659 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
660 | uint64_t message_id, | ||
661 | uint32_t psycstore_flags) | ||
662 | { | ||
663 | struct Plugin *plugin = cls; | ||
664 | |||
665 | struct GNUNET_PQ_QueryParam params_update[] = { | ||
666 | GNUNET_PQ_query_param_uint32 (&psycstore_flags), | ||
667 | GNUNET_PQ_query_param_auto_from_type (channel_key), | ||
668 | GNUNET_PQ_query_param_uint64 (&message_id), | ||
669 | GNUNET_PQ_query_param_end | ||
670 | }; | ||
671 | |||
672 | if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != | ||
673 | GNUNET_PQ_eval_prepared_non_select (plugin->dbh, "update_message_flags", params_update)) | ||
674 | return GNUNET_SYSERR; | ||
675 | |||
676 | return GNUNET_OK; | ||
677 | } | ||
678 | |||
679 | |||
680 | /** | ||
681 | * Closure for #fragment_rows. | ||
682 | */ | ||
683 | struct FragmentRowsContext { | ||
684 | GNUNET_PSYCSTORE_FragmentCallback cb; | ||
685 | void *cb_cls; | ||
686 | |||
687 | uint64_t *returned_fragments; | ||
688 | |||
689 | /* I preserved this but I do not see the point since | ||
690 | * it cannot stop the loop early and gets overwritten ?? */ | ||
691 | int ret; | ||
692 | }; | ||
693 | |||
694 | |||
695 | /** | ||
696 | * Callback that retrieves the results of a SELECT statement | ||
697 | * reading form the messages table. | ||
698 | * | ||
699 | * Only passed to GNUNET_PQ_eval_prepared_multi_select and | ||
700 | * has type GNUNET_PQ_PostgresResultHandler. | ||
701 | * | ||
702 | * @param cls closure | ||
703 | * @param result the postgres result | ||
704 | * @param num_result the number of results in @a result | ||
705 | */ | ||
706 | void fragment_rows (void *cls, | ||
707 | PGresult *res, | ||
708 | unsigned int num_results) | ||
709 | { | ||
710 | struct FragmentRowsContext *c = cls; | ||
711 | |||
712 | for (unsigned int i=0;i<num_results;i++) | ||
713 | { | ||
714 | uint32_t hop_counter; | ||
715 | void *signature = NULL; | ||
716 | void *purpose = NULL; | ||
717 | size_t signature_size; | ||
718 | size_t purpose_size; | ||
719 | uint64_t fragment_id; | ||
720 | uint64_t fragment_offset; | ||
721 | uint64_t message_id; | ||
722 | uint64_t group_generation; | ||
723 | uint32_t flags; | ||
724 | void *buf; | ||
725 | size_t buf_size; | ||
726 | uint32_t msg_flags; | ||
727 | struct GNUNET_PQ_ResultSpec results[] = { | ||
728 | GNUNET_PQ_result_spec_uint32 ("hop_counter", &hop_counter), | ||
729 | GNUNET_PQ_result_spec_variable_size ("signature", &signature, &signature_size), | ||
730 | GNUNET_PQ_result_spec_variable_size ("purpose", &purpose, &purpose_size), | ||
731 | GNUNET_PQ_result_spec_uint64 ("fragment_id", &fragment_id), | ||
732 | GNUNET_PQ_result_spec_uint64 ("fragment_offset", &fragment_offset), | ||
733 | GNUNET_PQ_result_spec_uint64 ("message_id", &message_id), | ||
734 | GNUNET_PQ_result_spec_uint64 ("group_generation", &group_generation), | ||
735 | GNUNET_PQ_result_spec_uint32 ("multicast_flags", &msg_flags), | ||
736 | GNUNET_PQ_result_spec_uint32 ("psycstore_flags", &flags), | ||
737 | GNUNET_PQ_result_spec_variable_size ("data", &buf, &buf_size), | ||
738 | GNUNET_PQ_result_spec_end | ||
739 | }; | ||
740 | struct GNUNET_MULTICAST_MessageHeader *mp; | ||
741 | |||
742 | if (GNUNET_YES != GNUNET_PQ_extract_result (res, results, i)) | ||
743 | { | ||
744 | GNUNET_PQ_cleanup_result(results); /* missing previously, a memory leak?? */ | ||
745 | break; /* nothing more?? */ | ||
746 | } | ||
747 | |||
748 | mp = GNUNET_malloc (sizeof (*mp) + buf_size); | ||
749 | |||
750 | mp->header.size = htons (sizeof (*mp) + buf_size); | ||
751 | mp->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE); | ||
752 | mp->hop_counter = htonl (hop_counter); | ||
753 | GNUNET_memcpy (&mp->signature, | ||
754 | signature, signature_size); | ||
755 | GNUNET_memcpy (&mp->purpose, | ||
756 | purpose, purpose_size); | ||
757 | mp->fragment_id = GNUNET_htonll (fragment_id); | ||
758 | mp->fragment_offset = GNUNET_htonll (fragment_offset); | ||
759 | mp->message_id = GNUNET_htonll (message_id); | ||
760 | mp->group_generation = GNUNET_htonll (group_generation); | ||
761 | mp->flags = htonl(msg_flags); | ||
762 | |||
763 | GNUNET_memcpy (&mp[1], | ||
764 | buf, buf_size); | ||
765 | GNUNET_PQ_cleanup_result(results); | ||
766 | c->ret = c->cb (c->cb_cls, mp, (enum GNUNET_PSYCSTORE_MessageFlags) flags); | ||
767 | if (NULL != c->returned_fragments) | ||
768 | (*c->returned_fragments)++; | ||
769 | } | ||
770 | } | ||
771 | |||
772 | |||
773 | static int | ||
774 | fragment_select (struct Plugin *plugin, | ||
775 | const char *stmt, | ||
776 | struct GNUNET_PQ_QueryParam *params, | ||
777 | uint64_t *returned_fragments, | ||
778 | GNUNET_PSYCSTORE_FragmentCallback cb, | ||
779 | void *cb_cls) | ||
780 | { | ||
781 | /* Stack based closure */ | ||
782 | struct FragmentRowsContext frc = { | ||
783 | .cb = cb, | ||
784 | .cb_cls = cb_cls, | ||
785 | .returned_fragments = returned_fragments, | ||
786 | .ret = GNUNET_SYSERR | ||
787 | }; | ||
788 | |||
789 | if (0 > GNUNET_PQ_eval_prepared_multi_select (plugin->dbh, | ||
790 | stmt, params, | ||
791 | &fragment_rows, &frc)) | ||
792 | return GNUNET_SYSERR; | ||
793 | return frc.ret; /* GNUNET_OK ?? */ | ||
794 | } | ||
795 | |||
796 | /** | ||
797 | * Retrieve a message fragment range by fragment ID. | ||
798 | * | ||
799 | * @see GNUNET_PSYCSTORE_fragment_get() | ||
800 | * | ||
801 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
802 | */ | ||
803 | static int | ||
804 | fragment_get (void *cls, | ||
805 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
806 | uint64_t first_fragment_id, | ||
807 | uint64_t last_fragment_id, | ||
808 | uint64_t *returned_fragments, | ||
809 | GNUNET_PSYCSTORE_FragmentCallback cb, | ||
810 | void *cb_cls) | ||
811 | { | ||
812 | struct Plugin *plugin = cls; | ||
813 | struct GNUNET_PQ_QueryParam params_select[] = { | ||
814 | GNUNET_PQ_query_param_auto_from_type (channel_key), | ||
815 | GNUNET_PQ_query_param_uint64 (&first_fragment_id), | ||
816 | GNUNET_PQ_query_param_uint64 (&last_fragment_id), | ||
817 | GNUNET_PQ_query_param_end | ||
818 | }; | ||
819 | |||
820 | *returned_fragments = 0; | ||
821 | return fragment_select (plugin, | ||
822 | "select_fragments", | ||
823 | params_select, | ||
824 | returned_fragments, | ||
825 | cb, cb_cls); | ||
826 | } | ||
827 | |||
828 | |||
829 | /** | ||
830 | * Retrieve a message fragment range by fragment ID. | ||
831 | * | ||
832 | * @see GNUNET_PSYCSTORE_fragment_get_latest() | ||
833 | * | ||
834 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
835 | */ | ||
836 | static int | ||
837 | fragment_get_latest (void *cls, | ||
838 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
839 | uint64_t fragment_limit, | ||
840 | uint64_t *returned_fragments, | ||
841 | GNUNET_PSYCSTORE_FragmentCallback cb, | ||
842 | void *cb_cls) | ||
843 | { | ||
844 | struct Plugin *plugin = cls; | ||
845 | |||
846 | *returned_fragments = 0; | ||
847 | |||
848 | struct GNUNET_PQ_QueryParam params_select[] = { | ||
849 | GNUNET_PQ_query_param_auto_from_type (channel_key), | ||
850 | GNUNET_PQ_query_param_uint64 (&fragment_limit), | ||
851 | GNUNET_PQ_query_param_end | ||
852 | }; | ||
853 | |||
854 | return fragment_select (plugin, | ||
855 | "select_latest_fragments", | ||
856 | params_select, | ||
857 | returned_fragments, | ||
858 | cb, cb_cls); | ||
859 | } | ||
860 | |||
861 | |||
862 | /** | ||
863 | * Retrieve all fragments of a message ID range. | ||
864 | * | ||
865 | * @see GNUNET_PSYCSTORE_message_get() | ||
866 | * | ||
867 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
868 | */ | ||
869 | static int | ||
870 | message_get (void *cls, | ||
871 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
872 | uint64_t first_message_id, | ||
873 | uint64_t last_message_id, | ||
874 | uint64_t fragment_limit, | ||
875 | uint64_t *returned_fragments, | ||
876 | GNUNET_PSYCSTORE_FragmentCallback cb, | ||
877 | void *cb_cls) | ||
878 | { | ||
879 | struct Plugin *plugin = cls; | ||
880 | struct GNUNET_PQ_QueryParam params_select[] = { | ||
881 | GNUNET_PQ_query_param_auto_from_type (channel_key), | ||
882 | GNUNET_PQ_query_param_uint64 (&first_message_id), | ||
883 | GNUNET_PQ_query_param_uint64 (&last_message_id), | ||
884 | GNUNET_PQ_query_param_uint64 (&fragment_limit), | ||
885 | GNUNET_PQ_query_param_end | ||
886 | }; | ||
887 | |||
888 | if (0 == fragment_limit) | ||
889 | fragment_limit = INT64_MAX; | ||
890 | *returned_fragments = 0; | ||
891 | return fragment_select (plugin, | ||
892 | "select_messages", | ||
893 | params_select, | ||
894 | returned_fragments, | ||
895 | cb, cb_cls); | ||
896 | } | ||
897 | |||
898 | |||
899 | /** | ||
900 | * Retrieve all fragments of the latest messages. | ||
901 | * | ||
902 | * @see GNUNET_PSYCSTORE_message_get_latest() | ||
903 | * | ||
904 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
905 | */ | ||
906 | static int | ||
907 | message_get_latest (void *cls, | ||
908 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
909 | uint64_t message_limit, | ||
910 | uint64_t *returned_fragments, | ||
911 | GNUNET_PSYCSTORE_FragmentCallback cb, | ||
912 | void *cb_cls) | ||
913 | { | ||
914 | struct Plugin *plugin = cls; | ||
915 | struct GNUNET_PQ_QueryParam params_select[] = { | ||
916 | GNUNET_PQ_query_param_auto_from_type (channel_key), | ||
917 | GNUNET_PQ_query_param_auto_from_type (channel_key), | ||
918 | GNUNET_PQ_query_param_uint64 (&message_limit), | ||
919 | GNUNET_PQ_query_param_end | ||
920 | }; | ||
921 | |||
922 | *returned_fragments = 0; | ||
923 | return fragment_select (plugin, | ||
924 | "select_latest_messages", | ||
925 | params_select, | ||
926 | returned_fragments, | ||
927 | cb, cb_cls); | ||
928 | } | ||
929 | |||
930 | |||
931 | /** | ||
932 | * Retrieve a fragment of message specified by its message ID and fragment | ||
933 | * offset. | ||
934 | * | ||
935 | * @see GNUNET_PSYCSTORE_message_get_fragment() | ||
936 | * | ||
937 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
938 | */ | ||
939 | static int | ||
940 | message_get_fragment (void *cls, | ||
941 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
942 | uint64_t message_id, | ||
943 | uint64_t fragment_offset, | ||
944 | GNUNET_PSYCSTORE_FragmentCallback cb, | ||
945 | void *cb_cls) | ||
946 | { | ||
947 | struct Plugin *plugin = cls; | ||
948 | const char *stmt = "select_message_fragment"; | ||
949 | |||
950 | struct GNUNET_PQ_QueryParam params_select[] = { | ||
951 | GNUNET_PQ_query_param_auto_from_type (channel_key), | ||
952 | GNUNET_PQ_query_param_uint64 (&message_id), | ||
953 | GNUNET_PQ_query_param_uint64 (&fragment_offset), | ||
954 | GNUNET_PQ_query_param_end | ||
955 | }; | ||
956 | |||
957 | /* Stack based closure */ | ||
958 | struct FragmentRowsContext frc = { | ||
959 | .cb = cb, | ||
960 | .cb_cls = cb_cls, | ||
961 | .returned_fragments = NULL, | ||
962 | .ret = GNUNET_SYSERR | ||
963 | }; | ||
964 | |||
965 | if (0 > GNUNET_PQ_eval_prepared_multi_select (plugin->dbh, | ||
966 | stmt, params_select, | ||
967 | &fragment_rows, &frc)) | ||
968 | return GNUNET_SYSERR; | ||
969 | return frc.ret; /* GNUNET_OK ?? */ | ||
970 | } | ||
971 | |||
972 | /** | ||
973 | * Retrieve the max. values of message counters for a channel. | ||
974 | * | ||
975 | * @see GNUNET_PSYCSTORE_counters_get() | ||
976 | * | ||
977 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
978 | */ | ||
979 | static int | ||
980 | counters_message_get (void *cls, | ||
981 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
982 | uint64_t *max_fragment_id, | ||
983 | uint64_t *max_message_id, | ||
984 | uint64_t *max_group_generation) | ||
985 | { | ||
986 | struct Plugin *plugin = cls; | ||
987 | |||
988 | const char *stmt = "select_counters_message"; | ||
989 | |||
990 | struct GNUNET_PQ_QueryParam params_select[] = { | ||
991 | GNUNET_PQ_query_param_auto_from_type (channel_key), | ||
992 | GNUNET_PQ_query_param_end | ||
993 | }; | ||
994 | |||
995 | struct GNUNET_PQ_ResultSpec results_select[] = { | ||
996 | GNUNET_PQ_result_spec_uint64 ("fragment_id", max_fragment_id), | ||
997 | GNUNET_PQ_result_spec_uint64 ("message_id", max_message_id), | ||
998 | GNUNET_PQ_result_spec_uint64 ("group_generation", max_group_generation), | ||
999 | GNUNET_PQ_result_spec_end | ||
1000 | }; | ||
1001 | |||
1002 | if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != | ||
1003 | GNUNET_PQ_eval_prepared_singleton_select (plugin->dbh, stmt, | ||
1004 | params_select, results_select)) | ||
1005 | return GNUNET_SYSERR; | ||
1006 | |||
1007 | return GNUNET_OK; | ||
1008 | } | ||
1009 | |||
1010 | /** | ||
1011 | * Retrieve the max. values of state counters for a channel. | ||
1012 | * | ||
1013 | * @see GNUNET_PSYCSTORE_counters_get() | ||
1014 | * | ||
1015 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
1016 | */ | ||
1017 | static int | ||
1018 | counters_state_get (void *cls, | ||
1019 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1020 | uint64_t *max_state_message_id) | ||
1021 | { | ||
1022 | struct Plugin *plugin = cls; | ||
1023 | |||
1024 | const char *stmt = "select_counters_state"; | ||
1025 | |||
1026 | struct GNUNET_PQ_QueryParam params_select[] = { | ||
1027 | GNUNET_PQ_query_param_auto_from_type (channel_key), | ||
1028 | GNUNET_PQ_query_param_end | ||
1029 | }; | ||
1030 | |||
1031 | struct GNUNET_PQ_ResultSpec results_select[] = { | ||
1032 | GNUNET_PQ_result_spec_uint64 ("max_state_message_id", max_state_message_id), | ||
1033 | GNUNET_PQ_result_spec_end | ||
1034 | }; | ||
1035 | |||
1036 | if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != | ||
1037 | GNUNET_PQ_eval_prepared_singleton_select (plugin->dbh, stmt, | ||
1038 | params_select, results_select)) | ||
1039 | return GNUNET_SYSERR; | ||
1040 | |||
1041 | return GNUNET_OK; | ||
1042 | } | ||
1043 | |||
1044 | |||
1045 | /** | ||
1046 | * Assign a value to a state variable. | ||
1047 | * | ||
1048 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
1049 | */ | ||
1050 | static int | ||
1051 | state_assign (struct Plugin *plugin, const char *stmt, | ||
1052 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1053 | const char *name, const void *value, size_t value_size) | ||
1054 | { | ||
1055 | struct GNUNET_PQ_QueryParam params[] = { | ||
1056 | GNUNET_PQ_query_param_auto_from_type (channel_key), | ||
1057 | GNUNET_PQ_query_param_string (name), | ||
1058 | GNUNET_PQ_query_param_fixed_size (value, value_size), | ||
1059 | GNUNET_PQ_query_param_end | ||
1060 | }; | ||
1061 | |||
1062 | if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != | ||
1063 | GNUNET_PQ_eval_prepared_non_select (plugin->dbh, stmt, params)) | ||
1064 | return GNUNET_SYSERR; | ||
1065 | |||
1066 | return GNUNET_OK; | ||
1067 | } | ||
1068 | |||
1069 | |||
1070 | static int | ||
1071 | update_message_id (struct Plugin *plugin, | ||
1072 | const char *stmt, | ||
1073 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1074 | uint64_t message_id) | ||
1075 | { | ||
1076 | struct GNUNET_PQ_QueryParam params[] = { | ||
1077 | GNUNET_PQ_query_param_uint64 (&message_id), | ||
1078 | GNUNET_PQ_query_param_auto_from_type (channel_key), | ||
1079 | GNUNET_PQ_query_param_end | ||
1080 | }; | ||
1081 | |||
1082 | if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS != | ||
1083 | GNUNET_PQ_eval_prepared_non_select (plugin->dbh, stmt, params)) | ||
1084 | return GNUNET_SYSERR; | ||
1085 | |||
1086 | return GNUNET_OK; | ||
1087 | } | ||
1088 | |||
1089 | |||
1090 | /** | ||
1091 | * Begin modifying current state. | ||
1092 | */ | ||
1093 | static int | ||
1094 | state_modify_begin (void *cls, | ||
1095 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1096 | uint64_t message_id, uint64_t state_delta) | ||
1097 | { | ||
1098 | struct Plugin *plugin = cls; | ||
1099 | |||
1100 | if (state_delta > 0) | ||
1101 | { | ||
1102 | /** | ||
1103 | * We can only apply state modifiers in the current message if modifiers in | ||
1104 | * the previous stateful message (message_id - state_delta) were already | ||
1105 | * applied. | ||
1106 | */ | ||
1107 | |||
1108 | uint64_t max_state_message_id = 0; | ||
1109 | int ret = counters_state_get (plugin, channel_key, &max_state_message_id); | ||
1110 | switch (ret) | ||
1111 | { | ||
1112 | case GNUNET_OK: | ||
1113 | case GNUNET_NO: // no state yet | ||
1114 | ret = GNUNET_OK; | ||
1115 | break; | ||
1116 | |||
1117 | default: | ||
1118 | return ret; | ||
1119 | } | ||
1120 | |||
1121 | if (max_state_message_id < message_id - state_delta) | ||
1122 | return GNUNET_NO; /* some stateful messages not yet applied */ | ||
1123 | else if (message_id - state_delta < max_state_message_id) | ||
1124 | return GNUNET_NO; /* changes already applied */ | ||
1125 | } | ||
1126 | |||
1127 | if (TRANSACTION_NONE != plugin->transaction) | ||
1128 | { | ||
1129 | /** @todo FIXME: wait for other transaction to finish */ | ||
1130 | return GNUNET_SYSERR; | ||
1131 | } | ||
1132 | return transaction_begin (plugin, TRANSACTION_STATE_MODIFY); | ||
1133 | } | ||
1134 | |||
1135 | |||
1136 | /** | ||
1137 | * Set the current value of state variable. | ||
1138 | * | ||
1139 | * @see GNUNET_PSYCSTORE_state_modify() | ||
1140 | * | ||
1141 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
1142 | */ | ||
1143 | static int | ||
1144 | state_modify_op (void *cls, | ||
1145 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1146 | enum GNUNET_PSYC_Operator op, | ||
1147 | const char *name, const void *value, size_t value_size) | ||
1148 | { | ||
1149 | struct Plugin *plugin = cls; | ||
1150 | GNUNET_assert (TRANSACTION_STATE_MODIFY == plugin->transaction); | ||
1151 | |||
1152 | switch (op) | ||
1153 | { | ||
1154 | case GNUNET_PSYC_OP_ASSIGN: | ||
1155 | return state_assign (plugin, "insert_state_current", | ||
1156 | channel_key, name, value, value_size); | ||
1157 | |||
1158 | default: /** @todo implement more state operations */ | ||
1159 | GNUNET_break (0); | ||
1160 | return GNUNET_SYSERR; | ||
1161 | } | ||
1162 | } | ||
1163 | |||
1164 | |||
1165 | /** | ||
1166 | * End modifying current state. | ||
1167 | */ | ||
1168 | static int | ||
1169 | state_modify_end (void *cls, | ||
1170 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1171 | uint64_t message_id) | ||
1172 | { | ||
1173 | struct Plugin *plugin = cls; | ||
1174 | GNUNET_assert (TRANSACTION_STATE_MODIFY == plugin->transaction); | ||
1175 | |||
1176 | return | ||
1177 | GNUNET_OK == exec_channel (plugin, "delete_state_empty", channel_key) | ||
1178 | && GNUNET_OK == update_message_id (plugin, | ||
1179 | "update_max_state_message_id", | ||
1180 | channel_key, message_id) | ||
1181 | && GNUNET_OK == transaction_commit (plugin) | ||
1182 | ? GNUNET_OK : GNUNET_SYSERR; | ||
1183 | } | ||
1184 | |||
1185 | |||
1186 | /** | ||
1187 | * Begin state synchronization. | ||
1188 | */ | ||
1189 | static int | ||
1190 | state_sync_begin (void *cls, | ||
1191 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key) | ||
1192 | { | ||
1193 | struct Plugin *plugin = cls; | ||
1194 | return exec_channel (plugin, "delete_state_sync", channel_key); | ||
1195 | } | ||
1196 | |||
1197 | |||
1198 | /** | ||
1199 | * Assign current value of a state variable. | ||
1200 | * | ||
1201 | * @see GNUNET_PSYCSTORE_state_modify() | ||
1202 | * | ||
1203 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
1204 | */ | ||
1205 | static int | ||
1206 | state_sync_assign (void *cls, | ||
1207 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1208 | const char *name, const void *value, size_t value_size) | ||
1209 | { | ||
1210 | struct Plugin *plugin = cls; | ||
1211 | return state_assign (plugin, "insert_state_sync", | ||
1212 | channel_key, name, value, value_size); | ||
1213 | } | ||
1214 | |||
1215 | |||
1216 | /** | ||
1217 | * End modifying current state. | ||
1218 | */ | ||
1219 | static int | ||
1220 | state_sync_end (void *cls, | ||
1221 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1222 | uint64_t max_state_message_id, | ||
1223 | uint64_t state_hash_message_id) | ||
1224 | { | ||
1225 | struct Plugin *plugin = cls; | ||
1226 | int ret = GNUNET_SYSERR; | ||
1227 | |||
1228 | if (TRANSACTION_NONE != plugin->transaction) | ||
1229 | { | ||
1230 | /** @todo FIXME: wait for other transaction to finish */ | ||
1231 | return GNUNET_SYSERR; | ||
1232 | } | ||
1233 | |||
1234 | GNUNET_OK == transaction_begin (plugin, TRANSACTION_STATE_SYNC) | ||
1235 | && GNUNET_OK == exec_channel (plugin, "delete_state", channel_key) | ||
1236 | && GNUNET_OK == exec_channel (plugin, "insert_state_from_sync", | ||
1237 | channel_key) | ||
1238 | && GNUNET_OK == exec_channel (plugin, "delete_state_sync", | ||
1239 | channel_key) | ||
1240 | && GNUNET_OK == update_message_id (plugin, | ||
1241 | "update_state_hash_message_id", | ||
1242 | channel_key, state_hash_message_id) | ||
1243 | && GNUNET_OK == update_message_id (plugin, | ||
1244 | "update_max_state_message_id", | ||
1245 | channel_key, max_state_message_id) | ||
1246 | && GNUNET_OK == transaction_commit (plugin) | ||
1247 | ? ret = GNUNET_OK | ||
1248 | : transaction_rollback (plugin); | ||
1249 | return ret; | ||
1250 | } | ||
1251 | |||
1252 | |||
1253 | /** | ||
1254 | * Delete the whole state. | ||
1255 | * | ||
1256 | * @see GNUNET_PSYCSTORE_state_reset() | ||
1257 | * | ||
1258 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
1259 | */ | ||
1260 | static int | ||
1261 | state_reset (void *cls, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key) | ||
1262 | { | ||
1263 | struct Plugin *plugin = cls; | ||
1264 | return exec_channel (plugin, "delete_state", channel_key); | ||
1265 | } | ||
1266 | |||
1267 | |||
1268 | /** | ||
1269 | * Update signed values of state variables in the state store. | ||
1270 | * | ||
1271 | * @see GNUNET_PSYCSTORE_state_hash_update() | ||
1272 | * | ||
1273 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
1274 | */ | ||
1275 | static int | ||
1276 | state_update_signed (void *cls, | ||
1277 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key) | ||
1278 | { | ||
1279 | struct Plugin *plugin = cls; | ||
1280 | return exec_channel (plugin, "update_state_signed", channel_key); | ||
1281 | } | ||
1282 | |||
1283 | |||
1284 | /** | ||
1285 | * Retrieve a state variable by name. | ||
1286 | * | ||
1287 | * @see GNUNET_PSYCSTORE_state_get() | ||
1288 | * | ||
1289 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
1290 | */ | ||
1291 | static int | ||
1292 | state_get (void *cls, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1293 | const char *name, GNUNET_PSYCSTORE_StateCallback cb, void *cb_cls) | ||
1294 | { | ||
1295 | struct Plugin *plugin = cls; | ||
1296 | |||
1297 | const char *stmt = "select_state_one"; | ||
1298 | |||
1299 | struct GNUNET_PQ_QueryParam params_select[] = { | ||
1300 | GNUNET_PQ_query_param_auto_from_type (channel_key), | ||
1301 | GNUNET_PQ_query_param_string (name), | ||
1302 | GNUNET_PQ_query_param_end | ||
1303 | }; | ||
1304 | |||
1305 | void *value_current = NULL; | ||
1306 | size_t value_size = 0; | ||
1307 | |||
1308 | struct GNUNET_PQ_ResultSpec results_select[] = { | ||
1309 | GNUNET_PQ_result_spec_variable_size ("value_current", &value_current, &value_size), | ||
1310 | GNUNET_PQ_result_spec_end | ||
1311 | }; | ||
1312 | |||
1313 | if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT != | ||
1314 | GNUNET_PQ_eval_prepared_singleton_select (plugin->dbh, stmt, | ||
1315 | params_select, results_select)) | ||
1316 | return GNUNET_SYSERR; | ||
1317 | |||
1318 | return cb (cb_cls, name, value_current, | ||
1319 | value_size); | ||
1320 | } | ||
1321 | |||
1322 | |||
1323 | |||
1324 | /** | ||
1325 | * Closure for #get_state_cb. | ||
1326 | */ | ||
1327 | struct GetStateContext { | ||
1328 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key; | ||
1329 | // const char *name, | ||
1330 | GNUNET_PSYCSTORE_StateCallback cb; | ||
1331 | void *cb_cls; | ||
1332 | |||
1333 | const char *value_id; | ||
1334 | |||
1335 | /* I preserved this but I do not see the point since | ||
1336 | * it cannot stop the loop early and gets overwritten ?? */ | ||
1337 | int ret; | ||
1338 | }; | ||
1339 | |||
1340 | |||
1341 | /** | ||
1342 | * Callback that retrieves the results of a SELECT statement | ||
1343 | * reading form the state table. | ||
1344 | * | ||
1345 | * Only passed to GNUNET_PQ_eval_prepared_multi_select and | ||
1346 | * has type GNUNET_PQ_PostgresResultHandler. | ||
1347 | * | ||
1348 | * @param cls closure | ||
1349 | * @param result the postgres result | ||
1350 | * @param num_result the number of results in @a result | ||
1351 | */ | ||
1352 | static void | ||
1353 | get_state_cb (void *cls, | ||
1354 | PGresult *res, | ||
1355 | unsigned int num_results) | ||
1356 | { | ||
1357 | struct GetStateContext *c = cls; | ||
1358 | |||
1359 | for (unsigned int i=0;i<num_results;i++) | ||
1360 | { | ||
1361 | char *name = ""; | ||
1362 | void *value = NULL; | ||
1363 | size_t value_size = 0; | ||
1364 | |||
1365 | struct GNUNET_PQ_ResultSpec results[] = { | ||
1366 | GNUNET_PQ_result_spec_string ("name", &name), | ||
1367 | GNUNET_PQ_result_spec_variable_size (c->value_id, &value, &value_size), | ||
1368 | GNUNET_PQ_result_spec_end | ||
1369 | }; | ||
1370 | |||
1371 | if (GNUNET_YES != GNUNET_PQ_extract_result (res, results, i)) | ||
1372 | { | ||
1373 | GNUNET_PQ_cleanup_result(results); /* previously invoked via PQclear?? */ | ||
1374 | break; /* nothing more?? */ | ||
1375 | } | ||
1376 | |||
1377 | c->ret = c->cb (c->cb_cls, (const char *) name, value, value_size); | ||
1378 | GNUNET_PQ_cleanup_result(results); | ||
1379 | } | ||
1380 | } | ||
1381 | |||
1382 | /** | ||
1383 | * Retrieve all state variables for a channel with the given prefix. | ||
1384 | * | ||
1385 | * @see GNUNET_PSYCSTORE_state_get_prefix() | ||
1386 | * | ||
1387 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
1388 | */ | ||
1389 | static int | ||
1390 | state_get_prefix (void *cls, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1391 | const char *name, GNUNET_PSYCSTORE_StateCallback cb, | ||
1392 | void *cb_cls) | ||
1393 | { | ||
1394 | struct Plugin *plugin = cls; | ||
1395 | |||
1396 | const char *stmt = "select_state_prefix"; | ||
1397 | |||
1398 | uint32_t name_len = (uint32_t) strlen (name); | ||
1399 | |||
1400 | struct GNUNET_PQ_QueryParam params_select[] = { | ||
1401 | GNUNET_PQ_query_param_auto_from_type (channel_key), | ||
1402 | GNUNET_PQ_query_param_string (name), | ||
1403 | GNUNET_PQ_query_param_uint32 (&name_len), | ||
1404 | GNUNET_PQ_query_param_string (name), | ||
1405 | GNUNET_PQ_query_param_end | ||
1406 | }; | ||
1407 | |||
1408 | struct GetStateContext gsc = { | ||
1409 | .cb = cb, | ||
1410 | .cb_cls = cb_cls, | ||
1411 | .value_id = "value_current", | ||
1412 | .ret = GNUNET_NO | ||
1413 | }; | ||
1414 | |||
1415 | if (0 > GNUNET_PQ_eval_prepared_multi_select (plugin->dbh, | ||
1416 | stmt, params_select, | ||
1417 | &get_state_cb, &gsc)) | ||
1418 | return GNUNET_SYSERR; | ||
1419 | return gsc.ret; /* GNUNET_OK ?? */ | ||
1420 | } | ||
1421 | |||
1422 | |||
1423 | /** | ||
1424 | * Retrieve all signed state variables for a channel. | ||
1425 | * | ||
1426 | * @see GNUNET_PSYCSTORE_state_get_signed() | ||
1427 | * | ||
1428 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
1429 | */ | ||
1430 | static int | ||
1431 | state_get_signed (void *cls, | ||
1432 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1433 | GNUNET_PSYCSTORE_StateCallback cb, void *cb_cls) | ||
1434 | { | ||
1435 | struct Plugin *plugin = cls; | ||
1436 | |||
1437 | const char *stmt = "select_state_signed"; | ||
1438 | |||
1439 | struct GNUNET_PQ_QueryParam params_select[] = { | ||
1440 | GNUNET_PQ_query_param_auto_from_type (channel_key), | ||
1441 | GNUNET_PQ_query_param_end | ||
1442 | }; | ||
1443 | |||
1444 | struct GetStateContext gsc = { | ||
1445 | .cb = cb, | ||
1446 | .cb_cls = cb_cls, | ||
1447 | .value_id = "value_signed", | ||
1448 | .ret = GNUNET_NO | ||
1449 | }; | ||
1450 | |||
1451 | if (0 > GNUNET_PQ_eval_prepared_multi_select (plugin->dbh, | ||
1452 | stmt, params_select, | ||
1453 | &get_state_cb, &gsc)) | ||
1454 | return GNUNET_SYSERR; | ||
1455 | return gsc.ret; /* GNUNET_OK ?? */ | ||
1456 | } | ||
1457 | |||
1458 | |||
1459 | /** | ||
1460 | * Entry point for the plugin. | ||
1461 | * | ||
1462 | * @param cls The struct GNUNET_CONFIGURATION_Handle. | ||
1463 | * @return NULL on error, otherwise the plugin context | ||
1464 | */ | ||
1465 | void * | ||
1466 | libgnunet_plugin_psycstore_postgres_init (void *cls) | ||
1467 | { | ||
1468 | static struct Plugin plugin; | ||
1469 | const struct GNUNET_CONFIGURATION_Handle *cfg = cls; | ||
1470 | struct GNUNET_PSYCSTORE_PluginFunctions *api; | ||
1471 | |||
1472 | if (NULL != plugin.cfg) | ||
1473 | return NULL; /* can only initialize once! */ | ||
1474 | memset (&plugin, 0, sizeof (struct Plugin)); | ||
1475 | plugin.cfg = cfg; | ||
1476 | if (GNUNET_OK != database_setup (&plugin)) | ||
1477 | { | ||
1478 | database_shutdown (&plugin); | ||
1479 | return NULL; | ||
1480 | } | ||
1481 | api = GNUNET_new (struct GNUNET_PSYCSTORE_PluginFunctions); | ||
1482 | api->cls = &plugin; | ||
1483 | api->membership_store = &postgres_membership_store; | ||
1484 | api->membership_test = &membership_test; | ||
1485 | api->fragment_store = &fragment_store; | ||
1486 | api->message_add_flags = &message_add_flags; | ||
1487 | api->fragment_get = &fragment_get; | ||
1488 | api->fragment_get_latest = &fragment_get_latest; | ||
1489 | api->message_get = &message_get; | ||
1490 | api->message_get_latest = &message_get_latest; | ||
1491 | api->message_get_fragment = &message_get_fragment; | ||
1492 | api->counters_message_get = &counters_message_get; | ||
1493 | api->counters_state_get = &counters_state_get; | ||
1494 | api->state_modify_begin = &state_modify_begin; | ||
1495 | api->state_modify_op = &state_modify_op; | ||
1496 | api->state_modify_end = &state_modify_end; | ||
1497 | api->state_sync_begin = &state_sync_begin; | ||
1498 | api->state_sync_assign = &state_sync_assign; | ||
1499 | api->state_sync_end = &state_sync_end; | ||
1500 | api->state_reset = &state_reset; | ||
1501 | api->state_update_signed = &state_update_signed; | ||
1502 | api->state_get = &state_get; | ||
1503 | api->state_get_prefix = &state_get_prefix; | ||
1504 | api->state_get_signed = &state_get_signed; | ||
1505 | |||
1506 | LOG (GNUNET_ERROR_TYPE_INFO, _("Postgres database running\n")); | ||
1507 | return api; | ||
1508 | } | ||
1509 | |||
1510 | |||
1511 | /** | ||
1512 | * Exit point from the plugin. | ||
1513 | * | ||
1514 | * @param cls The plugin context (as returned by "init") | ||
1515 | * @return Always NULL | ||
1516 | */ | ||
1517 | void * | ||
1518 | libgnunet_plugin_psycstore_postgres_done (void *cls) | ||
1519 | { | ||
1520 | struct GNUNET_PSYCSTORE_PluginFunctions *api = cls; | ||
1521 | struct Plugin *plugin = api->cls; | ||
1522 | |||
1523 | database_shutdown (plugin); | ||
1524 | plugin->cfg = NULL; | ||
1525 | GNUNET_free (api); | ||
1526 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Postgres plugin has finished\n"); | ||
1527 | return NULL; | ||
1528 | } | ||
1529 | |||
1530 | /* end of plugin_psycstore_postgres.c */ | ||
diff --git a/src/psycstore/plugin_psycstore_sqlite.c b/src/psycstore/plugin_psycstore_sqlite.c deleted file mode 100644 index 24de38392..000000000 --- a/src/psycstore/plugin_psycstore_sqlite.c +++ /dev/null | |||
@@ -1,1948 +0,0 @@ | |||
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 psycstore/plugin_psycstore_sqlite.c | ||
23 | * @brief sqlite-based psycstore backend | ||
24 | * @author Gabor X Toth | ||
25 | * @author Christian Grothoff | ||
26 | */ | ||
27 | |||
28 | /* | ||
29 | * FIXME: SQLite3 only supports signed 64-bit integers natively, | ||
30 | * thus it can only store 63 bits of the uint64_t's. | ||
31 | */ | ||
32 | |||
33 | #include "platform.h" | ||
34 | #include "gnunet_psycstore_plugin.h" | ||
35 | #include "gnunet_psycstore_service.h" | ||
36 | #include "gnunet_multicast_service.h" | ||
37 | #include "gnunet_crypto_lib.h" | ||
38 | #include "gnunet_psyc_util_lib.h" | ||
39 | #include "psycstore.h" | ||
40 | #include <sqlite3.h> | ||
41 | |||
42 | /** | ||
43 | * After how many ms "busy" should a DB operation fail for good? A | ||
44 | * low value makes sure that we are more responsive to requests | ||
45 | * (especially PUTs). A high value guarantees a higher success rate | ||
46 | * (SELECTs in iterate can take several seconds despite LIMIT=1). | ||
47 | * | ||
48 | * The default value of 1s should ensure that users do not experience | ||
49 | * huge latencies while at the same time allowing operations to | ||
50 | * succeed with reasonable probability. | ||
51 | */ | ||
52 | #define BUSY_TIMEOUT_MS 1000 | ||
53 | |||
54 | #define DEBUG_PSYCSTORE GNUNET_EXTRA_LOGGING | ||
55 | |||
56 | /** | ||
57 | * Log an error message at log-level 'level' that indicates | ||
58 | * a failure of the command 'cmd' on file 'filename' | ||
59 | * with the message given by strerror(errno). | ||
60 | */ | ||
61 | #define LOG_SQLITE(db, level, cmd) do { GNUNET_log_from (level, "psycstore-sqlite", _("`%s' failed at %s:%d with error: %s (%d)\n"), cmd, __FILE__, __LINE__, sqlite3_errmsg(db->dbh), sqlite3_errcode(db->dbh)); } while(0) | ||
62 | |||
63 | #define LOG(kind,...) GNUNET_log_from (kind, "psycstore-sqlite", __VA_ARGS__) | ||
64 | |||
65 | enum Transactions { | ||
66 | TRANSACTION_NONE = 0, | ||
67 | TRANSACTION_STATE_MODIFY, | ||
68 | TRANSACTION_STATE_SYNC, | ||
69 | }; | ||
70 | |||
71 | /** | ||
72 | * Context for all functions in this plugin. | ||
73 | */ | ||
74 | struct Plugin | ||
75 | { | ||
76 | |||
77 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
78 | |||
79 | /** | ||
80 | * Database filename. | ||
81 | */ | ||
82 | char *fn; | ||
83 | |||
84 | /** | ||
85 | * Native SQLite database handle. | ||
86 | */ | ||
87 | sqlite3 *dbh; | ||
88 | |||
89 | /** | ||
90 | * Current transaction. | ||
91 | */ | ||
92 | enum Transactions transaction; | ||
93 | |||
94 | sqlite3_stmt *transaction_begin; | ||
95 | |||
96 | sqlite3_stmt *transaction_commit; | ||
97 | |||
98 | sqlite3_stmt *transaction_rollback; | ||
99 | |||
100 | /** | ||
101 | * Precompiled SQL for channel_key_store() | ||
102 | */ | ||
103 | sqlite3_stmt *insert_channel_key; | ||
104 | |||
105 | /** | ||
106 | * Precompiled SQL for slave_key_store() | ||
107 | */ | ||
108 | sqlite3_stmt *insert_slave_key; | ||
109 | |||
110 | |||
111 | /** | ||
112 | * Precompiled SQL for membership_store() | ||
113 | */ | ||
114 | sqlite3_stmt *insert_membership; | ||
115 | |||
116 | /** | ||
117 | * Precompiled SQL for membership_test() | ||
118 | */ | ||
119 | sqlite3_stmt *select_membership; | ||
120 | |||
121 | |||
122 | /** | ||
123 | * Precompiled SQL for fragment_store() | ||
124 | */ | ||
125 | sqlite3_stmt *insert_fragment; | ||
126 | |||
127 | /** | ||
128 | * Precompiled SQL for message_add_flags() | ||
129 | */ | ||
130 | sqlite3_stmt *update_message_flags; | ||
131 | |||
132 | /** | ||
133 | * Precompiled SQL for fragment_get() | ||
134 | */ | ||
135 | sqlite3_stmt *select_fragments; | ||
136 | |||
137 | /** | ||
138 | * Precompiled SQL for fragment_get() | ||
139 | */ | ||
140 | sqlite3_stmt *select_latest_fragments; | ||
141 | |||
142 | /** | ||
143 | * Precompiled SQL for message_get() | ||
144 | */ | ||
145 | sqlite3_stmt *select_messages; | ||
146 | |||
147 | /** | ||
148 | * Precompiled SQL for message_get() | ||
149 | */ | ||
150 | sqlite3_stmt *select_latest_messages; | ||
151 | |||
152 | /** | ||
153 | * Precompiled SQL for message_get_fragment() | ||
154 | */ | ||
155 | sqlite3_stmt *select_message_fragment; | ||
156 | |||
157 | /** | ||
158 | * Precompiled SQL for counters_get_message() | ||
159 | */ | ||
160 | sqlite3_stmt *select_counters_message; | ||
161 | |||
162 | /** | ||
163 | * Precompiled SQL for counters_get_state() | ||
164 | */ | ||
165 | sqlite3_stmt *select_counters_state; | ||
166 | |||
167 | /** | ||
168 | * Precompiled SQL for state_modify_end() | ||
169 | */ | ||
170 | sqlite3_stmt *update_state_hash_message_id; | ||
171 | |||
172 | /** | ||
173 | * Precompiled SQL for state_sync_end() | ||
174 | */ | ||
175 | sqlite3_stmt *update_max_state_message_id; | ||
176 | |||
177 | /** | ||
178 | * Precompiled SQL for state_modify_op() | ||
179 | */ | ||
180 | sqlite3_stmt *insert_state_current; | ||
181 | |||
182 | /** | ||
183 | * Precompiled SQL for state_modify_end() | ||
184 | */ | ||
185 | sqlite3_stmt *delete_state_empty; | ||
186 | |||
187 | /** | ||
188 | * Precompiled SQL for state_set_signed() | ||
189 | */ | ||
190 | sqlite3_stmt *update_state_signed; | ||
191 | |||
192 | /** | ||
193 | * Precompiled SQL for state_sync() | ||
194 | */ | ||
195 | sqlite3_stmt *insert_state_sync; | ||
196 | |||
197 | /** | ||
198 | * Precompiled SQL for state_sync() | ||
199 | */ | ||
200 | sqlite3_stmt *delete_state; | ||
201 | |||
202 | /** | ||
203 | * Precompiled SQL for state_sync() | ||
204 | */ | ||
205 | sqlite3_stmt *insert_state_from_sync; | ||
206 | |||
207 | /** | ||
208 | * Precompiled SQL for state_sync() | ||
209 | */ | ||
210 | sqlite3_stmt *delete_state_sync; | ||
211 | |||
212 | /** | ||
213 | * Precompiled SQL for state_get_signed() | ||
214 | */ | ||
215 | sqlite3_stmt *select_state_signed; | ||
216 | |||
217 | /** | ||
218 | * Precompiled SQL for state_get() | ||
219 | */ | ||
220 | sqlite3_stmt *select_state_one; | ||
221 | |||
222 | /** | ||
223 | * Precompiled SQL for state_get_prefix() | ||
224 | */ | ||
225 | sqlite3_stmt *select_state_prefix; | ||
226 | |||
227 | }; | ||
228 | |||
229 | #if DEBUG_PSYCSTORE | ||
230 | |||
231 | static void | ||
232 | sql_trace (void *cls, const char *sql) | ||
233 | { | ||
234 | LOG (GNUNET_ERROR_TYPE_DEBUG, "SQL query:\n%s\n", sql); | ||
235 | } | ||
236 | |||
237 | #endif | ||
238 | |||
239 | /** | ||
240 | * @brief Prepare a SQL statement | ||
241 | * | ||
242 | * @param dbh handle to the database | ||
243 | * @param sql SQL statement, UTF-8 encoded | ||
244 | * @param stmt set to the prepared statement | ||
245 | * @return 0 on success | ||
246 | */ | ||
247 | static int | ||
248 | sql_prepare (sqlite3 *dbh, const char *sql, sqlite3_stmt **stmt) | ||
249 | { | ||
250 | char *tail; | ||
251 | int result; | ||
252 | |||
253 | result = sqlite3_prepare_v2 (dbh, sql, strlen (sql), stmt, | ||
254 | (const char **) &tail); | ||
255 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
256 | "Prepared `%s' / %p: %d\n", sql, *stmt, result); | ||
257 | if (result != SQLITE_OK) | ||
258 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
259 | _("Error preparing SQL query: %s\n %s\n"), | ||
260 | sqlite3_errmsg (dbh), sql); | ||
261 | return result; | ||
262 | } | ||
263 | |||
264 | |||
265 | /** | ||
266 | * @brief Prepare a SQL statement | ||
267 | * | ||
268 | * @param dbh handle to the database | ||
269 | * @param sql SQL statement, UTF-8 encoded | ||
270 | * @return 0 on success | ||
271 | */ | ||
272 | static int | ||
273 | sql_exec (sqlite3 *dbh, const char *sql) | ||
274 | { | ||
275 | int result; | ||
276 | |||
277 | result = sqlite3_exec (dbh, sql, NULL, NULL, NULL); | ||
278 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
279 | "Executed `%s' / %d\n", sql, result); | ||
280 | if (result != SQLITE_OK) | ||
281 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
282 | _("Error executing SQL query: %s\n %s\n"), | ||
283 | sqlite3_errmsg (dbh), sql); | ||
284 | return result; | ||
285 | } | ||
286 | |||
287 | |||
288 | /** | ||
289 | * Initialize the database connections and associated | ||
290 | * data structures (create tables and indices | ||
291 | * as needed as well). | ||
292 | * | ||
293 | * @param plugin the plugin context (state for this module) | ||
294 | * @return GNUNET_OK on success | ||
295 | */ | ||
296 | static int | ||
297 | database_setup (struct Plugin *plugin) | ||
298 | { | ||
299 | char *filename; | ||
300 | |||
301 | if (GNUNET_OK != | ||
302 | GNUNET_CONFIGURATION_get_value_filename (plugin->cfg, "psycstore-sqlite", | ||
303 | "FILENAME", &filename)) | ||
304 | { | ||
305 | GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, | ||
306 | "psycstore-sqlite", "FILENAME"); | ||
307 | return GNUNET_SYSERR; | ||
308 | } | ||
309 | if (GNUNET_OK != GNUNET_DISK_file_test (filename)) | ||
310 | { | ||
311 | if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (filename)) | ||
312 | { | ||
313 | GNUNET_break (0); | ||
314 | GNUNET_free (filename); | ||
315 | return GNUNET_SYSERR; | ||
316 | } | ||
317 | } | ||
318 | /* filename should be UTF-8-encoded. If it isn't, it's a bug */ | ||
319 | plugin->fn = filename; | ||
320 | |||
321 | /* Open database and precompile statements */ | ||
322 | if (SQLITE_OK != sqlite3_open (plugin->fn, &plugin->dbh)) | ||
323 | { | ||
324 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
325 | _("Unable to initialize SQLite: %s.\n"), | ||
326 | sqlite3_errmsg (plugin->dbh)); | ||
327 | return GNUNET_SYSERR; | ||
328 | } | ||
329 | |||
330 | #if DEBUG_PSYCSTORE | ||
331 | sqlite3_trace (plugin->dbh, &sql_trace, NULL); | ||
332 | #endif | ||
333 | |||
334 | sql_exec (plugin->dbh, "PRAGMA temp_store=MEMORY"); | ||
335 | sql_exec (plugin->dbh, "PRAGMA synchronous=NORMAL"); | ||
336 | sql_exec (plugin->dbh, "PRAGMA legacy_file_format=OFF"); | ||
337 | sql_exec (plugin->dbh, "PRAGMA auto_vacuum=INCREMENTAL"); | ||
338 | sql_exec (plugin->dbh, "PRAGMA encoding=\"UTF-8\""); | ||
339 | #if ! DEBUG_PSYCSTORE | ||
340 | sql_exec (plugin->dbh, "PRAGMA locking_mode=EXCLUSIVE"); | ||
341 | #endif | ||
342 | sql_exec (plugin->dbh, "PRAGMA page_size=4096"); | ||
343 | |||
344 | sqlite3_busy_timeout (plugin->dbh, BUSY_TIMEOUT_MS); | ||
345 | |||
346 | /* Create tables */ | ||
347 | |||
348 | sql_exec (plugin->dbh, | ||
349 | "CREATE TABLE IF NOT EXISTS channels (\n" | ||
350 | " id INTEGER PRIMARY KEY,\n" | ||
351 | " pub_key BLOB(32) UNIQUE,\n" | ||
352 | " max_state_message_id INTEGER,\n" // last applied state message ID | ||
353 | " state_hash_message_id INTEGER\n" // last message ID with a state hash | ||
354 | ");"); | ||
355 | |||
356 | sql_exec (plugin->dbh, | ||
357 | "CREATE TABLE IF NOT EXISTS slaves (\n" | ||
358 | " id INTEGER PRIMARY KEY,\n" | ||
359 | " pub_key BLOB(32) UNIQUE\n" | ||
360 | ");"); | ||
361 | |||
362 | sql_exec (plugin->dbh, | ||
363 | "CREATE TABLE IF NOT EXISTS membership (\n" | ||
364 | " channel_id INTEGER NOT NULL REFERENCES channels(id),\n" | ||
365 | " slave_id INTEGER NOT NULL REFERENCES slaves(id),\n" | ||
366 | " did_join INTEGER NOT NULL,\n" | ||
367 | " announced_at INTEGER NOT NULL,\n" | ||
368 | " effective_since INTEGER NOT NULL,\n" | ||
369 | " group_generation INTEGER NOT NULL\n" | ||
370 | ");"); | ||
371 | sql_exec (plugin->dbh, | ||
372 | "CREATE INDEX IF NOT EXISTS idx_membership_channel_id_slave_id " | ||
373 | "ON membership (channel_id, slave_id);"); | ||
374 | |||
375 | /** @todo messages table: add method_name column */ | ||
376 | sql_exec (plugin->dbh, | ||
377 | "CREATE TABLE IF NOT EXISTS messages (\n" | ||
378 | " channel_id INTEGER NOT NULL REFERENCES channels(id),\n" | ||
379 | " hop_counter INTEGER NOT NULL,\n" | ||
380 | " signature BLOB,\n" | ||
381 | " purpose BLOB,\n" | ||
382 | " fragment_id INTEGER NOT NULL,\n" | ||
383 | " fragment_offset INTEGER NOT NULL,\n" | ||
384 | " message_id INTEGER NOT NULL,\n" | ||
385 | " group_generation INTEGER NOT NULL,\n" | ||
386 | " multicast_flags INTEGER NOT NULL,\n" | ||
387 | " psycstore_flags INTEGER NOT NULL,\n" | ||
388 | " data BLOB,\n" | ||
389 | " PRIMARY KEY (channel_id, fragment_id),\n" | ||
390 | " UNIQUE (channel_id, message_id, fragment_offset)\n" | ||
391 | ");"); | ||
392 | |||
393 | sql_exec (plugin->dbh, | ||
394 | "CREATE TABLE IF NOT EXISTS state (\n" | ||
395 | " channel_id INTEGER NOT NULL REFERENCES channels(id),\n" | ||
396 | " name TEXT NOT NULL,\n" | ||
397 | " value_current BLOB,\n" | ||
398 | " value_signed BLOB,\n" | ||
399 | " PRIMARY KEY (channel_id, name)\n" | ||
400 | ");"); | ||
401 | |||
402 | sql_exec (plugin->dbh, | ||
403 | "CREATE TABLE IF NOT EXISTS state_sync (\n" | ||
404 | " channel_id INTEGER NOT NULL REFERENCES channels(id),\n" | ||
405 | " name TEXT NOT NULL,\n" | ||
406 | " value BLOB,\n" | ||
407 | " PRIMARY KEY (channel_id, name)\n" | ||
408 | ");"); | ||
409 | |||
410 | /* Prepare statements */ | ||
411 | |||
412 | sql_prepare (plugin->dbh, "BEGIN;", &plugin->transaction_begin); | ||
413 | |||
414 | sql_prepare (plugin->dbh, "COMMIT;", &plugin->transaction_commit); | ||
415 | |||
416 | sql_prepare (plugin->dbh, "ROLLBACK;", &plugin->transaction_rollback); | ||
417 | |||
418 | sql_prepare (plugin->dbh, | ||
419 | "INSERT OR IGNORE INTO channels (pub_key) VALUES (?);", | ||
420 | &plugin->insert_channel_key); | ||
421 | |||
422 | sql_prepare (plugin->dbh, | ||
423 | "INSERT OR IGNORE INTO slaves (pub_key) VALUES (?);", | ||
424 | &plugin->insert_slave_key); | ||
425 | |||
426 | sql_prepare (plugin->dbh, | ||
427 | "INSERT INTO membership\n" | ||
428 | " (channel_id, slave_id, did_join, announced_at,\n" | ||
429 | " effective_since, group_generation)\n" | ||
430 | "VALUES ((SELECT id FROM channels WHERE pub_key = ?),\n" | ||
431 | " (SELECT id FROM slaves WHERE pub_key = ?),\n" | ||
432 | " ?, ?, ?, ?);", | ||
433 | &plugin->insert_membership); | ||
434 | |||
435 | sql_prepare (plugin->dbh, | ||
436 | "SELECT did_join FROM membership\n" | ||
437 | "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" | ||
438 | " AND slave_id = (SELECT id FROM slaves WHERE pub_key = ?)\n" | ||
439 | " AND effective_since <= ? AND did_join = 1\n" | ||
440 | "ORDER BY announced_at DESC LIMIT 1;", | ||
441 | &plugin->select_membership); | ||
442 | |||
443 | sql_prepare (plugin->dbh, | ||
444 | "INSERT OR IGNORE INTO messages\n" | ||
445 | " (channel_id, hop_counter, signature, purpose,\n" | ||
446 | " fragment_id, fragment_offset, message_id,\n" | ||
447 | " group_generation, multicast_flags, psycstore_flags, data)\n" | ||
448 | "VALUES ((SELECT id FROM channels WHERE pub_key = ?),\n" | ||
449 | " ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);", | ||
450 | &plugin->insert_fragment); | ||
451 | |||
452 | sql_prepare (plugin->dbh, | ||
453 | "UPDATE messages\n" | ||
454 | "SET psycstore_flags = psycstore_flags | ?\n" | ||
455 | "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" | ||
456 | " AND message_id = ? AND fragment_offset = 0;", | ||
457 | &plugin->update_message_flags); | ||
458 | |||
459 | sql_prepare (plugin->dbh, | ||
460 | "SELECT hop_counter, signature, purpose, fragment_id,\n" | ||
461 | " fragment_offset, message_id, group_generation,\n" | ||
462 | " multicast_flags, psycstore_flags, data\n" | ||
463 | "FROM messages\n" | ||
464 | "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" | ||
465 | " AND ? <= fragment_id AND fragment_id <= ?;", | ||
466 | &plugin->select_fragments); | ||
467 | |||
468 | /** @todo select_messages: add method_prefix filter */ | ||
469 | sql_prepare (plugin->dbh, | ||
470 | "SELECT hop_counter, signature, purpose, fragment_id,\n" | ||
471 | " fragment_offset, message_id, group_generation,\n" | ||
472 | " multicast_flags, psycstore_flags, data\n" | ||
473 | "FROM messages\n" | ||
474 | "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" | ||
475 | " AND ? <= message_id AND message_id <= ?" | ||
476 | "LIMIT ?;", | ||
477 | &plugin->select_messages); | ||
478 | |||
479 | sql_prepare (plugin->dbh, | ||
480 | "SELECT * FROM\n" | ||
481 | "(SELECT hop_counter, signature, purpose, fragment_id,\n" | ||
482 | " fragment_offset, message_id, group_generation,\n" | ||
483 | " multicast_flags, psycstore_flags, data\n" | ||
484 | " FROM messages\n" | ||
485 | " WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" | ||
486 | " ORDER BY fragment_id DESC\n" | ||
487 | " LIMIT ?)\n" | ||
488 | "ORDER BY fragment_id;", | ||
489 | &plugin->select_latest_fragments); | ||
490 | |||
491 | /** @todo select_latest_messages: add method_prefix filter */ | ||
492 | sql_prepare (plugin->dbh, | ||
493 | "SELECT hop_counter, signature, purpose, fragment_id,\n" | ||
494 | " fragment_offset, message_id, group_generation,\n" | ||
495 | " multicast_flags, psycstore_flags, data\n" | ||
496 | "FROM messages\n" | ||
497 | "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" | ||
498 | " AND message_id IN\n" | ||
499 | " (SELECT message_id\n" | ||
500 | " FROM messages\n" | ||
501 | " WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" | ||
502 | " GROUP BY message_id\n" | ||
503 | " ORDER BY message_id\n" | ||
504 | " DESC LIMIT ?)\n" | ||
505 | "ORDER BY fragment_id;", | ||
506 | &plugin->select_latest_messages); | ||
507 | |||
508 | sql_prepare (plugin->dbh, | ||
509 | "SELECT hop_counter, signature, purpose, fragment_id,\n" | ||
510 | " fragment_offset, message_id, group_generation,\n" | ||
511 | " multicast_flags, psycstore_flags, data\n" | ||
512 | "FROM messages\n" | ||
513 | "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" | ||
514 | " AND message_id = ? AND fragment_offset = ?;", | ||
515 | &plugin->select_message_fragment); | ||
516 | |||
517 | sql_prepare (plugin->dbh, | ||
518 | "SELECT fragment_id, message_id, group_generation\n" | ||
519 | "FROM messages\n" | ||
520 | "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" | ||
521 | "ORDER BY fragment_id DESC LIMIT 1;", | ||
522 | &plugin->select_counters_message); | ||
523 | |||
524 | sql_prepare (plugin->dbh, | ||
525 | "SELECT max_state_message_id\n" | ||
526 | "FROM channels\n" | ||
527 | "WHERE pub_key = ? AND max_state_message_id IS NOT NULL;", | ||
528 | &plugin->select_counters_state); | ||
529 | |||
530 | sql_prepare (plugin->dbh, | ||
531 | "UPDATE channels\n" | ||
532 | "SET max_state_message_id = ?\n" | ||
533 | "WHERE pub_key = ?;", | ||
534 | &plugin->update_max_state_message_id); | ||
535 | |||
536 | sql_prepare (plugin->dbh, | ||
537 | "UPDATE channels\n" | ||
538 | "SET state_hash_message_id = ?\n" | ||
539 | "WHERE pub_key = ?;", | ||
540 | &plugin->update_state_hash_message_id); | ||
541 | |||
542 | sql_prepare (plugin->dbh, | ||
543 | "INSERT OR REPLACE INTO state\n" | ||
544 | " (channel_id, name, value_current, value_signed)\n" | ||
545 | "SELECT new.channel_id, new.name,\n" | ||
546 | " new.value_current, old.value_signed\n" | ||
547 | "FROM (SELECT (SELECT id FROM channels WHERE pub_key = ?)\n" | ||
548 | " AS channel_id,\n" | ||
549 | " ? AS name, ? AS value_current) AS new\n" | ||
550 | "LEFT JOIN (SELECT channel_id, name, value_signed\n" | ||
551 | " FROM state) AS old\n" | ||
552 | "ON new.channel_id = old.channel_id AND new.name = old.name;", | ||
553 | &plugin->insert_state_current); | ||
554 | |||
555 | sql_prepare (plugin->dbh, | ||
556 | "DELETE FROM state\n" | ||
557 | "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" | ||
558 | " AND (value_current IS NULL OR length(value_current) = 0)\n" | ||
559 | " AND (value_signed IS NULL OR length(value_signed) = 0);", | ||
560 | &plugin->delete_state_empty); | ||
561 | |||
562 | sql_prepare (plugin->dbh, | ||
563 | "UPDATE state\n" | ||
564 | "SET value_signed = value_current\n" | ||
565 | "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?);", | ||
566 | &plugin->update_state_signed); | ||
567 | |||
568 | sql_prepare (plugin->dbh, | ||
569 | "DELETE FROM state\n" | ||
570 | "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?);", | ||
571 | &plugin->delete_state); | ||
572 | |||
573 | sql_prepare (plugin->dbh, | ||
574 | "INSERT INTO state_sync (channel_id, name, value)\n" | ||
575 | "VALUES ((SELECT id FROM channels WHERE pub_key = ?), ?, ?);", | ||
576 | &plugin->insert_state_sync); | ||
577 | |||
578 | sql_prepare (plugin->dbh, | ||
579 | "INSERT INTO state\n" | ||
580 | " (channel_id, name, value_current, value_signed)\n" | ||
581 | "SELECT channel_id, name, value, value\n" | ||
582 | "FROM state_sync\n" | ||
583 | "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?);", | ||
584 | &plugin->insert_state_from_sync); | ||
585 | |||
586 | sql_prepare (plugin->dbh, | ||
587 | "DELETE FROM state_sync\n" | ||
588 | "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?);", | ||
589 | &plugin->delete_state_sync); | ||
590 | |||
591 | sql_prepare (plugin->dbh, | ||
592 | "SELECT value_current\n" | ||
593 | "FROM state\n" | ||
594 | "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" | ||
595 | " AND name = ?;", | ||
596 | &plugin->select_state_one); | ||
597 | |||
598 | sql_prepare (plugin->dbh, | ||
599 | "SELECT name, value_current\n" | ||
600 | "FROM state\n" | ||
601 | "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)\n" | ||
602 | " AND (name = ? OR substr(name, 1, ?) = ?);", | ||
603 | &plugin->select_state_prefix); | ||
604 | |||
605 | sql_prepare (plugin->dbh, | ||
606 | "SELECT name, value_signed\n" | ||
607 | "FROM state\n" | ||
608 | "WHERE channel_id = (SELECT id FROM channels WHERE pub_key = ?)" | ||
609 | " AND value_signed IS NOT NULL;", | ||
610 | &plugin->select_state_signed); | ||
611 | |||
612 | return GNUNET_OK; | ||
613 | } | ||
614 | |||
615 | |||
616 | /** | ||
617 | * Shutdown database connection and associate data | ||
618 | * structures. | ||
619 | * @param plugin the plugin context (state for this module) | ||
620 | */ | ||
621 | static void | ||
622 | database_shutdown (struct Plugin *plugin) | ||
623 | { | ||
624 | int result; | ||
625 | sqlite3_stmt *stmt; | ||
626 | while (NULL != (stmt = sqlite3_next_stmt (plugin->dbh, NULL))) | ||
627 | { | ||
628 | result = sqlite3_finalize (stmt); | ||
629 | if (SQLITE_OK != result) | ||
630 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
631 | "Failed to close statement %p: %d\n", stmt, result); | ||
632 | } | ||
633 | if (SQLITE_OK != sqlite3_close (plugin->dbh)) | ||
634 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR, "sqlite3_close"); | ||
635 | |||
636 | GNUNET_free_non_null (plugin->fn); | ||
637 | } | ||
638 | |||
639 | /** | ||
640 | * Execute a prepared statement with a @a channel_key argument. | ||
641 | * | ||
642 | * @param plugin Plugin handle. | ||
643 | * @param stmt Statement to execute. | ||
644 | * @param channel_key Public key of the channel. | ||
645 | * | ||
646 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
647 | */ | ||
648 | static int | ||
649 | exec_channel (struct Plugin *plugin, sqlite3_stmt *stmt, | ||
650 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key) | ||
651 | { | ||
652 | if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key, | ||
653 | sizeof (*channel_key), SQLITE_STATIC)) | ||
654 | { | ||
655 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
656 | "sqlite3_bind"); | ||
657 | } | ||
658 | else if (SQLITE_DONE != sqlite3_step (stmt)) | ||
659 | { | ||
660 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
661 | "sqlite3_step"); | ||
662 | } | ||
663 | |||
664 | if (SQLITE_OK != sqlite3_reset (stmt)) | ||
665 | { | ||
666 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
667 | "sqlite3_reset"); | ||
668 | return GNUNET_SYSERR; | ||
669 | } | ||
670 | |||
671 | return GNUNET_OK; | ||
672 | } | ||
673 | |||
674 | /** | ||
675 | * Begin a transaction. | ||
676 | */ | ||
677 | static int | ||
678 | transaction_begin (struct Plugin *plugin, enum Transactions transaction) | ||
679 | { | ||
680 | sqlite3_stmt *stmt = plugin->transaction_begin; | ||
681 | |||
682 | if (SQLITE_DONE != sqlite3_step (stmt)) | ||
683 | { | ||
684 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
685 | "sqlite3_step"); | ||
686 | } | ||
687 | if (SQLITE_OK != sqlite3_reset (stmt)) | ||
688 | { | ||
689 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
690 | "sqlite3_reset"); | ||
691 | return GNUNET_SYSERR; | ||
692 | } | ||
693 | |||
694 | plugin->transaction = transaction; | ||
695 | return GNUNET_OK; | ||
696 | } | ||
697 | |||
698 | |||
699 | /** | ||
700 | * Commit current transaction. | ||
701 | */ | ||
702 | static int | ||
703 | transaction_commit (struct Plugin *plugin) | ||
704 | { | ||
705 | sqlite3_stmt *stmt = plugin->transaction_commit; | ||
706 | |||
707 | if (SQLITE_DONE != sqlite3_step (stmt)) | ||
708 | { | ||
709 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
710 | "sqlite3_step"); | ||
711 | } | ||
712 | if (SQLITE_OK != sqlite3_reset (stmt)) | ||
713 | { | ||
714 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
715 | "sqlite3_reset"); | ||
716 | return GNUNET_SYSERR; | ||
717 | } | ||
718 | |||
719 | plugin->transaction = TRANSACTION_NONE; | ||
720 | return GNUNET_OK; | ||
721 | } | ||
722 | |||
723 | |||
724 | /** | ||
725 | * Roll back current transaction. | ||
726 | */ | ||
727 | static int | ||
728 | transaction_rollback (struct Plugin *plugin) | ||
729 | { | ||
730 | sqlite3_stmt *stmt = plugin->transaction_rollback; | ||
731 | |||
732 | if (SQLITE_DONE != sqlite3_step (stmt)) | ||
733 | { | ||
734 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
735 | "sqlite3_step"); | ||
736 | } | ||
737 | if (SQLITE_OK != sqlite3_reset (stmt)) | ||
738 | { | ||
739 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
740 | "sqlite3_reset"); | ||
741 | return GNUNET_SYSERR; | ||
742 | } | ||
743 | plugin->transaction = TRANSACTION_NONE; | ||
744 | return GNUNET_OK; | ||
745 | } | ||
746 | |||
747 | |||
748 | static int | ||
749 | channel_key_store (struct Plugin *plugin, | ||
750 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key) | ||
751 | { | ||
752 | sqlite3_stmt *stmt = plugin->insert_channel_key; | ||
753 | |||
754 | if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key, | ||
755 | sizeof (*channel_key), SQLITE_STATIC)) | ||
756 | { | ||
757 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
758 | "sqlite3_bind"); | ||
759 | } | ||
760 | else if (SQLITE_DONE != sqlite3_step (stmt)) | ||
761 | { | ||
762 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
763 | "sqlite3_step"); | ||
764 | } | ||
765 | |||
766 | if (SQLITE_OK != sqlite3_reset (stmt)) | ||
767 | { | ||
768 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
769 | "sqlite3_reset"); | ||
770 | return GNUNET_SYSERR; | ||
771 | } | ||
772 | |||
773 | return GNUNET_OK; | ||
774 | } | ||
775 | |||
776 | |||
777 | static int | ||
778 | slave_key_store (struct Plugin *plugin, | ||
779 | const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key) | ||
780 | { | ||
781 | sqlite3_stmt *stmt = plugin->insert_slave_key; | ||
782 | |||
783 | if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, slave_key, | ||
784 | sizeof (*slave_key), SQLITE_STATIC)) | ||
785 | { | ||
786 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
787 | "sqlite3_bind"); | ||
788 | } | ||
789 | else if (SQLITE_DONE != sqlite3_step (stmt)) | ||
790 | { | ||
791 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
792 | "sqlite3_step"); | ||
793 | } | ||
794 | |||
795 | |||
796 | if (SQLITE_OK != sqlite3_reset (stmt)) | ||
797 | { | ||
798 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
799 | "sqlite3_reset"); | ||
800 | return GNUNET_SYSERR; | ||
801 | } | ||
802 | |||
803 | return GNUNET_OK; | ||
804 | } | ||
805 | |||
806 | |||
807 | /** | ||
808 | * Store join/leave events for a PSYC channel in order to be able to answer | ||
809 | * membership test queries later. | ||
810 | * | ||
811 | * @see GNUNET_PSYCSTORE_membership_store() | ||
812 | * | ||
813 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
814 | */ | ||
815 | static int | ||
816 | sqlite_membership_store (void *cls, | ||
817 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
818 | const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, | ||
819 | int did_join, | ||
820 | uint64_t announced_at, | ||
821 | uint64_t effective_since, | ||
822 | uint64_t group_generation) | ||
823 | { | ||
824 | struct Plugin *plugin = cls; | ||
825 | sqlite3_stmt *stmt = plugin->insert_membership; | ||
826 | |||
827 | GNUNET_assert (TRANSACTION_NONE == plugin->transaction); | ||
828 | |||
829 | if (announced_at > INT64_MAX || | ||
830 | effective_since > INT64_MAX || | ||
831 | group_generation > INT64_MAX) | ||
832 | { | ||
833 | GNUNET_break (0); | ||
834 | return GNUNET_SYSERR; | ||
835 | } | ||
836 | |||
837 | if (GNUNET_OK != channel_key_store (plugin, channel_key) | ||
838 | || GNUNET_OK != slave_key_store (plugin, slave_key)) | ||
839 | return GNUNET_SYSERR; | ||
840 | |||
841 | if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key, | ||
842 | sizeof (*channel_key), SQLITE_STATIC) | ||
843 | || SQLITE_OK != sqlite3_bind_blob (stmt, 2, slave_key, | ||
844 | sizeof (*slave_key), SQLITE_STATIC) | ||
845 | || SQLITE_OK != sqlite3_bind_int (stmt, 3, did_join) | ||
846 | || SQLITE_OK != sqlite3_bind_int64 (stmt, 4, announced_at) | ||
847 | || SQLITE_OK != sqlite3_bind_int64 (stmt, 5, effective_since) | ||
848 | || SQLITE_OK != sqlite3_bind_int64 (stmt, 6, group_generation)) | ||
849 | { | ||
850 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
851 | "sqlite3_bind"); | ||
852 | } | ||
853 | else if (SQLITE_DONE != sqlite3_step (stmt)) | ||
854 | { | ||
855 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
856 | "sqlite3_step"); | ||
857 | } | ||
858 | |||
859 | if (SQLITE_OK != sqlite3_reset (stmt)) | ||
860 | { | ||
861 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
862 | "sqlite3_reset"); | ||
863 | return GNUNET_SYSERR; | ||
864 | } | ||
865 | |||
866 | return GNUNET_OK; | ||
867 | } | ||
868 | |||
869 | /** | ||
870 | * Test if a member was admitted to the channel at the given message ID. | ||
871 | * | ||
872 | * @see GNUNET_PSYCSTORE_membership_test() | ||
873 | * | ||
874 | * @return #GNUNET_YES if the member was admitted, #GNUNET_NO if not, | ||
875 | * #GNUNET_SYSERR if there was en error. | ||
876 | */ | ||
877 | static int | ||
878 | membership_test (void *cls, | ||
879 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
880 | const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, | ||
881 | uint64_t message_id) | ||
882 | { | ||
883 | struct Plugin *plugin = cls; | ||
884 | sqlite3_stmt *stmt = plugin->select_membership; | ||
885 | int ret = GNUNET_SYSERR; | ||
886 | |||
887 | if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key, | ||
888 | sizeof (*channel_key), SQLITE_STATIC) | ||
889 | || SQLITE_OK != sqlite3_bind_blob (stmt, 2, slave_key, | ||
890 | sizeof (*slave_key), SQLITE_STATIC) | ||
891 | || SQLITE_OK != sqlite3_bind_int64 (stmt, 3, message_id)) | ||
892 | { | ||
893 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
894 | "sqlite3_bind"); | ||
895 | } | ||
896 | else | ||
897 | { | ||
898 | switch (sqlite3_step (stmt)) | ||
899 | { | ||
900 | case SQLITE_DONE: | ||
901 | ret = GNUNET_NO; | ||
902 | break; | ||
903 | case SQLITE_ROW: | ||
904 | ret = GNUNET_YES; | ||
905 | } | ||
906 | } | ||
907 | |||
908 | if (SQLITE_OK != sqlite3_reset (stmt)) | ||
909 | { | ||
910 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
911 | "sqlite3_reset"); | ||
912 | } | ||
913 | |||
914 | return ret; | ||
915 | } | ||
916 | |||
917 | /** | ||
918 | * Store a message fragment sent to a channel. | ||
919 | * | ||
920 | * @see GNUNET_PSYCSTORE_fragment_store() | ||
921 | * | ||
922 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
923 | */ | ||
924 | static int | ||
925 | fragment_store (void *cls, | ||
926 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
927 | const struct GNUNET_MULTICAST_MessageHeader *msg, | ||
928 | uint32_t psycstore_flags) | ||
929 | { | ||
930 | struct Plugin *plugin = cls; | ||
931 | sqlite3_stmt *stmt = plugin->insert_fragment; | ||
932 | |||
933 | GNUNET_assert (TRANSACTION_NONE == plugin->transaction); | ||
934 | |||
935 | uint64_t fragment_id = GNUNET_ntohll (msg->fragment_id); | ||
936 | uint64_t fragment_offset = GNUNET_ntohll (msg->fragment_offset); | ||
937 | uint64_t message_id = GNUNET_ntohll (msg->message_id); | ||
938 | uint64_t group_generation = GNUNET_ntohll (msg->group_generation); | ||
939 | |||
940 | if (fragment_id > INT64_MAX || fragment_offset > INT64_MAX || | ||
941 | message_id > INT64_MAX || group_generation > INT64_MAX) | ||
942 | { | ||
943 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
944 | "Tried to store fragment with a field > INT64_MAX: " | ||
945 | "%lu, %lu, %lu, %lu\n", fragment_id, fragment_offset, | ||
946 | message_id, group_generation); | ||
947 | GNUNET_break (0); | ||
948 | return GNUNET_SYSERR; | ||
949 | } | ||
950 | |||
951 | if (GNUNET_OK != channel_key_store (plugin, channel_key)) | ||
952 | return GNUNET_SYSERR; | ||
953 | |||
954 | if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key, | ||
955 | sizeof (*channel_key), SQLITE_STATIC) | ||
956 | || SQLITE_OK != sqlite3_bind_int64 (stmt, 2, ntohl (msg->hop_counter) ) | ||
957 | || SQLITE_OK != sqlite3_bind_blob (stmt, 3, (const void *) &msg->signature, | ||
958 | sizeof (msg->signature), SQLITE_STATIC) | ||
959 | || SQLITE_OK != sqlite3_bind_blob (stmt, 4, (const void *) &msg->purpose, | ||
960 | sizeof (msg->purpose), SQLITE_STATIC) | ||
961 | || SQLITE_OK != sqlite3_bind_int64 (stmt, 5, fragment_id) | ||
962 | || SQLITE_OK != sqlite3_bind_int64 (stmt, 6, fragment_offset) | ||
963 | || SQLITE_OK != sqlite3_bind_int64 (stmt, 7, message_id) | ||
964 | || SQLITE_OK != sqlite3_bind_int64 (stmt, 8, group_generation) | ||
965 | || SQLITE_OK != sqlite3_bind_int64 (stmt, 9, ntohl (msg->flags)) | ||
966 | || SQLITE_OK != sqlite3_bind_int64 (stmt, 10, psycstore_flags) | ||
967 | || SQLITE_OK != sqlite3_bind_blob (stmt, 11, (const void *) &msg[1], | ||
968 | ntohs (msg->header.size) | ||
969 | - sizeof (*msg), SQLITE_STATIC)) | ||
970 | { | ||
971 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
972 | "sqlite3_bind"); | ||
973 | } | ||
974 | else if (SQLITE_DONE != sqlite3_step (stmt)) | ||
975 | { | ||
976 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
977 | "sqlite3_step"); | ||
978 | } | ||
979 | |||
980 | if (SQLITE_OK != sqlite3_reset (stmt)) | ||
981 | { | ||
982 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
983 | "sqlite3_reset"); | ||
984 | return GNUNET_SYSERR; | ||
985 | } | ||
986 | |||
987 | return GNUNET_OK; | ||
988 | } | ||
989 | |||
990 | /** | ||
991 | * Set additional flags for a given message. | ||
992 | * | ||
993 | * They are OR'd with any existing flags set. | ||
994 | * | ||
995 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
996 | */ | ||
997 | static int | ||
998 | message_add_flags (void *cls, | ||
999 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1000 | uint64_t message_id, | ||
1001 | uint32_t psycstore_flags) | ||
1002 | { | ||
1003 | struct Plugin *plugin = cls; | ||
1004 | sqlite3_stmt *stmt = plugin->update_message_flags; | ||
1005 | int ret = GNUNET_SYSERR; | ||
1006 | |||
1007 | if (SQLITE_OK != sqlite3_bind_int64 (stmt, 1, psycstore_flags) | ||
1008 | || SQLITE_OK != sqlite3_bind_blob (stmt, 2, channel_key, | ||
1009 | sizeof (*channel_key), SQLITE_STATIC) | ||
1010 | || SQLITE_OK != sqlite3_bind_int64 (stmt, 3, message_id)) | ||
1011 | { | ||
1012 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1013 | "sqlite3_bind"); | ||
1014 | } | ||
1015 | else | ||
1016 | { | ||
1017 | switch (sqlite3_step (stmt)) | ||
1018 | { | ||
1019 | case SQLITE_DONE: | ||
1020 | ret = sqlite3_total_changes (plugin->dbh) > 0 ? GNUNET_OK : GNUNET_NO; | ||
1021 | break; | ||
1022 | default: | ||
1023 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1024 | "sqlite3_step"); | ||
1025 | } | ||
1026 | } | ||
1027 | |||
1028 | if (SQLITE_OK != sqlite3_reset (stmt)) | ||
1029 | { | ||
1030 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1031 | "sqlite3_reset"); | ||
1032 | return GNUNET_SYSERR; | ||
1033 | } | ||
1034 | |||
1035 | return ret; | ||
1036 | } | ||
1037 | |||
1038 | static int | ||
1039 | fragment_row (sqlite3_stmt *stmt, GNUNET_PSYCSTORE_FragmentCallback cb, | ||
1040 | void *cb_cls) | ||
1041 | { | ||
1042 | int data_size = sqlite3_column_bytes (stmt, 9); | ||
1043 | struct GNUNET_MULTICAST_MessageHeader *msg | ||
1044 | = GNUNET_malloc (sizeof (*msg) + data_size); | ||
1045 | |||
1046 | msg->header.size = htons (sizeof (*msg) + data_size); | ||
1047 | msg->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE); | ||
1048 | msg->hop_counter = htonl ((uint32_t) sqlite3_column_int64 (stmt, 0)); | ||
1049 | GNUNET_memcpy (&msg->signature, | ||
1050 | sqlite3_column_blob (stmt, 1), | ||
1051 | sqlite3_column_bytes (stmt, 1)); | ||
1052 | GNUNET_memcpy (&msg->purpose, | ||
1053 | sqlite3_column_blob (stmt, 2), | ||
1054 | sqlite3_column_bytes (stmt, 2)); | ||
1055 | msg->fragment_id = GNUNET_htonll (sqlite3_column_int64 (stmt, 3)); | ||
1056 | msg->fragment_offset = GNUNET_htonll (sqlite3_column_int64 (stmt, 4)); | ||
1057 | msg->message_id = GNUNET_htonll (sqlite3_column_int64 (stmt, 5)); | ||
1058 | msg->group_generation = GNUNET_htonll (sqlite3_column_int64 (stmt, 6)); | ||
1059 | msg->flags = htonl (sqlite3_column_int64 (stmt, 7)); | ||
1060 | GNUNET_memcpy (&msg[1], sqlite3_column_blob (stmt, 9), data_size); | ||
1061 | |||
1062 | return cb (cb_cls, (void *) msg, sqlite3_column_int64 (stmt, 8)); | ||
1063 | } | ||
1064 | |||
1065 | |||
1066 | static int | ||
1067 | fragment_select (struct Plugin *plugin, sqlite3_stmt *stmt, | ||
1068 | uint64_t *returned_fragments, | ||
1069 | GNUNET_PSYCSTORE_FragmentCallback cb, void *cb_cls) | ||
1070 | { | ||
1071 | int ret = GNUNET_SYSERR; | ||
1072 | int sql_ret; | ||
1073 | |||
1074 | do | ||
1075 | { | ||
1076 | sql_ret = sqlite3_step (stmt); | ||
1077 | switch (sql_ret) | ||
1078 | { | ||
1079 | case SQLITE_DONE: | ||
1080 | if (ret != GNUNET_OK) | ||
1081 | ret = GNUNET_NO; | ||
1082 | break; | ||
1083 | case SQLITE_ROW: | ||
1084 | ret = fragment_row (stmt, cb, cb_cls); | ||
1085 | (*returned_fragments)++; | ||
1086 | if (ret != GNUNET_YES) | ||
1087 | sql_ret = SQLITE_DONE; | ||
1088 | break; | ||
1089 | default: | ||
1090 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1091 | "sqlite3_step"); | ||
1092 | } | ||
1093 | } | ||
1094 | while (sql_ret == SQLITE_ROW); | ||
1095 | |||
1096 | return ret; | ||
1097 | } | ||
1098 | |||
1099 | /** | ||
1100 | * Retrieve a message fragment range by fragment ID. | ||
1101 | * | ||
1102 | * @see GNUNET_PSYCSTORE_fragment_get() | ||
1103 | * | ||
1104 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
1105 | */ | ||
1106 | static int | ||
1107 | fragment_get (void *cls, | ||
1108 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1109 | uint64_t first_fragment_id, | ||
1110 | uint64_t last_fragment_id, | ||
1111 | uint64_t *returned_fragments, | ||
1112 | GNUNET_PSYCSTORE_FragmentCallback cb, | ||
1113 | void *cb_cls) | ||
1114 | { | ||
1115 | struct Plugin *plugin = cls; | ||
1116 | sqlite3_stmt *stmt = plugin->select_fragments; | ||
1117 | int ret = GNUNET_SYSERR; | ||
1118 | *returned_fragments = 0; | ||
1119 | |||
1120 | if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key, | ||
1121 | sizeof (*channel_key), | ||
1122 | SQLITE_STATIC) | ||
1123 | || SQLITE_OK != sqlite3_bind_int64 (stmt, 2, first_fragment_id) | ||
1124 | || SQLITE_OK != sqlite3_bind_int64 (stmt, 3, last_fragment_id)) | ||
1125 | { | ||
1126 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1127 | "sqlite3_bind"); | ||
1128 | } | ||
1129 | else | ||
1130 | { | ||
1131 | ret = fragment_select (plugin, stmt, returned_fragments, cb, cb_cls); | ||
1132 | } | ||
1133 | |||
1134 | if (SQLITE_OK != sqlite3_reset (stmt)) | ||
1135 | { | ||
1136 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1137 | "sqlite3_reset"); | ||
1138 | } | ||
1139 | |||
1140 | return ret; | ||
1141 | } | ||
1142 | |||
1143 | |||
1144 | /** | ||
1145 | * Retrieve a message fragment range by fragment ID. | ||
1146 | * | ||
1147 | * @see GNUNET_PSYCSTORE_fragment_get_latest() | ||
1148 | * | ||
1149 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
1150 | */ | ||
1151 | static int | ||
1152 | fragment_get_latest (void *cls, | ||
1153 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1154 | uint64_t fragment_limit, | ||
1155 | uint64_t *returned_fragments, | ||
1156 | GNUNET_PSYCSTORE_FragmentCallback cb, | ||
1157 | void *cb_cls) | ||
1158 | { | ||
1159 | struct Plugin *plugin = cls; | ||
1160 | sqlite3_stmt *stmt = plugin->select_latest_fragments; | ||
1161 | int ret = GNUNET_SYSERR; | ||
1162 | *returned_fragments = 0; | ||
1163 | |||
1164 | if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key, | ||
1165 | sizeof (*channel_key), | ||
1166 | SQLITE_STATIC) | ||
1167 | || SQLITE_OK != sqlite3_bind_int64 (stmt, 2, fragment_limit)) | ||
1168 | { | ||
1169 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1170 | "sqlite3_bind"); | ||
1171 | } | ||
1172 | else | ||
1173 | { | ||
1174 | ret = fragment_select (plugin, stmt, returned_fragments, cb, cb_cls); | ||
1175 | } | ||
1176 | |||
1177 | if (SQLITE_OK != sqlite3_reset (stmt)) | ||
1178 | { | ||
1179 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1180 | "sqlite3_reset"); | ||
1181 | } | ||
1182 | |||
1183 | return ret; | ||
1184 | } | ||
1185 | |||
1186 | |||
1187 | /** | ||
1188 | * Retrieve all fragments of a message ID range. | ||
1189 | * | ||
1190 | * @see GNUNET_PSYCSTORE_message_get() | ||
1191 | * | ||
1192 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
1193 | */ | ||
1194 | static int | ||
1195 | message_get (void *cls, | ||
1196 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1197 | uint64_t first_message_id, | ||
1198 | uint64_t last_message_id, | ||
1199 | uint64_t fragment_limit, | ||
1200 | uint64_t *returned_fragments, | ||
1201 | GNUNET_PSYCSTORE_FragmentCallback cb, | ||
1202 | void *cb_cls) | ||
1203 | { | ||
1204 | struct Plugin *plugin = cls; | ||
1205 | sqlite3_stmt *stmt = plugin->select_messages; | ||
1206 | int ret = GNUNET_SYSERR; | ||
1207 | *returned_fragments = 0; | ||
1208 | |||
1209 | if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key, | ||
1210 | sizeof (*channel_key), | ||
1211 | SQLITE_STATIC) | ||
1212 | || SQLITE_OK != sqlite3_bind_int64 (stmt, 2, first_message_id) | ||
1213 | || SQLITE_OK != sqlite3_bind_int64 (stmt, 3, last_message_id) | ||
1214 | || SQLITE_OK != sqlite3_bind_int64 (stmt, 4, | ||
1215 | (0 != fragment_limit) | ||
1216 | ? fragment_limit | ||
1217 | : INT64_MAX)) | ||
1218 | { | ||
1219 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1220 | "sqlite3_bind"); | ||
1221 | } | ||
1222 | else | ||
1223 | { | ||
1224 | ret = fragment_select (plugin, stmt, returned_fragments, cb, cb_cls); | ||
1225 | } | ||
1226 | |||
1227 | if (SQLITE_OK != sqlite3_reset (stmt)) | ||
1228 | { | ||
1229 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1230 | "sqlite3_reset"); | ||
1231 | } | ||
1232 | |||
1233 | return ret; | ||
1234 | } | ||
1235 | |||
1236 | |||
1237 | /** | ||
1238 | * Retrieve all fragments of the latest messages. | ||
1239 | * | ||
1240 | * @see GNUNET_PSYCSTORE_message_get_latest() | ||
1241 | * | ||
1242 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
1243 | */ | ||
1244 | static int | ||
1245 | message_get_latest (void *cls, | ||
1246 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1247 | uint64_t message_limit, | ||
1248 | uint64_t *returned_fragments, | ||
1249 | GNUNET_PSYCSTORE_FragmentCallback cb, | ||
1250 | void *cb_cls) | ||
1251 | { | ||
1252 | struct Plugin *plugin = cls; | ||
1253 | sqlite3_stmt *stmt = plugin->select_latest_messages; | ||
1254 | int ret = GNUNET_SYSERR; | ||
1255 | *returned_fragments = 0; | ||
1256 | |||
1257 | if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key, | ||
1258 | sizeof (*channel_key), | ||
1259 | SQLITE_STATIC) | ||
1260 | || SQLITE_OK != sqlite3_bind_blob (stmt, 2, channel_key, | ||
1261 | sizeof (*channel_key), | ||
1262 | SQLITE_STATIC) | ||
1263 | || SQLITE_OK != sqlite3_bind_int64 (stmt, 3, message_limit)) | ||
1264 | { | ||
1265 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1266 | "sqlite3_bind"); | ||
1267 | } | ||
1268 | else | ||
1269 | { | ||
1270 | ret = fragment_select (plugin, stmt, returned_fragments, cb, cb_cls); | ||
1271 | } | ||
1272 | |||
1273 | if (SQLITE_OK != sqlite3_reset (stmt)) | ||
1274 | { | ||
1275 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1276 | "sqlite3_reset"); | ||
1277 | } | ||
1278 | |||
1279 | return ret; | ||
1280 | } | ||
1281 | |||
1282 | |||
1283 | /** | ||
1284 | * Retrieve a fragment of message specified by its message ID and fragment | ||
1285 | * offset. | ||
1286 | * | ||
1287 | * @see GNUNET_PSYCSTORE_message_get_fragment() | ||
1288 | * | ||
1289 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
1290 | */ | ||
1291 | static int | ||
1292 | message_get_fragment (void *cls, | ||
1293 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1294 | uint64_t message_id, | ||
1295 | uint64_t fragment_offset, | ||
1296 | GNUNET_PSYCSTORE_FragmentCallback cb, | ||
1297 | void *cb_cls) | ||
1298 | { | ||
1299 | struct Plugin *plugin = cls; | ||
1300 | sqlite3_stmt *stmt = plugin->select_message_fragment; | ||
1301 | int ret = GNUNET_SYSERR; | ||
1302 | |||
1303 | if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key, | ||
1304 | sizeof (*channel_key), | ||
1305 | SQLITE_STATIC) | ||
1306 | || SQLITE_OK != sqlite3_bind_int64 (stmt, 2, message_id) | ||
1307 | || SQLITE_OK != sqlite3_bind_int64 (stmt, 3, fragment_offset)) | ||
1308 | { | ||
1309 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1310 | "sqlite3_bind"); | ||
1311 | } | ||
1312 | else | ||
1313 | { | ||
1314 | switch (sqlite3_step (stmt)) | ||
1315 | { | ||
1316 | case SQLITE_DONE: | ||
1317 | ret = GNUNET_NO; | ||
1318 | break; | ||
1319 | case SQLITE_ROW: | ||
1320 | ret = fragment_row (stmt, cb, cb_cls); | ||
1321 | break; | ||
1322 | default: | ||
1323 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1324 | "sqlite3_step"); | ||
1325 | } | ||
1326 | } | ||
1327 | |||
1328 | if (SQLITE_OK != sqlite3_reset (stmt)) | ||
1329 | { | ||
1330 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1331 | "sqlite3_reset"); | ||
1332 | } | ||
1333 | |||
1334 | return ret; | ||
1335 | } | ||
1336 | |||
1337 | /** | ||
1338 | * Retrieve the max. values of message counters for a channel. | ||
1339 | * | ||
1340 | * @see GNUNET_PSYCSTORE_counters_get() | ||
1341 | * | ||
1342 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
1343 | */ | ||
1344 | static int | ||
1345 | counters_message_get (void *cls, | ||
1346 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1347 | uint64_t *max_fragment_id, | ||
1348 | uint64_t *max_message_id, | ||
1349 | uint64_t *max_group_generation) | ||
1350 | { | ||
1351 | struct Plugin *plugin = cls; | ||
1352 | sqlite3_stmt *stmt = plugin->select_counters_message; | ||
1353 | int ret = GNUNET_SYSERR; | ||
1354 | |||
1355 | if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key, | ||
1356 | sizeof (*channel_key), | ||
1357 | SQLITE_STATIC)) | ||
1358 | { | ||
1359 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1360 | "sqlite3_bind"); | ||
1361 | } | ||
1362 | else | ||
1363 | { | ||
1364 | switch (sqlite3_step (stmt)) | ||
1365 | { | ||
1366 | case SQLITE_DONE: | ||
1367 | ret = GNUNET_NO; | ||
1368 | break; | ||
1369 | case SQLITE_ROW: | ||
1370 | *max_fragment_id = sqlite3_column_int64 (stmt, 0); | ||
1371 | *max_message_id = sqlite3_column_int64 (stmt, 1); | ||
1372 | *max_group_generation = sqlite3_column_int64 (stmt, 2); | ||
1373 | ret = GNUNET_OK; | ||
1374 | break; | ||
1375 | default: | ||
1376 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1377 | "sqlite3_step"); | ||
1378 | } | ||
1379 | } | ||
1380 | |||
1381 | if (SQLITE_OK != sqlite3_reset (stmt)) | ||
1382 | { | ||
1383 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1384 | "sqlite3_reset"); | ||
1385 | } | ||
1386 | |||
1387 | return ret; | ||
1388 | } | ||
1389 | |||
1390 | /** | ||
1391 | * Retrieve the max. values of state counters for a channel. | ||
1392 | * | ||
1393 | * @see GNUNET_PSYCSTORE_counters_get() | ||
1394 | * | ||
1395 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
1396 | */ | ||
1397 | static int | ||
1398 | counters_state_get (void *cls, | ||
1399 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1400 | uint64_t *max_state_message_id) | ||
1401 | { | ||
1402 | struct Plugin *plugin = cls; | ||
1403 | sqlite3_stmt *stmt = plugin->select_counters_state; | ||
1404 | int ret = GNUNET_SYSERR; | ||
1405 | |||
1406 | if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key, | ||
1407 | sizeof (*channel_key), | ||
1408 | SQLITE_STATIC)) | ||
1409 | { | ||
1410 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1411 | "sqlite3_bind"); | ||
1412 | } | ||
1413 | else | ||
1414 | { | ||
1415 | switch (sqlite3_step (stmt)) | ||
1416 | { | ||
1417 | case SQLITE_DONE: | ||
1418 | ret = GNUNET_NO; | ||
1419 | break; | ||
1420 | case SQLITE_ROW: | ||
1421 | *max_state_message_id = sqlite3_column_int64 (stmt, 0); | ||
1422 | ret = GNUNET_OK; | ||
1423 | break; | ||
1424 | default: | ||
1425 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1426 | "sqlite3_step"); | ||
1427 | } | ||
1428 | } | ||
1429 | |||
1430 | if (SQLITE_OK != sqlite3_reset (stmt)) | ||
1431 | { | ||
1432 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1433 | "sqlite3_reset"); | ||
1434 | } | ||
1435 | |||
1436 | return ret; | ||
1437 | } | ||
1438 | |||
1439 | |||
1440 | /** | ||
1441 | * Assign a value to a state variable. | ||
1442 | * | ||
1443 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
1444 | */ | ||
1445 | static int | ||
1446 | state_assign (struct Plugin *plugin, sqlite3_stmt *stmt, | ||
1447 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1448 | const char *name, const void *value, size_t value_size) | ||
1449 | { | ||
1450 | int ret = GNUNET_SYSERR; | ||
1451 | |||
1452 | if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key, | ||
1453 | sizeof (*channel_key), SQLITE_STATIC) | ||
1454 | || SQLITE_OK != sqlite3_bind_text (stmt, 2, name, -1, SQLITE_STATIC) | ||
1455 | || SQLITE_OK != sqlite3_bind_blob (stmt, 3, value, value_size, | ||
1456 | SQLITE_STATIC)) | ||
1457 | { | ||
1458 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1459 | "sqlite3_bind"); | ||
1460 | } | ||
1461 | else | ||
1462 | { | ||
1463 | switch (sqlite3_step (stmt)) | ||
1464 | { | ||
1465 | case SQLITE_DONE: | ||
1466 | ret = 0 < sqlite3_total_changes (plugin->dbh) ? GNUNET_OK : GNUNET_NO; | ||
1467 | break; | ||
1468 | default: | ||
1469 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1470 | "sqlite3_step"); | ||
1471 | } | ||
1472 | } | ||
1473 | |||
1474 | if (SQLITE_OK != sqlite3_reset (stmt)) | ||
1475 | { | ||
1476 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1477 | "sqlite3_reset"); | ||
1478 | return GNUNET_SYSERR; | ||
1479 | } | ||
1480 | |||
1481 | return ret; | ||
1482 | } | ||
1483 | |||
1484 | |||
1485 | static int | ||
1486 | update_message_id (struct Plugin *plugin, sqlite3_stmt *stmt, | ||
1487 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1488 | uint64_t message_id) | ||
1489 | { | ||
1490 | if (SQLITE_OK != sqlite3_bind_int64 (stmt, 1, message_id) | ||
1491 | || SQLITE_OK != sqlite3_bind_blob (stmt, 2, channel_key, | ||
1492 | sizeof (*channel_key), SQLITE_STATIC)) | ||
1493 | { | ||
1494 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1495 | "sqlite3_bind"); | ||
1496 | } | ||
1497 | else if (SQLITE_DONE != sqlite3_step (stmt)) | ||
1498 | { | ||
1499 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1500 | "sqlite3_step"); | ||
1501 | } | ||
1502 | if (SQLITE_OK != sqlite3_reset (stmt)) | ||
1503 | { | ||
1504 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1505 | "sqlite3_reset"); | ||
1506 | return GNUNET_SYSERR; | ||
1507 | } | ||
1508 | return GNUNET_OK; | ||
1509 | } | ||
1510 | |||
1511 | |||
1512 | /** | ||
1513 | * Begin modifying current state. | ||
1514 | */ | ||
1515 | static int | ||
1516 | state_modify_begin (void *cls, | ||
1517 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1518 | uint64_t message_id, uint64_t state_delta) | ||
1519 | { | ||
1520 | struct Plugin *plugin = cls; | ||
1521 | |||
1522 | if (state_delta > 0) | ||
1523 | { | ||
1524 | /** | ||
1525 | * We can only apply state modifiers in the current message if modifiers in | ||
1526 | * the previous stateful message (message_id - state_delta) were already | ||
1527 | * applied. | ||
1528 | */ | ||
1529 | |||
1530 | uint64_t max_state_message_id = 0; | ||
1531 | int ret = counters_state_get (plugin, channel_key, &max_state_message_id); | ||
1532 | switch (ret) | ||
1533 | { | ||
1534 | case GNUNET_OK: | ||
1535 | case GNUNET_NO: // no state yet | ||
1536 | ret = GNUNET_OK; | ||
1537 | break; | ||
1538 | default: | ||
1539 | return ret; | ||
1540 | } | ||
1541 | |||
1542 | if (max_state_message_id < message_id - state_delta) | ||
1543 | return GNUNET_NO; /* some stateful messages not yet applied */ | ||
1544 | else if (message_id - state_delta < max_state_message_id) | ||
1545 | return GNUNET_NO; /* changes already applied */ | ||
1546 | } | ||
1547 | |||
1548 | if (TRANSACTION_NONE != plugin->transaction) | ||
1549 | { | ||
1550 | /** @todo FIXME: wait for other transaction to finish */ | ||
1551 | return GNUNET_SYSERR; | ||
1552 | } | ||
1553 | return transaction_begin (plugin, TRANSACTION_STATE_MODIFY); | ||
1554 | } | ||
1555 | |||
1556 | |||
1557 | /** | ||
1558 | * Set the current value of state variable. | ||
1559 | * | ||
1560 | * @see GNUNET_PSYCSTORE_state_modify() | ||
1561 | * | ||
1562 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
1563 | */ | ||
1564 | static int | ||
1565 | state_modify_op (void *cls, | ||
1566 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1567 | enum GNUNET_PSYC_Operator op, | ||
1568 | const char *name, const void *value, size_t value_size) | ||
1569 | { | ||
1570 | struct Plugin *plugin = cls; | ||
1571 | GNUNET_assert (TRANSACTION_STATE_MODIFY == plugin->transaction); | ||
1572 | |||
1573 | switch (op) | ||
1574 | { | ||
1575 | case GNUNET_PSYC_OP_ASSIGN: | ||
1576 | return state_assign (plugin, plugin->insert_state_current, channel_key, | ||
1577 | name, value, value_size); | ||
1578 | |||
1579 | default: /** @todo implement more state operations */ | ||
1580 | GNUNET_break (0); | ||
1581 | return GNUNET_SYSERR; | ||
1582 | } | ||
1583 | } | ||
1584 | |||
1585 | |||
1586 | /** | ||
1587 | * End modifying current state. | ||
1588 | */ | ||
1589 | static int | ||
1590 | state_modify_end (void *cls, | ||
1591 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1592 | uint64_t message_id) | ||
1593 | { | ||
1594 | struct Plugin *plugin = cls; | ||
1595 | GNUNET_assert (TRANSACTION_STATE_MODIFY == plugin->transaction); | ||
1596 | |||
1597 | return | ||
1598 | GNUNET_OK == exec_channel (plugin, plugin->delete_state_empty, channel_key) | ||
1599 | && GNUNET_OK == update_message_id (plugin, | ||
1600 | plugin->update_max_state_message_id, | ||
1601 | channel_key, message_id) | ||
1602 | && GNUNET_OK == transaction_commit (plugin) | ||
1603 | ? GNUNET_OK : GNUNET_SYSERR; | ||
1604 | } | ||
1605 | |||
1606 | |||
1607 | /** | ||
1608 | * Begin state synchronization. | ||
1609 | */ | ||
1610 | static int | ||
1611 | state_sync_begin (void *cls, | ||
1612 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key) | ||
1613 | { | ||
1614 | struct Plugin *plugin = cls; | ||
1615 | return exec_channel (plugin, plugin->delete_state_sync, channel_key); | ||
1616 | } | ||
1617 | |||
1618 | |||
1619 | /** | ||
1620 | * Assign current value of a state variable. | ||
1621 | * | ||
1622 | * @see GNUNET_PSYCSTORE_state_modify() | ||
1623 | * | ||
1624 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
1625 | */ | ||
1626 | static int | ||
1627 | state_sync_assign (void *cls, | ||
1628 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1629 | const char *name, const void *value, size_t value_size) | ||
1630 | { | ||
1631 | struct Plugin *plugin = cls; | ||
1632 | return state_assign (cls, plugin->insert_state_sync, channel_key, | ||
1633 | name, value, value_size); | ||
1634 | } | ||
1635 | |||
1636 | |||
1637 | /** | ||
1638 | * End modifying current state. | ||
1639 | */ | ||
1640 | static int | ||
1641 | state_sync_end (void *cls, | ||
1642 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1643 | uint64_t max_state_message_id, | ||
1644 | uint64_t state_hash_message_id) | ||
1645 | { | ||
1646 | struct Plugin *plugin = cls; | ||
1647 | int ret = GNUNET_SYSERR; | ||
1648 | |||
1649 | if (TRANSACTION_NONE != plugin->transaction) | ||
1650 | { | ||
1651 | /** @todo FIXME: wait for other transaction to finish */ | ||
1652 | return GNUNET_SYSERR; | ||
1653 | } | ||
1654 | |||
1655 | GNUNET_OK == transaction_begin (plugin, TRANSACTION_STATE_SYNC) | ||
1656 | && GNUNET_OK == exec_channel (plugin, plugin->delete_state, channel_key) | ||
1657 | && GNUNET_OK == exec_channel (plugin, plugin->insert_state_from_sync, | ||
1658 | channel_key) | ||
1659 | && GNUNET_OK == exec_channel (plugin, plugin->delete_state_sync, | ||
1660 | channel_key) | ||
1661 | && GNUNET_OK == update_message_id (plugin, | ||
1662 | plugin->update_state_hash_message_id, | ||
1663 | channel_key, state_hash_message_id) | ||
1664 | && GNUNET_OK == update_message_id (plugin, | ||
1665 | plugin->update_max_state_message_id, | ||
1666 | channel_key, max_state_message_id) | ||
1667 | && GNUNET_OK == transaction_commit (plugin) | ||
1668 | ? ret = GNUNET_OK | ||
1669 | : transaction_rollback (plugin); | ||
1670 | return ret; | ||
1671 | } | ||
1672 | |||
1673 | |||
1674 | /** | ||
1675 | * Delete the whole state. | ||
1676 | * | ||
1677 | * @see GNUNET_PSYCSTORE_state_reset() | ||
1678 | * | ||
1679 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
1680 | */ | ||
1681 | static int | ||
1682 | state_reset (void *cls, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key) | ||
1683 | { | ||
1684 | struct Plugin *plugin = cls; | ||
1685 | return exec_channel (plugin, plugin->delete_state, channel_key); | ||
1686 | } | ||
1687 | |||
1688 | |||
1689 | /** | ||
1690 | * Update signed values of state variables in the state store. | ||
1691 | * | ||
1692 | * @see GNUNET_PSYCSTORE_state_hash_update() | ||
1693 | * | ||
1694 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
1695 | */ | ||
1696 | static int | ||
1697 | state_update_signed (void *cls, | ||
1698 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key) | ||
1699 | { | ||
1700 | struct Plugin *plugin = cls; | ||
1701 | return exec_channel (plugin, plugin->update_state_signed, channel_key); | ||
1702 | } | ||
1703 | |||
1704 | |||
1705 | /** | ||
1706 | * Retrieve a state variable by name. | ||
1707 | * | ||
1708 | * @see GNUNET_PSYCSTORE_state_get() | ||
1709 | * | ||
1710 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
1711 | */ | ||
1712 | static int | ||
1713 | state_get (void *cls, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1714 | const char *name, GNUNET_PSYCSTORE_StateCallback cb, void *cb_cls) | ||
1715 | { | ||
1716 | struct Plugin *plugin = cls; | ||
1717 | int ret = GNUNET_SYSERR; | ||
1718 | |||
1719 | sqlite3_stmt *stmt = plugin->select_state_one; | ||
1720 | |||
1721 | if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key, | ||
1722 | sizeof (*channel_key), | ||
1723 | SQLITE_STATIC) | ||
1724 | || SQLITE_OK != sqlite3_bind_text (stmt, 2, name, -1, SQLITE_STATIC)) | ||
1725 | { | ||
1726 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1727 | "sqlite3_bind"); | ||
1728 | } | ||
1729 | else | ||
1730 | { | ||
1731 | switch (sqlite3_step (stmt)) | ||
1732 | { | ||
1733 | case SQLITE_DONE: | ||
1734 | ret = GNUNET_NO; | ||
1735 | break; | ||
1736 | case SQLITE_ROW: | ||
1737 | ret = cb (cb_cls, name, sqlite3_column_blob (stmt, 0), | ||
1738 | sqlite3_column_bytes (stmt, 0)); | ||
1739 | break; | ||
1740 | default: | ||
1741 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1742 | "sqlite3_step"); | ||
1743 | } | ||
1744 | } | ||
1745 | |||
1746 | if (SQLITE_OK != sqlite3_reset (stmt)) | ||
1747 | { | ||
1748 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1749 | "sqlite3_reset"); | ||
1750 | } | ||
1751 | |||
1752 | return ret; | ||
1753 | } | ||
1754 | |||
1755 | |||
1756 | /** | ||
1757 | * Retrieve all state variables for a channel with the given prefix. | ||
1758 | * | ||
1759 | * @see GNUNET_PSYCSTORE_state_get_prefix() | ||
1760 | * | ||
1761 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
1762 | */ | ||
1763 | static int | ||
1764 | state_get_prefix (void *cls, const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1765 | const char *name, GNUNET_PSYCSTORE_StateCallback cb, | ||
1766 | void *cb_cls) | ||
1767 | { | ||
1768 | struct Plugin *plugin = cls; | ||
1769 | int ret = GNUNET_SYSERR; | ||
1770 | sqlite3_stmt *stmt = plugin->select_state_prefix; | ||
1771 | size_t name_len = strlen (name); | ||
1772 | |||
1773 | if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key, | ||
1774 | sizeof (*channel_key), SQLITE_STATIC) | ||
1775 | || SQLITE_OK != sqlite3_bind_text (stmt, 2, name, name_len, SQLITE_STATIC) | ||
1776 | || SQLITE_OK != sqlite3_bind_int (stmt, 3, name_len) | ||
1777 | || SQLITE_OK != sqlite3_bind_text (stmt, 4, name, name_len, SQLITE_STATIC)) | ||
1778 | { | ||
1779 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1780 | "sqlite3_bind"); | ||
1781 | } | ||
1782 | else | ||
1783 | { | ||
1784 | int sql_ret; | ||
1785 | do | ||
1786 | { | ||
1787 | sql_ret = sqlite3_step (stmt); | ||
1788 | switch (sql_ret) | ||
1789 | { | ||
1790 | case SQLITE_DONE: | ||
1791 | if (ret != GNUNET_OK) | ||
1792 | ret = GNUNET_NO; | ||
1793 | break; | ||
1794 | case SQLITE_ROW: | ||
1795 | ret = cb (cb_cls, (const char *) sqlite3_column_text (stmt, 0), | ||
1796 | sqlite3_column_blob (stmt, 1), | ||
1797 | sqlite3_column_bytes (stmt, 1)); | ||
1798 | if (ret != GNUNET_YES) | ||
1799 | sql_ret = SQLITE_DONE; | ||
1800 | break; | ||
1801 | default: | ||
1802 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1803 | "sqlite3_step"); | ||
1804 | } | ||
1805 | } | ||
1806 | while (sql_ret == SQLITE_ROW); | ||
1807 | } | ||
1808 | if (SQLITE_OK != sqlite3_reset (stmt)) | ||
1809 | { | ||
1810 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1811 | "sqlite3_reset"); | ||
1812 | } | ||
1813 | return ret; | ||
1814 | } | ||
1815 | |||
1816 | |||
1817 | /** | ||
1818 | * Retrieve all signed state variables for a channel. | ||
1819 | * | ||
1820 | * @see GNUNET_PSYCSTORE_state_get_signed() | ||
1821 | * | ||
1822 | * @return #GNUNET_OK on success, else #GNUNET_SYSERR | ||
1823 | */ | ||
1824 | static int | ||
1825 | state_get_signed (void *cls, | ||
1826 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1827 | GNUNET_PSYCSTORE_StateCallback cb, void *cb_cls) | ||
1828 | { | ||
1829 | struct Plugin *plugin = cls; | ||
1830 | int ret = GNUNET_SYSERR; | ||
1831 | |||
1832 | sqlite3_stmt *stmt = plugin->select_state_signed; | ||
1833 | |||
1834 | if (SQLITE_OK != sqlite3_bind_blob (stmt, 1, channel_key, | ||
1835 | sizeof (*channel_key), SQLITE_STATIC)) | ||
1836 | { | ||
1837 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1838 | "sqlite3_bind"); | ||
1839 | } | ||
1840 | else | ||
1841 | { | ||
1842 | int sql_ret; | ||
1843 | do | ||
1844 | { | ||
1845 | sql_ret = sqlite3_step (stmt); | ||
1846 | switch (sql_ret) | ||
1847 | { | ||
1848 | case SQLITE_DONE: | ||
1849 | if (ret != GNUNET_OK) | ||
1850 | ret = GNUNET_NO; | ||
1851 | break; | ||
1852 | case SQLITE_ROW: | ||
1853 | ret = cb (cb_cls, (const char *) sqlite3_column_text (stmt, 0), | ||
1854 | sqlite3_column_blob (stmt, 1), | ||
1855 | sqlite3_column_bytes (stmt, 1)); | ||
1856 | if (ret != GNUNET_YES) | ||
1857 | sql_ret = SQLITE_DONE; | ||
1858 | break; | ||
1859 | default: | ||
1860 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1861 | "sqlite3_step"); | ||
1862 | } | ||
1863 | } | ||
1864 | while (sql_ret == SQLITE_ROW); | ||
1865 | } | ||
1866 | |||
1867 | if (SQLITE_OK != sqlite3_reset (stmt)) | ||
1868 | { | ||
1869 | LOG_SQLITE (plugin, GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
1870 | "sqlite3_reset"); | ||
1871 | } | ||
1872 | |||
1873 | return ret; | ||
1874 | } | ||
1875 | |||
1876 | |||
1877 | /** | ||
1878 | * Entry point for the plugin. | ||
1879 | * | ||
1880 | * @param cls The struct GNUNET_CONFIGURATION_Handle. | ||
1881 | * @return NULL on error, otherwise the plugin context | ||
1882 | */ | ||
1883 | void * | ||
1884 | libgnunet_plugin_psycstore_sqlite_init (void *cls) | ||
1885 | { | ||
1886 | static struct Plugin plugin; | ||
1887 | const struct GNUNET_CONFIGURATION_Handle *cfg = cls; | ||
1888 | struct GNUNET_PSYCSTORE_PluginFunctions *api; | ||
1889 | |||
1890 | if (NULL != plugin.cfg) | ||
1891 | return NULL; /* can only initialize once! */ | ||
1892 | memset (&plugin, 0, sizeof (struct Plugin)); | ||
1893 | plugin.cfg = cfg; | ||
1894 | if (GNUNET_OK != database_setup (&plugin)) | ||
1895 | { | ||
1896 | database_shutdown (&plugin); | ||
1897 | return NULL; | ||
1898 | } | ||
1899 | api = GNUNET_new (struct GNUNET_PSYCSTORE_PluginFunctions); | ||
1900 | api->cls = &plugin; | ||
1901 | api->membership_store = &sqlite_membership_store; | ||
1902 | api->membership_test = &membership_test; | ||
1903 | api->fragment_store = &fragment_store; | ||
1904 | api->message_add_flags = &message_add_flags; | ||
1905 | api->fragment_get = &fragment_get; | ||
1906 | api->fragment_get_latest = &fragment_get_latest; | ||
1907 | api->message_get = &message_get; | ||
1908 | api->message_get_latest = &message_get_latest; | ||
1909 | api->message_get_fragment = &message_get_fragment; | ||
1910 | api->counters_message_get = &counters_message_get; | ||
1911 | api->counters_state_get = &counters_state_get; | ||
1912 | api->state_modify_begin = &state_modify_begin; | ||
1913 | api->state_modify_op = &state_modify_op; | ||
1914 | api->state_modify_end = &state_modify_end; | ||
1915 | api->state_sync_begin = &state_sync_begin; | ||
1916 | api->state_sync_assign = &state_sync_assign; | ||
1917 | api->state_sync_end = &state_sync_end; | ||
1918 | api->state_reset = &state_reset; | ||
1919 | api->state_update_signed = &state_update_signed; | ||
1920 | api->state_get = &state_get; | ||
1921 | api->state_get_prefix = &state_get_prefix; | ||
1922 | api->state_get_signed = &state_get_signed; | ||
1923 | |||
1924 | LOG (GNUNET_ERROR_TYPE_INFO, _("SQLite database running\n")); | ||
1925 | return api; | ||
1926 | } | ||
1927 | |||
1928 | |||
1929 | /** | ||
1930 | * Exit point from the plugin. | ||
1931 | * | ||
1932 | * @param cls The plugin context (as returned by "init") | ||
1933 | * @return Always NULL | ||
1934 | */ | ||
1935 | void * | ||
1936 | libgnunet_plugin_psycstore_sqlite_done (void *cls) | ||
1937 | { | ||
1938 | struct GNUNET_PSYCSTORE_PluginFunctions *api = cls; | ||
1939 | struct Plugin *plugin = api->cls; | ||
1940 | |||
1941 | database_shutdown (plugin); | ||
1942 | plugin->cfg = NULL; | ||
1943 | GNUNET_free (api); | ||
1944 | LOG (GNUNET_ERROR_TYPE_DEBUG, "SQLite plugin is finished\n"); | ||
1945 | return NULL; | ||
1946 | } | ||
1947 | |||
1948 | /* end of plugin_psycstore_sqlite.c */ | ||
diff --git a/src/psycstore/psycstore.conf.in b/src/psycstore/psycstore.conf.in deleted file mode 100644 index 3905db173..000000000 --- a/src/psycstore/psycstore.conf.in +++ /dev/null | |||
@@ -1,28 +0,0 @@ | |||
1 | [psycstore] | ||
2 | START_ON_DEMAND = @START_ON_DEMAND@ | ||
3 | BINARY = gnunet-service-psycstore | ||
4 | |||
5 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-psycstore.sock | ||
6 | UNIX_MATCH_UID = YES | ||
7 | UNIX_MATCH_GID = YES | ||
8 | |||
9 | @UNIXONLY@PORT = 2111 | ||
10 | HOSTNAME = localhost | ||
11 | ACCEPT_FROM = 127.0.0.1; | ||
12 | ACCEPT_FROM6 = ::1; | ||
13 | |||
14 | DATABASE = sqlite | ||
15 | |||
16 | [psycstore-sqlite] | ||
17 | FILENAME = $GNUNET_DATA_HOME/psycstore/sqlite.db | ||
18 | |||
19 | [psycstore-mysql] | ||
20 | DATABASE = gnunet | ||
21 | CONFIG = ~/.my.cnf | ||
22 | # USER = gnunet | ||
23 | # PASSWORD = | ||
24 | # HOST = localhost | ||
25 | # PORT = 3306 | ||
26 | |||
27 | [psycstore-postgres] | ||
28 | CONFIG = connect_timeout=10; dbname=gnunet | ||
diff --git a/src/psycstore/psycstore.h b/src/psycstore/psycstore.h deleted file mode 100644 index 9a1c06aa8..000000000 --- a/src/psycstore/psycstore.h +++ /dev/null | |||
@@ -1,520 +0,0 @@ | |||
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 psycstore/psycstore.h | ||
23 | * @brief Common type definitions for the PSYCstore service and API. | ||
24 | * @author Gabor X Toth | ||
25 | */ | ||
26 | |||
27 | #ifndef GNUNET_PSYCSTORE_H | ||
28 | #define GNUNET_PSYCSTORE_H | ||
29 | |||
30 | #include "gnunet_common.h" | ||
31 | |||
32 | |||
33 | GNUNET_NETWORK_STRUCT_BEGIN | ||
34 | |||
35 | /** | ||
36 | * Answer from service to client about last operation. | ||
37 | */ | ||
38 | struct OperationResult | ||
39 | { | ||
40 | /** | ||
41 | * Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_CODE | ||
42 | */ | ||
43 | struct GNUNET_MessageHeader header; | ||
44 | |||
45 | uint32_t reserved GNUNET_PACKED; | ||
46 | |||
47 | /** | ||
48 | * Operation ID. | ||
49 | */ | ||
50 | uint64_t op_id GNUNET_PACKED; | ||
51 | |||
52 | /**lowed by | ||
53 | * Status code for the operation. | ||
54 | */ | ||
55 | uint64_t result_code GNUNET_PACKED; | ||
56 | |||
57 | /* followed by 0-terminated error message (on error) */ | ||
58 | |||
59 | }; | ||
60 | |||
61 | |||
62 | /** | ||
63 | * Answer from service to client about master counters. | ||
64 | * | ||
65 | * @see GNUNET_PSYCSTORE_counters_get() | ||
66 | */ | ||
67 | struct CountersResult | ||
68 | { | ||
69 | /** | ||
70 | * Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_COUNTERS | ||
71 | */ | ||
72 | struct GNUNET_MessageHeader header; | ||
73 | |||
74 | /** | ||
75 | * Status code for the operation: | ||
76 | * #GNUNET_OK: success, counter values are returned. | ||
77 | * #GNUNET_NO: no message has been sent to the channel yet. | ||
78 | * #GNUNET_SYSERR: an error occurred. | ||
79 | */ | ||
80 | uint32_t result_code GNUNET_PACKED; | ||
81 | |||
82 | /** | ||
83 | * Operation ID. | ||
84 | */ | ||
85 | uint64_t op_id GNUNET_PACKED; | ||
86 | |||
87 | uint64_t max_fragment_id GNUNET_PACKED; | ||
88 | |||
89 | uint64_t max_message_id GNUNET_PACKED; | ||
90 | |||
91 | uint64_t max_group_generation GNUNET_PACKED; | ||
92 | |||
93 | uint64_t max_state_message_id GNUNET_PACKED; | ||
94 | }; | ||
95 | |||
96 | |||
97 | /** | ||
98 | * Answer from service to client containing a message fragment. | ||
99 | */ | ||
100 | struct FragmentResult | ||
101 | { | ||
102 | /** | ||
103 | * Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_CODE | ||
104 | */ | ||
105 | struct GNUNET_MessageHeader header; | ||
106 | |||
107 | uint32_t psycstore_flags GNUNET_PACKED; | ||
108 | |||
109 | /** | ||
110 | * Operation ID. | ||
111 | */ | ||
112 | uint64_t op_id GNUNET_PACKED; | ||
113 | |||
114 | /* Followed by GNUNET_MULTICAST_MessageHeader */ | ||
115 | }; | ||
116 | |||
117 | |||
118 | /** | ||
119 | * Answer from service to client containing a state variable. | ||
120 | */ | ||
121 | struct StateResult | ||
122 | { | ||
123 | /** | ||
124 | * Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_CODE | ||
125 | */ | ||
126 | struct GNUNET_MessageHeader header; | ||
127 | |||
128 | uint16_t name_size GNUNET_PACKED; | ||
129 | |||
130 | uint16_t reserved GNUNET_PACKED; | ||
131 | |||
132 | /** | ||
133 | * Operation ID. | ||
134 | */ | ||
135 | uint64_t op_id GNUNET_PACKED; | ||
136 | |||
137 | /* Followed by name and value */ | ||
138 | }; | ||
139 | |||
140 | |||
141 | /** | ||
142 | * Generic operation request. | ||
143 | */ | ||
144 | struct OperationRequest | ||
145 | { | ||
146 | struct GNUNET_MessageHeader header; | ||
147 | |||
148 | uint32_t reserved GNUNET_PACKED; | ||
149 | |||
150 | /** | ||
151 | * Operation ID. | ||
152 | */ | ||
153 | uint64_t op_id GNUNET_PACKED; | ||
154 | |||
155 | struct GNUNET_CRYPTO_EddsaPublicKey channel_key; | ||
156 | }; | ||
157 | |||
158 | |||
159 | /** | ||
160 | * @see GNUNET_PSYCSTORE_membership_store() | ||
161 | */ | ||
162 | struct MembershipStoreRequest | ||
163 | { | ||
164 | /** | ||
165 | * Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_MEMBERSHIP_STORE | ||
166 | */ | ||
167 | struct GNUNET_MessageHeader header; | ||
168 | |||
169 | uint32_t reserved GNUNET_PACKED; | ||
170 | |||
171 | /** | ||
172 | * Operation ID. | ||
173 | */ | ||
174 | uint64_t op_id GNUNET_PACKED; | ||
175 | |||
176 | /** | ||
177 | * Channel's public key. | ||
178 | */ | ||
179 | struct GNUNET_CRYPTO_EddsaPublicKey channel_key; | ||
180 | |||
181 | /** | ||
182 | * Slave's public key. | ||
183 | */ | ||
184 | struct GNUNET_CRYPTO_EcdsaPublicKey slave_key; | ||
185 | |||
186 | uint64_t announced_at GNUNET_PACKED; | ||
187 | uint64_t effective_since GNUNET_PACKED; | ||
188 | uint64_t group_generation GNUNET_PACKED; | ||
189 | uint8_t did_join; | ||
190 | }; | ||
191 | |||
192 | |||
193 | /** | ||
194 | * @see GNUNET_PSYCSTORE_membership_test() | ||
195 | */ | ||
196 | struct MembershipTestRequest | ||
197 | { | ||
198 | /** | ||
199 | * Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_MEMBERSHIP_TEST | ||
200 | */ | ||
201 | struct GNUNET_MessageHeader header; | ||
202 | |||
203 | uint32_t reserved GNUNET_PACKED; | ||
204 | |||
205 | /** | ||
206 | * Operation ID. | ||
207 | */ | ||
208 | uint64_t op_id GNUNET_PACKED; | ||
209 | |||
210 | /** | ||
211 | * Channel's public key. | ||
212 | */ | ||
213 | struct GNUNET_CRYPTO_EddsaPublicKey channel_key; | ||
214 | |||
215 | /** | ||
216 | * Slave's public key. | ||
217 | */ | ||
218 | struct GNUNET_CRYPTO_EcdsaPublicKey slave_key; | ||
219 | |||
220 | uint64_t message_id GNUNET_PACKED; | ||
221 | |||
222 | uint64_t group_generation GNUNET_PACKED; | ||
223 | }; | ||
224 | |||
225 | |||
226 | /** | ||
227 | * @see GNUNET_PSYCSTORE_fragment_store() | ||
228 | */ | ||
229 | struct FragmentStoreRequest | ||
230 | { | ||
231 | /** | ||
232 | * Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_FRAGMENT_STORE | ||
233 | */ | ||
234 | struct GNUNET_MessageHeader header; | ||
235 | |||
236 | /** | ||
237 | * enum GNUNET_PSYCSTORE_MessageFlags | ||
238 | */ | ||
239 | uint32_t psycstore_flags GNUNET_PACKED; | ||
240 | |||
241 | /** | ||
242 | * Channel's public key. | ||
243 | */ | ||
244 | struct GNUNET_CRYPTO_EddsaPublicKey channel_key; | ||
245 | |||
246 | /** | ||
247 | * Operation ID. | ||
248 | */ | ||
249 | uint64_t op_id; | ||
250 | |||
251 | /* Followed by fragment */ | ||
252 | }; | ||
253 | |||
254 | |||
255 | /** | ||
256 | * @see GNUNET_PSYCSTORE_fragment_get() | ||
257 | */ | ||
258 | struct FragmentGetRequest | ||
259 | { | ||
260 | /** | ||
261 | * Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_FRAGMENT_GET | ||
262 | */ | ||
263 | struct GNUNET_MessageHeader header; | ||
264 | |||
265 | uint32_t reserved GNUNET_PACKED; | ||
266 | |||
267 | /** | ||
268 | * Operation ID. | ||
269 | */ | ||
270 | uint64_t op_id GNUNET_PACKED; | ||
271 | |||
272 | /** | ||
273 | * Channel's public key. | ||
274 | */ | ||
275 | struct GNUNET_CRYPTO_EddsaPublicKey channel_key; | ||
276 | |||
277 | /** | ||
278 | * Slave's public key. | ||
279 | */ | ||
280 | struct GNUNET_CRYPTO_EcdsaPublicKey slave_key; | ||
281 | |||
282 | /** | ||
283 | * First fragment ID to request. | ||
284 | */ | ||
285 | uint64_t first_fragment_id GNUNET_PACKED; | ||
286 | |||
287 | /** | ||
288 | * Last fragment ID to request. | ||
289 | */ | ||
290 | uint64_t last_fragment_id GNUNET_PACKED; | ||
291 | |||
292 | /** | ||
293 | * Maximum number of fragments to retrieve. | ||
294 | */ | ||
295 | uint64_t fragment_limit GNUNET_PACKED; | ||
296 | |||
297 | /** | ||
298 | * Do membership test with @a slave_key before returning fragment? | ||
299 | * #GNUNET_YES or #GNUNET_NO | ||
300 | */ | ||
301 | uint8_t do_membership_test; | ||
302 | }; | ||
303 | |||
304 | |||
305 | /** | ||
306 | * @see GNUNET_PSYCSTORE_message_get() | ||
307 | */ | ||
308 | struct MessageGetRequest | ||
309 | { | ||
310 | /** | ||
311 | * Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_MESSAGE_GET | ||
312 | */ | ||
313 | struct GNUNET_MessageHeader header; | ||
314 | |||
315 | uint32_t reserved GNUNET_PACKED; | ||
316 | |||
317 | /** | ||
318 | * Operation ID. | ||
319 | */ | ||
320 | uint64_t op_id GNUNET_PACKED; | ||
321 | |||
322 | /** | ||
323 | * Channel's public key. | ||
324 | */ | ||
325 | struct GNUNET_CRYPTO_EddsaPublicKey channel_key; | ||
326 | |||
327 | /** | ||
328 | * Slave's public key. | ||
329 | */ | ||
330 | struct GNUNET_CRYPTO_EcdsaPublicKey slave_key; | ||
331 | |||
332 | /** | ||
333 | * First message ID to request. | ||
334 | */ | ||
335 | uint64_t first_message_id GNUNET_PACKED; | ||
336 | |||
337 | /** | ||
338 | * Last message ID to request. | ||
339 | */ | ||
340 | uint64_t last_message_id GNUNET_PACKED; | ||
341 | |||
342 | /** | ||
343 | * Maximum number of messages to retrieve. | ||
344 | */ | ||
345 | uint64_t message_limit GNUNET_PACKED; | ||
346 | |||
347 | /** | ||
348 | * Maximum number of fragments to retrieve. | ||
349 | */ | ||
350 | uint64_t fragment_limit GNUNET_PACKED; | ||
351 | |||
352 | /** | ||
353 | * Do membership test with @a slave_key before returning fragment? | ||
354 | * #GNUNET_YES or #GNUNET_NO | ||
355 | */ | ||
356 | uint8_t do_membership_test; | ||
357 | |||
358 | /* Followed by method_prefix */ | ||
359 | }; | ||
360 | |||
361 | |||
362 | /** | ||
363 | * @see GNUNET_PSYCSTORE_message_get_fragment() | ||
364 | */ | ||
365 | struct MessageGetFragmentRequest | ||
366 | { | ||
367 | /** | ||
368 | * Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_MESSAGE_FRAGMENT_GET | ||
369 | */ | ||
370 | struct GNUNET_MessageHeader header; | ||
371 | |||
372 | uint32_t reserved GNUNET_PACKED; | ||
373 | |||
374 | /** | ||
375 | * Operation ID. | ||
376 | */ | ||
377 | uint64_t op_id GNUNET_PACKED; | ||
378 | |||
379 | /** | ||
380 | * Channel's public key. | ||
381 | */ | ||
382 | struct GNUNET_CRYPTO_EddsaPublicKey channel_key; | ||
383 | |||
384 | /** | ||
385 | * Slave's public key. | ||
386 | */ | ||
387 | struct GNUNET_CRYPTO_EcdsaPublicKey slave_key; | ||
388 | |||
389 | /** | ||
390 | * Requested message ID. | ||
391 | */ | ||
392 | uint64_t message_id GNUNET_PACKED; | ||
393 | |||
394 | /** | ||
395 | * Requested fragment offset. | ||
396 | */ | ||
397 | uint64_t fragment_offset GNUNET_PACKED; | ||
398 | |||
399 | /** | ||
400 | * Do membership test with @a slave_key before returning fragment? | ||
401 | * #GNUNET_YES or #GNUNET_NO | ||
402 | */ | ||
403 | uint8_t do_membership_test; | ||
404 | }; | ||
405 | |||
406 | |||
407 | /** | ||
408 | * @see GNUNET_PSYCSTORE_state_hash_update() | ||
409 | */ | ||
410 | struct StateHashUpdateRequest | ||
411 | { | ||
412 | /** | ||
413 | * Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_HASH_UPDATE | ||
414 | */ | ||
415 | struct GNUNET_MessageHeader header; | ||
416 | |||
417 | uint32_t reserved GNUNET_PACKED; | ||
418 | |||
419 | /** | ||
420 | * Operation ID. | ||
421 | */ | ||
422 | uint64_t op_id GNUNET_PACKED; | ||
423 | |||
424 | /** | ||
425 | * Channel's public key. | ||
426 | */ | ||
427 | struct GNUNET_CRYPTO_EddsaPublicKey channel_key; | ||
428 | |||
429 | struct GNUNET_HashCode hash; | ||
430 | }; | ||
431 | |||
432 | |||
433 | enum StateOpFlags | ||
434 | { | ||
435 | STATE_OP_FIRST = 1 << 0, | ||
436 | STATE_OP_LAST = 1 << 1 | ||
437 | }; | ||
438 | |||
439 | |||
440 | /** | ||
441 | * @see GNUNET_PSYCSTORE_state_modify() | ||
442 | */ | ||
443 | struct StateModifyRequest | ||
444 | { | ||
445 | /** | ||
446 | * Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_MODIFY | ||
447 | */ | ||
448 | struct GNUNET_MessageHeader header; | ||
449 | |||
450 | /** | ||
451 | * Operation ID. | ||
452 | */ | ||
453 | uint64_t op_id GNUNET_PACKED; | ||
454 | |||
455 | /** | ||
456 | * ID of the message to apply the state changes in. | ||
457 | */ | ||
458 | uint64_t message_id GNUNET_PACKED; | ||
459 | |||
460 | /** | ||
461 | * State delta of the message with ID @a message_id. | ||
462 | */ | ||
463 | uint64_t state_delta GNUNET_PACKED; | ||
464 | |||
465 | /** | ||
466 | * Channel's public key. | ||
467 | */ | ||
468 | struct GNUNET_CRYPTO_EddsaPublicKey channel_key; | ||
469 | }; | ||
470 | |||
471 | |||
472 | /** | ||
473 | * @see GNUNET_PSYCSTORE_state_sync() | ||
474 | */ | ||
475 | struct StateSyncRequest | ||
476 | { | ||
477 | /** | ||
478 | * Type: GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_SYNC | ||
479 | */ | ||
480 | struct GNUNET_MessageHeader header; | ||
481 | |||
482 | /** | ||
483 | * Size of name, including NUL terminator. | ||
484 | */ | ||
485 | uint16_t name_size GNUNET_PACKED; | ||
486 | |||
487 | /** | ||
488 | * OR'd StateOpFlags | ||
489 | */ | ||
490 | uint8_t flags; | ||
491 | |||
492 | uint8_t reserved; | ||
493 | |||
494 | /** | ||
495 | * Operation ID. | ||
496 | */ | ||
497 | uint64_t op_id GNUNET_PACKED; | ||
498 | |||
499 | /** | ||
500 | * ID of the message that contains the state_hash PSYC header variable. | ||
501 | */ | ||
502 | uint64_t state_hash_message_id GNUNET_PACKED; | ||
503 | |||
504 | /** | ||
505 | * ID of the last stateful message before @a state_hash_message_id. | ||
506 | */ | ||
507 | uint64_t max_state_message_id GNUNET_PACKED; | ||
508 | |||
509 | /** | ||
510 | * Channel's public key. | ||
511 | */ | ||
512 | struct GNUNET_CRYPTO_EddsaPublicKey channel_key; | ||
513 | |||
514 | /* Followed by NUL-terminated name, then the value. */ | ||
515 | }; | ||
516 | |||
517 | |||
518 | GNUNET_NETWORK_STRUCT_END | ||
519 | |||
520 | #endif | ||
diff --git a/src/psycstore/psycstore_api.c b/src/psycstore/psycstore_api.c deleted file mode 100644 index ab4cd0fbf..000000000 --- a/src/psycstore/psycstore_api.c +++ /dev/null | |||
@@ -1,1285 +0,0 @@ | |||
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 psycstore/psycstore_api.c | ||
23 | * @brief API to interact with the PSYCstore service | ||
24 | * @author Gabor X Toth | ||
25 | * @author Christian Grothoff | ||
26 | */ | ||
27 | |||
28 | #include <inttypes.h> | ||
29 | |||
30 | #include "platform.h" | ||
31 | #include "gnunet_util_lib.h" | ||
32 | #include "gnunet_constants.h" | ||
33 | #include "gnunet_protocols.h" | ||
34 | #include "gnunet_psycstore_service.h" | ||
35 | #include "gnunet_multicast_service.h" | ||
36 | #include "psycstore.h" | ||
37 | |||
38 | #define LOG(kind,...) GNUNET_log_from (kind, "psycstore-api",__VA_ARGS__) | ||
39 | |||
40 | /** | ||
41 | * Handle for an operation with the PSYCstore service. | ||
42 | */ | ||
43 | struct GNUNET_PSYCSTORE_OperationHandle | ||
44 | { | ||
45 | |||
46 | /** | ||
47 | * Main PSYCstore handle. | ||
48 | */ | ||
49 | struct GNUNET_PSYCSTORE_Handle *h; | ||
50 | |||
51 | /** | ||
52 | * Data callbacks. | ||
53 | */ | ||
54 | union { | ||
55 | GNUNET_PSYCSTORE_FragmentCallback fragment_cb; | ||
56 | GNUNET_PSYCSTORE_CountersCallback counters_cb; | ||
57 | GNUNET_PSYCSTORE_StateCallback state_cb; | ||
58 | }; | ||
59 | |||
60 | /** | ||
61 | * Closure for callbacks. | ||
62 | */ | ||
63 | void *cls; | ||
64 | |||
65 | /** | ||
66 | * Message envelope. | ||
67 | */ | ||
68 | struct GNUNET_MQ_Envelope *env; | ||
69 | |||
70 | /** | ||
71 | * Operation ID. | ||
72 | */ | ||
73 | uint64_t op_id; | ||
74 | }; | ||
75 | |||
76 | |||
77 | /** | ||
78 | * Handle for the service. | ||
79 | */ | ||
80 | struct GNUNET_PSYCSTORE_Handle | ||
81 | { | ||
82 | /** | ||
83 | * Configuration to use. | ||
84 | */ | ||
85 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
86 | |||
87 | /** | ||
88 | * Client connection. | ||
89 | */ | ||
90 | struct GNUNET_MQ_Handle *mq; | ||
91 | |||
92 | /** | ||
93 | * Async operations. | ||
94 | */ | ||
95 | struct GNUNET_OP_Handle *op; | ||
96 | |||
97 | /** | ||
98 | * Task doing exponential back-off trying to reconnect. | ||
99 | */ | ||
100 | struct GNUNET_SCHEDULER_Task *reconnect_task; | ||
101 | |||
102 | /** | ||
103 | * Delay for next connect retry. | ||
104 | */ | ||
105 | struct GNUNET_TIME_Relative reconnect_delay; | ||
106 | |||
107 | |||
108 | GNUNET_PSYCSTORE_FragmentCallback *fragment_cb; | ||
109 | |||
110 | GNUNET_PSYCSTORE_CountersCallback *counters_cb; | ||
111 | |||
112 | GNUNET_PSYCSTORE_StateCallback *state_cb; | ||
113 | /** | ||
114 | * Closure for callbacks. | ||
115 | */ | ||
116 | void *cb_cls; | ||
117 | }; | ||
118 | |||
119 | |||
120 | static int | ||
121 | check_result_code (void *cls, const struct OperationResult *opres) | ||
122 | { | ||
123 | uint16_t size = ntohs (opres->header.size); | ||
124 | const char *str = (const char *) &opres[1]; | ||
125 | if ( (sizeof (*opres) < size) && | ||
126 | ('\0' != str[size - sizeof (*opres) - 1]) ) | ||
127 | { | ||
128 | GNUNET_break (0); | ||
129 | return GNUNET_SYSERR; | ||
130 | } | ||
131 | |||
132 | return GNUNET_OK; | ||
133 | } | ||
134 | |||
135 | |||
136 | static void | ||
137 | handle_result_code (void *cls, const struct OperationResult *opres) | ||
138 | { | ||
139 | struct GNUNET_PSYCSTORE_Handle *h = cls; | ||
140 | struct GNUNET_PSYCSTORE_OperationHandle *op = NULL; | ||
141 | uint16_t size = ntohs (opres->header.size); | ||
142 | |||
143 | const char * | ||
144 | str = (sizeof (*opres) < size) ? (const char *) &opres[1] : ""; | ||
145 | |||
146 | if (GNUNET_YES == GNUNET_OP_result (h->op, GNUNET_ntohll (opres->op_id), | ||
147 | GNUNET_ntohll (opres->result_code) + INT64_MIN, | ||
148 | str, size - sizeof (*opres), (void **) &op)) | ||
149 | { | ||
150 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
151 | "handle_result_code: Received result message with OP ID: %" PRIu64 "\n", | ||
152 | GNUNET_ntohll (opres->op_id)); | ||
153 | GNUNET_free (op); | ||
154 | } | ||
155 | else | ||
156 | { | ||
157 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
158 | "handle_result_code: No callback registered for OP ID %" PRIu64 ".\n", | ||
159 | GNUNET_ntohll (opres->op_id)); | ||
160 | } | ||
161 | h->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS; | ||
162 | } | ||
163 | |||
164 | |||
165 | static void | ||
166 | handle_result_counters (void *cls, const struct CountersResult *cres) | ||
167 | { | ||
168 | struct GNUNET_PSYCSTORE_Handle *h = cls; | ||
169 | struct GNUNET_PSYCSTORE_OperationHandle *op = NULL; | ||
170 | |||
171 | if (GNUNET_YES == GNUNET_OP_get (h->op, GNUNET_ntohll (cres->op_id), | ||
172 | NULL, NULL, (void **) &op)) | ||
173 | { | ||
174 | GNUNET_assert (NULL != op); | ||
175 | if (NULL != op->counters_cb) | ||
176 | { | ||
177 | op->counters_cb (op->cls, | ||
178 | ntohl (cres->result_code), | ||
179 | GNUNET_ntohll (cres->max_fragment_id), | ||
180 | GNUNET_ntohll (cres->max_message_id), | ||
181 | GNUNET_ntohll (cres->max_group_generation), | ||
182 | GNUNET_ntohll (cres->max_state_message_id)); | ||
183 | } | ||
184 | GNUNET_OP_remove (h->op, GNUNET_ntohll (cres->op_id)); | ||
185 | GNUNET_free (op); | ||
186 | } | ||
187 | else | ||
188 | { | ||
189 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
190 | "handle_result_counters: No callback registered for OP ID %" PRIu64 ".\n", | ||
191 | GNUNET_ntohll (cres->op_id)); | ||
192 | } | ||
193 | h->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS; | ||
194 | } | ||
195 | |||
196 | |||
197 | static int | ||
198 | check_result_fragment (void *cls, const struct FragmentResult *fres) | ||
199 | { | ||
200 | uint16_t size = ntohs (fres->header.size); | ||
201 | struct GNUNET_MULTICAST_MessageHeader *mmsg = | ||
202 | (struct GNUNET_MULTICAST_MessageHeader *) &fres[1]; | ||
203 | if (sizeof (*fres) + sizeof (*mmsg) < size | ||
204 | && sizeof (*fres) + ntohs (mmsg->header.size) != size) | ||
205 | { | ||
206 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
207 | "check_result_fragment: Received message with invalid length %lu bytes.\n", | ||
208 | size, sizeof (*fres)); | ||
209 | GNUNET_break (0); | ||
210 | return GNUNET_SYSERR; | ||
211 | } | ||
212 | return GNUNET_OK; | ||
213 | } | ||
214 | |||
215 | |||
216 | static void | ||
217 | handle_result_fragment (void *cls, const struct FragmentResult *fres) | ||
218 | { | ||
219 | struct GNUNET_PSYCSTORE_Handle *h = cls; | ||
220 | struct GNUNET_PSYCSTORE_OperationHandle *op = NULL; | ||
221 | |||
222 | if (GNUNET_YES == GNUNET_OP_get (h->op, GNUNET_ntohll (fres->op_id), | ||
223 | NULL, NULL, (void **) &op)) | ||
224 | { | ||
225 | GNUNET_assert (NULL != op); | ||
226 | if (NULL != op->fragment_cb) | ||
227 | op->fragment_cb (op->cls, | ||
228 | (struct GNUNET_MULTICAST_MessageHeader *) &fres[1], | ||
229 | ntohl (fres->psycstore_flags)); | ||
230 | //GNUNET_OP_remove (h->op, GNUNET_ntohll (fres->op_id)); | ||
231 | //GNUNET_free (op); | ||
232 | } | ||
233 | else | ||
234 | { | ||
235 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
236 | "handle_result_fragment: No callback registered for OP ID %" PRIu64 ".\n", | ||
237 | GNUNET_ntohll (fres->op_id)); | ||
238 | } | ||
239 | h->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS; | ||
240 | } | ||
241 | |||
242 | |||
243 | static int | ||
244 | check_result_state (void *cls, const struct StateResult *sres) | ||
245 | { | ||
246 | const char *name = (const char *) &sres[1]; | ||
247 | uint16_t size = ntohs (sres->header.size); | ||
248 | uint16_t name_size = ntohs (sres->name_size); | ||
249 | |||
250 | if (name_size <= 2 | ||
251 | || size - sizeof (*sres) < name_size | ||
252 | || '\0' != name[name_size - 1]) | ||
253 | { | ||
254 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
255 | "check_result_state: Received state result message with invalid name.\n"); | ||
256 | GNUNET_break (0); | ||
257 | return GNUNET_SYSERR; | ||
258 | } | ||
259 | return GNUNET_OK; | ||
260 | } | ||
261 | |||
262 | |||
263 | static void | ||
264 | handle_result_state (void *cls, const struct StateResult *sres) | ||
265 | { | ||
266 | struct GNUNET_PSYCSTORE_Handle *h = cls; | ||
267 | struct GNUNET_PSYCSTORE_OperationHandle *op = NULL; | ||
268 | |||
269 | const char *name = (const char *) &sres[1]; | ||
270 | uint16_t name_size = ntohs (sres->name_size); | ||
271 | |||
272 | if (GNUNET_YES == GNUNET_OP_get (h->op, GNUNET_ntohll (sres->op_id), | ||
273 | NULL, NULL, (void **) &op)) | ||
274 | { | ||
275 | GNUNET_assert (NULL != op); | ||
276 | if (NULL != op->state_cb) | ||
277 | op->state_cb (op->cls, name, (char *) &sres[1] + name_size, | ||
278 | ntohs (sres->header.size) - sizeof (*sres) - name_size); | ||
279 | //GNUNET_OP_remove (h->op, GNUNET_ntohll (sres->op_id)); | ||
280 | //GNUNET_free (op); | ||
281 | } | ||
282 | else | ||
283 | { | ||
284 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
285 | "handle_result_state: No callback registered for OP ID %" PRIu64 ".\n", | ||
286 | GNUNET_ntohll (sres->op_id)); | ||
287 | } | ||
288 | h->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS; | ||
289 | } | ||
290 | |||
291 | |||
292 | static void | ||
293 | reconnect (void *cls); | ||
294 | |||
295 | |||
296 | /** | ||
297 | * Client disconnected from service. | ||
298 | * | ||
299 | * Reconnect after backoff period.= | ||
300 | */ | ||
301 | static void | ||
302 | disconnected (void *cls, enum GNUNET_MQ_Error error) | ||
303 | { | ||
304 | struct GNUNET_PSYCSTORE_Handle *h = cls; | ||
305 | |||
306 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
307 | "Origin client disconnected (%d), re-connecting\n", | ||
308 | (int) error); | ||
309 | if (NULL != h->mq) | ||
310 | { | ||
311 | GNUNET_MQ_destroy (h->mq); | ||
312 | GNUNET_OP_destroy (h->op); | ||
313 | h->mq = NULL; | ||
314 | h->op = NULL; | ||
315 | } | ||
316 | |||
317 | h->reconnect_task = GNUNET_SCHEDULER_add_delayed (h->reconnect_delay, | ||
318 | &reconnect, h); | ||
319 | h->reconnect_delay = GNUNET_TIME_STD_BACKOFF (h->reconnect_delay); | ||
320 | } | ||
321 | |||
322 | |||
323 | static void | ||
324 | do_connect (struct GNUNET_PSYCSTORE_Handle *h) | ||
325 | { | ||
326 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
327 | "Connecting to PSYCstore service.\n"); | ||
328 | |||
329 | struct GNUNET_MQ_MessageHandler handlers[] = { | ||
330 | GNUNET_MQ_hd_var_size (result_code, | ||
331 | GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_CODE, | ||
332 | struct OperationResult, | ||
333 | h), | ||
334 | GNUNET_MQ_hd_fixed_size (result_counters, | ||
335 | GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_COUNTERS, | ||
336 | struct CountersResult, | ||
337 | h), | ||
338 | GNUNET_MQ_hd_var_size (result_fragment, | ||
339 | GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_FRAGMENT, | ||
340 | struct FragmentResult, | ||
341 | h), | ||
342 | GNUNET_MQ_hd_var_size (result_state, | ||
343 | GNUNET_MESSAGE_TYPE_PSYCSTORE_RESULT_STATE, | ||
344 | struct StateResult, | ||
345 | h), | ||
346 | GNUNET_MQ_handler_end () | ||
347 | }; | ||
348 | |||
349 | h->op = GNUNET_OP_create (); | ||
350 | GNUNET_assert (NULL == h->mq); | ||
351 | h->mq = GNUNET_CLIENT_connect (h->cfg, "psycstore", | ||
352 | handlers, disconnected, h); | ||
353 | GNUNET_assert (NULL != h->mq); | ||
354 | } | ||
355 | |||
356 | |||
357 | /** | ||
358 | * Try again to connect to the PSYCstore service. | ||
359 | * | ||
360 | * @param cls Handle to the PSYCstore service. | ||
361 | */ | ||
362 | static void | ||
363 | reconnect (void *cls) | ||
364 | { | ||
365 | struct GNUNET_PSYCSTORE_Handle *h = cls; | ||
366 | |||
367 | h->reconnect_task = NULL; | ||
368 | do_connect (cls); | ||
369 | } | ||
370 | |||
371 | |||
372 | /** | ||
373 | * Connect to the PSYCstore service. | ||
374 | * | ||
375 | * @param cfg The configuration to use | ||
376 | * @return Handle to use | ||
377 | */ | ||
378 | struct GNUNET_PSYCSTORE_Handle * | ||
379 | GNUNET_PSYCSTORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
380 | { | ||
381 | struct GNUNET_PSYCSTORE_Handle *h | ||
382 | = GNUNET_new (struct GNUNET_PSYCSTORE_Handle); | ||
383 | h->cfg = cfg; | ||
384 | h->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS; | ||
385 | do_connect (h); | ||
386 | return h; | ||
387 | } | ||
388 | |||
389 | |||
390 | /** | ||
391 | * Disconnect from PSYCstore service | ||
392 | * | ||
393 | * @param h Handle to destroy | ||
394 | */ | ||
395 | void | ||
396 | GNUNET_PSYCSTORE_disconnect (struct GNUNET_PSYCSTORE_Handle *h) | ||
397 | { | ||
398 | GNUNET_assert (NULL != h); | ||
399 | if (h->reconnect_task != NULL) | ||
400 | { | ||
401 | GNUNET_SCHEDULER_cancel (h->reconnect_task); | ||
402 | h->reconnect_task = NULL; | ||
403 | } | ||
404 | if (NULL != h->mq) | ||
405 | { | ||
406 | // FIXME: free data structures for pending operations | ||
407 | GNUNET_MQ_destroy (h->mq); | ||
408 | h->mq = NULL; | ||
409 | } | ||
410 | GNUNET_free (h); | ||
411 | } | ||
412 | |||
413 | |||
414 | /** | ||
415 | * Message sent notification. | ||
416 | * | ||
417 | * Remove invalidated envelope pointer. | ||
418 | */ | ||
419 | static void | ||
420 | message_sent (void *cls) | ||
421 | { | ||
422 | struct GNUNET_PSYCSTORE_OperationHandle *op = cls; | ||
423 | op->env = NULL; | ||
424 | } | ||
425 | |||
426 | |||
427 | /** | ||
428 | * Create a new operation. | ||
429 | */ | ||
430 | static struct GNUNET_PSYCSTORE_OperationHandle * | ||
431 | op_create (struct GNUNET_PSYCSTORE_Handle *h, | ||
432 | struct GNUNET_OP_Handle *hop, | ||
433 | GNUNET_PSYCSTORE_ResultCallback result_cb, | ||
434 | void *cls) | ||
435 | { | ||
436 | struct GNUNET_PSYCSTORE_OperationHandle * | ||
437 | op = GNUNET_malloc (sizeof (*op)); | ||
438 | op->h = h; | ||
439 | op->op_id = GNUNET_OP_add (hop, | ||
440 | (GNUNET_ResultCallback) result_cb, | ||
441 | cls, op); | ||
442 | return op; | ||
443 | } | ||
444 | |||
445 | |||
446 | /** | ||
447 | * Send a message associated with an operation. | ||
448 | * | ||
449 | * @param h | ||
450 | * PSYCstore handle. | ||
451 | * @param op | ||
452 | * Operation handle. | ||
453 | * @param env | ||
454 | * Message envelope to send. | ||
455 | * @param[out] op_id | ||
456 | * Operation ID to write in network byte order. NULL if not needed. | ||
457 | * | ||
458 | * @return Operation handle. | ||
459 | * | ||
460 | */ | ||
461 | static struct GNUNET_PSYCSTORE_OperationHandle * | ||
462 | op_send (struct GNUNET_PSYCSTORE_Handle *h, | ||
463 | struct GNUNET_PSYCSTORE_OperationHandle *op, | ||
464 | struct GNUNET_MQ_Envelope *env, | ||
465 | uint64_t *op_id) | ||
466 | { | ||
467 | op->env = env; | ||
468 | if (NULL != op_id) | ||
469 | *op_id = GNUNET_htonll (op->op_id); | ||
470 | |||
471 | GNUNET_MQ_notify_sent (env, message_sent, op); | ||
472 | GNUNET_MQ_send (h->mq, env); | ||
473 | return op; | ||
474 | } | ||
475 | |||
476 | |||
477 | /** | ||
478 | * Cancel a PSYCstore operation. Note that the operation MAY still | ||
479 | * be executed; this merely cancels the continuation; if the request | ||
480 | * was already transmitted, the service may still choose to complete | ||
481 | * the operation. | ||
482 | * | ||
483 | * @param op Operation to cancel. | ||
484 | * | ||
485 | * @return #GNUNET_YES if message was not sent yet and got discarded, | ||
486 | * #GNUNET_NO if it was already sent, and only the callbacks got cancelled. | ||
487 | */ | ||
488 | int | ||
489 | GNUNET_PSYCSTORE_operation_cancel (struct GNUNET_PSYCSTORE_OperationHandle *op) | ||
490 | { | ||
491 | struct GNUNET_PSYCSTORE_Handle *h = op->h; | ||
492 | int ret = GNUNET_NO; | ||
493 | |||
494 | if (NULL != op->env) | ||
495 | { | ||
496 | GNUNET_MQ_send_cancel (op->env); | ||
497 | ret = GNUNET_YES; | ||
498 | } | ||
499 | |||
500 | GNUNET_OP_remove (h->op, op->op_id); | ||
501 | GNUNET_free (op); | ||
502 | |||
503 | return ret; | ||
504 | } | ||
505 | |||
506 | |||
507 | /** | ||
508 | * Store join/leave events for a PSYC channel in order to be able to answer | ||
509 | * membership test queries later. | ||
510 | * | ||
511 | * @param h | ||
512 | * Handle for the PSYCstore. | ||
513 | * @param channel_key | ||
514 | * The channel where the event happened. | ||
515 | * @param slave_key | ||
516 | * Public key of joining/leaving slave. | ||
517 | * @param did_join | ||
518 | * #GNUNET_YES on join, #GNUNET_NO on part. | ||
519 | * @param announced_at | ||
520 | * ID of the message that announced the membership change. | ||
521 | * @param effective_since | ||
522 | * Message ID this membership change is in effect since. | ||
523 | * For joins it is <= announced_at, for parts it is always 0. | ||
524 | * @param group_generation | ||
525 | * In case of a part, the last group generation the slave has access to. | ||
526 | * It has relevance when a larger message have fragments with different | ||
527 | * group generations. | ||
528 | * @param result_cb | ||
529 | * Callback to call with the result of the storage operation. | ||
530 | * @param cls | ||
531 | * Closure for the callback. | ||
532 | * | ||
533 | * @return Operation handle that can be used to cancel the operation. | ||
534 | */ | ||
535 | struct GNUNET_PSYCSTORE_OperationHandle * | ||
536 | GNUNET_PSYCSTORE_membership_store (struct GNUNET_PSYCSTORE_Handle *h, | ||
537 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
538 | const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, | ||
539 | int did_join, | ||
540 | uint64_t announced_at, | ||
541 | uint64_t effective_since, | ||
542 | uint64_t group_generation, | ||
543 | GNUNET_PSYCSTORE_ResultCallback result_cb, | ||
544 | void *cls) | ||
545 | { | ||
546 | GNUNET_assert (NULL != h); | ||
547 | GNUNET_assert (NULL != channel_key); | ||
548 | GNUNET_assert (NULL != slave_key); | ||
549 | GNUNET_assert (GNUNET_YES == did_join || GNUNET_NO == did_join); | ||
550 | GNUNET_assert (did_join | ||
551 | ? effective_since <= announced_at | ||
552 | : effective_since == 0); | ||
553 | |||
554 | struct MembershipStoreRequest *req; | ||
555 | struct GNUNET_MQ_Envelope * | ||
556 | env = GNUNET_MQ_msg (req, GNUNET_MESSAGE_TYPE_PSYCSTORE_MEMBERSHIP_STORE); | ||
557 | req->channel_key = *channel_key; | ||
558 | req->slave_key = *slave_key; | ||
559 | req->did_join = did_join; | ||
560 | req->announced_at = GNUNET_htonll (announced_at); | ||
561 | req->effective_since = GNUNET_htonll (effective_since); | ||
562 | req->group_generation = GNUNET_htonll (group_generation); | ||
563 | |||
564 | return | ||
565 | op_send (h, op_create (h, h->op, result_cb, cls), | ||
566 | env, &req->op_id); | ||
567 | } | ||
568 | |||
569 | |||
570 | /** | ||
571 | * Test if a member was admitted to the channel at the given message ID. | ||
572 | * | ||
573 | * This is useful when relaying and replaying messages to check if a particular | ||
574 | * slave has access to the message fragment with a given group generation. It | ||
575 | * is also used when handling join requests to determine whether the slave is | ||
576 | * currently admitted to the channel. | ||
577 | * | ||
578 | * @param h | ||
579 | * Handle for the PSYCstore. | ||
580 | * @param channel_key | ||
581 | * The channel we are interested in. | ||
582 | * @param slave_key | ||
583 | * Public key of slave whose membership to check. | ||
584 | * @param message_id | ||
585 | * Message ID for which to do the membership test. | ||
586 | * @param group_generation | ||
587 | * Group generation of the fragment of the message to test. | ||
588 | * It has relevance if the message consists of multiple fragments with | ||
589 | * different group generations. | ||
590 | * @param result_cb | ||
591 | * Callback to call with the test result. | ||
592 | * @param cls | ||
593 | * Closure for the callback. | ||
594 | * | ||
595 | * @return Operation handle that can be used to cancel the operation. | ||
596 | */ | ||
597 | struct GNUNET_PSYCSTORE_OperationHandle * | ||
598 | GNUNET_PSYCSTORE_membership_test (struct GNUNET_PSYCSTORE_Handle *h, | ||
599 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
600 | const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, | ||
601 | uint64_t message_id, | ||
602 | uint64_t group_generation, | ||
603 | GNUNET_PSYCSTORE_ResultCallback result_cb, | ||
604 | void *cls) | ||
605 | { | ||
606 | struct MembershipTestRequest *req; | ||
607 | struct GNUNET_MQ_Envelope * | ||
608 | env = GNUNET_MQ_msg (req, GNUNET_MESSAGE_TYPE_PSYCSTORE_MEMBERSHIP_TEST); | ||
609 | req->channel_key = *channel_key; | ||
610 | req->slave_key = *slave_key; | ||
611 | req->message_id = GNUNET_htonll (message_id); | ||
612 | req->group_generation = GNUNET_htonll (group_generation); | ||
613 | |||
614 | return | ||
615 | op_send (h, op_create (h, h->op, result_cb, cls), | ||
616 | env, &req->op_id); | ||
617 | } | ||
618 | |||
619 | |||
620 | /** | ||
621 | * Store a message fragment sent to a channel. | ||
622 | * | ||
623 | * @param h Handle for the PSYCstore. | ||
624 | * @param channel_key The channel the message belongs to. | ||
625 | * @param message Message to store. | ||
626 | * @param psycstore_flags Flags indicating whether the PSYC message contains | ||
627 | * state modifiers. | ||
628 | * @param result_cb Callback to call with the result of the operation. | ||
629 | * @param cls Closure for the callback. | ||
630 | * | ||
631 | * @return Handle that can be used to cancel the operation. | ||
632 | */ | ||
633 | struct GNUNET_PSYCSTORE_OperationHandle * | ||
634 | GNUNET_PSYCSTORE_fragment_store (struct GNUNET_PSYCSTORE_Handle *h, | ||
635 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
636 | const struct GNUNET_MULTICAST_MessageHeader *msg, | ||
637 | enum GNUNET_PSYCSTORE_MessageFlags psycstore_flags, | ||
638 | GNUNET_PSYCSTORE_ResultCallback result_cb, | ||
639 | void *cls) | ||
640 | { | ||
641 | uint16_t size = ntohs (msg->header.size); | ||
642 | struct FragmentStoreRequest *req; | ||
643 | struct GNUNET_MQ_Envelope * | ||
644 | env = GNUNET_MQ_msg_extra (req, size, | ||
645 | GNUNET_MESSAGE_TYPE_PSYCSTORE_FRAGMENT_STORE); | ||
646 | req->channel_key = *channel_key; | ||
647 | req->psycstore_flags = htonl (psycstore_flags); | ||
648 | GNUNET_memcpy (&req[1], msg, size); | ||
649 | |||
650 | return | ||
651 | op_send (h, op_create (h, h->op, result_cb, cls), | ||
652 | env, &req->op_id); | ||
653 | } | ||
654 | |||
655 | |||
656 | /** | ||
657 | * Retrieve message fragments by fragment ID range. | ||
658 | * | ||
659 | * @param h | ||
660 | * Handle for the PSYCstore. | ||
661 | * @param channel_key | ||
662 | * The channel we are interested in. | ||
663 | * @param slave_key | ||
664 | * The slave requesting the fragment. If not NULL, a membership test is | ||
665 | * performed first and the fragment is only returned if the slave has | ||
666 | * access to it. | ||
667 | * @param first_fragment_id | ||
668 | * First fragment ID to retrieve. | ||
669 | * Use 0 to get the latest message fragment. | ||
670 | * @param last_fragment_id | ||
671 | * Last consecutive fragment ID to retrieve. | ||
672 | * Use 0 to get the latest message fragment. | ||
673 | * @param fragment_limit | ||
674 | * Maximum number of fragments to retrieve. | ||
675 | * @param fragment_cb | ||
676 | * Callback to call with the retrieved fragments. | ||
677 | * @param result_cb | ||
678 | * Callback to call with the result of the operation. | ||
679 | * @param cls | ||
680 | * Closure for the callbacks. | ||
681 | * | ||
682 | * @return Handle that can be used to cancel the operation. | ||
683 | */ | ||
684 | struct GNUNET_PSYCSTORE_OperationHandle * | ||
685 | GNUNET_PSYCSTORE_fragment_get (struct GNUNET_PSYCSTORE_Handle *h, | ||
686 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
687 | const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, | ||
688 | uint64_t first_fragment_id, | ||
689 | uint64_t last_fragment_id, | ||
690 | GNUNET_PSYCSTORE_FragmentCallback fragment_cb, | ||
691 | GNUNET_PSYCSTORE_ResultCallback result_cb, | ||
692 | void *cls) | ||
693 | { | ||
694 | struct FragmentGetRequest *req; | ||
695 | struct GNUNET_MQ_Envelope * | ||
696 | env = GNUNET_MQ_msg (req, GNUNET_MESSAGE_TYPE_PSYCSTORE_FRAGMENT_GET); | ||
697 | req->channel_key = *channel_key; | ||
698 | req->first_fragment_id = GNUNET_htonll (first_fragment_id); | ||
699 | req->last_fragment_id = GNUNET_htonll (last_fragment_id); | ||
700 | if (NULL != slave_key) | ||
701 | { | ||
702 | req->slave_key = *slave_key; | ||
703 | req->do_membership_test = GNUNET_YES; | ||
704 | } | ||
705 | |||
706 | struct GNUNET_PSYCSTORE_OperationHandle * | ||
707 | op = op_create (h, h->op, result_cb, cls); | ||
708 | op->fragment_cb = fragment_cb; | ||
709 | op->cls = cls; | ||
710 | return op_send (h, op, env, &req->op_id); | ||
711 | } | ||
712 | |||
713 | |||
714 | /** | ||
715 | * Retrieve latest message fragments. | ||
716 | * | ||
717 | * @param h | ||
718 | * Handle for the PSYCstore. | ||
719 | * @param channel_key | ||
720 | * The channel we are interested in. | ||
721 | * @param slave_key | ||
722 | * The slave requesting the fragment. If not NULL, a membership test is | ||
723 | * performed first and the fragment is only returned if the slave has | ||
724 | * access to it. | ||
725 | * @param first_fragment_id | ||
726 | * First fragment ID to retrieve. | ||
727 | * Use 0 to get the latest message fragment. | ||
728 | * @param last_fragment_id | ||
729 | * Last consecutive fragment ID to retrieve. | ||
730 | * Use 0 to get the latest message fragment. | ||
731 | * @param fragment_limit | ||
732 | * Maximum number of fragments to retrieve. | ||
733 | * @param fragment_cb | ||
734 | * Callback to call with the retrieved fragments. | ||
735 | * @param result_cb | ||
736 | * Callback to call with the result of the operation. | ||
737 | * @param cls | ||
738 | * Closure for the callbacks. | ||
739 | * | ||
740 | * @return Handle that can be used to cancel the operation. | ||
741 | */ | ||
742 | struct GNUNET_PSYCSTORE_OperationHandle * | ||
743 | GNUNET_PSYCSTORE_fragment_get_latest (struct GNUNET_PSYCSTORE_Handle *h, | ||
744 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
745 | const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, | ||
746 | uint64_t fragment_limit, | ||
747 | GNUNET_PSYCSTORE_FragmentCallback fragment_cb, | ||
748 | GNUNET_PSYCSTORE_ResultCallback result_cb, | ||
749 | void *cls) | ||
750 | { | ||
751 | struct FragmentGetRequest *req; | ||
752 | struct GNUNET_MQ_Envelope * | ||
753 | env = GNUNET_MQ_msg (req, GNUNET_MESSAGE_TYPE_PSYCSTORE_FRAGMENT_GET); | ||
754 | req->channel_key = *channel_key; | ||
755 | req->fragment_limit = GNUNET_ntohll (fragment_limit); | ||
756 | if (NULL != slave_key) | ||
757 | { | ||
758 | req->slave_key = *slave_key; | ||
759 | req->do_membership_test = GNUNET_YES; | ||
760 | } | ||
761 | |||
762 | struct GNUNET_PSYCSTORE_OperationHandle * | ||
763 | op = op_create (h, h->op, result_cb, cls); | ||
764 | op->fragment_cb = fragment_cb; | ||
765 | op->cls = cls; | ||
766 | return op_send (h, op, env, &req->op_id); | ||
767 | } | ||
768 | |||
769 | |||
770 | /** | ||
771 | * Retrieve all fragments of messages in a message ID range. | ||
772 | * | ||
773 | * @param h | ||
774 | * Handle for the PSYCstore. | ||
775 | * @param channel_key | ||
776 | * The channel we are interested in. | ||
777 | * @param slave_key | ||
778 | * The slave requesting the message. | ||
779 | * If not NULL, a membership test is performed first | ||
780 | * and the message is only returned if the slave has access to it. | ||
781 | * @param first_message_id | ||
782 | * First message ID to retrieve. | ||
783 | * @param last_message_id | ||
784 | * Last consecutive message ID to retrieve. | ||
785 | * @param fragment_limit | ||
786 | * Maximum number of fragments to retrieve. | ||
787 | * @param method_prefix | ||
788 | * Retrieve only messages with a matching method prefix. | ||
789 | * @todo Implement method_prefix query. | ||
790 | * @param fragment_cb | ||
791 | * Callback to call with the retrieved fragments. | ||
792 | * @param result_cb | ||
793 | * Callback to call with the result of the operation. | ||
794 | * @param cls | ||
795 | * Closure for the callbacks. | ||
796 | * | ||
797 | * @return Handle that can be used to cancel the operation. | ||
798 | */ | ||
799 | struct GNUNET_PSYCSTORE_OperationHandle * | ||
800 | GNUNET_PSYCSTORE_message_get (struct GNUNET_PSYCSTORE_Handle *h, | ||
801 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
802 | const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, | ||
803 | uint64_t first_message_id, | ||
804 | uint64_t last_message_id, | ||
805 | uint64_t fragment_limit, | ||
806 | const char *method_prefix, | ||
807 | GNUNET_PSYCSTORE_FragmentCallback fragment_cb, | ||
808 | GNUNET_PSYCSTORE_ResultCallback result_cb, | ||
809 | void *cls) | ||
810 | { | ||
811 | struct MessageGetRequest *req; | ||
812 | if (NULL == method_prefix) | ||
813 | method_prefix = ""; | ||
814 | uint16_t method_size = strnlen (method_prefix, | ||
815 | GNUNET_MAX_MESSAGE_SIZE | ||
816 | - sizeof (*req)) + 1; | ||
817 | |||
818 | struct GNUNET_MQ_Envelope * | ||
819 | env = GNUNET_MQ_msg_extra (req, method_size, | ||
820 | GNUNET_MESSAGE_TYPE_PSYCSTORE_MESSAGE_GET); | ||
821 | req->channel_key = *channel_key; | ||
822 | req->first_message_id = GNUNET_htonll (first_message_id); | ||
823 | req->last_message_id = GNUNET_htonll (last_message_id); | ||
824 | req->fragment_limit = GNUNET_htonll (fragment_limit); | ||
825 | if (NULL != slave_key) | ||
826 | { | ||
827 | req->slave_key = *slave_key; | ||
828 | req->do_membership_test = GNUNET_YES; | ||
829 | } | ||
830 | GNUNET_memcpy (&req[1], method_prefix, method_size); | ||
831 | ((char *) &req[1])[method_size - 1] = '\0'; | ||
832 | |||
833 | struct GNUNET_PSYCSTORE_OperationHandle * | ||
834 | op = op_create (h, h->op, result_cb, cls); | ||
835 | op->fragment_cb = fragment_cb; | ||
836 | op->cls = cls; | ||
837 | return op_send (h, op, env, &req->op_id); | ||
838 | } | ||
839 | |||
840 | |||
841 | /** | ||
842 | * Retrieve all fragments of the latest messages. | ||
843 | * | ||
844 | * @param h | ||
845 | * Handle for the PSYCstore. | ||
846 | * @param channel_key | ||
847 | * The channel we are interested in. | ||
848 | * @param slave_key | ||
849 | * The slave requesting the message. | ||
850 | * If not NULL, a membership test is performed first | ||
851 | * and the message is only returned if the slave has access to it. | ||
852 | * @param message_limit | ||
853 | * Maximum number of messages to retrieve. | ||
854 | * @param method_prefix | ||
855 | * Retrieve only messages with a matching method prefix. | ||
856 | * @todo Implement method_prefix query. | ||
857 | * @param fragment_cb | ||
858 | * Callback to call with the retrieved fragments. | ||
859 | * @param result_cb | ||
860 | * Callback to call with the result of the operation. | ||
861 | * @param cls | ||
862 | * Closure for the callbacks. | ||
863 | * | ||
864 | * @return Handle that can be used to cancel the operation. | ||
865 | */ | ||
866 | struct GNUNET_PSYCSTORE_OperationHandle * | ||
867 | GNUNET_PSYCSTORE_message_get_latest (struct GNUNET_PSYCSTORE_Handle *h, | ||
868 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
869 | const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, | ||
870 | uint64_t message_limit, | ||
871 | const char *method_prefix, | ||
872 | GNUNET_PSYCSTORE_FragmentCallback fragment_cb, | ||
873 | GNUNET_PSYCSTORE_ResultCallback result_cb, | ||
874 | void *cls) | ||
875 | { | ||
876 | struct MessageGetRequest *req; | ||
877 | |||
878 | if (NULL == method_prefix) | ||
879 | method_prefix = ""; | ||
880 | uint16_t method_size = strnlen (method_prefix, | ||
881 | GNUNET_MAX_MESSAGE_SIZE | ||
882 | - sizeof (*req)) + 1; | ||
883 | GNUNET_assert ('\0' == method_prefix[method_size - 1]); | ||
884 | |||
885 | struct GNUNET_MQ_Envelope * | ||
886 | env = GNUNET_MQ_msg_extra (req, method_size, | ||
887 | GNUNET_MESSAGE_TYPE_PSYCSTORE_MESSAGE_GET); | ||
888 | req->channel_key = *channel_key; | ||
889 | req->message_limit = GNUNET_ntohll (message_limit); | ||
890 | if (NULL != slave_key) | ||
891 | { | ||
892 | req->slave_key = *slave_key; | ||
893 | req->do_membership_test = GNUNET_YES; | ||
894 | } | ||
895 | GNUNET_memcpy (&req[1], method_prefix, method_size); | ||
896 | |||
897 | struct GNUNET_PSYCSTORE_OperationHandle * | ||
898 | op = op_create (h, h->op, result_cb, cls); | ||
899 | op->fragment_cb = fragment_cb; | ||
900 | op->cls = cls; | ||
901 | return op_send (h, op, env, &req->op_id); | ||
902 | } | ||
903 | |||
904 | |||
905 | /** | ||
906 | * Retrieve a fragment of message specified by its message ID and fragment | ||
907 | * offset. | ||
908 | * | ||
909 | * @param h | ||
910 | * Handle for the PSYCstore. | ||
911 | * @param channel_key | ||
912 | * The channel we are interested in. | ||
913 | * @param slave_key | ||
914 | * The slave requesting the message fragment. If not NULL, a membership | ||
915 | * test is performed first and the message fragment is only returned | ||
916 | * if the slave has access to it. | ||
917 | * @param message_id | ||
918 | * Message ID to retrieve. Use 0 to get the latest message. | ||
919 | * @param fragment_offset | ||
920 | * Offset of the fragment to retrieve. | ||
921 | * @param fragment_cb | ||
922 | * Callback to call with the retrieved fragments. | ||
923 | * @param result_cb | ||
924 | * Callback to call with the result of the operation. | ||
925 | * @param cls | ||
926 | * Closure for the callbacks. | ||
927 | * | ||
928 | * @return Handle that can be used to cancel the operation. | ||
929 | */ | ||
930 | struct GNUNET_PSYCSTORE_OperationHandle * | ||
931 | GNUNET_PSYCSTORE_message_get_fragment (struct GNUNET_PSYCSTORE_Handle *h, | ||
932 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
933 | const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, | ||
934 | uint64_t message_id, | ||
935 | uint64_t fragment_offset, | ||
936 | GNUNET_PSYCSTORE_FragmentCallback fragment_cb, | ||
937 | GNUNET_PSYCSTORE_ResultCallback result_cb, | ||
938 | void *cls) | ||
939 | { | ||
940 | struct MessageGetFragmentRequest *req; | ||
941 | struct GNUNET_MQ_Envelope * | ||
942 | env = GNUNET_MQ_msg (req, GNUNET_MESSAGE_TYPE_PSYCSTORE_MESSAGE_GET_FRAGMENT); | ||
943 | |||
944 | req->channel_key = *channel_key; | ||
945 | req->message_id = GNUNET_htonll (message_id); | ||
946 | req->fragment_offset = GNUNET_htonll (fragment_offset); | ||
947 | if (NULL != slave_key) | ||
948 | { | ||
949 | req->slave_key = *slave_key; | ||
950 | req->do_membership_test = GNUNET_YES; | ||
951 | } | ||
952 | |||
953 | struct GNUNET_PSYCSTORE_OperationHandle * | ||
954 | op = op_create (h, h->op, result_cb, cls); | ||
955 | op->fragment_cb = fragment_cb; | ||
956 | op->cls = cls; | ||
957 | return op_send (h, op, env, &req->op_id); | ||
958 | } | ||
959 | |||
960 | |||
961 | /** | ||
962 | * Retrieve latest values of counters for a channel master. | ||
963 | * | ||
964 | * The current value of counters are needed when a channel master is restarted, | ||
965 | * so that it can continue incrementing the counters from their last value. | ||
966 | * | ||
967 | * @param h | ||
968 | * Handle for the PSYCstore. | ||
969 | * @param channel_key | ||
970 | * Public key that identifies the channel. | ||
971 | * @param ccb | ||
972 | * Callback to call with the result. | ||
973 | * @param ccb_cls | ||
974 | * Closure for the @a ccb callback. | ||
975 | * | ||
976 | * @return Handle that can be used to cancel the operation. | ||
977 | */ | ||
978 | struct GNUNET_PSYCSTORE_OperationHandle * | ||
979 | GNUNET_PSYCSTORE_counters_get (struct GNUNET_PSYCSTORE_Handle *h, | ||
980 | struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
981 | GNUNET_PSYCSTORE_CountersCallback counters_cb, | ||
982 | void *cls) | ||
983 | { | ||
984 | struct OperationRequest *req; | ||
985 | struct GNUNET_MQ_Envelope * | ||
986 | env = GNUNET_MQ_msg (req, GNUNET_MESSAGE_TYPE_PSYCSTORE_COUNTERS_GET); | ||
987 | req->channel_key = *channel_key; | ||
988 | |||
989 | struct GNUNET_PSYCSTORE_OperationHandle * | ||
990 | op = op_create (h, h->op, NULL, NULL); | ||
991 | op->counters_cb = counters_cb; | ||
992 | op->cls = cls; | ||
993 | return op_send (h, op, env, &req->op_id); | ||
994 | } | ||
995 | |||
996 | |||
997 | /** | ||
998 | * Apply modifiers of a message to the current channel state. | ||
999 | * | ||
1000 | * An error is returned if there are missing messages containing state | ||
1001 | * operations before the current one. | ||
1002 | * | ||
1003 | * @param h | ||
1004 | * Handle for the PSYCstore. | ||
1005 | * @param channel_key | ||
1006 | * The channel we are interested in. | ||
1007 | * @param message_id | ||
1008 | * ID of the message that contains the @a modifiers. | ||
1009 | * @param state_delta | ||
1010 | * Value of the _state_delta PSYC header variable of the message. | ||
1011 | * @param result_cb | ||
1012 | * Callback to call with the result of the operation. | ||
1013 | * @param cls | ||
1014 | * Closure for @a result_cb. | ||
1015 | * | ||
1016 | * @return Handle that can be used to cancel the operation. | ||
1017 | */ | ||
1018 | struct GNUNET_PSYCSTORE_OperationHandle * | ||
1019 | GNUNET_PSYCSTORE_state_modify (struct GNUNET_PSYCSTORE_Handle *h, | ||
1020 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1021 | uint64_t message_id, | ||
1022 | uint64_t state_delta, | ||
1023 | GNUNET_PSYCSTORE_ResultCallback result_cb, | ||
1024 | void *cls) | ||
1025 | { | ||
1026 | struct StateModifyRequest *req; | ||
1027 | struct GNUNET_MQ_Envelope * | ||
1028 | env = GNUNET_MQ_msg (req, GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_MODIFY); | ||
1029 | req->channel_key = *channel_key; | ||
1030 | req->message_id = GNUNET_htonll (message_id); | ||
1031 | req->state_delta = GNUNET_htonll (state_delta); | ||
1032 | |||
1033 | return op_send (h, op_create (h, h->op, result_cb, cls), | ||
1034 | env, &req->op_id); | ||
1035 | } | ||
1036 | |||
1037 | |||
1038 | struct StateSyncClosure | ||
1039 | { | ||
1040 | GNUNET_PSYCSTORE_ResultCallback result_cb; | ||
1041 | void *cls; | ||
1042 | uint8_t last; | ||
1043 | }; | ||
1044 | |||
1045 | |||
1046 | static void | ||
1047 | state_sync_result (void *cls, int64_t result, | ||
1048 | const char *err_msg, uint16_t err_msg_size) | ||
1049 | { | ||
1050 | struct StateSyncClosure *ssc = cls; | ||
1051 | if (GNUNET_OK != result || ssc->last) | ||
1052 | ssc->result_cb (ssc->cls, result, err_msg, err_msg_size); | ||
1053 | GNUNET_free (ssc); | ||
1054 | } | ||
1055 | |||
1056 | |||
1057 | /** | ||
1058 | * Store synchronized state. | ||
1059 | * | ||
1060 | * @param h | ||
1061 | * Handle for the PSYCstore. | ||
1062 | * @param channel_key | ||
1063 | * The channel we are interested in. | ||
1064 | * @param max_state_message_id | ||
1065 | * ID of the last stateful message before @a state_hash_message_id. | ||
1066 | * @param state_hash_message_id | ||
1067 | * ID of the message that contains the state_hash PSYC header variable. | ||
1068 | * @param modifier_count | ||
1069 | * Number of elements in the @a modifiers array. | ||
1070 | * @param modifiers | ||
1071 | * Full state to store. | ||
1072 | * @param result_cb | ||
1073 | * Callback to call with the result of the operation. | ||
1074 | * @param cls | ||
1075 | * Closure for the callback. | ||
1076 | * | ||
1077 | * @return Handle that can be used to cancel the operation. | ||
1078 | */ | ||
1079 | struct GNUNET_PSYCSTORE_OperationHandle * | ||
1080 | GNUNET_PSYCSTORE_state_sync (struct GNUNET_PSYCSTORE_Handle *h, | ||
1081 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1082 | uint64_t max_state_message_id, | ||
1083 | uint64_t state_hash_message_id, | ||
1084 | size_t modifier_count, | ||
1085 | const struct GNUNET_PSYC_Modifier *modifiers, | ||
1086 | GNUNET_PSYCSTORE_ResultCallback result_cb, | ||
1087 | void *cls) | ||
1088 | { | ||
1089 | struct GNUNET_PSYCSTORE_OperationHandle *op = NULL; | ||
1090 | size_t i; | ||
1091 | |||
1092 | for (i = 0; i < modifier_count; i++) { | ||
1093 | struct StateSyncRequest *req; | ||
1094 | uint16_t name_size = strlen (modifiers[i].name) + 1; | ||
1095 | |||
1096 | struct GNUNET_MQ_Envelope * | ||
1097 | env = GNUNET_MQ_msg_extra (req, | ||
1098 | sizeof (*req) + name_size + modifiers[i].value_size, | ||
1099 | GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_SYNC); | ||
1100 | |||
1101 | req->header.type = htons (GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_SYNC); | ||
1102 | req->header.size = htons (sizeof (*req) + name_size | ||
1103 | + modifiers[i].value_size); | ||
1104 | req->channel_key = *channel_key; | ||
1105 | req->max_state_message_id = GNUNET_htonll (max_state_message_id); | ||
1106 | req->state_hash_message_id = GNUNET_htonll (state_hash_message_id); | ||
1107 | req->name_size = htons (name_size); | ||
1108 | req->flags | ||
1109 | = (0 == i) | ||
1110 | ? STATE_OP_FIRST | ||
1111 | : (modifier_count - 1 == i) | ||
1112 | ? STATE_OP_LAST | ||
1113 | : 0; | ||
1114 | |||
1115 | GNUNET_memcpy (&req[1], modifiers[i].name, name_size); | ||
1116 | GNUNET_memcpy ((char *) &req[1] + name_size, modifiers[i].value, modifiers[i].value_size); | ||
1117 | |||
1118 | struct StateSyncClosure *ssc = GNUNET_malloc (sizeof (*ssc)); | ||
1119 | ssc->last = (req->flags & STATE_OP_LAST); | ||
1120 | ssc->result_cb = result_cb; | ||
1121 | ssc->cls = cls; | ||
1122 | |||
1123 | op_send (h, op_create (h, h->op, state_sync_result, ssc), | ||
1124 | env, &req->op_id); | ||
1125 | } | ||
1126 | // FIXME: only one operation is returned, | ||
1127 | // add pointers to other operations and make all cancellable. | ||
1128 | return op; | ||
1129 | } | ||
1130 | |||
1131 | |||
1132 | /** | ||
1133 | * Reset the state of a channel. | ||
1134 | * | ||
1135 | * Delete all state variables stored for the given channel. | ||
1136 | * | ||
1137 | * @param h | ||
1138 | * Handle for the PSYCstore. | ||
1139 | * @param channel_key | ||
1140 | * The channel we are interested in. | ||
1141 | * @param result_cb | ||
1142 | * Callback to call with the result of the operation. | ||
1143 | * @param cls | ||
1144 | * Closure for the callback. | ||
1145 | * | ||
1146 | * @return Handle that can be used to cancel the operation. | ||
1147 | */ | ||
1148 | struct GNUNET_PSYCSTORE_OperationHandle * | ||
1149 | GNUNET_PSYCSTORE_state_reset (struct GNUNET_PSYCSTORE_Handle *h, | ||
1150 | const struct GNUNET_CRYPTO_EddsaPublicKey | ||
1151 | *channel_key, | ||
1152 | GNUNET_PSYCSTORE_ResultCallback result_cb, | ||
1153 | void *cls) | ||
1154 | { | ||
1155 | struct OperationRequest *req; | ||
1156 | struct GNUNET_MQ_Envelope * | ||
1157 | env = GNUNET_MQ_msg (req, GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_RESET); | ||
1158 | req->channel_key = *channel_key; | ||
1159 | |||
1160 | return | ||
1161 | op_send (h, op_create (h, h->op, result_cb, cls), | ||
1162 | env, &req->op_id); | ||
1163 | } | ||
1164 | |||
1165 | |||
1166 | /** | ||
1167 | * Update signed values of state variables in the state store. | ||
1168 | * | ||
1169 | * @param h | ||
1170 | * Handle for the PSYCstore. | ||
1171 | * @param channel_key | ||
1172 | * The channel we are interested in. | ||
1173 | * @param message_id | ||
1174 | * Message ID that contained the state @a hash. | ||
1175 | * @param hash | ||
1176 | * Hash of the serialized full state. | ||
1177 | * @param result_cb | ||
1178 | * Callback to call with the result of the operation. | ||
1179 | * @param cls | ||
1180 | * Closure for the callback. | ||
1181 | */ | ||
1182 | struct GNUNET_PSYCSTORE_OperationHandle * | ||
1183 | GNUNET_PSYCSTORE_state_hash_update (struct GNUNET_PSYCSTORE_Handle *h, | ||
1184 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1185 | uint64_t message_id, | ||
1186 | const struct GNUNET_HashCode *hash, | ||
1187 | GNUNET_PSYCSTORE_ResultCallback result_cb, | ||
1188 | void *cls) | ||
1189 | { | ||
1190 | struct StateHashUpdateRequest *req; | ||
1191 | struct GNUNET_MQ_Envelope * | ||
1192 | env = GNUNET_MQ_msg (req, GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_HASH_UPDATE); | ||
1193 | req->channel_key = *channel_key; | ||
1194 | req->hash = *hash; | ||
1195 | |||
1196 | return | ||
1197 | op_send (h, op_create (h, h->op, result_cb, cls), | ||
1198 | env, &req->op_id); | ||
1199 | } | ||
1200 | |||
1201 | |||
1202 | /** | ||
1203 | * Retrieve the best matching state variable. | ||
1204 | * | ||
1205 | * @param h | ||
1206 | * Handle for the PSYCstore. | ||
1207 | * @param channel_key | ||
1208 | * The channel we are interested in. | ||
1209 | * @param name | ||
1210 | * Name of variable to match, the returned variable might be less specific. | ||
1211 | * @param state_cb | ||
1212 | * Callback to return the matching state variable. | ||
1213 | * @param result_cb | ||
1214 | * Callback to call with the result of the operation. | ||
1215 | * @param cls | ||
1216 | * Closure for the callbacks. | ||
1217 | * | ||
1218 | * @return Handle that can be used to cancel the operation. | ||
1219 | */ | ||
1220 | struct GNUNET_PSYCSTORE_OperationHandle * | ||
1221 | GNUNET_PSYCSTORE_state_get (struct GNUNET_PSYCSTORE_Handle *h, | ||
1222 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1223 | const char *name, | ||
1224 | GNUNET_PSYCSTORE_StateCallback state_cb, | ||
1225 | GNUNET_PSYCSTORE_ResultCallback result_cb, | ||
1226 | void *cls) | ||
1227 | { | ||
1228 | size_t name_size = strlen (name) + 1; | ||
1229 | struct OperationRequest *req; | ||
1230 | struct GNUNET_MQ_Envelope * | ||
1231 | env = GNUNET_MQ_msg_extra (req, name_size, | ||
1232 | GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_GET); | ||
1233 | req->channel_key = *channel_key; | ||
1234 | GNUNET_memcpy (&req[1], name, name_size); | ||
1235 | |||
1236 | struct GNUNET_PSYCSTORE_OperationHandle * | ||
1237 | op = op_create (h, h->op, result_cb, cls); | ||
1238 | op->state_cb = state_cb; | ||
1239 | op->cls = cls; | ||
1240 | return op_send (h, op, env, &req->op_id); | ||
1241 | } | ||
1242 | |||
1243 | |||
1244 | /** | ||
1245 | * Retrieve all state variables for a channel with the given prefix. | ||
1246 | * | ||
1247 | * @param h | ||
1248 | * Handle for the PSYCstore. | ||
1249 | * @param channel_key | ||
1250 | * The channel we are interested in. | ||
1251 | * @param name_prefix | ||
1252 | * Prefix of state variable names to match. | ||
1253 | * @param state_cb | ||
1254 | * Callback to return matching state variables. | ||
1255 | * @param result_cb | ||
1256 | * Callback to call with the result of the operation. | ||
1257 | * @param cls | ||
1258 | * Closure for the callbacks. | ||
1259 | * | ||
1260 | * @return Handle that can be used to cancel the operation. | ||
1261 | */ | ||
1262 | struct GNUNET_PSYCSTORE_OperationHandle * | ||
1263 | GNUNET_PSYCSTORE_state_get_prefix (struct GNUNET_PSYCSTORE_Handle *h, | ||
1264 | const struct GNUNET_CRYPTO_EddsaPublicKey *channel_key, | ||
1265 | const char *name_prefix, | ||
1266 | GNUNET_PSYCSTORE_StateCallback state_cb, | ||
1267 | GNUNET_PSYCSTORE_ResultCallback result_cb, | ||
1268 | void *cls) | ||
1269 | { | ||
1270 | size_t name_size = strlen (name_prefix) + 1; | ||
1271 | struct OperationRequest *req; | ||
1272 | struct GNUNET_MQ_Envelope * | ||
1273 | env = GNUNET_MQ_msg_extra (req, name_size, | ||
1274 | GNUNET_MESSAGE_TYPE_PSYCSTORE_STATE_GET_PREFIX); | ||
1275 | req->channel_key = *channel_key; | ||
1276 | GNUNET_memcpy (&req[1], name_prefix, name_size); | ||
1277 | |||
1278 | struct GNUNET_PSYCSTORE_OperationHandle * | ||
1279 | op = op_create (h, h->op, result_cb, cls); | ||
1280 | op->state_cb = state_cb; | ||
1281 | op->cls = cls; | ||
1282 | return op_send (h, op, env, &req->op_id); | ||
1283 | } | ||
1284 | |||
1285 | /* end of psycstore_api.c */ | ||
diff --git a/src/psycstore/test_plugin_psycstore.c b/src/psycstore/test_plugin_psycstore.c deleted file mode 100644 index ff4eac820..000000000 --- a/src/psycstore/test_plugin_psycstore.c +++ /dev/null | |||
@@ -1,532 +0,0 @@ | |||
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 | * @author Gabor X Toth | ||
23 | * @author Christian Grothoff | ||
24 | * | ||
25 | * @file | ||
26 | * Test for the PSYCstore plugins. | ||
27 | */ | ||
28 | |||
29 | #include <inttypes.h> | ||
30 | |||
31 | #include "platform.h" | ||
32 | #include "gnunet_util_lib.h" | ||
33 | #include "gnunet_testing_lib.h" | ||
34 | #include "gnunet_psycstore_plugin.h" | ||
35 | #include "gnunet_psycstore_service.h" | ||
36 | #include "gnunet_multicast_service.h" | ||
37 | |||
38 | #define DEBUG_PSYCSTORE GNUNET_EXTRA_LOGGING | ||
39 | #if DEBUG_PSYCSTORE | ||
40 | # define LOG_LEVEL "DEBUG" | ||
41 | #else | ||
42 | # define LOG_LEVEL "WARNING" | ||
43 | #endif | ||
44 | |||
45 | #define C2ARG(str) str, (sizeof (str) - 1) | ||
46 | |||
47 | #define LOG(kind,...) \ | ||
48 | GNUNET_log_from (kind, "test-plugin-psycstore", __VA_ARGS__) | ||
49 | |||
50 | static int ok; | ||
51 | |||
52 | /** | ||
53 | * Name of plugin under test. | ||
54 | */ | ||
55 | static const char *plugin_name; | ||
56 | |||
57 | static struct GNUNET_CRYPTO_EddsaPrivateKey *channel_key; | ||
58 | static struct GNUNET_CRYPTO_EcdsaPrivateKey *slave_key; | ||
59 | |||
60 | static struct GNUNET_CRYPTO_EddsaPublicKey channel_pub_key; | ||
61 | static struct GNUNET_CRYPTO_EcdsaPublicKey slave_pub_key; | ||
62 | |||
63 | /** | ||
64 | * Function called when the service shuts down. Unloads our psycstore | ||
65 | * plugin. | ||
66 | * | ||
67 | * @param api api to unload | ||
68 | */ | ||
69 | static void | ||
70 | unload_plugin (struct GNUNET_PSYCSTORE_PluginFunctions *api) | ||
71 | { | ||
72 | char *libname; | ||
73 | |||
74 | GNUNET_asprintf (&libname, "libgnunet_plugin_psycstore_%s", plugin_name); | ||
75 | GNUNET_break (NULL == GNUNET_PLUGIN_unload (libname, api)); | ||
76 | GNUNET_free (libname); | ||
77 | } | ||
78 | |||
79 | |||
80 | /** | ||
81 | * Load the psycstore plugin. | ||
82 | * | ||
83 | * @param cfg configuration to pass | ||
84 | * @return NULL on error | ||
85 | */ | ||
86 | static struct GNUNET_PSYCSTORE_PluginFunctions * | ||
87 | load_plugin (const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
88 | { | ||
89 | struct GNUNET_PSYCSTORE_PluginFunctions *ret; | ||
90 | char *libname; | ||
91 | |||
92 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, _ ("Loading `%s' psycstore plugin\n"), | ||
93 | plugin_name); | ||
94 | GNUNET_asprintf (&libname, "libgnunet_plugin_psycstore_%s", plugin_name); | ||
95 | if (NULL == (ret = GNUNET_PLUGIN_load (libname, (void*) cfg))) | ||
96 | { | ||
97 | FPRINTF (stderr, "Failed to load plugin `%s'!\n", plugin_name); | ||
98 | return NULL; | ||
99 | } | ||
100 | GNUNET_free (libname); | ||
101 | return ret; | ||
102 | } | ||
103 | |||
104 | |||
105 | #define MAX_MSG 16 | ||
106 | |||
107 | struct FragmentClosure | ||
108 | { | ||
109 | uint8_t n; | ||
110 | uint64_t flags[MAX_MSG]; | ||
111 | struct GNUNET_MULTICAST_MessageHeader *msg[MAX_MSG]; | ||
112 | }; | ||
113 | |||
114 | static int | ||
115 | fragment_cb (void *cls, struct GNUNET_MULTICAST_MessageHeader *msg2, | ||
116 | enum GNUNET_PSYCSTORE_MessageFlags flags) | ||
117 | { | ||
118 | struct FragmentClosure *fcls = cls; | ||
119 | struct GNUNET_MULTICAST_MessageHeader *msg1; | ||
120 | uint64_t flags1; | ||
121 | int ret; | ||
122 | |||
123 | if (fcls->n >= MAX_MSG) | ||
124 | { | ||
125 | GNUNET_break (0); | ||
126 | return GNUNET_SYSERR; | ||
127 | } | ||
128 | msg1 = fcls->msg[fcls->n]; | ||
129 | flags1 = fcls->flags[fcls->n++]; | ||
130 | if (NULL == msg1) | ||
131 | { | ||
132 | GNUNET_break (0); | ||
133 | return GNUNET_SYSERR; | ||
134 | } | ||
135 | |||
136 | if (flags1 == flags && msg1->header.size == msg2->header.size | ||
137 | && 0 == memcmp (msg1, msg2, ntohs (msg1->header.size))) | ||
138 | { | ||
139 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Fragment %llu matches\n", | ||
140 | GNUNET_ntohll (msg1->fragment_id)); | ||
141 | ret = GNUNET_YES; | ||
142 | } | ||
143 | else | ||
144 | { | ||
145 | LOG (GNUNET_ERROR_TYPE_ERROR, "Fragment %llu differs\n", | ||
146 | GNUNET_ntohll (msg1->fragment_id)); | ||
147 | ret = GNUNET_SYSERR; | ||
148 | } | ||
149 | |||
150 | GNUNET_free (msg2); | ||
151 | return ret; | ||
152 | } | ||
153 | |||
154 | |||
155 | struct StateClosure { | ||
156 | size_t n; | ||
157 | char *name[16]; | ||
158 | void *value[16]; | ||
159 | size_t value_size[16]; | ||
160 | }; | ||
161 | |||
162 | static int | ||
163 | state_cb (void *cls, const char *name, const void *value, uint32_t value_size) | ||
164 | { | ||
165 | struct StateClosure *scls = cls; | ||
166 | const void *val = scls->value[scls->n]; // FIXME: check for n out-of-bounds FIRST! | ||
167 | size_t val_size = scls->value_size[scls->n++]; | ||
168 | |||
169 | /* FIXME: check name */ | ||
170 | |||
171 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
172 | " name = %s, value_size = %u\n", | ||
173 | name, value_size); | ||
174 | |||
175 | return GNUNET_YES; | ||
176 | return value_size == val_size && 0 == memcmp (value, val, val_size) | ||
177 | ? GNUNET_YES | ||
178 | : GNUNET_SYSERR; | ||
179 | } | ||
180 | |||
181 | |||
182 | static void | ||
183 | run (void *cls, char *const *args, const char *cfgfile, | ||
184 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
185 | { | ||
186 | struct GNUNET_PSYCSTORE_PluginFunctions *db; | ||
187 | |||
188 | ok = 1; | ||
189 | db = load_plugin (cfg); | ||
190 | if (NULL == db) | ||
191 | { | ||
192 | FPRINTF (stderr, | ||
193 | "%s", | ||
194 | "Failed to initialize PSYCstore. " | ||
195 | "Database likely not setup, skipping test.\n"); | ||
196 | ok = 77; | ||
197 | return; | ||
198 | } | ||
199 | |||
200 | /* Store & test membership */ | ||
201 | |||
202 | LOG (GNUNET_ERROR_TYPE_INFO, "MEMBERSHIP\n"); | ||
203 | |||
204 | channel_key = GNUNET_CRYPTO_eddsa_key_create (); | ||
205 | slave_key = GNUNET_CRYPTO_ecdsa_key_create (); | ||
206 | |||
207 | GNUNET_CRYPTO_eddsa_key_get_public (channel_key, | ||
208 | &channel_pub_key); | ||
209 | GNUNET_CRYPTO_ecdsa_key_get_public (slave_key, &slave_pub_key); | ||
210 | |||
211 | LOG (GNUNET_ERROR_TYPE_INFO, "membership_store()\n"); | ||
212 | |||
213 | GNUNET_assert (GNUNET_OK == db->membership_store (db->cls, &channel_pub_key, | ||
214 | &slave_pub_key, GNUNET_YES, | ||
215 | 4, 2, 1)); | ||
216 | |||
217 | LOG (GNUNET_ERROR_TYPE_INFO, "membership_test()\n"); | ||
218 | |||
219 | GNUNET_assert (GNUNET_YES == db->membership_test (db->cls, &channel_pub_key, | ||
220 | &slave_pub_key, 4)); | ||
221 | |||
222 | GNUNET_assert (GNUNET_YES == db->membership_test (db->cls, &channel_pub_key, | ||
223 | &slave_pub_key, 2)); | ||
224 | |||
225 | GNUNET_assert (GNUNET_NO == db->membership_test (db->cls, &channel_pub_key, | ||
226 | &slave_pub_key, 1)); | ||
227 | |||
228 | /* Store & get messages */ | ||
229 | |||
230 | LOG (GNUNET_ERROR_TYPE_INFO, "MESSAGES\n"); | ||
231 | |||
232 | struct GNUNET_MULTICAST_MessageHeader *msg | ||
233 | = GNUNET_malloc (sizeof (*msg) + sizeof (channel_pub_key)); | ||
234 | GNUNET_assert (msg != NULL); | ||
235 | |||
236 | msg->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE); | ||
237 | msg->header.size = htons (sizeof (*msg) + sizeof (channel_pub_key)); | ||
238 | |||
239 | uint64_t fragment_id = INT64_MAX - 1; | ||
240 | msg->fragment_id = GNUNET_htonll (fragment_id); | ||
241 | |||
242 | uint64_t message_id = INT64_MAX - 10; | ||
243 | msg->message_id = GNUNET_htonll (message_id); | ||
244 | |||
245 | uint64_t group_generation = INT64_MAX - 3; | ||
246 | msg->group_generation = GNUNET_htonll (group_generation); | ||
247 | |||
248 | msg->hop_counter = htonl (9); | ||
249 | msg->fragment_offset = GNUNET_htonll (0); | ||
250 | msg->flags = htonl (GNUNET_MULTICAST_MESSAGE_LAST_FRAGMENT); | ||
251 | |||
252 | GNUNET_memcpy (&msg[1], &channel_pub_key, sizeof (channel_pub_key)); | ||
253 | |||
254 | msg->purpose.size = htonl (ntohs (msg->header.size) | ||
255 | - sizeof (msg->header) | ||
256 | - sizeof (msg->hop_counter) | ||
257 | - sizeof (msg->signature)); | ||
258 | msg->purpose.purpose = htonl (234); | ||
259 | GNUNET_assert (GNUNET_OK == | ||
260 | GNUNET_CRYPTO_eddsa_sign (channel_key, &msg->purpose, &msg->signature)); | ||
261 | |||
262 | LOG (GNUNET_ERROR_TYPE_INFO, "fragment_store()\n"); | ||
263 | |||
264 | struct FragmentClosure fcls = { 0 }; | ||
265 | fcls.n = 0; | ||
266 | fcls.msg[0] = msg; | ||
267 | fcls.flags[0] = GNUNET_PSYCSTORE_MESSAGE_STATE; | ||
268 | |||
269 | GNUNET_assert ( | ||
270 | GNUNET_OK == db->fragment_store (db->cls, &channel_pub_key, msg, | ||
271 | fcls.flags[0])); | ||
272 | |||
273 | LOG (GNUNET_ERROR_TYPE_INFO, "fragment_get(%" PRIu64 ")\n", fragment_id); | ||
274 | |||
275 | uint64_t ret_frags = 0; | ||
276 | GNUNET_assert ( | ||
277 | GNUNET_OK == db->fragment_get (db->cls, &channel_pub_key, | ||
278 | fragment_id, fragment_id, | ||
279 | &ret_frags, fragment_cb, &fcls)); | ||
280 | GNUNET_assert (fcls.n == 1); | ||
281 | |||
282 | LOG (GNUNET_ERROR_TYPE_INFO, "message_get_fragment()\n"); | ||
283 | |||
284 | fcls.n = 0; | ||
285 | GNUNET_assert ( | ||
286 | GNUNET_OK == db->message_get_fragment (db->cls, &channel_pub_key, | ||
287 | GNUNET_ntohll (msg->message_id), | ||
288 | GNUNET_ntohll (msg->fragment_offset), | ||
289 | fragment_cb, &fcls)); | ||
290 | GNUNET_assert (fcls.n == 1); | ||
291 | |||
292 | LOG (GNUNET_ERROR_TYPE_INFO, "message_add_flags()\n"); | ||
293 | GNUNET_assert ( | ||
294 | GNUNET_OK == db->message_add_flags (db->cls, &channel_pub_key, | ||
295 | GNUNET_ntohll (msg->message_id), | ||
296 | GNUNET_PSYCSTORE_MESSAGE_STATE_APPLIED)); | ||
297 | LOG (GNUNET_ERROR_TYPE_INFO, "fragment_get(%" PRIu64 ")\n", fragment_id); | ||
298 | |||
299 | fcls.n = 0; | ||
300 | fcls.flags[0] |= GNUNET_PSYCSTORE_MESSAGE_STATE_APPLIED; | ||
301 | |||
302 | GNUNET_assert ( | ||
303 | GNUNET_OK == db->fragment_get (db->cls, &channel_pub_key, | ||
304 | fragment_id, fragment_id, | ||
305 | &ret_frags, fragment_cb, &fcls)); | ||
306 | |||
307 | GNUNET_assert (fcls.n == 1); | ||
308 | |||
309 | LOG (GNUNET_ERROR_TYPE_INFO, "fragment_store()\n"); | ||
310 | |||
311 | struct GNUNET_MULTICAST_MessageHeader *msg1 | ||
312 | = GNUNET_malloc (sizeof (*msg1) + sizeof (channel_pub_key)); | ||
313 | |||
314 | GNUNET_memcpy (msg1, msg, sizeof (*msg1) + sizeof (channel_pub_key)); | ||
315 | |||
316 | msg1->fragment_id = GNUNET_htonll (INT64_MAX); | ||
317 | msg1->fragment_offset = GNUNET_htonll (32768); | ||
318 | |||
319 | fcls.n = 0; | ||
320 | fcls.msg[1] = msg1; | ||
321 | fcls.flags[1] = GNUNET_PSYCSTORE_MESSAGE_STATE_HASH; | ||
322 | |||
323 | GNUNET_assert (GNUNET_OK == db->fragment_store (db->cls, &channel_pub_key, msg1, | ||
324 | fcls.flags[1])); | ||
325 | |||
326 | LOG (GNUNET_ERROR_TYPE_INFO, "message_get()\n"); | ||
327 | |||
328 | GNUNET_assert ( | ||
329 | GNUNET_OK == db->message_get (db->cls, &channel_pub_key, | ||
330 | message_id, message_id, 0, | ||
331 | &ret_frags, fragment_cb, &fcls)); | ||
332 | GNUNET_assert (fcls.n == 2 && ret_frags == 2); | ||
333 | |||
334 | /* Message counters */ | ||
335 | |||
336 | LOG (GNUNET_ERROR_TYPE_INFO, "counters_message_get()\n"); | ||
337 | |||
338 | fragment_id = 0; | ||
339 | message_id = 0; | ||
340 | group_generation = 0; | ||
341 | GNUNET_assert ( | ||
342 | GNUNET_OK == db->counters_message_get (db->cls, &channel_pub_key, | ||
343 | &fragment_id, &message_id, | ||
344 | &group_generation) | ||
345 | && fragment_id == GNUNET_ntohll (msg1->fragment_id) | ||
346 | && message_id == GNUNET_ntohll (msg1->message_id) | ||
347 | && group_generation == GNUNET_ntohll (msg1->group_generation)); | ||
348 | |||
349 | /* Modify state */ | ||
350 | |||
351 | LOG (GNUNET_ERROR_TYPE_INFO, "STATE\n"); | ||
352 | |||
353 | LOG (GNUNET_ERROR_TYPE_INFO, "state_modify_*()\n"); | ||
354 | |||
355 | message_id = GNUNET_ntohll (fcls.msg[0]->message_id) + 1; | ||
356 | GNUNET_assert (GNUNET_OK == db->state_modify_begin (db->cls, &channel_pub_key, | ||
357 | message_id, 0)); | ||
358 | |||
359 | GNUNET_assert (GNUNET_OK == db->state_modify_op (db->cls, &channel_pub_key, | ||
360 | GNUNET_PSYC_OP_ASSIGN, | ||
361 | "_foo", | ||
362 | C2ARG("one two three"))); | ||
363 | |||
364 | GNUNET_assert (GNUNET_OK == db->state_modify_op (db->cls, &channel_pub_key, | ||
365 | GNUNET_PSYC_OP_ASSIGN, | ||
366 | "_foo_bar", slave_key, | ||
367 | sizeof (*slave_key))); | ||
368 | |||
369 | GNUNET_assert (GNUNET_OK == db->state_modify_end (db->cls, &channel_pub_key, | ||
370 | message_id)); | ||
371 | |||
372 | LOG (GNUNET_ERROR_TYPE_INFO, "state_get()\n"); | ||
373 | |||
374 | struct StateClosure scls = { 0 }; | ||
375 | scls.n = 0; | ||
376 | scls.value[0] = "one two three"; | ||
377 | scls.value_size[0] = strlen ("one two three"); | ||
378 | |||
379 | GNUNET_assert (GNUNET_OK == db->state_get (db->cls, &channel_pub_key, "_foo", | ||
380 | state_cb, &scls)); | ||
381 | GNUNET_assert (scls.n == 1); | ||
382 | |||
383 | LOG (GNUNET_ERROR_TYPE_INFO, "state_get_prefix()\n"); | ||
384 | |||
385 | scls.n = 0; | ||
386 | scls.value[1] = slave_key; | ||
387 | scls.value_size[1] = sizeof (*slave_key); | ||
388 | |||
389 | GNUNET_assert (GNUNET_OK == db->state_get_prefix (db->cls, &channel_pub_key, | ||
390 | "_foo", state_cb, &scls)); | ||
391 | GNUNET_assert (scls.n == 2); | ||
392 | |||
393 | LOG (GNUNET_ERROR_TYPE_INFO, "state_get_signed()\n"); | ||
394 | |||
395 | scls.n = 0; | ||
396 | GNUNET_assert (GNUNET_NO == db->state_get_signed (db->cls, &channel_pub_key, | ||
397 | state_cb, &scls)); | ||
398 | GNUNET_assert (scls.n == 0); | ||
399 | |||
400 | LOG (GNUNET_ERROR_TYPE_INFO, "state_update_signed()\n"); | ||
401 | |||
402 | GNUNET_assert (GNUNET_OK == db->state_update_signed (db->cls, | ||
403 | &channel_pub_key)); | ||
404 | |||
405 | LOG (GNUNET_ERROR_TYPE_INFO, "state_get_signed()\n"); | ||
406 | |||
407 | scls.n = 0; | ||
408 | GNUNET_assert (GNUNET_YES == db->state_get_signed (db->cls, &channel_pub_key, | ||
409 | state_cb, &scls)); | ||
410 | GNUNET_assert (scls.n == 2); | ||
411 | |||
412 | /* State counters */ | ||
413 | |||
414 | LOG (GNUNET_ERROR_TYPE_INFO, "counters_state_get()\n"); | ||
415 | |||
416 | uint64_t max_state_msg_id = 0; | ||
417 | GNUNET_assert (GNUNET_OK == db->counters_state_get (db->cls, &channel_pub_key, | ||
418 | &max_state_msg_id) | ||
419 | && max_state_msg_id == message_id); | ||
420 | |||
421 | /* State sync */ | ||
422 | |||
423 | LOG (GNUNET_ERROR_TYPE_INFO, "state_sync_*()\n"); | ||
424 | |||
425 | scls.n = 0; | ||
426 | scls.value[0] = channel_key; | ||
427 | scls.value_size[0] = sizeof (*channel_key); | ||
428 | scls.value[1] = "three two one"; | ||
429 | scls.value_size[1] = strlen ("three two one"); | ||
430 | |||
431 | GNUNET_assert (GNUNET_OK == db->state_sync_begin (db->cls, &channel_pub_key)); | ||
432 | |||
433 | GNUNET_assert (GNUNET_OK == db->state_sync_assign (db->cls, &channel_pub_key, | ||
434 | "_sync_bar", scls.value[0], | ||
435 | scls.value_size[0])); | ||
436 | |||
437 | GNUNET_assert (GNUNET_OK == db->state_sync_assign (db->cls, &channel_pub_key, | ||
438 | "_sync_foo", scls.value[1], | ||
439 | scls.value_size[1])); | ||
440 | |||
441 | GNUNET_assert (GNUNET_OK == db->state_sync_end (db->cls, &channel_pub_key, | ||
442 | max_state_msg_id, | ||
443 | INT64_MAX - 5)); | ||
444 | |||
445 | GNUNET_assert (GNUNET_NO == db->state_get_prefix (db->cls, &channel_pub_key, | ||
446 | "_foo", state_cb, &scls)); | ||
447 | GNUNET_assert (scls.n == 0); | ||
448 | |||
449 | GNUNET_assert (GNUNET_OK == db->state_get_prefix (db->cls, &channel_pub_key, | ||
450 | "_sync", state_cb, &scls)); | ||
451 | GNUNET_assert (scls.n == 2); | ||
452 | |||
453 | scls.n = 0; | ||
454 | GNUNET_assert (GNUNET_OK == db->state_get_signed (db->cls, &channel_pub_key, | ||
455 | state_cb, &scls)); | ||
456 | GNUNET_assert (scls.n == 2); | ||
457 | |||
458 | /* Modify state after sync */ | ||
459 | |||
460 | LOG (GNUNET_ERROR_TYPE_INFO, "state_modify_*()\n"); | ||
461 | |||
462 | message_id = GNUNET_ntohll (fcls.msg[0]->message_id) + 6; | ||
463 | GNUNET_assert (GNUNET_OK == db->state_modify_begin (db->cls, &channel_pub_key, | ||
464 | message_id, | ||
465 | message_id - max_state_msg_id)); | ||
466 | |||
467 | GNUNET_assert (GNUNET_OK == db->state_modify_op (db->cls, &channel_pub_key, | ||
468 | GNUNET_PSYC_OP_ASSIGN, | ||
469 | "_sync_foo", | ||
470 | C2ARG("five six seven"))); | ||
471 | |||
472 | GNUNET_assert (GNUNET_OK == db->state_modify_end (db->cls, &channel_pub_key, | ||
473 | message_id)); | ||
474 | |||
475 | /* Reset state */ | ||
476 | |||
477 | LOG (GNUNET_ERROR_TYPE_INFO, "state_reset()\n"); | ||
478 | |||
479 | scls.n = 0; | ||
480 | GNUNET_assert (GNUNET_OK == db->state_reset (db->cls, &channel_pub_key)); | ||
481 | GNUNET_assert (scls.n == 0); | ||
482 | |||
483 | ok = 0; | ||
484 | |||
485 | if (NULL != channel_key) | ||
486 | { | ||
487 | GNUNET_free (channel_key); | ||
488 | channel_key = NULL; | ||
489 | } | ||
490 | if (NULL != slave_key) | ||
491 | { | ||
492 | GNUNET_free (slave_key); | ||
493 | slave_key = NULL; | ||
494 | } | ||
495 | |||
496 | unload_plugin (db); | ||
497 | } | ||
498 | |||
499 | |||
500 | int | ||
501 | main (int argc, char *argv[]) | ||
502 | { | ||
503 | char cfg_name[128]; | ||
504 | char *const xargv[] = { | ||
505 | "test-plugin-psycstore", | ||
506 | "-c", cfg_name, | ||
507 | "-L", LOG_LEVEL, | ||
508 | NULL | ||
509 | }; | ||
510 | struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
511 | GNUNET_GETOPT_OPTION_END | ||
512 | }; | ||
513 | GNUNET_DISK_directory_remove ("/tmp/gnunet-test-plugin-psycstore-sqlite"); | ||
514 | GNUNET_log_setup ("test-plugin-psycstore", LOG_LEVEL, NULL); | ||
515 | plugin_name = GNUNET_TESTING_get_testname_from_underscore (argv[0]); | ||
516 | GNUNET_snprintf (cfg_name, sizeof (cfg_name), "test_plugin_psycstore_%s.conf", | ||
517 | plugin_name); | ||
518 | GNUNET_PROGRAM_run ((sizeof (xargv) / sizeof (char *)) - 1, xargv, | ||
519 | "test-plugin-psycstore", "nohelp", options, &run, NULL); | ||
520 | |||
521 | if ( (0 != ok) && | ||
522 | (77 != ok) ) | ||
523 | FPRINTF (stderr, "Missed some testcases: %d\n", ok); | ||
524 | |||
525 | #if ! DEBUG_PSYCSTORE | ||
526 | GNUNET_DISK_directory_remove ("/tmp/gnunet-test-plugin-psycstore-sqlite"); | ||
527 | #endif | ||
528 | |||
529 | return ok; | ||
530 | } | ||
531 | |||
532 | /* end of test_plugin_psycstore.c */ | ||
diff --git a/src/psycstore/test_plugin_psycstore_mysql.conf b/src/psycstore/test_plugin_psycstore_mysql.conf deleted file mode 100644 index e15b3fd63..000000000 --- a/src/psycstore/test_plugin_psycstore_mysql.conf +++ /dev/null | |||
@@ -1,7 +0,0 @@ | |||
1 | [psycstore-mysql] | ||
2 | DATABASE = test | ||
3 | # CONFIG = ~/.my.cnf | ||
4 | # USER = gnunet | ||
5 | # PASSWORD = | ||
6 | # HOST = localhost | ||
7 | # PORT = 3306 | ||
diff --git a/src/psycstore/test_plugin_psycstore_postgres.conf b/src/psycstore/test_plugin_psycstore_postgres.conf deleted file mode 100644 index 4b870dd02..000000000 --- a/src/psycstore/test_plugin_psycstore_postgres.conf +++ /dev/null | |||
@@ -1,2 +0,0 @@ | |||
1 | [psycstore-postgres] | ||
2 | CONFIG = connect_timeout=10; dbname=template1 | ||
diff --git a/src/psycstore/test_plugin_psycstore_sqlite.conf b/src/psycstore/test_plugin_psycstore_sqlite.conf deleted file mode 100644 index 498b1d02d..000000000 --- a/src/psycstore/test_plugin_psycstore_sqlite.conf +++ /dev/null | |||
@@ -1,2 +0,0 @@ | |||
1 | [psycstore-sqlite] | ||
2 | FILENAME = $GNUNET_TMP/gnunet-test-plugin-psycstore-sqlite/sqlite.db | ||
diff --git a/src/psycstore/test_psycstore.c b/src/psycstore/test_psycstore.c deleted file mode 100644 index ca509041c..000000000 --- a/src/psycstore/test_psycstore.c +++ /dev/null | |||
@@ -1,586 +0,0 @@ | |||
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 psycstore/test_psycstore.c | ||
23 | * @brief Test for the PSYCstore service. | ||
24 | * @author Gabor X Toth | ||
25 | * @author Christian Grothoff | ||
26 | */ | ||
27 | |||
28 | #include <inttypes.h> | ||
29 | |||
30 | #include "platform.h" | ||
31 | #include "gnunet_util_lib.h" | ||
32 | #include "gnunet_common.h" | ||
33 | #include "gnunet_testing_lib.h" | ||
34 | #include "gnunet_psycstore_service.h" | ||
35 | |||
36 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) | ||
37 | |||
38 | |||
39 | /** | ||
40 | * Return value from 'main'. | ||
41 | */ | ||
42 | static int res; | ||
43 | |||
44 | /** | ||
45 | * Handle to PSYCstore service. | ||
46 | */ | ||
47 | static struct GNUNET_PSYCSTORE_Handle *h; | ||
48 | |||
49 | /** | ||
50 | * Handle to PSYCstore operation. | ||
51 | */ | ||
52 | static struct GNUNET_PSYCSTORE_OperationHandle *op; | ||
53 | |||
54 | /** | ||
55 | * Handle for task for timeout termination. | ||
56 | */ | ||
57 | static struct GNUNET_SCHEDULER_Task *end_badly_task; | ||
58 | |||
59 | static struct GNUNET_CRYPTO_EddsaPrivateKey *channel_key; | ||
60 | static struct GNUNET_CRYPTO_EcdsaPrivateKey *slave_key; | ||
61 | |||
62 | static struct GNUNET_CRYPTO_EddsaPublicKey channel_pub_key; | ||
63 | static struct GNUNET_CRYPTO_EcdsaPublicKey slave_pub_key; | ||
64 | |||
65 | static struct FragmentClosure | ||
66 | { | ||
67 | uint8_t n; | ||
68 | uint8_t n_expected; | ||
69 | uint64_t flags[16]; | ||
70 | struct GNUNET_MULTICAST_MessageHeader *msg[16]; | ||
71 | } fcls; | ||
72 | |||
73 | struct StateClosure { | ||
74 | size_t n; | ||
75 | char *name[16]; | ||
76 | void *value[16]; | ||
77 | size_t value_size[16]; | ||
78 | } scls; | ||
79 | |||
80 | static struct GNUNET_PSYC_Modifier modifiers[16]; | ||
81 | |||
82 | /** | ||
83 | * Clean up all resources used. | ||
84 | */ | ||
85 | static void | ||
86 | cleanup () | ||
87 | { | ||
88 | if (NULL != op) | ||
89 | { | ||
90 | GNUNET_PSYCSTORE_operation_cancel (op); | ||
91 | op = NULL; | ||
92 | } | ||
93 | if (NULL != h) | ||
94 | { | ||
95 | GNUNET_PSYCSTORE_disconnect (h); | ||
96 | h = NULL; | ||
97 | } | ||
98 | if (NULL != channel_key) | ||
99 | { | ||
100 | GNUNET_free (channel_key); | ||
101 | channel_key = NULL; | ||
102 | } | ||
103 | if (NULL != slave_key) | ||
104 | { | ||
105 | GNUNET_free (slave_key); | ||
106 | slave_key = NULL; | ||
107 | } | ||
108 | GNUNET_SCHEDULER_shutdown (); | ||
109 | } | ||
110 | |||
111 | |||
112 | /** | ||
113 | * Terminate the testcase (failure). | ||
114 | * | ||
115 | * @param cls NULL | ||
116 | */ | ||
117 | static void | ||
118 | end_badly (void *cls) | ||
119 | { | ||
120 | res = 1; | ||
121 | cleanup (); | ||
122 | } | ||
123 | |||
124 | |||
125 | /** | ||
126 | * Terminate the testcase (success). | ||
127 | * | ||
128 | * @param cls NULL | ||
129 | */ | ||
130 | static void | ||
131 | end_normally (void *cls) | ||
132 | { | ||
133 | res = 0; | ||
134 | cleanup (); | ||
135 | } | ||
136 | |||
137 | |||
138 | /** | ||
139 | * Finish the testcase (successfully). | ||
140 | */ | ||
141 | static void | ||
142 | end () | ||
143 | { | ||
144 | if (NULL != end_badly_task) | ||
145 | { | ||
146 | GNUNET_SCHEDULER_cancel (end_badly_task); | ||
147 | end_badly_task = NULL; | ||
148 | } | ||
149 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MILLISECONDS, | ||
150 | &end_normally, NULL); | ||
151 | } | ||
152 | |||
153 | |||
154 | static void | ||
155 | state_reset_result (void *cls, | ||
156 | int64_t result, | ||
157 | const char *err_msg, | ||
158 | uint16_t err_msg_size) | ||
159 | { | ||
160 | op = NULL; | ||
161 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
162 | "state_reset_result:\t%d\n", | ||
163 | (int) result); | ||
164 | GNUNET_assert (GNUNET_OK == result); | ||
165 | |||
166 | op = GNUNET_PSYCSTORE_state_reset (h, &channel_pub_key, | ||
167 | &state_reset_result, cls); | ||
168 | GNUNET_PSYCSTORE_operation_cancel (op); | ||
169 | op = NULL; | ||
170 | end (); | ||
171 | } | ||
172 | |||
173 | |||
174 | static int | ||
175 | state_result (void *cls, | ||
176 | const char *name, | ||
177 | const void *value, | ||
178 | uint32_t value_size) | ||
179 | { | ||
180 | struct StateClosure *scls = cls; | ||
181 | const char *nam = scls->name[scls->n]; | ||
182 | const void *val = scls->value[scls->n]; | ||
183 | size_t val_size = scls->value_size[scls->n++]; | ||
184 | |||
185 | if (value_size == val_size | ||
186 | && 0 == memcmp (value, val, val_size) | ||
187 | && 0 == strcmp (name, nam)) | ||
188 | { | ||
189 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
190 | " variable %s matches\n", | ||
191 | name); | ||
192 | return GNUNET_YES; | ||
193 | } | ||
194 | else | ||
195 | { | ||
196 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
197 | " variable %s differs\nReceived: %.*s\nExpected: %.*s\n", | ||
198 | name, (int) value_size, (char*) value, (int) val_size, (char*) val); | ||
199 | GNUNET_assert (0); | ||
200 | return GNUNET_SYSERR; | ||
201 | } | ||
202 | } | ||
203 | |||
204 | |||
205 | static void | ||
206 | state_get_prefix_result (void *cls, int64_t result, | ||
207 | const char *err_msg, uint16_t err_msg_size) | ||
208 | { | ||
209 | struct StateClosure *scls = cls; | ||
210 | op = NULL; | ||
211 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "state_get_prefix_result:\t%ld\n", (long int) result); | ||
212 | GNUNET_assert (GNUNET_OK == result && 2 == scls->n); | ||
213 | |||
214 | op = GNUNET_PSYCSTORE_state_reset (h, &channel_pub_key, | ||
215 | &state_reset_result, cls); | ||
216 | } | ||
217 | |||
218 | |||
219 | static void | ||
220 | state_get_result (void *cls, int64_t result, | ||
221 | const char *err_msg, uint16_t err_msg_size) | ||
222 | { | ||
223 | op = NULL; | ||
224 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "state_get_result:\t%ld\n", (long int) result); | ||
225 | GNUNET_assert (GNUNET_OK == result); | ||
226 | |||
227 | scls.n = 0; | ||
228 | |||
229 | scls.name[0] = "_sync_bar"; | ||
230 | scls.value[0] = "ten eleven twelve"; | ||
231 | scls.value_size[0] = sizeof ("ten eleven twelve") - 1; | ||
232 | |||
233 | scls.name[1] = "_sync_foo"; | ||
234 | scls.value[1] = "three two one"; | ||
235 | scls.value_size[1] = sizeof ("three two one") - 1; | ||
236 | |||
237 | op = GNUNET_PSYCSTORE_state_get_prefix (h, &channel_pub_key, "_sync", | ||
238 | &state_result, | ||
239 | &state_get_prefix_result, &scls); | ||
240 | } | ||
241 | |||
242 | |||
243 | static void | ||
244 | counters_result (void *cls, int status, uint64_t max_fragment_id, | ||
245 | uint64_t max_message_id, uint64_t max_group_generation, | ||
246 | uint64_t max_state_message_id) | ||
247 | { | ||
248 | struct FragmentClosure *fcls = cls; | ||
249 | int result = 0; | ||
250 | op = NULL; | ||
251 | |||
252 | if (GNUNET_OK == status | ||
253 | && max_fragment_id == GNUNET_ntohll (fcls->msg[2]->fragment_id) | ||
254 | && max_message_id == GNUNET_ntohll (fcls->msg[2]->message_id) | ||
255 | && max_group_generation == GNUNET_ntohll (fcls->msg[2]->group_generation) | ||
256 | && max_state_message_id == GNUNET_ntohll (fcls->msg[0]->message_id)) | ||
257 | result = 1; | ||
258 | |||
259 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "counters_get:\t%d\n", result); | ||
260 | GNUNET_assert (result == 1); | ||
261 | |||
262 | scls.n = 0; | ||
263 | scls.name[0] = "_sync_bar"; | ||
264 | scls.value[0] = "ten eleven twelve"; | ||
265 | scls.value_size[0] = sizeof ("ten eleven twelve") - 1; | ||
266 | |||
267 | op = GNUNET_PSYCSTORE_state_get (h, &channel_pub_key, "_sync_bar_x_yy_zzz", | ||
268 | &state_result, &state_get_result, &scls); | ||
269 | } | ||
270 | |||
271 | |||
272 | static void | ||
273 | state_modify_result (void *cls, int64_t result, | ||
274 | const char *err_msg, uint16_t err_msg_size) | ||
275 | { | ||
276 | op = NULL; | ||
277 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "state_modify_result:\t%ld\n", (long int) result); | ||
278 | GNUNET_assert (GNUNET_OK == result); | ||
279 | |||
280 | op = GNUNET_PSYCSTORE_counters_get (h, &channel_pub_key, | ||
281 | &counters_result, cls); | ||
282 | } | ||
283 | |||
284 | |||
285 | static void | ||
286 | state_sync_result (void *cls, int64_t result, | ||
287 | const char *err_msg, uint16_t err_msg_size) | ||
288 | { | ||
289 | struct FragmentClosure *fcls = cls; | ||
290 | op = NULL; | ||
291 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "state_sync_result:\t%ld\n", (long int) result); | ||
292 | GNUNET_assert (GNUNET_OK == result); | ||
293 | |||
294 | op = GNUNET_PSYCSTORE_state_modify (h, &channel_pub_key, | ||
295 | GNUNET_ntohll (fcls->msg[0]->message_id), | ||
296 | 0, state_modify_result, fcls); | ||
297 | } | ||
298 | |||
299 | |||
300 | static int | ||
301 | fragment_result (void *cls, | ||
302 | struct GNUNET_MULTICAST_MessageHeader *msg, | ||
303 | enum GNUNET_PSYCSTORE_MessageFlags flags) | ||
304 | { | ||
305 | struct FragmentClosure *fcls = cls; | ||
306 | GNUNET_assert (fcls->n < fcls->n_expected); | ||
307 | struct GNUNET_MULTICAST_MessageHeader *msg0 = fcls->msg[fcls->n]; | ||
308 | uint64_t flags0 = fcls->flags[fcls->n++]; | ||
309 | |||
310 | if (flags == flags0 && msg->header.size == msg0->header.size | ||
311 | && 0 == memcmp (msg, msg0, ntohs (msg->header.size))) | ||
312 | { | ||
313 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, " fragment %" PRIu64 " matches\n", | ||
314 | GNUNET_ntohll (msg->fragment_id)); | ||
315 | return GNUNET_YES; | ||
316 | } | ||
317 | else | ||
318 | { | ||
319 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
320 | " fragment differs: expected %" PRIu64 ", got %" PRIu64 "\n", | ||
321 | GNUNET_ntohll (msg0->fragment_id), | ||
322 | GNUNET_ntohll (msg->fragment_id)); | ||
323 | GNUNET_assert (0); | ||
324 | return GNUNET_SYSERR; | ||
325 | } | ||
326 | } | ||
327 | |||
328 | |||
329 | static void | ||
330 | message_get_latest_result (void *cls, int64_t result, | ||
331 | const char *err_msg, uint16_t err_msg_size) | ||
332 | { | ||
333 | struct FragmentClosure *fcls = cls; | ||
334 | op = NULL; | ||
335 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "message_get_latest:\t%ld\n", (long int) result); | ||
336 | GNUNET_assert (0 < result && fcls->n == fcls->n_expected); | ||
337 | |||
338 | modifiers[0] = (struct GNUNET_PSYC_Modifier) { | ||
339 | .oper = '=', | ||
340 | .name = "_sync_foo", | ||
341 | .value = "three two one", | ||
342 | .value_size = sizeof ("three two one") - 1 | ||
343 | }; | ||
344 | modifiers[1] = (struct GNUNET_PSYC_Modifier) { | ||
345 | .oper = '=', | ||
346 | .name = "_sync_bar", | ||
347 | .value = "ten eleven twelve", | ||
348 | .value_size = sizeof ("ten eleven twelve") - 1 | ||
349 | }; | ||
350 | |||
351 | op = GNUNET_PSYCSTORE_state_sync (h, &channel_pub_key, | ||
352 | GNUNET_ntohll (fcls->msg[0]->message_id) + 1, | ||
353 | GNUNET_ntohll (fcls->msg[0]->message_id) + 2, | ||
354 | 2, modifiers, state_sync_result, fcls); | ||
355 | } | ||
356 | |||
357 | |||
358 | static void | ||
359 | message_get_result (void *cls, int64_t result, | ||
360 | const char *err_msg, uint16_t err_msg_size) | ||
361 | { | ||
362 | struct FragmentClosure *fcls = cls; | ||
363 | op = NULL; | ||
364 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "message_get:\t%ld\n", (long int) result); | ||
365 | GNUNET_assert (0 < result && fcls->n == fcls->n_expected); | ||
366 | |||
367 | fcls->n = 0; | ||
368 | fcls->n_expected = 3; | ||
369 | op = GNUNET_PSYCSTORE_message_get_latest (h, &channel_pub_key, &slave_pub_key, | ||
370 | 1, "", &fragment_result, | ||
371 | &message_get_latest_result, fcls); | ||
372 | } | ||
373 | |||
374 | |||
375 | static void | ||
376 | message_get_fragment_result (void *cls, int64_t result, | ||
377 | const char *err_msg, uint16_t err_msg_size) | ||
378 | { | ||
379 | struct FragmentClosure *fcls = cls; | ||
380 | op = NULL; | ||
381 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "message_get_fragment:\t%ld\n", (long int) result); | ||
382 | GNUNET_assert (0 < result && fcls->n == fcls->n_expected); | ||
383 | |||
384 | fcls->n = 0; | ||
385 | fcls->n_expected = 3; | ||
386 | uint64_t message_id = GNUNET_ntohll (fcls->msg[0]->message_id); | ||
387 | op = GNUNET_PSYCSTORE_message_get (h, &channel_pub_key, &slave_pub_key, | ||
388 | message_id, message_id, 0, "", | ||
389 | &fragment_result, | ||
390 | &message_get_result, fcls); | ||
391 | } | ||
392 | |||
393 | |||
394 | static void | ||
395 | fragment_get_latest_result (void *cls, int64_t result, | ||
396 | const char *err_msg, uint16_t err_msg_size) | ||
397 | { | ||
398 | struct FragmentClosure *fcls = cls; | ||
399 | op = NULL; | ||
400 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "fragment_get_latest:\t%ld\n", (long int) result); | ||
401 | GNUNET_assert (0 < result && fcls->n == fcls->n_expected); | ||
402 | |||
403 | fcls->n = 1; | ||
404 | fcls->n_expected = 2; | ||
405 | op = GNUNET_PSYCSTORE_message_get_fragment (h, &channel_pub_key, &slave_pub_key, | ||
406 | GNUNET_ntohll (fcls->msg[1]->message_id), | ||
407 | GNUNET_ntohll (fcls->msg[1]->fragment_offset), | ||
408 | &fragment_result, | ||
409 | &message_get_fragment_result, fcls); | ||
410 | } | ||
411 | |||
412 | |||
413 | static void | ||
414 | fragment_get_result (void *cls, int64_t result, | ||
415 | const char *err_msg, uint16_t err_msg_size) | ||
416 | { | ||
417 | struct FragmentClosure *fcls = cls; | ||
418 | op = NULL; | ||
419 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
420 | "fragment_get:\t%d\n", | ||
421 | (int) result); | ||
422 | GNUNET_assert (0 < result && fcls->n == fcls->n_expected); | ||
423 | |||
424 | fcls->n = 0; | ||
425 | fcls->n_expected = 3; | ||
426 | op = GNUNET_PSYCSTORE_fragment_get_latest (h, &channel_pub_key, | ||
427 | &slave_pub_key, fcls->n_expected, | ||
428 | &fragment_result, | ||
429 | &fragment_get_latest_result, fcls); | ||
430 | } | ||
431 | |||
432 | |||
433 | static void | ||
434 | fragment_store_result (void *cls, int64_t result, | ||
435 | const char *err_msg, uint16_t err_msg_size) | ||
436 | { | ||
437 | op = NULL; | ||
438 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "fragment_store:\t%ld\n", (long int) result); | ||
439 | GNUNET_assert (GNUNET_OK == result); | ||
440 | |||
441 | if ((intptr_t) cls == GNUNET_YES) | ||
442 | { /* last fragment */ | ||
443 | fcls.n = 0; | ||
444 | fcls.n_expected = 1; | ||
445 | uint64_t fragment_id = GNUNET_ntohll (fcls.msg[0]->fragment_id); | ||
446 | op = GNUNET_PSYCSTORE_fragment_get (h, &channel_pub_key, &slave_pub_key, | ||
447 | fragment_id, fragment_id, | ||
448 | &fragment_result, | ||
449 | &fragment_get_result, &fcls); | ||
450 | } | ||
451 | } | ||
452 | |||
453 | |||
454 | static void | ||
455 | fragment_store () | ||
456 | { | ||
457 | struct GNUNET_MULTICAST_MessageHeader *msg; | ||
458 | fcls.flags[0] = GNUNET_PSYCSTORE_MESSAGE_STATE; | ||
459 | fcls.msg[0] = msg = GNUNET_malloc (sizeof (*msg) + sizeof (channel_pub_key)); | ||
460 | GNUNET_assert (msg != NULL); | ||
461 | |||
462 | msg->header.type = htons (GNUNET_MESSAGE_TYPE_MULTICAST_MESSAGE); | ||
463 | msg->header.size = htons (sizeof (*msg) + sizeof (channel_pub_key)); | ||
464 | |||
465 | msg->hop_counter = htonl (9); | ||
466 | msg->fragment_id = GNUNET_htonll (INT64_MAX - 8); | ||
467 | msg->fragment_offset = GNUNET_htonll (0); | ||
468 | msg->message_id = GNUNET_htonll (INT64_MAX - 10); | ||
469 | msg->group_generation = GNUNET_htonll (INT64_MAX - 3); | ||
470 | msg->flags = htonl (GNUNET_MULTICAST_MESSAGE_LAST_FRAGMENT); | ||
471 | |||
472 | GNUNET_memcpy (&msg[1], &channel_pub_key, sizeof (channel_pub_key)); | ||
473 | |||
474 | msg->purpose.size = htonl (ntohs (msg->header.size) | ||
475 | - sizeof (msg->header) | ||
476 | - sizeof (msg->hop_counter) | ||
477 | - sizeof (msg->signature)); | ||
478 | msg->purpose.purpose = htonl (234); | ||
479 | GNUNET_assert (GNUNET_OK == GNUNET_CRYPTO_eddsa_sign (channel_key, &msg->purpose, | ||
480 | &msg->signature)); | ||
481 | |||
482 | op = GNUNET_PSYCSTORE_fragment_store (h, &channel_pub_key, msg, fcls.flags[0], | ||
483 | &fragment_store_result, GNUNET_NO); | ||
484 | |||
485 | fcls.flags[1] = GNUNET_PSYCSTORE_MESSAGE_STATE_APPLIED; | ||
486 | fcls.msg[1] = msg = GNUNET_malloc (sizeof (*msg) + sizeof (channel_pub_key)); | ||
487 | GNUNET_memcpy (msg, fcls.msg[0], sizeof (*msg) + sizeof (channel_pub_key)); | ||
488 | msg->fragment_id = GNUNET_htonll (INT64_MAX - 4); | ||
489 | msg->fragment_offset = GNUNET_htonll (1024); | ||
490 | |||
491 | op = GNUNET_PSYCSTORE_fragment_store (h, &channel_pub_key, msg, fcls.flags[1], | ||
492 | &fragment_store_result, GNUNET_NO); | ||
493 | |||
494 | fcls.flags[2] = GNUNET_PSYCSTORE_MESSAGE_STATE_HASH; | ||
495 | fcls.msg[2] = msg = GNUNET_malloc (sizeof (*msg) + sizeof (channel_pub_key)); | ||
496 | GNUNET_memcpy (msg, fcls.msg[1], sizeof (*msg) + sizeof (channel_pub_key)); | ||
497 | msg->fragment_id = GNUNET_htonll (INT64_MAX); | ||
498 | msg->fragment_offset = GNUNET_htonll (16384); | ||
499 | |||
500 | op = GNUNET_PSYCSTORE_fragment_store (h, &channel_pub_key, msg, fcls.flags[2], | ||
501 | &fragment_store_result, (void *) GNUNET_YES); | ||
502 | } | ||
503 | |||
504 | |||
505 | static void | ||
506 | membership_test_result (void *cls, int64_t result, | ||
507 | const char *err_msg, uint16_t err_msg_size) | ||
508 | { | ||
509 | op = NULL; | ||
510 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "membership_test:\t%ld\n", (long int) result); | ||
511 | GNUNET_assert (GNUNET_OK == result); | ||
512 | |||
513 | fragment_store (); | ||
514 | } | ||
515 | |||
516 | |||
517 | static void | ||
518 | membership_store_result (void *cls, int64_t result, | ||
519 | const char *err_msg, uint16_t err_msg_size) | ||
520 | { | ||
521 | op = NULL; | ||
522 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "membership_store:\t%ld\n", (long int) result); | ||
523 | GNUNET_assert (GNUNET_OK == result); | ||
524 | |||
525 | op = GNUNET_PSYCSTORE_membership_test (h, &channel_pub_key, &slave_pub_key, | ||
526 | INT64_MAX - 10, 2, | ||
527 | &membership_test_result, NULL); | ||
528 | } | ||
529 | |||
530 | |||
531 | /** | ||
532 | * Main function of the test, run from scheduler. | ||
533 | * | ||
534 | * @param cls NULL | ||
535 | * @param cfg configuration we use (also to connect to PSYCstore service) | ||
536 | * @param peer handle to access more of the peer (not used) | ||
537 | */ | ||
538 | static void | ||
539 | #if DEBUG_TEST_PSYCSTORE | ||
540 | run (void *cls, char *const *args, const char *cfgfile, | ||
541 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
542 | #else | ||
543 | run (void *cls, | ||
544 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
545 | struct GNUNET_TESTING_Peer *peer) | ||
546 | #endif | ||
547 | { | ||
548 | end_badly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL); | ||
549 | |||
550 | h = GNUNET_PSYCSTORE_connect (cfg); | ||
551 | GNUNET_assert (NULL != h); | ||
552 | |||
553 | channel_key = GNUNET_CRYPTO_eddsa_key_create (); | ||
554 | slave_key = GNUNET_CRYPTO_ecdsa_key_create (); | ||
555 | |||
556 | GNUNET_CRYPTO_eddsa_key_get_public (channel_key, &channel_pub_key); | ||
557 | GNUNET_CRYPTO_ecdsa_key_get_public (slave_key, &slave_pub_key); | ||
558 | |||
559 | op = GNUNET_PSYCSTORE_membership_store (h, &channel_pub_key, &slave_pub_key, | ||
560 | GNUNET_YES, INT64_MAX - 5, | ||
561 | INT64_MAX - 10, 2, | ||
562 | &membership_store_result, NULL); | ||
563 | } | ||
564 | |||
565 | |||
566 | int | ||
567 | main (int argc, char *argv[]) | ||
568 | { | ||
569 | res = 1; | ||
570 | #if DEBUG_TEST_PSYCSTORE | ||
571 | const struct GNUNET_GETOPT_CommandLineOption opts[] = { | ||
572 | GNUNET_GETOPT_OPTION_END | ||
573 | }; | ||
574 | if (GNUNET_OK != GNUNET_PROGRAM_run (argc, argv, "test-psycstore", | ||
575 | "test-psycstore [options]", | ||
576 | opts, &run, NULL)) | ||
577 | return 1; | ||
578 | #else | ||
579 | if (0 != GNUNET_TESTING_service_run ("test-psycstore", "psycstore", | ||
580 | "test_psycstore.conf", &run, NULL)) | ||
581 | return 1; | ||
582 | #endif | ||
583 | return res; | ||
584 | } | ||
585 | |||
586 | /* end of test_psycstore.c */ | ||
diff --git a/src/psycstore/test_psycstore.conf b/src/psycstore/test_psycstore.conf deleted file mode 100644 index fa7c2d003..000000000 --- a/src/psycstore/test_psycstore.conf +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | [PATHS] | ||
2 | GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-psycstore/ | ||
3 | |||
4 | [psycstore] | ||
5 | DATABASE = sqlite | ||
6 | |||
7 | [psycstore-sqlite] | ||
8 | FILENAME = $GNUNET_TEST_HOME/psycstore/sqlite.db | ||
diff --git a/src/psycutil/.gitignore b/src/psycutil/.gitignore deleted file mode 100644 index 03d8197fb..000000000 --- a/src/psycutil/.gitignore +++ /dev/null | |||
@@ -1 +0,0 @@ | |||
1 | test_psyc_env | ||
diff --git a/src/psycutil/Makefile.am b/src/psycutil/Makefile.am deleted file mode 100644 index 2732c3a21..000000000 --- a/src/psycutil/Makefile.am +++ /dev/null | |||
@@ -1,45 +0,0 @@ | |||
1 | # This Makefile.am is in the public domain | ||
2 | AM_CPPFLAGS = -I$(top_srcdir)/src/include | ||
3 | |||
4 | pkgcfgdir= $(pkgdatadir)/config.d/ | ||
5 | |||
6 | libexecdir= $(pkglibdir)/libexec/ | ||
7 | |||
8 | if MINGW | ||
9 | WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols | ||
10 | endif | ||
11 | |||
12 | if USE_COVERAGE | ||
13 | AM_CFLAGS = --coverage -O0 | ||
14 | XLIB = -lgcov | ||
15 | endif | ||
16 | |||
17 | lib_LTLIBRARIES = libgnunetpsycutil.la | ||
18 | |||
19 | libgnunetpsycutil_la_SOURCES = \ | ||
20 | psyc_env.c \ | ||
21 | psyc_message.c \ | ||
22 | psyc_slicer.c | ||
23 | libgnunetpsycutil_la_LIBADD = \ | ||
24 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
25 | $(GN_LIBINTL) $(XLIB) | ||
26 | libgnunetpsycutil_la_LDFLAGS = \ | ||
27 | $(GN_LIB_LDFLAGS) $(WINFLAGS) \ | ||
28 | -version-info 0:0:0 | ||
29 | |||
30 | if HAVE_TESTING | ||
31 | check_PROGRAMS = \ | ||
32 | test_psyc_env | ||
33 | endif | ||
34 | |||
35 | if ENABLE_TEST_RUN | ||
36 | AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME; | ||
37 | TESTS = $(check_PROGRAMS) | ||
38 | endif | ||
39 | |||
40 | test_psyc_env_SOURCES = \ | ||
41 | test_psyc_env.c | ||
42 | test_psyc_env_LDADD = \ | ||
43 | libgnunetpsycutil.la \ | ||
44 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
45 | $(top_builddir)/src/util/libgnunetutil.la | ||
diff --git a/src/psycutil/psyc_env.c b/src/psycutil/psyc_env.c deleted file mode 100644 index fc4b8eb7c..000000000 --- a/src/psycutil/psyc_env.c +++ /dev/null | |||
@@ -1,196 +0,0 @@ | |||
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 | * @author Gabor X Toth | ||
23 | * | ||
24 | * @file | ||
25 | * Library providing operations for the @e environment of | ||
26 | * PSYC and Social messages. | ||
27 | */ | ||
28 | |||
29 | #include "platform.h" | ||
30 | #include "gnunet_util_lib.h" | ||
31 | #include "gnunet_psyc_env.h" | ||
32 | |||
33 | /** | ||
34 | * Environment for a message. | ||
35 | * | ||
36 | * Contains modifiers. | ||
37 | */ | ||
38 | struct GNUNET_PSYC_Environment | ||
39 | { | ||
40 | struct GNUNET_PSYC_Modifier *mod_head; | ||
41 | struct GNUNET_PSYC_Modifier *mod_tail; | ||
42 | size_t mod_count; | ||
43 | }; | ||
44 | |||
45 | |||
46 | /** | ||
47 | * Create an environment. | ||
48 | * | ||
49 | * @return A newly allocated environment. | ||
50 | */ | ||
51 | struct GNUNET_PSYC_Environment * | ||
52 | GNUNET_PSYC_env_create () | ||
53 | { | ||
54 | return GNUNET_new (struct GNUNET_PSYC_Environment); | ||
55 | } | ||
56 | |||
57 | |||
58 | /** | ||
59 | * Add a modifier to the environment. | ||
60 | * | ||
61 | * @param env The environment. | ||
62 | * @param oper Operation to perform. | ||
63 | * @param name Name of the variable. | ||
64 | * @param value Value of the variable. | ||
65 | * @param value_size Size of @a value. | ||
66 | */ | ||
67 | void | ||
68 | GNUNET_PSYC_env_add (struct GNUNET_PSYC_Environment *env, | ||
69 | enum GNUNET_PSYC_Operator oper, const char *name, | ||
70 | const void *value, size_t value_size) | ||
71 | { | ||
72 | struct GNUNET_PSYC_Modifier *mod = GNUNET_new (struct GNUNET_PSYC_Modifier); | ||
73 | mod->oper = oper; | ||
74 | mod->name = name; | ||
75 | mod->value = value; | ||
76 | mod->value_size = value_size; | ||
77 | GNUNET_CONTAINER_DLL_insert_tail (env->mod_head, env->mod_tail, mod); | ||
78 | env->mod_count++; | ||
79 | } | ||
80 | |||
81 | |||
82 | /** | ||
83 | * Get the first modifier of the environment. | ||
84 | */ | ||
85 | struct GNUNET_PSYC_Modifier * | ||
86 | GNUNET_PSYC_env_head (const struct GNUNET_PSYC_Environment *env) | ||
87 | { | ||
88 | return env->mod_head; | ||
89 | } | ||
90 | |||
91 | |||
92 | /** | ||
93 | * Get the last modifier of the environment. | ||
94 | */ | ||
95 | struct GNUNET_PSYC_Modifier * | ||
96 | GNUNET_PSYC_env_tail (const struct GNUNET_PSYC_Environment *env) | ||
97 | { | ||
98 | return env->mod_tail; | ||
99 | } | ||
100 | |||
101 | |||
102 | /** | ||
103 | * Remove a modifier from the environment. | ||
104 | */ | ||
105 | void | ||
106 | GNUNET_PSYC_env_remove (struct GNUNET_PSYC_Environment *env, | ||
107 | struct GNUNET_PSYC_Modifier *mod) | ||
108 | { | ||
109 | GNUNET_CONTAINER_DLL_remove (env->mod_head, env->mod_tail, mod); | ||
110 | } | ||
111 | |||
112 | |||
113 | /** | ||
114 | * Get the modifier at the beginning of an environment and remove it. | ||
115 | * | ||
116 | * @param env | ||
117 | * @param oper | ||
118 | * @param name | ||
119 | * @param value | ||
120 | * @param value_size | ||
121 | * | ||
122 | * @return | ||
123 | */ | ||
124 | int | ||
125 | GNUNET_PSYC_env_shift (struct GNUNET_PSYC_Environment *env, | ||
126 | enum GNUNET_PSYC_Operator *oper, const char **name, | ||
127 | const void **value, size_t *value_size) | ||
128 | { | ||
129 | if (NULL == env->mod_head) | ||
130 | return GNUNET_NO; | ||
131 | |||
132 | struct GNUNET_PSYC_Modifier *mod = env->mod_head; | ||
133 | *oper = mod->oper; | ||
134 | *name = mod->name; | ||
135 | *value = mod->value; | ||
136 | *value_size = mod->value_size; | ||
137 | |||
138 | GNUNET_CONTAINER_DLL_remove (env->mod_head, env->mod_tail, mod); | ||
139 | GNUNET_free (mod); | ||
140 | env->mod_count--; | ||
141 | |||
142 | return GNUNET_YES; | ||
143 | } | ||
144 | |||
145 | |||
146 | /** | ||
147 | * Iterate through all modifiers in the environment. | ||
148 | * | ||
149 | * @param env The environment. | ||
150 | * @param it Iterator. | ||
151 | * @param it_cls Closure for iterator. | ||
152 | */ | ||
153 | void | ||
154 | GNUNET_PSYC_env_iterate (const struct GNUNET_PSYC_Environment *env, | ||
155 | GNUNET_PSYC_Iterator it, void *it_cls) | ||
156 | { | ||
157 | struct GNUNET_PSYC_Modifier *mod; | ||
158 | for (mod = env->mod_head; NULL != mod; mod = mod->next) | ||
159 | it (it_cls, mod->oper, mod->name, mod->value, mod->value_size); | ||
160 | } | ||
161 | |||
162 | |||
163 | /** | ||
164 | * Get the number of modifiers in the environment. | ||
165 | * | ||
166 | * @param env The environment. | ||
167 | * | ||
168 | * @return Number of modifiers. | ||
169 | */ | ||
170 | size_t | ||
171 | GNUNET_PSYC_env_get_count (const struct GNUNET_PSYC_Environment *env) | ||
172 | { | ||
173 | return env->mod_count; | ||
174 | } | ||
175 | |||
176 | |||
177 | /** | ||
178 | * Destroy an environment. | ||
179 | * | ||
180 | * @param env The environment to destroy. | ||
181 | */ | ||
182 | void | ||
183 | GNUNET_PSYC_env_destroy (struct GNUNET_PSYC_Environment *env) | ||
184 | { | ||
185 | struct GNUNET_PSYC_Modifier *mod, *prev = NULL; | ||
186 | for (mod = env->mod_head; NULL != mod; mod = mod->next) | ||
187 | { | ||
188 | if (NULL != prev) | ||
189 | GNUNET_free (prev); | ||
190 | prev = mod; | ||
191 | } | ||
192 | if (NULL != prev) | ||
193 | GNUNET_free (prev); | ||
194 | |||
195 | GNUNET_free (env); | ||
196 | } | ||
diff --git a/src/psycutil/psyc_message.c b/src/psycutil/psyc_message.c deleted file mode 100644 index a03eff47f..000000000 --- a/src/psycutil/psyc_message.c +++ /dev/null | |||
@@ -1,1355 +0,0 @@ | |||
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 psycutil/psyc_message.c | ||
23 | * @brief PSYC utilities; receiving/transmitting/logging PSYC messages. | ||
24 | * @author Gabor X Toth | ||
25 | */ | ||
26 | |||
27 | #include <inttypes.h> | ||
28 | |||
29 | #include "platform.h" | ||
30 | #include "gnunet_util_lib.h" | ||
31 | #include "gnunet_psyc_util_lib.h" | ||
32 | #include "gnunet_psyc_service.h" | ||
33 | |||
34 | #define LOG(kind,...) GNUNET_log_from (kind, "psyc-util",__VA_ARGS__) | ||
35 | |||
36 | |||
37 | struct GNUNET_PSYC_TransmitHandle | ||
38 | { | ||
39 | /** | ||
40 | * Client connection to service. | ||
41 | */ | ||
42 | struct GNUNET_MQ_Handle *mq; | ||
43 | |||
44 | /** | ||
45 | * Message currently being received from the client. | ||
46 | */ | ||
47 | struct GNUNET_MessageHeader *msg; | ||
48 | |||
49 | /** | ||
50 | * Envelope for @a msg | ||
51 | */ | ||
52 | struct GNUNET_MQ_Envelope *env; | ||
53 | |||
54 | /** | ||
55 | * Callback to request next modifier from client. | ||
56 | */ | ||
57 | GNUNET_PSYC_TransmitNotifyModifier notify_mod; | ||
58 | |||
59 | /** | ||
60 | * Closure for the notify callbacks. | ||
61 | */ | ||
62 | void *notify_mod_cls; | ||
63 | |||
64 | /** | ||
65 | * Callback to request next data fragment from client. | ||
66 | */ | ||
67 | GNUNET_PSYC_TransmitNotifyData notify_data; | ||
68 | |||
69 | /** | ||
70 | * Closure for the notify callbacks. | ||
71 | */ | ||
72 | void *notify_data_cls; | ||
73 | |||
74 | /** | ||
75 | * Modifier of the environment that is currently being transmitted. | ||
76 | */ | ||
77 | struct GNUNET_PSYC_Modifier *mod; | ||
78 | |||
79 | /** | ||
80 | * | ||
81 | */ | ||
82 | const char *mod_value; | ||
83 | |||
84 | /** | ||
85 | * Number of bytes remaining to be transmitted from the current modifier value. | ||
86 | */ | ||
87 | uint32_t mod_value_remaining; | ||
88 | |||
89 | /** | ||
90 | * State of the current message being received from client. | ||
91 | */ | ||
92 | enum GNUNET_PSYC_MessageState state; | ||
93 | |||
94 | /** | ||
95 | * Number of PSYC_TRANSMIT_ACK messages we are still waiting for. | ||
96 | */ | ||
97 | uint8_t acks_pending; | ||
98 | |||
99 | /** | ||
100 | * Is transmission paused? | ||
101 | */ | ||
102 | uint8_t paused; | ||
103 | |||
104 | /** | ||
105 | * Are we currently transmitting a message? | ||
106 | */ | ||
107 | uint8_t in_transmit; | ||
108 | |||
109 | /** | ||
110 | * Notify callback is currently being called. | ||
111 | */ | ||
112 | uint8_t in_notify; | ||
113 | |||
114 | }; | ||
115 | |||
116 | |||
117 | |||
118 | struct GNUNET_PSYC_ReceiveHandle | ||
119 | { | ||
120 | /** | ||
121 | * Message callback. | ||
122 | */ | ||
123 | GNUNET_PSYC_MessageCallback message_cb; | ||
124 | |||
125 | /** | ||
126 | * Message part callback. | ||
127 | */ | ||
128 | GNUNET_PSYC_MessagePartCallback message_part_cb; | ||
129 | |||
130 | /** | ||
131 | * Closure for the callbacks. | ||
132 | */ | ||
133 | void *cb_cls; | ||
134 | |||
135 | /** | ||
136 | * ID of the message being received from the PSYC service. | ||
137 | */ | ||
138 | uint64_t message_id; | ||
139 | |||
140 | /** | ||
141 | * Public key of the slave from which a message is being received. | ||
142 | */ | ||
143 | struct GNUNET_CRYPTO_EcdsaPublicKey slave_pub_key; | ||
144 | |||
145 | /** | ||
146 | * State of the currently being received message from the PSYC service. | ||
147 | */ | ||
148 | enum GNUNET_PSYC_MessageState state; | ||
149 | |||
150 | /** | ||
151 | * Flags for the currently being received message from the PSYC service. | ||
152 | */ | ||
153 | enum GNUNET_PSYC_MessageFlags flags; | ||
154 | |||
155 | /** | ||
156 | * Expected value size for the modifier being received from the PSYC service. | ||
157 | */ | ||
158 | uint32_t mod_value_size_expected; | ||
159 | |||
160 | /** | ||
161 | * Actual value size for the modifier being received from the PSYC service. | ||
162 | */ | ||
163 | uint32_t mod_value_size; | ||
164 | }; | ||
165 | |||
166 | |||
167 | /**** Messages ****/ | ||
168 | |||
169 | |||
170 | /** | ||
171 | * Create a PSYC message. | ||
172 | * | ||
173 | * @param method_name | ||
174 | * PSYC method for the message. | ||
175 | * @param env | ||
176 | * Environment for the message. | ||
177 | * @param data | ||
178 | * Data payload for the message. | ||
179 | * @param data_size | ||
180 | * Size of @a data. | ||
181 | * | ||
182 | * @return Message header with size information, | ||
183 | * followed by the message parts. | ||
184 | */ | ||
185 | struct GNUNET_PSYC_Message * | ||
186 | GNUNET_PSYC_message_create (const char *method_name, | ||
187 | const struct GNUNET_PSYC_Environment *env, | ||
188 | const void *data, | ||
189 | size_t data_size) | ||
190 | { | ||
191 | struct GNUNET_PSYC_Modifier *mod = NULL; | ||
192 | struct GNUNET_PSYC_MessageMethod *pmeth = NULL; | ||
193 | struct GNUNET_PSYC_MessageModifier *pmod = NULL; | ||
194 | struct GNUNET_MessageHeader *pmsg = NULL; | ||
195 | uint16_t env_size = 0; | ||
196 | if (NULL != env) | ||
197 | { | ||
198 | mod = GNUNET_PSYC_env_head (env); | ||
199 | while (NULL != mod) | ||
200 | { | ||
201 | env_size += sizeof (*pmod) + strlen (mod->name) + 1 + mod->value_size; | ||
202 | mod = mod->next; | ||
203 | } | ||
204 | } | ||
205 | |||
206 | struct GNUNET_PSYC_Message *msg; | ||
207 | uint16_t method_name_size = strlen (method_name) + 1; | ||
208 | if (method_name_size == 1) | ||
209 | return NULL; | ||
210 | |||
211 | uint16_t msg_size = sizeof (*msg) /* header */ | ||
212 | + sizeof (*pmeth) + method_name_size /* method */ | ||
213 | + env_size /* modifiers */ | ||
214 | + ((0 < data_size) ? sizeof (*pmsg) + data_size : 0) /* data */ | ||
215 | + sizeof (*pmsg); /* end of message */ | ||
216 | msg = GNUNET_malloc (msg_size); | ||
217 | msg->header.size = htons (msg_size); | ||
218 | msg->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE); /* FIXME */ | ||
219 | |||
220 | pmeth = (struct GNUNET_PSYC_MessageMethod *) &msg[1]; | ||
221 | pmeth->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD); | ||
222 | pmeth->header.size = htons (sizeof (*pmeth) + method_name_size); | ||
223 | GNUNET_memcpy (&pmeth[1], method_name, method_name_size); | ||
224 | |||
225 | uint16_t p = sizeof (*msg) + sizeof (*pmeth) + method_name_size; | ||
226 | if (NULL != env) | ||
227 | { | ||
228 | mod = GNUNET_PSYC_env_head (env); | ||
229 | while (NULL != mod) | ||
230 | { | ||
231 | uint16_t mod_name_size = strlen (mod->name) + 1; | ||
232 | pmod = (struct GNUNET_PSYC_MessageModifier *) ((char *) msg + p); | ||
233 | pmod->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER); | ||
234 | pmod->header.size = sizeof (*pmod) + mod_name_size + mod->value_size; | ||
235 | p += pmod->header.size; | ||
236 | pmod->header.size = htons (pmod->header.size); | ||
237 | |||
238 | pmod->oper = mod->oper; | ||
239 | pmod->name_size = htons (mod_name_size); | ||
240 | pmod->value_size = htonl (mod->value_size); | ||
241 | |||
242 | GNUNET_memcpy (&pmod[1], mod->name, mod_name_size); | ||
243 | if (0 < mod->value_size) | ||
244 | GNUNET_memcpy ((char *) &pmod[1] + mod_name_size, mod->value, mod->value_size); | ||
245 | |||
246 | mod = mod->next; | ||
247 | } | ||
248 | } | ||
249 | |||
250 | if (0 < data_size) | ||
251 | { | ||
252 | pmsg = (struct GNUNET_MessageHeader *) ((char *) msg + p); | ||
253 | pmsg->size = sizeof (*pmsg) + data_size; | ||
254 | p += pmsg->size; | ||
255 | pmsg->size = htons (pmsg->size); | ||
256 | pmsg->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA); | ||
257 | GNUNET_memcpy (&pmsg[1], data, data_size); | ||
258 | } | ||
259 | |||
260 | pmsg = (struct GNUNET_MessageHeader *) ((char *) msg + p); | ||
261 | pmsg->size = htons (sizeof (*pmsg)); | ||
262 | pmsg->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END); | ||
263 | |||
264 | GNUNET_assert (p + sizeof (*pmsg) == msg_size); | ||
265 | return msg; | ||
266 | } | ||
267 | |||
268 | |||
269 | void | ||
270 | GNUNET_PSYC_log_message (enum GNUNET_ErrorType kind, | ||
271 | const struct GNUNET_MessageHeader *msg) | ||
272 | { | ||
273 | uint16_t size = ntohs (msg->size); | ||
274 | uint16_t type = ntohs (msg->type); | ||
275 | |||
276 | GNUNET_log (kind, | ||
277 | "Message of type %d and size %u:\n", | ||
278 | type, | ||
279 | size); | ||
280 | switch (type) | ||
281 | { | ||
282 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE: | ||
283 | { | ||
284 | const struct GNUNET_PSYC_MessageHeader *pmsg | ||
285 | = (const struct GNUNET_PSYC_MessageHeader *) msg; | ||
286 | GNUNET_log (kind, | ||
287 | "\tID: %" PRIu64 "\tflags: %x" PRIu32 "\n", | ||
288 | GNUNET_ntohll (pmsg->message_id), | ||
289 | ntohl (pmsg->flags)); | ||
290 | break; | ||
291 | } | ||
292 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD: | ||
293 | { | ||
294 | const struct GNUNET_PSYC_MessageMethod *meth | ||
295 | = (const struct GNUNET_PSYC_MessageMethod *) msg; | ||
296 | GNUNET_log (kind, | ||
297 | "\t%.*s\n", | ||
298 | (int) (size - sizeof (*meth)), | ||
299 | (const char *) &meth[1]); | ||
300 | break; | ||
301 | } | ||
302 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER: | ||
303 | { | ||
304 | const struct GNUNET_PSYC_MessageModifier *mod | ||
305 | = (const struct GNUNET_PSYC_MessageModifier *) msg; | ||
306 | uint16_t name_size = ntohs (mod->name_size); | ||
307 | char oper = ' ' < mod->oper ? mod->oper : ' '; | ||
308 | GNUNET_log (kind, | ||
309 | "\t%c%.*s\t%.*s\n", | ||
310 | oper, | ||
311 | (int) name_size, | ||
312 | (const char *) &mod[1], | ||
313 | (int) (size - sizeof (*mod) - name_size), | ||
314 | ((const char *) &mod[1]) + name_size); | ||
315 | break; | ||
316 | } | ||
317 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT: | ||
318 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA: | ||
319 | GNUNET_log (kind, | ||
320 | "\t%.*s\n", | ||
321 | (int) (size - sizeof (*msg)), | ||
322 | (const char *) &msg[1]); | ||
323 | break; | ||
324 | } | ||
325 | } | ||
326 | |||
327 | |||
328 | /**** Transmitting messages ****/ | ||
329 | |||
330 | |||
331 | /** | ||
332 | * Create a transmission handle. | ||
333 | */ | ||
334 | struct GNUNET_PSYC_TransmitHandle * | ||
335 | GNUNET_PSYC_transmit_create (struct GNUNET_MQ_Handle *mq) | ||
336 | { | ||
337 | struct GNUNET_PSYC_TransmitHandle *tmit = GNUNET_new (struct GNUNET_PSYC_TransmitHandle); | ||
338 | |||
339 | tmit->mq = mq; | ||
340 | return tmit; | ||
341 | } | ||
342 | |||
343 | |||
344 | /** | ||
345 | * Destroy a transmission handle. | ||
346 | */ | ||
347 | void | ||
348 | GNUNET_PSYC_transmit_destroy (struct GNUNET_PSYC_TransmitHandle *tmit) | ||
349 | { | ||
350 | GNUNET_free (tmit); | ||
351 | } | ||
352 | |||
353 | |||
354 | /** | ||
355 | * Queue a message part for transmission. | ||
356 | * | ||
357 | * The message part is added to the current message buffer. | ||
358 | * When this buffer is full, it is added to the transmission queue. | ||
359 | * | ||
360 | * @param tmit | ||
361 | * Transmission handle. | ||
362 | * @param msg | ||
363 | * Message part, or NULL. | ||
364 | * @param tmit_now | ||
365 | * Transmit message now, or wait for buffer to fill up? | ||
366 | * #GNUNET_YES or #GNUNET_NO. | ||
367 | */ | ||
368 | static void | ||
369 | transmit_queue_insert (struct GNUNET_PSYC_TransmitHandle *tmit, | ||
370 | const struct GNUNET_MessageHeader *msg, | ||
371 | uint8_t tmit_now) | ||
372 | { | ||
373 | uint16_t size = (NULL != msg) ? ntohs (msg->size) : 0; | ||
374 | |||
375 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
376 | "Queueing message part of type %u and size %u (tmit_now: %u)).\n", | ||
377 | NULL != msg ? ntohs (msg->type) : 0, size, tmit_now); | ||
378 | |||
379 | if (NULL != tmit->msg) | ||
380 | { | ||
381 | if (NULL == msg | ||
382 | || GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD < tmit->msg->size + size) | ||
383 | { | ||
384 | /* End of message or buffer is full, add it to transmission queue | ||
385 | * and start with empty buffer */ | ||
386 | tmit->msg->size = htons (tmit->msg->size); | ||
387 | GNUNET_MQ_send (tmit->mq, tmit->env); | ||
388 | tmit->env = NULL; | ||
389 | tmit->msg = NULL; | ||
390 | tmit->acks_pending++; | ||
391 | } | ||
392 | else | ||
393 | { | ||
394 | /* Message fits in current buffer, append */ | ||
395 | GNUNET_memcpy ((char *) tmit->msg + tmit->msg->size, msg, size); | ||
396 | tmit->msg->size += size; | ||
397 | } | ||
398 | } | ||
399 | |||
400 | if (NULL == tmit->msg && NULL != msg) | ||
401 | { | ||
402 | /* Empty buffer, copy over message. */ | ||
403 | tmit->env = GNUNET_MQ_msg_extra (tmit->msg, | ||
404 | GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD, | ||
405 | GNUNET_MESSAGE_TYPE_PSYC_MESSAGE); | ||
406 | /* store current message size in host byte order | ||
407 | * then later switch it to network byte order before sending */ | ||
408 | tmit->msg->size = sizeof (*tmit->msg) + size; | ||
409 | |||
410 | GNUNET_memcpy (&tmit->msg[1], msg, size); | ||
411 | } | ||
412 | |||
413 | if (NULL != tmit->msg | ||
414 | && (GNUNET_YES == tmit_now | ||
415 | || (GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD | ||
416 | < tmit->msg->size + sizeof (struct GNUNET_MessageHeader)))) | ||
417 | { | ||
418 | /* End of message or buffer is full, add it to transmission queue. */ | ||
419 | tmit->msg->size = htons (tmit->msg->size); | ||
420 | GNUNET_MQ_send (tmit->mq, tmit->env); | ||
421 | tmit->env = NULL; | ||
422 | tmit->msg = NULL; | ||
423 | tmit->acks_pending++; | ||
424 | } | ||
425 | } | ||
426 | |||
427 | |||
428 | /** | ||
429 | * Request data from client to transmit. | ||
430 | * | ||
431 | * @param tmit Transmission handle. | ||
432 | */ | ||
433 | static void | ||
434 | transmit_data (struct GNUNET_PSYC_TransmitHandle *tmit) | ||
435 | { | ||
436 | int notify_ret = GNUNET_YES; | ||
437 | uint16_t data_size = 0; | ||
438 | char data[GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD] = ""; | ||
439 | struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) data; | ||
440 | msg->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA); | ||
441 | |||
442 | if (NULL != tmit->notify_data) | ||
443 | { | ||
444 | data_size = GNUNET_PSYC_DATA_MAX_PAYLOAD; | ||
445 | tmit->in_notify = GNUNET_YES; | ||
446 | notify_ret = tmit->notify_data (tmit->notify_data_cls, &data_size, &msg[1]); | ||
447 | tmit->in_notify = GNUNET_NO; | ||
448 | } | ||
449 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
450 | "transmit_data (ret: %d, size: %u): %.*s\n", | ||
451 | notify_ret, data_size, data_size, &msg[1]); | ||
452 | switch (notify_ret) | ||
453 | { | ||
454 | case GNUNET_NO: | ||
455 | if (0 == data_size) | ||
456 | { | ||
457 | /* Transmission paused, nothing to send. */ | ||
458 | tmit->paused = GNUNET_YES; | ||
459 | return; | ||
460 | } | ||
461 | break; | ||
462 | |||
463 | case GNUNET_YES: | ||
464 | tmit->state = GNUNET_PSYC_MESSAGE_STATE_END; | ||
465 | break; | ||
466 | |||
467 | default: | ||
468 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
469 | "TransmitNotifyData callback returned error when requesting data.\n"); | ||
470 | |||
471 | tmit->state = GNUNET_PSYC_MESSAGE_STATE_CANCEL; | ||
472 | msg->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL); | ||
473 | msg->size = htons (sizeof (*msg)); | ||
474 | transmit_queue_insert (tmit, msg, GNUNET_YES); | ||
475 | tmit->in_transmit = GNUNET_NO; | ||
476 | return; | ||
477 | } | ||
478 | |||
479 | if (0 < data_size) | ||
480 | { | ||
481 | GNUNET_assert (data_size <= GNUNET_PSYC_DATA_MAX_PAYLOAD); | ||
482 | msg->size = htons (sizeof (*msg) + data_size); | ||
483 | transmit_queue_insert (tmit, msg, !notify_ret); | ||
484 | } | ||
485 | |||
486 | /* End of message. */ | ||
487 | if (GNUNET_YES == notify_ret) | ||
488 | { | ||
489 | msg->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END); | ||
490 | msg->size = htons (sizeof (*msg)); | ||
491 | transmit_queue_insert (tmit, msg, GNUNET_YES); | ||
492 | /* FIXME: wait for ACK before setting in_transmit to no */ | ||
493 | tmit->in_transmit = GNUNET_NO; | ||
494 | } | ||
495 | } | ||
496 | |||
497 | |||
498 | /** | ||
499 | * Request a modifier from a client to transmit. | ||
500 | * | ||
501 | * @param tmit Transmission handle. | ||
502 | */ | ||
503 | static void | ||
504 | transmit_mod (struct GNUNET_PSYC_TransmitHandle *tmit) | ||
505 | { | ||
506 | uint16_t max_data_size = 0; | ||
507 | uint16_t data_size = 0; | ||
508 | char data[GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD] = ""; | ||
509 | struct GNUNET_MessageHeader *msg = (struct GNUNET_MessageHeader *) data; | ||
510 | int notify_ret = GNUNET_YES; | ||
511 | |||
512 | switch (tmit->state) | ||
513 | { | ||
514 | case GNUNET_PSYC_MESSAGE_STATE_MODIFIER: | ||
515 | { | ||
516 | struct GNUNET_PSYC_MessageModifier *mod | ||
517 | = (struct GNUNET_PSYC_MessageModifier *) msg; | ||
518 | msg->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER); | ||
519 | msg->size = sizeof (struct GNUNET_PSYC_MessageModifier); | ||
520 | |||
521 | if (NULL != tmit->notify_mod) | ||
522 | { | ||
523 | max_data_size = GNUNET_PSYC_MODIFIER_MAX_PAYLOAD; | ||
524 | data_size = max_data_size; | ||
525 | tmit->in_notify = GNUNET_YES; | ||
526 | notify_ret = tmit->notify_mod (tmit->notify_mod_cls, &data_size, &mod[1], | ||
527 | &mod->oper, &mod->value_size); | ||
528 | tmit->in_notify = GNUNET_NO; | ||
529 | } | ||
530 | |||
531 | mod->name_size = strnlen ((char *) &mod[1], data_size) + 1; | ||
532 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
533 | "transmit_mod (ret: %d, size: %u + %u): %.*s\n", | ||
534 | notify_ret, mod->name_size, mod->value_size, data_size, &mod[1]); | ||
535 | if (mod->name_size < data_size) | ||
536 | { | ||
537 | tmit->mod_value_remaining | ||
538 | = mod->value_size - (data_size - mod->name_size); | ||
539 | mod->value_size = htonl (mod->value_size); | ||
540 | mod->name_size = htons (mod->name_size); | ||
541 | } | ||
542 | else if (0 < data_size) | ||
543 | { | ||
544 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got invalid modifier name.\n"); | ||
545 | notify_ret = GNUNET_SYSERR; | ||
546 | } | ||
547 | break; | ||
548 | } | ||
549 | case GNUNET_PSYC_MESSAGE_STATE_MOD_CONT: | ||
550 | { | ||
551 | msg->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT); | ||
552 | msg->size = sizeof (struct GNUNET_MessageHeader); | ||
553 | |||
554 | if (NULL != tmit->notify_mod) | ||
555 | { | ||
556 | max_data_size = GNUNET_PSYC_MOD_CONT_MAX_PAYLOAD; | ||
557 | data_size = max_data_size; | ||
558 | tmit->in_notify = GNUNET_YES; | ||
559 | notify_ret = tmit->notify_mod (tmit->notify_mod_cls, | ||
560 | &data_size, &msg[1], NULL, NULL); | ||
561 | tmit->in_notify = GNUNET_NO; | ||
562 | } | ||
563 | tmit->mod_value_remaining -= data_size; | ||
564 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
565 | "transmit_mod (ret: %d, size: %u): %.*s\n", | ||
566 | notify_ret, data_size, data_size, &msg[1]); | ||
567 | break; | ||
568 | } | ||
569 | default: | ||
570 | GNUNET_assert (0); | ||
571 | } | ||
572 | |||
573 | switch (notify_ret) | ||
574 | { | ||
575 | case GNUNET_NO: | ||
576 | if (0 == data_size) | ||
577 | { /* Transmission paused, nothing to send. */ | ||
578 | tmit->paused = GNUNET_YES; | ||
579 | return; | ||
580 | } | ||
581 | tmit->state | ||
582 | = (0 == tmit->mod_value_remaining) | ||
583 | ? GNUNET_PSYC_MESSAGE_STATE_MODIFIER | ||
584 | : GNUNET_PSYC_MESSAGE_STATE_MOD_CONT; | ||
585 | break; | ||
586 | |||
587 | case GNUNET_YES: /* End of modifiers. */ | ||
588 | GNUNET_assert (0 == tmit->mod_value_remaining); | ||
589 | break; | ||
590 | |||
591 | default: | ||
592 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
593 | "TransmitNotifyModifier callback returned with error.\n"); | ||
594 | |||
595 | tmit->state = GNUNET_PSYC_MESSAGE_STATE_CANCEL; | ||
596 | msg->type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL); | ||
597 | msg->size = htons (sizeof (*msg)); | ||
598 | transmit_queue_insert (tmit, msg, GNUNET_YES); | ||
599 | tmit->in_transmit = GNUNET_NO; | ||
600 | return; | ||
601 | } | ||
602 | |||
603 | if (0 < data_size) | ||
604 | { | ||
605 | GNUNET_assert (data_size <= max_data_size); | ||
606 | msg->size = htons (msg->size + data_size); | ||
607 | transmit_queue_insert (tmit, msg, GNUNET_NO); | ||
608 | } | ||
609 | |||
610 | if (GNUNET_YES == notify_ret) | ||
611 | { | ||
612 | tmit->state = GNUNET_PSYC_MESSAGE_STATE_DATA; | ||
613 | if (0 == tmit->acks_pending) | ||
614 | transmit_data (tmit); | ||
615 | } | ||
616 | else | ||
617 | { | ||
618 | transmit_mod (tmit); | ||
619 | } | ||
620 | } | ||
621 | |||
622 | |||
623 | int | ||
624 | transmit_notify_env (void *cls, uint16_t *data_size, void *data, uint8_t *oper, | ||
625 | uint32_t *full_value_size) | ||
626 | |||
627 | { | ||
628 | struct GNUNET_PSYC_TransmitHandle *tmit = cls; | ||
629 | uint16_t name_size = 0; | ||
630 | uint32_t value_size = 0; | ||
631 | const char *value = NULL; | ||
632 | |||
633 | if (NULL != oper) | ||
634 | { /* New modifier */ | ||
635 | if (NULL != tmit->mod) | ||
636 | tmit->mod = tmit->mod->next; | ||
637 | if (NULL == tmit->mod) | ||
638 | { /* No more modifiers, continue with data */ | ||
639 | *data_size = 0; | ||
640 | return GNUNET_YES; | ||
641 | } | ||
642 | |||
643 | GNUNET_assert (tmit->mod->value_size < UINT32_MAX); | ||
644 | *full_value_size = tmit->mod->value_size; | ||
645 | *oper = tmit->mod->oper; | ||
646 | name_size = strlen (tmit->mod->name) + 1; | ||
647 | |||
648 | if (name_size + tmit->mod->value_size <= *data_size) | ||
649 | { | ||
650 | value_size = tmit->mod->value_size; | ||
651 | *data_size = name_size + value_size; | ||
652 | } | ||
653 | else /* full modifier does not fit in data, continuation needed */ | ||
654 | { | ||
655 | value_size = *data_size - name_size; | ||
656 | tmit->mod_value = tmit->mod->value + value_size; | ||
657 | } | ||
658 | |||
659 | GNUNET_memcpy (data, tmit->mod->name, name_size); | ||
660 | GNUNET_memcpy ((char *)data + name_size, tmit->mod->value, value_size); | ||
661 | return GNUNET_NO; | ||
662 | } | ||
663 | else | ||
664 | { /* Modifier continuation */ | ||
665 | GNUNET_assert (NULL != tmit->mod_value && 0 < tmit->mod_value_remaining); | ||
666 | value = tmit->mod_value; | ||
667 | if (tmit->mod_value_remaining <= *data_size) | ||
668 | { | ||
669 | value_size = tmit->mod_value_remaining; | ||
670 | tmit->mod_value = NULL; | ||
671 | } | ||
672 | else | ||
673 | { | ||
674 | value_size = *data_size; | ||
675 | tmit->mod_value += value_size; | ||
676 | } | ||
677 | |||
678 | if (*data_size < value_size) | ||
679 | { | ||
680 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
681 | "Value in environment larger than buffer: %u < %zu\n", | ||
682 | *data_size, value_size); | ||
683 | *data_size = 0; | ||
684 | return GNUNET_NO; | ||
685 | } | ||
686 | |||
687 | *data_size = value_size; | ||
688 | GNUNET_memcpy (data, value, value_size); | ||
689 | return (NULL == tmit->mod_value) ? GNUNET_YES : GNUNET_NO; | ||
690 | } | ||
691 | } | ||
692 | |||
693 | |||
694 | /** | ||
695 | * Transmit a message. | ||
696 | * | ||
697 | * @param tmit | ||
698 | * Transmission handle. | ||
699 | * @param method_name | ||
700 | * Which method should be invoked. | ||
701 | * @param env | ||
702 | * Environment for the message. | ||
703 | * Should stay available until the first call to notify_data. | ||
704 | * Can be NULL if there are no modifiers or @a notify_mod is | ||
705 | * provided instead. | ||
706 | * @param notify_mod | ||
707 | * Function to call to obtain modifiers. | ||
708 | * Can be NULL if there are no modifiers or @a env is provided instead. | ||
709 | * @param notify_data | ||
710 | * Function to call to obtain fragments of the data. | ||
711 | * @param notify_cls | ||
712 | * Closure for @a notify_mod and @a notify_data. | ||
713 | * @param flags | ||
714 | * Flags for the message being transmitted. | ||
715 | * | ||
716 | * @return #GNUNET_OK if the transmission was started. | ||
717 | * #GNUNET_SYSERR if another transmission is already going on. | ||
718 | */ | ||
719 | int | ||
720 | GNUNET_PSYC_transmit_message (struct GNUNET_PSYC_TransmitHandle *tmit, | ||
721 | const char *method_name, | ||
722 | const struct GNUNET_PSYC_Environment *env, | ||
723 | GNUNET_PSYC_TransmitNotifyModifier notify_mod, | ||
724 | GNUNET_PSYC_TransmitNotifyData notify_data, | ||
725 | void *notify_cls, | ||
726 | uint32_t flags) | ||
727 | { | ||
728 | if (GNUNET_NO != tmit->in_transmit) | ||
729 | return GNUNET_SYSERR; | ||
730 | tmit->in_transmit = GNUNET_YES; | ||
731 | |||
732 | size_t size = strlen (method_name) + 1; | ||
733 | struct GNUNET_PSYC_MessageMethod *pmeth; | ||
734 | |||
735 | tmit->env = GNUNET_MQ_msg_extra (tmit->msg, | ||
736 | GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD, | ||
737 | GNUNET_MESSAGE_TYPE_PSYC_MESSAGE); | ||
738 | /* store current message size in host byte order | ||
739 | * then later switch it to network byte order before sending */ | ||
740 | tmit->msg->size = sizeof (*tmit->msg) + sizeof (*pmeth) + size; | ||
741 | |||
742 | if (NULL != notify_mod) | ||
743 | { | ||
744 | tmit->notify_mod = notify_mod; | ||
745 | tmit->notify_mod_cls = notify_cls; | ||
746 | } | ||
747 | else | ||
748 | { | ||
749 | tmit->notify_mod = &transmit_notify_env; | ||
750 | tmit->notify_mod_cls = tmit; | ||
751 | if (NULL != env) | ||
752 | { | ||
753 | struct GNUNET_PSYC_Modifier mod = {}; | ||
754 | mod.next = GNUNET_PSYC_env_head (env); | ||
755 | tmit->mod = &mod; | ||
756 | |||
757 | struct GNUNET_PSYC_Modifier *m = tmit->mod; | ||
758 | while (NULL != (m = m->next)) | ||
759 | { | ||
760 | if (m->oper != GNUNET_PSYC_OP_SET) | ||
761 | flags |= GNUNET_PSYC_MASTER_TRANSMIT_STATE_MODIFY; | ||
762 | } | ||
763 | } | ||
764 | else | ||
765 | { | ||
766 | tmit->mod = NULL; | ||
767 | } | ||
768 | } | ||
769 | |||
770 | pmeth = (struct GNUNET_PSYC_MessageMethod *) &tmit->msg[1]; | ||
771 | pmeth->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD); | ||
772 | pmeth->header.size = htons (sizeof (*pmeth) + size); | ||
773 | pmeth->flags = htonl (flags); | ||
774 | GNUNET_memcpy (&pmeth[1], method_name, size); | ||
775 | |||
776 | tmit->state = GNUNET_PSYC_MESSAGE_STATE_MODIFIER; | ||
777 | tmit->notify_data = notify_data; | ||
778 | tmit->notify_data_cls = notify_cls; | ||
779 | |||
780 | transmit_mod (tmit); | ||
781 | return GNUNET_OK; | ||
782 | } | ||
783 | |||
784 | |||
785 | /** | ||
786 | * Resume transmission. | ||
787 | * | ||
788 | * @param tmit Transmission handle. | ||
789 | */ | ||
790 | void | ||
791 | GNUNET_PSYC_transmit_resume (struct GNUNET_PSYC_TransmitHandle *tmit) | ||
792 | { | ||
793 | if (GNUNET_YES != tmit->in_transmit || GNUNET_NO != tmit->in_notify) | ||
794 | return; | ||
795 | |||
796 | if (0 == tmit->acks_pending) | ||
797 | { | ||
798 | tmit->paused = GNUNET_NO; | ||
799 | transmit_data (tmit); | ||
800 | } | ||
801 | } | ||
802 | |||
803 | |||
804 | /** | ||
805 | * Abort transmission request. | ||
806 | * | ||
807 | * @param tmit Transmission handle. | ||
808 | */ | ||
809 | void | ||
810 | GNUNET_PSYC_transmit_cancel (struct GNUNET_PSYC_TransmitHandle *tmit) | ||
811 | { | ||
812 | if (GNUNET_NO == tmit->in_transmit) | ||
813 | return; | ||
814 | |||
815 | tmit->state = GNUNET_PSYC_MESSAGE_STATE_CANCEL; | ||
816 | tmit->in_transmit = GNUNET_NO; | ||
817 | tmit->paused = GNUNET_NO; | ||
818 | |||
819 | /* FIXME */ | ||
820 | struct GNUNET_MessageHeader msg; | ||
821 | msg.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL); | ||
822 | msg.size = htons (sizeof (msg)); | ||
823 | transmit_queue_insert (tmit, &msg, GNUNET_YES); | ||
824 | } | ||
825 | |||
826 | |||
827 | /** | ||
828 | * Got acknowledgement of a transmitted message part, continue transmission. | ||
829 | * | ||
830 | * @param tmit Transmission handle. | ||
831 | */ | ||
832 | void | ||
833 | GNUNET_PSYC_transmit_got_ack (struct GNUNET_PSYC_TransmitHandle *tmit) | ||
834 | { | ||
835 | if (0 == tmit->acks_pending) | ||
836 | { | ||
837 | LOG (GNUNET_ERROR_TYPE_WARNING, "Ignoring extraneous message ACK\n"); | ||
838 | GNUNET_break (0); | ||
839 | return; | ||
840 | } | ||
841 | tmit->acks_pending--; | ||
842 | |||
843 | if (GNUNET_YES == tmit->paused) | ||
844 | return; | ||
845 | |||
846 | switch (tmit->state) | ||
847 | { | ||
848 | case GNUNET_PSYC_MESSAGE_STATE_MODIFIER: | ||
849 | case GNUNET_PSYC_MESSAGE_STATE_MOD_CONT: | ||
850 | transmit_mod (tmit); | ||
851 | break; | ||
852 | |||
853 | case GNUNET_PSYC_MESSAGE_STATE_DATA: | ||
854 | transmit_data (tmit); | ||
855 | break; | ||
856 | |||
857 | case GNUNET_PSYC_MESSAGE_STATE_END: | ||
858 | case GNUNET_PSYC_MESSAGE_STATE_CANCEL: | ||
859 | break; | ||
860 | |||
861 | default: | ||
862 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
863 | "Ignoring message ACK in state %u.\n", tmit->state); | ||
864 | } | ||
865 | } | ||
866 | |||
867 | |||
868 | /**** Receiving messages ****/ | ||
869 | |||
870 | |||
871 | /** | ||
872 | * Create handle for receiving messages. | ||
873 | */ | ||
874 | struct GNUNET_PSYC_ReceiveHandle * | ||
875 | GNUNET_PSYC_receive_create (GNUNET_PSYC_MessageCallback message_cb, | ||
876 | GNUNET_PSYC_MessagePartCallback message_part_cb, | ||
877 | void *cb_cls) | ||
878 | { | ||
879 | struct GNUNET_PSYC_ReceiveHandle *recv = GNUNET_malloc (sizeof (*recv)); | ||
880 | recv->message_cb = message_cb; | ||
881 | recv->message_part_cb = message_part_cb; | ||
882 | recv->cb_cls = cb_cls; | ||
883 | return recv; | ||
884 | } | ||
885 | |||
886 | |||
887 | /** | ||
888 | * Destroy handle for receiving messages. | ||
889 | */ | ||
890 | void | ||
891 | GNUNET_PSYC_receive_destroy (struct GNUNET_PSYC_ReceiveHandle *recv) | ||
892 | { | ||
893 | GNUNET_free (recv); | ||
894 | } | ||
895 | |||
896 | |||
897 | /** | ||
898 | * Reset stored data related to the last received message. | ||
899 | */ | ||
900 | void | ||
901 | GNUNET_PSYC_receive_reset (struct GNUNET_PSYC_ReceiveHandle *recv) | ||
902 | { | ||
903 | recv->state = GNUNET_PSYC_MESSAGE_STATE_START; | ||
904 | recv->flags = 0; | ||
905 | recv->message_id = 0; | ||
906 | recv->mod_value_size = 0; | ||
907 | recv->mod_value_size_expected = 0; | ||
908 | } | ||
909 | |||
910 | |||
911 | static void | ||
912 | recv_error (struct GNUNET_PSYC_ReceiveHandle *recv) | ||
913 | { | ||
914 | if (NULL != recv->message_part_cb) | ||
915 | recv->message_part_cb (recv->cb_cls, NULL, NULL); | ||
916 | |||
917 | if (NULL != recv->message_cb) | ||
918 | recv->message_cb (recv->cb_cls, NULL); | ||
919 | |||
920 | GNUNET_PSYC_receive_reset (recv); | ||
921 | } | ||
922 | |||
923 | |||
924 | /** | ||
925 | * Handle incoming PSYC message. | ||
926 | * | ||
927 | * @param recv Receive handle. | ||
928 | * @param msg The message. | ||
929 | * | ||
930 | * @return #GNUNET_OK on success, | ||
931 | * #GNUNET_SYSERR on receive error. | ||
932 | */ | ||
933 | int | ||
934 | GNUNET_PSYC_receive_message (struct GNUNET_PSYC_ReceiveHandle *recv, | ||
935 | const struct GNUNET_PSYC_MessageHeader *msg) | ||
936 | { | ||
937 | uint16_t size = ntohs (msg->header.size); | ||
938 | uint32_t flags = ntohl (msg->flags); | ||
939 | |||
940 | GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, | ||
941 | (struct GNUNET_MessageHeader *) msg); | ||
942 | |||
943 | if (GNUNET_PSYC_MESSAGE_STATE_START == recv->state) | ||
944 | { | ||
945 | recv->message_id = GNUNET_ntohll (msg->message_id); | ||
946 | recv->flags = flags; | ||
947 | recv->slave_pub_key = msg->slave_pub_key; | ||
948 | recv->mod_value_size = 0; | ||
949 | recv->mod_value_size_expected = 0; | ||
950 | } | ||
951 | else if (GNUNET_ntohll (msg->message_id) != recv->message_id) | ||
952 | { | ||
953 | // FIXME | ||
954 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
955 | "Unexpected message ID. Got: %" PRIu64 ", expected: %" PRIu64 "\n", | ||
956 | GNUNET_ntohll (msg->message_id), recv->message_id); | ||
957 | GNUNET_break_op (0); | ||
958 | recv_error (recv); | ||
959 | return GNUNET_SYSERR; | ||
960 | } | ||
961 | else if (flags != recv->flags) | ||
962 | { | ||
963 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
964 | "Unexpected message flags. Got: %lu, expected: %lu\n", | ||
965 | flags, recv->flags); | ||
966 | GNUNET_break_op (0); | ||
967 | recv_error (recv); | ||
968 | return GNUNET_SYSERR; | ||
969 | } | ||
970 | |||
971 | uint16_t pos = 0, psize = 0, ptype, size_eq, size_min; | ||
972 | |||
973 | for (pos = 0; sizeof (*msg) + pos < size; pos += psize) | ||
974 | { | ||
975 | const struct GNUNET_MessageHeader *pmsg | ||
976 | = (const struct GNUNET_MessageHeader *) ((char *) &msg[1] + pos); | ||
977 | psize = ntohs (pmsg->size); | ||
978 | ptype = ntohs (pmsg->type); | ||
979 | size_eq = size_min = 0; | ||
980 | |||
981 | if (psize < sizeof (*pmsg) || sizeof (*msg) + pos + psize > size) | ||
982 | { | ||
983 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
984 | "Dropping message of type %u with invalid size %u.\n", | ||
985 | ptype, psize); | ||
986 | recv_error (recv); | ||
987 | return GNUNET_SYSERR; | ||
988 | } | ||
989 | |||
990 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
991 | "Received message part of type %u and size %u from PSYC.\n", | ||
992 | ptype, psize); | ||
993 | GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, pmsg); | ||
994 | |||
995 | switch (ptype) | ||
996 | { | ||
997 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD: | ||
998 | size_min = sizeof (struct GNUNET_PSYC_MessageMethod); | ||
999 | break; | ||
1000 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER: | ||
1001 | size_min = sizeof (struct GNUNET_PSYC_MessageModifier); | ||
1002 | break; | ||
1003 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT: | ||
1004 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA: | ||
1005 | size_min = sizeof (struct GNUNET_MessageHeader); | ||
1006 | break; | ||
1007 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END: | ||
1008 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL: | ||
1009 | size_eq = sizeof (struct GNUNET_MessageHeader); | ||
1010 | break; | ||
1011 | default: | ||
1012 | GNUNET_break_op (0); | ||
1013 | recv_error (recv); | ||
1014 | return GNUNET_SYSERR; | ||
1015 | } | ||
1016 | |||
1017 | if (! ((0 < size_eq && psize == size_eq) | ||
1018 | || (0 < size_min && size_min <= psize))) | ||
1019 | { | ||
1020 | GNUNET_break_op (0); | ||
1021 | recv_error (recv); | ||
1022 | return GNUNET_SYSERR; | ||
1023 | } | ||
1024 | |||
1025 | switch (ptype) | ||
1026 | { | ||
1027 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD: | ||
1028 | { | ||
1029 | struct GNUNET_PSYC_MessageMethod *meth | ||
1030 | = (struct GNUNET_PSYC_MessageMethod *) pmsg; | ||
1031 | |||
1032 | if (GNUNET_PSYC_MESSAGE_STATE_START != recv->state) | ||
1033 | { | ||
1034 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
1035 | "Dropping out of order message method (%u).\n", | ||
1036 | recv->state); | ||
1037 | /* It is normal to receive an incomplete message right after connecting, | ||
1038 | * but should not happen later. | ||
1039 | * FIXME: add a check for this condition. | ||
1040 | */ | ||
1041 | GNUNET_break_op (0); | ||
1042 | recv_error (recv); | ||
1043 | return GNUNET_SYSERR; | ||
1044 | } | ||
1045 | |||
1046 | if ('\0' != *((char *) meth + psize - 1)) | ||
1047 | { | ||
1048 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
1049 | "Dropping message with malformed method. " | ||
1050 | "Message ID: %" PRIu64 "\n", recv->message_id); | ||
1051 | GNUNET_break_op (0); | ||
1052 | recv_error (recv); | ||
1053 | return GNUNET_SYSERR; | ||
1054 | } | ||
1055 | recv->state = GNUNET_PSYC_MESSAGE_STATE_METHOD; | ||
1056 | break; | ||
1057 | } | ||
1058 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER: | ||
1059 | { | ||
1060 | if (!(GNUNET_PSYC_MESSAGE_STATE_METHOD == recv->state | ||
1061 | || GNUNET_PSYC_MESSAGE_STATE_MODIFIER == recv->state | ||
1062 | || GNUNET_PSYC_MESSAGE_STATE_MOD_CONT == recv->state)) | ||
1063 | { | ||
1064 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
1065 | "Dropping out of order message modifier (%u).\n", | ||
1066 | recv->state); | ||
1067 | GNUNET_break_op (0); | ||
1068 | recv_error (recv); | ||
1069 | return GNUNET_SYSERR; | ||
1070 | } | ||
1071 | |||
1072 | struct GNUNET_PSYC_MessageModifier *mod | ||
1073 | = (struct GNUNET_PSYC_MessageModifier *) pmsg; | ||
1074 | |||
1075 | uint16_t name_size = ntohs (mod->name_size); | ||
1076 | recv->mod_value_size_expected = ntohl (mod->value_size); | ||
1077 | recv->mod_value_size = psize - sizeof (*mod) - name_size; | ||
1078 | |||
1079 | if (psize < sizeof (*mod) + name_size | ||
1080 | || '\0' != *((char *) &mod[1] + name_size - 1) | ||
1081 | || recv->mod_value_size_expected < recv->mod_value_size) | ||
1082 | { | ||
1083 | LOG (GNUNET_ERROR_TYPE_WARNING, "Dropping malformed modifier.\n"); | ||
1084 | GNUNET_break_op (0); | ||
1085 | recv_error (recv); | ||
1086 | return GNUNET_SYSERR; | ||
1087 | } | ||
1088 | recv->state = GNUNET_PSYC_MESSAGE_STATE_MODIFIER; | ||
1089 | break; | ||
1090 | } | ||
1091 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT: | ||
1092 | { | ||
1093 | recv->mod_value_size += psize - sizeof (*pmsg); | ||
1094 | |||
1095 | if (!(GNUNET_PSYC_MESSAGE_STATE_MODIFIER == recv->state | ||
1096 | || GNUNET_PSYC_MESSAGE_STATE_MOD_CONT == recv->state) | ||
1097 | || recv->mod_value_size_expected < recv->mod_value_size) | ||
1098 | { | ||
1099 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
1100 | "Dropping out of order message modifier continuation " | ||
1101 | "!(%u == %u || %u == %u) || %lu < %lu.\n", | ||
1102 | GNUNET_PSYC_MESSAGE_STATE_MODIFIER, recv->state, | ||
1103 | GNUNET_PSYC_MESSAGE_STATE_MOD_CONT, recv->state, | ||
1104 | recv->mod_value_size_expected, recv->mod_value_size); | ||
1105 | GNUNET_break_op (0); | ||
1106 | recv_error (recv); | ||
1107 | return GNUNET_SYSERR; | ||
1108 | } | ||
1109 | break; | ||
1110 | } | ||
1111 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA: | ||
1112 | { | ||
1113 | if (recv->state < GNUNET_PSYC_MESSAGE_STATE_METHOD | ||
1114 | || recv->mod_value_size_expected != recv->mod_value_size) | ||
1115 | { | ||
1116 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
1117 | "Dropping out of order message data fragment " | ||
1118 | "(%u < %u || %lu != %lu).\n", | ||
1119 | recv->state, GNUNET_PSYC_MESSAGE_STATE_METHOD, | ||
1120 | recv->mod_value_size_expected, recv->mod_value_size); | ||
1121 | |||
1122 | GNUNET_break_op (0); | ||
1123 | recv_error (recv); | ||
1124 | return GNUNET_SYSERR; | ||
1125 | } | ||
1126 | recv->state = GNUNET_PSYC_MESSAGE_STATE_DATA; | ||
1127 | break; | ||
1128 | } | ||
1129 | } | ||
1130 | |||
1131 | if (NULL != recv->message_part_cb) | ||
1132 | recv->message_part_cb (recv->cb_cls, msg, pmsg); | ||
1133 | |||
1134 | switch (ptype) | ||
1135 | { | ||
1136 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END: | ||
1137 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL: | ||
1138 | GNUNET_PSYC_receive_reset (recv); | ||
1139 | break; | ||
1140 | } | ||
1141 | } | ||
1142 | |||
1143 | if (NULL != recv->message_cb) | ||
1144 | recv->message_cb (recv->cb_cls, msg); | ||
1145 | return GNUNET_OK; | ||
1146 | } | ||
1147 | |||
1148 | |||
1149 | /** | ||
1150 | * Check if @a data contains a series of valid message parts. | ||
1151 | * | ||
1152 | * @param data_size Size of @a data. | ||
1153 | * @param data Data. | ||
1154 | * @param[out] first_ptype Type of first message part. | ||
1155 | * @param[out] last_ptype Type of last message part. | ||
1156 | * | ||
1157 | * @return Number of message parts found in @a data. | ||
1158 | * or GNUNET_SYSERR if the message contains invalid parts. | ||
1159 | */ | ||
1160 | int | ||
1161 | GNUNET_PSYC_receive_check_parts (uint16_t data_size, const char *data, | ||
1162 | uint16_t *first_ptype, uint16_t *last_ptype) | ||
1163 | { | ||
1164 | const struct GNUNET_MessageHeader *pmsg; | ||
1165 | uint16_t parts = 0, ptype = 0, psize = 0, pos = 0; | ||
1166 | if (NULL != first_ptype) | ||
1167 | *first_ptype = 0; | ||
1168 | if (NULL != last_ptype) | ||
1169 | *last_ptype = 0; | ||
1170 | |||
1171 | for (pos = 0; pos < data_size; pos += psize, parts++) | ||
1172 | { | ||
1173 | pmsg = (const struct GNUNET_MessageHeader *) (data + pos); | ||
1174 | GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, pmsg); | ||
1175 | psize = ntohs (pmsg->size); | ||
1176 | ptype = ntohs (pmsg->type); | ||
1177 | if (0 == parts && NULL != first_ptype) | ||
1178 | *first_ptype = ptype; | ||
1179 | if (NULL != last_ptype | ||
1180 | && *last_ptype < GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END) | ||
1181 | *last_ptype = ptype; | ||
1182 | if (psize < sizeof (*pmsg) | ||
1183 | || pos + psize > data_size | ||
1184 | || ptype < GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD | ||
1185 | || GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL < ptype) | ||
1186 | { | ||
1187 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1188 | "Invalid message part of type %u and size %u.\n", | ||
1189 | ptype, psize); | ||
1190 | return GNUNET_SYSERR; | ||
1191 | } | ||
1192 | /** @todo FIXME: check message part order */ | ||
1193 | } | ||
1194 | return parts; | ||
1195 | } | ||
1196 | |||
1197 | |||
1198 | struct ParseMessageClosure | ||
1199 | { | ||
1200 | struct GNUNET_PSYC_Environment *env; | ||
1201 | const char **method_name; | ||
1202 | const void **data; | ||
1203 | uint16_t *data_size; | ||
1204 | enum GNUNET_PSYC_MessageState msg_state; | ||
1205 | }; | ||
1206 | |||
1207 | |||
1208 | static void | ||
1209 | parse_message_part_cb (void *cls, | ||
1210 | const struct GNUNET_PSYC_MessageHeader *msg, | ||
1211 | const struct GNUNET_MessageHeader *pmsg) | ||
1212 | { | ||
1213 | struct ParseMessageClosure *pmc = cls; | ||
1214 | if (NULL == pmsg) | ||
1215 | { | ||
1216 | pmc->msg_state = GNUNET_PSYC_MESSAGE_STATE_ERROR; | ||
1217 | return; | ||
1218 | } | ||
1219 | |||
1220 | switch (ntohs (pmsg->type)) | ||
1221 | { | ||
1222 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD: | ||
1223 | { | ||
1224 | struct GNUNET_PSYC_MessageMethod * | ||
1225 | pmeth = (struct GNUNET_PSYC_MessageMethod *) pmsg; | ||
1226 | *pmc->method_name = (const char *) &pmeth[1]; | ||
1227 | pmc->msg_state = GNUNET_PSYC_MESSAGE_STATE_METHOD; | ||
1228 | break; | ||
1229 | } | ||
1230 | |||
1231 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER: | ||
1232 | { | ||
1233 | struct GNUNET_PSYC_MessageModifier * | ||
1234 | pmod = (struct GNUNET_PSYC_MessageModifier *) pmsg; | ||
1235 | |||
1236 | const char *name = (const char *) &pmod[1]; | ||
1237 | const void *value = name + ntohs (pmod->name_size); | ||
1238 | GNUNET_PSYC_env_add (pmc->env, pmod->oper, name, value, | ||
1239 | ntohl (pmod->value_size)); | ||
1240 | pmc->msg_state = GNUNET_PSYC_MESSAGE_STATE_MODIFIER; | ||
1241 | break; | ||
1242 | } | ||
1243 | |||
1244 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA: | ||
1245 | *pmc->data = &pmsg[1]; | ||
1246 | *pmc->data_size = ntohs (pmsg->size) - sizeof (*pmsg); | ||
1247 | pmc->msg_state = GNUNET_PSYC_MESSAGE_STATE_DATA; | ||
1248 | break; | ||
1249 | |||
1250 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END: | ||
1251 | pmc->msg_state = GNUNET_PSYC_MESSAGE_STATE_END; | ||
1252 | break; | ||
1253 | |||
1254 | default: | ||
1255 | pmc->msg_state = GNUNET_PSYC_MESSAGE_STATE_ERROR; | ||
1256 | } | ||
1257 | } | ||
1258 | |||
1259 | |||
1260 | /** | ||
1261 | * Parse PSYC message. | ||
1262 | * | ||
1263 | * @param msg | ||
1264 | * The PSYC message to parse. | ||
1265 | * @param[out] method_name | ||
1266 | * Pointer to the method name inside @a pmsg. | ||
1267 | * @param env | ||
1268 | * The environment for the message with a list of modifiers. | ||
1269 | * @param[out] data | ||
1270 | * Pointer to data inside @a msg. | ||
1271 | * @param[out] data_size | ||
1272 | * Size of @data is written here. | ||
1273 | * | ||
1274 | * @return #GNUNET_OK on success, | ||
1275 | * #GNUNET_SYSERR on parse error. | ||
1276 | */ | ||
1277 | int | ||
1278 | GNUNET_PSYC_message_parse (const struct GNUNET_PSYC_MessageHeader *msg, | ||
1279 | const char **method_name, | ||
1280 | struct GNUNET_PSYC_Environment *env, | ||
1281 | const void **data, | ||
1282 | uint16_t *data_size) | ||
1283 | { | ||
1284 | struct ParseMessageClosure cls; | ||
1285 | cls.env = env; | ||
1286 | cls.method_name = method_name; | ||
1287 | cls.data = data; | ||
1288 | cls.data_size = data_size; | ||
1289 | |||
1290 | struct GNUNET_PSYC_ReceiveHandle * | ||
1291 | recv = GNUNET_PSYC_receive_create (NULL, parse_message_part_cb, &cls); | ||
1292 | int ret = GNUNET_PSYC_receive_message (recv, msg); | ||
1293 | GNUNET_PSYC_receive_destroy (recv); | ||
1294 | |||
1295 | if (GNUNET_OK != ret) | ||
1296 | return GNUNET_SYSERR; | ||
1297 | |||
1298 | return (GNUNET_PSYC_MESSAGE_STATE_END == cls.msg_state) | ||
1299 | ? GNUNET_OK | ||
1300 | : GNUNET_NO; | ||
1301 | } | ||
1302 | |||
1303 | |||
1304 | /** | ||
1305 | * Initialize PSYC message header. | ||
1306 | */ | ||
1307 | void | ||
1308 | GNUNET_PSYC_message_header_init (struct GNUNET_PSYC_MessageHeader *pmsg, | ||
1309 | const struct GNUNET_MULTICAST_MessageHeader *mmsg, | ||
1310 | uint32_t flags) | ||
1311 | { | ||
1312 | uint16_t size = ntohs (mmsg->header.size); | ||
1313 | uint16_t psize = sizeof (*pmsg) + size - sizeof (*mmsg); | ||
1314 | |||
1315 | pmsg->header.size = htons (psize); | ||
1316 | pmsg->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE); | ||
1317 | pmsg->message_id = mmsg->message_id; | ||
1318 | pmsg->fragment_offset = mmsg->fragment_offset; | ||
1319 | pmsg->flags = htonl (flags); | ||
1320 | |||
1321 | GNUNET_memcpy (&pmsg[1], &mmsg[1], size - sizeof (*mmsg)); | ||
1322 | } | ||
1323 | |||
1324 | |||
1325 | /** | ||
1326 | * Create a new PSYC message header from a multicast message. | ||
1327 | */ | ||
1328 | struct GNUNET_PSYC_MessageHeader * | ||
1329 | GNUNET_PSYC_message_header_create (const struct GNUNET_MULTICAST_MessageHeader *mmsg, | ||
1330 | uint32_t flags) | ||
1331 | { | ||
1332 | struct GNUNET_PSYC_MessageHeader *pmsg; | ||
1333 | uint16_t size = ntohs (mmsg->header.size); | ||
1334 | uint16_t psize = sizeof (*pmsg) + size - sizeof (*mmsg); | ||
1335 | |||
1336 | pmsg = GNUNET_malloc (psize); | ||
1337 | GNUNET_PSYC_message_header_init (pmsg, mmsg, flags); | ||
1338 | return pmsg; | ||
1339 | } | ||
1340 | |||
1341 | |||
1342 | /** | ||
1343 | * Create a new PSYC message header from a PSYC message. | ||
1344 | */ | ||
1345 | struct GNUNET_PSYC_MessageHeader * | ||
1346 | GNUNET_PSYC_message_header_create_from_psyc (const struct GNUNET_PSYC_Message *msg) | ||
1347 | { | ||
1348 | uint16_t msg_size = ntohs (msg->header.size); | ||
1349 | struct GNUNET_PSYC_MessageHeader * | ||
1350 | pmsg = GNUNET_malloc (sizeof (*pmsg) + msg_size - sizeof (*msg)); | ||
1351 | pmsg->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE); | ||
1352 | pmsg->header.size = htons (sizeof (*pmsg) + msg_size - sizeof (*msg)); | ||
1353 | GNUNET_memcpy (&pmsg[1], &msg[1], msg_size - sizeof (*msg)); | ||
1354 | return pmsg; | ||
1355 | } | ||
diff --git a/src/psycutil/psyc_slicer.c b/src/psycutil/psyc_slicer.c deleted file mode 100644 index 9b25d8a4b..000000000 --- a/src/psycutil/psyc_slicer.c +++ /dev/null | |||
@@ -1,711 +0,0 @@ | |||
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 | * @author Gabor X Toth | ||
23 | * | ||
24 | * @file | ||
25 | * PSYC Slicer API | ||
26 | */ | ||
27 | |||
28 | #include <inttypes.h> | ||
29 | |||
30 | #include "platform.h" | ||
31 | #include "gnunet_util_lib.h" | ||
32 | #include "gnunet_psyc_util_lib.h" | ||
33 | |||
34 | #define LOG(kind,...) GNUNET_log_from (kind, "psyc-util-slicer",__VA_ARGS__) | ||
35 | |||
36 | |||
37 | /** | ||
38 | * Handle for a try-and-slice instance. | ||
39 | */ | ||
40 | struct GNUNET_PSYC_Slicer | ||
41 | { | ||
42 | /** | ||
43 | * Method handlers: H(method_name) -> SlicerMethodCallbacks | ||
44 | */ | ||
45 | struct GNUNET_CONTAINER_MultiHashMap *method_handlers; | ||
46 | |||
47 | /** | ||
48 | * Modifier handlers: H(modifier_name) -> SlicerModifierCallbacks | ||
49 | */ | ||
50 | struct GNUNET_CONTAINER_MultiHashMap *modifier_handlers; | ||
51 | |||
52 | /** | ||
53 | * Receive handle for incoming messages. | ||
54 | */ | ||
55 | struct GNUNET_PSYC_ReceiveHandle *recv; | ||
56 | |||
57 | /** | ||
58 | * Currently being processed message. | ||
59 | */ | ||
60 | const struct GNUNET_PSYC_MessageHeader *msg; | ||
61 | |||
62 | /** | ||
63 | * Currently being processed message part. | ||
64 | */ | ||
65 | const struct GNUNET_MessageHeader *pmsg; | ||
66 | |||
67 | /** | ||
68 | * ID of currently being received message. | ||
69 | */ | ||
70 | uint64_t message_id; | ||
71 | |||
72 | /** | ||
73 | * Fragment offset of currently being received message. | ||
74 | */ | ||
75 | uint64_t fragment_offset; | ||
76 | |||
77 | /** | ||
78 | * Flags of currently being received message. | ||
79 | */ | ||
80 | uint32_t flags; | ||
81 | |||
82 | /** | ||
83 | * Method name of currently being received message. | ||
84 | */ | ||
85 | char *method_name; | ||
86 | |||
87 | /** | ||
88 | * Name of currently processed modifier. | ||
89 | */ | ||
90 | char *mod_name; | ||
91 | |||
92 | /** | ||
93 | * Value of currently processed modifier. | ||
94 | */ | ||
95 | char *mod_value; | ||
96 | |||
97 | /** | ||
98 | * Public key of the nym the current message originates from. | ||
99 | */ | ||
100 | struct GNUNET_CRYPTO_EcdsaPublicKey nym_pub_key; | ||
101 | |||
102 | /** | ||
103 | * Size of @a method_name (including terminating \0). | ||
104 | */ | ||
105 | uint16_t method_name_size; | ||
106 | |||
107 | /** | ||
108 | * Size of @a modifier_name (including terminating \0). | ||
109 | */ | ||
110 | uint16_t mod_name_size; | ||
111 | |||
112 | /** | ||
113 | * Size of modifier value fragment. | ||
114 | */ | ||
115 | uint16_t mod_value_size; | ||
116 | |||
117 | /** | ||
118 | * Full size of modifier value. | ||
119 | */ | ||
120 | uint16_t mod_full_value_size; | ||
121 | |||
122 | /** | ||
123 | * Remaining bytes from the value of the current modifier. | ||
124 | */ | ||
125 | uint16_t mod_value_remaining; | ||
126 | |||
127 | /** | ||
128 | * Operator of currently processed modifier. | ||
129 | */ | ||
130 | uint8_t mod_oper; | ||
131 | }; | ||
132 | |||
133 | |||
134 | /** | ||
135 | * Callbacks for a slicer method handler. | ||
136 | */ | ||
137 | struct SlicerMethodCallbacks | ||
138 | { | ||
139 | GNUNET_PSYC_MessageCallback msg_cb; | ||
140 | GNUNET_PSYC_MethodCallback method_cb; | ||
141 | GNUNET_PSYC_ModifierCallback modifier_cb; | ||
142 | GNUNET_PSYC_DataCallback data_cb; | ||
143 | GNUNET_PSYC_EndOfMessageCallback eom_cb; | ||
144 | void *cls; | ||
145 | }; | ||
146 | |||
147 | |||
148 | struct SlicerMethodRemoveClosure | ||
149 | { | ||
150 | struct GNUNET_PSYC_Slicer *slicer; | ||
151 | struct SlicerMethodCallbacks rm_cbs; | ||
152 | }; | ||
153 | |||
154 | |||
155 | /** | ||
156 | * Callbacks for a slicer method handler. | ||
157 | */ | ||
158 | struct SlicerModifierCallbacks | ||
159 | { | ||
160 | GNUNET_PSYC_ModifierCallback modifier_cb; | ||
161 | void *cls; | ||
162 | }; | ||
163 | |||
164 | |||
165 | struct SlicerModifierRemoveClosure | ||
166 | { | ||
167 | struct GNUNET_PSYC_Slicer *slicer; | ||
168 | struct SlicerModifierCallbacks rm_cbs; | ||
169 | }; | ||
170 | |||
171 | |||
172 | /** | ||
173 | * Call a method handler for an incoming message part. | ||
174 | */ | ||
175 | static int | ||
176 | slicer_method_handler_notify (void *cls, const struct GNUNET_HashCode *key, | ||
177 | void *value) | ||
178 | { | ||
179 | struct GNUNET_PSYC_Slicer *slicer = cls; | ||
180 | const struct GNUNET_MessageHeader *pmsg = slicer->pmsg; | ||
181 | struct SlicerMethodCallbacks *cbs = value; | ||
182 | |||
183 | uint16_t ptype = ntohs (pmsg->type); | ||
184 | switch (ptype) | ||
185 | { | ||
186 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD: | ||
187 | { | ||
188 | if (NULL != cbs->msg_cb) | ||
189 | cbs->msg_cb (cbs->cls, slicer->msg); | ||
190 | if (NULL == cbs->method_cb) | ||
191 | break; | ||
192 | struct GNUNET_PSYC_MessageMethod * | ||
193 | meth = (struct GNUNET_PSYC_MessageMethod *) pmsg; | ||
194 | cbs->method_cb (cbs->cls, slicer->msg, meth, slicer->message_id, | ||
195 | slicer->method_name); | ||
196 | break; | ||
197 | } | ||
198 | |||
199 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER: | ||
200 | { | ||
201 | if (NULL == cbs->modifier_cb) | ||
202 | break; | ||
203 | struct GNUNET_PSYC_MessageModifier * | ||
204 | mod = (struct GNUNET_PSYC_MessageModifier *) pmsg; | ||
205 | cbs->modifier_cb (cbs->cls, slicer->msg, &mod->header, slicer->message_id, | ||
206 | mod->oper, (const char *) &mod[1], | ||
207 | (const void *) &mod[1] + ntohs (mod->name_size), | ||
208 | ntohs (mod->header.size) - sizeof (*mod) - ntohs (mod->name_size), | ||
209 | ntohs (mod->value_size)); | ||
210 | break; | ||
211 | } | ||
212 | |||
213 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT: | ||
214 | { | ||
215 | if (NULL == cbs->modifier_cb) | ||
216 | break; | ||
217 | cbs->modifier_cb (cbs->cls, slicer->msg, pmsg, slicer->message_id, | ||
218 | slicer->mod_oper, slicer->mod_name, &pmsg[1], | ||
219 | ntohs (pmsg->size) - sizeof (*pmsg), | ||
220 | slicer->mod_full_value_size); | ||
221 | break; | ||
222 | } | ||
223 | |||
224 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA: | ||
225 | { | ||
226 | if (NULL == cbs->data_cb) | ||
227 | break; | ||
228 | cbs->data_cb (cbs->cls, slicer->msg, pmsg, slicer->message_id, | ||
229 | &pmsg[1], ntohs (pmsg->size) - sizeof (*pmsg)); | ||
230 | break; | ||
231 | } | ||
232 | |||
233 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END: | ||
234 | if (NULL == cbs->eom_cb) | ||
235 | break; | ||
236 | cbs->eom_cb (cbs->cls, slicer->msg, pmsg, slicer->message_id, GNUNET_NO); | ||
237 | break; | ||
238 | |||
239 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL: | ||
240 | if (NULL == cbs->eom_cb) | ||
241 | break; | ||
242 | cbs->eom_cb (cbs->cls, slicer->msg, pmsg, slicer->message_id, GNUNET_YES); | ||
243 | break; | ||
244 | } | ||
245 | return GNUNET_YES; | ||
246 | } | ||
247 | |||
248 | |||
249 | /** | ||
250 | * Call a method handler for an incoming message part. | ||
251 | */ | ||
252 | static int | ||
253 | slicer_modifier_handler_notify (void *cls, const struct GNUNET_HashCode *key, | ||
254 | void *value) | ||
255 | { | ||
256 | struct GNUNET_PSYC_Slicer *slicer = cls; | ||
257 | struct SlicerModifierCallbacks *cbs = value; | ||
258 | |||
259 | cbs->modifier_cb (cbs->cls, slicer->msg, slicer->pmsg, slicer->message_id, | ||
260 | slicer->mod_oper, slicer->mod_name, slicer->mod_value, | ||
261 | slicer->mod_value_size, slicer->mod_full_value_size); | ||
262 | return GNUNET_YES; | ||
263 | } | ||
264 | |||
265 | |||
266 | /** | ||
267 | * Process an incoming message and call matching handlers. | ||
268 | * | ||
269 | * @param slicer | ||
270 | * The slicer to use. | ||
271 | * @param msg | ||
272 | * The message as it arrived from the network. | ||
273 | */ | ||
274 | void | ||
275 | GNUNET_PSYC_slicer_message (struct GNUNET_PSYC_Slicer *slicer, | ||
276 | const struct GNUNET_PSYC_MessageHeader *msg) | ||
277 | { | ||
278 | GNUNET_PSYC_receive_message (slicer->recv, msg); | ||
279 | } | ||
280 | |||
281 | |||
282 | /** | ||
283 | * Process an incoming message part and call matching handlers. | ||
284 | * | ||
285 | * @param cls | ||
286 | * Closure. | ||
287 | * @param message_id | ||
288 | * ID of the message. | ||
289 | * @param flags | ||
290 | * Flags for the message. | ||
291 | * @see enum GNUNET_PSYC_MessageFlags | ||
292 | * @param msg | ||
293 | * The message part. as it arrived from the network. | ||
294 | */ | ||
295 | void | ||
296 | GNUNET_PSYC_slicer_message_part (struct GNUNET_PSYC_Slicer *slicer, | ||
297 | const struct GNUNET_PSYC_MessageHeader *msg, | ||
298 | const struct GNUNET_MessageHeader *pmsg) | ||
299 | { | ||
300 | slicer->msg = msg; | ||
301 | slicer->pmsg = pmsg; | ||
302 | |||
303 | uint64_t message_id = GNUNET_ntohll (msg->message_id); | ||
304 | |||
305 | uint16_t ptype = ntohs (pmsg->type); | ||
306 | if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD == ptype) | ||
307 | { | ||
308 | struct GNUNET_PSYC_MessageMethod * | ||
309 | meth = (struct GNUNET_PSYC_MessageMethod *) pmsg; | ||
310 | slicer->method_name_size = ntohs (meth->header.size) - sizeof (*meth); | ||
311 | slicer->method_name = GNUNET_malloc (slicer->method_name_size); | ||
312 | GNUNET_memcpy (slicer->method_name, &meth[1], slicer->method_name_size); | ||
313 | slicer->message_id = message_id; | ||
314 | } | ||
315 | else | ||
316 | { | ||
317 | GNUNET_assert (message_id == slicer->message_id); | ||
318 | } | ||
319 | |||
320 | char *nym_str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&msg->slave_pub_key); | ||
321 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
322 | "Slicer received message of type %u and size %u, " | ||
323 | "with ID %" PRIu64 " and method %s from %s\n", | ||
324 | ptype, ntohs (pmsg->size), message_id, slicer->method_name, nym_str); | ||
325 | GNUNET_free (nym_str); | ||
326 | |||
327 | /* try-and-slice modifier */ | ||
328 | |||
329 | switch (ptype) | ||
330 | { | ||
331 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER: | ||
332 | { | ||
333 | struct GNUNET_PSYC_MessageModifier * | ||
334 | mod = (struct GNUNET_PSYC_MessageModifier *) pmsg; | ||
335 | slicer->mod_oper = mod->oper; | ||
336 | slicer->mod_name_size = ntohs (mod->name_size); | ||
337 | slicer->mod_name = GNUNET_malloc (slicer->mod_name_size); | ||
338 | GNUNET_memcpy (slicer->mod_name, &mod[1], slicer->mod_name_size); | ||
339 | slicer->mod_value = (char *) &mod[1] + slicer->mod_name_size; | ||
340 | slicer->mod_full_value_size = ntohs (mod->value_size); | ||
341 | slicer->mod_value_remaining = slicer->mod_full_value_size; | ||
342 | slicer->mod_value_size | ||
343 | = ntohs (mod->header.size) - sizeof (*mod) - slicer->mod_name_size; | ||
344 | // fall through | ||
345 | } | ||
346 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT: | ||
347 | if (ptype == GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT) | ||
348 | { | ||
349 | slicer->mod_value = (char *) &pmsg[1]; | ||
350 | slicer->mod_value_size = ntohs (pmsg->size) - sizeof (*pmsg); | ||
351 | } | ||
352 | slicer->mod_value_remaining -= slicer->mod_value_size; | ||
353 | char *name = GNUNET_malloc (slicer->mod_name_size); | ||
354 | GNUNET_memcpy (name, slicer->mod_name, slicer->mod_name_size); | ||
355 | do | ||
356 | { | ||
357 | struct GNUNET_HashCode key; | ||
358 | uint16_t name_len = strlen (name); | ||
359 | GNUNET_CRYPTO_hash (name, name_len, &key); | ||
360 | GNUNET_CONTAINER_multihashmap_get_multiple (slicer->modifier_handlers, &key, | ||
361 | slicer_modifier_handler_notify, | ||
362 | slicer); | ||
363 | char *p = strrchr (name, '_'); | ||
364 | if (NULL == p) | ||
365 | break; | ||
366 | *p = '\0'; | ||
367 | } while (1); | ||
368 | GNUNET_free (name); | ||
369 | } | ||
370 | |||
371 | /* try-and-slice method */ | ||
372 | |||
373 | char *name = GNUNET_malloc (slicer->method_name_size); | ||
374 | GNUNET_memcpy (name, slicer->method_name, slicer->method_name_size); | ||
375 | do | ||
376 | { | ||
377 | struct GNUNET_HashCode key; | ||
378 | uint16_t name_len = strlen (name); | ||
379 | GNUNET_CRYPTO_hash (name, name_len, &key); | ||
380 | GNUNET_CONTAINER_multihashmap_get_multiple (slicer->method_handlers, &key, | ||
381 | slicer_method_handler_notify, | ||
382 | slicer); | ||
383 | char *p = strrchr (name, '_'); | ||
384 | if (NULL == p) | ||
385 | break; | ||
386 | *p = '\0'; | ||
387 | } while (1); | ||
388 | GNUNET_free (name); | ||
389 | |||
390 | if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= ptype) | ||
391 | GNUNET_free (slicer->method_name); | ||
392 | |||
393 | if (0 == slicer->mod_value_remaining && NULL != slicer->mod_name) | ||
394 | { | ||
395 | GNUNET_free (slicer->mod_name); | ||
396 | slicer->mod_name = NULL; | ||
397 | slicer->mod_name_size = 0; | ||
398 | slicer->mod_value_size = 0; | ||
399 | slicer->mod_full_value_size = 0; | ||
400 | slicer->mod_oper = 0; | ||
401 | } | ||
402 | |||
403 | slicer->msg = NULL; | ||
404 | slicer->pmsg = NULL; | ||
405 | } | ||
406 | |||
407 | |||
408 | /** | ||
409 | * Create a try-and-slice instance. | ||
410 | * | ||
411 | * A slicer processes incoming messages and notifies callbacks about matching | ||
412 | * methods or modifiers encountered. | ||
413 | * | ||
414 | * @return A new try-and-slice construct. | ||
415 | */ | ||
416 | struct GNUNET_PSYC_Slicer * | ||
417 | GNUNET_PSYC_slicer_create (void) | ||
418 | { | ||
419 | struct GNUNET_PSYC_Slicer *slicer = GNUNET_malloc (sizeof (*slicer)); | ||
420 | slicer->method_handlers = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); | ||
421 | slicer->modifier_handlers = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); | ||
422 | slicer->recv = GNUNET_PSYC_receive_create (NULL, | ||
423 | (GNUNET_PSYC_MessagePartCallback) | ||
424 | GNUNET_PSYC_slicer_message_part, | ||
425 | slicer); | ||
426 | return slicer; | ||
427 | } | ||
428 | |||
429 | |||
430 | /** | ||
431 | * Add a method to the try-and-slice instance. | ||
432 | * | ||
433 | * The callbacks are called for messages with a matching @a method_name prefix. | ||
434 | * | ||
435 | * @param slicer | ||
436 | * The try-and-slice instance to extend. | ||
437 | * @param method_name | ||
438 | * Name of the given method, use empty string to match all. | ||
439 | * @param method_cb | ||
440 | * Method handler invoked upon a matching message. | ||
441 | * @param modifier_cb | ||
442 | * Modifier handler, invoked after @a method_cb | ||
443 | * for each modifier in the message. | ||
444 | * @param data_cb | ||
445 | * Data handler, invoked after @a modifier_cb for each data fragment. | ||
446 | * @param eom_cb | ||
447 | * Invoked upon reaching the end of a matching message. | ||
448 | * @param cls | ||
449 | * Closure for the callbacks. | ||
450 | */ | ||
451 | void | ||
452 | GNUNET_PSYC_slicer_method_add (struct GNUNET_PSYC_Slicer *slicer, | ||
453 | const char *method_name, | ||
454 | GNUNET_PSYC_MessageCallback msg_cb, | ||
455 | GNUNET_PSYC_MethodCallback method_cb, | ||
456 | GNUNET_PSYC_ModifierCallback modifier_cb, | ||
457 | GNUNET_PSYC_DataCallback data_cb, | ||
458 | GNUNET_PSYC_EndOfMessageCallback eom_cb, | ||
459 | void *cls) | ||
460 | { | ||
461 | struct GNUNET_HashCode key; | ||
462 | GNUNET_CRYPTO_hash (method_name, strlen (method_name), &key); | ||
463 | |||
464 | struct SlicerMethodCallbacks *cbs = GNUNET_malloc (sizeof (*cbs)); | ||
465 | cbs->msg_cb = msg_cb, | ||
466 | cbs->method_cb = method_cb; | ||
467 | cbs->modifier_cb = modifier_cb; | ||
468 | cbs->data_cb = data_cb; | ||
469 | cbs->eom_cb = eom_cb; | ||
470 | cbs->cls = cls; | ||
471 | |||
472 | GNUNET_CONTAINER_multihashmap_put (slicer->method_handlers, &key, cbs, | ||
473 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
474 | } | ||
475 | |||
476 | |||
477 | static int | ||
478 | slicer_method_remove (void *cls, const struct GNUNET_HashCode *key, void *value) | ||
479 | { | ||
480 | struct SlicerMethodRemoveClosure *rm_cls = cls; | ||
481 | struct GNUNET_PSYC_Slicer *slicer = rm_cls->slicer; | ||
482 | struct SlicerMethodCallbacks *rm_cbs = &rm_cls->rm_cbs; | ||
483 | struct SlicerMethodCallbacks *cbs = value; | ||
484 | |||
485 | if ((NULL == rm_cbs->msg_cb || cbs->msg_cb == rm_cbs->msg_cb) | ||
486 | && (NULL == rm_cbs->method_cb || cbs->method_cb == rm_cbs->method_cb) | ||
487 | && (NULL == rm_cbs->modifier_cb || cbs->modifier_cb == rm_cbs->modifier_cb) | ||
488 | && (NULL == rm_cbs->data_cb || cbs->data_cb == rm_cbs->data_cb) | ||
489 | && (NULL == rm_cbs->eom_cb || cbs->eom_cb == rm_cbs->eom_cb)) | ||
490 | { | ||
491 | GNUNET_CONTAINER_multihashmap_remove (slicer->method_handlers, key, cbs); | ||
492 | GNUNET_free (cbs); | ||
493 | return GNUNET_NO; | ||
494 | } | ||
495 | return GNUNET_YES; | ||
496 | } | ||
497 | |||
498 | |||
499 | /** | ||
500 | * Remove a registered method from the try-and-slice instance. | ||
501 | * | ||
502 | * Removes one matching handler registered with the given | ||
503 | * @a method_name and callbacks. | ||
504 | * | ||
505 | * @param slicer | ||
506 | * The try-and-slice instance. | ||
507 | * @param method_name | ||
508 | * Name of the method to remove. | ||
509 | * @param method_cb | ||
510 | * Method handler. | ||
511 | * @param modifier_cb | ||
512 | * Modifier handler. | ||
513 | * @param data_cb | ||
514 | * Data handler. | ||
515 | * @param eom_cb | ||
516 | * End of message handler. | ||
517 | * | ||
518 | * @return #GNUNET_OK if a method handler was removed, | ||
519 | * #GNUNET_NO if no handler matched the given method name and callbacks. | ||
520 | */ | ||
521 | int | ||
522 | GNUNET_PSYC_slicer_method_remove (struct GNUNET_PSYC_Slicer *slicer, | ||
523 | const char *method_name, | ||
524 | GNUNET_PSYC_MessageCallback msg_cb, | ||
525 | GNUNET_PSYC_MethodCallback method_cb, | ||
526 | GNUNET_PSYC_ModifierCallback modifier_cb, | ||
527 | GNUNET_PSYC_DataCallback data_cb, | ||
528 | GNUNET_PSYC_EndOfMessageCallback eom_cb) | ||
529 | { | ||
530 | struct GNUNET_HashCode key; | ||
531 | GNUNET_CRYPTO_hash (method_name, strlen (method_name), &key); | ||
532 | |||
533 | struct SlicerMethodRemoveClosure rm_cls; | ||
534 | rm_cls.slicer = slicer; | ||
535 | struct SlicerMethodCallbacks *rm_cbs = &rm_cls.rm_cbs; | ||
536 | rm_cbs->msg_cb = msg_cb; | ||
537 | rm_cbs->method_cb = method_cb; | ||
538 | rm_cbs->modifier_cb = modifier_cb; | ||
539 | rm_cbs->data_cb = data_cb; | ||
540 | rm_cbs->eom_cb = eom_cb; | ||
541 | |||
542 | return | ||
543 | (GNUNET_SYSERR | ||
544 | == GNUNET_CONTAINER_multihashmap_get_multiple (slicer->method_handlers, &key, | ||
545 | slicer_method_remove, | ||
546 | &rm_cls)) | ||
547 | ? GNUNET_NO | ||
548 | : GNUNET_OK; | ||
549 | } | ||
550 | |||
551 | |||
552 | /** | ||
553 | * Watch a place for changed objects. | ||
554 | * | ||
555 | * @param slicer | ||
556 | * The try-and-slice instance. | ||
557 | * @param object_filter | ||
558 | * Object prefix to match. | ||
559 | * @param modifier_cb | ||
560 | * Function to call when encountering a state modifier. | ||
561 | * @param cls | ||
562 | * Closure for callback. | ||
563 | */ | ||
564 | void | ||
565 | GNUNET_PSYC_slicer_modifier_add (struct GNUNET_PSYC_Slicer *slicer, | ||
566 | const char *object_filter, | ||
567 | GNUNET_PSYC_ModifierCallback modifier_cb, | ||
568 | void *cls) | ||
569 | { | ||
570 | struct SlicerModifierCallbacks *cbs = GNUNET_malloc (sizeof *cbs); | ||
571 | cbs->modifier_cb = modifier_cb; | ||
572 | cbs->cls = cls; | ||
573 | |||
574 | struct GNUNET_HashCode key; | ||
575 | GNUNET_CRYPTO_hash (object_filter, strlen (object_filter), &key); | ||
576 | GNUNET_CONTAINER_multihashmap_put (slicer->modifier_handlers, &key, cbs, | ||
577 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
578 | } | ||
579 | |||
580 | |||
581 | static int | ||
582 | slicer_modifier_remove (void *cls, const struct GNUNET_HashCode *key, void *value) | ||
583 | { | ||
584 | struct SlicerModifierRemoveClosure *rm_cls = cls; | ||
585 | struct GNUNET_PSYC_Slicer *slicer = rm_cls->slicer; | ||
586 | struct SlicerModifierCallbacks *rm_cbs = &rm_cls->rm_cbs; | ||
587 | struct SlicerModifierCallbacks *cbs = value; | ||
588 | |||
589 | if (cbs->modifier_cb == rm_cbs->modifier_cb) | ||
590 | { | ||
591 | GNUNET_CONTAINER_multihashmap_remove (slicer->modifier_handlers, key, cbs); | ||
592 | GNUNET_free (cbs); | ||
593 | return GNUNET_NO; | ||
594 | } | ||
595 | return GNUNET_YES; | ||
596 | } | ||
597 | |||
598 | |||
599 | /** | ||
600 | * Remove a registered modifier from the try-and-slice instance. | ||
601 | * | ||
602 | * Removes one matching handler registered with the given | ||
603 | * @a object_filter and @a modifier_cb. | ||
604 | * | ||
605 | * @param slicer | ||
606 | * The try-and-slice instance. | ||
607 | * @param object_filter | ||
608 | * Object prefix to match. | ||
609 | * @param modifier_cb | ||
610 | * Function to call when encountering a state modifier changes. | ||
611 | */ | ||
612 | int | ||
613 | GNUNET_PSYC_slicer_modifier_remove (struct GNUNET_PSYC_Slicer *slicer, | ||
614 | const char *object_filter, | ||
615 | GNUNET_PSYC_ModifierCallback modifier_cb) | ||
616 | { | ||
617 | struct GNUNET_HashCode key; | ||
618 | GNUNET_CRYPTO_hash (object_filter, strlen (object_filter), &key); | ||
619 | |||
620 | struct SlicerModifierRemoveClosure rm_cls; | ||
621 | rm_cls.slicer = slicer; | ||
622 | struct SlicerModifierCallbacks *rm_cbs = &rm_cls.rm_cbs; | ||
623 | rm_cbs->modifier_cb = modifier_cb; | ||
624 | |||
625 | return | ||
626 | (GNUNET_SYSERR | ||
627 | == GNUNET_CONTAINER_multihashmap_get_multiple (slicer->modifier_handlers, &key, | ||
628 | slicer_modifier_remove, | ||
629 | &rm_cls)) | ||
630 | ? GNUNET_NO | ||
631 | : GNUNET_OK; | ||
632 | } | ||
633 | |||
634 | |||
635 | static int | ||
636 | slicer_method_free (void *cls, const struct GNUNET_HashCode *key, void *value) | ||
637 | { | ||
638 | struct SlicerMethodCallbacks *cbs = value; | ||
639 | GNUNET_free (cbs); | ||
640 | return GNUNET_YES; | ||
641 | } | ||
642 | |||
643 | |||
644 | static int | ||
645 | slicer_modifier_free (void *cls, const struct GNUNET_HashCode *key, void *value) | ||
646 | { | ||
647 | struct SlicerModifierCallbacks *cbs = value; | ||
648 | GNUNET_free (cbs); | ||
649 | return GNUNET_YES; | ||
650 | } | ||
651 | |||
652 | |||
653 | /** | ||
654 | * Remove all registered method handlers. | ||
655 | * | ||
656 | * @param slicer | ||
657 | * Slicer to clear. | ||
658 | */ | ||
659 | void | ||
660 | GNUNET_PSYC_slicer_method_clear (struct GNUNET_PSYC_Slicer *slicer) | ||
661 | { | ||
662 | GNUNET_CONTAINER_multihashmap_iterate (slicer->method_handlers, | ||
663 | slicer_method_free, NULL); | ||
664 | GNUNET_CONTAINER_multihashmap_clear (slicer->method_handlers); | ||
665 | } | ||
666 | |||
667 | |||
668 | /** | ||
669 | * Remove all registered modifier handlers. | ||
670 | * | ||
671 | * @param slicer | ||
672 | * Slicer to clear. | ||
673 | */ | ||
674 | void | ||
675 | GNUNET_PSYC_slicer_modifier_clear (struct GNUNET_PSYC_Slicer *slicer) | ||
676 | { | ||
677 | GNUNET_CONTAINER_multihashmap_iterate (slicer->modifier_handlers, | ||
678 | slicer_modifier_free, NULL); | ||
679 | GNUNET_CONTAINER_multihashmap_clear (slicer->modifier_handlers); | ||
680 | } | ||
681 | |||
682 | |||
683 | /** | ||
684 | * Remove all registered method & modifier handlers. | ||
685 | * | ||
686 | * @param slicer | ||
687 | * Slicer to clear. | ||
688 | */ | ||
689 | void | ||
690 | GNUNET_PSYC_slicer_clear (struct GNUNET_PSYC_Slicer *slicer) | ||
691 | { | ||
692 | GNUNET_PSYC_slicer_method_clear (slicer); | ||
693 | GNUNET_PSYC_slicer_modifier_clear (slicer); | ||
694 | } | ||
695 | |||
696 | |||
697 | /** | ||
698 | * Destroy a given try-and-slice instance. | ||
699 | * | ||
700 | * @param slicer | ||
701 | * Slicer to destroy | ||
702 | */ | ||
703 | void | ||
704 | GNUNET_PSYC_slicer_destroy (struct GNUNET_PSYC_Slicer *slicer) | ||
705 | { | ||
706 | GNUNET_PSYC_slicer_clear (slicer); | ||
707 | GNUNET_CONTAINER_multihashmap_destroy (slicer->method_handlers); | ||
708 | GNUNET_CONTAINER_multihashmap_destroy (slicer->modifier_handlers); | ||
709 | GNUNET_PSYC_receive_destroy (slicer->recv); | ||
710 | GNUNET_free (slicer); | ||
711 | } | ||
diff --git a/src/psycutil/test_psyc_env.c b/src/psycutil/test_psyc_env.c deleted file mode 100644 index 432e15503..000000000 --- a/src/psycutil/test_psyc_env.c +++ /dev/null | |||
@@ -1,96 +0,0 @@ | |||
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 | * @author Gabor X Toth | ||
23 | * | ||
24 | * @file | ||
25 | * Tests for the environment library. | ||
26 | */ | ||
27 | |||
28 | #include "platform.h" | ||
29 | #include "gnunet_util_lib.h" | ||
30 | #include "gnunet_testing_lib.h" | ||
31 | #include "gnunet_psyc_util_lib.h" | ||
32 | |||
33 | struct GNUNET_PSYC_Modifier mods[] = { | ||
34 | { .oper = GNUNET_PSYC_OP_SET, | ||
35 | .name = "_foo", .value = "foo", .value_size = 3 }, | ||
36 | |||
37 | { .oper = GNUNET_PSYC_OP_ASSIGN, | ||
38 | .name = "_foo_bar", .value = "foo bar", .value_size = 7 }, | ||
39 | |||
40 | { .oper = GNUNET_PSYC_OP_AUGMENT, | ||
41 | .name = "_foo_bar_baz", .value = "foo bar baz", .value_size = 11 } | ||
42 | }; | ||
43 | |||
44 | struct ItCls | ||
45 | { | ||
46 | size_t n; | ||
47 | }; | ||
48 | |||
49 | int | ||
50 | iterator (void *cls, enum GNUNET_PSYC_Operator oper, | ||
51 | const char *name, const char *value, uint32_t value_size) | ||
52 | { | ||
53 | struct ItCls *it_cls = cls; | ||
54 | struct GNUNET_PSYC_Modifier *m = &mods[it_cls->n++]; | ||
55 | |||
56 | GNUNET_assert (oper == m->oper); | ||
57 | GNUNET_assert (value_size == m->value_size); | ||
58 | GNUNET_assert (0 == memcmp (name, m->name, strlen (m->name))); | ||
59 | GNUNET_assert (0 == memcmp (value, m->value, m->value_size)); | ||
60 | |||
61 | return GNUNET_YES; | ||
62 | } | ||
63 | |||
64 | int | ||
65 | main (int argc, char *argv[]) | ||
66 | { | ||
67 | GNUNET_log_setup ("test-env", "WARNING", NULL); | ||
68 | |||
69 | struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create (); | ||
70 | GNUNET_assert (NULL != env); | ||
71 | int i, len = 3; | ||
72 | |||
73 | for (i = 0; i < len; i++) | ||
74 | { | ||
75 | GNUNET_PSYC_env_add (env, mods[i].oper, mods[i].name, | ||
76 | mods[i].value, mods[i].value_size); | ||
77 | } | ||
78 | |||
79 | struct ItCls it_cls = { .n = 0 }; | ||
80 | GNUNET_PSYC_env_iterate (env, iterator, &it_cls); | ||
81 | GNUNET_assert (len == it_cls.n); | ||
82 | |||
83 | for (i = 0; i < len; i++) | ||
84 | { | ||
85 | enum GNUNET_PSYC_Operator oper; | ||
86 | const char *name; | ||
87 | const void *value; | ||
88 | size_t value_size; | ||
89 | GNUNET_PSYC_env_shift (env, &oper, &name, &value, &value_size); | ||
90 | GNUNET_assert (len - i - 1 == GNUNET_PSYC_env_get_count (env)); | ||
91 | } | ||
92 | |||
93 | GNUNET_PSYC_env_destroy (env); | ||
94 | |||
95 | return 0; | ||
96 | } | ||
diff --git a/src/social/.gitignore b/src/social/.gitignore deleted file mode 100644 index 875aa1105..000000000 --- a/src/social/.gitignore +++ /dev/null | |||
@@ -1,3 +0,0 @@ | |||
1 | gnunet-social | ||
2 | gnunet-service-social | ||
3 | test_social | ||
diff --git a/src/social/Makefile.am b/src/social/Makefile.am deleted file mode 100644 index 94a9ba108..000000000 --- a/src/social/Makefile.am +++ /dev/null | |||
@@ -1,79 +0,0 @@ | |||
1 | # This Makefile.am is in the public domain | ||
2 | AM_CPPFLAGS = -I$(top_srcdir)/src/include | ||
3 | |||
4 | pkgcfgdir= $(pkgdatadir)/config.d/ | ||
5 | |||
6 | libexecdir= $(pkglibdir)/libexec/ | ||
7 | |||
8 | pkgcfg_DATA = \ | ||
9 | social.conf | ||
10 | |||
11 | |||
12 | if MINGW | ||
13 | WINFLAGS = -Wl,--no-undefined -Wl,--export-all-symbols | ||
14 | endif | ||
15 | |||
16 | if USE_COVERAGE | ||
17 | AM_CFLAGS = --coverage -O0 | ||
18 | XLIB = -lgcov | ||
19 | endif | ||
20 | |||
21 | lib_LTLIBRARIES = libgnunetsocial.la | ||
22 | |||
23 | libgnunetsocial_la_SOURCES = \ | ||
24 | social_api.c social.h | ||
25 | libgnunetsocial_la_LIBADD = \ | ||
26 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
27 | $(top_builddir)/src/psycutil/libgnunetpsycutil.la \ | ||
28 | $(GN_LIBINTL) $(XLIB) | ||
29 | libgnunetsocial_la_LDFLAGS = \ | ||
30 | $(GN_LIB_LDFLAGS) $(WINFLAGS) \ | ||
31 | -version-info 0:0:0 | ||
32 | |||
33 | bin_PROGRAMS = \ | ||
34 | gnunet-social | ||
35 | |||
36 | libexec_PROGRAMS = \ | ||
37 | gnunet-service-social | ||
38 | |||
39 | gnunet_social_SOURCES = \ | ||
40 | gnunet-social.c | ||
41 | gnunet_social_LDADD = \ | ||
42 | libgnunetsocial.la \ | ||
43 | $(top_builddir)/src/psycutil/libgnunetpsycutil.la \ | ||
44 | $(top_builddir)/src/util/libgnunetutil.la | ||
45 | |||
46 | gnunet_service_social_SOURCES = \ | ||
47 | gnunet-service-social.c | ||
48 | gnunet_service_social_LDADD = \ | ||
49 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
50 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ | ||
51 | $(top_builddir)/src/psycutil/libgnunetpsycutil.la \ | ||
52 | $(top_builddir)/src/psyc/libgnunetpsyc.la \ | ||
53 | $(top_builddir)/src/identity/libgnunetidentity.la \ | ||
54 | $(top_builddir)/src/gns/libgnunetgns.la \ | ||
55 | $(top_builddir)/src/namestore/libgnunetnamestore.la \ | ||
56 | $(GN_LIBINTL) | ||
57 | |||
58 | |||
59 | if HAVE_TESTING | ||
60 | check_PROGRAMS = \ | ||
61 | test_social | ||
62 | endif | ||
63 | |||
64 | if ENABLE_TEST_RUN | ||
65 | AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME; | ||
66 | TESTS = $(check_PROGRAMS) | ||
67 | endif | ||
68 | |||
69 | test_social_SOURCES = \ | ||
70 | test_social.c | ||
71 | test_social_LDADD = \ | ||
72 | libgnunetsocial.la \ | ||
73 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
74 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
75 | $(top_builddir)/src/psycutil/libgnunetpsycutil.la \ | ||
76 | $(top_builddir)/src/identity/libgnunetidentity.la | ||
77 | |||
78 | EXTRA_DIST = \ | ||
79 | test_social.conf | ||
diff --git a/src/social/gnunet-service-social.c b/src/social/gnunet-service-social.c deleted file mode 100644 index 33fabae5d..000000000 --- a/src/social/gnunet-service-social.c +++ /dev/null | |||
@@ -1,3760 +0,0 @@ | |||
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 social/gnunet-service-social.c | ||
23 | * @brief Social service | ||
24 | * @author Gabor X Toth | ||
25 | */ | ||
26 | |||
27 | #include <inttypes.h> | ||
28 | #include <strings.h> | ||
29 | |||
30 | #include "platform.h" | ||
31 | #include "gnunet_util_lib.h" | ||
32 | #include "gnunet_constants.h" | ||
33 | #include "gnunet_protocols.h" | ||
34 | #include "gnunet_identity_service.h" | ||
35 | #include "gnunet_namestore_service.h" | ||
36 | #include "gnunet_gns_service.h" | ||
37 | #include "gnunet_statistics_service.h" | ||
38 | #include "gnunet_psyc_service.h" | ||
39 | #include "gnunet_psyc_util_lib.h" | ||
40 | #include "gnunet_social_service.h" | ||
41 | #include "social.h" | ||
42 | |||
43 | |||
44 | /** | ||
45 | * Handle to our current configuration. | ||
46 | */ | ||
47 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
48 | |||
49 | /** | ||
50 | * Service handle. | ||
51 | */ | ||
52 | static struct GNUNET_SERVICE_Handle *service; | ||
53 | |||
54 | /* Handles to other services */ | ||
55 | static struct GNUNET_IDENTITY_Handle *id; | ||
56 | static struct GNUNET_GNS_Handle *gns; | ||
57 | static struct GNUNET_NAMESTORE_Handle *namestore; | ||
58 | static struct GNUNET_STATISTICS_Handle *stats; | ||
59 | |||
60 | /** | ||
61 | * ID of this peer. | ||
62 | */ | ||
63 | static struct GNUNET_PeerIdentity this_peer; | ||
64 | |||
65 | /** | ||
66 | * All connected hosts. | ||
67 | * H(place_pub_key) -> struct Host | ||
68 | */ | ||
69 | static struct GNUNET_CONTAINER_MultiHashMap *hosts; | ||
70 | |||
71 | /** | ||
72 | * All connected guests. | ||
73 | * H(place_pub_key) -> struct Guest | ||
74 | */ | ||
75 | static struct GNUNET_CONTAINER_MultiHashMap *guests; | ||
76 | |||
77 | /** | ||
78 | * Connected guests per place. | ||
79 | * H(place_pub_key) -> ego_pub_key -> struct Guest | ||
80 | */ | ||
81 | static struct GNUNET_CONTAINER_MultiHashMap *place_guests; | ||
82 | |||
83 | /** | ||
84 | * Places entered as host or guest. | ||
85 | * H(place_pub_key) -> struct HostEnterRequest OR struct GuestEnterRequest | ||
86 | */ | ||
87 | static struct GNUNET_CONTAINER_MultiHashMap *places; | ||
88 | |||
89 | /** | ||
90 | * Places entered per application. | ||
91 | * H(app_id) -> H(place_pub_key) -> NULL | ||
92 | */ | ||
93 | static struct GNUNET_CONTAINER_MultiHashMap *apps_places; | ||
94 | |||
95 | /** | ||
96 | * Application subscriptions per place. | ||
97 | * H(place_pub_key) -> H(app_id) | ||
98 | */ | ||
99 | //static struct GNUNET_CONTAINER_MultiHashMap *places_apps; | ||
100 | |||
101 | /** | ||
102 | * Connected applications. | ||
103 | * H(app_id) -> struct Application | ||
104 | */ | ||
105 | static struct GNUNET_CONTAINER_MultiHashMap *apps; | ||
106 | |||
107 | /** | ||
108 | * All egos. | ||
109 | * H(ego_pub_key) -> struct Ego | ||
110 | */ | ||
111 | static struct GNUNET_CONTAINER_MultiHashMap *egos; | ||
112 | |||
113 | /** | ||
114 | * Directory for storing social data. | ||
115 | * Default: $GNUNET_DATA_HOME/social | ||
116 | */ | ||
117 | static char *dir_social; | ||
118 | |||
119 | /** | ||
120 | * Directory for storing place data. | ||
121 | * $dir_social/places | ||
122 | */ | ||
123 | static char *dir_places; | ||
124 | |||
125 | /** | ||
126 | * Directory for storing app data. | ||
127 | * $dir_social/apps | ||
128 | */ | ||
129 | static char *dir_apps; | ||
130 | |||
131 | |||
132 | /** | ||
133 | * Message fragment transmission queue. | ||
134 | */ | ||
135 | struct FragmentTransmitQueue | ||
136 | { | ||
137 | struct FragmentTransmitQueue *prev; | ||
138 | struct FragmentTransmitQueue *next; | ||
139 | |||
140 | struct GNUNET_SERVICE_Client *client; | ||
141 | |||
142 | /** | ||
143 | * Pointer to the next message part inside the data after this struct. | ||
144 | */ | ||
145 | struct GNUNET_MessageHeader *next_part; | ||
146 | |||
147 | /** | ||
148 | * Size of message. | ||
149 | */ | ||
150 | uint16_t size; | ||
151 | |||
152 | /** | ||
153 | * @see enum GNUNET_PSYC_MessageState | ||
154 | */ | ||
155 | uint8_t state; | ||
156 | |||
157 | /* Followed by one or more message parts. */ | ||
158 | }; | ||
159 | |||
160 | |||
161 | /** | ||
162 | * Message transmission queue. | ||
163 | */ | ||
164 | struct MessageTransmitQueue | ||
165 | { | ||
166 | struct MessageTransmitQueue *prev; | ||
167 | struct MessageTransmitQueue *next; | ||
168 | |||
169 | struct FragmentTransmitQueue *frags_head; | ||
170 | struct FragmentTransmitQueue *frags_tail; | ||
171 | |||
172 | struct GNUNET_SERVICE_Client *client; | ||
173 | }; | ||
174 | |||
175 | /** | ||
176 | * List of connected clients. | ||
177 | */ | ||
178 | struct ClientListItem | ||
179 | { | ||
180 | struct ClientListItem *prev; | ||
181 | struct ClientListItem *next; | ||
182 | |||
183 | struct GNUNET_SERVICE_Client *client; | ||
184 | }; | ||
185 | |||
186 | |||
187 | /** | ||
188 | * Common part of the client context for both a host and guest. | ||
189 | */ | ||
190 | struct Place | ||
191 | { | ||
192 | struct ClientListItem *clients_head; | ||
193 | struct ClientListItem *clients_tail; | ||
194 | |||
195 | struct MessageTransmitQueue *tmit_msgs_head; | ||
196 | struct MessageTransmitQueue *tmit_msgs_tail; | ||
197 | |||
198 | struct GNUNET_PSYC_Channel *channel; | ||
199 | |||
200 | /** | ||
201 | * Private key of home in case of a host. | ||
202 | */ | ||
203 | struct GNUNET_CRYPTO_EddsaPublicKey key; | ||
204 | |||
205 | /** | ||
206 | * Public key of place. | ||
207 | */ | ||
208 | struct GNUNET_CRYPTO_EddsaPublicKey pub_key; | ||
209 | |||
210 | /** | ||
211 | * Hash of @a pub_key. | ||
212 | */ | ||
213 | struct GNUNET_HashCode pub_key_hash; | ||
214 | |||
215 | /** | ||
216 | * Private key of ego. | ||
217 | */ | ||
218 | struct GNUNET_CRYPTO_EcdsaPrivateKey ego_key; | ||
219 | |||
220 | /** | ||
221 | * Public key of ego. | ||
222 | */ | ||
223 | struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key; | ||
224 | |||
225 | /** | ||
226 | * Hash of @a ego_pub_key. | ||
227 | */ | ||
228 | struct GNUNET_HashCode ego_pub_hash; | ||
229 | |||
230 | /** | ||
231 | * Slicer for processing incoming messages. | ||
232 | */ | ||
233 | struct GNUNET_PSYC_Slicer *slicer; | ||
234 | |||
235 | /** | ||
236 | * Last message ID received for the place. | ||
237 | * 0 if there is no such message. | ||
238 | */ | ||
239 | uint64_t max_message_id; | ||
240 | |||
241 | /** | ||
242 | * Offset where the file is currently being written. | ||
243 | */ | ||
244 | uint64_t file_offset; | ||
245 | |||
246 | /** | ||
247 | * Whether or not to save the file (#GNUNET_YES or #GNUNET_NO) | ||
248 | */ | ||
249 | uint8_t file_save; | ||
250 | |||
251 | /** | ||
252 | * Is this place ready to receive messages from client? | ||
253 | * #GNUNET_YES or #GNUNET_NO | ||
254 | */ | ||
255 | uint8_t is_ready; | ||
256 | |||
257 | /** | ||
258 | * Is the client disconnecting? | ||
259 | * #GNUNET_YES or #GNUNET_NO | ||
260 | */ | ||
261 | uint8_t is_disconnecting; | ||
262 | |||
263 | /** | ||
264 | * Is this a host (#GNUNET_YES), or guest (#GNUNET_NO)? | ||
265 | */ | ||
266 | uint8_t is_host; | ||
267 | |||
268 | union { | ||
269 | struct Host *host; | ||
270 | struct Guest *guest; | ||
271 | }; | ||
272 | }; | ||
273 | |||
274 | |||
275 | /** | ||
276 | * Client context for a host. | ||
277 | */ | ||
278 | struct Host | ||
279 | { | ||
280 | /** | ||
281 | * Place struct common for Host and Guest | ||
282 | */ | ||
283 | struct Place place; | ||
284 | |||
285 | /** | ||
286 | * Handle for the multicast origin. | ||
287 | */ | ||
288 | struct GNUNET_PSYC_Master *master; | ||
289 | |||
290 | /** | ||
291 | * Transmit handle for multicast. | ||
292 | */ | ||
293 | struct GNUNET_PSYC_MasterTransmitHandle *tmit_handle; | ||
294 | |||
295 | /** | ||
296 | * Incoming join requests. | ||
297 | * guest_key -> struct GNUNET_PSYC_JoinHandle * | ||
298 | */ | ||
299 | struct GNUNET_CONTAINER_MultiHashMap *join_reqs; | ||
300 | |||
301 | /** | ||
302 | * Messages being relayed. | ||
303 | */ | ||
304 | struct GNUNET_CONTAINER_MultiHashMap *relay_msgs; | ||
305 | |||
306 | /** | ||
307 | * @see enum GNUNET_PSYC_Policy | ||
308 | */ | ||
309 | enum GNUNET_PSYC_Policy policy; | ||
310 | }; | ||
311 | |||
312 | |||
313 | /** | ||
314 | * Client context for a guest. | ||
315 | */ | ||
316 | struct Guest | ||
317 | { | ||
318 | /** | ||
319 | * Place struct common for Host and Guest. | ||
320 | */ | ||
321 | struct Place place; | ||
322 | |||
323 | /** | ||
324 | * Handle for the PSYC slave. | ||
325 | */ | ||
326 | struct GNUNET_PSYC_Slave *slave; | ||
327 | |||
328 | /** | ||
329 | * Transmit handle for multicast. | ||
330 | */ | ||
331 | struct GNUNET_PSYC_SlaveTransmitHandle *tmit_handle; | ||
332 | |||
333 | /** | ||
334 | * Peer identity of the origin. | ||
335 | */ | ||
336 | struct GNUNET_PeerIdentity origin; | ||
337 | |||
338 | /** | ||
339 | * Number of items in @a relays. | ||
340 | */ | ||
341 | uint32_t relay_count; | ||
342 | |||
343 | /** | ||
344 | * Relays that multicast can use to connect. | ||
345 | */ | ||
346 | struct GNUNET_PeerIdentity *relays; | ||
347 | |||
348 | /** | ||
349 | * Join request to be transmitted to the master on join. | ||
350 | */ | ||
351 | struct GNUNET_MessageHeader *join_req; // FIXME: not used! | ||
352 | |||
353 | /** | ||
354 | * Join decision received from PSYC. | ||
355 | */ | ||
356 | struct GNUNET_PSYC_JoinDecisionMessage *join_dcsn; | ||
357 | |||
358 | /** | ||
359 | * Join flags for the PSYC service. | ||
360 | */ | ||
361 | enum GNUNET_PSYC_SlaveJoinFlags join_flags; | ||
362 | }; | ||
363 | |||
364 | |||
365 | /** | ||
366 | * Context for a client. | ||
367 | */ | ||
368 | struct Client | ||
369 | { | ||
370 | /** | ||
371 | * Client handle. | ||
372 | */ | ||
373 | struct GNUNET_SERVICE_Client *client; | ||
374 | |||
375 | /** | ||
376 | * Place where the client entered. | ||
377 | */ | ||
378 | struct Place *place; | ||
379 | |||
380 | /** | ||
381 | * Message queue for the message currently being transmitted | ||
382 | * by this client. | ||
383 | */ | ||
384 | struct MessageTransmitQueue *tmit_msg; | ||
385 | |||
386 | /** | ||
387 | * ID for application clients. | ||
388 | */ | ||
389 | char *app_id; | ||
390 | }; | ||
391 | |||
392 | |||
393 | struct Application | ||
394 | { | ||
395 | struct ClientListItem *clients_head; | ||
396 | struct ClientListItem *clients_tail; | ||
397 | }; | ||
398 | |||
399 | |||
400 | struct Ego { | ||
401 | struct GNUNET_CRYPTO_EcdsaPrivateKey key; | ||
402 | char *name; | ||
403 | }; | ||
404 | |||
405 | |||
406 | struct OperationClosure | ||
407 | { | ||
408 | struct Client *client; | ||
409 | uint64_t op_id; | ||
410 | uint32_t flags; | ||
411 | }; | ||
412 | |||
413 | |||
414 | static int | ||
415 | psyc_transmit_message (struct Place *plc); | ||
416 | |||
417 | |||
418 | /** | ||
419 | * Clean up place data structures after a client disconnected. | ||
420 | * | ||
421 | * @param cls the `struct Place` to clean up | ||
422 | */ | ||
423 | static void | ||
424 | cleanup_place (void *cls); | ||
425 | |||
426 | |||
427 | static struct MessageTransmitQueue * | ||
428 | psyc_transmit_queue_message (struct Place *plc, | ||
429 | struct GNUNET_SERVICE_Client *client, | ||
430 | size_t data_size, | ||
431 | const void *data, | ||
432 | uint16_t first_ptype, uint16_t last_ptype, | ||
433 | struct MessageTransmitQueue *tmit_msg); | ||
434 | |||
435 | |||
436 | static int | ||
437 | place_entry_cleanup (void *cls, | ||
438 | const struct GNUNET_HashCode *key, | ||
439 | void *value) | ||
440 | { | ||
441 | struct Place *plc = value; | ||
442 | |||
443 | cleanup_place (plc); | ||
444 | return GNUNET_YES; | ||
445 | } | ||
446 | |||
447 | |||
448 | /** | ||
449 | * Task run during shutdown. | ||
450 | * | ||
451 | * @param cls unused | ||
452 | */ | ||
453 | static void | ||
454 | shutdown_task (void *cls) | ||
455 | { | ||
456 | GNUNET_CONTAINER_multihashmap_iterate (hosts, place_entry_cleanup, NULL); | ||
457 | GNUNET_CONTAINER_multihashmap_iterate (guests, place_entry_cleanup, NULL); | ||
458 | |||
459 | if (NULL != id) | ||
460 | { | ||
461 | GNUNET_IDENTITY_disconnect (id); | ||
462 | id = NULL; | ||
463 | } | ||
464 | if (NULL != namestore) | ||
465 | { | ||
466 | GNUNET_NAMESTORE_disconnect (namestore); | ||
467 | namestore = NULL; | ||
468 | } | ||
469 | if (NULL != gns) | ||
470 | { | ||
471 | GNUNET_GNS_disconnect (gns); | ||
472 | gns = NULL; | ||
473 | } | ||
474 | if (NULL != stats) | ||
475 | { | ||
476 | GNUNET_STATISTICS_destroy (stats, GNUNET_YES); | ||
477 | stats = NULL; | ||
478 | } | ||
479 | } | ||
480 | |||
481 | |||
482 | /** | ||
483 | * Clean up host data structures after a client disconnected. | ||
484 | */ | ||
485 | static void | ||
486 | cleanup_host (struct Host *hst) | ||
487 | { | ||
488 | struct Place *plc = &hst->place; | ||
489 | |||
490 | GNUNET_CONTAINER_multihashmap_destroy (hst->join_reqs); | ||
491 | GNUNET_CONTAINER_multihashmap_destroy (hst->relay_msgs); | ||
492 | GNUNET_CONTAINER_multihashmap_remove (hosts, &plc->pub_key_hash, plc); | ||
493 | } | ||
494 | |||
495 | |||
496 | /** | ||
497 | * Clean up guest data structures after a client disconnected. | ||
498 | */ | ||
499 | static void | ||
500 | cleanup_guest (struct Guest *gst) | ||
501 | { | ||
502 | struct Place *plc = &gst->place; | ||
503 | struct GNUNET_CONTAINER_MultiHashMap * | ||
504 | plc_gst = GNUNET_CONTAINER_multihashmap_get (place_guests, | ||
505 | &plc->pub_key_hash); | ||
506 | if (NULL != plc_gst) | ||
507 | { | ||
508 | GNUNET_CONTAINER_multihashmap_remove (plc_gst, &plc->ego_pub_hash, gst); | ||
509 | |||
510 | if (0 == GNUNET_CONTAINER_multihashmap_size (plc_gst)) | ||
511 | { | ||
512 | GNUNET_CONTAINER_multihashmap_remove (place_guests, &plc->pub_key_hash, | ||
513 | plc_gst); | ||
514 | GNUNET_CONTAINER_multihashmap_destroy (plc_gst); | ||
515 | } | ||
516 | } | ||
517 | GNUNET_CONTAINER_multihashmap_remove (guests, &plc->pub_key_hash, gst); | ||
518 | if (NULL != gst->join_req) | ||
519 | GNUNET_free (gst->join_req); | ||
520 | if (NULL != gst->relays) | ||
521 | GNUNET_free (gst->relays); | ||
522 | GNUNET_CONTAINER_multihashmap_remove (guests, &plc->pub_key_hash, plc); | ||
523 | } | ||
524 | |||
525 | |||
526 | /** | ||
527 | * Clean up place data structures after a client disconnected. | ||
528 | * | ||
529 | * @param cls the `struct Place` to clean up | ||
530 | */ | ||
531 | static void | ||
532 | cleanup_place (void *cls) | ||
533 | { | ||
534 | struct Place *plc = cls; | ||
535 | |||
536 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
537 | "cleaning up place %s\n", | ||
538 | GNUNET_h2s (&plc->pub_key_hash)); | ||
539 | |||
540 | (GNUNET_YES == plc->is_host) | ||
541 | ? cleanup_host ((struct Host *) plc) | ||
542 | : cleanup_guest ((struct Guest *) plc); | ||
543 | |||
544 | GNUNET_PSYC_slicer_destroy (plc->slicer); | ||
545 | GNUNET_free (plc); | ||
546 | } | ||
547 | |||
548 | |||
549 | /** | ||
550 | * Called whenever a client is disconnected. | ||
551 | * Frees our resources associated with that client. | ||
552 | * | ||
553 | * @param cls closure | ||
554 | * @param client identification of the client | ||
555 | * @param app_ctx must match @a client | ||
556 | */ | ||
557 | static void | ||
558 | client_notify_disconnect (void *cls, | ||
559 | struct GNUNET_SERVICE_Client *client, | ||
560 | void *app_ctx) | ||
561 | { | ||
562 | struct Client *c = app_ctx; | ||
563 | struct Place *plc = c->place; | ||
564 | |||
565 | if (NULL != c->app_id) | ||
566 | GNUNET_free (c->app_id); | ||
567 | |||
568 | GNUNET_free (c); | ||
569 | |||
570 | if (NULL == plc) | ||
571 | return; // application client, nothing to do | ||
572 | |||
573 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
574 | "%p Client (%s) disconnected from place %s\n", | ||
575 | plc, (GNUNET_YES == plc->is_host) ? "host" : "guest", | ||
576 | GNUNET_h2s (&plc->pub_key_hash)); | ||
577 | |||
578 | struct ClientListItem *cli = plc->clients_head; | ||
579 | while (NULL != cli) | ||
580 | { | ||
581 | if (cli->client == client) | ||
582 | { | ||
583 | GNUNET_CONTAINER_DLL_remove (plc->clients_head, | ||
584 | plc->clients_tail, | ||
585 | cli); | ||
586 | GNUNET_free (cli); | ||
587 | break; | ||
588 | } | ||
589 | cli = cli->next; | ||
590 | } | ||
591 | if (GNUNET_YES == plc->is_disconnecting) | ||
592 | { | ||
593 | GNUNET_PSYC_slicer_destroy (plc->slicer); | ||
594 | GNUNET_free (plc); | ||
595 | } | ||
596 | } | ||
597 | |||
598 | |||
599 | /** | ||
600 | * A new client connected. | ||
601 | * | ||
602 | * @param cls NULL | ||
603 | * @param client client to add | ||
604 | * @param mq message queue for @a client | ||
605 | * @return @a client | ||
606 | */ | ||
607 | static void * | ||
608 | client_notify_connect (void *cls, | ||
609 | struct GNUNET_SERVICE_Client *client, | ||
610 | struct GNUNET_MQ_Handle *mq) | ||
611 | { | ||
612 | struct Client *c = GNUNET_new (struct Client); | ||
613 | |||
614 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
615 | "Client %p connected with queue %p\n", | ||
616 | client, | ||
617 | mq); | ||
618 | c->client = client; | ||
619 | return c; | ||
620 | } | ||
621 | |||
622 | |||
623 | /** | ||
624 | * Send message to all clients connected to a place and | ||
625 | * takes care of freeing @env. | ||
626 | */ | ||
627 | static void | ||
628 | place_send_msg (const struct Place *plc, | ||
629 | struct GNUNET_MQ_Envelope *env) | ||
630 | { | ||
631 | struct ClientListItem *cli = plc->clients_head; | ||
632 | |||
633 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
634 | "%p Sending message to clients of place.\n", plc); | ||
635 | while (NULL != cli) | ||
636 | { | ||
637 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
638 | "Sending message to client %p\n", | ||
639 | cli); | ||
640 | GNUNET_MQ_send_copy (GNUNET_SERVICE_client_get_mq (cli->client), | ||
641 | env); | ||
642 | cli = cli->next; | ||
643 | } | ||
644 | GNUNET_MQ_discard (env); | ||
645 | } | ||
646 | |||
647 | |||
648 | static void | ||
649 | place_send_leave_ack (struct Place *plc) | ||
650 | { | ||
651 | struct GNUNET_MQ_Envelope *env; | ||
652 | |||
653 | for (struct ClientListItem *cli = plc->clients_head; | ||
654 | NULL != cli; | ||
655 | cli = cli->next) | ||
656 | { | ||
657 | env = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LEAVE_ACK); | ||
658 | GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (cli->client), | ||
659 | env); | ||
660 | } | ||
661 | } | ||
662 | |||
663 | |||
664 | /** | ||
665 | * Send a result code back to the client. | ||
666 | * | ||
667 | * @param client | ||
668 | * Client that should receive the result code. | ||
669 | * @param result_code | ||
670 | * Code to transmit. | ||
671 | * @param op_id | ||
672 | * Operation ID in network byte order. | ||
673 | * @param data | ||
674 | * Data payload or NULL. | ||
675 | * @param data_size | ||
676 | * Size of @a data. | ||
677 | */ | ||
678 | static void | ||
679 | client_send_result (struct GNUNET_SERVICE_Client *client, uint64_t op_id, | ||
680 | int64_t result_code, const void *data, uint16_t data_size) | ||
681 | { | ||
682 | struct GNUNET_MQ_Envelope *env; | ||
683 | struct GNUNET_OperationResultMessage *res; | ||
684 | |||
685 | env = GNUNET_MQ_msg_extra (res, | ||
686 | data_size, | ||
687 | GNUNET_MESSAGE_TYPE_PSYC_RESULT_CODE); | ||
688 | res->result_code = GNUNET_htonll (result_code); | ||
689 | res->op_id = op_id; | ||
690 | if (0 < data_size) | ||
691 | GNUNET_memcpy (&res[1], data, data_size); | ||
692 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
693 | "%p Sending result to client for operation #%" PRIu64 ": " | ||
694 | "%" PRId64 " (size: %u)\n", | ||
695 | client, GNUNET_ntohll (op_id), result_code, data_size); | ||
696 | GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), env); | ||
697 | } | ||
698 | |||
699 | |||
700 | static void | ||
701 | client_send_host_enter_ack (struct GNUNET_SERVICE_Client *client, | ||
702 | struct Host *hst, uint32_t result) | ||
703 | { | ||
704 | struct GNUNET_MQ_Envelope *env; | ||
705 | struct HostEnterAck *hack; | ||
706 | struct Place *plc = &hst->place; | ||
707 | |||
708 | env = GNUNET_MQ_msg (hack, | ||
709 | GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER_ACK); | ||
710 | hack->result_code = htonl (result); | ||
711 | hack->max_message_id = GNUNET_htonll (plc->max_message_id); | ||
712 | hack->place_pub_key = plc->pub_key; | ||
713 | |||
714 | if (NULL != client) | ||
715 | GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), | ||
716 | env); | ||
717 | else | ||
718 | place_send_msg (plc, env); | ||
719 | } | ||
720 | |||
721 | |||
722 | /** | ||
723 | * Called after a PSYC master is started. | ||
724 | */ | ||
725 | static void | ||
726 | psyc_master_started (void *cls, int result, uint64_t max_message_id) | ||
727 | { | ||
728 | struct Host *hst = cls; | ||
729 | struct Place *plc = &hst->place; | ||
730 | plc->max_message_id = max_message_id; | ||
731 | plc->is_ready = GNUNET_YES; | ||
732 | |||
733 | client_send_host_enter_ack (NULL, hst, result); | ||
734 | } | ||
735 | |||
736 | |||
737 | /** | ||
738 | * Called when a PSYC master receives a join request. | ||
739 | */ | ||
740 | static void | ||
741 | psyc_recv_join_request (void *cls, | ||
742 | const struct GNUNET_PSYC_JoinRequestMessage *req, | ||
743 | const struct GNUNET_CRYPTO_EcdsaPublicKey *slave_key, | ||
744 | const struct GNUNET_PSYC_Message *join_msg, | ||
745 | struct GNUNET_PSYC_JoinHandle *jh) | ||
746 | { | ||
747 | struct Host *hst = cls; | ||
748 | struct GNUNET_HashCode slave_key_hash; | ||
749 | GNUNET_CRYPTO_hash (slave_key, sizeof (*slave_key), &slave_key_hash); | ||
750 | GNUNET_CONTAINER_multihashmap_put (hst->join_reqs, &slave_key_hash, jh, | ||
751 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
752 | place_send_msg (&hst->place, | ||
753 | GNUNET_MQ_msg_copy (&req->header)); | ||
754 | } | ||
755 | |||
756 | |||
757 | /** | ||
758 | * Called after a PSYC slave is connected. | ||
759 | */ | ||
760 | static void | ||
761 | psyc_slave_connected (void *cls, int result, uint64_t max_message_id) | ||
762 | { | ||
763 | struct GNUNET_PSYC_CountersResultMessage *res; | ||
764 | struct GNUNET_MQ_Envelope *env; | ||
765 | struct Guest *gst = cls; | ||
766 | struct Place *plc = &gst->place; | ||
767 | |||
768 | plc->max_message_id = max_message_id; | ||
769 | plc->is_ready = GNUNET_YES; | ||
770 | env = GNUNET_MQ_msg (res, | ||
771 | GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_ACK); | ||
772 | res->result_code = | ||
773 | (result != GNUNET_SYSERR) ? htonl (GNUNET_OK) : htonl (GNUNET_SYSERR); | ||
774 | res->max_message_id = GNUNET_htonll (plc->max_message_id); | ||
775 | place_send_msg (plc, env); | ||
776 | } | ||
777 | |||
778 | |||
779 | static void | ||
780 | slave_parted_after_join_decision (void *cls) | ||
781 | { | ||
782 | struct Guest *gst = cls; | ||
783 | |||
784 | GNUNET_assert (NULL != gst->join_dcsn); | ||
785 | place_send_msg (&gst->place, GNUNET_MQ_msg_copy (&gst->join_dcsn->header)); | ||
786 | } | ||
787 | |||
788 | |||
789 | /** | ||
790 | * Called when a PSYC slave receives a join decision. | ||
791 | */ | ||
792 | static void | ||
793 | psyc_recv_join_dcsn (void *cls, | ||
794 | const struct GNUNET_PSYC_JoinDecisionMessage *dcsn, | ||
795 | int is_admitted, | ||
796 | const struct GNUNET_PSYC_Message *join_msg) | ||
797 | { | ||
798 | struct Guest *gst = cls; | ||
799 | |||
800 | gst->join_dcsn = GNUNET_malloc (dcsn->header.size); | ||
801 | GNUNET_memcpy (gst->join_dcsn, | ||
802 | dcsn, | ||
803 | dcsn->header.size); | ||
804 | if (GNUNET_NO == is_admitted) | ||
805 | { | ||
806 | GNUNET_PSYC_slave_part (gst->slave, | ||
807 | GNUNET_NO, | ||
808 | &slave_parted_after_join_decision, | ||
809 | gst); | ||
810 | gst->slave = NULL; | ||
811 | return; | ||
812 | } | ||
813 | place_send_msg (&gst->place, GNUNET_MQ_msg_copy (&gst->join_dcsn->header)); | ||
814 | } | ||
815 | |||
816 | |||
817 | /** | ||
818 | * Called when a PSYC master or slave receives a message. | ||
819 | */ | ||
820 | static void | ||
821 | psyc_recv_message (void *cls, | ||
822 | const struct GNUNET_PSYC_MessageHeader *msg) | ||
823 | { | ||
824 | struct Place *plc = cls; | ||
825 | |||
826 | char *str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&msg->slave_pub_key); | ||
827 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
828 | "%p Received PSYC message of size %u from %s.\n", | ||
829 | plc, ntohs (msg->header.size), str); | ||
830 | GNUNET_free (str); | ||
831 | |||
832 | GNUNET_PSYC_slicer_message (plc->slicer, msg); | ||
833 | |||
834 | place_send_msg (plc, GNUNET_MQ_msg_copy (&msg->header)); | ||
835 | } | ||
836 | |||
837 | |||
838 | /** | ||
839 | * Relay a message part received from a guest to the the place. | ||
840 | * | ||
841 | * @param hst | ||
842 | * Host. | ||
843 | * @param pmsg | ||
844 | * Message part. | ||
845 | * @param nym_pub_key | ||
846 | * Nym the message is received from. | ||
847 | */ | ||
848 | static void | ||
849 | host_relay_message_part (struct Host *hst, | ||
850 | const struct GNUNET_MessageHeader *pmsg, | ||
851 | const struct GNUNET_CRYPTO_EcdsaPublicKey *nym_pub_key) | ||
852 | { | ||
853 | /* separate queue per nym */ | ||
854 | struct GNUNET_HashCode nym_pub_hash; | ||
855 | GNUNET_CRYPTO_hash (nym_pub_key, sizeof (*nym_pub_key), &nym_pub_hash); | ||
856 | |||
857 | struct MessageTransmitQueue * | ||
858 | tmit_msg = GNUNET_CONTAINER_multihashmap_get (hst->relay_msgs, &nym_pub_hash); | ||
859 | |||
860 | uint16_t ptype = ntohs (pmsg->type); | ||
861 | |||
862 | if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD == ptype) | ||
863 | { | ||
864 | /* FIXME: last message was unfinished, cancel & remove from queue */ | ||
865 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
866 | "FIXME: last message was unfinished.\n"); | ||
867 | } | ||
868 | |||
869 | tmit_msg = psyc_transmit_queue_message (&hst->place, NULL, ntohs (pmsg->size), | ||
870 | pmsg, ptype, ptype, tmit_msg); | ||
871 | |||
872 | switch (ptype) | ||
873 | { | ||
874 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD: | ||
875 | GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_put | ||
876 | (hst->relay_msgs, &nym_pub_hash, tmit_msg, | ||
877 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
878 | break; | ||
879 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END: | ||
880 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL: | ||
881 | GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove | ||
882 | (hst->relay_msgs, &nym_pub_hash, tmit_msg)); | ||
883 | break; | ||
884 | } | ||
885 | } | ||
886 | |||
887 | |||
888 | /** | ||
889 | * Received a method to be relayed from a guest. | ||
890 | */ | ||
891 | static void | ||
892 | place_recv_relay_method (void *cls, | ||
893 | const struct GNUNET_PSYC_MessageHeader *msg, | ||
894 | const struct GNUNET_PSYC_MessageMethod *meth, | ||
895 | uint64_t message_id, | ||
896 | const char *method_name) | ||
897 | { | ||
898 | struct Place *plc = cls; | ||
899 | |||
900 | if (GNUNET_PSYC_MESSAGE_REQUEST & ntohs (msg->flags) | ||
901 | && GNUNET_YES == plc->is_host) | ||
902 | { | ||
903 | struct Host *hst = cls; | ||
904 | host_relay_message_part (hst, &meth->header, &msg->slave_pub_key); | ||
905 | } | ||
906 | } | ||
907 | |||
908 | |||
909 | /** | ||
910 | * Received a modifier to be relayed from a guest. | ||
911 | */ | ||
912 | static void | ||
913 | place_recv_relay_modifier (void *cls, | ||
914 | const struct GNUNET_PSYC_MessageHeader *msg, | ||
915 | const struct GNUNET_MessageHeader *pmsg, | ||
916 | uint64_t message_id, | ||
917 | enum GNUNET_PSYC_Operator oper, | ||
918 | const char *name, | ||
919 | const void *value, | ||
920 | uint16_t value_size, | ||
921 | uint16_t full_value_size) | ||
922 | { | ||
923 | struct Place *plc = cls; | ||
924 | |||
925 | if (GNUNET_PSYC_MESSAGE_REQUEST & ntohs (msg->flags) | ||
926 | && GNUNET_YES == plc->is_host) | ||
927 | { | ||
928 | struct Host *hst = cls; | ||
929 | host_relay_message_part (hst, pmsg, &msg->slave_pub_key); | ||
930 | } | ||
931 | } | ||
932 | |||
933 | /** | ||
934 | * Received a data fragment to be relayed from a guest. | ||
935 | */ | ||
936 | static void | ||
937 | place_recv_relay_data (void *cls, | ||
938 | const struct GNUNET_PSYC_MessageHeader *msg, | ||
939 | const struct GNUNET_MessageHeader *pmsg, | ||
940 | uint64_t message_id, | ||
941 | const void *data, | ||
942 | uint16_t data_size) | ||
943 | { | ||
944 | struct Place *plc = cls; | ||
945 | |||
946 | if (GNUNET_PSYC_MESSAGE_REQUEST & ntohs (msg->flags) | ||
947 | && GNUNET_YES == plc->is_host) | ||
948 | { | ||
949 | struct Host *hst = cls; | ||
950 | host_relay_message_part (hst, pmsg, &msg->slave_pub_key); | ||
951 | } | ||
952 | } | ||
953 | |||
954 | |||
955 | /** | ||
956 | * Received end of message to be relayed from a guest. | ||
957 | */ | ||
958 | static void | ||
959 | place_recv_relay_eom (void *cls, | ||
960 | const struct GNUNET_PSYC_MessageHeader *msg, | ||
961 | const struct GNUNET_MessageHeader *pmsg, | ||
962 | uint64_t message_id, | ||
963 | uint8_t is_cancelled) | ||
964 | { | ||
965 | struct Place *plc = cls; | ||
966 | |||
967 | if (GNUNET_PSYC_MESSAGE_REQUEST & ntohs (msg->flags) | ||
968 | && GNUNET_YES == plc->is_host) | ||
969 | { | ||
970 | struct Host *hst = cls; | ||
971 | host_relay_message_part (hst, pmsg, &msg->slave_pub_key); | ||
972 | } | ||
973 | } | ||
974 | |||
975 | |||
976 | /** | ||
977 | * Received a method to be saved to disk. | ||
978 | * | ||
979 | * Create a new file for writing the data part of the message into, | ||
980 | * if the file does not yet exist. | ||
981 | */ | ||
982 | static void | ||
983 | place_recv_save_method (void *cls, | ||
984 | const struct GNUNET_PSYC_MessageHeader *msg, | ||
985 | const struct GNUNET_PSYC_MessageMethod *meth, | ||
986 | uint64_t message_id, | ||
987 | const char *method_name) | ||
988 | { | ||
989 | struct Place *plc = cls; | ||
990 | plc->file_offset = 0; | ||
991 | plc->file_save = GNUNET_NO; | ||
992 | |||
993 | char *place_pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (&plc->pub_key); | ||
994 | char *filename = NULL; | ||
995 | GNUNET_asprintf (&filename, "%s%c" "%s%c" "%s%c" "%" PRIu64 ".part", | ||
996 | dir_social, DIR_SEPARATOR, | ||
997 | "files", DIR_SEPARATOR, | ||
998 | place_pub_str, DIR_SEPARATOR, | ||
999 | GNUNET_ntohll (msg->message_id)); | ||
1000 | GNUNET_free (place_pub_str); | ||
1001 | |||
1002 | /* save if does not already exist */ | ||
1003 | if (GNUNET_YES != GNUNET_DISK_file_test (filename)) | ||
1004 | { | ||
1005 | if (0 == GNUNET_DISK_fn_write (filename, NULL, 0, | ||
1006 | GNUNET_DISK_PERM_USER_READ | ||
1007 | | GNUNET_DISK_PERM_USER_WRITE)) | ||
1008 | { | ||
1009 | plc->file_save = GNUNET_YES; | ||
1010 | } | ||
1011 | else | ||
1012 | { | ||
1013 | GNUNET_break (0); | ||
1014 | } | ||
1015 | } | ||
1016 | GNUNET_free (filename); | ||
1017 | } | ||
1018 | |||
1019 | |||
1020 | /** | ||
1021 | * Received a data fragment to be saved to disk. | ||
1022 | * | ||
1023 | * Append data fragment to the file. | ||
1024 | */ | ||
1025 | static void | ||
1026 | place_recv_save_data (void *cls, | ||
1027 | const struct GNUNET_PSYC_MessageHeader *msg, | ||
1028 | const struct GNUNET_MessageHeader *pmsg, | ||
1029 | uint64_t message_id, | ||
1030 | const void *data, | ||
1031 | uint16_t data_size) | ||
1032 | { | ||
1033 | struct Place *plc = cls; | ||
1034 | if (GNUNET_YES != plc->file_save) | ||
1035 | return; | ||
1036 | |||
1037 | char *place_pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (&plc->pub_key); | ||
1038 | char *filename = NULL; | ||
1039 | GNUNET_asprintf (&filename, "%s%c" "%s%c" "%s%c" "%" PRIu64 ".part", | ||
1040 | dir_social, DIR_SEPARATOR, | ||
1041 | "files", DIR_SEPARATOR, | ||
1042 | place_pub_str, DIR_SEPARATOR, | ||
1043 | GNUNET_ntohll (msg->message_id)); | ||
1044 | GNUNET_free (place_pub_str); | ||
1045 | if (GNUNET_SYSERR == GNUNET_DISK_directory_create_for_file (filename)) | ||
1046 | { | ||
1047 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "create", filename); | ||
1048 | GNUNET_free (filename); | ||
1049 | return; | ||
1050 | } | ||
1051 | |||
1052 | struct GNUNET_DISK_FileHandle * | ||
1053 | fh = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_WRITE, | ||
1054 | GNUNET_DISK_PERM_NONE); | ||
1055 | if (NULL != fh) | ||
1056 | { | ||
1057 | if (plc->file_offset != GNUNET_DISK_file_seek | ||
1058 | (fh, plc->file_offset, GNUNET_DISK_SEEK_SET)) { | ||
1059 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "seek", filename); | ||
1060 | GNUNET_DISK_file_close (fh); | ||
1061 | GNUNET_free (filename); | ||
1062 | return; | ||
1063 | } | ||
1064 | GNUNET_DISK_file_write (fh, data, data_size); | ||
1065 | GNUNET_DISK_file_close (fh); | ||
1066 | GNUNET_free (filename); | ||
1067 | } | ||
1068 | else | ||
1069 | { | ||
1070 | GNUNET_free (filename); | ||
1071 | GNUNET_break (0); | ||
1072 | } | ||
1073 | plc->file_offset += data_size; | ||
1074 | } | ||
1075 | |||
1076 | |||
1077 | /** | ||
1078 | * Received end of message to be saved to disk. | ||
1079 | * | ||
1080 | * Remove .part ending from the filename. | ||
1081 | */ | ||
1082 | static void | ||
1083 | place_recv_save_eom (void *cls, | ||
1084 | const struct GNUNET_PSYC_MessageHeader *msg, | ||
1085 | const struct GNUNET_MessageHeader *pmsg, | ||
1086 | uint64_t message_id, | ||
1087 | uint8_t is_cancelled) | ||
1088 | { | ||
1089 | struct Place *plc = cls; | ||
1090 | if (GNUNET_YES != plc->file_save) | ||
1091 | return; | ||
1092 | |||
1093 | char *place_pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (&plc->pub_key); | ||
1094 | char *fn = NULL; | ||
1095 | GNUNET_asprintf (&fn, "%s%c%s%c%s%c%" PRIu64, | ||
1096 | dir_social, DIR_SEPARATOR, | ||
1097 | "files", DIR_SEPARATOR, | ||
1098 | place_pub_str, DIR_SEPARATOR, | ||
1099 | GNUNET_ntohll (msg->message_id)); | ||
1100 | GNUNET_free (place_pub_str); | ||
1101 | char *fn_part = NULL; | ||
1102 | GNUNET_asprintf (&fn_part, "%s.part", fn); | ||
1103 | |||
1104 | if (rename (fn_part, fn)) { | ||
1105 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1106 | "Failed to rename %s into %s: %s (%d)\n", | ||
1107 | fn_part, fn, strerror (errno), errno); | ||
1108 | } | ||
1109 | |||
1110 | GNUNET_free (fn); | ||
1111 | GNUNET_free (fn_part); | ||
1112 | } | ||
1113 | |||
1114 | |||
1115 | /** | ||
1116 | * Initialize place data structure. | ||
1117 | */ | ||
1118 | static void | ||
1119 | place_init (struct Place *plc) | ||
1120 | { | ||
1121 | plc->slicer = GNUNET_PSYC_slicer_create (); | ||
1122 | } | ||
1123 | |||
1124 | |||
1125 | /** | ||
1126 | * Add a place to the @e places hash map. | ||
1127 | * | ||
1128 | * @param ereq | ||
1129 | * Entry request. | ||
1130 | * | ||
1131 | * @return #GNUNET_OK if the place was added | ||
1132 | * #GNUNET_NO if the place already exists in the hash map | ||
1133 | * #GNUNET_SYSERR on error | ||
1134 | */ | ||
1135 | static int | ||
1136 | place_add (const struct PlaceEnterRequest *ereq) | ||
1137 | { | ||
1138 | struct EgoPlacePublicKey ego_place_pub_key = { | ||
1139 | .ego_pub_key = ereq->ego_pub_key, | ||
1140 | .place_pub_key = ereq->place_pub_key, | ||
1141 | }; | ||
1142 | struct GNUNET_HashCode ego_place_pub_hash; | ||
1143 | GNUNET_CRYPTO_hash (&ego_place_pub_key, sizeof (ego_place_pub_key), &ego_place_pub_hash); | ||
1144 | |||
1145 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1146 | " ego_place_pub_hash = %s\n", GNUNET_h2s (&ego_place_pub_hash)); | ||
1147 | |||
1148 | struct GNUNET_MessageHeader * | ||
1149 | place_msg = GNUNET_CONTAINER_multihashmap_get (places, &ego_place_pub_hash); | ||
1150 | if (NULL != place_msg) | ||
1151 | return GNUNET_NO; | ||
1152 | |||
1153 | place_msg = GNUNET_copy_message (&ereq->header); | ||
1154 | if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (places, &ego_place_pub_hash, place_msg, | ||
1155 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) | ||
1156 | { | ||
1157 | GNUNET_break (0); | ||
1158 | GNUNET_free (place_msg); | ||
1159 | return GNUNET_SYSERR; | ||
1160 | } | ||
1161 | |||
1162 | return GNUNET_OK; | ||
1163 | } | ||
1164 | |||
1165 | /** | ||
1166 | * Add a place to the @e app_places hash map. | ||
1167 | * | ||
1168 | * @param app_id | ||
1169 | * Application ID. | ||
1170 | * @param ereq | ||
1171 | * Entry request. | ||
1172 | * | ||
1173 | * @return #GNUNET_OK if the place was added | ||
1174 | * #GNUNET_NO if the place already exists in the hash map | ||
1175 | * #GNUNET_SYSERR on error | ||
1176 | */ | ||
1177 | static int | ||
1178 | app_place_add (const char *app_id, | ||
1179 | const struct PlaceEnterRequest *ereq) | ||
1180 | { | ||
1181 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1182 | "Adding app place to hashmap:\n"); | ||
1183 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1184 | " app_id = %s\n", app_id); | ||
1185 | |||
1186 | struct GNUNET_HashCode app_id_hash; | ||
1187 | GNUNET_CRYPTO_hash (app_id, strlen (app_id) + 1, &app_id_hash); | ||
1188 | |||
1189 | struct EgoPlacePublicKey ego_place_pub_key = { | ||
1190 | .ego_pub_key = ereq->ego_pub_key, | ||
1191 | .place_pub_key = ereq->place_pub_key, | ||
1192 | }; | ||
1193 | struct GNUNET_HashCode ego_place_pub_hash; | ||
1194 | GNUNET_CRYPTO_hash (&ego_place_pub_key, sizeof (ego_place_pub_key), &ego_place_pub_hash); | ||
1195 | |||
1196 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1197 | " ego_place_pub_hash = %s\n", GNUNET_h2s (&ego_place_pub_hash)); | ||
1198 | |||
1199 | struct GNUNET_CONTAINER_MultiHashMap * | ||
1200 | app_places = GNUNET_CONTAINER_multihashmap_get (apps_places, &app_id_hash); | ||
1201 | if (NULL == app_places) | ||
1202 | { | ||
1203 | app_places = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); | ||
1204 | GNUNET_CONTAINER_multihashmap_put (apps_places, &app_id_hash, app_places, | ||
1205 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); | ||
1206 | } | ||
1207 | |||
1208 | if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (app_places, &ego_place_pub_hash)) | ||
1209 | return GNUNET_NO; | ||
1210 | |||
1211 | if (GNUNET_SYSERR == place_add (ereq)) | ||
1212 | { | ||
1213 | return GNUNET_SYSERR; | ||
1214 | } | ||
1215 | |||
1216 | if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (app_places, &ego_place_pub_hash, NULL, | ||
1217 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)) | ||
1218 | { | ||
1219 | GNUNET_break (0); | ||
1220 | return GNUNET_SYSERR; | ||
1221 | } | ||
1222 | return GNUNET_OK; | ||
1223 | } | ||
1224 | |||
1225 | |||
1226 | /** | ||
1227 | * Save place entry message to disk. | ||
1228 | * | ||
1229 | * @param app_id | ||
1230 | * Application ID. | ||
1231 | * @param ereq | ||
1232 | * Entry request message. | ||
1233 | */ | ||
1234 | static int | ||
1235 | app_place_save (const char *app_id, | ||
1236 | const struct PlaceEnterRequest *ereq) | ||
1237 | { | ||
1238 | if (GNUNET_SYSERR == app_place_add (app_id, ereq)) | ||
1239 | { | ||
1240 | GNUNET_assert (0); | ||
1241 | } | ||
1242 | |||
1243 | if (NULL == dir_places) | ||
1244 | return GNUNET_SYSERR; | ||
1245 | |||
1246 | char *ego_pub_str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&ereq->ego_pub_key); | ||
1247 | char *place_pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (&ereq->place_pub_key); | ||
1248 | char *filename = NULL; | ||
1249 | GNUNET_asprintf (&filename, "%s%c" "%s%c" "%s%c" "%s", | ||
1250 | dir_social, DIR_SEPARATOR, | ||
1251 | "places", DIR_SEPARATOR, | ||
1252 | ego_pub_str, DIR_SEPARATOR, | ||
1253 | place_pub_str); | ||
1254 | int ret = GNUNET_DISK_directory_create_for_file (filename); | ||
1255 | if (GNUNET_OK != ret | ||
1256 | || 0 > GNUNET_DISK_fn_write (filename, ereq, ntohs (ereq->header.size), | ||
1257 | GNUNET_DISK_PERM_USER_READ | ||
1258 | | GNUNET_DISK_PERM_USER_WRITE)) | ||
1259 | { | ||
1260 | GNUNET_break (0); | ||
1261 | ret = GNUNET_SYSERR; | ||
1262 | } | ||
1263 | GNUNET_free (filename); | ||
1264 | |||
1265 | if (ret == GNUNET_OK) | ||
1266 | { | ||
1267 | GNUNET_asprintf (&filename, "%s%c" "%s%c" "%s%c" "%s%c" "%s", | ||
1268 | dir_social, DIR_SEPARATOR, | ||
1269 | "apps", DIR_SEPARATOR, | ||
1270 | app_id, DIR_SEPARATOR, | ||
1271 | ego_pub_str, DIR_SEPARATOR, | ||
1272 | place_pub_str); | ||
1273 | ret = GNUNET_DISK_directory_create_for_file (filename); | ||
1274 | if (GNUNET_OK != ret | ||
1275 | || 0 > GNUNET_DISK_fn_write (filename, "", 0, | ||
1276 | GNUNET_DISK_PERM_USER_READ | ||
1277 | | GNUNET_DISK_PERM_USER_WRITE)) | ||
1278 | { | ||
1279 | GNUNET_break (0); | ||
1280 | ret = GNUNET_SYSERR; | ||
1281 | } | ||
1282 | GNUNET_free (filename); | ||
1283 | } | ||
1284 | GNUNET_free (ego_pub_str); | ||
1285 | GNUNET_free (place_pub_str); | ||
1286 | return ret; | ||
1287 | } | ||
1288 | |||
1289 | |||
1290 | int | ||
1291 | app_place_remove (const char *app_id, | ||
1292 | const struct GNUNET_CRYPTO_EcdsaPublicKey *ego_pub_key, | ||
1293 | const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key) | ||
1294 | { | ||
1295 | struct GNUNET_HashCode ego_pub_hash; | ||
1296 | struct GNUNET_HashCode place_pub_hash; | ||
1297 | GNUNET_CRYPTO_hash (ego_pub_key, sizeof (*ego_pub_key), &ego_pub_hash); | ||
1298 | GNUNET_CRYPTO_hash (place_pub_key, sizeof (*place_pub_key), &place_pub_hash); | ||
1299 | |||
1300 | char *ego_pub_str = GNUNET_CRYPTO_ecdsa_public_key_to_string (ego_pub_key); | ||
1301 | char *place_pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (place_pub_key); | ||
1302 | char *app_place_filename = NULL; | ||
1303 | GNUNET_asprintf (&app_place_filename, | ||
1304 | "%s%c" "%s%c" "%s%c" "%s%c" "%s", | ||
1305 | dir_social, DIR_SEPARATOR, | ||
1306 | "apps", DIR_SEPARATOR, | ||
1307 | app_id, DIR_SEPARATOR, | ||
1308 | ego_pub_str, DIR_SEPARATOR, | ||
1309 | place_pub_str); | ||
1310 | GNUNET_free (ego_pub_str); | ||
1311 | GNUNET_free (place_pub_str); | ||
1312 | |||
1313 | struct GNUNET_HashCode app_id_hash; | ||
1314 | GNUNET_CRYPTO_hash (app_id, strlen (app_id) + 1, &app_id_hash); | ||
1315 | |||
1316 | struct GNUNET_CONTAINER_MultiHashMap * | ||
1317 | app_places = GNUNET_CONTAINER_multihashmap_get (apps_places, &app_id_hash); | ||
1318 | |||
1319 | if (NULL != app_places) | ||
1320 | GNUNET_CONTAINER_multihashmap_remove (app_places, &place_pub_hash, NULL); | ||
1321 | |||
1322 | int ret = GNUNET_OK; | ||
1323 | |||
1324 | if (0 != unlink (app_place_filename)) | ||
1325 | { | ||
1326 | GNUNET_break (0); | ||
1327 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1328 | "Error removing app place file: %s: %s (%d)\n", | ||
1329 | app_place_filename, strerror (errno), errno); | ||
1330 | ret = GNUNET_SYSERR; | ||
1331 | } | ||
1332 | GNUNET_free (app_place_filename); | ||
1333 | |||
1334 | return ret; | ||
1335 | } | ||
1336 | |||
1337 | |||
1338 | /** | ||
1339 | * Enter place as host. | ||
1340 | * | ||
1341 | * @param hreq | ||
1342 | * Host entry request. | ||
1343 | * @param[out] ret_hst | ||
1344 | * Returned Host struct. | ||
1345 | * | ||
1346 | * @return #GNUNET_YES if the host entered the place just now, | ||
1347 | * #GNUNET_NO if the place is already entered, | ||
1348 | * #GNUNET_SYSERR if place_pub_key was set | ||
1349 | * but its private key was not found | ||
1350 | */ | ||
1351 | static int | ||
1352 | host_enter (const struct HostEnterRequest *hreq, struct Host **ret_hst) | ||
1353 | { | ||
1354 | int ret = GNUNET_NO; | ||
1355 | struct GNUNET_HashCode place_pub_hash; | ||
1356 | GNUNET_CRYPTO_hash (&hreq->place_pub_key, sizeof (hreq->place_pub_key), | ||
1357 | &place_pub_hash); | ||
1358 | struct Host *hst = GNUNET_CONTAINER_multihashmap_get (hosts, &place_pub_hash); | ||
1359 | |||
1360 | if (NULL == hst) | ||
1361 | { | ||
1362 | hst = GNUNET_new (struct Host); | ||
1363 | hst->policy = hreq->policy; | ||
1364 | hst->join_reqs = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); | ||
1365 | hst->relay_msgs = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); | ||
1366 | |||
1367 | struct Place *plc = &hst->place; | ||
1368 | place_init (plc); | ||
1369 | plc->is_host = GNUNET_YES; | ||
1370 | plc->pub_key = hreq->place_pub_key; | ||
1371 | plc->pub_key_hash = place_pub_hash; | ||
1372 | |||
1373 | GNUNET_CONTAINER_multihashmap_put (hosts, &plc->pub_key_hash, plc, | ||
1374 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
1375 | hst->master = GNUNET_PSYC_master_start (cfg, &hreq->place_key, hst->policy, | ||
1376 | &psyc_master_started, | ||
1377 | &psyc_recv_join_request, | ||
1378 | &psyc_recv_message, NULL, hst); | ||
1379 | plc->channel = GNUNET_PSYC_master_get_channel (hst->master); | ||
1380 | ret = GNUNET_YES; | ||
1381 | } | ||
1382 | |||
1383 | if (NULL != ret_hst) | ||
1384 | *ret_hst = hst; | ||
1385 | return ret; | ||
1386 | } | ||
1387 | |||
1388 | |||
1389 | static int | ||
1390 | msg_proc_parse (const struct MsgProcRequest *mpreq, | ||
1391 | uint32_t *flags, | ||
1392 | const char **method_prefix, | ||
1393 | struct GNUNET_HashCode *method_hash) | ||
1394 | { | ||
1395 | ssize_t method_size = ntohs (mpreq->header.size) - sizeof (*mpreq); | ||
1396 | uint16_t offset; | ||
1397 | |||
1398 | if (method_size < 0) | ||
1399 | { | ||
1400 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1401 | "MsgProcRequest has invalid size\n"); | ||
1402 | return GNUNET_SYSERR; | ||
1403 | } | ||
1404 | |||
1405 | offset = GNUNET_STRINGS_buffer_tokenize ((const char *) &mpreq[1], | ||
1406 | method_size, | ||
1407 | 1, | ||
1408 | method_prefix); | ||
1409 | if (0 == offset || offset != method_size || *method_prefix == NULL) | ||
1410 | { | ||
1411 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1412 | "MsgProcRequest contains invalid method\n"); | ||
1413 | return GNUNET_SYSERR; | ||
1414 | } | ||
1415 | GNUNET_CRYPTO_hash (*method_prefix, (size_t) method_size, method_hash); | ||
1416 | *flags = ntohl (mpreq->flags); | ||
1417 | return GNUNET_OK; | ||
1418 | } | ||
1419 | |||
1420 | |||
1421 | void | ||
1422 | app_notify_place (const struct GNUNET_MessageHeader *msg, | ||
1423 | struct GNUNET_SERVICE_Client *client) | ||
1424 | { | ||
1425 | struct AppPlaceMessage *amsg; | ||
1426 | struct GNUNET_MQ_Envelope *env; | ||
1427 | uint16_t msg_size = ntohs (msg->size); | ||
1428 | |||
1429 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1430 | "%p Sending place notification of type %u to client.\n", | ||
1431 | client, ntohs (msg->type)); | ||
1432 | switch (ntohs (msg->type)) | ||
1433 | { | ||
1434 | case GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER: | ||
1435 | { | ||
1436 | struct HostEnterRequest *hreq = (struct HostEnterRequest *) msg; | ||
1437 | if (msg_size < sizeof (struct HostEnterRequest)) | ||
1438 | return; | ||
1439 | env = GNUNET_MQ_msg (amsg, | ||
1440 | GNUNET_MESSAGE_TYPE_SOCIAL_APP_PLACE); | ||
1441 | // FIXME: also notify about not entered places | ||
1442 | amsg->place_state = GNUNET_SOCIAL_PLACE_STATE_ENTERED; | ||
1443 | amsg->is_host = GNUNET_YES; | ||
1444 | amsg->ego_pub_key = hreq->ego_pub_key; | ||
1445 | amsg->place_pub_key = hreq->place_pub_key; | ||
1446 | GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), | ||
1447 | env); | ||
1448 | break; | ||
1449 | } | ||
1450 | case GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER: | ||
1451 | { | ||
1452 | if (msg_size < sizeof (struct GuestEnterRequest)) | ||
1453 | return; | ||
1454 | struct GuestEnterRequest *greq = (struct GuestEnterRequest *) msg; | ||
1455 | env = GNUNET_MQ_msg (amsg, | ||
1456 | GNUNET_MESSAGE_TYPE_SOCIAL_APP_PLACE); | ||
1457 | // FIXME: also notify about not entered places | ||
1458 | amsg->place_state = GNUNET_SOCIAL_PLACE_STATE_ENTERED; | ||
1459 | amsg->is_host = GNUNET_NO; | ||
1460 | amsg->ego_pub_key = greq->ego_pub_key; | ||
1461 | amsg->place_pub_key = greq->place_pub_key; | ||
1462 | GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), | ||
1463 | env); | ||
1464 | break; | ||
1465 | } | ||
1466 | default: | ||
1467 | return; | ||
1468 | } | ||
1469 | } | ||
1470 | |||
1471 | |||
1472 | void | ||
1473 | app_notify_place_end (struct GNUNET_SERVICE_Client *client) | ||
1474 | { | ||
1475 | struct GNUNET_MQ_Envelope *env; | ||
1476 | |||
1477 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1478 | "%p Sending end of place list notification to client\n", | ||
1479 | client); | ||
1480 | env = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SOCIAL_APP_PLACE_END); | ||
1481 | GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), | ||
1482 | env); | ||
1483 | } | ||
1484 | |||
1485 | |||
1486 | void | ||
1487 | app_notify_ego (struct Ego *ego, struct GNUNET_SERVICE_Client *client) | ||
1488 | { | ||
1489 | struct AppEgoMessage *emsg; | ||
1490 | struct GNUNET_MQ_Envelope *env; | ||
1491 | size_t name_size = strlen (ego->name) + 1; | ||
1492 | |||
1493 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1494 | "%p Sending ego notification to client: %s\n", | ||
1495 | client, ego->name); | ||
1496 | env = GNUNET_MQ_msg_extra (emsg, | ||
1497 | name_size, | ||
1498 | GNUNET_MESSAGE_TYPE_SOCIAL_APP_EGO); | ||
1499 | GNUNET_CRYPTO_ecdsa_key_get_public (&ego->key, &emsg->ego_pub_key); | ||
1500 | GNUNET_memcpy (&emsg[1], ego->name, name_size); | ||
1501 | GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), | ||
1502 | env); | ||
1503 | } | ||
1504 | |||
1505 | |||
1506 | void | ||
1507 | app_notify_ego_end (struct GNUNET_SERVICE_Client *client) | ||
1508 | { | ||
1509 | struct GNUNET_MQ_Envelope *env; | ||
1510 | |||
1511 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1512 | "%p Sending end of ego list notification to client\n", | ||
1513 | client); | ||
1514 | env = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SOCIAL_APP_EGO_END); | ||
1515 | GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), | ||
1516 | env); | ||
1517 | } | ||
1518 | |||
1519 | |||
1520 | int | ||
1521 | app_place_entry_notify (void *cls, const struct GNUNET_HashCode *key, void *value) | ||
1522 | { | ||
1523 | struct GNUNET_MessageHeader * | ||
1524 | msg = GNUNET_CONTAINER_multihashmap_get (places, key); | ||
1525 | if (NULL != msg) | ||
1526 | app_notify_place (msg, cls); | ||
1527 | return GNUNET_YES; | ||
1528 | } | ||
1529 | |||
1530 | |||
1531 | int | ||
1532 | ego_entry (void *cls, const struct GNUNET_HashCode *key, void *value) | ||
1533 | { | ||
1534 | app_notify_ego (value, cls); | ||
1535 | return GNUNET_YES; | ||
1536 | } | ||
1537 | |||
1538 | |||
1539 | static int | ||
1540 | check_client_msg_proc_set (void *cls, | ||
1541 | const struct MsgProcRequest *mpreq) | ||
1542 | { | ||
1543 | return GNUNET_OK; | ||
1544 | } | ||
1545 | |||
1546 | |||
1547 | /** | ||
1548 | * Handle a client setting message proccesing flags for a method prefix. | ||
1549 | */ | ||
1550 | static void | ||
1551 | handle_client_msg_proc_set (void *cls, | ||
1552 | const struct MsgProcRequest *mpreq) | ||
1553 | { | ||
1554 | struct Client *c = cls; | ||
1555 | struct GNUNET_SERVICE_Client *client = c->client; | ||
1556 | struct Place *plc = c->place; | ||
1557 | if (NULL == plc) | ||
1558 | { | ||
1559 | GNUNET_break (0); | ||
1560 | GNUNET_SERVICE_client_drop (client); | ||
1561 | return; | ||
1562 | } | ||
1563 | |||
1564 | const char *method_prefix = NULL; | ||
1565 | uint32_t flags = 0; | ||
1566 | struct GNUNET_HashCode method_hash; | ||
1567 | |||
1568 | if (GNUNET_OK != | ||
1569 | msg_proc_parse (mpreq, &flags, &method_prefix, &method_hash)) | ||
1570 | { | ||
1571 | GNUNET_break (0); | ||
1572 | GNUNET_SERVICE_client_drop (client); | ||
1573 | return; | ||
1574 | } | ||
1575 | #if 0 | ||
1576 | GNUNET_PSYC_slicer_method_remove (plc->slicer, method_prefix, | ||
1577 | place_recv_relay_method, | ||
1578 | place_recv_relay_modifier, | ||
1579 | place_recv_relay_data, | ||
1580 | place_recv_relay_eom); | ||
1581 | GNUNET_PSYC_slicer_method_remove (plc->slicer, method_prefix, | ||
1582 | place_recv_save_method, | ||
1583 | NULL, | ||
1584 | place_recv_save_data, | ||
1585 | place_recv_save_eom); | ||
1586 | #endif | ||
1587 | if (flags & GNUNET_SOCIAL_MSG_PROC_RELAY) | ||
1588 | { | ||
1589 | GNUNET_PSYC_slicer_method_add (plc->slicer, method_prefix, NULL, | ||
1590 | place_recv_relay_method, | ||
1591 | place_recv_relay_modifier, | ||
1592 | place_recv_relay_data, | ||
1593 | place_recv_relay_eom, | ||
1594 | plc); | ||
1595 | } | ||
1596 | if (flags & GNUNET_SOCIAL_MSG_PROC_SAVE) | ||
1597 | { | ||
1598 | GNUNET_PSYC_slicer_method_add (plc->slicer, method_prefix, NULL, | ||
1599 | place_recv_save_method, | ||
1600 | NULL, | ||
1601 | place_recv_save_data, | ||
1602 | place_recv_save_eom, | ||
1603 | plc); | ||
1604 | } | ||
1605 | |||
1606 | /** @todo Save flags to be able to resume relaying/saving after restart */ | ||
1607 | |||
1608 | GNUNET_SERVICE_client_continue (client); | ||
1609 | } | ||
1610 | |||
1611 | |||
1612 | /** | ||
1613 | * Handle a connecting client requesting to clear all relay rules. | ||
1614 | */ | ||
1615 | static void | ||
1616 | handle_client_msg_proc_clear (void *cls, | ||
1617 | const struct GNUNET_MessageHeader *msg) | ||
1618 | { | ||
1619 | struct Client *c = cls; | ||
1620 | struct GNUNET_SERVICE_Client *client = c->client; | ||
1621 | struct Place *plc = c->place; | ||
1622 | if (NULL == plc) | ||
1623 | { | ||
1624 | GNUNET_break (0); | ||
1625 | GNUNET_SERVICE_client_drop (client); | ||
1626 | return; | ||
1627 | } | ||
1628 | |||
1629 | GNUNET_PSYC_slicer_clear (plc->slicer); | ||
1630 | |||
1631 | GNUNET_SERVICE_client_continue (client); | ||
1632 | } | ||
1633 | |||
1634 | |||
1635 | static int | ||
1636 | check_client_host_enter (void *cls, | ||
1637 | const struct HostEnterRequest *hr) | ||
1638 | { | ||
1639 | return GNUNET_OK; | ||
1640 | } | ||
1641 | |||
1642 | |||
1643 | /** | ||
1644 | * Handle a connecting client entering a place as host. | ||
1645 | */ | ||
1646 | static void | ||
1647 | handle_client_host_enter (void *cls, | ||
1648 | const struct HostEnterRequest *hr) | ||
1649 | { | ||
1650 | struct Client *c = cls; | ||
1651 | struct GNUNET_SERVICE_Client *client = c->client; | ||
1652 | struct HostEnterRequest * | ||
1653 | hreq = (struct HostEnterRequest *) GNUNET_copy_message (&hr->header); | ||
1654 | |||
1655 | uint8_t app_id_size = ntohs (hreq->header.size) - sizeof (*hreq); | ||
1656 | const char *app_id = NULL; | ||
1657 | uint16_t offset = GNUNET_STRINGS_buffer_tokenize ((const char *) &hreq[1], | ||
1658 | app_id_size, 1, &app_id); | ||
1659 | if (0 == offset || offset != app_id_size || app_id == NULL) | ||
1660 | { | ||
1661 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1662 | "offset = %u, app_id_size = %u, app_id = %s\n", | ||
1663 | offset, app_id_size, app_id); | ||
1664 | GNUNET_break (0); | ||
1665 | GNUNET_SERVICE_client_drop (client); | ||
1666 | return; | ||
1667 | } | ||
1668 | |||
1669 | struct Host *hst = NULL; | ||
1670 | struct Place *plc = NULL; | ||
1671 | int ret = GNUNET_OK; | ||
1672 | |||
1673 | struct GNUNET_CRYPTO_EddsaPublicKey empty_pub_key; | ||
1674 | memset (&empty_pub_key, 0, sizeof (empty_pub_key)); | ||
1675 | |||
1676 | if (0 == memcmp (&hreq->place_pub_key, &empty_pub_key, sizeof (empty_pub_key))) | ||
1677 | { // no public key set: create new private key & save the place | ||
1678 | struct GNUNET_CRYPTO_EddsaPrivateKey * | ||
1679 | place_key = GNUNET_CRYPTO_eddsa_key_create (); | ||
1680 | hreq->place_key = *place_key; | ||
1681 | GNUNET_CRYPTO_eddsa_key_get_public (place_key, &hreq->place_pub_key); | ||
1682 | GNUNET_CRYPTO_eddsa_key_clear (place_key); | ||
1683 | GNUNET_free (place_key); | ||
1684 | |||
1685 | app_place_save (app_id, (const struct PlaceEnterRequest *) hreq); | ||
1686 | } | ||
1687 | |||
1688 | switch (host_enter (hreq, &hst)) | ||
1689 | { | ||
1690 | case GNUNET_YES: | ||
1691 | plc = c->place = &hst->place; | ||
1692 | plc->host = hst; | ||
1693 | break; | ||
1694 | |||
1695 | case GNUNET_NO: | ||
1696 | { | ||
1697 | plc = c->place = &hst->place; | ||
1698 | plc->host = hst; | ||
1699 | client_send_host_enter_ack (client, hst, GNUNET_OK); | ||
1700 | break; | ||
1701 | } | ||
1702 | case GNUNET_SYSERR: | ||
1703 | ret = GNUNET_SYSERR; | ||
1704 | } | ||
1705 | |||
1706 | if (ret != GNUNET_SYSERR) | ||
1707 | { | ||
1708 | |||
1709 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1710 | "%p Client connected as host to place %s.\n", | ||
1711 | hst, GNUNET_h2s (&plc->pub_key_hash)); | ||
1712 | |||
1713 | struct ClientListItem *cli = GNUNET_new (struct ClientListItem); | ||
1714 | cli->client = client; | ||
1715 | GNUNET_CONTAINER_DLL_insert (plc->clients_head, plc->clients_tail, cli); | ||
1716 | c->place = plc; | ||
1717 | app_notify_place (&hreq->header, client); | ||
1718 | } | ||
1719 | |||
1720 | GNUNET_CRYPTO_eddsa_key_clear (&hreq->place_key); | ||
1721 | GNUNET_free (hreq); | ||
1722 | |||
1723 | if (GNUNET_OK == ret) | ||
1724 | GNUNET_SERVICE_client_continue (client); | ||
1725 | else | ||
1726 | GNUNET_SERVICE_client_drop (client); | ||
1727 | } | ||
1728 | |||
1729 | |||
1730 | /** | ||
1731 | * Enter place as guest. | ||
1732 | * | ||
1733 | * @param greq | ||
1734 | * Guest entry request. | ||
1735 | * @param[out] ret_gst | ||
1736 | * Returned Guest struct. | ||
1737 | * | ||
1738 | * @return #GNUNET_YES if the guest entered the place just now, | ||
1739 | * #GNUNET_NO if the place is already entered, | ||
1740 | * #GNUNET_SYSERR on error. | ||
1741 | */ | ||
1742 | static int | ||
1743 | guest_enter (const struct GuestEnterRequest *greq, struct Guest **ret_gst) | ||
1744 | { | ||
1745 | int ret = GNUNET_NO; | ||
1746 | uint16_t greq_size = ntohs (greq->header.size); | ||
1747 | |||
1748 | struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key = greq->ego_pub_key; | ||
1749 | struct GNUNET_HashCode ego_pub_hash; | ||
1750 | GNUNET_CRYPTO_hash (&ego_pub_key, sizeof (ego_pub_key), &ego_pub_hash); | ||
1751 | struct Ego *ego = GNUNET_CONTAINER_multihashmap_get (egos, &ego_pub_hash); | ||
1752 | |||
1753 | if (NULL == ego) | ||
1754 | { | ||
1755 | return GNUNET_SYSERR; | ||
1756 | } | ||
1757 | |||
1758 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1759 | "entering as guest\n"); | ||
1760 | struct GNUNET_HashCode place_pub_hash; | ||
1761 | GNUNET_CRYPTO_hash (&greq->place_pub_key, sizeof (greq->place_pub_key), | ||
1762 | &place_pub_hash); | ||
1763 | |||
1764 | struct GNUNET_CONTAINER_MultiHashMap * | ||
1765 | plc_gst = GNUNET_CONTAINER_multihashmap_get (place_guests, &place_pub_hash); | ||
1766 | struct Guest *gst = NULL; | ||
1767 | int new_guest; | ||
1768 | |||
1769 | if (NULL != plc_gst) | ||
1770 | gst = GNUNET_CONTAINER_multihashmap_get (plc_gst, &ego_pub_hash); | ||
1771 | |||
1772 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1773 | "plc_gst = %p, gst = %p\n", | ||
1774 | plc_gst, | ||
1775 | gst); | ||
1776 | |||
1777 | if (NULL == gst) | ||
1778 | { | ||
1779 | gst = GNUNET_new (struct Guest); | ||
1780 | new_guest = GNUNET_YES; | ||
1781 | } | ||
1782 | else new_guest = GNUNET_NO; | ||
1783 | |||
1784 | if (NULL == gst->slave) | ||
1785 | { | ||
1786 | gst->origin = greq->origin; | ||
1787 | gst->relay_count = ntohl (greq->relay_count); | ||
1788 | |||
1789 | uint16_t len; | ||
1790 | uint16_t remaining = ntohs (greq->header.size) - sizeof (*greq); | ||
1791 | const char *app_id = (const char *) &greq[1]; | ||
1792 | const char *p = app_id; | ||
1793 | |||
1794 | len = strnlen (app_id, remaining); | ||
1795 | if (len == remaining) | ||
1796 | { | ||
1797 | GNUNET_free (gst); | ||
1798 | GNUNET_break (0); | ||
1799 | return GNUNET_SYSERR; | ||
1800 | } | ||
1801 | p += len + 1; | ||
1802 | remaining -= len + 1; | ||
1803 | |||
1804 | const struct GNUNET_PeerIdentity *relays = NULL; | ||
1805 | uint16_t relay_size = gst->relay_count * sizeof (*relays); | ||
1806 | if (remaining < relay_size) | ||
1807 | { | ||
1808 | GNUNET_free (gst); | ||
1809 | GNUNET_break (0); | ||
1810 | return GNUNET_SYSERR; | ||
1811 | } | ||
1812 | if (0 < relay_size) | ||
1813 | relays = (const struct GNUNET_PeerIdentity *) p; | ||
1814 | p += relay_size; | ||
1815 | remaining -= relay_size; | ||
1816 | |||
1817 | struct GNUNET_PSYC_Message *join_msg = NULL; | ||
1818 | uint16_t join_msg_size = 0; | ||
1819 | |||
1820 | if (sizeof (struct GNUNET_MessageHeader) <= remaining) | ||
1821 | { | ||
1822 | join_msg = (struct GNUNET_PSYC_Message *) p; | ||
1823 | join_msg_size = ntohs (join_msg->header.size); | ||
1824 | p += join_msg_size; | ||
1825 | remaining -= join_msg_size; | ||
1826 | } | ||
1827 | if (0 != remaining) | ||
1828 | { | ||
1829 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1830 | "%zu + %u + %u != %u\n", | ||
1831 | sizeof (*greq), relay_size, join_msg_size, greq_size); | ||
1832 | GNUNET_free (gst); | ||
1833 | GNUNET_break (0); | ||
1834 | return GNUNET_SYSERR; | ||
1835 | } | ||
1836 | if (0 < relay_size) | ||
1837 | { | ||
1838 | gst->relays = GNUNET_malloc (relay_size); | ||
1839 | GNUNET_memcpy (gst->relays, relays, relay_size); | ||
1840 | } | ||
1841 | |||
1842 | gst->join_flags = ntohl (greq->flags); | ||
1843 | |||
1844 | struct Place *plc = &gst->place; | ||
1845 | place_init (plc); | ||
1846 | plc->is_host = GNUNET_NO; | ||
1847 | plc->pub_key = greq->place_pub_key; | ||
1848 | plc->pub_key_hash = place_pub_hash; | ||
1849 | plc->ego_pub_key = ego_pub_key; | ||
1850 | plc->ego_pub_hash = ego_pub_hash; | ||
1851 | plc->ego_key = ego->key; | ||
1852 | |||
1853 | if (NULL == plc_gst) | ||
1854 | { | ||
1855 | plc_gst = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES); | ||
1856 | (void) GNUNET_CONTAINER_multihashmap_put (place_guests, &plc->pub_key_hash, plc_gst, | ||
1857 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); | ||
1858 | } | ||
1859 | if (GNUNET_YES == new_guest) | ||
1860 | { | ||
1861 | (void) GNUNET_CONTAINER_multihashmap_put (plc_gst, &plc->ego_pub_hash, gst, | ||
1862 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); | ||
1863 | (void) GNUNET_CONTAINER_multihashmap_put (guests, &plc->pub_key_hash, gst, | ||
1864 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
1865 | |||
1866 | } | ||
1867 | gst->slave | ||
1868 | = GNUNET_PSYC_slave_join (cfg, &plc->pub_key, &plc->ego_key, | ||
1869 | gst->join_flags, &gst->origin, | ||
1870 | gst->relay_count, gst->relays, | ||
1871 | &psyc_recv_message, NULL, | ||
1872 | &psyc_slave_connected, | ||
1873 | &psyc_recv_join_dcsn, | ||
1874 | gst, join_msg); | ||
1875 | plc->channel = GNUNET_PSYC_slave_get_channel (gst->slave); | ||
1876 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1877 | "slave entered channel %p\n", | ||
1878 | plc->channel); | ||
1879 | ret = GNUNET_YES; | ||
1880 | } | ||
1881 | |||
1882 | // TODO: explain to automatic code scanners why free(gst) not necessary | ||
1883 | if (NULL != ret_gst) | ||
1884 | *ret_gst = gst; | ||
1885 | return ret; | ||
1886 | } | ||
1887 | |||
1888 | |||
1889 | static int | ||
1890 | client_guest_enter (struct Client *c, | ||
1891 | const struct GuestEnterRequest *greq) | ||
1892 | { | ||
1893 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1894 | "client_guest_enter\n"); | ||
1895 | struct GNUNET_PSYC_CountersResultMessage *result_msg; | ||
1896 | struct GNUNET_MQ_Envelope *env; | ||
1897 | struct GNUNET_SERVICE_Client *client = c->client; | ||
1898 | uint16_t remaining = ntohs (greq->header.size) - sizeof (*greq); | ||
1899 | const char *app_id = NULL; | ||
1900 | uint16_t offset = GNUNET_STRINGS_buffer_tokenize ((const char *) &greq[1], | ||
1901 | remaining, 1, &app_id); | ||
1902 | struct Guest *gst = NULL; | ||
1903 | struct Place *plc = NULL; | ||
1904 | |||
1905 | if (0 == offset) | ||
1906 | { | ||
1907 | return GNUNET_SYSERR; | ||
1908 | } | ||
1909 | switch (guest_enter (greq, &gst)) | ||
1910 | { | ||
1911 | case GNUNET_YES: | ||
1912 | { | ||
1913 | plc = c->place = &gst->place; | ||
1914 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1915 | "guest entered successfully to local place %s\n", | ||
1916 | GNUNET_h2s (&plc->pub_key_hash)); | ||
1917 | plc->guest = gst; | ||
1918 | app_place_save (app_id, (const struct PlaceEnterRequest *) greq); | ||
1919 | app_notify_place (&greq->header, client); | ||
1920 | break; | ||
1921 | } | ||
1922 | case GNUNET_NO: | ||
1923 | { | ||
1924 | plc = c->place = &gst->place; | ||
1925 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1926 | "guest re-entered successfully to local place %s\n", | ||
1927 | GNUNET_h2s (&plc->pub_key_hash)); | ||
1928 | plc->guest = gst; | ||
1929 | env = GNUNET_MQ_msg (result_msg, | ||
1930 | GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_ACK); | ||
1931 | result_msg->result_code = htonl (GNUNET_OK); | ||
1932 | result_msg->max_message_id = GNUNET_htonll (plc->max_message_id); | ||
1933 | GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), | ||
1934 | env); | ||
1935 | if (NULL != gst->join_dcsn) | ||
1936 | { | ||
1937 | env = GNUNET_MQ_msg_copy (&gst->join_dcsn->header); | ||
1938 | GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), | ||
1939 | env); | ||
1940 | } | ||
1941 | break; | ||
1942 | } | ||
1943 | case GNUNET_SYSERR: | ||
1944 | { | ||
1945 | return GNUNET_SYSERR; | ||
1946 | } | ||
1947 | } | ||
1948 | |||
1949 | struct ClientListItem *cli = GNUNET_new (struct ClientListItem); | ||
1950 | cli->client = client; | ||
1951 | GNUNET_CONTAINER_DLL_insert (plc->clients_head, plc->clients_tail, cli); | ||
1952 | return GNUNET_OK; | ||
1953 | } | ||
1954 | |||
1955 | |||
1956 | static int | ||
1957 | check_client_guest_enter (void *cls, | ||
1958 | const struct GuestEnterRequest *greq) | ||
1959 | { | ||
1960 | return GNUNET_OK; | ||
1961 | } | ||
1962 | |||
1963 | |||
1964 | /** | ||
1965 | * Handle a connecting client entering a place as guest. | ||
1966 | */ | ||
1967 | static void | ||
1968 | handle_client_guest_enter (void *cls, | ||
1969 | const struct GuestEnterRequest *greq) | ||
1970 | { | ||
1971 | struct Client *c = cls; | ||
1972 | |||
1973 | if (GNUNET_SYSERR == client_guest_enter (c, greq)) | ||
1974 | { | ||
1975 | GNUNET_break (0); | ||
1976 | GNUNET_SERVICE_client_drop (c->client); | ||
1977 | return; | ||
1978 | } | ||
1979 | GNUNET_SERVICE_client_continue (c->client); | ||
1980 | } | ||
1981 | |||
1982 | |||
1983 | struct GuestEnterByNameClosure | ||
1984 | { | ||
1985 | struct Client *client; | ||
1986 | char *app_id; | ||
1987 | char *password; | ||
1988 | struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key; | ||
1989 | struct GNUNET_MessageHeader *join_msg; | ||
1990 | }; | ||
1991 | |||
1992 | |||
1993 | /** | ||
1994 | * Result of a GNS name lookup for entering a place. | ||
1995 | * | ||
1996 | * @see GNUNET_SOCIAL_guest_enter_by_name | ||
1997 | */ | ||
1998 | static void | ||
1999 | gns_result_guest_enter (void *cls, uint32_t rd_count, | ||
2000 | const struct GNUNET_GNSRECORD_Data *rd) | ||
2001 | { | ||
2002 | struct GuestEnterByNameClosure *gcls = cls; | ||
2003 | struct Client *c = gcls->client; | ||
2004 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2005 | "%p GNS result: %u records.\n", | ||
2006 | c, rd_count); | ||
2007 | |||
2008 | const struct GNUNET_GNSRECORD_PlaceData * | ||
2009 | rec = (const struct GNUNET_GNSRECORD_PlaceData *) rd->data; | ||
2010 | |||
2011 | if (0 == rd_count || rd->data_size < sizeof (*rec)) | ||
2012 | { | ||
2013 | GNUNET_break (0); | ||
2014 | GNUNET_SERVICE_client_drop (c->client); | ||
2015 | return; | ||
2016 | } | ||
2017 | |||
2018 | uint16_t relay_count = ntohl (rec->relay_count); | ||
2019 | struct GNUNET_PeerIdentity *relays = NULL; | ||
2020 | |||
2021 | if (0 < relay_count) | ||
2022 | { | ||
2023 | if (rd->data_size == sizeof (*rec) + relay_count * sizeof (struct GNUNET_PeerIdentity)) | ||
2024 | { | ||
2025 | relays = (struct GNUNET_PeerIdentity *) &rec[1]; | ||
2026 | } | ||
2027 | else | ||
2028 | { | ||
2029 | relay_count = 0; | ||
2030 | GNUNET_break_op (0); | ||
2031 | } | ||
2032 | } | ||
2033 | |||
2034 | uint16_t app_id_size = strlen (gcls->app_id) + 1; | ||
2035 | uint16_t relay_size = relay_count * sizeof (*relays); | ||
2036 | uint16_t join_msg_size = 0; | ||
2037 | if (NULL != gcls->join_msg) | ||
2038 | join_msg_size = ntohs (gcls->join_msg->size); | ||
2039 | uint16_t greq_size = sizeof (struct GuestEnterRequest) | ||
2040 | + app_id_size + relay_size + join_msg_size; | ||
2041 | struct GuestEnterRequest *greq = GNUNET_malloc (greq_size); | ||
2042 | greq->header.size = htons (greq_size); | ||
2043 | greq->header.type = htons (GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER); | ||
2044 | greq->ego_pub_key = gcls->ego_pub_key; | ||
2045 | greq->place_pub_key = rec->place_pub_key; | ||
2046 | greq->origin = rec->origin; | ||
2047 | greq->relay_count = rec->relay_count; | ||
2048 | |||
2049 | void *p = &greq[1]; | ||
2050 | GNUNET_memcpy (p, gcls->app_id, app_id_size); | ||
2051 | p += app_id_size; | ||
2052 | GNUNET_memcpy (p, relays, relay_size); | ||
2053 | p += relay_size; | ||
2054 | GNUNET_memcpy (p, gcls->join_msg, join_msg_size); | ||
2055 | |||
2056 | client_guest_enter (c, greq); | ||
2057 | |||
2058 | GNUNET_free (gcls->app_id); | ||
2059 | if (NULL != gcls->password) | ||
2060 | GNUNET_free (gcls->password); | ||
2061 | if (NULL != gcls->join_msg) | ||
2062 | GNUNET_free (gcls->join_msg); | ||
2063 | GNUNET_free (gcls); | ||
2064 | GNUNET_free (greq); | ||
2065 | } | ||
2066 | |||
2067 | |||
2068 | static int | ||
2069 | check_client_guest_enter_by_name (void *cls, | ||
2070 | const struct GuestEnterByNameRequest *greq) | ||
2071 | { | ||
2072 | return GNUNET_OK; | ||
2073 | } | ||
2074 | |||
2075 | |||
2076 | /** | ||
2077 | * Handle a connecting client entering a place as guest using a GNS address. | ||
2078 | * | ||
2079 | * Look up GNS address and generate a GuestEnterRequest from that. | ||
2080 | */ | ||
2081 | static void | ||
2082 | handle_client_guest_enter_by_name (void *cls, | ||
2083 | const struct GuestEnterByNameRequest *greq) | ||
2084 | { | ||
2085 | struct Client *c = cls; | ||
2086 | struct GNUNET_SERVICE_Client *client = c->client; | ||
2087 | |||
2088 | struct GuestEnterByNameClosure *gcls = GNUNET_malloc (sizeof (*gcls)); | ||
2089 | gcls->client = c; | ||
2090 | gcls->ego_pub_key = greq->ego_pub_key; | ||
2091 | |||
2092 | const char *p = (const char *) &greq[1]; | ||
2093 | const char *app_id = NULL, *password = NULL, *gns_name = NULL; | ||
2094 | uint16_t remaining = ntohs (greq->header.size) - sizeof (*greq); | ||
2095 | uint16_t offset = GNUNET_STRINGS_buffer_tokenize (p, remaining, 3, | ||
2096 | &app_id, | ||
2097 | &gns_name, | ||
2098 | &password); | ||
2099 | p += offset; | ||
2100 | remaining -= offset; | ||
2101 | |||
2102 | if (0 != offset && sizeof (*gcls->join_msg) <= remaining) | ||
2103 | { | ||
2104 | gcls->join_msg = GNUNET_copy_message ((struct GNUNET_MessageHeader *) p); | ||
2105 | remaining -= ntohs (gcls->join_msg->size); | ||
2106 | } | ||
2107 | |||
2108 | if (0 == offset || 0 != remaining) | ||
2109 | { | ||
2110 | if (NULL != gcls->join_msg) | ||
2111 | GNUNET_free (gcls->join_msg); | ||
2112 | GNUNET_free (gcls); | ||
2113 | GNUNET_break (0); | ||
2114 | GNUNET_SERVICE_client_drop (client); | ||
2115 | return; | ||
2116 | } | ||
2117 | |||
2118 | uint16_t app_id_size = strlen (app_id) + 1; | ||
2119 | gcls->app_id = GNUNET_malloc (app_id_size); | ||
2120 | GNUNET_memcpy (gcls->app_id, app_id, app_id_size); | ||
2121 | |||
2122 | uint16_t password_size = strlen (password); | ||
2123 | if (0 < password_size++) | ||
2124 | { | ||
2125 | gcls->password = GNUNET_malloc (password_size); | ||
2126 | GNUNET_memcpy (gcls->password, password, password_size); | ||
2127 | } | ||
2128 | |||
2129 | GNUNET_GNS_lookup (gns, gns_name, | ||
2130 | &greq->ego_pub_key, | ||
2131 | GNUNET_GNSRECORD_TYPE_PLACE, | ||
2132 | GNUNET_GNS_LO_DEFAULT, | ||
2133 | &gns_result_guest_enter, gcls); | ||
2134 | GNUNET_SERVICE_client_continue (client); | ||
2135 | } | ||
2136 | |||
2137 | |||
2138 | static int | ||
2139 | check_client_app_connect (void *cls, | ||
2140 | const struct AppConnectRequest *creq) | ||
2141 | { | ||
2142 | return GNUNET_OK; | ||
2143 | } | ||
2144 | |||
2145 | |||
2146 | /** | ||
2147 | * Handle application connection. | ||
2148 | */ | ||
2149 | static void | ||
2150 | handle_client_app_connect (void *cls, | ||
2151 | const struct AppConnectRequest *creq) | ||
2152 | { | ||
2153 | struct Client *c = cls; | ||
2154 | struct GNUNET_SERVICE_Client *client = c->client; | ||
2155 | ssize_t app_id_size = ntohs (creq->header.size) - sizeof (*creq); | ||
2156 | const char *app_id = NULL; | ||
2157 | uint16_t offset; | ||
2158 | |||
2159 | if (app_id_size < 0) | ||
2160 | { | ||
2161 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
2162 | "AppConnectRequest has invalid size\n"); | ||
2163 | GNUNET_break (0); | ||
2164 | GNUNET_SERVICE_client_drop (client); | ||
2165 | return; | ||
2166 | } | ||
2167 | |||
2168 | offset = GNUNET_STRINGS_buffer_tokenize ((const char *) &creq[1], | ||
2169 | (size_t) app_id_size, | ||
2170 | 1, | ||
2171 | &app_id); | ||
2172 | if (0 == offset || offset != app_id_size) | ||
2173 | { | ||
2174 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
2175 | "AppConnectRequest contains invalid app ID\n"); | ||
2176 | GNUNET_break (0); | ||
2177 | GNUNET_SERVICE_client_drop (client); | ||
2178 | return; | ||
2179 | } | ||
2180 | |||
2181 | struct GNUNET_HashCode app_id_hash; | ||
2182 | GNUNET_CRYPTO_hash (app_id, (size_t) app_id_size, &app_id_hash); | ||
2183 | |||
2184 | GNUNET_CONTAINER_multihashmap_iterate (egos, ego_entry, client); | ||
2185 | app_notify_ego_end (client); | ||
2186 | |||
2187 | struct GNUNET_CONTAINER_MultiHashMap * | ||
2188 | app_places = GNUNET_CONTAINER_multihashmap_get (apps_places, &app_id_hash); | ||
2189 | if (NULL != app_places) | ||
2190 | GNUNET_CONTAINER_multihashmap_iterate (app_places, app_place_entry_notify, client); | ||
2191 | app_notify_place_end (client); | ||
2192 | |||
2193 | struct ClientListItem *cli = GNUNET_new (struct ClientListItem); | ||
2194 | cli->client = client; | ||
2195 | struct Application *app = GNUNET_CONTAINER_multihashmap_get (apps, | ||
2196 | &app_id_hash); | ||
2197 | if (NULL == app) { | ||
2198 | app = GNUNET_malloc (sizeof (*app)); | ||
2199 | (void) GNUNET_CONTAINER_multihashmap_put (apps, &app_id_hash, app, | ||
2200 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); | ||
2201 | } | ||
2202 | GNUNET_CONTAINER_DLL_insert (app->clients_head, app->clients_tail, cli); | ||
2203 | |||
2204 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2205 | "%p Application %s connected.\n", app, app_id); | ||
2206 | |||
2207 | c->app_id = GNUNET_malloc ((size_t) app_id_size); | ||
2208 | GNUNET_memcpy (c->app_id, app_id, (size_t) app_id_size); | ||
2209 | |||
2210 | GNUNET_SERVICE_client_continue (client); | ||
2211 | } | ||
2212 | |||
2213 | |||
2214 | /** | ||
2215 | * Handle application detach request. | ||
2216 | */ | ||
2217 | static void | ||
2218 | handle_client_app_detach (void *cls, | ||
2219 | const struct AppDetachRequest *req) | ||
2220 | { | ||
2221 | struct Client *c = cls; | ||
2222 | struct GNUNET_SERVICE_Client *client = c->client; | ||
2223 | |||
2224 | int ret = app_place_remove (c->app_id, &req->ego_pub_key, &req->place_pub_key); | ||
2225 | client_send_result (client, req->op_id, ret, NULL, 0); | ||
2226 | |||
2227 | GNUNET_SERVICE_client_continue (client); | ||
2228 | } | ||
2229 | |||
2230 | |||
2231 | static void | ||
2232 | place_leave_cb (void *cls) | ||
2233 | { | ||
2234 | struct Place *plc = cls; | ||
2235 | |||
2236 | place_send_leave_ack (plc); | ||
2237 | (GNUNET_YES == plc->is_host) | ||
2238 | ? cleanup_host ((struct Host *) plc) | ||
2239 | : cleanup_guest ((struct Guest *) plc); | ||
2240 | } | ||
2241 | |||
2242 | |||
2243 | /** | ||
2244 | * Handle application leave request. | ||
2245 | */ | ||
2246 | static void | ||
2247 | handle_client_place_leave (void *cls, | ||
2248 | const struct GNUNET_MessageHeader *msg) | ||
2249 | { | ||
2250 | struct Client *c = cls; | ||
2251 | struct GNUNET_SERVICE_Client *client = c->client; | ||
2252 | struct Place *plc = c->place; | ||
2253 | |||
2254 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2255 | "got leave request from %s for place %s", | ||
2256 | plc->is_host? "host" : "slave", | ||
2257 | GNUNET_h2s (&plc->pub_key_hash)); | ||
2258 | if (NULL == plc) | ||
2259 | { | ||
2260 | GNUNET_break (0); | ||
2261 | GNUNET_SERVICE_client_drop (client); | ||
2262 | return; | ||
2263 | } | ||
2264 | |||
2265 | if (GNUNET_YES != plc->is_disconnecting) | ||
2266 | { | ||
2267 | plc->is_disconnecting = GNUNET_YES; | ||
2268 | if (plc->is_host) | ||
2269 | { | ||
2270 | struct Host *host = plc->host; | ||
2271 | GNUNET_assert (NULL != host); | ||
2272 | GNUNET_PSYC_master_stop (host->master, GNUNET_NO, &place_leave_cb, plc); | ||
2273 | } | ||
2274 | else | ||
2275 | { | ||
2276 | struct Guest *guest = plc->guest; | ||
2277 | GNUNET_assert (NULL != guest); | ||
2278 | GNUNET_PSYC_slave_part (guest->slave, GNUNET_NO, &place_leave_cb, plc); | ||
2279 | } | ||
2280 | } | ||
2281 | else | ||
2282 | { | ||
2283 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
2284 | "got leave request but place is already leaving\n"); | ||
2285 | } | ||
2286 | GNUNET_SERVICE_client_continue (client); | ||
2287 | } | ||
2288 | |||
2289 | |||
2290 | struct JoinDecisionClosure | ||
2291 | { | ||
2292 | int32_t is_admitted; | ||
2293 | struct GNUNET_PSYC_Message *msg; | ||
2294 | }; | ||
2295 | |||
2296 | |||
2297 | /** | ||
2298 | * Iterator callback for responding to join requests. | ||
2299 | */ | ||
2300 | static int | ||
2301 | psyc_send_join_decision (void *cls, const struct GNUNET_HashCode *pub_key_hash, | ||
2302 | void *value) | ||
2303 | { | ||
2304 | struct JoinDecisionClosure *jcls = cls; | ||
2305 | struct GNUNET_PSYC_JoinHandle *jh = value; | ||
2306 | // FIXME: add relays | ||
2307 | GNUNET_PSYC_join_decision (jh, jcls->is_admitted, 0, NULL, jcls->msg); | ||
2308 | return GNUNET_YES; | ||
2309 | } | ||
2310 | |||
2311 | |||
2312 | static int | ||
2313 | check_client_join_decision (void *cls, | ||
2314 | const struct GNUNET_PSYC_JoinDecisionMessage *dcsn) | ||
2315 | { | ||
2316 | return GNUNET_OK; | ||
2317 | } | ||
2318 | |||
2319 | |||
2320 | /** | ||
2321 | * Handle an entry decision from a host client. | ||
2322 | */ | ||
2323 | static void | ||
2324 | handle_client_join_decision (void *cls, | ||
2325 | const struct GNUNET_PSYC_JoinDecisionMessage *dcsn) | ||
2326 | { | ||
2327 | struct Client *c = cls; | ||
2328 | struct GNUNET_SERVICE_Client *client = c->client; | ||
2329 | struct Place *plc = c->place; | ||
2330 | if (NULL == plc || GNUNET_YES != plc->is_host) | ||
2331 | { | ||
2332 | GNUNET_break (0); | ||
2333 | GNUNET_SERVICE_client_drop (client); | ||
2334 | return; | ||
2335 | } | ||
2336 | struct Host *hst = plc->host; | ||
2337 | |||
2338 | struct JoinDecisionClosure jcls; | ||
2339 | jcls.is_admitted = ntohl (dcsn->is_admitted); | ||
2340 | jcls.msg | ||
2341 | = (sizeof (*dcsn) + sizeof (*jcls.msg) <= ntohs (dcsn->header.size)) | ||
2342 | ? (struct GNUNET_PSYC_Message *) &dcsn[1] | ||
2343 | : NULL; | ||
2344 | |||
2345 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2346 | "jcls.msg = %p\n", | ||
2347 | jcls.msg); | ||
2348 | struct GNUNET_HashCode slave_pub_hash; | ||
2349 | GNUNET_CRYPTO_hash (&dcsn->slave_pub_key, sizeof (dcsn->slave_pub_key), | ||
2350 | &slave_pub_hash); | ||
2351 | |||
2352 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2353 | "%p Got join decision (%d) from client for place %s..\n", | ||
2354 | hst, jcls.is_admitted, GNUNET_h2s (&plc->pub_key_hash)); | ||
2355 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2356 | "%p ..and slave %s.\n", | ||
2357 | hst, GNUNET_h2s (&slave_pub_hash)); | ||
2358 | |||
2359 | GNUNET_CONTAINER_multihashmap_get_multiple (hst->join_reqs, &slave_pub_hash, | ||
2360 | &psyc_send_join_decision, &jcls); | ||
2361 | GNUNET_CONTAINER_multihashmap_remove_all (hst->join_reqs, &slave_pub_hash); | ||
2362 | |||
2363 | GNUNET_SERVICE_client_continue (client); | ||
2364 | } | ||
2365 | |||
2366 | |||
2367 | /** | ||
2368 | * Send acknowledgement to a client. | ||
2369 | * | ||
2370 | * Sent after a message fragment has been passed on to multicast. | ||
2371 | * | ||
2372 | * @param plc The place struct for the client. | ||
2373 | */ | ||
2374 | static void | ||
2375 | send_message_ack (struct Place *plc, struct GNUNET_SERVICE_Client *client) | ||
2376 | { | ||
2377 | struct GNUNET_MQ_Envelope *env; | ||
2378 | |||
2379 | env = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_ACK); | ||
2380 | GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client), | ||
2381 | env); | ||
2382 | } | ||
2383 | |||
2384 | |||
2385 | /** | ||
2386 | * Proceed to the next message part in the transmission queue. | ||
2387 | * | ||
2388 | * @param plc | ||
2389 | * Place where the transmission is going on. | ||
2390 | * @param tmit_msg | ||
2391 | * Currently transmitted message. | ||
2392 | * @param tmit_frag | ||
2393 | * Currently transmitted message fragment. | ||
2394 | * | ||
2395 | * @return @a tmit_frag, or NULL if reached the end of fragment. | ||
2396 | */ | ||
2397 | static struct FragmentTransmitQueue * | ||
2398 | psyc_transmit_queue_next_part (struct Place *plc, | ||
2399 | struct MessageTransmitQueue *tmit_msg, | ||
2400 | struct FragmentTransmitQueue *tmit_frag) | ||
2401 | { | ||
2402 | uint16_t psize = ntohs (tmit_frag->next_part->size); | ||
2403 | if ((char *) tmit_frag->next_part + psize - ((char *) &tmit_frag[1]) | ||
2404 | < tmit_frag->size) | ||
2405 | { | ||
2406 | tmit_frag->next_part | ||
2407 | = (struct GNUNET_MessageHeader *) ((char *) tmit_frag->next_part + psize); | ||
2408 | } | ||
2409 | else /* Reached end of current fragment. */ | ||
2410 | { | ||
2411 | if (NULL != tmit_frag->client) | ||
2412 | send_message_ack (plc, tmit_frag->client); | ||
2413 | GNUNET_CONTAINER_DLL_remove (tmit_msg->frags_head, tmit_msg->frags_tail, tmit_frag); | ||
2414 | GNUNET_free (tmit_frag); | ||
2415 | tmit_frag = NULL; | ||
2416 | } | ||
2417 | return tmit_frag; | ||
2418 | } | ||
2419 | |||
2420 | |||
2421 | /** | ||
2422 | * Proceed to next message in transmission queue. | ||
2423 | * | ||
2424 | * @param plc | ||
2425 | * Place where the transmission is going on. | ||
2426 | * @param tmit_msg | ||
2427 | * Currently transmitted message. | ||
2428 | * | ||
2429 | * @return The next message in queue, or NULL if queue is empty. | ||
2430 | */ | ||
2431 | static struct MessageTransmitQueue * | ||
2432 | psyc_transmit_queue_next_msg (struct Place *plc, | ||
2433 | struct MessageTransmitQueue *tmit_msg) | ||
2434 | { | ||
2435 | GNUNET_CONTAINER_DLL_remove (plc->tmit_msgs_head, plc->tmit_msgs_tail, tmit_msg); | ||
2436 | GNUNET_free (tmit_msg); | ||
2437 | return plc->tmit_msgs_head; | ||
2438 | } | ||
2439 | |||
2440 | |||
2441 | /** | ||
2442 | * Callback for data transmission to PSYC. | ||
2443 | */ | ||
2444 | static int | ||
2445 | psyc_transmit_notify_data (void *cls, uint16_t *data_size, void *data) | ||
2446 | { | ||
2447 | struct Place *plc = cls; | ||
2448 | struct MessageTransmitQueue *tmit_msg = plc->tmit_msgs_head; | ||
2449 | GNUNET_assert (NULL != tmit_msg); | ||
2450 | struct FragmentTransmitQueue *tmit_frag = tmit_msg->frags_head; | ||
2451 | if (NULL == tmit_frag) | ||
2452 | { /* Rest of the message have not arrived yet, pause transmission */ | ||
2453 | *data_size = 0; | ||
2454 | return GNUNET_NO; | ||
2455 | } | ||
2456 | struct GNUNET_MessageHeader *pmsg = tmit_frag->next_part; | ||
2457 | if (NULL == pmsg) | ||
2458 | { | ||
2459 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2460 | "%p psyc_transmit_notify_data: nothing to send.\n", plc); | ||
2461 | *data_size = 0; | ||
2462 | return GNUNET_NO; | ||
2463 | } | ||
2464 | |||
2465 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2466 | "%p psyc_transmit_notify_data()\n", plc); | ||
2467 | GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, pmsg); | ||
2468 | |||
2469 | uint16_t ptype = ntohs (pmsg->type); | ||
2470 | uint16_t pdata_size = ntohs (pmsg->size) - sizeof (*pmsg); | ||
2471 | int ret; | ||
2472 | |||
2473 | switch (ptype) | ||
2474 | { | ||
2475 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA: | ||
2476 | if (*data_size < pdata_size) | ||
2477 | { | ||
2478 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2479 | "%p psyc_transmit_notify_data: buffer size too small for data.\n", plc); | ||
2480 | *data_size = 0; | ||
2481 | return GNUNET_NO; | ||
2482 | } | ||
2483 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2484 | "%p psyc_transmit_notify_data: sending %u bytes.\n", | ||
2485 | plc, pdata_size); | ||
2486 | |||
2487 | *data_size = pdata_size; | ||
2488 | GNUNET_memcpy (data, &pmsg[1], *data_size); | ||
2489 | ret = GNUNET_NO; | ||
2490 | break; | ||
2491 | |||
2492 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END: | ||
2493 | *data_size = 0; | ||
2494 | ret = GNUNET_YES; | ||
2495 | break; | ||
2496 | |||
2497 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL: | ||
2498 | *data_size = 0; | ||
2499 | ret = GNUNET_SYSERR; | ||
2500 | break; | ||
2501 | |||
2502 | default: | ||
2503 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
2504 | "%p psyc_transmit_notify_data: unexpected message part of type %u.\n", | ||
2505 | plc, ptype); | ||
2506 | ret = GNUNET_SYSERR; | ||
2507 | } | ||
2508 | |||
2509 | if (GNUNET_SYSERR == ret && GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL != ptype) | ||
2510 | { | ||
2511 | *data_size = 0; | ||
2512 | tmit_msg = psyc_transmit_queue_next_msg (plc, tmit_msg); | ||
2513 | GNUNET_SERVICE_client_drop (tmit_frag->client); | ||
2514 | GNUNET_SCHEDULER_add_now (&cleanup_place, plc); | ||
2515 | return ret; | ||
2516 | } | ||
2517 | else | ||
2518 | { | ||
2519 | tmit_frag = psyc_transmit_queue_next_part (plc, tmit_msg, tmit_frag); | ||
2520 | if (NULL != tmit_frag) | ||
2521 | { | ||
2522 | struct GNUNET_MessageHeader *pmsg = tmit_frag->next_part; | ||
2523 | ptype = ntohs (pmsg->type); | ||
2524 | switch (ptype) | ||
2525 | { | ||
2526 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END: | ||
2527 | ret = GNUNET_YES; | ||
2528 | break; | ||
2529 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL: | ||
2530 | ret = GNUNET_SYSERR; | ||
2531 | break; | ||
2532 | } | ||
2533 | switch (ptype) | ||
2534 | { | ||
2535 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END: | ||
2536 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL: | ||
2537 | tmit_frag = psyc_transmit_queue_next_part (plc, tmit_msg, tmit_frag); | ||
2538 | } | ||
2539 | } | ||
2540 | |||
2541 | if (NULL == tmit_msg->frags_head | ||
2542 | && GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= ptype) | ||
2543 | { /* Reached end of current message. */ | ||
2544 | tmit_msg = psyc_transmit_queue_next_msg (plc, tmit_msg); | ||
2545 | } | ||
2546 | } | ||
2547 | |||
2548 | if (ret != GNUNET_NO) | ||
2549 | { | ||
2550 | if (NULL != tmit_msg) | ||
2551 | { | ||
2552 | psyc_transmit_message (plc); | ||
2553 | } | ||
2554 | /* FIXME: handle partial message (when still in_transmit) */ | ||
2555 | } | ||
2556 | return ret; | ||
2557 | } | ||
2558 | |||
2559 | |||
2560 | /** | ||
2561 | * Callback for modifier transmission to PSYC. | ||
2562 | */ | ||
2563 | static int | ||
2564 | psyc_transmit_notify_mod (void *cls, uint16_t *data_size, void *data, | ||
2565 | uint8_t *oper, uint32_t *full_value_size) | ||
2566 | { | ||
2567 | struct Place *plc = cls; | ||
2568 | struct MessageTransmitQueue *tmit_msg = plc->tmit_msgs_head; | ||
2569 | GNUNET_assert (NULL != tmit_msg); | ||
2570 | struct FragmentTransmitQueue *tmit_frag = tmit_msg->frags_head; | ||
2571 | if (NULL == tmit_frag) | ||
2572 | { /* Rest of the message have not arrived yet, pause transmission */ | ||
2573 | *data_size = 0; | ||
2574 | return GNUNET_NO; | ||
2575 | } | ||
2576 | struct GNUNET_MessageHeader *pmsg = tmit_frag->next_part; | ||
2577 | if (NULL == pmsg) | ||
2578 | { | ||
2579 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2580 | "%p psyc_transmit_notify_mod: nothing to send.\n", plc); | ||
2581 | *data_size = 0; | ||
2582 | return GNUNET_NO; | ||
2583 | } | ||
2584 | |||
2585 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2586 | "%p psyc_transmit_notify_mod()\n", plc); | ||
2587 | GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, pmsg); | ||
2588 | |||
2589 | uint16_t ptype = ntohs (pmsg->type); | ||
2590 | int ret; | ||
2591 | |||
2592 | switch (ptype) | ||
2593 | { | ||
2594 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER: | ||
2595 | { | ||
2596 | if (NULL == oper) | ||
2597 | { | ||
2598 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
2599 | "%p psyc_transmit_notify_mod: oper is NULL.\n", plc); | ||
2600 | ret = GNUNET_SYSERR; | ||
2601 | break; | ||
2602 | } | ||
2603 | struct GNUNET_PSYC_MessageModifier * | ||
2604 | pmod = (struct GNUNET_PSYC_MessageModifier *) tmit_frag->next_part; | ||
2605 | uint16_t mod_size = ntohs (pmod->header.size) - sizeof (*pmod); | ||
2606 | |||
2607 | if (*data_size < mod_size) | ||
2608 | { | ||
2609 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2610 | "%p psyc_transmit_notify_mod: buffer size too small for data.\n", plc); | ||
2611 | *data_size = 0; | ||
2612 | return GNUNET_NO; | ||
2613 | } | ||
2614 | |||
2615 | *full_value_size = ntohl (pmod->value_size); | ||
2616 | *oper = pmod->oper; | ||
2617 | *data_size = mod_size; | ||
2618 | GNUNET_memcpy (data, &pmod[1], mod_size); | ||
2619 | ret = GNUNET_NO; | ||
2620 | break; | ||
2621 | } | ||
2622 | |||
2623 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT: | ||
2624 | { | ||
2625 | if (NULL != oper) | ||
2626 | { | ||
2627 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
2628 | "%p psyc_transmit_notify_mod: oper is not NULL.\n", plc); | ||
2629 | ret = GNUNET_SYSERR; | ||
2630 | break; | ||
2631 | } | ||
2632 | uint16_t mod_size = ntohs (pmsg->size) - sizeof (*pmsg); | ||
2633 | if (*data_size < mod_size) | ||
2634 | { | ||
2635 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2636 | "%p psyc_transmit_notify_mod: buffer size too small for data.\n", plc); | ||
2637 | *data_size = 0; | ||
2638 | return GNUNET_NO; | ||
2639 | } | ||
2640 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2641 | "%p psyc_transmit_notify_mod: sending %u bytes.\n", plc, mod_size); | ||
2642 | |||
2643 | *data_size = mod_size; | ||
2644 | GNUNET_memcpy (data, &pmsg[1], *data_size); | ||
2645 | ret = GNUNET_NO; | ||
2646 | break; | ||
2647 | } | ||
2648 | |||
2649 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_DATA: | ||
2650 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END: | ||
2651 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL: | ||
2652 | *data_size = 0; | ||
2653 | ret = GNUNET_YES; | ||
2654 | break; | ||
2655 | |||
2656 | default: | ||
2657 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
2658 | "%p psyc_transmit_notify_mod: unexpected message part of type %u.\n", | ||
2659 | plc, ptype); | ||
2660 | ret = GNUNET_SYSERR; | ||
2661 | } | ||
2662 | |||
2663 | if (GNUNET_SYSERR == ret) | ||
2664 | { | ||
2665 | *data_size = 0; | ||
2666 | ret = GNUNET_SYSERR; | ||
2667 | tmit_msg = psyc_transmit_queue_next_msg (plc, tmit_msg); | ||
2668 | GNUNET_SERVICE_client_drop (tmit_frag->client); | ||
2669 | GNUNET_SCHEDULER_add_now (&cleanup_place, plc); | ||
2670 | } | ||
2671 | else | ||
2672 | { | ||
2673 | if (GNUNET_YES != ret) | ||
2674 | psyc_transmit_queue_next_part (plc, tmit_msg, tmit_frag); | ||
2675 | |||
2676 | if (NULL == tmit_msg->frags_head | ||
2677 | && GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= ptype) | ||
2678 | { /* Reached end of current message. */ | ||
2679 | tmit_msg = psyc_transmit_queue_next_msg (plc, tmit_msg); | ||
2680 | } | ||
2681 | } | ||
2682 | return ret; | ||
2683 | } | ||
2684 | |||
2685 | /** | ||
2686 | * Callback for data transmission from a host to PSYC. | ||
2687 | */ | ||
2688 | static int | ||
2689 | host_transmit_notify_data (void *cls, uint16_t *data_size, void *data) | ||
2690 | { | ||
2691 | int ret = psyc_transmit_notify_data (cls, data_size, data); | ||
2692 | |||
2693 | if (GNUNET_NO != ret) | ||
2694 | { | ||
2695 | struct Host *hst = cls; | ||
2696 | hst->tmit_handle = NULL; | ||
2697 | } | ||
2698 | return ret; | ||
2699 | } | ||
2700 | |||
2701 | |||
2702 | /** | ||
2703 | * Callback for the transmit functions of multicast. | ||
2704 | */ | ||
2705 | static int | ||
2706 | guest_transmit_notify_data (void *cls, uint16_t *data_size, void *data) | ||
2707 | { | ||
2708 | int ret = psyc_transmit_notify_data (cls, data_size, data); | ||
2709 | |||
2710 | if (GNUNET_NO != ret) | ||
2711 | { | ||
2712 | struct Guest *gst = cls; | ||
2713 | gst->tmit_handle = NULL; | ||
2714 | } | ||
2715 | return ret; | ||
2716 | } | ||
2717 | |||
2718 | |||
2719 | /** | ||
2720 | * Callback for modifier transmission from a host to PSYC. | ||
2721 | */ | ||
2722 | static int | ||
2723 | host_transmit_notify_mod (void *cls, uint16_t *data_size, void *data, | ||
2724 | uint8_t *oper, uint32_t *full_value_size) | ||
2725 | { | ||
2726 | int ret = psyc_transmit_notify_mod (cls, data_size, data, | ||
2727 | oper, full_value_size); | ||
2728 | if (GNUNET_SYSERR == ret) | ||
2729 | { | ||
2730 | struct Host *hst = cls; | ||
2731 | hst->tmit_handle = NULL; | ||
2732 | } | ||
2733 | return ret; | ||
2734 | } | ||
2735 | |||
2736 | |||
2737 | /** | ||
2738 | * Callback for modifier transmission from a guest to PSYC. | ||
2739 | */ | ||
2740 | static int | ||
2741 | guest_transmit_notify_mod (void *cls, uint16_t *data_size, void *data, | ||
2742 | uint8_t *oper, uint32_t *full_value_size) | ||
2743 | { | ||
2744 | int ret = psyc_transmit_notify_mod (cls, data_size, data, | ||
2745 | oper, full_value_size); | ||
2746 | if (GNUNET_SYSERR == ret) | ||
2747 | { | ||
2748 | struct Guest *gst = cls; | ||
2749 | gst->tmit_handle = NULL; | ||
2750 | } | ||
2751 | return ret; | ||
2752 | } | ||
2753 | |||
2754 | |||
2755 | /** | ||
2756 | * Get method part of next message from transmission queue. | ||
2757 | * | ||
2758 | * @param plc | ||
2759 | * Place | ||
2760 | * | ||
2761 | * @return #GNUNET_OK on success | ||
2762 | * #GNUNET_NO if there are no more messages in queue. | ||
2763 | * #GNUNET_SYSERR if the next message is malformed. | ||
2764 | */ | ||
2765 | static struct GNUNET_PSYC_MessageMethod * | ||
2766 | psyc_transmit_queue_next_method (struct Place *plc) | ||
2767 | { | ||
2768 | struct MessageTransmitQueue *tmit_msg = plc->tmit_msgs_head; | ||
2769 | if (NULL == tmit_msg) | ||
2770 | return GNUNET_NO; | ||
2771 | |||
2772 | struct FragmentTransmitQueue *tmit_frag = tmit_msg->frags_head; | ||
2773 | if (NULL == tmit_frag) | ||
2774 | { | ||
2775 | GNUNET_break (0); | ||
2776 | return GNUNET_NO; | ||
2777 | } | ||
2778 | |||
2779 | struct GNUNET_MessageHeader *pmsg = tmit_frag->next_part; | ||
2780 | if (NULL == pmsg | ||
2781 | || GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD != ntohs (pmsg->type)) | ||
2782 | { | ||
2783 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
2784 | "%p psyc_transmit_queue_next_method: unexpected message part of type %u.\n", | ||
2785 | plc, NULL != pmsg ? ntohs (pmsg->type) : 0); | ||
2786 | GNUNET_break (0); | ||
2787 | return NULL; | ||
2788 | } | ||
2789 | |||
2790 | uint16_t psize = ntohs (pmsg->size); | ||
2791 | struct GNUNET_PSYC_MessageMethod * | ||
2792 | pmeth = (struct GNUNET_PSYC_MessageMethod *) GNUNET_copy_message (pmsg); | ||
2793 | |||
2794 | if (psize < sizeof (*pmeth) + 1 || '\0' != *((char *) pmeth + psize - 1)) | ||
2795 | { | ||
2796 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
2797 | "%p psyc_transmit_queue_next_method: invalid method name.\n", | ||
2798 | plc); | ||
2799 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
2800 | "%zu <= %u || NUL != %u\n", | ||
2801 | sizeof (*pmeth), psize, *((char *) pmeth + psize - 1)); | ||
2802 | GNUNET_break (0); | ||
2803 | GNUNET_free (pmeth); | ||
2804 | return NULL; | ||
2805 | } | ||
2806 | |||
2807 | psyc_transmit_queue_next_part (plc, tmit_msg, tmit_frag); | ||
2808 | return pmeth; | ||
2809 | } | ||
2810 | |||
2811 | |||
2812 | /** | ||
2813 | * Transmit the next message in queue from the host to the PSYC channel. | ||
2814 | */ | ||
2815 | static int | ||
2816 | psyc_master_transmit_message (struct Host *hst) | ||
2817 | { | ||
2818 | struct Place *plc = &hst->place; | ||
2819 | |||
2820 | if (NULL == hst->tmit_handle) | ||
2821 | { | ||
2822 | struct GNUNET_PSYC_MessageMethod * | ||
2823 | pmeth = psyc_transmit_queue_next_method (plc); | ||
2824 | if (NULL == pmeth) | ||
2825 | return GNUNET_SYSERR; | ||
2826 | |||
2827 | hst->tmit_handle = (void *) &hst->tmit_handle; | ||
2828 | struct GNUNET_PSYC_MasterTransmitHandle * | ||
2829 | tmit_handle = GNUNET_PSYC_master_transmit (hst->master, (const char *) &pmeth[1], | ||
2830 | &host_transmit_notify_mod, | ||
2831 | &host_transmit_notify_data, hst, | ||
2832 | pmeth->flags); | ||
2833 | if (NULL != hst->tmit_handle) | ||
2834 | hst->tmit_handle = tmit_handle; | ||
2835 | GNUNET_free (pmeth); | ||
2836 | } | ||
2837 | else | ||
2838 | { | ||
2839 | GNUNET_PSYC_master_transmit_resume (hst->tmit_handle); | ||
2840 | } | ||
2841 | return GNUNET_OK; | ||
2842 | } | ||
2843 | |||
2844 | |||
2845 | /** | ||
2846 | * Transmit the next message in queue from a guest to the PSYC channel. | ||
2847 | */ | ||
2848 | static int | ||
2849 | psyc_slave_transmit_message (struct Guest *gst) | ||
2850 | { | ||
2851 | struct Place *plc = &gst->place; | ||
2852 | |||
2853 | if (NULL == gst->tmit_handle) | ||
2854 | { | ||
2855 | struct GNUNET_PSYC_MessageMethod * | ||
2856 | pmeth = psyc_transmit_queue_next_method (plc); | ||
2857 | if (NULL == pmeth) | ||
2858 | return GNUNET_SYSERR; | ||
2859 | |||
2860 | gst->tmit_handle = (void *) &gst->tmit_handle; | ||
2861 | struct GNUNET_PSYC_SlaveTransmitHandle * | ||
2862 | tmit_handle = GNUNET_PSYC_slave_transmit (gst->slave, (const char *) &pmeth[1], | ||
2863 | &guest_transmit_notify_mod, | ||
2864 | &guest_transmit_notify_data, gst, | ||
2865 | pmeth->flags); | ||
2866 | if (NULL != gst->tmit_handle) | ||
2867 | gst->tmit_handle = tmit_handle; | ||
2868 | GNUNET_free (pmeth); | ||
2869 | } | ||
2870 | else | ||
2871 | { | ||
2872 | GNUNET_PSYC_slave_transmit_resume (gst->tmit_handle); | ||
2873 | } | ||
2874 | return GNUNET_OK; | ||
2875 | } | ||
2876 | |||
2877 | |||
2878 | /** | ||
2879 | * Transmit a message to PSYC. | ||
2880 | */ | ||
2881 | static int | ||
2882 | psyc_transmit_message (struct Place *plc) | ||
2883 | { | ||
2884 | return | ||
2885 | (plc->is_host) | ||
2886 | ? psyc_master_transmit_message ((struct Host *) plc) | ||
2887 | : psyc_slave_transmit_message ((struct Guest *) plc); | ||
2888 | } | ||
2889 | |||
2890 | |||
2891 | /** | ||
2892 | * Queue message parts for sending to PSYC. | ||
2893 | * | ||
2894 | * @param plc Place to send to. | ||
2895 | * @param client Client the message originates from. | ||
2896 | * @param data_size Size of @a data. | ||
2897 | * @param data Concatenated message parts. | ||
2898 | * @param first_ptype First message part type in @a data. | ||
2899 | * @param last_ptype Last message part type in @a data. | ||
2900 | */ | ||
2901 | static struct MessageTransmitQueue * | ||
2902 | psyc_transmit_queue_message (struct Place *plc, | ||
2903 | struct GNUNET_SERVICE_Client *client, | ||
2904 | size_t data_size, | ||
2905 | const void *data, | ||
2906 | uint16_t first_ptype, uint16_t last_ptype, | ||
2907 | struct MessageTransmitQueue *tmit_msg) | ||
2908 | { | ||
2909 | if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_METHOD == first_ptype) | ||
2910 | { | ||
2911 | tmit_msg = GNUNET_malloc (sizeof (*tmit_msg)); | ||
2912 | GNUNET_CONTAINER_DLL_insert_tail (plc->tmit_msgs_head, plc->tmit_msgs_tail, tmit_msg); | ||
2913 | } | ||
2914 | else if (NULL == tmit_msg) | ||
2915 | { | ||
2916 | return NULL; | ||
2917 | } | ||
2918 | |||
2919 | struct FragmentTransmitQueue * | ||
2920 | tmit_frag = GNUNET_malloc (sizeof (*tmit_frag) + data_size); | ||
2921 | GNUNET_memcpy (&tmit_frag[1], data, data_size); | ||
2922 | tmit_frag->next_part = (struct GNUNET_MessageHeader *) &tmit_frag[1]; | ||
2923 | tmit_frag->client = client; | ||
2924 | tmit_frag->size = data_size; | ||
2925 | |||
2926 | GNUNET_CONTAINER_DLL_insert_tail (tmit_msg->frags_head, tmit_msg->frags_tail, tmit_frag); | ||
2927 | tmit_msg->client = client; | ||
2928 | return tmit_msg; | ||
2929 | } | ||
2930 | |||
2931 | |||
2932 | ///** | ||
2933 | // * Cancel transmission of current message to PSYC. | ||
2934 | // * | ||
2935 | // * @param plc Place to send to. | ||
2936 | // * @param client Client the message originates from. | ||
2937 | // */ | ||
2938 | //static void | ||
2939 | //psyc_transmit_cancel (struct Place *plc, struct GNUNET_SERVICE_Client *client) | ||
2940 | //{ | ||
2941 | // uint16_t type = GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_CANCEL; | ||
2942 | // | ||
2943 | // struct GNUNET_MessageHeader msg; | ||
2944 | // msg.size = htons (sizeof (msg)); | ||
2945 | // msg.type = htons (type); | ||
2946 | // | ||
2947 | // psyc_transmit_queue_message (plc, client, sizeof (msg), &msg, type, type, NULL); | ||
2948 | // psyc_transmit_message (plc); | ||
2949 | // | ||
2950 | // /* FIXME: cleanup */ | ||
2951 | //} | ||
2952 | |||
2953 | |||
2954 | static int | ||
2955 | check_client_psyc_message (void *cls, | ||
2956 | const struct GNUNET_MessageHeader *msg) | ||
2957 | { | ||
2958 | return GNUNET_OK; | ||
2959 | } | ||
2960 | |||
2961 | |||
2962 | /** | ||
2963 | * Handle an incoming message from a client, to be transmitted to the place. | ||
2964 | */ | ||
2965 | static void | ||
2966 | handle_client_psyc_message (void *cls, | ||
2967 | const struct GNUNET_MessageHeader *msg) | ||
2968 | { | ||
2969 | struct Client *c = cls; | ||
2970 | struct GNUNET_SERVICE_Client *client = c->client; | ||
2971 | struct Place *plc = c->place; | ||
2972 | int ret; | ||
2973 | |||
2974 | if (NULL == plc) | ||
2975 | { | ||
2976 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
2977 | "received PSYC message for non-existing client %p\n", | ||
2978 | client); | ||
2979 | GNUNET_break (0); | ||
2980 | GNUNET_SERVICE_client_drop (client); | ||
2981 | return; | ||
2982 | } | ||
2983 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2984 | "%p Received message of type %d from client.\n", plc, ntohs (msg->type)); | ||
2985 | GNUNET_PSYC_log_message (GNUNET_ERROR_TYPE_DEBUG, msg); | ||
2986 | |||
2987 | if (GNUNET_YES != plc->is_ready) | ||
2988 | { | ||
2989 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
2990 | "%p Place is not ready yet, disconnecting client.\n", plc); | ||
2991 | GNUNET_break (0); | ||
2992 | GNUNET_SERVICE_client_drop (client); | ||
2993 | return; | ||
2994 | } | ||
2995 | |||
2996 | uint16_t size = ntohs (msg->size); | ||
2997 | uint16_t psize = size - sizeof (*msg); | ||
2998 | if (psize < sizeof (struct GNUNET_MessageHeader) | ||
2999 | || GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD < psize) | ||
3000 | { | ||
3001 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
3002 | "%p Received message with invalid payload size (%u) from client.\n", | ||
3003 | plc, psize); | ||
3004 | GNUNET_break (0); | ||
3005 | GNUNET_SERVICE_client_drop (client); | ||
3006 | return; | ||
3007 | } | ||
3008 | |||
3009 | uint16_t first_ptype = 0; | ||
3010 | uint16_t last_ptype = 0; | ||
3011 | if (GNUNET_SYSERR == | ||
3012 | GNUNET_PSYC_receive_check_parts (psize, (const char *) &msg[1], | ||
3013 | &first_ptype, &last_ptype)) | ||
3014 | { | ||
3015 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
3016 | "%p Received invalid message part from client.\n", plc); | ||
3017 | GNUNET_break (0); | ||
3018 | GNUNET_SERVICE_client_drop (client); | ||
3019 | return; | ||
3020 | } | ||
3021 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3022 | "%p Received message with first part type %u and last part type %u.\n", | ||
3023 | plc, first_ptype, last_ptype); | ||
3024 | |||
3025 | c->tmit_msg | ||
3026 | = psyc_transmit_queue_message (plc, client, psize, &msg[1], | ||
3027 | first_ptype, last_ptype, c->tmit_msg); | ||
3028 | if (NULL != c->tmit_msg) | ||
3029 | { | ||
3030 | if (GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_END <= last_ptype) | ||
3031 | c->tmit_msg = NULL; | ||
3032 | ret = psyc_transmit_message (plc); | ||
3033 | } | ||
3034 | else | ||
3035 | { | ||
3036 | ret = GNUNET_SYSERR; | ||
3037 | } | ||
3038 | if (GNUNET_OK != ret) | ||
3039 | { | ||
3040 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
3041 | "%p Received invalid message part from client.\n", plc); | ||
3042 | GNUNET_break (0); | ||
3043 | GNUNET_SERVICE_client_drop (client); | ||
3044 | return; | ||
3045 | } | ||
3046 | GNUNET_SERVICE_client_continue (client); | ||
3047 | } | ||
3048 | |||
3049 | |||
3050 | /** | ||
3051 | * A historic message arrived from PSYC. | ||
3052 | */ | ||
3053 | static void | ||
3054 | psyc_recv_history_message (void *cls, const struct GNUNET_PSYC_MessageHeader *msg) | ||
3055 | { | ||
3056 | struct OperationClosure *opcls = cls; | ||
3057 | struct Client *c = opcls->client; | ||
3058 | struct Place *plc = c->place; | ||
3059 | |||
3060 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3061 | "%p Received historic message #%" PRId64 " (flags: %x)\n", | ||
3062 | plc, GNUNET_ntohll (msg->message_id), ntohl (msg->flags)); | ||
3063 | |||
3064 | uint16_t size = ntohs (msg->header.size); | ||
3065 | |||
3066 | struct GNUNET_OperationResultMessage * | ||
3067 | res = GNUNET_malloc (sizeof (*res) + size); | ||
3068 | res->header.size = htons (sizeof (*res) + size); | ||
3069 | res->header.type = htons (GNUNET_MESSAGE_TYPE_PSYC_HISTORY_RESULT); | ||
3070 | res->op_id = opcls->op_id; | ||
3071 | res->result_code = GNUNET_htonll (GNUNET_OK); | ||
3072 | |||
3073 | GNUNET_memcpy (&res[1], msg, size); | ||
3074 | |||
3075 | /** @todo FIXME: send only to requesting client */ | ||
3076 | place_send_msg (plc, GNUNET_MQ_msg_copy (&res->header)); | ||
3077 | |||
3078 | GNUNET_free (res); | ||
3079 | } | ||
3080 | |||
3081 | |||
3082 | /** | ||
3083 | * Result of message history replay from PSYC. | ||
3084 | */ | ||
3085 | static void | ||
3086 | psyc_recv_history_result (void *cls, int64_t result, | ||
3087 | const void *err_msg, uint16_t err_msg_size) | ||
3088 | { | ||
3089 | struct OperationClosure *opcls = cls; | ||
3090 | struct Client *c = opcls->client; | ||
3091 | struct Place *plc = c->place; | ||
3092 | |||
3093 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3094 | "%p History replay #%" PRIu64 ": " | ||
3095 | "PSYCstore returned %" PRId64 " (%.*s)\n", | ||
3096 | plc, GNUNET_ntohll (opcls->op_id), result, | ||
3097 | err_msg_size, (const char *) err_msg); | ||
3098 | |||
3099 | // FIXME: place might have been destroyed | ||
3100 | client_send_result (c->client, opcls->op_id, result, err_msg, err_msg_size); | ||
3101 | } | ||
3102 | |||
3103 | |||
3104 | static int | ||
3105 | check_client_history_replay (void *cls, | ||
3106 | const struct GNUNET_PSYC_HistoryRequestMessage *req) | ||
3107 | { | ||
3108 | return GNUNET_OK; | ||
3109 | } | ||
3110 | |||
3111 | |||
3112 | /** | ||
3113 | * Client requests channel history. | ||
3114 | */ | ||
3115 | static void | ||
3116 | handle_client_history_replay (void *cls, | ||
3117 | const struct GNUNET_PSYC_HistoryRequestMessage *req) | ||
3118 | { | ||
3119 | struct Client *c = cls; | ||
3120 | struct GNUNET_SERVICE_Client *client = c->client; | ||
3121 | struct Place *plc = c->place; | ||
3122 | if (NULL == plc) | ||
3123 | { | ||
3124 | GNUNET_break (0); | ||
3125 | GNUNET_SERVICE_client_drop (client); | ||
3126 | return; | ||
3127 | } | ||
3128 | |||
3129 | uint16_t size = ntohs (req->header.size); | ||
3130 | const char *method_prefix = (const char *) &req[1]; | ||
3131 | |||
3132 | if (size < sizeof (*req) + 1 | ||
3133 | || '\0' != method_prefix[size - sizeof (*req) - 1]) | ||
3134 | { | ||
3135 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
3136 | "%p History replay #%" PRIu64 ": " | ||
3137 | "invalid method prefix. size: %u < %zu?\n", | ||
3138 | plc, GNUNET_ntohll (req->op_id), size, sizeof (*req) + 1); | ||
3139 | GNUNET_break (0); | ||
3140 | GNUNET_SERVICE_client_drop (client); | ||
3141 | return; | ||
3142 | } | ||
3143 | |||
3144 | struct OperationClosure *opcls = GNUNET_malloc (sizeof (*opcls)); | ||
3145 | opcls->client = c; | ||
3146 | opcls->op_id = req->op_id; | ||
3147 | opcls->flags = ntohl (req->flags); | ||
3148 | |||
3149 | if (0 == req->message_limit) | ||
3150 | GNUNET_PSYC_channel_history_replay (plc->channel, | ||
3151 | GNUNET_ntohll (req->start_message_id), | ||
3152 | GNUNET_ntohll (req->end_message_id), | ||
3153 | method_prefix, opcls->flags, | ||
3154 | psyc_recv_history_message, NULL, | ||
3155 | psyc_recv_history_result, opcls); | ||
3156 | else | ||
3157 | GNUNET_PSYC_channel_history_replay_latest (plc->channel, | ||
3158 | GNUNET_ntohll (req->message_limit), | ||
3159 | method_prefix, opcls->flags, | ||
3160 | psyc_recv_history_message, NULL, | ||
3161 | psyc_recv_history_result, opcls); | ||
3162 | |||
3163 | GNUNET_SERVICE_client_continue (client); | ||
3164 | } | ||
3165 | |||
3166 | |||
3167 | /** | ||
3168 | * A state variable part arrived from PSYC. | ||
3169 | */ | ||
3170 | void | ||
3171 | psyc_recv_state_var (void *cls, | ||
3172 | const struct GNUNET_MessageHeader *mod, | ||
3173 | const char *name, | ||
3174 | const void *value, | ||
3175 | uint32_t value_size, | ||
3176 | uint32_t full_value_size) | ||
3177 | { | ||
3178 | struct GNUNET_OperationResultMessage *result_msg; | ||
3179 | struct GNUNET_MQ_Envelope *env; | ||
3180 | struct OperationClosure *opcls = cls; | ||
3181 | struct Client *c = opcls->client; | ||
3182 | struct Place *plc = c->place; | ||
3183 | uint16_t size = ntohs (mod->size); | ||
3184 | |||
3185 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3186 | "%p Received state variable %s from PSYC\n", | ||
3187 | plc, name); | ||
3188 | env = GNUNET_MQ_msg_extra (result_msg, | ||
3189 | size, | ||
3190 | GNUNET_MESSAGE_TYPE_PSYC_STATE_RESULT); | ||
3191 | result_msg->op_id = opcls->op_id; | ||
3192 | result_msg->result_code = GNUNET_htonll (GNUNET_OK); | ||
3193 | GNUNET_memcpy (&result_msg[1], mod, size); | ||
3194 | /** @todo FIXME: send only to requesting client */ | ||
3195 | place_send_msg (plc, env); | ||
3196 | } | ||
3197 | |||
3198 | |||
3199 | /** | ||
3200 | * Result of retrieving state variable from PSYC. | ||
3201 | */ | ||
3202 | static void | ||
3203 | psyc_recv_state_result (void *cls, int64_t result, | ||
3204 | const void *err_msg, uint16_t err_msg_size) | ||
3205 | { | ||
3206 | struct OperationClosure *opcls = cls; | ||
3207 | struct Client *c = opcls->client; | ||
3208 | struct Place *plc = c->place; | ||
3209 | |||
3210 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3211 | "%p State get #%" PRIu64 ": " | ||
3212 | "PSYCstore returned %" PRId64 " (%.*s)\n", | ||
3213 | plc, GNUNET_ntohll (opcls->op_id), result, | ||
3214 | err_msg_size, (const char *) err_msg); | ||
3215 | |||
3216 | // FIXME: place might have been destroyed | ||
3217 | client_send_result (c->client, opcls->op_id, result, err_msg, err_msg_size); | ||
3218 | } | ||
3219 | |||
3220 | |||
3221 | static int | ||
3222 | check_client_state_get (void *cls, | ||
3223 | const struct GNUNET_PSYC_StateRequestMessage *req) | ||
3224 | { | ||
3225 | return GNUNET_OK; | ||
3226 | } | ||
3227 | |||
3228 | |||
3229 | /** | ||
3230 | * Client requests channel history. | ||
3231 | */ | ||
3232 | static void | ||
3233 | handle_client_state_get (void *cls, | ||
3234 | const struct GNUNET_PSYC_StateRequestMessage *req) | ||
3235 | { | ||
3236 | struct Client *c = cls; | ||
3237 | struct GNUNET_SERVICE_Client *client = c->client; | ||
3238 | struct Place *plc = c->place; | ||
3239 | if (NULL == plc) | ||
3240 | { | ||
3241 | GNUNET_break (0); | ||
3242 | GNUNET_SERVICE_client_drop (client); | ||
3243 | return; | ||
3244 | } | ||
3245 | |||
3246 | uint16_t size = ntohs (req->header.size); | ||
3247 | const char *name = (const char *) &req[1]; | ||
3248 | |||
3249 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3250 | "%p State get #%" PRIu64 ": %s\n", | ||
3251 | plc, GNUNET_ntohll (req->op_id), name); | ||
3252 | |||
3253 | if (size < sizeof (*req) + 1 | ||
3254 | || '\0' != name[size - sizeof (*req) - 1]) | ||
3255 | { | ||
3256 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
3257 | "%p State get #%" PRIu64 ": " | ||
3258 | "invalid name. size: %u < %zu?\n", | ||
3259 | plc, GNUNET_ntohll (req->op_id), size, sizeof (*req) + 1); | ||
3260 | GNUNET_break (0); | ||
3261 | GNUNET_SERVICE_client_drop (client); | ||
3262 | return; | ||
3263 | } | ||
3264 | |||
3265 | struct OperationClosure *opcls = GNUNET_malloc (sizeof (*opcls)); | ||
3266 | opcls->client = c; | ||
3267 | opcls->op_id = req->op_id; | ||
3268 | |||
3269 | switch (ntohs (req->header.type)) | ||
3270 | { | ||
3271 | case GNUNET_MESSAGE_TYPE_PSYC_STATE_GET: | ||
3272 | GNUNET_PSYC_channel_state_get (plc->channel, name, | ||
3273 | psyc_recv_state_var, | ||
3274 | psyc_recv_state_result, opcls); | ||
3275 | break; | ||
3276 | |||
3277 | case GNUNET_MESSAGE_TYPE_PSYC_STATE_GET_PREFIX: | ||
3278 | GNUNET_PSYC_channel_state_get_prefix (plc->channel, name, | ||
3279 | psyc_recv_state_var, | ||
3280 | psyc_recv_state_result, opcls); | ||
3281 | break; | ||
3282 | |||
3283 | default: | ||
3284 | GNUNET_assert (0); | ||
3285 | } | ||
3286 | |||
3287 | GNUNET_SERVICE_client_continue (client); | ||
3288 | } | ||
3289 | |||
3290 | |||
3291 | #define check_client_state_get_prefix check_client_state_get | ||
3292 | #define handle_client_state_get_prefix handle_client_state_get | ||
3293 | |||
3294 | |||
3295 | static void | ||
3296 | namestore_recv_records_store_result (void *cls, int32_t result, | ||
3297 | const char *err_msg) | ||
3298 | { | ||
3299 | struct OperationClosure *opcls = cls; | ||
3300 | struct Client *c = opcls->client; | ||
3301 | |||
3302 | // FIXME: client might have been disconnected | ||
3303 | client_send_result (c->client, opcls->op_id, result, err_msg, | ||
3304 | (NULL != err_msg) ? strlen (err_msg) : 0); | ||
3305 | GNUNET_free (opcls); | ||
3306 | } | ||
3307 | |||
3308 | |||
3309 | static int | ||
3310 | check_client_zone_add_place (void *cls, | ||
3311 | const struct ZoneAddPlaceRequest *preq) | ||
3312 | { | ||
3313 | return GNUNET_OK; | ||
3314 | } | ||
3315 | |||
3316 | |||
3317 | /** | ||
3318 | * Handle request to add PLACE record to GNS zone. | ||
3319 | */ | ||
3320 | static void | ||
3321 | handle_client_zone_add_place (void *cls, | ||
3322 | const struct ZoneAddPlaceRequest *preq) | ||
3323 | { | ||
3324 | struct Client *c = cls; | ||
3325 | struct GNUNET_SERVICE_Client *client = c->client; | ||
3326 | |||
3327 | uint16_t remaining = ntohs (preq->header.size) - sizeof (*preq); | ||
3328 | const char *p = (const char *) &preq[1]; | ||
3329 | const char *name = NULL, *password = NULL; | ||
3330 | uint16_t offset = GNUNET_STRINGS_buffer_tokenize (p, remaining, 2, | ||
3331 | &name, &password); | ||
3332 | remaining -= offset; | ||
3333 | p += offset; | ||
3334 | const struct GNUNET_PeerIdentity * | ||
3335 | relays = (const struct GNUNET_PeerIdentity *) p; | ||
3336 | uint16_t relay_size = ntohl (preq->relay_count) * sizeof (*relays); | ||
3337 | |||
3338 | if (0 == offset || remaining != relay_size) | ||
3339 | { | ||
3340 | GNUNET_break (0); | ||
3341 | client_send_result (client, preq->op_id, GNUNET_SYSERR, NULL, 0); | ||
3342 | GNUNET_SERVICE_client_drop (client); | ||
3343 | return; | ||
3344 | } | ||
3345 | |||
3346 | struct GNUNET_GNSRECORD_Data rd = { }; | ||
3347 | rd.record_type = GNUNET_GNSRECORD_TYPE_PLACE; | ||
3348 | rd.flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION; | ||
3349 | rd.expiration_time = GNUNET_ntohll (preq->expiration_time); | ||
3350 | |||
3351 | struct GNUNET_GNSRECORD_PlaceData * | ||
3352 | rec = GNUNET_malloc (sizeof (*rec) + relay_size); | ||
3353 | rec->place_pub_key = preq->place_pub_key; | ||
3354 | rec->origin = this_peer; | ||
3355 | rec->relay_count = preq->relay_count; | ||
3356 | GNUNET_memcpy (&rec[1], relays, relay_size); | ||
3357 | |||
3358 | rd.data = rec; | ||
3359 | rd.data_size = sizeof (*rec) + relay_size; | ||
3360 | |||
3361 | struct GNUNET_HashCode ego_pub_hash; | ||
3362 | GNUNET_CRYPTO_hash (&preq->ego_pub_key, sizeof (preq->ego_pub_key), &ego_pub_hash); | ||
3363 | struct Ego *ego = GNUNET_CONTAINER_multihashmap_get (egos, &ego_pub_hash); | ||
3364 | if (NULL == ego) | ||
3365 | { | ||
3366 | client_send_result (client, preq->op_id, GNUNET_SYSERR, NULL, 0); | ||
3367 | } | ||
3368 | else | ||
3369 | { | ||
3370 | struct OperationClosure *opcls = GNUNET_malloc (sizeof (*opcls)); | ||
3371 | opcls->client = c; | ||
3372 | opcls->op_id = preq->op_id; | ||
3373 | GNUNET_NAMESTORE_records_store (namestore, &ego->key, | ||
3374 | name, 1, &rd, | ||
3375 | namestore_recv_records_store_result, opcls); | ||
3376 | /** @todo refresh stored records later */ | ||
3377 | } | ||
3378 | GNUNET_SERVICE_client_continue (client); | ||
3379 | } | ||
3380 | |||
3381 | |||
3382 | static int | ||
3383 | check_client_zone_add_nym (void *cls, | ||
3384 | const struct ZoneAddNymRequest *nreq) | ||
3385 | { | ||
3386 | return GNUNET_OK; | ||
3387 | } | ||
3388 | |||
3389 | |||
3390 | /** | ||
3391 | * Handle request to add PLACE record to GNS zone. | ||
3392 | */ | ||
3393 | static void | ||
3394 | handle_client_zone_add_nym (void *cls, | ||
3395 | const struct ZoneAddNymRequest *nreq) | ||
3396 | { | ||
3397 | struct Client *c = cls; | ||
3398 | struct GNUNET_SERVICE_Client *client = c->client; | ||
3399 | |||
3400 | uint16_t name_size = ntohs (nreq->header.size) - sizeof (*nreq); | ||
3401 | const char *name = NULL; | ||
3402 | uint16_t offset = GNUNET_STRINGS_buffer_tokenize ((const char *) &nreq[1], | ||
3403 | name_size, 1, &name); | ||
3404 | if (0 == offset || offset != name_size) | ||
3405 | { | ||
3406 | GNUNET_break (0); | ||
3407 | client_send_result (client, nreq->op_id, GNUNET_SYSERR, NULL, 0); | ||
3408 | GNUNET_SERVICE_client_continue (client); | ||
3409 | return; | ||
3410 | } | ||
3411 | |||
3412 | struct GNUNET_GNSRECORD_Data rd = { }; | ||
3413 | rd.record_type = GNUNET_GNSRECORD_TYPE_PKEY; | ||
3414 | rd.flags = GNUNET_GNSRECORD_RF_RELATIVE_EXPIRATION; | ||
3415 | rd.expiration_time = GNUNET_ntohll (nreq->expiration_time); | ||
3416 | rd.data = &nreq->nym_pub_key; | ||
3417 | rd.data_size = sizeof (nreq->nym_pub_key); | ||
3418 | |||
3419 | struct GNUNET_HashCode ego_pub_hash; | ||
3420 | GNUNET_CRYPTO_hash (&nreq->ego_pub_key, sizeof (nreq->ego_pub_key), &ego_pub_hash); | ||
3421 | struct Ego *ego = GNUNET_CONTAINER_multihashmap_get (egos, &ego_pub_hash); | ||
3422 | if (NULL == ego) | ||
3423 | { | ||
3424 | client_send_result (client, nreq->op_id, GNUNET_SYSERR, NULL, 0); | ||
3425 | } | ||
3426 | else | ||
3427 | { | ||
3428 | struct OperationClosure *opcls = GNUNET_malloc (sizeof (*opcls)); | ||
3429 | opcls->client = c; | ||
3430 | opcls->op_id = nreq->op_id; | ||
3431 | GNUNET_NAMESTORE_records_store (namestore, &ego->key, | ||
3432 | name, 1, &rd, | ||
3433 | namestore_recv_records_store_result, opcls); | ||
3434 | /** @todo refresh stored records later */ | ||
3435 | } | ||
3436 | GNUNET_SERVICE_client_continue (client); | ||
3437 | } | ||
3438 | |||
3439 | |||
3440 | const char * | ||
3441 | path_basename (const char *path) | ||
3442 | { | ||
3443 | const char *basename = strrchr (path, DIR_SEPARATOR); | ||
3444 | if (NULL != basename) | ||
3445 | basename++; | ||
3446 | |||
3447 | if (NULL == basename || '\0' == *basename) | ||
3448 | return NULL; | ||
3449 | |||
3450 | return basename; | ||
3451 | } | ||
3452 | |||
3453 | |||
3454 | struct PlaceLoadClosure | ||
3455 | { | ||
3456 | const char *app_id; | ||
3457 | const char *ego_pub_str; | ||
3458 | }; | ||
3459 | |||
3460 | |||
3461 | /** Load a place file */ | ||
3462 | int | ||
3463 | file_place_load (void *cls, const char *place_filename) | ||
3464 | { | ||
3465 | struct PlaceLoadClosure *plcls = cls; | ||
3466 | |||
3467 | const char *place_pub_str = path_basename (place_filename); | ||
3468 | if (NULL == place_pub_str) | ||
3469 | { | ||
3470 | GNUNET_break (0); | ||
3471 | return GNUNET_OK; | ||
3472 | } | ||
3473 | |||
3474 | char *filename = NULL; | ||
3475 | GNUNET_asprintf (&filename, "%s%c" "%s%c" "%s%c" "%s", | ||
3476 | dir_social, DIR_SEPARATOR, | ||
3477 | "places", DIR_SEPARATOR, | ||
3478 | plcls->ego_pub_str, DIR_SEPARATOR, | ||
3479 | place_pub_str); | ||
3480 | |||
3481 | uint64_t file_size = 0; | ||
3482 | if (GNUNET_OK != | ||
3483 | GNUNET_DISK_file_size (filename, &file_size, GNUNET_YES, GNUNET_YES) | ||
3484 | || file_size < sizeof (struct PlaceEnterRequest)) | ||
3485 | { | ||
3486 | GNUNET_free (filename); | ||
3487 | return GNUNET_OK; | ||
3488 | } | ||
3489 | |||
3490 | struct PlaceEnterRequest *ereq = GNUNET_malloc (file_size); | ||
3491 | ssize_t read_size = GNUNET_DISK_fn_read (filename, ereq, file_size); | ||
3492 | GNUNET_free (filename); | ||
3493 | if (read_size < 0 || read_size < sizeof (*ereq)) | ||
3494 | { | ||
3495 | GNUNET_free (ereq); | ||
3496 | return GNUNET_OK; | ||
3497 | } | ||
3498 | |||
3499 | uint16_t ereq_size = ntohs (ereq->header.size); | ||
3500 | if (read_size != ereq_size) | ||
3501 | { | ||
3502 | GNUNET_free (ereq); | ||
3503 | return GNUNET_OK; | ||
3504 | } | ||
3505 | |||
3506 | switch (ntohs (ereq->header.type)) | ||
3507 | { | ||
3508 | case GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER: | ||
3509 | if (ereq_size < sizeof (struct HostEnterRequest)) | ||
3510 | { | ||
3511 | GNUNET_free (ereq); | ||
3512 | return GNUNET_OK; | ||
3513 | } | ||
3514 | struct HostEnterRequest *hreq = (struct HostEnterRequest *) ereq; | ||
3515 | host_enter (hreq, NULL); | ||
3516 | break; | ||
3517 | |||
3518 | case GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER: | ||
3519 | if (ereq_size < sizeof (struct GuestEnterRequest)) | ||
3520 | { | ||
3521 | GNUNET_free (ereq); | ||
3522 | return GNUNET_OK; | ||
3523 | } | ||
3524 | struct GuestEnterRequest *greq = (struct GuestEnterRequest *) ereq; | ||
3525 | guest_enter (greq, NULL); | ||
3526 | break; | ||
3527 | |||
3528 | default: | ||
3529 | GNUNET_free (ereq); | ||
3530 | return GNUNET_OK; | ||
3531 | } | ||
3532 | |||
3533 | if (GNUNET_SYSERR == app_place_add (plcls->app_id, ereq)) | ||
3534 | { | ||
3535 | GNUNET_assert (0); | ||
3536 | } | ||
3537 | GNUNET_free (ereq); | ||
3538 | return GNUNET_OK; | ||
3539 | } | ||
3540 | |||
3541 | |||
3542 | /** | ||
3543 | * Read @e place_pub_str entries in @a dir_ego | ||
3544 | * | ||
3545 | * @param dir_ego | ||
3546 | * Data directory of an application ego. | ||
3547 | * $GNUNET_DATA_HOME/social/apps/$app_id/$ego_pub_str/ | ||
3548 | */ | ||
3549 | int | ||
3550 | scan_app_ego_dir (void *cls, const char *dir_ego) | ||
3551 | { | ||
3552 | struct PlaceLoadClosure *plcls = cls; | ||
3553 | plcls->ego_pub_str = path_basename (dir_ego); | ||
3554 | |||
3555 | if (NULL != plcls->ego_pub_str) | ||
3556 | GNUNET_DISK_directory_scan (dir_ego, file_place_load, plcls); | ||
3557 | |||
3558 | return GNUNET_OK; | ||
3559 | } | ||
3560 | |||
3561 | /** | ||
3562 | * Read @e ego_pub_str entries in @a dir_app | ||
3563 | * | ||
3564 | * @param dir_app | ||
3565 | * Data directory of an application. | ||
3566 | * $GNUNET_DATA_HOME/social/apps/$app_id/ | ||
3567 | */ | ||
3568 | int | ||
3569 | scan_app_dir (void *cls, const char *dir_app) | ||
3570 | { | ||
3571 | if (GNUNET_YES != GNUNET_DISK_directory_test (dir_app, GNUNET_YES)) | ||
3572 | return GNUNET_OK; | ||
3573 | |||
3574 | struct PlaceLoadClosure plcls; | ||
3575 | plcls.app_id = path_basename (dir_app); | ||
3576 | |||
3577 | if (NULL != plcls.app_id) | ||
3578 | GNUNET_DISK_directory_scan (dir_app, scan_app_ego_dir, &plcls); | ||
3579 | |||
3580 | return GNUNET_OK; | ||
3581 | } | ||
3582 | |||
3583 | |||
3584 | static void | ||
3585 | identity_recv_ego (void *cls, struct GNUNET_IDENTITY_Ego *id_ego, | ||
3586 | void **ctx, const char *name) | ||
3587 | { | ||
3588 | if (NULL == id_ego) // end of initial list of egos | ||
3589 | return; | ||
3590 | |||
3591 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3592 | "social service received ego %s\n", | ||
3593 | name); | ||
3594 | |||
3595 | struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key; | ||
3596 | GNUNET_IDENTITY_ego_get_public_key (id_ego, &ego_pub_key); | ||
3597 | |||
3598 | struct GNUNET_HashCode ego_pub_hash; | ||
3599 | GNUNET_CRYPTO_hash (&ego_pub_key, sizeof (ego_pub_key), &ego_pub_hash); | ||
3600 | |||
3601 | struct Ego *ego = GNUNET_CONTAINER_multihashmap_get (egos, &ego_pub_hash); | ||
3602 | if (NULL == ego && NULL == name) | ||
3603 | { | ||
3604 | // an ego that is none of our business has been deleted | ||
3605 | return; | ||
3606 | } | ||
3607 | if (NULL != ego) | ||
3608 | { | ||
3609 | // one of our egos has been changed | ||
3610 | GNUNET_free (ego->name); | ||
3611 | if (NULL == name) | ||
3612 | { | ||
3613 | // one of our egos has been deleted | ||
3614 | GNUNET_CONTAINER_multihashmap_remove (egos, &ego_pub_hash, ego); | ||
3615 | GNUNET_free (ego); | ||
3616 | return; | ||
3617 | } | ||
3618 | } | ||
3619 | else | ||
3620 | { | ||
3621 | ego = GNUNET_malloc (sizeof (*ego)); | ||
3622 | } | ||
3623 | ego->key = *(GNUNET_IDENTITY_ego_get_private_key (id_ego)); | ||
3624 | size_t name_size = strlen (name) + 1; | ||
3625 | ego->name = GNUNET_malloc (name_size); | ||
3626 | GNUNET_memcpy (ego->name, name, name_size); | ||
3627 | |||
3628 | GNUNET_CONTAINER_multihashmap_put (egos, &ego_pub_hash, ego, | ||
3629 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); | ||
3630 | |||
3631 | // FIXME: notify clients about changed ego | ||
3632 | } | ||
3633 | |||
3634 | |||
3635 | /** | ||
3636 | * Initialize the PSYC service. | ||
3637 | * | ||
3638 | * @param cls Closure. | ||
3639 | * @param server The initialized server. | ||
3640 | * @param c Configuration to use. | ||
3641 | */ | ||
3642 | static void | ||
3643 | run (void *cls, | ||
3644 | const struct GNUNET_CONFIGURATION_Handle *c, | ||
3645 | struct GNUNET_SERVICE_Handle *svc) | ||
3646 | { | ||
3647 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3648 | "starting social service\n"); | ||
3649 | |||
3650 | cfg = c; | ||
3651 | service = svc; | ||
3652 | GNUNET_CRYPTO_get_peer_identity (cfg, &this_peer); | ||
3653 | |||
3654 | hosts = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES); | ||
3655 | guests = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES); | ||
3656 | place_guests = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); | ||
3657 | |||
3658 | egos = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); | ||
3659 | apps = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); | ||
3660 | places = GNUNET_CONTAINER_multihashmap_create(1, GNUNET_NO); | ||
3661 | apps_places = GNUNET_CONTAINER_multihashmap_create(1, GNUNET_NO); | ||
3662 | //places_apps = GNUNET_CONTAINER_multihashmap_create(1, GNUNET_NO); | ||
3663 | |||
3664 | id = GNUNET_IDENTITY_connect (cfg, &identity_recv_ego, NULL); | ||
3665 | gns = GNUNET_GNS_connect (cfg); | ||
3666 | namestore = GNUNET_NAMESTORE_connect (cfg); | ||
3667 | stats = GNUNET_STATISTICS_create ("social", cfg); | ||
3668 | |||
3669 | if (GNUNET_OK != | ||
3670 | GNUNET_CONFIGURATION_get_value_filename (cfg, "social", "DATA_HOME", | ||
3671 | &dir_social)) | ||
3672 | { | ||
3673 | GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, | ||
3674 | "social", "DATA_HOME"); | ||
3675 | GNUNET_break (0); | ||
3676 | return; | ||
3677 | } | ||
3678 | GNUNET_asprintf (&dir_places, "%s%c%s", | ||
3679 | dir_social, DIR_SEPARATOR, "places"); | ||
3680 | GNUNET_asprintf (&dir_apps, "%s%c%s", | ||
3681 | dir_social, DIR_SEPARATOR, "apps"); | ||
3682 | |||
3683 | GNUNET_DISK_directory_scan (dir_apps, scan_app_dir, NULL); | ||
3684 | |||
3685 | GNUNET_SCHEDULER_add_shutdown (shutdown_task, NULL); | ||
3686 | } | ||
3687 | |||
3688 | |||
3689 | /** | ||
3690 | * Define "main" method using service macro. | ||
3691 | */ | ||
3692 | GNUNET_SERVICE_MAIN | ||
3693 | ("social", | ||
3694 | GNUNET_SERVICE_OPTION_NONE, | ||
3695 | run, | ||
3696 | client_notify_connect, | ||
3697 | client_notify_disconnect, | ||
3698 | NULL, | ||
3699 | GNUNET_MQ_hd_var_size (client_host_enter, | ||
3700 | GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER, | ||
3701 | struct HostEnterRequest, | ||
3702 | NULL), | ||
3703 | GNUNET_MQ_hd_var_size (client_guest_enter, | ||
3704 | GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER, | ||
3705 | struct GuestEnterRequest, | ||
3706 | NULL), | ||
3707 | GNUNET_MQ_hd_var_size (client_guest_enter_by_name, | ||
3708 | GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_BY_NAME, | ||
3709 | struct GuestEnterByNameRequest, | ||
3710 | NULL), | ||
3711 | GNUNET_MQ_hd_var_size (client_join_decision, | ||
3712 | GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION, | ||
3713 | struct GNUNET_PSYC_JoinDecisionMessage, | ||
3714 | NULL), | ||
3715 | GNUNET_MQ_hd_var_size (client_psyc_message, | ||
3716 | GNUNET_MESSAGE_TYPE_PSYC_MESSAGE, | ||
3717 | struct GNUNET_MessageHeader, | ||
3718 | NULL), | ||
3719 | GNUNET_MQ_hd_var_size (client_history_replay, | ||
3720 | GNUNET_MESSAGE_TYPE_PSYC_HISTORY_REPLAY, | ||
3721 | struct GNUNET_PSYC_HistoryRequestMessage, | ||
3722 | NULL), | ||
3723 | GNUNET_MQ_hd_var_size (client_state_get, | ||
3724 | GNUNET_MESSAGE_TYPE_PSYC_STATE_GET, | ||
3725 | struct GNUNET_PSYC_StateRequestMessage, | ||
3726 | NULL), | ||
3727 | GNUNET_MQ_hd_var_size (client_state_get_prefix, | ||
3728 | GNUNET_MESSAGE_TYPE_PSYC_STATE_GET_PREFIX, | ||
3729 | struct GNUNET_PSYC_StateRequestMessage, | ||
3730 | NULL), | ||
3731 | GNUNET_MQ_hd_var_size (client_zone_add_place, | ||
3732 | GNUNET_MESSAGE_TYPE_SOCIAL_ZONE_ADD_PLACE, | ||
3733 | struct ZoneAddPlaceRequest, | ||
3734 | NULL), | ||
3735 | GNUNET_MQ_hd_var_size (client_zone_add_nym, | ||
3736 | GNUNET_MESSAGE_TYPE_SOCIAL_ZONE_ADD_NYM, | ||
3737 | struct ZoneAddNymRequest, | ||
3738 | NULL), | ||
3739 | GNUNET_MQ_hd_var_size (client_app_connect, | ||
3740 | GNUNET_MESSAGE_TYPE_SOCIAL_APP_CONNECT, | ||
3741 | struct AppConnectRequest, | ||
3742 | NULL), | ||
3743 | GNUNET_MQ_hd_fixed_size (client_app_detach, | ||
3744 | GNUNET_MESSAGE_TYPE_SOCIAL_APP_DETACH, | ||
3745 | struct AppDetachRequest, | ||
3746 | NULL), | ||
3747 | GNUNET_MQ_hd_fixed_size (client_place_leave, | ||
3748 | GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LEAVE, | ||
3749 | struct GNUNET_MessageHeader, | ||
3750 | NULL), | ||
3751 | GNUNET_MQ_hd_var_size (client_msg_proc_set, | ||
3752 | GNUNET_MESSAGE_TYPE_SOCIAL_MSG_PROC_SET, | ||
3753 | struct MsgProcRequest, | ||
3754 | NULL), | ||
3755 | GNUNET_MQ_hd_fixed_size (client_msg_proc_clear, | ||
3756 | GNUNET_MESSAGE_TYPE_SOCIAL_MSG_PROC_CLEAR, | ||
3757 | struct GNUNET_MessageHeader, | ||
3758 | NULL)); | ||
3759 | |||
3760 | /* end of gnunet-service-social.c */ | ||
diff --git a/src/social/gnunet-social.c b/src/social/gnunet-social.c deleted file mode 100644 index 14701bfda..000000000 --- a/src/social/gnunet-social.c +++ /dev/null | |||
@@ -1,1411 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2016 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * CLI tool to interact with the social service. | ||
23 | * | ||
24 | * @author Gabor X Toth | ||
25 | */ | ||
26 | |||
27 | #include <inttypes.h> | ||
28 | |||
29 | #include "platform.h" | ||
30 | #include "gnunet_util_lib.h" | ||
31 | #include "gnunet_social_service.h" | ||
32 | |||
33 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) | ||
34 | |||
35 | #define DATA2ARG(data) data, sizeof (data) | ||
36 | |||
37 | /* operations corresponding to API calls */ | ||
38 | |||
39 | /** --status */ | ||
40 | static int op_status; | ||
41 | |||
42 | /** --host-enter */ | ||
43 | static int op_host_enter; | ||
44 | |||
45 | /** --host-reconnect */ | ||
46 | static int op_host_reconnect; | ||
47 | |||
48 | /** --host-leave */ | ||
49 | static int op_host_leave; | ||
50 | |||
51 | /** --host-announce */ | ||
52 | static int op_host_announce; | ||
53 | |||
54 | /** --host-assign */ | ||
55 | static int op_host_assign; | ||
56 | |||
57 | /** --guest-enter */ | ||
58 | static int op_guest_enter; | ||
59 | |||
60 | /** --guest-reconnect */ | ||
61 | static int op_guest_reconnect; | ||
62 | |||
63 | /** --guest-leave */ | ||
64 | static int op_guest_leave; | ||
65 | |||
66 | /** --guest-talk */ | ||
67 | static int op_guest_talk; | ||
68 | |||
69 | /** --replay */ | ||
70 | static int op_replay; | ||
71 | |||
72 | /** --replay-latest */ | ||
73 | static int op_replay_latest; | ||
74 | |||
75 | /** --look-at */ | ||
76 | static int op_look_at; | ||
77 | |||
78 | /** --look-for */ | ||
79 | static int op_look_for; | ||
80 | |||
81 | |||
82 | /* options */ | ||
83 | |||
84 | /** --app */ | ||
85 | static char *opt_app = "cli"; | ||
86 | |||
87 | /** --place */ | ||
88 | static char *opt_place; | ||
89 | |||
90 | /** --ego */ | ||
91 | static char *opt_ego; | ||
92 | |||
93 | /** --gns */ | ||
94 | static char *opt_gns; | ||
95 | |||
96 | /** --peer */ | ||
97 | static char *opt_peer; | ||
98 | |||
99 | /** --follow */ | ||
100 | static int opt_follow; | ||
101 | |||
102 | /** --welcome */ | ||
103 | static int opt_welcome; | ||
104 | |||
105 | /** --deny */ | ||
106 | static int opt_deny; | ||
107 | |||
108 | /** --method */ | ||
109 | static char *opt_method; | ||
110 | |||
111 | /** --data */ | ||
112 | // FIXME: should come from STDIN | ||
113 | static char *opt_data; | ||
114 | |||
115 | /** --name */ | ||
116 | static char *opt_name; | ||
117 | |||
118 | /** --start */ | ||
119 | static unsigned long long opt_start; | ||
120 | |||
121 | /** --until */ | ||
122 | static unsigned long long opt_until; | ||
123 | |||
124 | /** --limit */ | ||
125 | static unsigned long long opt_limit; | ||
126 | |||
127 | |||
128 | /* global vars */ | ||
129 | |||
130 | /** exit code */ | ||
131 | static int ret = 1; | ||
132 | |||
133 | /** are we waiting for service to close our connection */ | ||
134 | static char is_disconnecting = 0; | ||
135 | |||
136 | /** Task handle for timeout termination. */ | ||
137 | struct GNUNET_SCHEDULER_Task *timeout_task; | ||
138 | |||
139 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
140 | |||
141 | struct GNUNET_PeerIdentity peer, this_peer; | ||
142 | |||
143 | struct GNUNET_SOCIAL_App *app; | ||
144 | |||
145 | /** public key of connected place */ | ||
146 | struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key; | ||
147 | |||
148 | struct GNUNET_PSYC_Slicer *slicer; | ||
149 | |||
150 | struct GNUNET_SOCIAL_Ego *ego; | ||
151 | struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key; | ||
152 | |||
153 | struct GNUNET_SOCIAL_Host *hst; | ||
154 | struct GNUNET_SOCIAL_Guest *gst; | ||
155 | struct GNUNET_SOCIAL_Place *plc; | ||
156 | |||
157 | const char *method_received; | ||
158 | |||
159 | |||
160 | /* DISCONNECT */ | ||
161 | |||
162 | |||
163 | /** | ||
164 | * Callback called after the host or guest place disconnected. | ||
165 | */ | ||
166 | static void | ||
167 | disconnected (void *cls) | ||
168 | { | ||
169 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "disconnected()\n"); | ||
170 | GNUNET_SCHEDULER_shutdown (); | ||
171 | } | ||
172 | |||
173 | |||
174 | /** | ||
175 | * Callback called after the application disconnected. | ||
176 | */ | ||
177 | static void | ||
178 | app_disconnected (void *cls) | ||
179 | { | ||
180 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "app_disconnected()\n"); | ||
181 | if (hst || gst) | ||
182 | { | ||
183 | if (hst) | ||
184 | { | ||
185 | GNUNET_SOCIAL_host_disconnect (hst, disconnected, NULL); | ||
186 | } | ||
187 | if (gst) | ||
188 | { | ||
189 | GNUNET_SOCIAL_guest_disconnect (gst, disconnected, NULL); | ||
190 | } | ||
191 | } | ||
192 | else | ||
193 | { | ||
194 | GNUNET_SCHEDULER_shutdown (); | ||
195 | } | ||
196 | } | ||
197 | |||
198 | |||
199 | /** | ||
200 | * Disconnect from connected GNUnet services. | ||
201 | */ | ||
202 | static void | ||
203 | disconnect () | ||
204 | { | ||
205 | // handle that we get called several times from several places, but should we? | ||
206 | if (!is_disconnecting++) { | ||
207 | GNUNET_SOCIAL_app_disconnect (app, app_disconnected, NULL); | ||
208 | } | ||
209 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "disconnect() called for the #%d time\n", is_disconnecting); | ||
210 | } | ||
211 | |||
212 | |||
213 | static void | ||
214 | scheduler_shutdown (void *cls) | ||
215 | { | ||
216 | disconnect (); | ||
217 | } | ||
218 | |||
219 | |||
220 | /** | ||
221 | * Callback called when the program failed to finish the requested operation in time. | ||
222 | */ | ||
223 | static void | ||
224 | timeout (void *cls) | ||
225 | { | ||
226 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "timeout()\n"); | ||
227 | disconnect (); | ||
228 | } | ||
229 | |||
230 | static void | ||
231 | schedule_success (void *cls) | ||
232 | { | ||
233 | ret = 0; | ||
234 | disconnect (); | ||
235 | } | ||
236 | |||
237 | |||
238 | static void | ||
239 | schedule_fail (void *cls) | ||
240 | { | ||
241 | disconnect (); | ||
242 | } | ||
243 | |||
244 | |||
245 | /** | ||
246 | * Schedule exit with success result. | ||
247 | */ | ||
248 | static void | ||
249 | exit_success () | ||
250 | { | ||
251 | if (timeout_task != NULL) | ||
252 | { | ||
253 | GNUNET_SCHEDULER_cancel (timeout_task); | ||
254 | timeout_task = NULL; | ||
255 | } | ||
256 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, schedule_success, NULL); | ||
257 | } | ||
258 | |||
259 | |||
260 | /** | ||
261 | * Schedule exit with failure result. | ||
262 | */ | ||
263 | static void | ||
264 | exit_fail () | ||
265 | { | ||
266 | if (timeout_task != NULL) | ||
267 | { | ||
268 | GNUNET_SCHEDULER_cancel (timeout_task); | ||
269 | timeout_task = NULL; | ||
270 | } | ||
271 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, schedule_fail, NULL); | ||
272 | } | ||
273 | |||
274 | |||
275 | /* LEAVE */ | ||
276 | |||
277 | |||
278 | /** | ||
279 | * Callback notifying about the host has left and stopped hosting the place. | ||
280 | * | ||
281 | * This also indicates the end of the connection to the service. | ||
282 | */ | ||
283 | static void | ||
284 | host_left (void *cls) | ||
285 | { | ||
286 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
287 | "The host has left the place.\n"); | ||
288 | exit_success (); | ||
289 | } | ||
290 | |||
291 | |||
292 | /** | ||
293 | * Leave a place permanently and stop hosting a place. | ||
294 | */ | ||
295 | static void | ||
296 | host_leave () | ||
297 | { | ||
298 | GNUNET_SOCIAL_host_leave (hst, NULL, host_left, NULL); | ||
299 | hst = NULL; | ||
300 | plc = NULL; | ||
301 | } | ||
302 | |||
303 | |||
304 | /** | ||
305 | * Callback notifying about the guest has left the place. | ||
306 | * | ||
307 | * This also indicates the end of the connection to the service. | ||
308 | */ | ||
309 | static void | ||
310 | guest_left (void *cls) | ||
311 | { | ||
312 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
313 | "Guest has left the place.\n"); | ||
314 | } | ||
315 | |||
316 | |||
317 | /** | ||
318 | * Leave a place permanently as guest. | ||
319 | */ | ||
320 | static void | ||
321 | guest_leave () | ||
322 | { | ||
323 | struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create (); | ||
324 | // FIXME: wrong use of vars | ||
325 | GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_SET, | ||
326 | "_message", DATA2ARG ("Leaving.")); | ||
327 | GNUNET_SOCIAL_guest_leave (gst, env, guest_left, NULL); | ||
328 | GNUNET_PSYC_env_destroy (env); | ||
329 | gst = NULL; | ||
330 | plc = NULL; | ||
331 | } | ||
332 | |||
333 | |||
334 | /* ANNOUNCE / ASSIGN / TALK */ | ||
335 | |||
336 | |||
337 | struct TransmitClosure | ||
338 | { | ||
339 | const char *data; | ||
340 | size_t size; | ||
341 | } tmit; | ||
342 | |||
343 | |||
344 | /** | ||
345 | * Callback notifying about available buffer space to write message data | ||
346 | * when transmitting messages using host_announce() or guest_talk() | ||
347 | */ | ||
348 | static int | ||
349 | notify_data (void *cls, uint16_t *data_size, void *data) | ||
350 | { | ||
351 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
352 | "Transmit notify data: %u bytes available\n", | ||
353 | *data_size); | ||
354 | |||
355 | struct TransmitClosure *tmit = cls; | ||
356 | uint16_t size = tmit->size < *data_size ? tmit->size : *data_size; | ||
357 | *data_size = size; | ||
358 | GNUNET_memcpy (data, tmit->data, size); | ||
359 | |||
360 | tmit->size -= size; | ||
361 | tmit->data += size; | ||
362 | |||
363 | if (0 == tmit->size) | ||
364 | { | ||
365 | if ((op_host_announce || op_host_assign || op_guest_talk) && !opt_follow) | ||
366 | { | ||
367 | exit_success (); | ||
368 | } | ||
369 | return GNUNET_YES; | ||
370 | } | ||
371 | else | ||
372 | { | ||
373 | return GNUNET_NO; | ||
374 | } | ||
375 | } | ||
376 | |||
377 | |||
378 | /** | ||
379 | * Host announcement - send a message to the place. | ||
380 | */ | ||
381 | static void | ||
382 | host_announce (const char *method, const char *data, size_t data_size) | ||
383 | { | ||
384 | struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create (); | ||
385 | GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_SET, | ||
386 | "_foo", DATA2ARG ("bar baz")); | ||
387 | |||
388 | tmit = (struct TransmitClosure) {}; | ||
389 | tmit.data = data; | ||
390 | tmit.size = data_size; | ||
391 | |||
392 | GNUNET_SOCIAL_host_announce (hst, method, env, | ||
393 | notify_data, &tmit, | ||
394 | GNUNET_SOCIAL_ANNOUNCE_NONE); | ||
395 | GNUNET_PSYC_env_destroy (env); | ||
396 | } | ||
397 | |||
398 | |||
399 | /** | ||
400 | * Assign a state var of @a name to the value of @a data. | ||
401 | */ | ||
402 | static void | ||
403 | host_assign (const char *name, const char *data, size_t data_size) | ||
404 | { | ||
405 | struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create (); | ||
406 | GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_ASSIGN, | ||
407 | name, data, data_size); | ||
408 | |||
409 | tmit = (struct TransmitClosure) {}; | ||
410 | GNUNET_SOCIAL_host_announce (hst, "_assign", env, | ||
411 | notify_data, &tmit, | ||
412 | GNUNET_SOCIAL_ANNOUNCE_NONE); | ||
413 | GNUNET_PSYC_env_destroy (env); | ||
414 | } | ||
415 | |||
416 | |||
417 | /** | ||
418 | * Guest talk request to host. | ||
419 | */ | ||
420 | static void | ||
421 | guest_talk (const char *method, | ||
422 | const char *data, size_t data_size) | ||
423 | { | ||
424 | struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create (); | ||
425 | GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_SET, | ||
426 | "_foo", DATA2ARG ("bar baz")); | ||
427 | |||
428 | tmit = (struct TransmitClosure) {}; | ||
429 | tmit.data = data; | ||
430 | tmit.size = data_size; | ||
431 | |||
432 | GNUNET_SOCIAL_guest_talk (gst, method, env, | ||
433 | notify_data, &tmit, | ||
434 | GNUNET_SOCIAL_TALK_NONE); | ||
435 | GNUNET_PSYC_env_destroy (env); | ||
436 | } | ||
437 | |||
438 | |||
439 | /* HISTORY REPLAY */ | ||
440 | |||
441 | |||
442 | /** | ||
443 | * Callback notifying about the end of history replay results. | ||
444 | */ | ||
445 | static void | ||
446 | recv_history_replay_result (void *cls, int64_t result, | ||
447 | const void *data, uint16_t data_size) | ||
448 | { | ||
449 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
450 | "Received history replay result: %" PRId64 "\n" | ||
451 | "%.*s\n", | ||
452 | result, data_size, (const char *) data); | ||
453 | |||
454 | if (op_replay || op_replay_latest) | ||
455 | { | ||
456 | exit_success (); | ||
457 | } | ||
458 | } | ||
459 | |||
460 | |||
461 | /** | ||
462 | * Replay history between a given @a start and @a end message IDs, | ||
463 | * optionally filtered by a method @a prefix. | ||
464 | */ | ||
465 | static void | ||
466 | history_replay (uint64_t start, uint64_t end, const char *prefix) | ||
467 | { | ||
468 | GNUNET_SOCIAL_place_history_replay (plc, start, end, prefix, | ||
469 | GNUNET_PSYC_HISTORY_REPLAY_LOCAL, | ||
470 | slicer, | ||
471 | recv_history_replay_result, | ||
472 | NULL); | ||
473 | } | ||
474 | |||
475 | |||
476 | /** | ||
477 | * Replay latest @a limit messages. | ||
478 | */ | ||
479 | static void | ||
480 | history_replay_latest (uint64_t limit, const char *prefix) | ||
481 | { | ||
482 | GNUNET_SOCIAL_place_history_replay_latest (plc, limit, prefix, | ||
483 | GNUNET_PSYC_HISTORY_REPLAY_LOCAL, | ||
484 | slicer, | ||
485 | recv_history_replay_result, | ||
486 | NULL); | ||
487 | } | ||
488 | |||
489 | |||
490 | /* LOOK AT/FOR */ | ||
491 | |||
492 | |||
493 | /** | ||
494 | * Callback notifying about the end of state var results. | ||
495 | */ | ||
496 | static void | ||
497 | look_result (void *cls, int64_t result_code, | ||
498 | const void *data, uint16_t data_size) | ||
499 | { | ||
500 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
501 | "Received look result: %" PRId64 "\n", result_code); | ||
502 | |||
503 | if (op_look_at || op_look_for) | ||
504 | { | ||
505 | exit_success (); | ||
506 | } | ||
507 | } | ||
508 | |||
509 | |||
510 | /** | ||
511 | * Callback notifying about a state var result. | ||
512 | */ | ||
513 | static void | ||
514 | look_var (void *cls, | ||
515 | const struct GNUNET_MessageHeader *mod, | ||
516 | const char *name, | ||
517 | const void *value, | ||
518 | uint32_t value_size, | ||
519 | uint32_t full_value_size) | ||
520 | { | ||
521 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
522 | "Received var: %s\n%.*s\n", | ||
523 | name, value_size, (const char *) value); | ||
524 | } | ||
525 | |||
526 | |||
527 | /** | ||
528 | * Look for a state var using exact match of the name. | ||
529 | */ | ||
530 | static void | ||
531 | look_at (const char *full_name) | ||
532 | { | ||
533 | GNUNET_SOCIAL_place_look_at (plc, full_name, look_var, look_result, NULL); | ||
534 | } | ||
535 | |||
536 | |||
537 | /** | ||
538 | * Look for state vars by name prefix. | ||
539 | */ | ||
540 | static void | ||
541 | look_for (const char *name_prefix) | ||
542 | { | ||
543 | GNUNET_SOCIAL_place_look_for (plc, name_prefix, look_var, look_result, NULL); | ||
544 | } | ||
545 | |||
546 | |||
547 | /* SLICER */ | ||
548 | |||
549 | |||
550 | /** | ||
551 | * Callback notifying about the start of a new incoming message. | ||
552 | */ | ||
553 | static void | ||
554 | slicer_recv_method (void *cls, | ||
555 | const struct GNUNET_PSYC_MessageHeader *msg, | ||
556 | const struct GNUNET_PSYC_MessageMethod *meth, | ||
557 | uint64_t message_id, | ||
558 | const char *method_name) | ||
559 | { | ||
560 | method_received = method_name; | ||
561 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
562 | "Received method for message ID %" PRIu64 ":\n" | ||
563 | "%s (flags: %x)\n", | ||
564 | message_id, method_name, ntohl (meth->flags)); | ||
565 | /* routing header is missing, so we just print double newline */ | ||
566 | printf("\n"); | ||
567 | /* we output . instead of | to indicate that this is not proper PSYC syntax */ | ||
568 | /* FIXME: use libpsyc here */ | ||
569 | } | ||
570 | |||
571 | |||
572 | /** | ||
573 | * Callback notifying about an incoming modifier. | ||
574 | */ | ||
575 | static void | ||
576 | slicer_recv_modifier (void *cls, | ||
577 | const struct GNUNET_PSYC_MessageHeader *msg, | ||
578 | const struct GNUNET_MessageHeader *pmsg, | ||
579 | uint64_t message_id, | ||
580 | enum GNUNET_PSYC_Operator oper, | ||
581 | const char *name, | ||
582 | const void *value, | ||
583 | uint16_t value_size, | ||
584 | uint16_t full_value_size) | ||
585 | { | ||
586 | #if 0 | ||
587 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
588 | "Received modifier for message ID %" PRIu64 ":\n" | ||
589 | "%c%s: %.*s (size: %u)\n", | ||
590 | message_id, oper, name, value_size, (const char *) value, value_size); | ||
591 | #else | ||
592 | /* obviously not binary safe */ | ||
593 | printf("%c%s\t%.*s\n", | ||
594 | oper, name, value_size, (const char *) value); | ||
595 | #endif | ||
596 | } | ||
597 | |||
598 | |||
599 | /** | ||
600 | * Callback notifying about an incoming data fragment. | ||
601 | */ | ||
602 | static void | ||
603 | slicer_recv_data (void *cls, | ||
604 | const struct GNUNET_PSYC_MessageHeader *msg, | ||
605 | const struct GNUNET_MessageHeader *pmsg, | ||
606 | uint64_t message_id, | ||
607 | const void *data, | ||
608 | uint16_t data_size) | ||
609 | { | ||
610 | #if 0 | ||
611 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
612 | "Received data for message ID %" PRIu64 ":\n" | ||
613 | "%.*s\n", | ||
614 | message_id, data_size, (const char *) data); | ||
615 | #else | ||
616 | /* obviously not binary safe */ | ||
617 | printf("%s\n%.*s\n", | ||
618 | method_received, data_size, (const char *) data); | ||
619 | #endif | ||
620 | } | ||
621 | |||
622 | |||
623 | /** | ||
624 | * Callback notifying about the end of a message. | ||
625 | */ | ||
626 | static void | ||
627 | slicer_recv_eom (void *cls, | ||
628 | const struct GNUNET_PSYC_MessageHeader *msg, | ||
629 | const struct GNUNET_MessageHeader *pmsg, | ||
630 | uint64_t message_id, | ||
631 | uint8_t is_cancelled) | ||
632 | { | ||
633 | printf(".\n"); | ||
634 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
635 | "Received end of message ID %" PRIu64 | ||
636 | ", cancelled: %u\n", | ||
637 | message_id, is_cancelled); | ||
638 | } | ||
639 | |||
640 | |||
641 | /** | ||
642 | * Create a slicer for receiving message parts. | ||
643 | */ | ||
644 | static struct GNUNET_PSYC_Slicer * | ||
645 | slicer_create () | ||
646 | { | ||
647 | slicer = GNUNET_PSYC_slicer_create (); | ||
648 | |||
649 | /* register slicer to receive incoming messages with any method name */ | ||
650 | GNUNET_PSYC_slicer_method_add (slicer, "", NULL, | ||
651 | slicer_recv_method, slicer_recv_modifier, | ||
652 | slicer_recv_data, slicer_recv_eom, NULL); | ||
653 | return slicer; | ||
654 | } | ||
655 | |||
656 | |||
657 | /* GUEST ENTER */ | ||
658 | |||
659 | |||
660 | /** | ||
661 | * Callback called when the guest receives an entry decision from the host. | ||
662 | * | ||
663 | * It is called once after using guest_enter() or guest_enter_by_name(), | ||
664 | * in case of a reconnection only the local enter callback is called. | ||
665 | */ | ||
666 | static void | ||
667 | guest_recv_entry_decision (void *cls, | ||
668 | int is_admitted, | ||
669 | const struct GNUNET_PSYC_Message *entry_msg) | ||
670 | { | ||
671 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
672 | "Guest received entry decision %d\n", | ||
673 | is_admitted); | ||
674 | |||
675 | if (NULL != entry_msg) | ||
676 | { | ||
677 | struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create (); | ||
678 | const char *method_name = NULL; | ||
679 | const void *data = NULL; | ||
680 | uint16_t data_size = 0; | ||
681 | struct GNUNET_PSYC_MessageHeader * | ||
682 | pmsg = GNUNET_PSYC_message_header_create_from_psyc (entry_msg); | ||
683 | GNUNET_PSYC_message_parse (pmsg, &method_name, env, &data, &data_size); | ||
684 | GNUNET_free (pmsg); | ||
685 | |||
686 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
687 | "%s\n%.*s\n", | ||
688 | method_name, data_size, (const char *) data); | ||
689 | } | ||
690 | |||
691 | if (op_guest_enter && !opt_follow) | ||
692 | { | ||
693 | exit_success (); | ||
694 | } | ||
695 | } | ||
696 | |||
697 | |||
698 | /** | ||
699 | * Callback called after a guest connection is established to the local service. | ||
700 | */ | ||
701 | static void | ||
702 | guest_recv_local_enter (void *cls, int result, | ||
703 | const struct GNUNET_CRYPTO_EddsaPublicKey *pub_key, | ||
704 | uint64_t max_message_id) | ||
705 | { | ||
706 | char *pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (pub_key); | ||
707 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
708 | "Guest entered local place: %s, max_message_id: %" PRIu64 "\n", | ||
709 | pub_str, max_message_id); | ||
710 | GNUNET_free (pub_str); | ||
711 | GNUNET_assert (0 <= result); | ||
712 | |||
713 | if (op_guest_enter && !opt_follow) | ||
714 | { | ||
715 | exit_success (); | ||
716 | } | ||
717 | } | ||
718 | |||
719 | |||
720 | /** | ||
721 | * Create entry request message. | ||
722 | */ | ||
723 | static struct GNUNET_PSYC_Message * | ||
724 | guest_enter_msg_create () | ||
725 | { | ||
726 | const char *method_name = "_request_enter"; | ||
727 | struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create (); | ||
728 | GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_SET, | ||
729 | "_foo", DATA2ARG ("bar")); | ||
730 | void *data = "let me in"; | ||
731 | uint16_t data_size = strlen (data) + 1; | ||
732 | |||
733 | return GNUNET_PSYC_message_create (method_name, env, data, data_size); | ||
734 | } | ||
735 | |||
736 | |||
737 | /** | ||
738 | * Enter a place as guest, using its public key and peer ID. | ||
739 | */ | ||
740 | static void | ||
741 | guest_enter (const struct GNUNET_CRYPTO_EddsaPublicKey *pub_key, | ||
742 | const struct GNUNET_PeerIdentity *peer) | ||
743 | { | ||
744 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
745 | "Entering to place as guest.\n"); | ||
746 | |||
747 | if (NULL == ego) | ||
748 | { | ||
749 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "--ego missing or invalid\n"); | ||
750 | exit_fail (); | ||
751 | return; | ||
752 | } | ||
753 | |||
754 | struct GNUNET_PSYC_Message *join_msg = guest_enter_msg_create (); | ||
755 | gst = GNUNET_SOCIAL_guest_enter (app, ego, pub_key, | ||
756 | GNUNET_PSYC_SLAVE_JOIN_NONE, | ||
757 | peer, 0, NULL, join_msg, slicer_create (), | ||
758 | guest_recv_local_enter, | ||
759 | guest_recv_entry_decision, NULL); | ||
760 | GNUNET_free (join_msg); | ||
761 | plc = GNUNET_SOCIAL_guest_get_place (gst); | ||
762 | } | ||
763 | |||
764 | |||
765 | /** | ||
766 | * Enter a place as guest using its GNS address. | ||
767 | */ | ||
768 | static void | ||
769 | guest_enter_by_name (const char *gns_name) | ||
770 | { | ||
771 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
772 | "Entering to place by name as guest.\n"); | ||
773 | |||
774 | struct GNUNET_PSYC_Message *join_msg = guest_enter_msg_create (); | ||
775 | gst = GNUNET_SOCIAL_guest_enter_by_name (app, ego, gns_name, NULL, | ||
776 | join_msg, slicer, | ||
777 | guest_recv_local_enter, | ||
778 | guest_recv_entry_decision, NULL); | ||
779 | GNUNET_free (join_msg); | ||
780 | plc = GNUNET_SOCIAL_guest_get_place (gst); | ||
781 | } | ||
782 | |||
783 | |||
784 | /* HOST ENTER */ | ||
785 | |||
786 | |||
787 | /** | ||
788 | * Callback called when a @a nym wants to enter the place. | ||
789 | * | ||
790 | * The request needs to be replied with an entry decision. | ||
791 | */ | ||
792 | static void | ||
793 | host_answer_door (void *cls, | ||
794 | struct GNUNET_SOCIAL_Nym *nym, | ||
795 | const char *method_name, | ||
796 | struct GNUNET_PSYC_Environment *env, | ||
797 | const void *data, | ||
798 | size_t data_size) | ||
799 | { | ||
800 | const struct GNUNET_CRYPTO_EcdsaPublicKey * | ||
801 | nym_key = GNUNET_SOCIAL_nym_get_pub_key (nym); | ||
802 | char * | ||
803 | nym_str = GNUNET_CRYPTO_ecdsa_public_key_to_string (nym_key); | ||
804 | |||
805 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
806 | "Entry request: %s\n", nym_str); | ||
807 | GNUNET_free (nym_str); | ||
808 | |||
809 | if (opt_welcome) | ||
810 | { | ||
811 | struct GNUNET_PSYC_Message * | ||
812 | resp = GNUNET_PSYC_message_create ("_notice_place_admit", env, | ||
813 | DATA2ARG ("Welcome, nym!")); | ||
814 | GNUNET_SOCIAL_host_entry_decision (hst, nym, GNUNET_YES, resp); | ||
815 | GNUNET_free (resp); | ||
816 | } | ||
817 | else if (opt_deny) | ||
818 | { | ||
819 | struct GNUNET_PSYC_Message * | ||
820 | resp = GNUNET_PSYC_message_create ("_notice_place_refuse", NULL, | ||
821 | DATA2ARG ("Go away!")); | ||
822 | GNUNET_SOCIAL_host_entry_decision (hst, nym, GNUNET_NO, resp); | ||
823 | GNUNET_free (resp); | ||
824 | } | ||
825 | |||
826 | |||
827 | } | ||
828 | |||
829 | |||
830 | /** | ||
831 | * Callback called when a @a nym has left the place. | ||
832 | */ | ||
833 | static void | ||
834 | host_farewell (void *cls, | ||
835 | const struct GNUNET_SOCIAL_Nym *nym, | ||
836 | struct GNUNET_PSYC_Environment *env) | ||
837 | { | ||
838 | const struct GNUNET_CRYPTO_EcdsaPublicKey * | ||
839 | nym_key = GNUNET_SOCIAL_nym_get_pub_key (nym); | ||
840 | char * | ||
841 | nym_str = GNUNET_CRYPTO_ecdsa_public_key_to_string (nym_key); | ||
842 | |||
843 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
844 | "Farewell: %s\n", nym_str); | ||
845 | GNUNET_free (nym_str); | ||
846 | } | ||
847 | |||
848 | |||
849 | /** | ||
850 | * Callback called after the host entered the place. | ||
851 | */ | ||
852 | static void | ||
853 | host_entered (void *cls, int result, | ||
854 | const struct GNUNET_CRYPTO_EddsaPublicKey *pub_key, | ||
855 | uint64_t max_message_id) | ||
856 | { | ||
857 | place_pub_key = *pub_key; | ||
858 | char *pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (pub_key); | ||
859 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
860 | "Host entered: %s, max_message_id: %" PRIu64 "\n", | ||
861 | pub_str, max_message_id); | ||
862 | GNUNET_free (pub_str); | ||
863 | |||
864 | if (op_host_enter && !opt_follow) | ||
865 | { | ||
866 | exit_success (); | ||
867 | } | ||
868 | } | ||
869 | |||
870 | |||
871 | /** | ||
872 | * Enter and start hosting a place. | ||
873 | */ | ||
874 | static void | ||
875 | host_enter () | ||
876 | { | ||
877 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "host_enter()\n"); | ||
878 | |||
879 | if (NULL == ego) | ||
880 | { | ||
881 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "--ego missing or invalid\n"); | ||
882 | exit_fail (); | ||
883 | return; | ||
884 | } | ||
885 | |||
886 | hst = GNUNET_SOCIAL_host_enter (app, ego, | ||
887 | GNUNET_PSYC_CHANNEL_PRIVATE, | ||
888 | slicer_create (), host_entered, | ||
889 | host_answer_door, host_farewell, NULL); | ||
890 | plc = GNUNET_SOCIAL_host_get_place (hst); | ||
891 | } | ||
892 | |||
893 | |||
894 | /* PLACE RECONNECT */ | ||
895 | |||
896 | |||
897 | /** | ||
898 | * Perform operations common to both host & guest places. | ||
899 | */ | ||
900 | static void | ||
901 | place_reconnected () | ||
902 | { | ||
903 | static int first_run = GNUNET_YES; | ||
904 | if (GNUNET_NO == first_run) | ||
905 | return; | ||
906 | first_run = GNUNET_NO; | ||
907 | |||
908 | if (op_replay) { | ||
909 | history_replay (opt_start, opt_until, opt_method); | ||
910 | } | ||
911 | else if (op_replay_latest) { | ||
912 | history_replay_latest (opt_limit, opt_method); | ||
913 | } | ||
914 | else if (op_look_at) { | ||
915 | look_at (opt_name); | ||
916 | } | ||
917 | else if (op_look_for) { | ||
918 | look_for (opt_name); | ||
919 | } | ||
920 | } | ||
921 | |||
922 | |||
923 | /** | ||
924 | * Callback called after reconnecting to a host place. | ||
925 | */ | ||
926 | static void | ||
927 | host_reconnected (void *cls, int result, | ||
928 | const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key, | ||
929 | uint64_t max_message_id) | ||
930 | { | ||
931 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
932 | "Host reconnected.\n"); | ||
933 | |||
934 | if (op_host_leave) { | ||
935 | host_leave (); | ||
936 | } | ||
937 | else if (op_host_announce) { | ||
938 | host_announce (opt_method, opt_data, strlen (opt_data)); | ||
939 | } | ||
940 | else if (op_host_assign) { | ||
941 | host_assign (opt_name, opt_data, strlen (opt_data) + 1); | ||
942 | } | ||
943 | else { | ||
944 | place_reconnected (); | ||
945 | } | ||
946 | } | ||
947 | |||
948 | |||
949 | /** | ||
950 | * Callback called after reconnecting to a guest place. | ||
951 | */ | ||
952 | static void | ||
953 | guest_reconnected (void *cls, int result, | ||
954 | const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key, | ||
955 | uint64_t max_message_id) | ||
956 | { | ||
957 | char *place_pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (place_pub_key); | ||
958 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
959 | "Guest reconnected to place %s.\n", place_pub_str); | ||
960 | GNUNET_free (place_pub_str); | ||
961 | |||
962 | if (op_guest_leave) { | ||
963 | guest_leave (); | ||
964 | } | ||
965 | else if (op_guest_talk) { | ||
966 | guest_talk (opt_method, opt_data, strlen (opt_data)); | ||
967 | } | ||
968 | else { | ||
969 | place_reconnected (); | ||
970 | } | ||
971 | } | ||
972 | |||
973 | |||
974 | /* APP */ | ||
975 | |||
976 | |||
977 | /** | ||
978 | * Callback called after the ego and place callbacks. | ||
979 | */ | ||
980 | static void | ||
981 | app_connected (void *cls) | ||
982 | { | ||
983 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
984 | "App connected: %p\n", cls); | ||
985 | |||
986 | if (op_status) | ||
987 | { | ||
988 | exit_success (); | ||
989 | } | ||
990 | else if (op_host_enter) | ||
991 | { | ||
992 | host_enter (); | ||
993 | } | ||
994 | else if (op_guest_enter) | ||
995 | { | ||
996 | if (opt_gns) | ||
997 | { | ||
998 | guest_enter_by_name (opt_gns); | ||
999 | } | ||
1000 | else | ||
1001 | { | ||
1002 | if (opt_peer) | ||
1003 | { | ||
1004 | if (GNUNET_OK != GNUNET_CRYPTO_eddsa_public_key_from_string (opt_peer, | ||
1005 | strlen (opt_peer), | ||
1006 | &peer.public_key)) | ||
1007 | { | ||
1008 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1009 | "--peer invalid"); | ||
1010 | exit_fail (); | ||
1011 | return; | ||
1012 | } | ||
1013 | } | ||
1014 | else | ||
1015 | { | ||
1016 | peer = this_peer; | ||
1017 | } | ||
1018 | guest_enter (&place_pub_key, &peer); | ||
1019 | } | ||
1020 | } | ||
1021 | printf(".\n"); | ||
1022 | } | ||
1023 | |||
1024 | |||
1025 | /** | ||
1026 | * Callback notifying about a host place available for reconnection. | ||
1027 | */ | ||
1028 | static void | ||
1029 | app_recv_host (void *cls, | ||
1030 | struct GNUNET_SOCIAL_HostConnection *hconn, | ||
1031 | struct GNUNET_SOCIAL_Ego *ego, | ||
1032 | const struct GNUNET_CRYPTO_EddsaPublicKey *host_pub_key, | ||
1033 | enum GNUNET_SOCIAL_AppPlaceState place_state) | ||
1034 | { | ||
1035 | char *host_pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (host_pub_key); | ||
1036 | printf ("Host\t%s\n", host_pub_str); | ||
1037 | GNUNET_free (host_pub_str); | ||
1038 | |||
1039 | if ((op_host_reconnect || op_host_leave || op_host_announce || op_host_assign | ||
1040 | || op_replay || op_replay_latest | ||
1041 | || op_look_at || op_look_for) | ||
1042 | && 0 == memcmp (&place_pub_key, host_pub_key, sizeof (*host_pub_key))) | ||
1043 | { | ||
1044 | hst = GNUNET_SOCIAL_host_enter_reconnect (hconn, slicer_create (), host_reconnected, | ||
1045 | host_answer_door, host_farewell, NULL); | ||
1046 | plc = GNUNET_SOCIAL_host_get_place (hst); | ||
1047 | } | ||
1048 | } | ||
1049 | |||
1050 | |||
1051 | /** | ||
1052 | * Callback notifying about a guest place available for reconnection. | ||
1053 | */ | ||
1054 | static void | ||
1055 | app_recv_guest (void *cls, | ||
1056 | struct GNUNET_SOCIAL_GuestConnection *gconn, | ||
1057 | struct GNUNET_SOCIAL_Ego *ego, | ||
1058 | const struct GNUNET_CRYPTO_EddsaPublicKey *guest_pub_key, | ||
1059 | enum GNUNET_SOCIAL_AppPlaceState place_state) | ||
1060 | { | ||
1061 | char *guest_pub_str = GNUNET_CRYPTO_eddsa_public_key_to_string (guest_pub_key); | ||
1062 | printf ("Guest\t%s\n", guest_pub_str); | ||
1063 | GNUNET_free (guest_pub_str); | ||
1064 | |||
1065 | if ((op_guest_reconnect || op_guest_leave || op_guest_talk | ||
1066 | || op_replay || op_replay_latest | ||
1067 | || op_look_at || op_look_for) | ||
1068 | && 0 == memcmp (&place_pub_key, guest_pub_key, sizeof (*guest_pub_key))) | ||
1069 | { | ||
1070 | gst = GNUNET_SOCIAL_guest_enter_reconnect (gconn, GNUNET_PSYC_SLAVE_JOIN_NONE, | ||
1071 | slicer_create (), guest_reconnected, NULL); | ||
1072 | plc = GNUNET_SOCIAL_guest_get_place (gst); | ||
1073 | } | ||
1074 | } | ||
1075 | |||
1076 | |||
1077 | /** | ||
1078 | * Callback notifying about an available ego. | ||
1079 | */ | ||
1080 | static void | ||
1081 | app_recv_ego (void *cls, | ||
1082 | struct GNUNET_SOCIAL_Ego *e, | ||
1083 | const struct GNUNET_CRYPTO_EcdsaPublicKey *pub_key, | ||
1084 | const char *name) | ||
1085 | { | ||
1086 | char *s = GNUNET_CRYPTO_ecdsa_public_key_to_string (pub_key); | ||
1087 | printf ("Ego\t%s\t%s\n", s, name); | ||
1088 | GNUNET_free (s); | ||
1089 | |||
1090 | if (0 == memcmp (&ego_pub_key, pub_key, sizeof (*pub_key)) | ||
1091 | || (NULL != opt_ego && 0 == strcmp (opt_ego, name))) | ||
1092 | { | ||
1093 | ego = e; | ||
1094 | } | ||
1095 | |||
1096 | } | ||
1097 | |||
1098 | |||
1099 | |||
1100 | /** | ||
1101 | * Establish application connection to receive available egos and places. | ||
1102 | */ | ||
1103 | static void | ||
1104 | app_connect (void *cls) | ||
1105 | { | ||
1106 | app = GNUNET_SOCIAL_app_connect (cfg, opt_app, | ||
1107 | app_recv_ego, | ||
1108 | app_recv_host, | ||
1109 | app_recv_guest, | ||
1110 | app_connected, | ||
1111 | NULL); | ||
1112 | } | ||
1113 | |||
1114 | |||
1115 | /** | ||
1116 | * Main function run by the scheduler. | ||
1117 | * | ||
1118 | * @param cls closure | ||
1119 | * @param args remaining command-line arguments | ||
1120 | * @param cfgfile name of the configuration file used (for saving, can be NULL!) | ||
1121 | * @param c configuration | ||
1122 | */ | ||
1123 | static void | ||
1124 | run (void *cls, char *const *args, const char *cfgfile, | ||
1125 | const struct GNUNET_CONFIGURATION_Handle *c) | ||
1126 | { | ||
1127 | cfg = c; | ||
1128 | GNUNET_CRYPTO_get_peer_identity (cfg, &this_peer); | ||
1129 | |||
1130 | if (!opt_method) | ||
1131 | opt_method = "message"; | ||
1132 | if (!opt_data) | ||
1133 | opt_data = ""; | ||
1134 | if (!opt_name) | ||
1135 | opt_name = ""; | ||
1136 | |||
1137 | if (! (op_status | ||
1138 | || op_host_enter || op_host_reconnect || op_host_leave | ||
1139 | || op_host_announce || op_host_assign | ||
1140 | || op_guest_enter || op_guest_reconnect | ||
1141 | || op_guest_leave || op_guest_talk | ||
1142 | || op_replay || op_replay_latest | ||
1143 | || op_look_at || op_look_for)) | ||
1144 | { | ||
1145 | op_status = 1; | ||
1146 | fputs("Caution: This tool does not produce correct binary safe PSYC syntax.\n\n", stderr); | ||
1147 | } | ||
1148 | |||
1149 | GNUNET_SCHEDULER_add_shutdown (scheduler_shutdown, NULL); | ||
1150 | if (!opt_follow) | ||
1151 | { | ||
1152 | timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, timeout, NULL); | ||
1153 | } | ||
1154 | |||
1155 | if ((op_host_reconnect || op_host_leave || op_host_announce || op_host_assign | ||
1156 | || op_guest_reconnect || (op_guest_enter && !opt_gns) | ||
1157 | || op_guest_leave || op_guest_talk | ||
1158 | || op_replay || op_replay_latest | ||
1159 | || op_look_at || op_look_for) | ||
1160 | && (!opt_place | ||
1161 | || GNUNET_OK != GNUNET_CRYPTO_eddsa_public_key_from_string (opt_place, | ||
1162 | strlen (opt_place), | ||
1163 | &place_pub_key))) | ||
1164 | { | ||
1165 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1166 | _("--place missing or invalid.\n")); | ||
1167 | /* FIXME: why does it segfault here? */ | ||
1168 | exit_fail (); | ||
1169 | return; | ||
1170 | } | ||
1171 | |||
1172 | if (opt_ego) | ||
1173 | { | ||
1174 | if (GNUNET_OK != | ||
1175 | GNUNET_CRYPTO_ecdsa_public_key_from_string (opt_ego, | ||
1176 | strlen (opt_ego), | ||
1177 | &ego_pub_key)) | ||
1178 | { | ||
1179 | FPRINTF (stderr, | ||
1180 | _("Public key `%s' malformed\n"), | ||
1181 | opt_ego); | ||
1182 | exit_fail (); | ||
1183 | return; | ||
1184 | } | ||
1185 | } | ||
1186 | |||
1187 | GNUNET_SCHEDULER_add_now (app_connect, NULL); | ||
1188 | } | ||
1189 | |||
1190 | |||
1191 | /** | ||
1192 | * The main function to obtain peer information. | ||
1193 | * | ||
1194 | * @param argc number of arguments from the command line | ||
1195 | * @param argv command line arguments | ||
1196 | * @return 0 ok, 1 on error | ||
1197 | */ | ||
1198 | int | ||
1199 | main (int argc, char *const *argv) | ||
1200 | { | ||
1201 | int res; | ||
1202 | struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
1203 | /* | ||
1204 | * gnunet program options in addition to the ones below: | ||
1205 | * | ||
1206 | * -c, --config=FILENAME | ||
1207 | * -l, --logfile=LOGFILE | ||
1208 | * -L, --log=LOGLEVEL | ||
1209 | * -h, --help | ||
1210 | * -v, --version | ||
1211 | */ | ||
1212 | |||
1213 | /* operations */ | ||
1214 | |||
1215 | GNUNET_GETOPT_option_flag ('A', | ||
1216 | "host-assign", | ||
1217 | gettext_noop ("assign --name in state to --data"), | ||
1218 | &op_host_assign), | ||
1219 | |||
1220 | GNUNET_GETOPT_option_flag ('B', | ||
1221 | "guest-leave", | ||
1222 | gettext_noop ("say good-bye and leave somebody else's place"), | ||
1223 | &op_guest_leave), | ||
1224 | |||
1225 | GNUNET_GETOPT_option_flag ('C', | ||
1226 | "host-enter", | ||
1227 | gettext_noop ("create a place"), | ||
1228 | &op_host_enter), | ||
1229 | |||
1230 | GNUNET_GETOPT_option_flag ('D', | ||
1231 | "host-leave", | ||
1232 | gettext_noop ("destroy a place we were hosting"), | ||
1233 | &op_host_leave), | ||
1234 | |||
1235 | GNUNET_GETOPT_option_flag ('E', | ||
1236 | "guest-enter", | ||
1237 | gettext_noop ("enter somebody else's place"), | ||
1238 | &op_guest_enter), | ||
1239 | |||
1240 | |||
1241 | GNUNET_GETOPT_option_flag ('F', | ||
1242 | "look-for", | ||
1243 | gettext_noop ("find state matching name prefix"), | ||
1244 | &op_look_for), | ||
1245 | |||
1246 | GNUNET_GETOPT_option_flag ('H', | ||
1247 | "replay-latest", | ||
1248 | gettext_noop ("replay history of messages up to the given --limit"), | ||
1249 | &op_replay_latest), | ||
1250 | |||
1251 | GNUNET_GETOPT_option_flag ('N', | ||
1252 | "host-reconnect", | ||
1253 | gettext_noop ("reconnect to a previously created place"), | ||
1254 | &op_host_reconnect), | ||
1255 | |||
1256 | GNUNET_GETOPT_option_flag ('P', | ||
1257 | "host-announce", | ||
1258 | gettext_noop ("publish something to a place we are hosting"), | ||
1259 | &op_host_announce), | ||
1260 | |||
1261 | GNUNET_GETOPT_option_flag ('R', | ||
1262 | "guest-reconnect", | ||
1263 | gettext_noop ("reconnect to a previously entered place"), | ||
1264 | &op_guest_reconnect), | ||
1265 | |||
1266 | GNUNET_GETOPT_option_flag ('S', | ||
1267 | "look-at", | ||
1268 | gettext_noop ("search for state matching exact name"), | ||
1269 | &op_look_at), | ||
1270 | |||
1271 | GNUNET_GETOPT_option_flag ('T', | ||
1272 | "guest-talk", | ||
1273 | gettext_noop ("submit something to somebody's place"), | ||
1274 | &op_guest_talk), | ||
1275 | |||
1276 | GNUNET_GETOPT_option_flag ('U', | ||
1277 | "status", | ||
1278 | gettext_noop ("list of egos and subscribed places"), | ||
1279 | &op_status), | ||
1280 | |||
1281 | GNUNET_GETOPT_option_flag ('X', | ||
1282 | "replay", | ||
1283 | gettext_noop ("extract and replay history between message IDs --start and --until"), | ||
1284 | &op_replay), | ||
1285 | |||
1286 | |||
1287 | /* options */ | ||
1288 | |||
1289 | GNUNET_GETOPT_option_string ('a', | ||
1290 | "app", | ||
1291 | "APPLICATION_ID", | ||
1292 | gettext_noop ("application ID to use when connecting"), | ||
1293 | &opt_app), | ||
1294 | |||
1295 | GNUNET_GETOPT_option_string ('d', | ||
1296 | "data", | ||
1297 | "DATA", | ||
1298 | gettext_noop ("message body or state value"), | ||
1299 | &opt_data), | ||
1300 | |||
1301 | GNUNET_GETOPT_option_string ('e', | ||
1302 | "ego", | ||
1303 | "NAME|PUBKEY", | ||
1304 | gettext_noop ("name or public key of ego"), | ||
1305 | &opt_ego), | ||
1306 | |||
1307 | GNUNET_GETOPT_option_flag ('f', | ||
1308 | "follow", | ||
1309 | gettext_noop ("wait for incoming messages"), | ||
1310 | &opt_follow), | ||
1311 | |||
1312 | GNUNET_GETOPT_option_string ('g', | ||
1313 | "gns", | ||
1314 | "GNS_NAME", | ||
1315 | gettext_noop ("GNS name"), | ||
1316 | &opt_gns), | ||
1317 | |||
1318 | GNUNET_GETOPT_option_string ('i', | ||
1319 | "peer", | ||
1320 | "PEER_ID", | ||
1321 | gettext_noop ("peer ID for --guest-enter"), | ||
1322 | &opt_peer), | ||
1323 | |||
1324 | GNUNET_GETOPT_option_string ('k', | ||
1325 | "name", | ||
1326 | "VAR_NAME", | ||
1327 | gettext_noop ("name (key) to query from state"), | ||
1328 | &opt_name), | ||
1329 | |||
1330 | GNUNET_GETOPT_option_string ('m', | ||
1331 | "method", | ||
1332 | "METHOD_NAME", | ||
1333 | gettext_noop ("method name"), | ||
1334 | &opt_method), | ||
1335 | |||
1336 | GNUNET_GETOPT_option_ulong ('n', | ||
1337 | "limit", | ||
1338 | NULL, | ||
1339 | gettext_noop ("number of messages to replay from history"), | ||
1340 | &opt_limit), | ||
1341 | |||
1342 | GNUNET_GETOPT_option_string ('p', | ||
1343 | "place", | ||
1344 | "PUBKEY", | ||
1345 | gettext_noop ("key address of place"), | ||
1346 | &opt_place), | ||
1347 | |||
1348 | GNUNET_GETOPT_option_ulong ('s', | ||
1349 | "start", | ||
1350 | NULL, | ||
1351 | gettext_noop ("start message ID for history replay"), | ||
1352 | &opt_start), | ||
1353 | |||
1354 | GNUNET_GETOPT_option_flag ('w', | ||
1355 | "welcome", | ||
1356 | gettext_noop ("respond to entry requests by admitting all guests"), | ||
1357 | &opt_welcome), | ||
1358 | |||
1359 | GNUNET_GETOPT_option_ulong ('u', | ||
1360 | "until", | ||
1361 | NULL, | ||
1362 | gettext_noop ("end message ID for history replay"), | ||
1363 | &opt_until), | ||
1364 | |||
1365 | GNUNET_GETOPT_option_flag ('y', | ||
1366 | "deny", | ||
1367 | gettext_noop ("respond to entry requests by refusing all guests"), | ||
1368 | &opt_deny), | ||
1369 | |||
1370 | GNUNET_GETOPT_OPTION_END | ||
1371 | }; | ||
1372 | |||
1373 | if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) | ||
1374 | return 2; | ||
1375 | |||
1376 | const char *help = | ||
1377 | _ ("gnunet-social - Interact with the social service: enter/leave, send/receive messages, access history and state.\n"); | ||
1378 | const char *usage = | ||
1379 | "gnunet-social [--status]\n" | ||
1380 | "\n" | ||
1381 | "gnunet-social --host-enter --ego <NAME or PUBKEY> [--follow] [--welcome | --deny]\n" | ||
1382 | "gnunet-social --host-reconnect --place <PUBKEY> [--follow] [--welcome | --deny]\n" | ||
1383 | "gnunet-social --host-leave --place <PUBKEY>\n" | ||
1384 | "gnunet-social --host-assign --place <PUBKEY> --name <NAME> --data <VALUE>\n" | ||
1385 | // FIXME: some state ops not implemented yet (no hurry) | ||
1386 | // "gnunet-social --host-augment --place <PUBKEY> --name <NAME> --data <VALUE>\n" | ||
1387 | // "gnunet-social --host-diminish --place <PUBKEY> --name <NAME> --data <VALUE>\n" | ||
1388 | // "gnunet-social --host-set --place <PUBKEY> --name <NAME> --data <VALUE>\n" | ||
1389 | "gnunet-social --host-announce --place <PUBKEY> --method <METHOD_NAME> --data <MESSAGE_BODY>\n" | ||
1390 | "\n" | ||
1391 | "gnunet-social --guest-enter --place <PUBKEY> --peer <PEERID> --ego <NAME or PUBKEY> [--follow]\n" | ||
1392 | "gnunet-social --guest-enter --gns <GNS_NAME> --ego <NAME or PUBKEY> [--follow]\n" | ||
1393 | "gnunet-social --guest-reconnect --place <PUBKEY> [--follow]\n" | ||
1394 | "gnunet-social --guest-leave --place <PUBKEY>\n" | ||
1395 | "gnunet-social --guest-talk --place <PUBKEY> --method <METHOD_NAME> --data <MESSAGE_BODY>\n" | ||
1396 | "\n" | ||
1397 | "gnunet-social --replay --place <PUBKEY> --start <MSGID> --until <MSGID> [--method <METHOD_PREFIX>]\n" | ||
1398 | "gnunet-social --replay-latest --place <PUBKEY> --limit <MSG_LIMIT> [--method <METHOD_PREFIX>]\n" | ||
1399 | "\n" | ||
1400 | "gnunet-social --look-at --place <PUBKEY> --name <FULL_NAME>\n" | ||
1401 | "gnunet-social --look-for --place <PUBKEY> --name <NAME_PREFIX>\n"; | ||
1402 | |||
1403 | res = GNUNET_PROGRAM_run (argc, argv, help, usage, options, &run, NULL); | ||
1404 | |||
1405 | GNUNET_free ((void *) argv); | ||
1406 | |||
1407 | if (GNUNET_OK == res) | ||
1408 | return ret; | ||
1409 | else | ||
1410 | return 1; | ||
1411 | } | ||
diff --git a/src/social/social.conf.in b/src/social/social.conf.in deleted file mode 100644 index 3fe754c80..000000000 --- a/src/social/social.conf.in +++ /dev/null | |||
@@ -1,15 +0,0 @@ | |||
1 | [social] | ||
2 | START_ON_DEMAND = @START_ON_DEMAND@ | ||
3 | BINARY = gnunet-service-social | ||
4 | RUN_PER_USER = YES | ||
5 | |||
6 | UNIXPATH = $GNUNET_USER_RUNTIME_DIR/gnunet-service-social.sock | ||
7 | UNIX_MATCH_UID = YES | ||
8 | UNIX_MATCH_GID = YES | ||
9 | |||
10 | @UNIXONLY@PORT = 2116 | ||
11 | HOSTNAME = localhost | ||
12 | ACCEPT_FROM = 127.0.0.1; | ||
13 | ACCEPT_FROM6 = ::1; | ||
14 | |||
15 | DATA_HOME = $GNUNET_DATA_HOME/social | ||
diff --git a/src/social/social.h b/src/social/social.h deleted file mode 100644 index 73f73f651..000000000 --- a/src/social/social.h +++ /dev/null | |||
@@ -1,292 +0,0 @@ | |||
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 social/social.h | ||
23 | * @brief Common type definitions for the Social service and API. | ||
24 | * @author Gabor X Toth | ||
25 | */ | ||
26 | |||
27 | #ifndef SOCIAL_H | ||
28 | #define SOCIAL_H | ||
29 | |||
30 | #include "platform.h" | ||
31 | #include "gnunet_social_service.h" | ||
32 | |||
33 | enum MessageState | ||
34 | { | ||
35 | MSG_STATE_START = 0, | ||
36 | MSG_STATE_HEADER = 1, | ||
37 | MSG_STATE_METHOD = 2, | ||
38 | MSG_STATE_MODIFIER = 3, | ||
39 | MSG_STATE_MOD_CONT = 4, | ||
40 | MSG_STATE_DATA = 5, | ||
41 | MSG_STATE_END = 6, | ||
42 | MSG_STATE_CANCEL = 7, | ||
43 | MSG_STATE_ERROR = 8, | ||
44 | }; | ||
45 | |||
46 | |||
47 | GNUNET_NETWORK_STRUCT_BEGIN | ||
48 | |||
49 | /**** library -> service ****/ | ||
50 | |||
51 | |||
52 | struct AppConnectRequest | ||
53 | { | ||
54 | /** | ||
55 | * Type: GNUNET_MESSAGE_TYPE_SOCIAL_APP_CONNECT | ||
56 | */ | ||
57 | struct GNUNET_MessageHeader header; | ||
58 | |||
59 | /* Followed by char *app_id */ | ||
60 | }; | ||
61 | |||
62 | |||
63 | struct AppDetachRequest | ||
64 | { | ||
65 | /** | ||
66 | * Type: GNUNET_MESSAGE_TYPE_SOCIAL_APP_DETACH | ||
67 | */ | ||
68 | struct GNUNET_MessageHeader header; | ||
69 | |||
70 | /** | ||
71 | * Public key of place. | ||
72 | */ | ||
73 | struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key; | ||
74 | |||
75 | /** | ||
76 | * Public key of ego. | ||
77 | */ | ||
78 | struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key; | ||
79 | |||
80 | /** | ||
81 | * Operation ID. | ||
82 | */ | ||
83 | uint64_t op_id GNUNET_PACKED; | ||
84 | }; | ||
85 | |||
86 | |||
87 | struct MsgProcRequest | ||
88 | { | ||
89 | /** | ||
90 | * Type: GNUNET_MESSAGE_TYPE_SOCIAL_MSG_PROC_SET | ||
91 | */ | ||
92 | struct GNUNET_MessageHeader header; | ||
93 | |||
94 | /** | ||
95 | * @see enum GNUNET_SOCIAL_MsgProcFlags | ||
96 | */ | ||
97 | uint32_t flags; | ||
98 | |||
99 | /* Followed by char *method_prefix */ | ||
100 | }; | ||
101 | |||
102 | |||
103 | struct HostEnterRequest | ||
104 | { | ||
105 | /** | ||
106 | * Type: GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER | ||
107 | */ | ||
108 | struct GNUNET_MessageHeader header; | ||
109 | |||
110 | uint32_t policy GNUNET_PACKED; | ||
111 | |||
112 | struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key; | ||
113 | |||
114 | struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key; | ||
115 | |||
116 | struct GNUNET_CRYPTO_EddsaPrivateKey place_key; | ||
117 | |||
118 | /* Followed by char *app_id */ | ||
119 | }; | ||
120 | |||
121 | |||
122 | struct GuestEnterRequest | ||
123 | { | ||
124 | /** | ||
125 | * Type: GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER | ||
126 | */ | ||
127 | struct GNUNET_MessageHeader header; | ||
128 | |||
129 | uint32_t relay_count GNUNET_PACKED; | ||
130 | |||
131 | struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key; | ||
132 | |||
133 | struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key; | ||
134 | |||
135 | struct GNUNET_PeerIdentity origin; | ||
136 | |||
137 | uint32_t flags GNUNET_PACKED; | ||
138 | |||
139 | /* Followed by char *app_id */ | ||
140 | /* Followed by struct GNUNET_PeerIdentity relays[relay_count] */ | ||
141 | /* Followed by struct GNUNET_MessageHeader *join_msg */ | ||
142 | }; | ||
143 | |||
144 | |||
145 | /** Compatible parts of HostEnterRequest and GuestEnterRequest */ | ||
146 | struct PlaceEnterRequest | ||
147 | { | ||
148 | struct GNUNET_MessageHeader header; | ||
149 | |||
150 | uint32_t reserved GNUNET_PACKED; | ||
151 | |||
152 | struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key; | ||
153 | |||
154 | struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key; | ||
155 | }; | ||
156 | |||
157 | |||
158 | struct EgoPlacePublicKey | ||
159 | { | ||
160 | struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key; | ||
161 | struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key; | ||
162 | }; | ||
163 | |||
164 | |||
165 | struct GuestEnterByNameRequest | ||
166 | { | ||
167 | /** | ||
168 | * Type: GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_BY_NAME | ||
169 | */ | ||
170 | struct GNUNET_MessageHeader header; | ||
171 | |||
172 | struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key; | ||
173 | |||
174 | /* Followed by char *app_id */ | ||
175 | /* Followed by char *gns_name */ | ||
176 | /* Followed by char *password */ | ||
177 | /* Followed by struct GNUNET_MessageHeader *join_msg */ | ||
178 | }; | ||
179 | |||
180 | |||
181 | struct ZoneAddPlaceRequest | ||
182 | { | ||
183 | struct GNUNET_MessageHeader header; | ||
184 | |||
185 | uint32_t relay_count GNUNET_PACKED; | ||
186 | |||
187 | /** | ||
188 | * Operation ID. | ||
189 | */ | ||
190 | uint64_t op_id; | ||
191 | |||
192 | /** | ||
193 | * Expiration time: absolute value in us. | ||
194 | */ | ||
195 | uint64_t expiration_time; | ||
196 | |||
197 | struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key; | ||
198 | |||
199 | struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key; | ||
200 | |||
201 | struct GNUNET_PeerIdentity origin; | ||
202 | |||
203 | /* Followed by const char *name */ | ||
204 | /* Followed by const char *password */ | ||
205 | /* Followed by struct GNUNET_PeerIdentity *relays[relay_count] */ | ||
206 | }; | ||
207 | |||
208 | |||
209 | struct ZoneAddNymRequest | ||
210 | { | ||
211 | struct GNUNET_MessageHeader header; | ||
212 | |||
213 | /** | ||
214 | * Operation ID. | ||
215 | */ | ||
216 | uint64_t op_id; | ||
217 | |||
218 | /** | ||
219 | * Expiration time: absolute value in us. | ||
220 | */ | ||
221 | uint64_t expiration_time; | ||
222 | |||
223 | struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key; | ||
224 | |||
225 | struct GNUNET_CRYPTO_EcdsaPublicKey nym_pub_key; | ||
226 | |||
227 | /* Followed by const char *name */ | ||
228 | }; | ||
229 | |||
230 | |||
231 | /**** service -> library ****/ | ||
232 | |||
233 | |||
234 | struct AppEgoMessage | ||
235 | { | ||
236 | /** | ||
237 | * Type: GNUNET_MESSAGE_TYPE_SOCIAL_APP_EGO | ||
238 | */ | ||
239 | struct GNUNET_MessageHeader header; | ||
240 | |||
241 | /** | ||
242 | * Public key of ego. | ||
243 | */ | ||
244 | struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key; | ||
245 | |||
246 | /* Followed by char *name */ | ||
247 | }; | ||
248 | |||
249 | |||
250 | struct AppPlaceMessage | ||
251 | { | ||
252 | /** | ||
253 | * Type: GNUNET_MESSAGE_TYPE_SOCIAL_APP_PLACE | ||
254 | */ | ||
255 | struct GNUNET_MessageHeader header; | ||
256 | |||
257 | struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key; | ||
258 | |||
259 | struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key; | ||
260 | |||
261 | uint8_t is_host; | ||
262 | |||
263 | uint8_t place_state; | ||
264 | }; | ||
265 | |||
266 | |||
267 | struct HostEnterAck { | ||
268 | /** | ||
269 | * Type: GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER_ACK | ||
270 | */ | ||
271 | struct GNUNET_MessageHeader header; | ||
272 | |||
273 | /** | ||
274 | * Status code for the operation. | ||
275 | */ | ||
276 | uint32_t result_code GNUNET_PACKED; | ||
277 | |||
278 | /** | ||
279 | * Last message ID sent to the channel. | ||
280 | */ | ||
281 | uint64_t max_message_id GNUNET_PACKED; | ||
282 | |||
283 | /** | ||
284 | * Public key of the place. | ||
285 | */ | ||
286 | struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key; | ||
287 | }; | ||
288 | |||
289 | |||
290 | GNUNET_NETWORK_STRUCT_END | ||
291 | |||
292 | #endif | ||
diff --git a/src/social/social_api.c b/src/social/social_api.c deleted file mode 100644 index 9b9658096..000000000 --- a/src/social/social_api.c +++ /dev/null | |||
@@ -1,2827 +0,0 @@ | |||
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 | * @author Gabor X Toth | ||
23 | * | ||
24 | * @file | ||
25 | * Social service; implements social interactions using the PSYC service. | ||
26 | */ | ||
27 | |||
28 | #include <inttypes.h> | ||
29 | #include <string.h> | ||
30 | |||
31 | #include "platform.h" | ||
32 | #include "gnunet_util_lib.h" | ||
33 | #include "gnunet_psyc_service.h" | ||
34 | #include "gnunet_psyc_util_lib.h" | ||
35 | #include "gnunet_social_service.h" | ||
36 | #include "social.h" | ||
37 | |||
38 | #define LOG(kind,...) GNUNET_log_from (kind, "social-api",__VA_ARGS__) | ||
39 | |||
40 | /** | ||
41 | * Handle for an ego. | ||
42 | */ | ||
43 | struct GNUNET_SOCIAL_Ego | ||
44 | { | ||
45 | struct GNUNET_CRYPTO_EcdsaPublicKey pub_key; | ||
46 | struct GNUNET_HashCode pub_key_hash; | ||
47 | char *name; | ||
48 | }; | ||
49 | |||
50 | |||
51 | /** | ||
52 | * Handle for a pseudonym of another user in the network. | ||
53 | */ | ||
54 | struct GNUNET_SOCIAL_Nym | ||
55 | { | ||
56 | struct GNUNET_CRYPTO_EcdsaPublicKey pub_key; | ||
57 | struct GNUNET_HashCode pub_key_hash; | ||
58 | }; | ||
59 | |||
60 | |||
61 | /** | ||
62 | * Handle for an application. | ||
63 | */ | ||
64 | struct GNUNET_SOCIAL_App | ||
65 | { | ||
66 | /** | ||
67 | * Configuration to use. | ||
68 | */ | ||
69 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
70 | |||
71 | /** | ||
72 | * Client connection to the service. | ||
73 | */ | ||
74 | struct GNUNET_MQ_Handle *mq; | ||
75 | |||
76 | /** | ||
77 | * Message to send on connect. | ||
78 | */ | ||
79 | struct GNUNET_MQ_Envelope *connect_env; | ||
80 | |||
81 | /** | ||
82 | * Time to wait until we try to reconnect on failure. | ||
83 | */ | ||
84 | struct GNUNET_TIME_Relative reconnect_delay; | ||
85 | |||
86 | /** | ||
87 | * Task for reconnecting when the listener fails. | ||
88 | */ | ||
89 | struct GNUNET_SCHEDULER_Task *reconnect_task; | ||
90 | |||
91 | /** | ||
92 | * Async operations. | ||
93 | */ | ||
94 | struct GNUNET_OP_Handle *op; | ||
95 | |||
96 | /** | ||
97 | * Function called after disconnected from the service. | ||
98 | */ | ||
99 | GNUNET_ContinuationCallback disconnect_cb; | ||
100 | |||
101 | /** | ||
102 | * Closure for @a disconnect_cb. | ||
103 | */ | ||
104 | void *disconnect_cls; | ||
105 | |||
106 | /** | ||
107 | * Application ID. | ||
108 | */ | ||
109 | char *id; | ||
110 | |||
111 | /** | ||
112 | * Hash map of all egos. | ||
113 | * pub_key_hash -> struct GNUNET_SOCIAL_Ego * | ||
114 | */ | ||
115 | struct GNUNET_CONTAINER_MultiHashMap *egos; | ||
116 | |||
117 | GNUNET_SOCIAL_AppEgoCallback ego_cb; | ||
118 | GNUNET_SOCIAL_AppHostPlaceCallback host_cb; | ||
119 | GNUNET_SOCIAL_AppGuestPlaceCallback guest_cb; | ||
120 | GNUNET_SOCIAL_AppConnectedCallback connected_cb; | ||
121 | void *cb_cls; | ||
122 | }; | ||
123 | |||
124 | |||
125 | struct GNUNET_SOCIAL_HostConnection | ||
126 | { | ||
127 | struct GNUNET_SOCIAL_App *app; | ||
128 | |||
129 | struct AppPlaceMessage plc_msg; | ||
130 | }; | ||
131 | |||
132 | |||
133 | struct GNUNET_SOCIAL_GuestConnection | ||
134 | { | ||
135 | struct GNUNET_SOCIAL_App *app; | ||
136 | |||
137 | struct AppPlaceMessage plc_msg; | ||
138 | }; | ||
139 | |||
140 | |||
141 | /** | ||
142 | * Handle for a place where social interactions happen. | ||
143 | */ | ||
144 | struct GNUNET_SOCIAL_Place | ||
145 | { | ||
146 | /** | ||
147 | * Configuration to use. | ||
148 | */ | ||
149 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
150 | |||
151 | /** | ||
152 | * Client connection to the service. | ||
153 | */ | ||
154 | struct GNUNET_MQ_Handle *mq; | ||
155 | |||
156 | /** | ||
157 | * Message to send on connect. | ||
158 | */ | ||
159 | struct GNUNET_MQ_Envelope *connect_env; | ||
160 | |||
161 | /** | ||
162 | * Time to wait until we try to reconnect on failure. | ||
163 | */ | ||
164 | struct GNUNET_TIME_Relative reconnect_delay; | ||
165 | |||
166 | /** | ||
167 | * Task for reconnecting when the listener fails. | ||
168 | */ | ||
169 | struct GNUNET_SCHEDULER_Task *reconnect_task; | ||
170 | |||
171 | /** | ||
172 | * Async operations. | ||
173 | */ | ||
174 | struct GNUNET_OP_Handle *op; | ||
175 | |||
176 | /** | ||
177 | * Transmission handle. | ||
178 | */ | ||
179 | struct GNUNET_PSYC_TransmitHandle *tmit; | ||
180 | |||
181 | /** | ||
182 | * Slicer for processing incoming messages. | ||
183 | */ | ||
184 | struct GNUNET_PSYC_Slicer *slicer; | ||
185 | |||
186 | // FIXME: do we need is_disconnecing like on the psyc and multicast APIs? | ||
187 | /** | ||
188 | * Function called after disconnected from the service. | ||
189 | */ | ||
190 | GNUNET_ContinuationCallback disconnect_cb; | ||
191 | |||
192 | /** | ||
193 | * Closure for @a disconnect_cb. | ||
194 | */ | ||
195 | void *disconnect_cls; | ||
196 | |||
197 | /** | ||
198 | * Public key of the place. | ||
199 | */ | ||
200 | struct GNUNET_CRYPTO_EddsaPublicKey pub_key; | ||
201 | |||
202 | /** | ||
203 | * Public key of the ego. | ||
204 | */ | ||
205 | struct GNUNET_CRYPTO_EcdsaPublicKey ego_pub_key; | ||
206 | |||
207 | /** | ||
208 | * Does this place belong to a host (#GNUNET_YES) or guest (#GNUNET_NO)? | ||
209 | */ | ||
210 | uint8_t is_host; | ||
211 | }; | ||
212 | |||
213 | |||
214 | /** | ||
215 | * Host handle for a place that we entered. | ||
216 | */ | ||
217 | struct GNUNET_SOCIAL_Host | ||
218 | { | ||
219 | struct GNUNET_SOCIAL_Place plc; | ||
220 | |||
221 | /** | ||
222 | * Slicer for processing incoming messages from guests. | ||
223 | */ | ||
224 | struct GNUNET_PSYC_Slicer *slicer; | ||
225 | |||
226 | GNUNET_SOCIAL_HostEnterCallback enter_cb; | ||
227 | |||
228 | GNUNET_SOCIAL_AnswerDoorCallback answer_door_cb; | ||
229 | |||
230 | GNUNET_SOCIAL_FarewellCallback farewell_cb; | ||
231 | |||
232 | /** | ||
233 | * Closure for callbacks. | ||
234 | */ | ||
235 | void *cb_cls; | ||
236 | |||
237 | struct GNUNET_SOCIAL_Nym *notice_place_leave_nym; | ||
238 | struct GNUNET_PSYC_Environment *notice_place_leave_env; | ||
239 | }; | ||
240 | |||
241 | |||
242 | /** | ||
243 | * Guest handle for place that we entered. | ||
244 | */ | ||
245 | struct GNUNET_SOCIAL_Guest | ||
246 | { | ||
247 | struct GNUNET_SOCIAL_Place plc; | ||
248 | |||
249 | GNUNET_SOCIAL_GuestEnterCallback enter_cb; | ||
250 | |||
251 | GNUNET_SOCIAL_EntryDecisionCallback entry_dcsn_cb; | ||
252 | |||
253 | /** | ||
254 | * Closure for callbacks. | ||
255 | */ | ||
256 | void *cb_cls; | ||
257 | }; | ||
258 | |||
259 | |||
260 | /** | ||
261 | * Hash map of all nyms. | ||
262 | * pub_key_hash -> struct GNUNET_SOCIAL_Nym * | ||
263 | */ | ||
264 | struct GNUNET_CONTAINER_MultiHashMap *nyms; | ||
265 | |||
266 | |||
267 | /** | ||
268 | * Handle for an announcement request. | ||
269 | */ | ||
270 | struct GNUNET_SOCIAL_Announcement | ||
271 | { | ||
272 | |||
273 | }; | ||
274 | |||
275 | |||
276 | /** | ||
277 | * A talk request. | ||
278 | */ | ||
279 | struct GNUNET_SOCIAL_TalkRequest | ||
280 | { | ||
281 | |||
282 | }; | ||
283 | |||
284 | |||
285 | /** | ||
286 | * A history lesson. | ||
287 | */ | ||
288 | struct GNUNET_SOCIAL_HistoryRequest | ||
289 | { | ||
290 | /** | ||
291 | * Place. | ||
292 | */ | ||
293 | struct GNUNET_SOCIAL_Place *plc; | ||
294 | |||
295 | /** | ||
296 | * Operation ID. | ||
297 | */ | ||
298 | uint64_t op_id; | ||
299 | |||
300 | /** | ||
301 | * Slicer for processing incoming messages. | ||
302 | */ | ||
303 | struct GNUNET_PSYC_Slicer *slicer; | ||
304 | |||
305 | /** | ||
306 | * Function to call when the operation finished. | ||
307 | */ | ||
308 | GNUNET_ResultCallback result_cb; | ||
309 | |||
310 | /** | ||
311 | * Closure for @a result_cb. | ||
312 | */ | ||
313 | void *cls; | ||
314 | }; | ||
315 | |||
316 | |||
317 | struct GNUNET_SOCIAL_LookHandle | ||
318 | { | ||
319 | /** | ||
320 | * Place. | ||
321 | */ | ||
322 | struct GNUNET_SOCIAL_Place *plc; | ||
323 | |||
324 | /** | ||
325 | * Operation ID. | ||
326 | */ | ||
327 | uint64_t op_id; | ||
328 | |||
329 | /** | ||
330 | * State variable result callback. | ||
331 | */ | ||
332 | GNUNET_PSYC_StateVarCallback var_cb; | ||
333 | |||
334 | /** | ||
335 | * Function to call when the operation finished. | ||
336 | */ | ||
337 | GNUNET_ResultCallback result_cb; | ||
338 | |||
339 | /** | ||
340 | * Name of current modifier being received. | ||
341 | */ | ||
342 | char *mod_name; | ||
343 | |||
344 | /** | ||
345 | * Size of current modifier value being received. | ||
346 | */ | ||
347 | size_t mod_value_size; | ||
348 | |||
349 | /** | ||
350 | * Remaining size of current modifier value still to be received. | ||
351 | */ | ||
352 | size_t mod_value_remaining; | ||
353 | |||
354 | /** | ||
355 | * Closure for @a result_cb. | ||
356 | */ | ||
357 | void *cls; | ||
358 | }; | ||
359 | |||
360 | |||
361 | struct ZoneAddPlaceHandle | ||
362 | { | ||
363 | GNUNET_ResultCallback result_cb; | ||
364 | void *result_cls; | ||
365 | }; | ||
366 | |||
367 | |||
368 | struct ZoneAddNymHandle | ||
369 | { | ||
370 | GNUNET_ResultCallback result_cb; | ||
371 | void *result_cls; | ||
372 | }; | ||
373 | |||
374 | |||
375 | /*** CLEANUP / DISCONNECT ***/ | ||
376 | |||
377 | |||
378 | static void | ||
379 | host_cleanup (struct GNUNET_SOCIAL_Host *hst) | ||
380 | { | ||
381 | if (NULL != hst->slicer) | ||
382 | { | ||
383 | GNUNET_PSYC_slicer_destroy (hst->slicer); | ||
384 | hst->slicer = NULL; | ||
385 | } | ||
386 | GNUNET_free (hst); | ||
387 | } | ||
388 | |||
389 | |||
390 | static void | ||
391 | guest_cleanup (struct GNUNET_SOCIAL_Guest *gst) | ||
392 | { | ||
393 | GNUNET_free (gst); | ||
394 | } | ||
395 | |||
396 | |||
397 | static void | ||
398 | place_cleanup (struct GNUNET_SOCIAL_Place *plc) | ||
399 | { | ||
400 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
401 | "cleaning up place %p\n", | ||
402 | plc); | ||
403 | if (NULL != plc->tmit) | ||
404 | { | ||
405 | GNUNET_PSYC_transmit_destroy (plc->tmit); | ||
406 | plc->tmit = NULL; | ||
407 | } | ||
408 | if (NULL != plc->connect_env) | ||
409 | { | ||
410 | GNUNET_MQ_discard (plc->connect_env); | ||
411 | plc->connect_env = NULL; | ||
412 | } | ||
413 | if (NULL != plc->mq) | ||
414 | { | ||
415 | GNUNET_MQ_destroy (plc->mq); | ||
416 | plc->mq = NULL; | ||
417 | } | ||
418 | if (NULL != plc->disconnect_cb) | ||
419 | { | ||
420 | plc->disconnect_cb (plc->disconnect_cls); | ||
421 | plc->disconnect_cb = NULL; | ||
422 | } | ||
423 | |||
424 | (GNUNET_YES == plc->is_host) | ||
425 | ? host_cleanup ((struct GNUNET_SOCIAL_Host *) plc) | ||
426 | : guest_cleanup ((struct GNUNET_SOCIAL_Guest *) plc); | ||
427 | } | ||
428 | |||
429 | |||
430 | static void | ||
431 | place_disconnect (struct GNUNET_SOCIAL_Place *plc) | ||
432 | { | ||
433 | place_cleanup (plc); | ||
434 | } | ||
435 | |||
436 | |||
437 | /*** NYM ***/ | ||
438 | |||
439 | static struct GNUNET_SOCIAL_Nym * | ||
440 | nym_get_or_create (const struct GNUNET_CRYPTO_EcdsaPublicKey *pub_key) | ||
441 | { | ||
442 | struct GNUNET_SOCIAL_Nym *nym = NULL; | ||
443 | struct GNUNET_HashCode pub_key_hash; | ||
444 | |||
445 | if (NULL == pub_key) | ||
446 | return NULL; | ||
447 | |||
448 | GNUNET_CRYPTO_hash (pub_key, sizeof (*pub_key), &pub_key_hash); | ||
449 | |||
450 | if (NULL == nyms) | ||
451 | nyms = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_YES); | ||
452 | else | ||
453 | nym = GNUNET_CONTAINER_multihashmap_get (nyms, &pub_key_hash); | ||
454 | |||
455 | if (NULL == nym) | ||
456 | { | ||
457 | nym = GNUNET_new (struct GNUNET_SOCIAL_Nym); | ||
458 | nym->pub_key = *pub_key; | ||
459 | nym->pub_key_hash = pub_key_hash; | ||
460 | GNUNET_CONTAINER_multihashmap_put (nyms, &nym->pub_key_hash, nym, | ||
461 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST); | ||
462 | } | ||
463 | return nym; | ||
464 | } | ||
465 | |||
466 | |||
467 | static void | ||
468 | nym_destroy (struct GNUNET_SOCIAL_Nym *nym) | ||
469 | { | ||
470 | GNUNET_CONTAINER_multihashmap_remove (nyms, &nym->pub_key_hash, nym); | ||
471 | GNUNET_free (nym); | ||
472 | } | ||
473 | |||
474 | |||
475 | /*** MESSAGE HANDLERS ***/ | ||
476 | |||
477 | /** _notice_place_leave from guests */ | ||
478 | |||
479 | static void | ||
480 | host_recv_notice_place_leave_method (void *cls, | ||
481 | const struct GNUNET_PSYC_MessageHeader *msg, | ||
482 | const struct GNUNET_PSYC_MessageMethod *meth, | ||
483 | uint64_t message_id, | ||
484 | const char *method_name) | ||
485 | { | ||
486 | struct GNUNET_SOCIAL_Host *hst = cls; | ||
487 | |||
488 | if (0 == memcmp (&(struct GNUNET_CRYPTO_EcdsaPublicKey) {}, | ||
489 | &msg->slave_pub_key, sizeof (msg->slave_pub_key))) | ||
490 | return; | ||
491 | |||
492 | struct GNUNET_SOCIAL_Nym *nym = nym_get_or_create (&msg->slave_pub_key); | ||
493 | |||
494 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
495 | "Host received method for message ID %" PRIu64 " from nym %s: %s\n", | ||
496 | message_id, GNUNET_h2s (&nym->pub_key_hash), method_name); | ||
497 | |||
498 | hst->notice_place_leave_nym = (struct GNUNET_SOCIAL_Nym *) nym; | ||
499 | hst->notice_place_leave_env = GNUNET_PSYC_env_create (); | ||
500 | |||
501 | char *str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&hst->notice_place_leave_nym->pub_key); | ||
502 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
503 | "_notice_place_leave: got method from nym %s (%s).\n", | ||
504 | GNUNET_h2s (&hst->notice_place_leave_nym->pub_key_hash), str); | ||
505 | GNUNET_free (str); | ||
506 | } | ||
507 | |||
508 | |||
509 | static void | ||
510 | host_recv_notice_place_leave_modifier (void *cls, | ||
511 | const struct GNUNET_PSYC_MessageHeader *msg, | ||
512 | const struct GNUNET_MessageHeader *pmsg, | ||
513 | uint64_t message_id, | ||
514 | enum GNUNET_PSYC_Operator oper, | ||
515 | const char *name, | ||
516 | const void *value, | ||
517 | uint16_t value_size, | ||
518 | uint16_t full_value_size) | ||
519 | { | ||
520 | struct GNUNET_SOCIAL_Host *hst = cls; | ||
521 | if (NULL == hst->notice_place_leave_env) | ||
522 | return; | ||
523 | |||
524 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
525 | "Host received modifier for _notice_place_leave message with ID %" PRIu64 ":\n" | ||
526 | "%c%s: %.*s\n", | ||
527 | message_id, oper, name, value_size, (const char *) value); | ||
528 | |||
529 | /* skip _nym, it's added later in eom() */ | ||
530 | if (0 == memcmp (name, "_nym", sizeof ("_nym")) | ||
531 | || 0 == memcmp (name, "_nym_", sizeof ("_nym_") - 1)) | ||
532 | return; | ||
533 | |||
534 | GNUNET_PSYC_env_add (hst->notice_place_leave_env, | ||
535 | GNUNET_PSYC_OP_SET, name, value, value_size); | ||
536 | } | ||
537 | |||
538 | |||
539 | static void | ||
540 | host_recv_notice_place_leave_eom (void *cls, | ||
541 | const struct GNUNET_PSYC_MessageHeader *msg, | ||
542 | const struct GNUNET_MessageHeader *pmsg, | ||
543 | uint64_t message_id, | ||
544 | uint8_t is_cancelled) | ||
545 | { | ||
546 | struct GNUNET_SOCIAL_Host *hst = cls; | ||
547 | if (NULL == hst->notice_place_leave_env) | ||
548 | return; | ||
549 | |||
550 | char *str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&hst->notice_place_leave_nym->pub_key); | ||
551 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
552 | "_notice_place_leave: got EOM from nym %s (%s).\n", | ||
553 | GNUNET_h2s (&hst->notice_place_leave_nym->pub_key_hash), str); | ||
554 | GNUNET_free (str); | ||
555 | |||
556 | if (GNUNET_YES != is_cancelled) | ||
557 | { | ||
558 | if (NULL != hst->farewell_cb) | ||
559 | hst->farewell_cb (hst->cb_cls, hst->notice_place_leave_nym, | ||
560 | hst->notice_place_leave_env); | ||
561 | /* announce leaving guest to place */ | ||
562 | GNUNET_PSYC_env_add (hst->notice_place_leave_env, GNUNET_PSYC_OP_SET, | ||
563 | "_nym", hst->notice_place_leave_nym, | ||
564 | sizeof (*hst->notice_place_leave_nym)); | ||
565 | GNUNET_SOCIAL_host_announce (hst, "_notice_place_leave", | ||
566 | hst->notice_place_leave_env, | ||
567 | NULL, NULL, GNUNET_SOCIAL_ANNOUNCE_NONE); | ||
568 | nym_destroy (hst->notice_place_leave_nym); | ||
569 | } | ||
570 | GNUNET_PSYC_env_destroy (hst->notice_place_leave_env); | ||
571 | hst->notice_place_leave_env = NULL; | ||
572 | } | ||
573 | |||
574 | |||
575 | /*** PLACE ***/ | ||
576 | |||
577 | |||
578 | static int | ||
579 | check_place_result (void *cls, | ||
580 | const struct GNUNET_OperationResultMessage *res) | ||
581 | { | ||
582 | uint16_t size = ntohs (res->header.size); | ||
583 | if (size < sizeof (*res)) | ||
584 | { /* Error, message too small. */ | ||
585 | GNUNET_break (0); | ||
586 | return GNUNET_SYSERR; | ||
587 | } | ||
588 | return GNUNET_OK; | ||
589 | } | ||
590 | |||
591 | |||
592 | static void | ||
593 | handle_place_result (void *cls, | ||
594 | const struct GNUNET_OperationResultMessage *res) | ||
595 | { | ||
596 | struct GNUNET_SOCIAL_Place *plc = cls; | ||
597 | |||
598 | uint16_t size = ntohs (res->header.size); | ||
599 | uint16_t data_size = size - sizeof (*res); | ||
600 | const char *data = (0 < data_size) ? (const char *) &res[1] : NULL; | ||
601 | |||
602 | GNUNET_OP_result (plc->op, GNUNET_ntohll (res->op_id), | ||
603 | GNUNET_ntohll (res->result_code), | ||
604 | data, data_size, NULL); | ||
605 | } | ||
606 | |||
607 | |||
608 | static int | ||
609 | check_app_result (void *cls, | ||
610 | const struct GNUNET_OperationResultMessage *res) | ||
611 | { | ||
612 | uint16_t size = ntohs (res->header.size); | ||
613 | if (size < sizeof (*res)) | ||
614 | { /* Error, message too small. */ | ||
615 | GNUNET_break (0); | ||
616 | return GNUNET_SYSERR; | ||
617 | } | ||
618 | return GNUNET_OK; | ||
619 | } | ||
620 | |||
621 | |||
622 | static void | ||
623 | handle_app_result (void *cls, | ||
624 | const struct GNUNET_OperationResultMessage *res) | ||
625 | { | ||
626 | struct GNUNET_SOCIAL_App *app = cls; | ||
627 | |||
628 | uint16_t size = ntohs (res->header.size); | ||
629 | uint16_t data_size = size - sizeof (*res); | ||
630 | const char *data = (0 < data_size) ? (const char *) &res[1] : NULL; | ||
631 | |||
632 | GNUNET_OP_result (app->op, GNUNET_ntohll (res->op_id), | ||
633 | GNUNET_ntohll (res->result_code), | ||
634 | data, data_size, NULL); | ||
635 | } | ||
636 | |||
637 | |||
638 | static void | ||
639 | op_recv_history_result (void *cls, int64_t result, | ||
640 | const void *err_msg, uint16_t err_msg_size) | ||
641 | { | ||
642 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
643 | "Received history replay result: %" PRId64 ".\n", result); | ||
644 | |||
645 | struct GNUNET_SOCIAL_HistoryRequest *hist = cls; | ||
646 | |||
647 | if (NULL != hist->result_cb) | ||
648 | hist->result_cb (hist->cls, result, err_msg, err_msg_size); | ||
649 | |||
650 | GNUNET_free (hist); | ||
651 | } | ||
652 | |||
653 | |||
654 | static void | ||
655 | op_recv_state_result (void *cls, int64_t result, | ||
656 | const void *err_msg, uint16_t err_msg_size) | ||
657 | { | ||
658 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
659 | "Received state request result: %" PRId64 ".\n", result); | ||
660 | |||
661 | struct GNUNET_SOCIAL_LookHandle *look = cls; | ||
662 | |||
663 | if (NULL != look->result_cb) | ||
664 | look->result_cb (look->cls, result, err_msg, err_msg_size); | ||
665 | |||
666 | GNUNET_free (look); | ||
667 | } | ||
668 | |||
669 | |||
670 | static int | ||
671 | check_place_history_result (void *cls, | ||
672 | const struct GNUNET_OperationResultMessage *res) | ||
673 | { | ||
674 | struct GNUNET_PSYC_MessageHeader * | ||
675 | pmsg = (struct GNUNET_PSYC_MessageHeader *) GNUNET_MQ_extract_nested_mh (res); | ||
676 | uint16_t size = ntohs (res->header.size); | ||
677 | |||
678 | if (NULL == pmsg || size < sizeof (*res) + sizeof (*pmsg)) | ||
679 | { /* Error, message too small. */ | ||
680 | GNUNET_break (0); | ||
681 | return GNUNET_SYSERR; | ||
682 | } | ||
683 | return GNUNET_OK; | ||
684 | } | ||
685 | |||
686 | |||
687 | static void | ||
688 | handle_place_history_result (void *cls, | ||
689 | const struct GNUNET_OperationResultMessage *res) | ||
690 | { | ||
691 | struct GNUNET_SOCIAL_Place *plc = cls; | ||
692 | struct GNUNET_PSYC_MessageHeader * | ||
693 | pmsg = (struct GNUNET_PSYC_MessageHeader *) GNUNET_MQ_extract_nested_mh (res); | ||
694 | |||
695 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
696 | "%p Received historic fragment for message #%" PRIu64 ".\n", | ||
697 | plc, GNUNET_ntohll (pmsg->message_id)); | ||
698 | |||
699 | GNUNET_ResultCallback result_cb = NULL; | ||
700 | struct GNUNET_SOCIAL_HistoryRequest *hist = NULL; | ||
701 | |||
702 | if (GNUNET_YES != GNUNET_OP_get (plc->op, | ||
703 | GNUNET_ntohll (res->op_id), | ||
704 | &result_cb, (void *) &hist, NULL)) | ||
705 | { /* Operation not found. */ | ||
706 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
707 | "%p Replay operation not found for historic fragment of message #%" | ||
708 | PRIu64 ".\n", | ||
709 | plc, GNUNET_ntohll (pmsg->message_id)); | ||
710 | return; | ||
711 | } | ||
712 | |||
713 | GNUNET_PSYC_slicer_message (hist->slicer, | ||
714 | (const struct GNUNET_PSYC_MessageHeader *) pmsg); | ||
715 | } | ||
716 | |||
717 | |||
718 | static int | ||
719 | check_place_state_result (void *cls, | ||
720 | const struct GNUNET_OperationResultMessage *res) | ||
721 | { | ||
722 | const struct GNUNET_MessageHeader *mod = GNUNET_MQ_extract_nested_mh (res); | ||
723 | if (NULL == mod) | ||
724 | { | ||
725 | GNUNET_break_op (0); | ||
726 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
727 | "Invalid modifier in state result\n"); | ||
728 | return GNUNET_SYSERR; | ||
729 | } | ||
730 | |||
731 | uint16_t size = ntohs (res->header.size); | ||
732 | uint16_t mod_size = ntohs (mod->size); | ||
733 | if (size - sizeof (*res) != mod_size) | ||
734 | { | ||
735 | GNUNET_break_op (0); | ||
736 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
737 | "Invalid modifier size in state result: %u - %u != %u\n", | ||
738 | ntohs (res->header.size), sizeof (*res), mod_size); | ||
739 | return GNUNET_SYSERR; | ||
740 | } | ||
741 | return GNUNET_OK; | ||
742 | } | ||
743 | |||
744 | |||
745 | static void | ||
746 | handle_place_state_result (void *cls, | ||
747 | const struct GNUNET_OperationResultMessage *res) | ||
748 | { | ||
749 | struct GNUNET_SOCIAL_Place *plc = cls; | ||
750 | |||
751 | GNUNET_ResultCallback result_cb = NULL; | ||
752 | struct GNUNET_SOCIAL_LookHandle *look = NULL; | ||
753 | |||
754 | if (GNUNET_YES != GNUNET_OP_get (plc->op, | ||
755 | GNUNET_ntohll (res->op_id), | ||
756 | &result_cb, (void *) &look, NULL)) | ||
757 | { /* Operation not found. */ | ||
758 | return; | ||
759 | } | ||
760 | |||
761 | const struct GNUNET_MessageHeader *mod = GNUNET_MQ_extract_nested_mh (res); | ||
762 | uint16_t mod_size = ntohs (mod->size); | ||
763 | |||
764 | switch (ntohs (mod->type)) | ||
765 | { | ||
766 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MODIFIER: | ||
767 | { | ||
768 | const struct GNUNET_PSYC_MessageModifier * | ||
769 | pmod = (const struct GNUNET_PSYC_MessageModifier *) mod; | ||
770 | |||
771 | const char *name = (const char *) &pmod[1]; | ||
772 | uint16_t name_size = ntohs (pmod->name_size); | ||
773 | if (0 == name_size | ||
774 | || mod_size - sizeof (*pmod) < name_size | ||
775 | || '\0' != name[name_size - 1]) | ||
776 | { | ||
777 | GNUNET_break_op (0); | ||
778 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
779 | "Invalid modifier name in state result\n"); | ||
780 | return; | ||
781 | } | ||
782 | look->mod_value_size = ntohs (pmod->value_size); | ||
783 | look->var_cb (look->cls, mod, name, name + name_size, | ||
784 | mod_size - sizeof (*mod) - name_size, | ||
785 | look->mod_value_size); | ||
786 | if (look->mod_value_size > mod_size - sizeof (*mod) - name_size) | ||
787 | { | ||
788 | look->mod_value_remaining = look->mod_value_size; | ||
789 | look->mod_name = GNUNET_malloc (name_size); | ||
790 | GNUNET_memcpy (look->mod_name, name, name_size); | ||
791 | } | ||
792 | break; | ||
793 | } | ||
794 | |||
795 | case GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_MOD_CONT: | ||
796 | look->var_cb (look->cls, mod, look->mod_name, (const char *) &mod[1], | ||
797 | mod_size - sizeof (*mod), look->mod_value_size); | ||
798 | look->mod_value_remaining -= mod_size - sizeof (*mod); | ||
799 | if (0 == look->mod_value_remaining) | ||
800 | { | ||
801 | GNUNET_free (look->mod_name); | ||
802 | } | ||
803 | break; | ||
804 | } | ||
805 | } | ||
806 | |||
807 | |||
808 | static void | ||
809 | handle_place_message_ack (void *cls, | ||
810 | const struct GNUNET_MessageHeader *msg) | ||
811 | { | ||
812 | struct GNUNET_SOCIAL_Place *plc = cls; | ||
813 | |||
814 | GNUNET_PSYC_transmit_got_ack (plc->tmit); | ||
815 | } | ||
816 | |||
817 | |||
818 | static int | ||
819 | check_place_message (void *cls, | ||
820 | const struct GNUNET_PSYC_MessageHeader *pmsg) | ||
821 | { | ||
822 | return GNUNET_OK; | ||
823 | } | ||
824 | |||
825 | |||
826 | static void | ||
827 | handle_place_message (void *cls, | ||
828 | const struct GNUNET_PSYC_MessageHeader *pmsg) | ||
829 | { | ||
830 | struct GNUNET_SOCIAL_Place *plc = cls; | ||
831 | |||
832 | GNUNET_PSYC_slicer_message (plc->slicer, pmsg); | ||
833 | } | ||
834 | |||
835 | |||
836 | static int | ||
837 | check_host_message (void *cls, | ||
838 | const struct GNUNET_PSYC_MessageHeader *pmsg) | ||
839 | { | ||
840 | return GNUNET_OK; | ||
841 | } | ||
842 | |||
843 | |||
844 | static void | ||
845 | handle_host_message (void *cls, | ||
846 | const struct GNUNET_PSYC_MessageHeader *pmsg) | ||
847 | { | ||
848 | struct GNUNET_SOCIAL_Host *hst = cls; | ||
849 | |||
850 | GNUNET_PSYC_slicer_message (hst->slicer, pmsg); | ||
851 | GNUNET_PSYC_slicer_message (hst->plc.slicer, pmsg); | ||
852 | } | ||
853 | |||
854 | |||
855 | static void | ||
856 | handle_host_enter_ack (void *cls, | ||
857 | const struct HostEnterAck *hack) | ||
858 | { | ||
859 | struct GNUNET_SOCIAL_Host *hst = cls; | ||
860 | |||
861 | hst->plc.pub_key = hack->place_pub_key; | ||
862 | |||
863 | int32_t result = ntohl (hack->result_code); | ||
864 | if (NULL != hst->enter_cb) | ||
865 | hst->enter_cb (hst->cb_cls, result, &hack->place_pub_key, | ||
866 | GNUNET_ntohll (hack->max_message_id)); | ||
867 | } | ||
868 | |||
869 | |||
870 | static int | ||
871 | check_host_enter_request (void *cls, | ||
872 | const struct GNUNET_PSYC_JoinRequestMessage *req) | ||
873 | { | ||
874 | return GNUNET_OK; | ||
875 | } | ||
876 | |||
877 | |||
878 | static void | ||
879 | handle_host_enter_request (void *cls, | ||
880 | const struct GNUNET_PSYC_JoinRequestMessage *req) | ||
881 | { | ||
882 | struct GNUNET_SOCIAL_Host *hst = cls; | ||
883 | |||
884 | if (NULL == hst->answer_door_cb) | ||
885 | return; | ||
886 | |||
887 | const char *method_name = NULL; | ||
888 | struct GNUNET_PSYC_Environment *env = NULL; | ||
889 | struct GNUNET_PSYC_MessageHeader *entry_pmsg = NULL; | ||
890 | const void *data = NULL; | ||
891 | uint16_t data_size = 0; | ||
892 | char *str; | ||
893 | const struct GNUNET_PSYC_Message *join_msg = NULL; | ||
894 | |||
895 | do | ||
896 | { | ||
897 | if (sizeof (*req) + sizeof (*join_msg) <= ntohs (req->header.size)) | ||
898 | { | ||
899 | join_msg = (struct GNUNET_PSYC_Message *) GNUNET_MQ_extract_nested_mh (req); | ||
900 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
901 | "Received join_msg of type %u and size %u.\n", | ||
902 | ntohs (join_msg->header.type), ntohs (join_msg->header.size)); | ||
903 | |||
904 | env = GNUNET_PSYC_env_create (); | ||
905 | entry_pmsg = GNUNET_PSYC_message_header_create_from_psyc (join_msg); | ||
906 | if (GNUNET_OK != GNUNET_PSYC_message_parse (entry_pmsg, &method_name, env, | ||
907 | &data, &data_size)) | ||
908 | { | ||
909 | GNUNET_break_op (0); | ||
910 | str = GNUNET_CRYPTO_ecdsa_public_key_to_string (&req->slave_pub_key); | ||
911 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
912 | "Ignoring invalid entry request from nym %s.\n", | ||
913 | str); | ||
914 | GNUNET_free (str); | ||
915 | break; | ||
916 | } | ||
917 | } | ||
918 | |||
919 | struct GNUNET_SOCIAL_Nym *nym = nym_get_or_create (&req->slave_pub_key); | ||
920 | hst->answer_door_cb (hst->cb_cls, nym, method_name, env, | ||
921 | data, data_size); | ||
922 | } while (0); | ||
923 | |||
924 | if (NULL != env) | ||
925 | GNUNET_PSYC_env_destroy (env); | ||
926 | if (NULL != entry_pmsg) | ||
927 | GNUNET_free (entry_pmsg); | ||
928 | } | ||
929 | |||
930 | |||
931 | static void | ||
932 | handle_guest_enter_ack (void *cls, | ||
933 | const struct GNUNET_PSYC_CountersResultMessage *cres) | ||
934 | { | ||
935 | struct GNUNET_SOCIAL_Guest *gst = cls; | ||
936 | |||
937 | int32_t result = ntohl (cres->result_code); | ||
938 | if (NULL != gst->enter_cb) | ||
939 | gst->enter_cb (gst->cb_cls, result, &gst->plc.pub_key, | ||
940 | GNUNET_ntohll (cres->max_message_id)); | ||
941 | } | ||
942 | |||
943 | |||
944 | static int | ||
945 | check_guest_enter_decision (void *cls, | ||
946 | const struct GNUNET_PSYC_JoinDecisionMessage *dcsn) | ||
947 | { | ||
948 | return GNUNET_OK; | ||
949 | } | ||
950 | |||
951 | |||
952 | static void | ||
953 | handle_guest_enter_decision (void *cls, | ||
954 | const struct GNUNET_PSYC_JoinDecisionMessage *dcsn) | ||
955 | { | ||
956 | struct GNUNET_SOCIAL_Guest *gst = cls; | ||
957 | |||
958 | struct GNUNET_PSYC_Message *pmsg = NULL; | ||
959 | if (ntohs (dcsn->header.size) > sizeof (*dcsn)) | ||
960 | pmsg = (struct GNUNET_PSYC_Message *) GNUNET_MQ_extract_nested_mh (dcsn); | ||
961 | |||
962 | if (NULL != gst->entry_dcsn_cb) | ||
963 | gst->entry_dcsn_cb (gst->cb_cls, ntohl (dcsn->is_admitted), pmsg); | ||
964 | } | ||
965 | |||
966 | |||
967 | static int | ||
968 | check_app_ego (void *cls, | ||
969 | const struct AppEgoMessage *emsg) | ||
970 | { | ||
971 | return GNUNET_OK; | ||
972 | } | ||
973 | |||
974 | |||
975 | static void | ||
976 | handle_app_ego (void *cls, | ||
977 | const struct AppEgoMessage *emsg) | ||
978 | { | ||
979 | struct GNUNET_SOCIAL_App *app = cls; | ||
980 | |||
981 | uint16_t name_size = ntohs (emsg->header.size) - sizeof (*emsg); | ||
982 | |||
983 | struct GNUNET_HashCode ego_pub_hash; | ||
984 | GNUNET_CRYPTO_hash (&emsg->ego_pub_key, sizeof (emsg->ego_pub_key), | ||
985 | &ego_pub_hash); | ||
986 | |||
987 | struct GNUNET_SOCIAL_Ego * | ||
988 | ego = GNUNET_CONTAINER_multihashmap_get (app->egos, &ego_pub_hash); | ||
989 | if (NULL == ego) | ||
990 | { | ||
991 | ego = GNUNET_malloc (sizeof (*ego)); | ||
992 | ego->pub_key = emsg->ego_pub_key; | ||
993 | ego->name = GNUNET_malloc (name_size); | ||
994 | GNUNET_memcpy (ego->name, &emsg[1], name_size); | ||
995 | } | ||
996 | else | ||
997 | { | ||
998 | ego->name = GNUNET_realloc (ego->name, name_size); | ||
999 | GNUNET_memcpy (ego->name, &emsg[1], name_size); | ||
1000 | } | ||
1001 | |||
1002 | GNUNET_CONTAINER_multihashmap_put (app->egos, &ego_pub_hash, ego, | ||
1003 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE); | ||
1004 | |||
1005 | if (NULL != app->ego_cb) | ||
1006 | app->ego_cb (app->cb_cls, ego, &ego->pub_key, ego->name); | ||
1007 | } | ||
1008 | |||
1009 | |||
1010 | static void | ||
1011 | handle_app_ego_end (void *cls, | ||
1012 | const struct GNUNET_MessageHeader *msg) | ||
1013 | { | ||
1014 | //struct GNUNET_SOCIAL_App *app = cls; | ||
1015 | } | ||
1016 | |||
1017 | |||
1018 | static int | ||
1019 | check_app_place (void *cls, | ||
1020 | const struct AppPlaceMessage *pmsg) | ||
1021 | { | ||
1022 | return GNUNET_OK; | ||
1023 | } | ||
1024 | |||
1025 | |||
1026 | static void | ||
1027 | handle_app_place (void *cls, | ||
1028 | const struct AppPlaceMessage *pmsg) | ||
1029 | { | ||
1030 | struct GNUNET_SOCIAL_App *app = cls; | ||
1031 | |||
1032 | if ((GNUNET_YES == pmsg->is_host && NULL == app->host_cb) | ||
1033 | || (GNUNET_NO == pmsg->is_host && NULL == app->guest_cb)) | ||
1034 | return; | ||
1035 | |||
1036 | struct GNUNET_HashCode ego_pub_hash; | ||
1037 | GNUNET_CRYPTO_hash (&pmsg->ego_pub_key, sizeof (pmsg->ego_pub_key), | ||
1038 | &ego_pub_hash); | ||
1039 | struct GNUNET_SOCIAL_Ego * | ||
1040 | ego = GNUNET_CONTAINER_multihashmap_get (app->egos, &ego_pub_hash); | ||
1041 | if (NULL == ego) | ||
1042 | { | ||
1043 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failure to obtain ego %s.\n", | ||
1044 | GNUNET_h2s (&ego_pub_hash)); | ||
1045 | GNUNET_break (0); | ||
1046 | return; | ||
1047 | } | ||
1048 | |||
1049 | if (GNUNET_YES == pmsg->is_host) | ||
1050 | { | ||
1051 | if (NULL != app->host_cb) { | ||
1052 | struct GNUNET_SOCIAL_HostConnection *hconn = GNUNET_malloc (sizeof (*hconn)); | ||
1053 | hconn->app = app; | ||
1054 | hconn->plc_msg = *pmsg; | ||
1055 | app->host_cb (app->cb_cls, hconn, ego, &pmsg->place_pub_key, pmsg->place_state); | ||
1056 | GNUNET_free (hconn); | ||
1057 | } | ||
1058 | } | ||
1059 | else if (NULL != app->guest_cb) | ||
1060 | { | ||
1061 | struct GNUNET_SOCIAL_GuestConnection *gconn = GNUNET_malloc (sizeof (*gconn)); | ||
1062 | gconn->app = app; | ||
1063 | gconn->plc_msg = *pmsg; | ||
1064 | app->guest_cb (app->cb_cls, gconn, ego, &pmsg->place_pub_key, pmsg->place_state); | ||
1065 | GNUNET_free (gconn); | ||
1066 | } | ||
1067 | } | ||
1068 | |||
1069 | |||
1070 | static void | ||
1071 | handle_app_place_end (void *cls, | ||
1072 | const struct GNUNET_MessageHeader *msg) | ||
1073 | { | ||
1074 | struct GNUNET_SOCIAL_App *app = cls; | ||
1075 | |||
1076 | if (NULL != app->connected_cb) | ||
1077 | app->connected_cb (app->cb_cls); | ||
1078 | } | ||
1079 | |||
1080 | |||
1081 | /** | ||
1082 | * Handler for a #GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LEAVE_ACK message received | ||
1083 | * from the social service. | ||
1084 | * | ||
1085 | * @param cls the place of type `struct GNUNET_SOCIAL_Place` | ||
1086 | * @param msg the message received from the service | ||
1087 | */ | ||
1088 | static void | ||
1089 | handle_place_leave_ack (void *cls, | ||
1090 | const struct GNUNET_MessageHeader *msg) | ||
1091 | { | ||
1092 | struct GNUNET_SOCIAL_Place *plc = cls; | ||
1093 | |||
1094 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1095 | "%s left place %p\n", | ||
1096 | plc->is_host ? "host" : "guest", | ||
1097 | plc); | ||
1098 | place_disconnect (plc); | ||
1099 | } | ||
1100 | |||
1101 | |||
1102 | /*** HOST ***/ | ||
1103 | |||
1104 | |||
1105 | static void | ||
1106 | host_connect (struct GNUNET_SOCIAL_Host *hst); | ||
1107 | |||
1108 | |||
1109 | static void | ||
1110 | host_reconnect (void *cls) | ||
1111 | { | ||
1112 | host_connect (cls); | ||
1113 | } | ||
1114 | |||
1115 | |||
1116 | /** | ||
1117 | * Host client disconnected from service. | ||
1118 | * | ||
1119 | * Reconnect after backoff period. | ||
1120 | */ | ||
1121 | static void | ||
1122 | host_disconnected (void *cls, enum GNUNET_MQ_Error error) | ||
1123 | { | ||
1124 | struct GNUNET_SOCIAL_Host *hst = cls; | ||
1125 | struct GNUNET_SOCIAL_Place *plc = &hst->plc; | ||
1126 | |||
1127 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1128 | "Host client disconnected (%d), re-connecting\n", | ||
1129 | (int) error); | ||
1130 | if (NULL != plc->tmit) | ||
1131 | { | ||
1132 | GNUNET_PSYC_transmit_destroy (plc->tmit); | ||
1133 | plc->tmit = NULL; | ||
1134 | } | ||
1135 | if (NULL != plc->mq) | ||
1136 | { | ||
1137 | GNUNET_MQ_destroy (plc->mq); | ||
1138 | plc->mq = NULL; | ||
1139 | } | ||
1140 | |||
1141 | plc->reconnect_task = GNUNET_SCHEDULER_add_delayed (plc->reconnect_delay, | ||
1142 | host_reconnect, | ||
1143 | hst); | ||
1144 | plc->reconnect_delay = GNUNET_TIME_STD_BACKOFF (plc->reconnect_delay); | ||
1145 | } | ||
1146 | |||
1147 | |||
1148 | static void | ||
1149 | host_connect (struct GNUNET_SOCIAL_Host *hst) | ||
1150 | { | ||
1151 | struct GNUNET_SOCIAL_Place *plc = &hst->plc; | ||
1152 | |||
1153 | struct GNUNET_MQ_MessageHandler handlers[] = { | ||
1154 | GNUNET_MQ_hd_fixed_size (host_enter_ack, | ||
1155 | GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER_ACK, | ||
1156 | struct HostEnterAck, | ||
1157 | hst), | ||
1158 | GNUNET_MQ_hd_fixed_size (place_leave_ack, | ||
1159 | GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LEAVE_ACK, | ||
1160 | struct GNUNET_MessageHeader, | ||
1161 | plc), | ||
1162 | GNUNET_MQ_hd_var_size (host_enter_request, | ||
1163 | GNUNET_MESSAGE_TYPE_PSYC_JOIN_REQUEST, | ||
1164 | struct GNUNET_PSYC_JoinRequestMessage, | ||
1165 | hst), | ||
1166 | GNUNET_MQ_hd_var_size (host_message, | ||
1167 | GNUNET_MESSAGE_TYPE_PSYC_MESSAGE, | ||
1168 | struct GNUNET_PSYC_MessageHeader, | ||
1169 | hst), | ||
1170 | GNUNET_MQ_hd_fixed_size (place_message_ack, | ||
1171 | GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_ACK, | ||
1172 | struct GNUNET_MessageHeader, | ||
1173 | plc), | ||
1174 | GNUNET_MQ_hd_var_size (place_history_result, | ||
1175 | GNUNET_MESSAGE_TYPE_PSYC_HISTORY_RESULT, | ||
1176 | struct GNUNET_OperationResultMessage, | ||
1177 | plc), | ||
1178 | GNUNET_MQ_hd_var_size (place_state_result, | ||
1179 | GNUNET_MESSAGE_TYPE_PSYC_STATE_RESULT, | ||
1180 | struct GNUNET_OperationResultMessage, | ||
1181 | plc), | ||
1182 | GNUNET_MQ_hd_var_size (place_result, | ||
1183 | GNUNET_MESSAGE_TYPE_PSYC_RESULT_CODE, | ||
1184 | struct GNUNET_OperationResultMessage, | ||
1185 | plc), | ||
1186 | GNUNET_MQ_handler_end () | ||
1187 | }; | ||
1188 | |||
1189 | plc->mq = GNUNET_CLIENT_connect (plc->cfg, "social", | ||
1190 | handlers, host_disconnected, hst); | ||
1191 | GNUNET_assert (NULL != plc->mq); | ||
1192 | plc->tmit = GNUNET_PSYC_transmit_create (plc->mq); | ||
1193 | |||
1194 | GNUNET_MQ_send_copy (plc->mq, plc->connect_env); | ||
1195 | } | ||
1196 | |||
1197 | |||
1198 | /** | ||
1199 | * Enter a place as host. | ||
1200 | * | ||
1201 | * A place is created upon first entering, and it is active until permanently | ||
1202 | * left using GNUNET_SOCIAL_host_leave(). | ||
1203 | * | ||
1204 | * @param app | ||
1205 | * Application handle. | ||
1206 | * @param ego | ||
1207 | * Identity of the host. | ||
1208 | * @param policy | ||
1209 | * Policy specifying entry and history restrictions for the place. | ||
1210 | * @param slicer | ||
1211 | * Slicer to handle incoming messages. | ||
1212 | * @param enter_cb | ||
1213 | * Function called when the place is entered and ready to use. | ||
1214 | * @param answer_door_cb | ||
1215 | * Function to handle new nyms that want to enter. | ||
1216 | * @param farewell_cb | ||
1217 | * Function to handle departing nyms. | ||
1218 | * @param cls | ||
1219 | * Closure for the callbacks. | ||
1220 | * | ||
1221 | * @return Handle for the host. This handle contains the pubkey. | ||
1222 | */ | ||
1223 | struct GNUNET_SOCIAL_Host * | ||
1224 | GNUNET_SOCIAL_host_enter (const struct GNUNET_SOCIAL_App *app, | ||
1225 | const struct GNUNET_SOCIAL_Ego *ego, | ||
1226 | enum GNUNET_PSYC_Policy policy, | ||
1227 | struct GNUNET_PSYC_Slicer *slicer, | ||
1228 | GNUNET_SOCIAL_HostEnterCallback enter_cb, | ||
1229 | GNUNET_SOCIAL_AnswerDoorCallback answer_door_cb, | ||
1230 | GNUNET_SOCIAL_FarewellCallback farewell_cb, | ||
1231 | void *cls) | ||
1232 | { | ||
1233 | struct GNUNET_SOCIAL_Host *hst = GNUNET_malloc (sizeof (*hst)); | ||
1234 | struct GNUNET_SOCIAL_Place *plc = &hst->plc; | ||
1235 | |||
1236 | plc->cfg = app->cfg; | ||
1237 | plc->is_host = GNUNET_YES; | ||
1238 | plc->slicer = slicer; | ||
1239 | |||
1240 | hst->enter_cb = enter_cb; | ||
1241 | hst->answer_door_cb = answer_door_cb; | ||
1242 | hst->farewell_cb = farewell_cb; | ||
1243 | hst->cb_cls = cls; | ||
1244 | |||
1245 | plc->op = GNUNET_OP_create (); | ||
1246 | |||
1247 | hst->slicer = GNUNET_PSYC_slicer_create (); | ||
1248 | GNUNET_PSYC_slicer_method_add (hst->slicer, "_notice_place_leave", NULL, | ||
1249 | host_recv_notice_place_leave_method, | ||
1250 | host_recv_notice_place_leave_modifier, | ||
1251 | NULL, host_recv_notice_place_leave_eom, hst); | ||
1252 | |||
1253 | uint16_t app_id_size = strlen (app->id) + 1; | ||
1254 | struct HostEnterRequest *hreq; | ||
1255 | plc->connect_env = GNUNET_MQ_msg_extra (hreq, app_id_size, | ||
1256 | GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER); | ||
1257 | hreq->policy = policy; | ||
1258 | hreq->ego_pub_key = ego->pub_key; | ||
1259 | GNUNET_memcpy (&hreq[1], app->id, app_id_size); | ||
1260 | |||
1261 | host_connect (hst); | ||
1262 | return hst; | ||
1263 | } | ||
1264 | |||
1265 | |||
1266 | /** | ||
1267 | * Reconnect to an already entered place as host. | ||
1268 | * | ||
1269 | * @param hconn | ||
1270 | * Host connection handle. | ||
1271 | * @see GNUNET_SOCIAL_app_connect() & GNUNET_SOCIAL_AppHostPlaceCallback() | ||
1272 | * @param slicer | ||
1273 | * Slicer to handle incoming messages. | ||
1274 | * @param enter_cb | ||
1275 | * Function called when the place is entered and ready to use. | ||
1276 | * @param answer_door_cb | ||
1277 | * Function to handle new nyms that want to enter. | ||
1278 | * @param farewell_cb | ||
1279 | * Function to handle departing nyms. | ||
1280 | * @param cls | ||
1281 | * Closure for the callbacks. | ||
1282 | * | ||
1283 | * @return Handle for the host. | ||
1284 | */ | ||
1285 | struct GNUNET_SOCIAL_Host * | ||
1286 | GNUNET_SOCIAL_host_enter_reconnect (struct GNUNET_SOCIAL_HostConnection *hconn, | ||
1287 | struct GNUNET_PSYC_Slicer *slicer, | ||
1288 | GNUNET_SOCIAL_HostEnterCallback enter_cb, | ||
1289 | GNUNET_SOCIAL_AnswerDoorCallback answer_door_cb, | ||
1290 | GNUNET_SOCIAL_FarewellCallback farewell_cb, | ||
1291 | void *cls) | ||
1292 | { | ||
1293 | struct GNUNET_SOCIAL_Host *hst = GNUNET_malloc (sizeof (*hst)); | ||
1294 | struct GNUNET_SOCIAL_Place *plc = &hst->plc; | ||
1295 | |||
1296 | hst->enter_cb = enter_cb; | ||
1297 | hst->answer_door_cb = answer_door_cb; | ||
1298 | hst->farewell_cb = farewell_cb; | ||
1299 | hst->cb_cls = cls; | ||
1300 | |||
1301 | plc->cfg = hconn->app->cfg; | ||
1302 | plc->is_host = GNUNET_YES; | ||
1303 | plc->slicer = slicer; | ||
1304 | plc->pub_key = hconn->plc_msg.place_pub_key; | ||
1305 | plc->ego_pub_key = hconn->plc_msg.ego_pub_key; | ||
1306 | |||
1307 | plc->op = GNUNET_OP_create (); | ||
1308 | |||
1309 | hst->slicer = GNUNET_PSYC_slicer_create (); | ||
1310 | GNUNET_PSYC_slicer_method_add (hst->slicer, "_notice_place_leave", NULL, | ||
1311 | host_recv_notice_place_leave_method, | ||
1312 | host_recv_notice_place_leave_modifier, | ||
1313 | NULL, host_recv_notice_place_leave_eom, hst); | ||
1314 | |||
1315 | size_t app_id_size = strlen (hconn->app->id) + 1; | ||
1316 | struct HostEnterRequest *hreq; | ||
1317 | plc->connect_env = GNUNET_MQ_msg_extra (hreq, app_id_size, | ||
1318 | GNUNET_MESSAGE_TYPE_SOCIAL_HOST_ENTER); | ||
1319 | hreq->place_pub_key = hconn->plc_msg.place_pub_key; | ||
1320 | hreq->ego_pub_key = hconn->plc_msg.ego_pub_key; | ||
1321 | GNUNET_memcpy (&hreq[1], hconn->app->id, app_id_size); | ||
1322 | |||
1323 | host_connect (hst); | ||
1324 | return hst; | ||
1325 | } | ||
1326 | |||
1327 | |||
1328 | /** | ||
1329 | * Decision whether to admit @a nym into the place or refuse entry. | ||
1330 | * | ||
1331 | * @param hst | ||
1332 | * Host of the place. | ||
1333 | * @param nym | ||
1334 | * Handle for the entity that wanted to enter. | ||
1335 | * @param is_admitted | ||
1336 | * #GNUNET_YES if @a nym is admitted, | ||
1337 | * #GNUNET_NO if @a nym is refused entry, | ||
1338 | * #GNUNET_SYSERR if we cannot answer the request. | ||
1339 | * @param method_name | ||
1340 | * Method name for the rejection message. | ||
1341 | * @param env | ||
1342 | * Environment containing variables for the message, or NULL. | ||
1343 | * @param data | ||
1344 | * Data for the rejection message to send back. | ||
1345 | * @param data_size | ||
1346 | * Number of bytes in @a data for method. | ||
1347 | * @return #GNUNET_OK on success, | ||
1348 | * #GNUNET_SYSERR if the message is too large. | ||
1349 | */ | ||
1350 | int | ||
1351 | GNUNET_SOCIAL_host_entry_decision (struct GNUNET_SOCIAL_Host *hst, | ||
1352 | struct GNUNET_SOCIAL_Nym *nym, | ||
1353 | int is_admitted, | ||
1354 | const struct GNUNET_PSYC_Message *entry_resp) | ||
1355 | { | ||
1356 | struct GNUNET_SOCIAL_Place *plc = &hst->plc; | ||
1357 | struct GNUNET_PSYC_JoinDecisionMessage *dcsn; | ||
1358 | uint16_t entry_resp_size | ||
1359 | = (NULL != entry_resp) ? ntohs (entry_resp->header.size) : 0; | ||
1360 | |||
1361 | if (GNUNET_MULTICAST_FRAGMENT_MAX_PAYLOAD < sizeof (*dcsn) + entry_resp_size) | ||
1362 | return GNUNET_SYSERR; | ||
1363 | |||
1364 | struct GNUNET_MQ_Envelope * | ||
1365 | env = GNUNET_MQ_msg_extra (dcsn, entry_resp_size, | ||
1366 | GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION); | ||
1367 | dcsn->is_admitted = htonl (is_admitted); | ||
1368 | dcsn->slave_pub_key = nym->pub_key; | ||
1369 | |||
1370 | if (0 < entry_resp_size) | ||
1371 | GNUNET_memcpy (&dcsn[1], entry_resp, entry_resp_size); | ||
1372 | |||
1373 | GNUNET_MQ_send (plc->mq, env); | ||
1374 | return GNUNET_OK; | ||
1375 | } | ||
1376 | |||
1377 | |||
1378 | /** | ||
1379 | * Throw @a nym out of the place. | ||
1380 | * | ||
1381 | * The @a nym reference will remain valid until the | ||
1382 | * #GNUNET_SOCIAL_FarewellCallback is invoked, | ||
1383 | * which should be very soon after this call. | ||
1384 | * | ||
1385 | * @param host | ||
1386 | * Host of the place. | ||
1387 | * @param nym | ||
1388 | * Handle for the entity to be ejected. | ||
1389 | * @param env | ||
1390 | * Environment for the message or NULL. | ||
1391 | */ | ||
1392 | void | ||
1393 | GNUNET_SOCIAL_host_eject (struct GNUNET_SOCIAL_Host *hst, | ||
1394 | const struct GNUNET_SOCIAL_Nym *nym, | ||
1395 | struct GNUNET_PSYC_Environment *e) | ||
1396 | { | ||
1397 | struct GNUNET_PSYC_Environment *env = e; | ||
1398 | if (NULL == env) | ||
1399 | env = GNUNET_PSYC_env_create (); | ||
1400 | GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_SET, | ||
1401 | "_nym", &nym->pub_key, sizeof (nym->pub_key)); | ||
1402 | GNUNET_SOCIAL_host_announce (hst, "_notice_place_leave", env, NULL, NULL, | ||
1403 | GNUNET_SOCIAL_ANNOUNCE_NONE); | ||
1404 | if (NULL == e) | ||
1405 | GNUNET_PSYC_env_destroy (env); | ||
1406 | } | ||
1407 | |||
1408 | |||
1409 | /** | ||
1410 | * Get the public key of @a ego. | ||
1411 | * | ||
1412 | * @param ego | ||
1413 | * Ego. | ||
1414 | * | ||
1415 | * @return Public key of ego. | ||
1416 | */ | ||
1417 | const struct GNUNET_CRYPTO_EcdsaPublicKey * | ||
1418 | GNUNET_SOCIAL_ego_get_pub_key (const struct GNUNET_SOCIAL_Ego *ego) | ||
1419 | { | ||
1420 | return &ego->pub_key; | ||
1421 | } | ||
1422 | |||
1423 | |||
1424 | /** | ||
1425 | * Get the hash of the public key of @a ego. | ||
1426 | * | ||
1427 | * @param ego | ||
1428 | * Ego. | ||
1429 | * | ||
1430 | * @return Hash of the public key of @a ego. | ||
1431 | */ | ||
1432 | const struct GNUNET_HashCode * | ||
1433 | GNUNET_SOCIAL_ego_get_pub_key_hash (const struct GNUNET_SOCIAL_Ego *ego) | ||
1434 | { | ||
1435 | return &ego->pub_key_hash; | ||
1436 | } | ||
1437 | |||
1438 | |||
1439 | /** | ||
1440 | * Get the name of @a ego. | ||
1441 | * | ||
1442 | * @param ego | ||
1443 | * Ego. | ||
1444 | * | ||
1445 | * @return Public key of @a ego. | ||
1446 | */ | ||
1447 | const char * | ||
1448 | GNUNET_SOCIAL_ego_get_name (const struct GNUNET_SOCIAL_Ego *ego) | ||
1449 | { | ||
1450 | return ego->name; | ||
1451 | } | ||
1452 | |||
1453 | |||
1454 | /** | ||
1455 | * Get the public key of @a nym. | ||
1456 | * | ||
1457 | * Suitable, for example, to be used with GNUNET_SOCIAL_zone_add_nym(). | ||
1458 | * | ||
1459 | * @param nym | ||
1460 | * Pseudonym. | ||
1461 | * | ||
1462 | * @return Public key of @a nym. | ||
1463 | */ | ||
1464 | const struct GNUNET_CRYPTO_EcdsaPublicKey * | ||
1465 | GNUNET_SOCIAL_nym_get_pub_key (const struct GNUNET_SOCIAL_Nym *nym) | ||
1466 | { | ||
1467 | return &nym->pub_key; | ||
1468 | } | ||
1469 | |||
1470 | |||
1471 | /** | ||
1472 | * Get the hash of the public key of @a nym. | ||
1473 | * | ||
1474 | * @param nym | ||
1475 | * Pseudonym. | ||
1476 | * | ||
1477 | * @return Hash of the public key of @a nym. | ||
1478 | */ | ||
1479 | const struct GNUNET_HashCode * | ||
1480 | GNUNET_SOCIAL_nym_get_pub_key_hash (const struct GNUNET_SOCIAL_Nym *nym) | ||
1481 | { | ||
1482 | return &nym->pub_key_hash; | ||
1483 | } | ||
1484 | |||
1485 | |||
1486 | /** | ||
1487 | * Send a message to all nyms that are present in the place. | ||
1488 | * | ||
1489 | * This function is restricted to the host. Nyms can only send requests | ||
1490 | * to the host who can decide to relay it to everyone in the place. | ||
1491 | * | ||
1492 | * @param host Host of the place. | ||
1493 | * @param method_name Method to use for the announcement. | ||
1494 | * @param env Environment containing variables for the message and operations | ||
1495 | * on objects of the place. Can be NULL. | ||
1496 | * @param notify Function to call to get the payload of the announcement. | ||
1497 | * @param notify_cls Closure for @a notify. | ||
1498 | * @param flags Flags for this announcement. | ||
1499 | * | ||
1500 | * @return NULL on error (announcement already in progress?). | ||
1501 | */ | ||
1502 | struct GNUNET_SOCIAL_Announcement * | ||
1503 | GNUNET_SOCIAL_host_announce (struct GNUNET_SOCIAL_Host *hst, | ||
1504 | const char *method_name, | ||
1505 | const struct GNUNET_PSYC_Environment *env, | ||
1506 | GNUNET_PSYC_TransmitNotifyData notify_data, | ||
1507 | void *notify_data_cls, | ||
1508 | enum GNUNET_SOCIAL_AnnounceFlags flags) | ||
1509 | { | ||
1510 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1511 | "PSYC_transmit_message for host, method: %s\n", | ||
1512 | method_name); | ||
1513 | if (GNUNET_OK == | ||
1514 | GNUNET_PSYC_transmit_message (hst->plc.tmit, method_name, env, | ||
1515 | NULL, notify_data, notify_data_cls, flags)) | ||
1516 | return (struct GNUNET_SOCIAL_Announcement *) hst->plc.tmit; | ||
1517 | else | ||
1518 | return NULL; | ||
1519 | } | ||
1520 | |||
1521 | |||
1522 | /** | ||
1523 | * Resume transmitting announcement. | ||
1524 | * | ||
1525 | * @param a | ||
1526 | * The announcement to resume. | ||
1527 | */ | ||
1528 | void | ||
1529 | GNUNET_SOCIAL_host_announce_resume (struct GNUNET_SOCIAL_Announcement *a) | ||
1530 | { | ||
1531 | GNUNET_PSYC_transmit_resume ((struct GNUNET_PSYC_TransmitHandle *) a); | ||
1532 | } | ||
1533 | |||
1534 | |||
1535 | /** | ||
1536 | * Cancel announcement. | ||
1537 | * | ||
1538 | * @param a | ||
1539 | * The announcement to cancel. | ||
1540 | */ | ||
1541 | void | ||
1542 | GNUNET_SOCIAL_host_announce_cancel (struct GNUNET_SOCIAL_Announcement *a) | ||
1543 | { | ||
1544 | GNUNET_PSYC_transmit_cancel ((struct GNUNET_PSYC_TransmitHandle *) a); | ||
1545 | } | ||
1546 | |||
1547 | |||
1548 | /** | ||
1549 | * Obtain handle for a hosted place. | ||
1550 | * | ||
1551 | * The returned handle can be used to access the place API. | ||
1552 | * | ||
1553 | * @param host Handle for the host. | ||
1554 | * | ||
1555 | * @return Handle for the hosted place, valid as long as @a host is valid. | ||
1556 | */ | ||
1557 | struct GNUNET_SOCIAL_Place * | ||
1558 | GNUNET_SOCIAL_host_get_place (struct GNUNET_SOCIAL_Host *hst) | ||
1559 | { | ||
1560 | return &hst->plc; | ||
1561 | } | ||
1562 | |||
1563 | |||
1564 | /** | ||
1565 | * Disconnect from a home. | ||
1566 | * | ||
1567 | * Invalidates host handle. | ||
1568 | * | ||
1569 | * @param hst | ||
1570 | * The host to disconnect. | ||
1571 | */ | ||
1572 | void | ||
1573 | GNUNET_SOCIAL_host_disconnect (struct GNUNET_SOCIAL_Host *hst, | ||
1574 | GNUNET_ContinuationCallback disconnect_cb, | ||
1575 | void *cls) | ||
1576 | { | ||
1577 | struct GNUNET_SOCIAL_Place *plc = &hst->plc; | ||
1578 | |||
1579 | plc->disconnect_cb = disconnect_cb; | ||
1580 | plc->disconnect_cls = cls; | ||
1581 | place_disconnect (plc); | ||
1582 | } | ||
1583 | |||
1584 | |||
1585 | /** | ||
1586 | * Stop hosting the home. | ||
1587 | * | ||
1588 | * Sends a _notice_place_closing announcement to the home. | ||
1589 | * Invalidates host handle. | ||
1590 | * | ||
1591 | * @param hst | ||
1592 | * The host leaving. | ||
1593 | * @param env | ||
1594 | * Environment for the message or NULL. | ||
1595 | * _nym is set to @e nym regardless whether an @e env is provided. | ||
1596 | * @param disconnect_cb | ||
1597 | * Function called after the host left the place | ||
1598 | * and disconnected from the social service. | ||
1599 | * @param cls | ||
1600 | * Closure for @a disconnect_cb. | ||
1601 | */ | ||
1602 | void | ||
1603 | GNUNET_SOCIAL_host_leave (struct GNUNET_SOCIAL_Host *hst, | ||
1604 | const struct GNUNET_PSYC_Environment *env, | ||
1605 | GNUNET_ContinuationCallback disconnect_cb, | ||
1606 | void *cls) | ||
1607 | { | ||
1608 | struct GNUNET_MQ_Envelope *envelope; | ||
1609 | |||
1610 | GNUNET_SOCIAL_host_announce (hst, "_notice_place_closing", env, NULL, NULL, | ||
1611 | GNUNET_SOCIAL_ANNOUNCE_NONE); | ||
1612 | hst->plc.disconnect_cb = disconnect_cb; | ||
1613 | hst->plc.disconnect_cls = cls; | ||
1614 | envelope = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LEAVE); | ||
1615 | GNUNET_MQ_send (hst->plc.mq, | ||
1616 | envelope); | ||
1617 | } | ||
1618 | |||
1619 | |||
1620 | /*** GUEST ***/ | ||
1621 | |||
1622 | |||
1623 | static void | ||
1624 | guest_connect (struct GNUNET_SOCIAL_Guest *gst); | ||
1625 | |||
1626 | |||
1627 | static void | ||
1628 | guest_reconnect (void *cls) | ||
1629 | { | ||
1630 | guest_connect (cls); | ||
1631 | } | ||
1632 | |||
1633 | |||
1634 | /** | ||
1635 | * Guest client disconnected from service. | ||
1636 | * | ||
1637 | * Reconnect after backoff period. | ||
1638 | */ | ||
1639 | static void | ||
1640 | guest_disconnected (void *cls, enum GNUNET_MQ_Error error) | ||
1641 | { | ||
1642 | struct GNUNET_SOCIAL_Guest *gst = cls; | ||
1643 | struct GNUNET_SOCIAL_Place *plc = &gst->plc; | ||
1644 | |||
1645 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1646 | "Guest client disconnected (%d), re-connecting\n", | ||
1647 | (int) error); | ||
1648 | if (NULL != plc->tmit) | ||
1649 | { | ||
1650 | GNUNET_PSYC_transmit_destroy (plc->tmit); | ||
1651 | plc->tmit = NULL; | ||
1652 | } | ||
1653 | if (NULL != plc->mq) | ||
1654 | { | ||
1655 | GNUNET_MQ_destroy (plc->mq); | ||
1656 | plc->mq = NULL; | ||
1657 | } | ||
1658 | |||
1659 | plc->reconnect_task = GNUNET_SCHEDULER_add_delayed (plc->reconnect_delay, | ||
1660 | guest_reconnect, | ||
1661 | gst); | ||
1662 | plc->reconnect_delay = GNUNET_TIME_STD_BACKOFF (plc->reconnect_delay); | ||
1663 | } | ||
1664 | |||
1665 | |||
1666 | static void | ||
1667 | guest_connect (struct GNUNET_SOCIAL_Guest *gst) | ||
1668 | { | ||
1669 | struct GNUNET_SOCIAL_Place *plc = &gst->plc; | ||
1670 | |||
1671 | struct GNUNET_MQ_MessageHandler handlers[] = { | ||
1672 | GNUNET_MQ_hd_fixed_size (guest_enter_ack, | ||
1673 | GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_ACK, | ||
1674 | struct GNUNET_PSYC_CountersResultMessage, | ||
1675 | gst), | ||
1676 | GNUNET_MQ_hd_fixed_size (place_leave_ack, | ||
1677 | GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LEAVE_ACK, | ||
1678 | struct GNUNET_MessageHeader, | ||
1679 | plc), | ||
1680 | GNUNET_MQ_hd_var_size (guest_enter_decision, | ||
1681 | GNUNET_MESSAGE_TYPE_PSYC_JOIN_DECISION, | ||
1682 | struct GNUNET_PSYC_JoinDecisionMessage, | ||
1683 | gst), | ||
1684 | GNUNET_MQ_hd_var_size (place_message, | ||
1685 | GNUNET_MESSAGE_TYPE_PSYC_MESSAGE, | ||
1686 | struct GNUNET_PSYC_MessageHeader, | ||
1687 | plc), | ||
1688 | GNUNET_MQ_hd_fixed_size (place_message_ack, | ||
1689 | GNUNET_MESSAGE_TYPE_PSYC_MESSAGE_ACK, | ||
1690 | struct GNUNET_MessageHeader, | ||
1691 | plc), | ||
1692 | GNUNET_MQ_hd_var_size (place_history_result, | ||
1693 | GNUNET_MESSAGE_TYPE_PSYC_HISTORY_RESULT, | ||
1694 | struct GNUNET_OperationResultMessage, | ||
1695 | plc), | ||
1696 | GNUNET_MQ_hd_var_size (place_state_result, | ||
1697 | GNUNET_MESSAGE_TYPE_PSYC_STATE_RESULT, | ||
1698 | struct GNUNET_OperationResultMessage, | ||
1699 | plc), | ||
1700 | GNUNET_MQ_hd_var_size (place_result, | ||
1701 | GNUNET_MESSAGE_TYPE_PSYC_RESULT_CODE, | ||
1702 | struct GNUNET_OperationResultMessage, | ||
1703 | plc), | ||
1704 | GNUNET_MQ_handler_end () | ||
1705 | }; | ||
1706 | |||
1707 | plc->mq = GNUNET_CLIENT_connect (plc->cfg, "social", | ||
1708 | handlers, guest_disconnected, gst); | ||
1709 | GNUNET_assert (NULL != plc->mq); | ||
1710 | plc->tmit = GNUNET_PSYC_transmit_create (plc->mq); | ||
1711 | |||
1712 | GNUNET_MQ_send_copy (plc->mq, plc->connect_env); | ||
1713 | } | ||
1714 | |||
1715 | |||
1716 | static struct GNUNET_MQ_Envelope * | ||
1717 | guest_enter_request_create (const char *app_id, | ||
1718 | const struct GNUNET_CRYPTO_EcdsaPublicKey *ego_pub_key, | ||
1719 | const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key, | ||
1720 | const struct GNUNET_PeerIdentity *origin, | ||
1721 | size_t relay_count, | ||
1722 | const struct GNUNET_PeerIdentity *relays, | ||
1723 | const struct GNUNET_PSYC_Message *join_msg) | ||
1724 | { | ||
1725 | uint16_t app_id_size = strlen (app_id) + 1; | ||
1726 | uint16_t join_msg_size = ntohs (join_msg->header.size); | ||
1727 | uint16_t relay_size = relay_count * sizeof (*relays); | ||
1728 | |||
1729 | struct GuestEnterRequest *greq; | ||
1730 | struct GNUNET_MQ_Envelope * | ||
1731 | env = GNUNET_MQ_msg_extra (greq, app_id_size + relay_size + join_msg_size, | ||
1732 | GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER); | ||
1733 | greq->place_pub_key = *place_pub_key; | ||
1734 | greq->ego_pub_key = *ego_pub_key; | ||
1735 | greq->origin = *origin; | ||
1736 | greq->relay_count = htonl (relay_count); | ||
1737 | |||
1738 | char *p = (char *) &greq[1]; | ||
1739 | GNUNET_memcpy (p, app_id, app_id_size); | ||
1740 | p += app_id_size; | ||
1741 | |||
1742 | if (0 < relay_size) | ||
1743 | { | ||
1744 | GNUNET_memcpy (p, relays, relay_size); | ||
1745 | p += relay_size; | ||
1746 | } | ||
1747 | |||
1748 | GNUNET_memcpy (p, join_msg, join_msg_size); | ||
1749 | return env; | ||
1750 | } | ||
1751 | |||
1752 | |||
1753 | /** | ||
1754 | * Request entry to a place as a guest. | ||
1755 | * | ||
1756 | * @param app | ||
1757 | * Application handle. | ||
1758 | * @param ego | ||
1759 | * Identity of the guest. | ||
1760 | * @param place_pub_key | ||
1761 | * Public key of the place to enter. | ||
1762 | * @param flags | ||
1763 | * Flags for the entry. | ||
1764 | * @param origin | ||
1765 | * Peer identity of the origin of the underlying multicast group. | ||
1766 | * @param relay_count | ||
1767 | * Number of elements in the @a relays array. | ||
1768 | * @param relays | ||
1769 | * Relays for the underlying multicast group. | ||
1770 | * @param method_name | ||
1771 | * Method name for the message. | ||
1772 | * @param env | ||
1773 | * Environment containing variables for the message, or NULL. | ||
1774 | * @param data | ||
1775 | * Payload for the message to give to the enter callback. | ||
1776 | * @param data_size | ||
1777 | * Number of bytes in @a data. | ||
1778 | * @param slicer | ||
1779 | * Slicer to use for processing incoming requests from guests. | ||
1780 | * | ||
1781 | * @return NULL on errors, otherwise handle for the guest. | ||
1782 | */ | ||
1783 | struct GNUNET_SOCIAL_Guest * | ||
1784 | GNUNET_SOCIAL_guest_enter (const struct GNUNET_SOCIAL_App *app, | ||
1785 | const struct GNUNET_SOCIAL_Ego *ego, | ||
1786 | const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key, | ||
1787 | enum GNUNET_PSYC_SlaveJoinFlags flags, | ||
1788 | const struct GNUNET_PeerIdentity *origin, | ||
1789 | uint32_t relay_count, | ||
1790 | const struct GNUNET_PeerIdentity *relays, | ||
1791 | const struct GNUNET_PSYC_Message *entry_msg, | ||
1792 | struct GNUNET_PSYC_Slicer *slicer, | ||
1793 | GNUNET_SOCIAL_GuestEnterCallback local_enter_cb, | ||
1794 | GNUNET_SOCIAL_EntryDecisionCallback entry_dcsn_cb, | ||
1795 | void *cls) | ||
1796 | { | ||
1797 | struct GNUNET_SOCIAL_Guest *gst = GNUNET_malloc (sizeof (*gst)); | ||
1798 | struct GNUNET_SOCIAL_Place *plc = &gst->plc; | ||
1799 | |||
1800 | plc->ego_pub_key = ego->pub_key; | ||
1801 | plc->pub_key = *place_pub_key; | ||
1802 | plc->cfg = app->cfg; | ||
1803 | plc->is_host = GNUNET_NO; | ||
1804 | plc->slicer = slicer; | ||
1805 | |||
1806 | plc->op = GNUNET_OP_create (); | ||
1807 | |||
1808 | plc->connect_env | ||
1809 | = guest_enter_request_create (app->id, &ego->pub_key, &plc->pub_key, | ||
1810 | origin, relay_count, relays, entry_msg); | ||
1811 | |||
1812 | gst->enter_cb = local_enter_cb; | ||
1813 | gst->entry_dcsn_cb = entry_dcsn_cb; | ||
1814 | gst->cb_cls = cls; | ||
1815 | |||
1816 | guest_connect (gst); | ||
1817 | return gst; | ||
1818 | } | ||
1819 | |||
1820 | |||
1821 | /** | ||
1822 | * Request entry to a place by name as a guest. | ||
1823 | * | ||
1824 | * @param app | ||
1825 | * Application handle. | ||
1826 | * @param ego | ||
1827 | * Identity of the guest. | ||
1828 | * @param gns_name | ||
1829 | * GNS name of the place to enter. Either in the form of | ||
1830 | * 'room.friend.gnu', or 'NYMPUBKEY.zkey'. This latter case refers to | ||
1831 | * the 'PLACE' record of the empty label ("+") in the GNS zone with the | ||
1832 | * nym's public key 'NYMPUBKEY', and can be used to request entry to a | ||
1833 | * pseudonym's place directly. | ||
1834 | * @param password | ||
1835 | * Password to decrypt the record, or NULL for cleartext records. | ||
1836 | * @param join_msg | ||
1837 | * Entry request message or NULL. | ||
1838 | * @param slicer | ||
1839 | * Slicer to use for processing incoming requests from guests. | ||
1840 | * @param local_enter_cb | ||
1841 | * Called upon connection established to the social service. | ||
1842 | * @param entry_decision_cb | ||
1843 | * Called upon receiving entry decision. | ||
1844 | * | ||
1845 | * @return NULL on errors, otherwise handle for the guest. | ||
1846 | */ | ||
1847 | struct GNUNET_SOCIAL_Guest * | ||
1848 | GNUNET_SOCIAL_guest_enter_by_name (const struct GNUNET_SOCIAL_App *app, | ||
1849 | const struct GNUNET_SOCIAL_Ego *ego, | ||
1850 | const char *gns_name, | ||
1851 | const char *password, | ||
1852 | const struct GNUNET_PSYC_Message *join_msg, | ||
1853 | struct GNUNET_PSYC_Slicer *slicer, | ||
1854 | GNUNET_SOCIAL_GuestEnterCallback local_enter_cb, | ||
1855 | GNUNET_SOCIAL_EntryDecisionCallback entry_decision_cb, | ||
1856 | void *cls) | ||
1857 | { | ||
1858 | struct GNUNET_SOCIAL_Guest *gst = GNUNET_malloc (sizeof (*gst)); | ||
1859 | struct GNUNET_SOCIAL_Place *plc = &gst->plc; | ||
1860 | |||
1861 | if (NULL == password) | ||
1862 | password = ""; | ||
1863 | |||
1864 | uint16_t app_id_size = strlen (app->id) + 1; | ||
1865 | uint16_t gns_name_size = strlen (gns_name) + 1; | ||
1866 | uint16_t password_size = strlen (password) + 1; | ||
1867 | |||
1868 | uint16_t join_msg_size = 0; | ||
1869 | if (NULL != join_msg) | ||
1870 | join_msg_size = ntohs (join_msg->header.size); | ||
1871 | |||
1872 | struct GuestEnterByNameRequest *greq; | ||
1873 | plc->connect_env | ||
1874 | = GNUNET_MQ_msg_extra (greq, app_id_size + gns_name_size | ||
1875 | + password_size + join_msg_size, | ||
1876 | GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER_BY_NAME); | ||
1877 | |||
1878 | greq->ego_pub_key = ego->pub_key; | ||
1879 | |||
1880 | char *p = (char *) &greq[1]; | ||
1881 | GNUNET_memcpy (p, app->id, app_id_size); | ||
1882 | p += app_id_size; | ||
1883 | GNUNET_memcpy (p, gns_name, gns_name_size); | ||
1884 | p += gns_name_size; | ||
1885 | GNUNET_memcpy (p, password, password_size); | ||
1886 | p += password_size; | ||
1887 | if (NULL != join_msg) | ||
1888 | GNUNET_memcpy (p, join_msg, join_msg_size); | ||
1889 | |||
1890 | plc->ego_pub_key = ego->pub_key; | ||
1891 | plc->cfg = app->cfg; | ||
1892 | plc->is_host = GNUNET_NO; | ||
1893 | plc->slicer = slicer; | ||
1894 | |||
1895 | plc->op = GNUNET_OP_create (); | ||
1896 | |||
1897 | gst->enter_cb = local_enter_cb; | ||
1898 | gst->entry_dcsn_cb = entry_decision_cb; | ||
1899 | gst->cb_cls = cls; | ||
1900 | |||
1901 | guest_connect (gst); | ||
1902 | return gst; | ||
1903 | } | ||
1904 | |||
1905 | |||
1906 | struct ReconnectContext | ||
1907 | { | ||
1908 | struct GNUNET_SOCIAL_Guest *guest; | ||
1909 | int *result; | ||
1910 | int64_t *max_message_id; | ||
1911 | GNUNET_SOCIAL_GuestEnterCallback enter_cb; | ||
1912 | void *enter_cls; | ||
1913 | }; | ||
1914 | |||
1915 | |||
1916 | static void | ||
1917 | guest_enter_reconnect_cb (void *cls, | ||
1918 | int result, | ||
1919 | const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key, | ||
1920 | uint64_t max_message_id) | ||
1921 | { | ||
1922 | struct ReconnectContext *reconnect_ctx = cls; | ||
1923 | |||
1924 | GNUNET_assert (NULL != reconnect_ctx); | ||
1925 | reconnect_ctx->result = GNUNET_new (int); | ||
1926 | *(reconnect_ctx->result) = result; | ||
1927 | reconnect_ctx->max_message_id = GNUNET_new (int64_t); | ||
1928 | *(reconnect_ctx->max_message_id) = max_message_id; | ||
1929 | } | ||
1930 | |||
1931 | |||
1932 | static void | ||
1933 | guest_entry_dcsn_reconnect_cb (void *cls, | ||
1934 | int is_admitted, | ||
1935 | const struct GNUNET_PSYC_Message *entry_resp) | ||
1936 | { | ||
1937 | struct ReconnectContext *reconnect_ctx = cls; | ||
1938 | struct GNUNET_SOCIAL_Guest *gst = reconnect_ctx->guest; | ||
1939 | |||
1940 | GNUNET_assert (NULL != reconnect_ctx); | ||
1941 | GNUNET_assert (NULL != reconnect_ctx->result); | ||
1942 | GNUNET_assert (NULL != reconnect_ctx->max_message_id); | ||
1943 | if (GNUNET_YES != is_admitted) | ||
1944 | { | ||
1945 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1946 | "Guest was rejected after calling " | ||
1947 | "GNUNET_SOCIAL_guest_enter_reconnect ()\n"); | ||
1948 | } | ||
1949 | else if (NULL != reconnect_ctx->enter_cb) | ||
1950 | { | ||
1951 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1952 | "guest reconnected!\n"); | ||
1953 | reconnect_ctx->enter_cb (reconnect_ctx->enter_cls, | ||
1954 | *(reconnect_ctx->result), | ||
1955 | &gst->plc.pub_key, | ||
1956 | *(reconnect_ctx->max_message_id)); | ||
1957 | } | ||
1958 | GNUNET_free (reconnect_ctx->result); | ||
1959 | GNUNET_free (reconnect_ctx->max_message_id); | ||
1960 | GNUNET_free (reconnect_ctx); | ||
1961 | } | ||
1962 | |||
1963 | |||
1964 | /** | ||
1965 | * Reconnect to an already entered place as guest. | ||
1966 | * | ||
1967 | * @param gconn | ||
1968 | * Guest connection handle. | ||
1969 | * @see GNUNET_SOCIAL_app_connect() & GNUNET_SOCIAL_AppGuestPlaceCallback() | ||
1970 | * @param flags | ||
1971 | * Flags for the entry. | ||
1972 | * @param slicer | ||
1973 | * Slicer to use for processing incoming requests from guests. | ||
1974 | * @param enter_cb | ||
1975 | * Called upon re-entering is complete. | ||
1976 | * @param entry_decision_cb | ||
1977 | * Called upon receiving entry decision. | ||
1978 | * | ||
1979 | * @return NULL on errors, otherwise handle for the guest. | ||
1980 | */ | ||
1981 | struct GNUNET_SOCIAL_Guest * | ||
1982 | GNUNET_SOCIAL_guest_enter_reconnect (struct GNUNET_SOCIAL_GuestConnection *gconn, | ||
1983 | enum GNUNET_PSYC_SlaveJoinFlags flags, | ||
1984 | struct GNUNET_PSYC_Slicer *slicer, | ||
1985 | GNUNET_SOCIAL_GuestEnterCallback enter_cb, | ||
1986 | void *cls) | ||
1987 | { | ||
1988 | struct GNUNET_SOCIAL_Guest *gst = GNUNET_malloc (sizeof (*gst)); | ||
1989 | struct GNUNET_SOCIAL_Place *plc = &gst->plc; | ||
1990 | struct ReconnectContext *reconnect_ctx; | ||
1991 | |||
1992 | uint16_t app_id_size = strlen (gconn->app->id) + 1; | ||
1993 | struct GuestEnterRequest *greq; | ||
1994 | plc->connect_env | ||
1995 | = GNUNET_MQ_msg_extra (greq, app_id_size, | ||
1996 | GNUNET_MESSAGE_TYPE_SOCIAL_GUEST_ENTER); | ||
1997 | greq->ego_pub_key = gconn->plc_msg.ego_pub_key; | ||
1998 | greq->place_pub_key = gconn->plc_msg.place_pub_key; | ||
1999 | greq->flags = htonl (flags); | ||
2000 | |||
2001 | GNUNET_memcpy (&greq[1], gconn->app->id, app_id_size); | ||
2002 | |||
2003 | plc->cfg = gconn->app->cfg; | ||
2004 | plc->is_host = GNUNET_NO; | ||
2005 | plc->slicer = slicer; | ||
2006 | plc->pub_key = gconn->plc_msg.place_pub_key; | ||
2007 | plc->ego_pub_key = gconn->plc_msg.ego_pub_key; | ||
2008 | |||
2009 | reconnect_ctx = GNUNET_new (struct ReconnectContext); | ||
2010 | reconnect_ctx->guest = gst; | ||
2011 | reconnect_ctx->enter_cb = enter_cb; | ||
2012 | reconnect_ctx->enter_cls = cls; | ||
2013 | |||
2014 | plc->op = GNUNET_OP_create (); | ||
2015 | gst->enter_cb = &guest_enter_reconnect_cb; | ||
2016 | gst->entry_dcsn_cb = &guest_entry_dcsn_reconnect_cb; | ||
2017 | gst->cb_cls = reconnect_ctx; | ||
2018 | |||
2019 | guest_connect (gst); | ||
2020 | return gst; | ||
2021 | } | ||
2022 | |||
2023 | |||
2024 | /** | ||
2025 | * Talk to the host of the place. | ||
2026 | * | ||
2027 | * @param place | ||
2028 | * Place where we want to talk to the host. | ||
2029 | * @param method_name | ||
2030 | * Method to invoke on the host. | ||
2031 | * @param env | ||
2032 | * Environment containing variables for the message, or NULL. | ||
2033 | * @param notify_data | ||
2034 | * Function to use to get the payload for the method. | ||
2035 | * @param notify_data_cls | ||
2036 | * Closure for @a notify_data. | ||
2037 | * @param flags | ||
2038 | * Flags for the message being sent. | ||
2039 | * | ||
2040 | * @return NULL if we are already trying to talk to the host, | ||
2041 | * otherwise handle to cancel the request. | ||
2042 | */ | ||
2043 | struct GNUNET_SOCIAL_TalkRequest * | ||
2044 | GNUNET_SOCIAL_guest_talk (struct GNUNET_SOCIAL_Guest *gst, | ||
2045 | const char *method_name, | ||
2046 | const struct GNUNET_PSYC_Environment *env, | ||
2047 | GNUNET_PSYC_TransmitNotifyData notify_data, | ||
2048 | void *notify_data_cls, | ||
2049 | enum GNUNET_SOCIAL_TalkFlags flags) | ||
2050 | { | ||
2051 | struct GNUNET_SOCIAL_Place *plc = &gst->plc; | ||
2052 | GNUNET_assert (NULL != plc->tmit); | ||
2053 | |||
2054 | if (GNUNET_OK == | ||
2055 | GNUNET_PSYC_transmit_message (plc->tmit, method_name, env, | ||
2056 | NULL, notify_data, notify_data_cls, flags)) | ||
2057 | return (struct GNUNET_SOCIAL_TalkRequest *) plc->tmit; | ||
2058 | else | ||
2059 | return NULL; | ||
2060 | } | ||
2061 | |||
2062 | |||
2063 | /** | ||
2064 | * Resume talking to the host of the place. | ||
2065 | * | ||
2066 | * @param tr | ||
2067 | * Talk request to resume. | ||
2068 | */ | ||
2069 | void | ||
2070 | GNUNET_SOCIAL_guest_talk_resume (struct GNUNET_SOCIAL_TalkRequest *tr) | ||
2071 | { | ||
2072 | GNUNET_PSYC_transmit_resume ((struct GNUNET_PSYC_TransmitHandle *) tr); | ||
2073 | } | ||
2074 | |||
2075 | |||
2076 | /** | ||
2077 | * Cancel talking to the host of the place. | ||
2078 | * | ||
2079 | * @param tr | ||
2080 | * Talk request to cancel. | ||
2081 | */ | ||
2082 | void | ||
2083 | GNUNET_SOCIAL_guest_talk_cancel (struct GNUNET_SOCIAL_TalkRequest *tr) | ||
2084 | { | ||
2085 | GNUNET_PSYC_transmit_cancel ( (struct GNUNET_PSYC_TransmitHandle *) tr); | ||
2086 | } | ||
2087 | |||
2088 | |||
2089 | /** | ||
2090 | * Disconnect from a place. | ||
2091 | * | ||
2092 | * Invalidates guest handle. | ||
2093 | * | ||
2094 | * @param gst | ||
2095 | * The guest to disconnect. | ||
2096 | */ | ||
2097 | void | ||
2098 | GNUNET_SOCIAL_guest_disconnect (struct GNUNET_SOCIAL_Guest *gst, | ||
2099 | GNUNET_ContinuationCallback disconnect_cb, | ||
2100 | void *cls) | ||
2101 | { | ||
2102 | struct GNUNET_SOCIAL_Place *plc = &gst->plc; | ||
2103 | |||
2104 | plc->disconnect_cb = disconnect_cb; | ||
2105 | plc->disconnect_cls = cls; | ||
2106 | place_disconnect (plc); | ||
2107 | } | ||
2108 | |||
2109 | |||
2110 | /** | ||
2111 | * Leave a place temporarily or permanently. | ||
2112 | * | ||
2113 | * Notifies the owner of the place about leaving, and destroys the place handle. | ||
2114 | * | ||
2115 | * @param place | ||
2116 | * Place to leave. | ||
2117 | * @param keep_active | ||
2118 | * Keep place active after last application disconnected. | ||
2119 | * #GNUNET_YES or #GNUNET_NO | ||
2120 | * @param env | ||
2121 | * Optional environment for the leave message if @a keep_active | ||
2122 | * is #GNUNET_NO. NULL if not needed. | ||
2123 | * @param leave_cb | ||
2124 | * Called upon disconnecting from the social service. | ||
2125 | */ | ||
2126 | void | ||
2127 | GNUNET_SOCIAL_guest_leave (struct GNUNET_SOCIAL_Guest *gst, | ||
2128 | struct GNUNET_PSYC_Environment *env, | ||
2129 | GNUNET_ContinuationCallback disconnect_cb, | ||
2130 | void *cls) | ||
2131 | { | ||
2132 | struct GNUNET_MQ_Envelope *envelope; | ||
2133 | |||
2134 | GNUNET_SOCIAL_guest_talk (gst, "_notice_place_leave", env, NULL, NULL, | ||
2135 | GNUNET_SOCIAL_TALK_NONE); | ||
2136 | gst->plc.disconnect_cb = disconnect_cb; | ||
2137 | gst->plc.disconnect_cls = cls; | ||
2138 | envelope = GNUNET_MQ_msg_header (GNUNET_MESSAGE_TYPE_SOCIAL_PLACE_LEAVE); | ||
2139 | GNUNET_MQ_send (gst->plc.mq, | ||
2140 | envelope); | ||
2141 | } | ||
2142 | |||
2143 | |||
2144 | /** | ||
2145 | * Obtain handle for a place entered as guest. | ||
2146 | * | ||
2147 | * The returned handle can be used to access the place API. | ||
2148 | * | ||
2149 | * @param guest Handle for the guest. | ||
2150 | * | ||
2151 | * @return Handle for the place, valid as long as @a guest is valid. | ||
2152 | */ | ||
2153 | struct GNUNET_SOCIAL_Place * | ||
2154 | GNUNET_SOCIAL_guest_get_place (struct GNUNET_SOCIAL_Guest *gst) | ||
2155 | { | ||
2156 | return &gst->plc; | ||
2157 | } | ||
2158 | |||
2159 | |||
2160 | /** | ||
2161 | * Obtain the public key of a place. | ||
2162 | * | ||
2163 | * @param plc | ||
2164 | * Place. | ||
2165 | * | ||
2166 | * @return Public key of the place. | ||
2167 | */ | ||
2168 | const struct GNUNET_CRYPTO_EddsaPublicKey * | ||
2169 | GNUNET_SOCIAL_place_get_pub_key (const struct GNUNET_SOCIAL_Place *plc) | ||
2170 | { | ||
2171 | return &plc->pub_key; | ||
2172 | } | ||
2173 | |||
2174 | |||
2175 | /** | ||
2176 | * Set message processing @a flags for a @a method_prefix. | ||
2177 | * | ||
2178 | * @param plc | ||
2179 | * Place. | ||
2180 | * @param method_prefix | ||
2181 | * Method prefix @a flags apply to. | ||
2182 | * @param flags | ||
2183 | * The flags that apply to a matching @a method_prefix. | ||
2184 | */ | ||
2185 | void | ||
2186 | GNUNET_SOCIAL_place_msg_proc_set (struct GNUNET_SOCIAL_Place *plc, | ||
2187 | const char *method_prefix, | ||
2188 | enum GNUNET_SOCIAL_MsgProcFlags flags) | ||
2189 | { | ||
2190 | GNUNET_assert (NULL != method_prefix); | ||
2191 | struct MsgProcRequest *mpreq; | ||
2192 | uint16_t method_size = strnlen (method_prefix, | ||
2193 | GNUNET_MAX_MESSAGE_SIZE | ||
2194 | - sizeof (*mpreq)) + 1; | ||
2195 | GNUNET_assert ('\0' == method_prefix[method_size - 1]); | ||
2196 | |||
2197 | struct GNUNET_MQ_Envelope * | ||
2198 | env = GNUNET_MQ_msg_extra (mpreq, method_size, | ||
2199 | GNUNET_MESSAGE_TYPE_SOCIAL_MSG_PROC_SET); | ||
2200 | mpreq->flags = htonl (flags); | ||
2201 | GNUNET_memcpy (&mpreq[1], method_prefix, method_size); | ||
2202 | |||
2203 | GNUNET_MQ_send (plc->mq, env); | ||
2204 | } | ||
2205 | |||
2206 | |||
2207 | /** | ||
2208 | * Clear all message processing flags previously set for this place. | ||
2209 | */ | ||
2210 | void | ||
2211 | GNUNET_SOCIAL_place_msg_proc_clear (struct GNUNET_SOCIAL_Place *plc) | ||
2212 | { | ||
2213 | struct GNUNET_MessageHeader *req; | ||
2214 | struct GNUNET_MQ_Envelope * | ||
2215 | env = GNUNET_MQ_msg (req, GNUNET_MESSAGE_TYPE_SOCIAL_MSG_PROC_CLEAR); | ||
2216 | |||
2217 | GNUNET_MQ_send (plc->mq, env); | ||
2218 | } | ||
2219 | |||
2220 | |||
2221 | static struct GNUNET_SOCIAL_HistoryRequest * | ||
2222 | place_history_replay (struct GNUNET_SOCIAL_Place *plc, | ||
2223 | uint64_t start_message_id, | ||
2224 | uint64_t end_message_id, | ||
2225 | uint64_t message_limit, | ||
2226 | const char *method_prefix, | ||
2227 | uint32_t flags, | ||
2228 | struct GNUNET_PSYC_Slicer *slicer, | ||
2229 | GNUNET_ResultCallback result_cb, | ||
2230 | void *cls) | ||
2231 | { | ||
2232 | struct GNUNET_PSYC_HistoryRequestMessage *req; | ||
2233 | struct GNUNET_SOCIAL_HistoryRequest *hist = GNUNET_malloc (sizeof (*hist)); | ||
2234 | hist->plc = plc; | ||
2235 | hist->slicer = slicer; | ||
2236 | hist->result_cb = result_cb; | ||
2237 | hist->cls = cls; | ||
2238 | hist->op_id = GNUNET_OP_add (plc->op, op_recv_history_result, hist, NULL); | ||
2239 | |||
2240 | GNUNET_assert (NULL != method_prefix); | ||
2241 | uint16_t method_size = strnlen (method_prefix, | ||
2242 | GNUNET_MAX_MESSAGE_SIZE | ||
2243 | - sizeof (*req)) + 1; | ||
2244 | GNUNET_assert ('\0' == method_prefix[method_size - 1]); | ||
2245 | |||
2246 | struct GNUNET_MQ_Envelope * | ||
2247 | env = GNUNET_MQ_msg_extra (req, method_size, | ||
2248 | GNUNET_MESSAGE_TYPE_PSYC_HISTORY_REPLAY); | ||
2249 | req->start_message_id = GNUNET_htonll (start_message_id); | ||
2250 | req->end_message_id = GNUNET_htonll (end_message_id); | ||
2251 | req->message_limit = GNUNET_htonll (message_limit); | ||
2252 | req->flags = htonl (flags); | ||
2253 | req->op_id = GNUNET_htonll (hist->op_id); | ||
2254 | GNUNET_memcpy (&req[1], method_prefix, method_size); | ||
2255 | |||
2256 | GNUNET_MQ_send (plc->mq, env); | ||
2257 | return hist; | ||
2258 | } | ||
2259 | |||
2260 | |||
2261 | /** | ||
2262 | * Learn about the history of a place. | ||
2263 | * | ||
2264 | * Messages are returned through the @a slicer function | ||
2265 | * and have the #GNUNET_PSYC_MESSAGE_HISTORIC flag set. | ||
2266 | * | ||
2267 | * @param place | ||
2268 | * Place we want to learn more about. | ||
2269 | * @param start_message_id | ||
2270 | * First historic message we are interested in. | ||
2271 | * @param end_message_id | ||
2272 | * Last historic message we are interested in (inclusive). | ||
2273 | * @param method_prefix | ||
2274 | * Only retrieve messages with this method prefix. | ||
2275 | * @param flags | ||
2276 | * OR'ed GNUNET_PSYC_HistoryReplayFlags | ||
2277 | * @param slicer | ||
2278 | * Slicer to use for retrieved messages. | ||
2279 | * Can be the same as the slicer of the place. | ||
2280 | * @param result_cb | ||
2281 | * Function called after all messages retrieved. | ||
2282 | * NULL if not needed. | ||
2283 | * @param cls Closure for @a result_cb. | ||
2284 | */ | ||
2285 | struct GNUNET_SOCIAL_HistoryRequest * | ||
2286 | GNUNET_SOCIAL_place_history_replay (struct GNUNET_SOCIAL_Place *plc, | ||
2287 | uint64_t start_message_id, | ||
2288 | uint64_t end_message_id, | ||
2289 | const char *method_prefix, | ||
2290 | uint32_t flags, | ||
2291 | struct GNUNET_PSYC_Slicer *slicer, | ||
2292 | GNUNET_ResultCallback result_cb, | ||
2293 | void *cls) | ||
2294 | { | ||
2295 | return place_history_replay (plc, start_message_id, end_message_id, 0, | ||
2296 | method_prefix, flags, slicer, result_cb, cls); | ||
2297 | } | ||
2298 | |||
2299 | |||
2300 | /** | ||
2301 | * Learn about the history of a place. | ||
2302 | * | ||
2303 | * Sends messages through the slicer function of the place where | ||
2304 | * start_message_id <= message_id <= end_message_id. | ||
2305 | * The messages will have the #GNUNET_PSYC_MESSAGE_HISTORIC flag set. | ||
2306 | * | ||
2307 | * To get the latest message, use 0 for both the start and end message ID. | ||
2308 | * | ||
2309 | * @param place | ||
2310 | * Place we want to learn more about. | ||
2311 | * @param message_limit | ||
2312 | * Maximum number of historic messages we are interested in. | ||
2313 | * @param method_prefix | ||
2314 | * Only retrieve messages with this method prefix. | ||
2315 | * @param flags | ||
2316 | * OR'ed GNUNET_PSYC_HistoryReplayFlags | ||
2317 | * @param result_cb | ||
2318 | * Function called after all messages retrieved. | ||
2319 | * NULL if not needed. | ||
2320 | * @param cls Closure for @a result_cb. | ||
2321 | */ | ||
2322 | struct GNUNET_SOCIAL_HistoryRequest * | ||
2323 | GNUNET_SOCIAL_place_history_replay_latest (struct GNUNET_SOCIAL_Place *plc, | ||
2324 | uint64_t message_limit, | ||
2325 | const char *method_prefix, | ||
2326 | uint32_t flags, | ||
2327 | struct GNUNET_PSYC_Slicer *slicer, | ||
2328 | GNUNET_ResultCallback result_cb, | ||
2329 | void *cls) | ||
2330 | { | ||
2331 | return place_history_replay (plc, 0, 0, message_limit, method_prefix, flags, | ||
2332 | slicer, result_cb, cls); | ||
2333 | } | ||
2334 | |||
2335 | |||
2336 | /** | ||
2337 | * Cancel learning about the history of a place. | ||
2338 | * | ||
2339 | * @param hist | ||
2340 | * History lesson to cancel. | ||
2341 | */ | ||
2342 | void | ||
2343 | GNUNET_SOCIAL_place_history_replay_cancel (struct GNUNET_SOCIAL_HistoryRequest *hist) | ||
2344 | { | ||
2345 | GNUNET_OP_remove (hist->plc->op, hist->op_id); | ||
2346 | GNUNET_free (hist); | ||
2347 | } | ||
2348 | |||
2349 | |||
2350 | /** | ||
2351 | * Request matching state variables. | ||
2352 | */ | ||
2353 | static struct GNUNET_SOCIAL_LookHandle * | ||
2354 | place_state_get (struct GNUNET_SOCIAL_Place *plc, | ||
2355 | uint16_t type, const char *name, | ||
2356 | GNUNET_PSYC_StateVarCallback var_cb, | ||
2357 | GNUNET_ResultCallback result_cb, void *cls) | ||
2358 | { | ||
2359 | struct GNUNET_PSYC_StateRequestMessage *req; | ||
2360 | struct GNUNET_SOCIAL_LookHandle *look = GNUNET_malloc (sizeof (*look)); | ||
2361 | look->plc = plc; | ||
2362 | look->var_cb = var_cb; | ||
2363 | look->result_cb = result_cb; | ||
2364 | look->cls = cls; | ||
2365 | look->op_id = GNUNET_OP_add (plc->op, &op_recv_state_result, look, NULL); | ||
2366 | |||
2367 | GNUNET_assert (NULL != name); | ||
2368 | size_t name_size = strnlen (name, GNUNET_MAX_MESSAGE_SIZE | ||
2369 | - sizeof (*req)) + 1; | ||
2370 | struct GNUNET_MQ_Envelope * | ||
2371 | env = GNUNET_MQ_msg_extra (req, name_size, type); | ||
2372 | req->op_id = GNUNET_htonll (look->op_id); | ||
2373 | GNUNET_memcpy (&req[1], name, name_size); | ||
2374 | |||
2375 | GNUNET_MQ_send (plc->mq, env); | ||
2376 | return look; | ||
2377 | } | ||
2378 | |||
2379 | |||
2380 | /** | ||
2381 | * Look at a particular object in the place. | ||
2382 | * | ||
2383 | * The best matching object is returned (its name might be less specific than | ||
2384 | * what was requested). | ||
2385 | * | ||
2386 | * @param place | ||
2387 | * The place where to look. | ||
2388 | * @param full_name | ||
2389 | * Full name of the object. | ||
2390 | * @param value_size | ||
2391 | * Set to the size of the returned value. | ||
2392 | * | ||
2393 | * @return NULL if there is no such object at this place. | ||
2394 | */ | ||
2395 | struct GNUNET_SOCIAL_LookHandle * | ||
2396 | GNUNET_SOCIAL_place_look_at (struct GNUNET_SOCIAL_Place *plc, | ||
2397 | const char *full_name, | ||
2398 | GNUNET_PSYC_StateVarCallback var_cb, | ||
2399 | GNUNET_ResultCallback result_cb, | ||
2400 | void *cls) | ||
2401 | { | ||
2402 | return place_state_get (plc, GNUNET_MESSAGE_TYPE_PSYC_STATE_GET, | ||
2403 | full_name, var_cb, result_cb, cls); | ||
2404 | } | ||
2405 | |||
2406 | |||
2407 | /** | ||
2408 | * Look for objects in the place with a matching name prefix. | ||
2409 | * | ||
2410 | * @param place | ||
2411 | * The place where to look. | ||
2412 | * @param name_prefix | ||
2413 | * Look at objects with names beginning with this value. | ||
2414 | * @param var_cb | ||
2415 | * Function to call for each object found. | ||
2416 | * @param cls | ||
2417 | * Closure for callback function. | ||
2418 | * | ||
2419 | * @return Handle that can be used to stop looking at objects. | ||
2420 | */ | ||
2421 | struct GNUNET_SOCIAL_LookHandle * | ||
2422 | GNUNET_SOCIAL_place_look_for (struct GNUNET_SOCIAL_Place *plc, | ||
2423 | const char *name_prefix, | ||
2424 | GNUNET_PSYC_StateVarCallback var_cb, | ||
2425 | GNUNET_ResultCallback result_cb, | ||
2426 | void *cls) | ||
2427 | { | ||
2428 | return place_state_get (plc, GNUNET_MESSAGE_TYPE_PSYC_STATE_GET_PREFIX, | ||
2429 | name_prefix, var_cb, result_cb, cls); | ||
2430 | } | ||
2431 | |||
2432 | |||
2433 | /** | ||
2434 | * Cancel a state request operation. | ||
2435 | * | ||
2436 | * @param sr | ||
2437 | * Handle for the operation to cancel. | ||
2438 | */ | ||
2439 | void | ||
2440 | GNUNET_SOCIAL_place_look_cancel (struct GNUNET_SOCIAL_LookHandle *look) | ||
2441 | { | ||
2442 | GNUNET_OP_remove (look->plc->op, look->op_id); | ||
2443 | GNUNET_free (look); | ||
2444 | } | ||
2445 | |||
2446 | |||
2447 | static void | ||
2448 | op_recv_zone_add_place_result (void *cls, int64_t result, | ||
2449 | const void *err_msg, uint16_t err_msg_size) | ||
2450 | { | ||
2451 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2452 | "Received zone add place result: %" PRId64 ".\n", result); | ||
2453 | |||
2454 | struct ZoneAddPlaceHandle *add_plc = cls; | ||
2455 | if (NULL != add_plc->result_cb) | ||
2456 | add_plc->result_cb (add_plc->result_cls, result, err_msg, err_msg_size); | ||
2457 | |||
2458 | GNUNET_free (add_plc); | ||
2459 | } | ||
2460 | |||
2461 | |||
2462 | /** | ||
2463 | * Advertise @e place in the GNS zone of @e ego. | ||
2464 | * | ||
2465 | * @param app | ||
2466 | * Application handle. | ||
2467 | * @param ego | ||
2468 | * Ego. | ||
2469 | * @param place_pub_key | ||
2470 | * Public key of place to add. | ||
2471 | * @param name | ||
2472 | * The name for the PLACE record to put in the zone. | ||
2473 | * @param password | ||
2474 | * Password used to encrypt the record or NULL to keep it cleartext. | ||
2475 | * @param relay_count | ||
2476 | * Number of elements in the @a relays array. | ||
2477 | * @param relays | ||
2478 | * List of relays to put in the PLACE record to advertise | ||
2479 | * as entry points to the place in addition to the origin. | ||
2480 | * @param expiration_time | ||
2481 | * Expiration time of the record, use 0 to remove the record. | ||
2482 | * @param result_cb | ||
2483 | * Function called with the result of the operation. | ||
2484 | * @param result_cls | ||
2485 | * Closure for @a result_cb | ||
2486 | * | ||
2487 | * @return #GNUNET_OK if the request was sent, | ||
2488 | * #GNUNET_SYSERR on error, e.g. the name/password is too long. | ||
2489 | */ | ||
2490 | int | ||
2491 | GNUNET_SOCIAL_zone_add_place (const struct GNUNET_SOCIAL_App *app, | ||
2492 | const struct GNUNET_SOCIAL_Ego *ego, | ||
2493 | const char *name, | ||
2494 | const char *password, | ||
2495 | const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key, | ||
2496 | const struct GNUNET_PeerIdentity *origin, | ||
2497 | uint32_t relay_count, | ||
2498 | const struct GNUNET_PeerIdentity *relays, | ||
2499 | struct GNUNET_TIME_Absolute expiration_time, | ||
2500 | GNUNET_ResultCallback result_cb, | ||
2501 | void *result_cls) | ||
2502 | { | ||
2503 | struct ZoneAddPlaceRequest *preq; | ||
2504 | size_t name_size = strlen (name) + 1; | ||
2505 | size_t password_size = strlen (password) + 1; | ||
2506 | size_t relay_size = relay_count * sizeof (*relays); | ||
2507 | size_t payload_size = name_size + password_size + relay_size; | ||
2508 | |||
2509 | if (GNUNET_MAX_MESSAGE_SIZE < sizeof (*preq) + payload_size) | ||
2510 | return GNUNET_SYSERR; | ||
2511 | |||
2512 | struct GNUNET_MQ_Envelope * | ||
2513 | env = GNUNET_MQ_msg_extra (preq, payload_size, | ||
2514 | GNUNET_MESSAGE_TYPE_SOCIAL_ZONE_ADD_PLACE); | ||
2515 | preq->expiration_time = GNUNET_htonll (expiration_time.abs_value_us); | ||
2516 | preq->ego_pub_key = ego->pub_key; | ||
2517 | preq->place_pub_key = *place_pub_key; | ||
2518 | preq->origin = *origin; | ||
2519 | preq->relay_count = htonl (relay_count); | ||
2520 | |||
2521 | char *p = (char *) &preq[1]; | ||
2522 | GNUNET_memcpy (p, name, name_size); | ||
2523 | p += name_size; | ||
2524 | GNUNET_memcpy (p, password, password_size); | ||
2525 | p += password_size; | ||
2526 | GNUNET_memcpy (p, relays, relay_size); | ||
2527 | |||
2528 | struct ZoneAddPlaceHandle * add_plc = GNUNET_malloc (sizeof (*add_plc)); | ||
2529 | add_plc->result_cb = result_cb; | ||
2530 | add_plc->result_cls = result_cls; | ||
2531 | |||
2532 | preq->op_id = GNUNET_htonll (GNUNET_OP_add (app->op, | ||
2533 | op_recv_zone_add_place_result, | ||
2534 | add_plc, NULL)); | ||
2535 | |||
2536 | GNUNET_MQ_send (app->mq, env); | ||
2537 | return GNUNET_OK; | ||
2538 | } | ||
2539 | |||
2540 | |||
2541 | static void | ||
2542 | op_recv_zone_add_nym_result (void *cls, int64_t result, | ||
2543 | const void *err_msg, uint16_t err_msg_size) | ||
2544 | { | ||
2545 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2546 | "Received zone add nym result: %" PRId64 ".\n", result); | ||
2547 | |||
2548 | struct ZoneAddNymHandle *add_nym = cls; | ||
2549 | if (NULL != add_nym->result_cb) | ||
2550 | add_nym->result_cb (add_nym->result_cls, result, err_msg, err_msg_size); | ||
2551 | |||
2552 | GNUNET_free (add_nym); | ||
2553 | } | ||
2554 | |||
2555 | |||
2556 | /** | ||
2557 | * Add nym to the GNS zone of @e ego. | ||
2558 | * | ||
2559 | * @param cfg | ||
2560 | * Configuration. | ||
2561 | * @param ego | ||
2562 | * Ego. | ||
2563 | * @param name | ||
2564 | * The name for the PKEY record to put in the zone. | ||
2565 | * @param nym_pub_key | ||
2566 | * Public key of nym to add. | ||
2567 | * @param expiration_time | ||
2568 | * Expiration time of the record, use 0 to remove the record. | ||
2569 | * @param result_cb | ||
2570 | * Function called with the result of the operation. | ||
2571 | * @param result_cls | ||
2572 | * Closure for @a result_cb | ||
2573 | * | ||
2574 | * @return #GNUNET_OK if the request was sent, | ||
2575 | * #GNUNET_SYSERR on error, e.g. the name is too long. | ||
2576 | */ | ||
2577 | int | ||
2578 | GNUNET_SOCIAL_zone_add_nym (const struct GNUNET_SOCIAL_App *app, | ||
2579 | const struct GNUNET_SOCIAL_Ego *ego, | ||
2580 | const char *name, | ||
2581 | const struct GNUNET_CRYPTO_EcdsaPublicKey *nym_pub_key, | ||
2582 | struct GNUNET_TIME_Absolute expiration_time, | ||
2583 | GNUNET_ResultCallback result_cb, | ||
2584 | void *result_cls) | ||
2585 | { | ||
2586 | struct ZoneAddNymRequest *nreq; | ||
2587 | |||
2588 | size_t name_size = strlen (name) + 1; | ||
2589 | if (GNUNET_MAX_MESSAGE_SIZE < sizeof (*nreq) + name_size) | ||
2590 | return GNUNET_SYSERR; | ||
2591 | |||
2592 | struct GNUNET_MQ_Envelope * | ||
2593 | env = GNUNET_MQ_msg_extra (nreq, name_size, | ||
2594 | GNUNET_MESSAGE_TYPE_SOCIAL_ZONE_ADD_NYM); | ||
2595 | nreq->expiration_time = GNUNET_htonll (expiration_time.abs_value_us); | ||
2596 | nreq->ego_pub_key = ego->pub_key; | ||
2597 | nreq->nym_pub_key = *nym_pub_key; | ||
2598 | GNUNET_memcpy (&nreq[1], name, name_size); | ||
2599 | |||
2600 | struct ZoneAddNymHandle *add_nym = GNUNET_malloc (sizeof (*add_nym)); | ||
2601 | add_nym->result_cb = result_cb; | ||
2602 | add_nym->result_cls = result_cls; | ||
2603 | |||
2604 | nreq->op_id = GNUNET_htonll (GNUNET_OP_add (app->op, | ||
2605 | op_recv_zone_add_nym_result, | ||
2606 | add_nym, NULL)); | ||
2607 | |||
2608 | GNUNET_MQ_send (app->mq, env); | ||
2609 | return GNUNET_OK; | ||
2610 | } | ||
2611 | |||
2612 | |||
2613 | /*** APP ***/ | ||
2614 | |||
2615 | |||
2616 | static void | ||
2617 | app_connect (struct GNUNET_SOCIAL_App *app); | ||
2618 | |||
2619 | |||
2620 | static void | ||
2621 | app_reconnect (void *cls) | ||
2622 | { | ||
2623 | app_connect (cls); | ||
2624 | } | ||
2625 | |||
2626 | |||
2627 | /** | ||
2628 | * App client disconnected from service. | ||
2629 | * | ||
2630 | * Reconnect after backoff period. | ||
2631 | */ | ||
2632 | static void | ||
2633 | app_disconnected (void *cls, enum GNUNET_MQ_Error error) | ||
2634 | { | ||
2635 | struct GNUNET_SOCIAL_App *app = cls; | ||
2636 | |||
2637 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2638 | "App client disconnected (%d), re-connecting\n", | ||
2639 | (int) error); | ||
2640 | if (NULL != app->mq) | ||
2641 | { | ||
2642 | GNUNET_MQ_destroy (app->mq); | ||
2643 | app->mq = NULL; | ||
2644 | } | ||
2645 | |||
2646 | app->reconnect_task = GNUNET_SCHEDULER_add_delayed (app->reconnect_delay, | ||
2647 | app_reconnect, | ||
2648 | app); | ||
2649 | app->reconnect_delay = GNUNET_TIME_STD_BACKOFF (app->reconnect_delay); | ||
2650 | } | ||
2651 | |||
2652 | |||
2653 | static void | ||
2654 | app_connect (struct GNUNET_SOCIAL_App *app) | ||
2655 | { | ||
2656 | struct GNUNET_MQ_MessageHandler handlers[] = { | ||
2657 | GNUNET_MQ_hd_var_size (app_ego, | ||
2658 | GNUNET_MESSAGE_TYPE_SOCIAL_APP_EGO, | ||
2659 | struct AppEgoMessage, | ||
2660 | app), | ||
2661 | GNUNET_MQ_hd_fixed_size (app_ego_end, | ||
2662 | GNUNET_MESSAGE_TYPE_SOCIAL_APP_EGO_END, | ||
2663 | struct GNUNET_MessageHeader, | ||
2664 | app), | ||
2665 | GNUNET_MQ_hd_var_size (app_place, | ||
2666 | GNUNET_MESSAGE_TYPE_SOCIAL_APP_PLACE, | ||
2667 | struct AppPlaceMessage, | ||
2668 | app), | ||
2669 | GNUNET_MQ_hd_fixed_size (app_place_end, | ||
2670 | GNUNET_MESSAGE_TYPE_SOCIAL_APP_PLACE_END, | ||
2671 | struct GNUNET_MessageHeader, | ||
2672 | app), | ||
2673 | GNUNET_MQ_hd_var_size (app_result, | ||
2674 | GNUNET_MESSAGE_TYPE_PSYC_RESULT_CODE, | ||
2675 | struct GNUNET_OperationResultMessage, | ||
2676 | app), | ||
2677 | GNUNET_MQ_handler_end () | ||
2678 | }; | ||
2679 | |||
2680 | app->mq = GNUNET_CLIENT_connect (app->cfg, "social", | ||
2681 | handlers, app_disconnected, app); | ||
2682 | GNUNET_assert (NULL != app->mq); | ||
2683 | GNUNET_MQ_send_copy (app->mq, app->connect_env); | ||
2684 | } | ||
2685 | |||
2686 | |||
2687 | /** | ||
2688 | * Connect application to the social service. | ||
2689 | * | ||
2690 | * The @host_place_cb and @guest_place_cb functions are | ||
2691 | * initially called for each entered places, | ||
2692 | * then later each time a new place is entered with the current application ID. | ||
2693 | * | ||
2694 | * @param cfg | ||
2695 | * Configuration. | ||
2696 | * @param id | ||
2697 | * Application ID. | ||
2698 | * @param ego_cb | ||
2699 | * Function to notify about an available ego. | ||
2700 | * @param host_cb | ||
2701 | * Function to notify about a place entered as host. | ||
2702 | * @param guest_cb | ||
2703 | * Function to notify about a place entered as guest. | ||
2704 | * @param cls | ||
2705 | * Closure for the callbacks. | ||
2706 | * | ||
2707 | * @return Handle that can be used to stop listening. | ||
2708 | */ | ||
2709 | struct GNUNET_SOCIAL_App * | ||
2710 | GNUNET_SOCIAL_app_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
2711 | const char *id, | ||
2712 | GNUNET_SOCIAL_AppEgoCallback ego_cb, | ||
2713 | GNUNET_SOCIAL_AppHostPlaceCallback host_cb, | ||
2714 | GNUNET_SOCIAL_AppGuestPlaceCallback guest_cb, | ||
2715 | GNUNET_SOCIAL_AppConnectedCallback connected_cb, | ||
2716 | void *cls) | ||
2717 | { | ||
2718 | uint16_t app_id_size = strnlen (id, GNUNET_SOCIAL_APP_MAX_ID_SIZE); | ||
2719 | if (GNUNET_SOCIAL_APP_MAX_ID_SIZE == app_id_size) | ||
2720 | return NULL; | ||
2721 | app_id_size++; | ||
2722 | |||
2723 | struct GNUNET_SOCIAL_App *app = GNUNET_malloc (sizeof *app); | ||
2724 | app->cfg = cfg; | ||
2725 | app->ego_cb = ego_cb; | ||
2726 | app->host_cb = host_cb; | ||
2727 | app->guest_cb = guest_cb; | ||
2728 | app->connected_cb = connected_cb; | ||
2729 | app->cb_cls = cls; | ||
2730 | app->egos = GNUNET_CONTAINER_multihashmap_create (1, GNUNET_NO); | ||
2731 | app->op = GNUNET_OP_create (); | ||
2732 | app->id = GNUNET_malloc (app_id_size); | ||
2733 | GNUNET_memcpy (app->id, id, app_id_size); | ||
2734 | |||
2735 | struct AppConnectRequest *creq; | ||
2736 | app->connect_env = GNUNET_MQ_msg_extra (creq, app_id_size, | ||
2737 | GNUNET_MESSAGE_TYPE_SOCIAL_APP_CONNECT); | ||
2738 | GNUNET_memcpy (&creq[1], app->id, app_id_size); | ||
2739 | |||
2740 | app_connect (app); | ||
2741 | return app; | ||
2742 | } | ||
2743 | |||
2744 | |||
2745 | static void | ||
2746 | app_cleanup (struct GNUNET_SOCIAL_App *app) | ||
2747 | { | ||
2748 | if (NULL != app->mq) | ||
2749 | { | ||
2750 | GNUNET_MQ_destroy (app->mq); | ||
2751 | app->mq = NULL; | ||
2752 | } | ||
2753 | if (NULL != app->disconnect_cb) | ||
2754 | { | ||
2755 | app->disconnect_cb (app->disconnect_cls); | ||
2756 | app->disconnect_cb = NULL; | ||
2757 | } | ||
2758 | GNUNET_free (app); | ||
2759 | } | ||
2760 | |||
2761 | /** | ||
2762 | * Disconnect application. | ||
2763 | * | ||
2764 | * @param app | ||
2765 | * Application handle. | ||
2766 | * @param disconnect_cb | ||
2767 | * Disconnect callback. | ||
2768 | * @param disconnect_cls | ||
2769 | * Disconnect closure. | ||
2770 | */ | ||
2771 | void | ||
2772 | GNUNET_SOCIAL_app_disconnect (struct GNUNET_SOCIAL_App *app, | ||
2773 | GNUNET_ContinuationCallback disconnect_cb, | ||
2774 | void *disconnect_cls) | ||
2775 | { | ||
2776 | if (NULL == app) return; | ||
2777 | |||
2778 | app->disconnect_cb = disconnect_cb; | ||
2779 | app->disconnect_cls = disconnect_cls; | ||
2780 | |||
2781 | if (NULL != app->mq) | ||
2782 | { | ||
2783 | struct GNUNET_MQ_Envelope *env = GNUNET_MQ_get_last_envelope (app->mq); | ||
2784 | if (NULL != env) | ||
2785 | { | ||
2786 | GNUNET_MQ_notify_sent (env, (GNUNET_SCHEDULER_TaskCallback) app_cleanup, app); | ||
2787 | } | ||
2788 | else | ||
2789 | { | ||
2790 | app_cleanup (app); | ||
2791 | } | ||
2792 | } | ||
2793 | else | ||
2794 | { | ||
2795 | app_cleanup (app); | ||
2796 | } | ||
2797 | } | ||
2798 | |||
2799 | |||
2800 | /** | ||
2801 | * Detach application from a place. | ||
2802 | * | ||
2803 | * Removes the place from the entered places list for this application. | ||
2804 | * Note: this does not disconnect from the place. | ||
2805 | * | ||
2806 | * @see GNUNET_SOCIAL_host_disconnect() and GNUNET_SOCIAL_guest_disconnect() | ||
2807 | * | ||
2808 | * @param app | ||
2809 | * Application. | ||
2810 | * @param plc | ||
2811 | * Place. | ||
2812 | */ | ||
2813 | void | ||
2814 | GNUNET_SOCIAL_app_detach (struct GNUNET_SOCIAL_App *app, | ||
2815 | struct GNUNET_SOCIAL_Place *plc) | ||
2816 | { | ||
2817 | struct AppDetachRequest *dreq; | ||
2818 | struct GNUNET_MQ_Envelope * | ||
2819 | env = GNUNET_MQ_msg (dreq, GNUNET_MESSAGE_TYPE_SOCIAL_APP_DETACH); | ||
2820 | dreq->place_pub_key = plc->pub_key; | ||
2821 | dreq->ego_pub_key = plc->ego_pub_key; | ||
2822 | |||
2823 | GNUNET_MQ_send (app->mq, env); | ||
2824 | } | ||
2825 | |||
2826 | |||
2827 | /* end of social_api.c */ | ||
diff --git a/src/social/test_social.c b/src/social/test_social.c deleted file mode 100644 index feac3c591..000000000 --- a/src/social/test_social.c +++ /dev/null | |||
@@ -1,1449 +0,0 @@ | |||
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 | * @file social/test_social.c | ||
22 | * @brief Tests for the Social API. | ||
23 | * @author Gabor X Toth | ||
24 | */ | ||
25 | |||
26 | #include <inttypes.h> | ||
27 | |||
28 | #include "platform.h" | ||
29 | #include "gnunet_crypto_lib.h" | ||
30 | #include "gnunet_common.h" | ||
31 | #include "gnunet_util_lib.h" | ||
32 | #include "gnunet_testing_lib.h" | ||
33 | #include "gnunet_psyc_util_lib.h" | ||
34 | #include "gnunet_social_service.h" | ||
35 | #include "gnunet_identity_service.h" | ||
36 | |||
37 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30) | ||
38 | |||
39 | #define DATA2ARG(data) data, sizeof (data) | ||
40 | |||
41 | /** | ||
42 | * Return value from 'main'. | ||
43 | */ | ||
44 | int res; | ||
45 | |||
46 | struct GNUNET_SOCIAL_App *app; | ||
47 | const char *app_id = "test"; | ||
48 | |||
49 | /** | ||
50 | * Handle for task for timeout termination. | ||
51 | */ | ||
52 | struct GNUNET_SCHEDULER_Task *end_badly_task; | ||
53 | |||
54 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
55 | |||
56 | struct GNUNET_PeerIdentity this_peer; | ||
57 | |||
58 | struct GNUNET_IDENTITY_Handle *id; | ||
59 | |||
60 | const struct GNUNET_IDENTITY_Ego *identity_host_ego; | ||
61 | const struct GNUNET_IDENTITY_Ego *identity_guest_ego; | ||
62 | |||
63 | const struct GNUNET_SOCIAL_Ego *host_ego; | ||
64 | const struct GNUNET_SOCIAL_Ego *guest_ego; | ||
65 | |||
66 | const char *host_name = "Host One"; | ||
67 | const char *guest_name = "Guest One"; | ||
68 | |||
69 | struct GNUNET_CRYPTO_EddsaPrivateKey *place_key; | ||
70 | struct GNUNET_CRYPTO_EcdsaPrivateKey *guest_key; | ||
71 | |||
72 | struct GNUNET_CRYPTO_EddsaPublicKey place_pub_key; | ||
73 | struct GNUNET_HashCode place_pub_hash; | ||
74 | |||
75 | const struct GNUNET_CRYPTO_EcdsaPublicKey *guest_pub_key; | ||
76 | const struct GNUNET_CRYPTO_EcdsaPublicKey *host_pub_key; | ||
77 | |||
78 | struct GNUNET_PSYC_Slicer *host_slicer; | ||
79 | struct GNUNET_PSYC_Slicer *guest_slicer; | ||
80 | |||
81 | struct GNUNET_SOCIAL_Host *hst; | ||
82 | struct GNUNET_SOCIAL_Guest *gst; | ||
83 | |||
84 | struct GNUNET_SOCIAL_Place *hst_plc; | ||
85 | struct GNUNET_SOCIAL_Place *gst_plc; | ||
86 | |||
87 | struct GNUNET_SOCIAL_Nym *nym_eject; | ||
88 | |||
89 | struct GuestEnterMessage | ||
90 | { | ||
91 | struct GNUNET_PSYC_Message *msg; | ||
92 | const char *method_name; | ||
93 | struct GNUNET_PSYC_Environment *env; | ||
94 | void *data; | ||
95 | uint16_t data_size; | ||
96 | } guest_enter_msg; | ||
97 | |||
98 | struct TransmitClosure | ||
99 | { | ||
100 | struct GNUNET_SOCIAL_Announcement *host_ann; | ||
101 | struct GNUNET_SOCIAL_TalkRequest *guest_talk; | ||
102 | struct GNUNET_PSYC_Environment *env; | ||
103 | char *data[16]; | ||
104 | uint8_t data_delay[16]; | ||
105 | uint8_t data_count; | ||
106 | uint8_t paused; | ||
107 | uint8_t n; | ||
108 | } tmit; | ||
109 | |||
110 | struct ResultClosure { | ||
111 | uint32_t n; | ||
112 | } mod_foo_bar_rcls; | ||
113 | |||
114 | uint8_t join_req_count; | ||
115 | struct GNUNET_PSYC_Message *join_resp; | ||
116 | |||
117 | uint32_t counter; | ||
118 | |||
119 | uint8_t is_guest_nym_added = GNUNET_NO; | ||
120 | uint8_t is_host_reconnected = GNUNET_NO; | ||
121 | uint8_t is_guest_reconnected = GNUNET_NO; | ||
122 | |||
123 | enum | ||
124 | { | ||
125 | TEST_NONE = 0, | ||
126 | TEST_IDENTITIES_CREATE = 1, | ||
127 | TEST_HOST_ENTER = 2, | ||
128 | TEST_GUEST_ENTER = 3, | ||
129 | TEST_HOST_ANSWER_DOOR_REFUSE = 4, | ||
130 | TEST_GUEST_RECV_ENTRY_DCSN_REFUSE = 5, | ||
131 | TEST_HOST_ANSWER_DOOR_ADMIT = 6, | ||
132 | TEST_GUEST_RECV_ENTRY_DCSN_ADMIT = 7, | ||
133 | TEST_HOST_ANNOUNCE = 8, | ||
134 | TEST_HOST_ANNOUNCE_END = 9, | ||
135 | TEST_GUEST_TALK = 10, | ||
136 | TEST_HOST_ANNOUNCE2 = 11, | ||
137 | TEST_HOST_ANNOUNCE2_END = 12, | ||
138 | TEST_GUEST_HISTORY_REPLAY = 13, | ||
139 | TEST_GUEST_HISTORY_REPLAY_LATEST = 14, | ||
140 | TEST_GUEST_LOOK_AT = 15, | ||
141 | TEST_GUEST_LOOK_FOR = 16, | ||
142 | TEST_GUEST_LEAVE = 17, | ||
143 | TEST_ZONE_ADD_PLACE = 18, | ||
144 | TEST_GUEST_ENTER_BY_NAME = 19, | ||
145 | TEST_RECONNECT = 20, | ||
146 | TEST_GUEST_LEAVE2 = 21, | ||
147 | TEST_HOST_LEAVE = 22, | ||
148 | } test; | ||
149 | |||
150 | |||
151 | static void | ||
152 | schedule_guest_leave (void *cls); | ||
153 | |||
154 | |||
155 | static void | ||
156 | host_answer_door (void *cls, | ||
157 | struct GNUNET_SOCIAL_Nym *nym, | ||
158 | const char *method_name, | ||
159 | struct GNUNET_PSYC_Environment *env, | ||
160 | const void *data, | ||
161 | size_t data_size); | ||
162 | |||
163 | static void | ||
164 | host_enter (); | ||
165 | |||
166 | static void | ||
167 | guest_init (); | ||
168 | |||
169 | static void | ||
170 | guest_enter (); | ||
171 | |||
172 | static void | ||
173 | guest_enter_by_name (); | ||
174 | |||
175 | static void | ||
176 | guest_talk (); | ||
177 | |||
178 | static void | ||
179 | host_announce2 (); | ||
180 | |||
181 | |||
182 | /** | ||
183 | * Terminate the test case (failure). | ||
184 | * | ||
185 | * @param cls NULL | ||
186 | */ | ||
187 | static void | ||
188 | end_badly (void *cls) | ||
189 | { | ||
190 | end_badly_task = NULL; | ||
191 | GNUNET_SCHEDULER_shutdown (); | ||
192 | res = 2; | ||
193 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
194 | "Test FAILED.\n"); | ||
195 | } | ||
196 | |||
197 | |||
198 | /** | ||
199 | * Terminate the test case (failure). | ||
200 | * | ||
201 | * @param cls NULL | ||
202 | */ | ||
203 | static void | ||
204 | end_shutdown (void *cls) | ||
205 | { | ||
206 | if (NULL != id) | ||
207 | { | ||
208 | GNUNET_IDENTITY_disconnect (id); | ||
209 | id = NULL; | ||
210 | } | ||
211 | |||
212 | if (NULL != guest_slicer) | ||
213 | { | ||
214 | GNUNET_PSYC_slicer_destroy (guest_slicer); | ||
215 | guest_slicer = NULL; | ||
216 | } | ||
217 | |||
218 | if (NULL != host_slicer) | ||
219 | { | ||
220 | GNUNET_PSYC_slicer_destroy (host_slicer); | ||
221 | host_slicer = NULL; | ||
222 | } | ||
223 | if (NULL != end_badly_task) | ||
224 | { | ||
225 | GNUNET_SCHEDULER_cancel (end_badly_task); | ||
226 | end_badly_task = NULL; | ||
227 | } | ||
228 | if (NULL != gst) | ||
229 | { | ||
230 | GNUNET_SOCIAL_guest_leave (gst, NULL, NULL, NULL); | ||
231 | gst = NULL; | ||
232 | gst_plc = NULL; | ||
233 | } | ||
234 | if (NULL != hst) | ||
235 | { | ||
236 | GNUNET_SOCIAL_host_leave (hst, NULL, NULL, NULL); | ||
237 | hst = NULL; | ||
238 | hst_plc = NULL; | ||
239 | } | ||
240 | GNUNET_SOCIAL_app_disconnect (app, NULL, NULL); | ||
241 | } | ||
242 | |||
243 | |||
244 | /** | ||
245 | * Terminate the test case (success). | ||
246 | * | ||
247 | * @param cls NULL | ||
248 | */ | ||
249 | static void | ||
250 | end_normally (void *cls) | ||
251 | { | ||
252 | GNUNET_SCHEDULER_shutdown (); | ||
253 | res = 0; | ||
254 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, "Test PASSED.\n"); | ||
255 | } | ||
256 | |||
257 | |||
258 | /** | ||
259 | * Finish the test case (successfully). | ||
260 | */ | ||
261 | static void | ||
262 | end () | ||
263 | { | ||
264 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
265 | "Test #%u: Ending tests.\n", test); | ||
266 | |||
267 | if (end_badly_task != NULL) | ||
268 | { | ||
269 | GNUNET_SCHEDULER_cancel (end_badly_task); | ||
270 | end_badly_task = NULL; | ||
271 | } | ||
272 | GNUNET_SCHEDULER_add_now (&end_normally, NULL); | ||
273 | } | ||
274 | |||
275 | |||
276 | static void | ||
277 | transmit_resume (void *cls) | ||
278 | { | ||
279 | struct TransmitClosure *tmit = cls; | ||
280 | |||
281 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
282 | "Test #%u: Transmission resumed.\n", test); | ||
283 | if (NULL != tmit->host_ann) | ||
284 | GNUNET_SOCIAL_host_announce_resume (tmit->host_ann); | ||
285 | else | ||
286 | GNUNET_SOCIAL_guest_talk_resume (tmit->guest_talk); | ||
287 | } | ||
288 | |||
289 | |||
290 | static int | ||
291 | notify_data (void *cls, uint16_t *data_size, void *data) | ||
292 | { | ||
293 | struct TransmitClosure *tmit = cls; | ||
294 | if (NULL != tmit->env) | ||
295 | { | ||
296 | GNUNET_PSYC_env_destroy (tmit->env); | ||
297 | tmit->env = NULL; | ||
298 | } | ||
299 | if (0 == tmit->data_count) | ||
300 | { | ||
301 | *data_size = 0; | ||
302 | return GNUNET_YES; | ||
303 | } | ||
304 | |||
305 | uint16_t size = strlen (tmit->data[tmit->n]); | ||
306 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
307 | "Test #%u: Transmit notify data: %u bytes available, " | ||
308 | "processing fragment %u/%u (size %u).\n", | ||
309 | test, *data_size, tmit->n + 1, tmit->data_count, size); | ||
310 | if (*data_size < size) | ||
311 | { | ||
312 | *data_size = 0; | ||
313 | GNUNET_assert (0); | ||
314 | return GNUNET_SYSERR; | ||
315 | } | ||
316 | |||
317 | if (GNUNET_YES != tmit->paused && 0 < tmit->data_delay[tmit->n]) | ||
318 | { | ||
319 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
320 | "Test #%u: Transmission paused.\n", test); | ||
321 | tmit->paused = GNUNET_YES; | ||
322 | GNUNET_SCHEDULER_add_delayed ( | ||
323 | GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, | ||
324 | tmit->data_delay[tmit->n]), | ||
325 | &transmit_resume, tmit); | ||
326 | *data_size = 0; | ||
327 | return GNUNET_NO; | ||
328 | } | ||
329 | tmit->paused = GNUNET_NO; | ||
330 | |||
331 | *data_size = size; | ||
332 | GNUNET_memcpy (data, tmit->data[tmit->n], size); | ||
333 | |||
334 | return ++tmit->n < tmit->data_count ? GNUNET_NO : GNUNET_YES; | ||
335 | } | ||
336 | |||
337 | |||
338 | static void | ||
339 | host_left () | ||
340 | { | ||
341 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
342 | "Test #%u: The host has left the place.\n", test); | ||
343 | end (); | ||
344 | } | ||
345 | |||
346 | |||
347 | static void | ||
348 | schedule_host_leave (void *cls) | ||
349 | { | ||
350 | test = TEST_HOST_LEAVE; | ||
351 | GNUNET_SOCIAL_host_leave (hst, NULL, &host_left, NULL); | ||
352 | hst = NULL; | ||
353 | hst_plc = NULL; | ||
354 | } | ||
355 | |||
356 | |||
357 | static void | ||
358 | host_farewell2 (void *cls, | ||
359 | const struct GNUNET_SOCIAL_Nym *nym, | ||
360 | struct GNUNET_PSYC_Environment *env) | ||
361 | { | ||
362 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
363 | "Nym left the place again.\n"); | ||
364 | GNUNET_SCHEDULER_add_now (&schedule_host_leave, NULL); | ||
365 | } | ||
366 | |||
367 | |||
368 | static void | ||
369 | host_reconnected (void *cls, int result, | ||
370 | const struct GNUNET_CRYPTO_EddsaPublicKey *home_pub_key, | ||
371 | uint64_t max_message_id) | ||
372 | { | ||
373 | place_pub_key = *home_pub_key; | ||
374 | GNUNET_CRYPTO_hash (&place_pub_key, sizeof (place_pub_key), &place_pub_hash); | ||
375 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
376 | "Test #%u: Host reconnected to place %s\n", | ||
377 | test, GNUNET_h2s (&place_pub_hash)); | ||
378 | |||
379 | is_host_reconnected = GNUNET_YES; | ||
380 | if (GNUNET_YES == is_guest_reconnected) | ||
381 | { | ||
382 | GNUNET_assert (NULL != gst); | ||
383 | GNUNET_SCHEDULER_add_now (&schedule_guest_leave, NULL); | ||
384 | } | ||
385 | } | ||
386 | |||
387 | |||
388 | static void | ||
389 | guest_reconnected (void *cls, int result, | ||
390 | const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key, | ||
391 | uint64_t max_message_id) | ||
392 | { | ||
393 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
394 | "Test #%u: Guest reconnected to place: %d\n", | ||
395 | test, result); | ||
396 | GNUNET_assert (0 <= result); | ||
397 | |||
398 | is_guest_reconnected = GNUNET_YES; | ||
399 | if (GNUNET_YES == is_host_reconnected) | ||
400 | { | ||
401 | GNUNET_assert (NULL != gst); | ||
402 | GNUNET_SCHEDULER_add_now (&schedule_guest_leave, NULL); | ||
403 | } | ||
404 | } | ||
405 | |||
406 | |||
407 | static void | ||
408 | app_connected (void *cls) | ||
409 | { | ||
410 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
411 | "Test #%u: App connected: %p\n", test, cls); | ||
412 | } | ||
413 | |||
414 | |||
415 | static void | ||
416 | app_recv_host (void *cls, | ||
417 | struct GNUNET_SOCIAL_HostConnection *hconn, | ||
418 | struct GNUNET_SOCIAL_Ego *ego, | ||
419 | const struct GNUNET_CRYPTO_EddsaPublicKey *host_pub_key, | ||
420 | enum GNUNET_SOCIAL_AppPlaceState place_state) | ||
421 | { | ||
422 | struct GNUNET_HashCode host_pub_hash; | ||
423 | |||
424 | GNUNET_CRYPTO_hash (host_pub_key, | ||
425 | sizeof (*host_pub_key), | ||
426 | &host_pub_hash); | ||
427 | |||
428 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
429 | "Test #%u: Got app host place notification: %s\n", | ||
430 | test, | ||
431 | GNUNET_h2s (&host_pub_hash)); | ||
432 | |||
433 | if (test == TEST_RECONNECT) | ||
434 | { | ||
435 | if (0 == memcmp (&place_pub_key, host_pub_key, sizeof (*host_pub_key))) | ||
436 | { | ||
437 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
438 | "Test #%u: Reconnecting to host place: %s\n", | ||
439 | test, GNUNET_h2s (&host_pub_hash)); | ||
440 | hst = GNUNET_SOCIAL_host_enter_reconnect (hconn, host_slicer, | ||
441 | &host_reconnected, | ||
442 | &host_answer_door, | ||
443 | &host_farewell2, | ||
444 | NULL); | ||
445 | } | ||
446 | } | ||
447 | } | ||
448 | |||
449 | |||
450 | static void | ||
451 | app_recv_guest (void *cls, | ||
452 | struct GNUNET_SOCIAL_GuestConnection *gconn, | ||
453 | struct GNUNET_SOCIAL_Ego *ego, | ||
454 | const struct GNUNET_CRYPTO_EddsaPublicKey *guest_pub_key, | ||
455 | enum GNUNET_SOCIAL_AppPlaceState place_state) | ||
456 | { | ||
457 | struct GNUNET_HashCode guest_pub_hash; | ||
458 | |||
459 | GNUNET_CRYPTO_hash (guest_pub_key, | ||
460 | sizeof (*guest_pub_key), | ||
461 | &guest_pub_hash); | ||
462 | |||
463 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
464 | "Test #%u: Got app guest place notification: %s\n", | ||
465 | test, GNUNET_h2s (&guest_pub_hash)); | ||
466 | |||
467 | if (test == TEST_RECONNECT) | ||
468 | { | ||
469 | if (0 == memcmp (&place_pub_key, | ||
470 | guest_pub_key, | ||
471 | sizeof (*guest_pub_key))) | ||
472 | { | ||
473 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
474 | "Test #%u: Reconnecting to guest place: %s\n", | ||
475 | test, GNUNET_h2s (&guest_pub_hash)); | ||
476 | gst = GNUNET_SOCIAL_guest_enter_reconnect (gconn, | ||
477 | GNUNET_PSYC_SLAVE_JOIN_NONE, | ||
478 | guest_slicer, | ||
479 | &guest_reconnected, | ||
480 | NULL); | ||
481 | GNUNET_assert (NULL != gst); | ||
482 | } | ||
483 | } | ||
484 | } | ||
485 | |||
486 | |||
487 | static void | ||
488 | enter_if_ready () | ||
489 | { | ||
490 | if (NULL == host_ego || NULL == guest_ego) | ||
491 | { | ||
492 | return; | ||
493 | } | ||
494 | host_enter (); | ||
495 | guest_init (); | ||
496 | } | ||
497 | |||
498 | |||
499 | static void | ||
500 | app_recv_ego (void *cls, | ||
501 | struct GNUNET_SOCIAL_Ego *ego, | ||
502 | const struct GNUNET_CRYPTO_EcdsaPublicKey *ego_pub_key, | ||
503 | const char *name) | ||
504 | { | ||
505 | char *ego_pub_str = GNUNET_CRYPTO_ecdsa_public_key_to_string (ego_pub_key); | ||
506 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
507 | "Test #%u: Got app ego notification: %p %s %s\n", | ||
508 | test, ego, name, ego_pub_str); | ||
509 | GNUNET_free (ego_pub_str); | ||
510 | |||
511 | if (NULL != strstr (name, host_name)) | ||
512 | { | ||
513 | host_ego = ego; | ||
514 | host_pub_key = ego_pub_key; | ||
515 | if (TEST_IDENTITIES_CREATE == test) | ||
516 | { | ||
517 | enter_if_ready (); | ||
518 | } | ||
519 | else | ||
520 | { | ||
521 | GNUNET_assert (TEST_RECONNECT == test); | ||
522 | } | ||
523 | } | ||
524 | else if (NULL != strstr (name, guest_name)) | ||
525 | { | ||
526 | guest_ego = ego; | ||
527 | guest_pub_key = ego_pub_key; | ||
528 | if (TEST_IDENTITIES_CREATE == test) | ||
529 | { | ||
530 | enter_if_ready (); | ||
531 | } | ||
532 | else | ||
533 | { | ||
534 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
535 | "test = %d\n", | ||
536 | test); | ||
537 | GNUNET_assert (TEST_RECONNECT == test); | ||
538 | } | ||
539 | } | ||
540 | } | ||
541 | |||
542 | |||
543 | static void | ||
544 | schedule_reconnect (void *cls) | ||
545 | { | ||
546 | test = TEST_RECONNECT; | ||
547 | GNUNET_SOCIAL_host_disconnect (hst, NULL, NULL); | ||
548 | GNUNET_SOCIAL_guest_disconnect (gst, NULL, NULL); | ||
549 | hst = NULL; | ||
550 | gst = NULL; | ||
551 | |||
552 | GNUNET_SOCIAL_app_disconnect (app, NULL, NULL); | ||
553 | app = GNUNET_SOCIAL_app_connect (cfg, app_id, | ||
554 | &app_recv_ego, | ||
555 | &app_recv_host, | ||
556 | &app_recv_guest, | ||
557 | &app_connected, | ||
558 | NULL); | ||
559 | } | ||
560 | |||
561 | |||
562 | static void | ||
563 | host_recv_zone_add_place_result (void *cls, int64_t result, | ||
564 | const void *data, uint16_t data_size) | ||
565 | { | ||
566 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
567 | "Test #%u: Zone add place result: %" PRId64 " (%.*s).\n", | ||
568 | test, result, data_size, (const char *) data); | ||
569 | GNUNET_assert (GNUNET_YES == result); | ||
570 | |||
571 | GNUNET_assert (GNUNET_YES == is_guest_nym_added); | ||
572 | guest_enter_by_name (); | ||
573 | } | ||
574 | |||
575 | |||
576 | static void | ||
577 | zone_add_place () | ||
578 | { | ||
579 | test = TEST_ZONE_ADD_PLACE; | ||
580 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
581 | "Test #%u: Adding place to zone.\n", test); | ||
582 | |||
583 | GNUNET_SOCIAL_zone_add_place (app, host_ego, "home", "let.me*in!", | ||
584 | &place_pub_key, &this_peer, 1, &this_peer, | ||
585 | GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES), | ||
586 | host_recv_zone_add_place_result, app); | ||
587 | } | ||
588 | |||
589 | |||
590 | static void | ||
591 | host_farewell (void *cls, | ||
592 | const struct GNUNET_SOCIAL_Nym *nym, | ||
593 | struct GNUNET_PSYC_Environment *env) | ||
594 | { | ||
595 | const struct GNUNET_CRYPTO_EcdsaPublicKey * | ||
596 | nym_key = GNUNET_SOCIAL_nym_get_pub_key (nym); | ||
597 | |||
598 | char *str = GNUNET_CRYPTO_ecdsa_public_key_to_string (nym_key); | ||
599 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
600 | "Test #%u: Farewell: nym %s (%s) has left the place.\n", | ||
601 | test, GNUNET_h2s (GNUNET_SOCIAL_nym_get_pub_key_hash (nym)), str); | ||
602 | GNUNET_free (str); | ||
603 | GNUNET_assert (1 == GNUNET_PSYC_env_get_count (env)); | ||
604 | if (0 != memcmp (guest_pub_key, nym_key, sizeof (*nym_key))) | ||
605 | { | ||
606 | str = GNUNET_CRYPTO_ecdsa_public_key_to_string (guest_pub_key); | ||
607 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
608 | "Test #%u: Farewell: nym does not match guest: %s\n", | ||
609 | test, str); | ||
610 | GNUNET_free (str); | ||
611 | GNUNET_assert (0); | ||
612 | } | ||
613 | zone_add_place (); | ||
614 | } | ||
615 | |||
616 | |||
617 | static void | ||
618 | guest_left (void *cls) | ||
619 | { | ||
620 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
621 | "Test #%u: The guest has left the place.\n", test); | ||
622 | } | ||
623 | |||
624 | |||
625 | static void | ||
626 | guest_leave () | ||
627 | { | ||
628 | if (test < TEST_RECONNECT) | ||
629 | test = TEST_GUEST_LEAVE; | ||
630 | else | ||
631 | test = TEST_GUEST_LEAVE2; | ||
632 | |||
633 | struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create (); | ||
634 | GNUNET_PSYC_env_add (env, GNUNET_PSYC_OP_SET, | ||
635 | "_notice_place_leave", DATA2ARG ("Leaving.")); | ||
636 | GNUNET_SOCIAL_guest_leave (gst, env, &guest_left, NULL); | ||
637 | GNUNET_PSYC_env_destroy (env); | ||
638 | gst = NULL; | ||
639 | gst_plc = NULL; | ||
640 | } | ||
641 | |||
642 | |||
643 | static void | ||
644 | schedule_guest_leave (void *cls) | ||
645 | { | ||
646 | guest_leave (); | ||
647 | } | ||
648 | |||
649 | |||
650 | static void | ||
651 | guest_look_for_result (void *cls, | ||
652 | int64_t result_code, | ||
653 | const void *data, | ||
654 | uint16_t data_size) | ||
655 | { | ||
656 | struct ResultClosure *rcls = cls; | ||
657 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
658 | "Test #%u: guest_look_for_result: %" PRId64 "\n", | ||
659 | test, result_code); | ||
660 | GNUNET_assert (GNUNET_OK == result_code); | ||
661 | GNUNET_assert (6 == rcls->n); | ||
662 | GNUNET_free (rcls); | ||
663 | GNUNET_SCHEDULER_add_now (&schedule_guest_leave, NULL); | ||
664 | } | ||
665 | |||
666 | |||
667 | static void | ||
668 | guest_look_for_var (void *cls, | ||
669 | const struct GNUNET_MessageHeader *mod, | ||
670 | const char *name, | ||
671 | const void *value, | ||
672 | uint32_t value_size, | ||
673 | uint32_t full_value_size) | ||
674 | { | ||
675 | struct ResultClosure *rcls = cls; | ||
676 | rcls->n++; | ||
677 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
678 | "Test #%u: guest_look_for_var: %s\n%.*s\n", | ||
679 | test, name, value_size, (const char *) value); | ||
680 | } | ||
681 | |||
682 | |||
683 | static void | ||
684 | guest_look_for () | ||
685 | { | ||
686 | test = TEST_GUEST_LOOK_FOR; | ||
687 | struct ResultClosure *rcls = GNUNET_malloc (sizeof (*rcls)); | ||
688 | GNUNET_SOCIAL_place_look_for (gst_plc, "_foo", guest_look_for_var, guest_look_for_result, rcls); | ||
689 | } | ||
690 | |||
691 | |||
692 | static void | ||
693 | guest_look_at_result (void *cls, int64_t result_code, | ||
694 | const void *data, uint16_t data_size) | ||
695 | { | ||
696 | struct ResultClosure *rcls = cls; | ||
697 | |||
698 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
699 | "Test #%u: guest_look_at_result: %" PRId64 "\n", | ||
700 | test, result_code); | ||
701 | GNUNET_assert (GNUNET_OK == result_code); | ||
702 | GNUNET_assert (1 == rcls->n); | ||
703 | GNUNET_free (rcls); | ||
704 | guest_look_for (); | ||
705 | } | ||
706 | |||
707 | |||
708 | static void | ||
709 | guest_look_at_var (void *cls, | ||
710 | const struct GNUNET_MessageHeader *mod, | ||
711 | const char *name, | ||
712 | const void *value, | ||
713 | uint32_t value_size, | ||
714 | uint32_t full_value_size) | ||
715 | { | ||
716 | struct ResultClosure *rcls = cls; | ||
717 | rcls->n++; | ||
718 | |||
719 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
720 | "Test #%u: guest_look_at_var: %s\n%.*s\n", | ||
721 | test ,name, value_size, (const char *) value); | ||
722 | } | ||
723 | |||
724 | |||
725 | static void | ||
726 | guest_look_at () | ||
727 | { | ||
728 | test = TEST_GUEST_LOOK_AT; | ||
729 | struct ResultClosure *rcls = GNUNET_malloc (sizeof (*rcls)); | ||
730 | GNUNET_SOCIAL_place_look_at (gst_plc, "_foo_bar", guest_look_at_var, guest_look_at_result, rcls); | ||
731 | } | ||
732 | |||
733 | |||
734 | static void | ||
735 | guest_recv_history_replay_latest_result (void *cls, int64_t result, | ||
736 | const void *data, uint16_t data_size) | ||
737 | { | ||
738 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
739 | "Test #%u: Guest received latest history replay result " | ||
740 | "(%" PRIu32 " messages, %" PRId64 " fragments):\n" | ||
741 | "%.*s\n", | ||
742 | test, counter, result, data_size, (const char *) data); | ||
743 | //GNUNET_assert (2 == counter); /* message count */ | ||
744 | //GNUNET_assert (7 == result); /* fragment count */ | ||
745 | |||
746 | guest_look_at (); | ||
747 | } | ||
748 | |||
749 | |||
750 | static void | ||
751 | guest_history_replay_latest () | ||
752 | { | ||
753 | test = TEST_GUEST_HISTORY_REPLAY_LATEST; | ||
754 | counter = 0; | ||
755 | GNUNET_SOCIAL_place_history_replay_latest (gst_plc, 3, "", | ||
756 | GNUNET_PSYC_HISTORY_REPLAY_LOCAL, | ||
757 | guest_slicer, | ||
758 | &guest_recv_history_replay_latest_result, | ||
759 | NULL); | ||
760 | } | ||
761 | |||
762 | |||
763 | static void | ||
764 | guest_recv_history_replay_result (void *cls, int64_t result, | ||
765 | const void *data, uint16_t data_size) | ||
766 | { | ||
767 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
768 | "Test #%u: Guest received history replay result: %" PRId64 "\n" | ||
769 | "%.*s\n", | ||
770 | test, result, data_size, (const char *) data); | ||
771 | // GNUNET_assert (2 == counter); /* message count */ | ||
772 | // GNUNET_assert (7 == result); /* fragment count */ | ||
773 | |||
774 | guest_history_replay_latest (); | ||
775 | } | ||
776 | |||
777 | |||
778 | static void | ||
779 | guest_history_replay () | ||
780 | { | ||
781 | test = TEST_GUEST_HISTORY_REPLAY; | ||
782 | counter = 0; | ||
783 | GNUNET_SOCIAL_place_history_replay (gst_plc, 1, 3, "", | ||
784 | GNUNET_PSYC_HISTORY_REPLAY_LOCAL, | ||
785 | guest_slicer, | ||
786 | &guest_recv_history_replay_result, | ||
787 | NULL); | ||
788 | } | ||
789 | |||
790 | |||
791 | static void | ||
792 | guest_recv_method (void *cls, | ||
793 | const struct GNUNET_PSYC_MessageHeader *msg, | ||
794 | const struct GNUNET_PSYC_MessageMethod *meth, | ||
795 | uint64_t message_id, | ||
796 | const char *method_name) | ||
797 | { | ||
798 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
799 | "Test #%u: Guest received method for message ID %" PRIu64 ":\n" | ||
800 | "%s (flags: %x)\n", | ||
801 | test, message_id, method_name, ntohl (meth->flags)); | ||
802 | /** @todo FIXME: check message */ | ||
803 | } | ||
804 | |||
805 | |||
806 | static void | ||
807 | guest_recv_modifier (void *cls, | ||
808 | const struct GNUNET_PSYC_MessageHeader *msg, | ||
809 | const struct GNUNET_MessageHeader *pmsg, | ||
810 | uint64_t message_id, | ||
811 | enum GNUNET_PSYC_Operator oper, | ||
812 | const char *name, | ||
813 | const void *value, | ||
814 | uint16_t value_size, | ||
815 | uint16_t full_value_size) | ||
816 | { | ||
817 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
818 | "Test #%u: Guest received modifier for message ID %" PRIu64 ":\n" | ||
819 | "%c%s: %.*s (size: %u)\n", | ||
820 | test, message_id, oper, name, value_size, (const char *) value, value_size); | ||
821 | /** @todo FIXME: check modifier */ | ||
822 | } | ||
823 | |||
824 | static void | ||
825 | guest_recv_mod_foo_bar (void *cls, | ||
826 | const struct GNUNET_PSYC_MessageHeader *msg, | ||
827 | const struct GNUNET_MessageHeader *pmsg, | ||
828 | uint64_t message_id, | ||
829 | enum GNUNET_PSYC_Operator oper, | ||
830 | const char *name, | ||
831 | const void *value, | ||
832 | uint16_t value_size, | ||
833 | uint16_t full_value_size) | ||
834 | { | ||
835 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
836 | "Test #%u: Guest received modifier matching _foo_bar for message ID %" PRIu64 ":\n" | ||
837 | "%c%s: %.*s (size: %u)\n", | ||
838 | test, message_id, oper, name, value_size, (const char *) value, value_size); | ||
839 | struct ResultClosure *rc = cls; | ||
840 | rc->n++; | ||
841 | /** @todo FIXME: check modifier */ | ||
842 | } | ||
843 | |||
844 | |||
845 | static void | ||
846 | guest_recv_data (void *cls, | ||
847 | const struct GNUNET_PSYC_MessageHeader *msg, | ||
848 | const struct GNUNET_MessageHeader *pmsg, | ||
849 | uint64_t message_id, | ||
850 | const void *data, | ||
851 | uint16_t data_size) | ||
852 | { | ||
853 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
854 | "Test #%u: Guest received data for message ID %" PRIu64 ":\n" | ||
855 | "%.*s\n", | ||
856 | test, message_id, data_size, (const char *) data); | ||
857 | /** @todo FIXME: check data */ | ||
858 | } | ||
859 | |||
860 | |||
861 | static void | ||
862 | guest_recv_eom (void *cls, | ||
863 | const struct GNUNET_PSYC_MessageHeader *msg, | ||
864 | const struct GNUNET_MessageHeader *pmsg, | ||
865 | uint64_t message_id, | ||
866 | uint8_t is_cancelled) | ||
867 | { | ||
868 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
869 | "Test #%u: Guest received end of message ID %" PRIu64 | ||
870 | ", cancelled: %u\n", | ||
871 | test, message_id, is_cancelled); | ||
872 | |||
873 | switch (test) | ||
874 | { | ||
875 | case TEST_HOST_ANNOUNCE: | ||
876 | test = TEST_HOST_ANNOUNCE_END; | ||
877 | break; | ||
878 | |||
879 | case TEST_HOST_ANNOUNCE_END: | ||
880 | guest_talk (); | ||
881 | break; | ||
882 | |||
883 | case TEST_HOST_ANNOUNCE2: | ||
884 | test = TEST_HOST_ANNOUNCE2_END; | ||
885 | break; | ||
886 | |||
887 | case TEST_HOST_ANNOUNCE2_END: | ||
888 | guest_history_replay (); | ||
889 | break; | ||
890 | |||
891 | case TEST_GUEST_HISTORY_REPLAY: | ||
892 | case TEST_GUEST_HISTORY_REPLAY_LATEST: | ||
893 | counter++; | ||
894 | break; | ||
895 | |||
896 | default: | ||
897 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "invalid test: %d\n", test); | ||
898 | GNUNET_assert (0); | ||
899 | } | ||
900 | } | ||
901 | |||
902 | |||
903 | static void | ||
904 | host_recv_method (void *cls, | ||
905 | const struct GNUNET_PSYC_MessageHeader *msg, | ||
906 | const struct GNUNET_PSYC_MessageMethod *meth, | ||
907 | uint64_t message_id, | ||
908 | const char *method_name) | ||
909 | { | ||
910 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
911 | "Test #%u: Host received method for message ID %" PRIu64 ":\n" | ||
912 | "%s\n", | ||
913 | test, message_id, method_name); | ||
914 | /** @todo FIXME: check message */ | ||
915 | } | ||
916 | |||
917 | |||
918 | static void | ||
919 | host_recv_modifier (void *cls, | ||
920 | const struct GNUNET_PSYC_MessageHeader *msg, | ||
921 | const struct GNUNET_MessageHeader *pmsg, | ||
922 | uint64_t message_id, | ||
923 | enum GNUNET_PSYC_Operator oper, | ||
924 | const char *name, | ||
925 | const void *value, | ||
926 | uint16_t value_size, | ||
927 | uint16_t full_value_size) | ||
928 | { | ||
929 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
930 | "Test #%u: Host received modifier for message ID %" PRIu64 ":\n" | ||
931 | "%c%s: %.*s\n", | ||
932 | test, message_id, oper, name, value_size, (const char *) value); | ||
933 | } | ||
934 | |||
935 | |||
936 | static void | ||
937 | host_recv_data (void *cls, | ||
938 | const struct GNUNET_PSYC_MessageHeader *msg, | ||
939 | const struct GNUNET_MessageHeader *pmsg, | ||
940 | uint64_t message_id, | ||
941 | const void *data, | ||
942 | uint16_t data_size) | ||
943 | { | ||
944 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
945 | "Test #%u: Host received data for message ID %" PRIu64 ":\n" | ||
946 | "%.*s\n", | ||
947 | test, message_id, data_size, (const char *) data); | ||
948 | } | ||
949 | |||
950 | |||
951 | static void | ||
952 | host_recv_eom (void *cls, | ||
953 | const struct GNUNET_PSYC_MessageHeader *msg, | ||
954 | const struct GNUNET_MessageHeader *pmsg, | ||
955 | uint64_t message_id, | ||
956 | uint8_t is_cancelled) | ||
957 | { | ||
958 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
959 | "Test #%u: Host received end of message ID %" PRIu64 | ||
960 | ", cancelled: %u\n", | ||
961 | test, message_id, is_cancelled); | ||
962 | |||
963 | switch (test) | ||
964 | { | ||
965 | case TEST_HOST_ANNOUNCE: | ||
966 | test = TEST_HOST_ANNOUNCE_END; | ||
967 | break; | ||
968 | |||
969 | case TEST_HOST_ANNOUNCE_END: | ||
970 | guest_talk (); | ||
971 | break; | ||
972 | |||
973 | case TEST_HOST_ANNOUNCE2: | ||
974 | test = TEST_HOST_ANNOUNCE2_END; | ||
975 | break; | ||
976 | |||
977 | case TEST_HOST_ANNOUNCE2_END: | ||
978 | guest_history_replay (); | ||
979 | break; | ||
980 | |||
981 | case TEST_GUEST_TALK: | ||
982 | host_announce2 (); | ||
983 | break; | ||
984 | |||
985 | default: | ||
986 | if (TEST_GUEST_LEAVE <= test) | ||
987 | break; | ||
988 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid test: #%u\n", test); | ||
989 | GNUNET_assert (0); | ||
990 | } | ||
991 | } | ||
992 | |||
993 | |||
994 | static void | ||
995 | guest_talk () | ||
996 | { | ||
997 | test = TEST_GUEST_TALK; | ||
998 | |||
999 | tmit = (struct TransmitClosure) {}; | ||
1000 | tmit.env = GNUNET_PSYC_env_create (); | ||
1001 | GNUNET_PSYC_env_add (tmit.env, GNUNET_PSYC_OP_ASSIGN, | ||
1002 | "_bar_foo", DATA2ARG ("one two three")); | ||
1003 | GNUNET_PSYC_env_add (tmit.env, GNUNET_PSYC_OP_ASSIGN, | ||
1004 | "_bar_baz", DATA2ARG ("four five")); | ||
1005 | tmit.data[0] = "zzz xxx yyy "; | ||
1006 | tmit.data[1] = "zyx wvu tsr qpo.\n"; | ||
1007 | tmit.data_delay[1] = 1; | ||
1008 | tmit.data[2] = "testing ten nine eight.\n"; | ||
1009 | tmit.data_count = 3; | ||
1010 | |||
1011 | tmit.guest_talk | ||
1012 | = GNUNET_SOCIAL_guest_talk (gst, "_converse_guest", tmit.env, | ||
1013 | ¬ify_data, &tmit, | ||
1014 | GNUNET_SOCIAL_TALK_NONE); | ||
1015 | } | ||
1016 | |||
1017 | |||
1018 | static void | ||
1019 | host_announce () | ||
1020 | { | ||
1021 | test = TEST_HOST_ANNOUNCE; | ||
1022 | |||
1023 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
1024 | "Test #%u: Host announcement.\n", test); | ||
1025 | |||
1026 | tmit = (struct TransmitClosure) {}; | ||
1027 | tmit.env = GNUNET_PSYC_env_create (); | ||
1028 | GNUNET_PSYC_env_add (tmit.env, GNUNET_PSYC_OP_ASSIGN, | ||
1029 | "_foo", DATA2ARG ("bar baz")); | ||
1030 | GNUNET_PSYC_env_add (tmit.env, GNUNET_PSYC_OP_ASSIGN, | ||
1031 | "_foo_bar", DATA2ARG ("foo bar")); | ||
1032 | GNUNET_PSYC_env_add (tmit.env, GNUNET_PSYC_OP_ASSIGN, | ||
1033 | "_foo_bar_baz", DATA2ARG ("foo bar baz")); | ||
1034 | tmit.data[0] = "aaa bbb ccc "; | ||
1035 | tmit.data[1] = "abc def ghi jkl.\n"; | ||
1036 | tmit.data_delay[1] = 1; | ||
1037 | tmit.data[2] = "testing one two three "; | ||
1038 | tmit.data[3] = "four five.\n"; | ||
1039 | tmit.data_count = 4; | ||
1040 | |||
1041 | tmit.host_ann | ||
1042 | = GNUNET_SOCIAL_host_announce (hst, "_converse_host", tmit.env, | ||
1043 | ¬ify_data, &tmit, | ||
1044 | GNUNET_SOCIAL_ANNOUNCE_NONE); | ||
1045 | } | ||
1046 | |||
1047 | |||
1048 | static void | ||
1049 | host_announce2 () | ||
1050 | { | ||
1051 | GNUNET_assert (2 == mod_foo_bar_rcls.n); | ||
1052 | GNUNET_PSYC_slicer_modifier_remove (guest_slicer, "_foo_bar", | ||
1053 | guest_recv_mod_foo_bar); | ||
1054 | |||
1055 | test = TEST_HOST_ANNOUNCE2; | ||
1056 | |||
1057 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
1058 | "Test #%u: Host announcement 2.\n", test); | ||
1059 | |||
1060 | tmit = (struct TransmitClosure) {}; | ||
1061 | tmit.env = GNUNET_PSYC_env_create (); | ||
1062 | GNUNET_PSYC_env_add (tmit.env, GNUNET_PSYC_OP_ASSIGN, | ||
1063 | "_foo2", DATA2ARG ("BAR BAZ")); | ||
1064 | GNUNET_PSYC_env_add (tmit.env, GNUNET_PSYC_OP_ASSIGN, | ||
1065 | "_foo2_bar", DATA2ARG ("FOO BAR")); | ||
1066 | GNUNET_PSYC_env_add (tmit.env, GNUNET_PSYC_OP_ASSIGN, | ||
1067 | "_foo2_bar_baz", DATA2ARG ("FOO BAR BAZ")); | ||
1068 | tmit.data[0] = "AAA BBB CCC "; | ||
1069 | tmit.data[1] = "ABC DEF GHI JKL.\n"; | ||
1070 | tmit.data[2] = "TESTING ONE TWO THREE.\n"; | ||
1071 | tmit.data_count = 3; | ||
1072 | |||
1073 | tmit.host_ann | ||
1074 | = GNUNET_SOCIAL_host_announce (hst, "_converse_host_two", tmit.env, | ||
1075 | ¬ify_data, &tmit, | ||
1076 | GNUNET_SOCIAL_ANNOUNCE_NONE); | ||
1077 | } | ||
1078 | |||
1079 | |||
1080 | static void | ||
1081 | guest_recv_entry_decision (void *cls, | ||
1082 | int is_admitted, | ||
1083 | const struct GNUNET_PSYC_Message *entry_msg) | ||
1084 | { | ||
1085 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
1086 | "Test #%u: Guest received entry decision (try %u): %d.\n", | ||
1087 | test, join_req_count, is_admitted); | ||
1088 | |||
1089 | if (NULL != entry_msg) | ||
1090 | { | ||
1091 | struct GNUNET_PSYC_Environment *env = GNUNET_PSYC_env_create (); | ||
1092 | const char *method_name = NULL; | ||
1093 | const void *data = NULL; | ||
1094 | uint16_t data_size = 0; | ||
1095 | struct GNUNET_PSYC_MessageHeader * | ||
1096 | pmsg = GNUNET_PSYC_message_header_create_from_psyc (entry_msg); | ||
1097 | GNUNET_PSYC_message_parse (pmsg, &method_name, env, &data, &data_size); | ||
1098 | GNUNET_free (pmsg); | ||
1099 | |||
1100 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1101 | "%s\n%.*s\n", | ||
1102 | method_name, data_size, (const char *) data); | ||
1103 | /** @todo FIXME: check response message */ | ||
1104 | } | ||
1105 | |||
1106 | switch (test) | ||
1107 | { | ||
1108 | case TEST_GUEST_RECV_ENTRY_DCSN_REFUSE: | ||
1109 | GNUNET_assert (GNUNET_NO == is_admitted); | ||
1110 | test = TEST_HOST_ANSWER_DOOR_ADMIT; | ||
1111 | GNUNET_SOCIAL_guest_disconnect (gst, &guest_enter, NULL); | ||
1112 | break; | ||
1113 | |||
1114 | case TEST_GUEST_RECV_ENTRY_DCSN_ADMIT: | ||
1115 | GNUNET_assert (GNUNET_YES == is_admitted); | ||
1116 | host_announce (); | ||
1117 | break; | ||
1118 | |||
1119 | case TEST_GUEST_ENTER_BY_NAME: | ||
1120 | GNUNET_SCHEDULER_add_now (&schedule_reconnect, NULL); | ||
1121 | break; | ||
1122 | |||
1123 | default: | ||
1124 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "invalid test: %d\n", test); | ||
1125 | GNUNET_assert (0); | ||
1126 | } | ||
1127 | } | ||
1128 | |||
1129 | |||
1130 | static void | ||
1131 | host_answer_door (void *cls, | ||
1132 | struct GNUNET_SOCIAL_Nym *nym, | ||
1133 | const char *method_name, | ||
1134 | struct GNUNET_PSYC_Environment *env, | ||
1135 | const void *data, | ||
1136 | size_t data_size) | ||
1137 | { | ||
1138 | join_req_count++; | ||
1139 | |||
1140 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
1141 | "Test #%u: Host received entry request from guest (try %u).\n", | ||
1142 | (uint8_t) test, join_req_count); | ||
1143 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1144 | "%s\n%.*s\n", | ||
1145 | method_name, (int) data_size, (const char *) data); | ||
1146 | |||
1147 | switch (test) | ||
1148 | { | ||
1149 | case TEST_HOST_ANSWER_DOOR_REFUSE: | ||
1150 | test = TEST_GUEST_RECV_ENTRY_DCSN_REFUSE; | ||
1151 | join_resp = GNUNET_PSYC_message_create ("_notice_place_refuse", env, | ||
1152 | DATA2ARG ("Go away!")); | ||
1153 | GNUNET_SOCIAL_host_entry_decision (hst, nym, GNUNET_NO, join_resp); | ||
1154 | break; | ||
1155 | |||
1156 | case TEST_HOST_ANSWER_DOOR_ADMIT: | ||
1157 | test = TEST_GUEST_RECV_ENTRY_DCSN_ADMIT; | ||
1158 | // fall through | ||
1159 | |||
1160 | case TEST_GUEST_ENTER_BY_NAME: | ||
1161 | join_resp = GNUNET_PSYC_message_create ("_notice_place_admit", env, | ||
1162 | DATA2ARG ("Welcome, nym!")); | ||
1163 | GNUNET_SOCIAL_host_entry_decision (hst, nym, GNUNET_YES, join_resp); | ||
1164 | break; | ||
1165 | |||
1166 | default: | ||
1167 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid test: #%u\n", test); | ||
1168 | GNUNET_assert (0); | ||
1169 | } | ||
1170 | } | ||
1171 | |||
1172 | |||
1173 | static void | ||
1174 | guest_recv_local_enter (void *cls, int result, | ||
1175 | const struct GNUNET_CRYPTO_EddsaPublicKey *place_pub_key, | ||
1176 | uint64_t max_message_id) | ||
1177 | { | ||
1178 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
1179 | "Test #%u: Guest entered local place: %d\n", | ||
1180 | test, result); | ||
1181 | GNUNET_assert (GNUNET_OK == result); | ||
1182 | } | ||
1183 | |||
1184 | |||
1185 | static void | ||
1186 | guest_enter () | ||
1187 | { | ||
1188 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
1189 | "Test #%u: Entering place as guest.\n", test); | ||
1190 | |||
1191 | struct GuestEnterMessage *emsg = &guest_enter_msg; | ||
1192 | |||
1193 | emsg->method_name = "_request_enter"; | ||
1194 | emsg->env = GNUNET_PSYC_env_create (); | ||
1195 | GNUNET_PSYC_env_add (emsg->env, GNUNET_PSYC_OP_ASSIGN, | ||
1196 | "_abc", "abc def", 7); | ||
1197 | GNUNET_PSYC_env_add (emsg->env, GNUNET_PSYC_OP_ASSIGN, | ||
1198 | "_abc_def", "abc def ghi", 11); | ||
1199 | emsg->data = "let me in"; | ||
1200 | emsg->data_size = strlen (emsg->data) + 1; | ||
1201 | emsg->msg = GNUNET_PSYC_message_create (emsg->method_name, emsg->env, | ||
1202 | emsg->data, emsg->data_size); | ||
1203 | |||
1204 | gst = GNUNET_SOCIAL_guest_enter (app, guest_ego, &place_pub_key, | ||
1205 | GNUNET_PSYC_SLAVE_JOIN_NONE, | ||
1206 | &this_peer, 0, NULL, emsg->msg, guest_slicer, | ||
1207 | guest_recv_local_enter, | ||
1208 | guest_recv_entry_decision, NULL); | ||
1209 | gst_plc = GNUNET_SOCIAL_guest_get_place (gst); | ||
1210 | |||
1211 | GNUNET_SOCIAL_place_msg_proc_set (gst_plc, "_converse", | ||
1212 | GNUNET_SOCIAL_MSG_PROC_SAVE); | ||
1213 | } | ||
1214 | |||
1215 | |||
1216 | static void | ||
1217 | guest_enter_by_name () | ||
1218 | { | ||
1219 | test = TEST_GUEST_ENTER_BY_NAME; | ||
1220 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
1221 | "Test #%u: Entering place by name as guest.\n", test); | ||
1222 | |||
1223 | struct GuestEnterMessage *emsg = &guest_enter_msg; | ||
1224 | |||
1225 | emsg->method_name = "_request_enter"; | ||
1226 | emsg->env = GNUNET_PSYC_env_create (); | ||
1227 | GNUNET_PSYC_env_add (emsg->env, GNUNET_PSYC_OP_ASSIGN, | ||
1228 | "_abc", "abc def", 7); | ||
1229 | GNUNET_PSYC_env_add (emsg->env, GNUNET_PSYC_OP_ASSIGN, | ||
1230 | "_abc_def", "abc def ghi", 11); | ||
1231 | emsg->data = "let me in"; | ||
1232 | emsg->data_size = strlen (emsg->data) + 1; | ||
1233 | emsg->msg = GNUNET_PSYC_message_create (emsg->method_name, emsg->env, | ||
1234 | emsg->data, emsg->data_size); | ||
1235 | |||
1236 | gst = GNUNET_SOCIAL_guest_enter_by_name (app, guest_ego, | ||
1237 | "home.host.gnu", "let.me*in!", | ||
1238 | emsg->msg, guest_slicer, | ||
1239 | guest_recv_local_enter, | ||
1240 | guest_recv_entry_decision, NULL); | ||
1241 | gst_plc = GNUNET_SOCIAL_guest_get_place (gst); | ||
1242 | } | ||
1243 | |||
1244 | |||
1245 | static void | ||
1246 | app_recv_zone_add_nym_result (void *cls, int64_t result, | ||
1247 | const void *data, uint16_t data_size) | ||
1248 | { | ||
1249 | GNUNET_assert (GNUNET_YES == result); | ||
1250 | is_guest_nym_added = GNUNET_YES; | ||
1251 | } | ||
1252 | |||
1253 | |||
1254 | static void | ||
1255 | guest_init () | ||
1256 | { | ||
1257 | guest_pub_key = GNUNET_SOCIAL_ego_get_pub_key (guest_ego); | ||
1258 | |||
1259 | guest_slicer = GNUNET_PSYC_slicer_create (); | ||
1260 | GNUNET_PSYC_slicer_method_add (guest_slicer, "", NULL, | ||
1261 | guest_recv_method, guest_recv_modifier, | ||
1262 | guest_recv_data, guest_recv_eom, NULL); | ||
1263 | GNUNET_PSYC_slicer_modifier_add (guest_slicer, "_foo_bar", | ||
1264 | guest_recv_mod_foo_bar, &mod_foo_bar_rcls); | ||
1265 | test = TEST_HOST_ANSWER_DOOR_REFUSE; | ||
1266 | |||
1267 | GNUNET_SOCIAL_zone_add_nym (app, guest_ego, "host", host_pub_key, | ||
1268 | GNUNET_TIME_relative_to_absolute (GNUNET_TIME_UNIT_MINUTES), | ||
1269 | app_recv_zone_add_nym_result, NULL); | ||
1270 | } | ||
1271 | |||
1272 | |||
1273 | static void | ||
1274 | id_host_created (void *cls, const char *emsg) | ||
1275 | { | ||
1276 | if (NULL != emsg) | ||
1277 | { | ||
1278 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1279 | "Test #%u: Could not create host identity: %s\n", | ||
1280 | test, emsg); | ||
1281 | #if ! DEBUG_TEST_SOCIAL | ||
1282 | GNUNET_assert (0); | ||
1283 | #endif | ||
1284 | } | ||
1285 | |||
1286 | } | ||
1287 | |||
1288 | |||
1289 | static void | ||
1290 | id_guest_created (void *cls, const char *emsg) | ||
1291 | { | ||
1292 | if (NULL != emsg) | ||
1293 | { | ||
1294 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1295 | "Test #%u: Could not create guest identity: %s\n", | ||
1296 | test, emsg); | ||
1297 | #if ! DEBUG_TEST_SOCIAL | ||
1298 | GNUNET_assert (0); | ||
1299 | #endif | ||
1300 | } | ||
1301 | //if (NULL != guest_ego) | ||
1302 | // guest_init (); | ||
1303 | } | ||
1304 | |||
1305 | |||
1306 | static void | ||
1307 | host_entered (void *cls, int result, | ||
1308 | const struct GNUNET_CRYPTO_EddsaPublicKey *home_pub_key, | ||
1309 | uint64_t max_message_id) | ||
1310 | { | ||
1311 | place_pub_key = *home_pub_key; | ||
1312 | GNUNET_CRYPTO_hash (&place_pub_key, sizeof (place_pub_key), &place_pub_hash); | ||
1313 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
1314 | "Test #%u: Host entered place %s\n", | ||
1315 | test, GNUNET_h2s (&place_pub_hash)); | ||
1316 | guest_enter (); | ||
1317 | } | ||
1318 | |||
1319 | |||
1320 | static void | ||
1321 | host_enter () | ||
1322 | { | ||
1323 | host_slicer = GNUNET_PSYC_slicer_create (); | ||
1324 | GNUNET_PSYC_slicer_method_add (host_slicer, "", NULL, | ||
1325 | host_recv_method, host_recv_modifier, | ||
1326 | host_recv_data, host_recv_eom, NULL); | ||
1327 | |||
1328 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
1329 | "Test #%u: Entering place as host.\n", test); | ||
1330 | test = TEST_HOST_ENTER; | ||
1331 | hst = GNUNET_SOCIAL_host_enter (app, host_ego, | ||
1332 | GNUNET_PSYC_CHANNEL_PRIVATE, | ||
1333 | host_slicer, host_entered, | ||
1334 | host_answer_door, host_farewell, NULL); | ||
1335 | hst_plc = GNUNET_SOCIAL_host_get_place (hst); | ||
1336 | |||
1337 | GNUNET_SOCIAL_place_msg_proc_set (hst_plc, "_converse", | ||
1338 | GNUNET_SOCIAL_MSG_PROC_RELAY); | ||
1339 | } | ||
1340 | |||
1341 | |||
1342 | static void | ||
1343 | start_app_if_ready () | ||
1344 | { | ||
1345 | if (NULL == identity_host_ego || NULL == identity_guest_ego) | ||
1346 | { | ||
1347 | return; | ||
1348 | } | ||
1349 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
1350 | "starting app...\n"); | ||
1351 | app = GNUNET_SOCIAL_app_connect (cfg, | ||
1352 | app_id, | ||
1353 | app_recv_ego, | ||
1354 | app_recv_host, | ||
1355 | app_recv_guest, | ||
1356 | app_connected, | ||
1357 | NULL); | ||
1358 | } | ||
1359 | |||
1360 | |||
1361 | static void | ||
1362 | identity_ego_cb (void *cls, struct GNUNET_IDENTITY_Ego *ego, | ||
1363 | void **ctx, const char *name) | ||
1364 | { | ||
1365 | if (NULL != ego) | ||
1366 | { | ||
1367 | if (ego == identity_host_ego) | ||
1368 | { | ||
1369 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
1370 | "Host ego deleted\n"); | ||
1371 | } | ||
1372 | else if (ego == identity_guest_ego) | ||
1373 | { | ||
1374 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
1375 | "Guest ego deleted\n"); | ||
1376 | } | ||
1377 | else if (0 == strcmp (name, host_name)) | ||
1378 | { | ||
1379 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
1380 | "Created ego %s\n", | ||
1381 | name); | ||
1382 | identity_host_ego = ego; | ||
1383 | start_app_if_ready (); | ||
1384 | } | ||
1385 | else if (0 == strcmp (name, guest_name)) | ||
1386 | { | ||
1387 | GNUNET_log (GNUNET_ERROR_TYPE_MESSAGE, | ||
1388 | "Created guest ego %s\n", | ||
1389 | name); | ||
1390 | identity_guest_ego = ego; | ||
1391 | start_app_if_ready (); | ||
1392 | } | ||
1393 | } | ||
1394 | } | ||
1395 | |||
1396 | |||
1397 | /** | ||
1398 | * Main function of the test, run from scheduler. | ||
1399 | * | ||
1400 | * @param cls NULL | ||
1401 | * @param cfg configuration we use (also to connect to Social service) | ||
1402 | * @param peer handle to access more of the peer (not used) | ||
1403 | */ | ||
1404 | static void | ||
1405 | #if DEBUG_TEST_SOCIAL | ||
1406 | run (void *cls, char *const *args, const char *cfgfile, | ||
1407 | const struct GNUNET_CONFIGURATION_Handle *c) | ||
1408 | #else | ||
1409 | run (void *cls, | ||
1410 | const struct GNUNET_CONFIGURATION_Handle *c, | ||
1411 | struct GNUNET_TESTING_Peer *peer) | ||
1412 | #endif | ||
1413 | { | ||
1414 | cfg = c; | ||
1415 | res = 1; | ||
1416 | end_badly_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, | ||
1417 | &end_badly, NULL); | ||
1418 | GNUNET_SCHEDULER_add_shutdown (&end_shutdown, | ||
1419 | NULL); | ||
1420 | GNUNET_CRYPTO_get_peer_identity (cfg, &this_peer); | ||
1421 | |||
1422 | id = GNUNET_IDENTITY_connect (cfg, &identity_ego_cb, NULL); | ||
1423 | |||
1424 | test = TEST_IDENTITIES_CREATE; | ||
1425 | GNUNET_IDENTITY_create (id, host_name, &id_host_created, NULL); | ||
1426 | GNUNET_IDENTITY_create (id, guest_name, &id_guest_created, NULL); | ||
1427 | } | ||
1428 | |||
1429 | |||
1430 | int | ||
1431 | main (int argc, char *argv[]) | ||
1432 | { | ||
1433 | res = 1; | ||
1434 | #if DEBUG_TEST_SOCIAL | ||
1435 | const struct GNUNET_GETOPT_CommandLineOption opts[] = { | ||
1436 | GNUNET_GETOPT_OPTION_END | ||
1437 | }; | ||
1438 | if (GNUNET_OK != GNUNET_PROGRAM_run (argc, argv, "test-social", | ||
1439 | "test-social [options]", | ||
1440 | opts, &run, NULL)) | ||
1441 | return 1; | ||
1442 | #else | ||
1443 | if (0 != GNUNET_TESTING_peer_run ("test-social", "test_social.conf", &run, NULL)) | ||
1444 | return 1; | ||
1445 | #endif | ||
1446 | return res; | ||
1447 | } | ||
1448 | |||
1449 | /* end of test_social.c */ | ||
diff --git a/src/social/test_social.conf b/src/social/test_social.conf deleted file mode 100644 index bc487760f..000000000 --- a/src/social/test_social.conf +++ /dev/null | |||
@@ -1,19 +0,0 @@ | |||
1 | @INLINE@ ../../contrib/conf/gnunet/no_forcestart.conf | ||
2 | |||
3 | [PATHS] | ||
4 | GNUNET_TEST_HOME = $GNUNET_TMP/gnunet-test-social/ | ||
5 | |||
6 | [social] | ||
7 | IMMEDIATE_START = YES | ||
8 | |||
9 | [transport] | ||
10 | PLUGINS = tcp | ||
11 | |||
12 | [nat] | ||
13 | DISABLEV6 = YES | ||
14 | ENABLE_UPNP = NO | ||
15 | BEHIND_NAT = NO | ||
16 | ALLOW_NAT = NO | ||
17 | INTERNAL_ADDRESS = 127.0.0.1 | ||
18 | EXTERNAL_ADDRESS = 127.0.0.1 | ||
19 | |||