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