diff options
author | Christian Grothoff <christian@grothoff.org> | 2019-02-11 20:39:36 +0100 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2019-02-11 20:39:36 +0100 |
commit | 1f59e703d82b47f3aeaf432045a2633c2841169b (patch) | |
tree | 6af5609b388cf1906a29b5d572bec2dd8fb2ae1c /src/psycstore/psycstore_api.c | |
download | gnunet-secushare-1f59e703d82b47f3aeaf432045a2633c2841169b.tar.gz gnunet-secushare-1f59e703d82b47f3aeaf432045a2633c2841169b.zip |
initial import from gnunet.git
Diffstat (limited to 'src/psycstore/psycstore_api.c')
-rw-r--r-- | src/psycstore/psycstore_api.c | 1285 |
1 files changed, 1285 insertions, 0 deletions
diff --git a/src/psycstore/psycstore_api.c b/src/psycstore/psycstore_api.c new file mode 100644 index 0000000..ab4cd0f --- /dev/null +++ b/src/psycstore/psycstore_api.c | |||
@@ -0,0 +1,1285 @@ | |||
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 */ | ||