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