diff options
Diffstat (limited to 'src/service/namestore/namestore_api_monitor.c')
-rw-r--r-- | src/service/namestore/namestore_api_monitor.c | 443 |
1 files changed, 443 insertions, 0 deletions
diff --git a/src/service/namestore/namestore_api_monitor.c b/src/service/namestore/namestore_api_monitor.c new file mode 100644 index 000000000..ec4ba879b --- /dev/null +++ b/src/service/namestore/namestore_api_monitor.c | |||
@@ -0,0 +1,443 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2013, 2016, 2018 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 namestore/namestore_api_monitor.c | ||
22 | * @brief API to monitor changes in the NAMESTORE | ||
23 | * @author Christian Grothoff | ||
24 | */ | ||
25 | |||
26 | #include "platform.h" | ||
27 | #include "gnunet_util_lib.h" | ||
28 | #include "gnunet_constants.h" | ||
29 | #include "gnunet_arm_service.h" | ||
30 | #include "gnunet_signatures.h" | ||
31 | #include "gnunet_namestore_service.h" | ||
32 | #include "namestore.h" | ||
33 | |||
34 | |||
35 | /** | ||
36 | * Handle for a monitoring activity. | ||
37 | */ | ||
38 | struct GNUNET_NAMESTORE_ZoneMonitor | ||
39 | { | ||
40 | /** | ||
41 | * Configuration (to reconnect). | ||
42 | */ | ||
43 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
44 | |||
45 | /** | ||
46 | * Handle to namestore service. | ||
47 | */ | ||
48 | struct GNUNET_MQ_Handle *mq; | ||
49 | |||
50 | /** | ||
51 | * Function to call on errors. | ||
52 | */ | ||
53 | GNUNET_SCHEDULER_TaskCallback error_cb; | ||
54 | |||
55 | /** | ||
56 | * Closure for @e error_cb. | ||
57 | */ | ||
58 | void *error_cb_cls; | ||
59 | |||
60 | /** | ||
61 | * Function to call on events. | ||
62 | */ | ||
63 | GNUNET_NAMESTORE_RecordMonitor monitor; | ||
64 | |||
65 | /** | ||
66 | * Function to call on events. | ||
67 | */ | ||
68 | GNUNET_NAMESTORE_RecordSetMonitor monitor2; | ||
69 | |||
70 | /** | ||
71 | * Record set filter for this monitor | ||
72 | */ | ||
73 | enum GNUNET_GNSRECORD_Filter filter; | ||
74 | |||
75 | /** | ||
76 | * Closure for @e monitor. | ||
77 | */ | ||
78 | void *monitor_cls; | ||
79 | |||
80 | /** | ||
81 | * Function called when we've synchronized. | ||
82 | */ | ||
83 | GNUNET_SCHEDULER_TaskCallback sync_cb; | ||
84 | |||
85 | /** | ||
86 | * Closure for @e sync_cb. | ||
87 | */ | ||
88 | void *sync_cb_cls; | ||
89 | |||
90 | /** | ||
91 | * Monitored zone. | ||
92 | */ | ||
93 | struct GNUNET_CRYPTO_PrivateKey zone; | ||
94 | |||
95 | /** | ||
96 | * Do we first iterate over all existing records? | ||
97 | */ | ||
98 | int iterate_first; | ||
99 | |||
100 | /** | ||
101 | * Zone key length | ||
102 | */ | ||
103 | uint32_t key_len; | ||
104 | }; | ||
105 | |||
106 | |||
107 | /** | ||
108 | * Reconnect to the namestore service. | ||
109 | * | ||
110 | * @param zm monitor to reconnect | ||
111 | */ | ||
112 | static void | ||
113 | reconnect (struct GNUNET_NAMESTORE_ZoneMonitor *zm); | ||
114 | |||
115 | |||
116 | /** | ||
117 | * Handle SYNC message from the namestore service. | ||
118 | * | ||
119 | * @param cls the monitor | ||
120 | * @param msg the sync message | ||
121 | */ | ||
122 | static void | ||
123 | handle_sync (void *cls, const struct GNUNET_MessageHeader *msg) | ||
124 | { | ||
125 | struct GNUNET_NAMESTORE_ZoneMonitor *zm = cls; | ||
126 | |||
127 | (void) cls; | ||
128 | (void) msg; | ||
129 | if (NULL != zm->sync_cb) | ||
130 | zm->sync_cb (zm->sync_cb_cls); | ||
131 | } | ||
132 | |||
133 | |||
134 | /** | ||
135 | * We've received a notification about a change to our zone. | ||
136 | * Check that it is well-formed. | ||
137 | * | ||
138 | * @param cls the zone monitor handle | ||
139 | * @param lrm the message from the service. | ||
140 | */ | ||
141 | static int | ||
142 | check_result (void *cls, const struct RecordResultMessage *lrm) | ||
143 | { | ||
144 | struct GNUNET_NAMESTORE_ZoneMonitor *zm = cls; | ||
145 | size_t lrm_len; | ||
146 | size_t exp_lrm_len; | ||
147 | size_t name_len; | ||
148 | size_t rd_len; | ||
149 | unsigned rd_count; | ||
150 | const char *name_tmp; | ||
151 | const char *rd_ser_tmp; | ||
152 | size_t key_len; | ||
153 | |||
154 | (void) zm; | ||
155 | key_len = ntohs (lrm->key_len); | ||
156 | (void) cls; | ||
157 | if (0 == key_len) | ||
158 | { | ||
159 | GNUNET_break (0); | ||
160 | return GNUNET_SYSERR; | ||
161 | } | ||
162 | lrm_len = ntohs (lrm->gns_header.header.size); | ||
163 | rd_len = ntohs (lrm->rd_len); | ||
164 | rd_count = ntohs (lrm->rd_count); | ||
165 | name_len = ntohs (lrm->name_len); | ||
166 | if (name_len > MAX_NAME_LEN) | ||
167 | { | ||
168 | GNUNET_break (0); | ||
169 | return GNUNET_SYSERR; | ||
170 | } | ||
171 | exp_lrm_len = sizeof(struct RecordResultMessage) + name_len + rd_len + key_len; | ||
172 | if (lrm_len != exp_lrm_len) | ||
173 | { | ||
174 | GNUNET_break (0); | ||
175 | return GNUNET_SYSERR; | ||
176 | } | ||
177 | if (0 == name_len) | ||
178 | { | ||
179 | GNUNET_break (0); | ||
180 | return GNUNET_SYSERR; | ||
181 | } | ||
182 | name_tmp = (const char *) &lrm[1] + key_len; | ||
183 | if (name_tmp[name_len - 1] != '\0') | ||
184 | { | ||
185 | GNUNET_break (0); | ||
186 | return GNUNET_SYSERR; | ||
187 | } | ||
188 | rd_ser_tmp = (const char *) &name_tmp[name_len]; | ||
189 | { | ||
190 | struct GNUNET_GNSRECORD_Data rd[rd_count]; | ||
191 | |||
192 | if (GNUNET_OK != | ||
193 | GNUNET_GNSRECORD_records_deserialize (rd_len, rd_ser_tmp, rd_count, rd)) | ||
194 | { | ||
195 | GNUNET_break (0); | ||
196 | return GNUNET_SYSERR; | ||
197 | } | ||
198 | } | ||
199 | return GNUNET_OK; | ||
200 | } | ||
201 | |||
202 | |||
203 | /** | ||
204 | * We've received a notification about a change to our zone. | ||
205 | * Forward to monitor callback. | ||
206 | * | ||
207 | * @param cls the zone monitor handle | ||
208 | * @param lrm the message from the service. | ||
209 | */ | ||
210 | static void | ||
211 | handle_result (void *cls, const struct RecordResultMessage *lrm) | ||
212 | { | ||
213 | struct GNUNET_NAMESTORE_ZoneMonitor *zm = cls; | ||
214 | struct GNUNET_CRYPTO_PrivateKey private_key; | ||
215 | size_t name_len; | ||
216 | size_t rd_len; | ||
217 | size_t key_len; | ||
218 | size_t kbytes_read; | ||
219 | unsigned rd_count; | ||
220 | const char *name_tmp; | ||
221 | const char *rd_ser_tmp; | ||
222 | |||
223 | key_len = ntohs (lrm->key_len); | ||
224 | rd_len = ntohs (lrm->rd_len); | ||
225 | rd_count = ntohs (lrm->rd_count); | ||
226 | name_len = ntohs (lrm->name_len); | ||
227 | name_tmp = (const char *) &lrm[1] + key_len; | ||
228 | GNUNET_assert (GNUNET_SYSERR != | ||
229 | GNUNET_CRYPTO_read_private_key_from_buffer (&lrm[1], | ||
230 | key_len, | ||
231 | &private_key, | ||
232 | &kbytes_read)); | ||
233 | GNUNET_assert (kbytes_read == key_len); | ||
234 | rd_ser_tmp = (const char *) &name_tmp[name_len]; | ||
235 | { | ||
236 | struct GNUNET_GNSRECORD_Data rd[rd_count]; | ||
237 | |||
238 | GNUNET_assert ( | ||
239 | GNUNET_OK == | ||
240 | GNUNET_GNSRECORD_records_deserialize (rd_len, rd_ser_tmp, rd_count, rd)); | ||
241 | if (NULL != zm->monitor2) | ||
242 | zm->monitor2 (zm->monitor_cls, &private_key, name_tmp, | ||
243 | rd_count, rd, GNUNET_TIME_absolute_ntoh (lrm->expire)); | ||
244 | else | ||
245 | zm->monitor (zm->monitor_cls, &private_key, name_tmp, rd_count, rd); | ||
246 | } | ||
247 | } | ||
248 | |||
249 | |||
250 | /** | ||
251 | * Generic error handler, called with the appropriate error code and | ||
252 | * the same closure specified at the creation of the message queue. | ||
253 | * Not every message queue implementation supports an error handler. | ||
254 | * | ||
255 | * @param cls closure with the `struct GNUNET_NAMESTORE_ZoneMonitor *` | ||
256 | * @param error error code | ||
257 | */ | ||
258 | static void | ||
259 | mq_error_handler (void *cls, enum GNUNET_MQ_Error error) | ||
260 | { | ||
261 | struct GNUNET_NAMESTORE_ZoneMonitor *zm = cls; | ||
262 | |||
263 | (void) error; | ||
264 | reconnect (zm); | ||
265 | } | ||
266 | |||
267 | |||
268 | /** | ||
269 | * Reconnect to the namestore service. | ||
270 | * | ||
271 | * @param zm monitor to reconnect | ||
272 | */ | ||
273 | static void | ||
274 | reconnect (struct GNUNET_NAMESTORE_ZoneMonitor *zm) | ||
275 | { | ||
276 | struct GNUNET_MQ_MessageHandler handlers[] = | ||
277 | { GNUNET_MQ_hd_fixed_size (sync, | ||
278 | GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_SYNC, | ||
279 | struct GNUNET_MessageHeader, | ||
280 | zm), | ||
281 | GNUNET_MQ_hd_var_size (result, | ||
282 | GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT, | ||
283 | struct RecordResultMessage, | ||
284 | zm), | ||
285 | GNUNET_MQ_handler_end () }; | ||
286 | struct GNUNET_MQ_Envelope *env; | ||
287 | struct ZoneMonitorStartMessage *sm; | ||
288 | |||
289 | if (NULL != zm->mq) | ||
290 | { | ||
291 | GNUNET_MQ_destroy (zm->mq); | ||
292 | zm->error_cb (zm->error_cb_cls); | ||
293 | } | ||
294 | zm->mq = GNUNET_CLIENT_connect (zm->cfg, | ||
295 | "namestore", | ||
296 | handlers, | ||
297 | &mq_error_handler, | ||
298 | zm); | ||
299 | if (NULL == zm->mq) | ||
300 | return; | ||
301 | env = GNUNET_MQ_msg_extra (sm, | ||
302 | zm->key_len, | ||
303 | GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_START); | ||
304 | sm->iterate_first = htonl (zm->iterate_first); | ||
305 | if (0 < zm->key_len) | ||
306 | GNUNET_CRYPTO_write_private_key_to_buffer (&zm->zone, | ||
307 | &sm[1], | ||
308 | zm->key_len); | ||
309 | sm->key_len = htons (zm->key_len); | ||
310 | sm->filter = htons (zm->filter); | ||
311 | GNUNET_MQ_send (zm->mq, env); | ||
312 | } | ||
313 | |||
314 | |||
315 | struct GNUNET_NAMESTORE_ZoneMonitor * | ||
316 | GNUNET_NAMESTORE_zone_monitor_start ( | ||
317 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
318 | const struct GNUNET_CRYPTO_PrivateKey *zone, | ||
319 | int iterate_first, | ||
320 | GNUNET_SCHEDULER_TaskCallback error_cb, | ||
321 | void *error_cb_cls, | ||
322 | GNUNET_NAMESTORE_RecordMonitor monitor, | ||
323 | void *monitor_cls, | ||
324 | GNUNET_SCHEDULER_TaskCallback sync_cb, | ||
325 | void *sync_cb_cls) | ||
326 | { | ||
327 | struct GNUNET_NAMESTORE_ZoneMonitor *zm; | ||
328 | |||
329 | zm = GNUNET_new (struct GNUNET_NAMESTORE_ZoneMonitor); | ||
330 | if (NULL != zone) | ||
331 | { | ||
332 | zm->key_len = GNUNET_CRYPTO_private_key_get_length (zone); | ||
333 | zm->zone = *zone; | ||
334 | } | ||
335 | zm->iterate_first = iterate_first; | ||
336 | zm->error_cb = error_cb; | ||
337 | zm->error_cb_cls = error_cb_cls; | ||
338 | zm->monitor = monitor; | ||
339 | zm->monitor_cls = monitor_cls; | ||
340 | zm->sync_cb = sync_cb; | ||
341 | zm->sync_cb_cls = sync_cb_cls; | ||
342 | zm->cfg = cfg; | ||
343 | reconnect (zm); | ||
344 | if (NULL == zm->mq) | ||
345 | { | ||
346 | GNUNET_free (zm); | ||
347 | return NULL; | ||
348 | } | ||
349 | return zm; | ||
350 | } | ||
351 | |||
352 | struct GNUNET_NAMESTORE_ZoneMonitor * | ||
353 | GNUNET_NAMESTORE_zone_monitor_start2 ( | ||
354 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
355 | const struct GNUNET_CRYPTO_PrivateKey *zone, | ||
356 | int iterate_first, | ||
357 | GNUNET_SCHEDULER_TaskCallback error_cb, | ||
358 | void *error_cb_cls, | ||
359 | GNUNET_NAMESTORE_RecordSetMonitor monitor, | ||
360 | void *monitor_cls, | ||
361 | GNUNET_SCHEDULER_TaskCallback sync_cb, | ||
362 | void *sync_cb_cls, | ||
363 | enum GNUNET_GNSRECORD_Filter filter) | ||
364 | { | ||
365 | struct GNUNET_NAMESTORE_ZoneMonitor *zm; | ||
366 | |||
367 | zm = GNUNET_new (struct GNUNET_NAMESTORE_ZoneMonitor); | ||
368 | if (NULL != zone) | ||
369 | { | ||
370 | zm->key_len = GNUNET_CRYPTO_private_key_get_length (zone); | ||
371 | zm->zone = *zone; | ||
372 | } | ||
373 | zm->iterate_first = iterate_first; | ||
374 | zm->error_cb = error_cb; | ||
375 | zm->error_cb_cls = error_cb_cls; | ||
376 | zm->monitor2 = monitor; | ||
377 | zm->monitor_cls = monitor_cls; | ||
378 | zm->sync_cb = sync_cb; | ||
379 | zm->sync_cb_cls = sync_cb_cls; | ||
380 | zm->cfg = cfg; | ||
381 | zm->filter = filter; | ||
382 | reconnect (zm); | ||
383 | if (NULL == zm->mq) | ||
384 | { | ||
385 | GNUNET_free (zm); | ||
386 | return NULL; | ||
387 | } | ||
388 | return zm; | ||
389 | } | ||
390 | |||
391 | |||
392 | /** | ||
393 | * Calls the monitor processor specified in #GNUNET_NAMESTORE_zone_monitor_start | ||
394 | * for the next record(s). This function is used to allow clients that merely | ||
395 | * monitor the NAMESTORE to still throttle namestore operations, so we can be | ||
396 | * sure that the monitors can keep up. | ||
397 | * | ||
398 | * Note that #GNUNET_NAMESTORE_records_store() only waits for this | ||
399 | * call if the previous limit set by the client was already reached. | ||
400 | * Thus, by using a @a limit greater than 1, monitors basically enable | ||
401 | * a queue of notifications to be processed asynchronously with some | ||
402 | * delay. Note that even with a limit of 1 the | ||
403 | * #GNUNET_NAMESTORE_records_store() function will run asynchronously | ||
404 | * and the continuation may be invoked before the monitors completed | ||
405 | * (or even started) processing the notification. Thus, monitors will | ||
406 | * only closely track the current state of the namestore, but not | ||
407 | * be involved in the transactions. | ||
408 | * | ||
409 | * @param zm the monitor | ||
410 | * @param limit number of records to return to the iterator in one shot | ||
411 | * (before #GNUNET_NAMESTORE_zone_monitor_next is to be called again) | ||
412 | */ | ||
413 | void | ||
414 | GNUNET_NAMESTORE_zone_monitor_next (struct GNUNET_NAMESTORE_ZoneMonitor *zm, | ||
415 | uint64_t limit) | ||
416 | { | ||
417 | struct GNUNET_MQ_Envelope *env; | ||
418 | struct ZoneMonitorNextMessage *nm; | ||
419 | |||
420 | env = GNUNET_MQ_msg (nm, GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_NEXT); | ||
421 | nm->limit = GNUNET_htonll (limit); | ||
422 | GNUNET_MQ_send (zm->mq, env); | ||
423 | } | ||
424 | |||
425 | |||
426 | /** | ||
427 | * Stop monitoring a zone for changes. | ||
428 | * | ||
429 | * @param zm handle to the monitor activity to stop | ||
430 | */ | ||
431 | void | ||
432 | GNUNET_NAMESTORE_zone_monitor_stop (struct GNUNET_NAMESTORE_ZoneMonitor *zm) | ||
433 | { | ||
434 | if (NULL != zm->mq) | ||
435 | { | ||
436 | GNUNET_MQ_destroy (zm->mq); | ||
437 | zm->mq = NULL; | ||
438 | } | ||
439 | GNUNET_free (zm); | ||
440 | } | ||
441 | |||
442 | |||
443 | /* end of namestore_api_monitor.c */ | ||