-coverity
[oweals/gnunet.git] / src / namestore / namestore_api_monitor.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2013, 2016 GNUnet e.V.
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      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      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18      Boston, MA 02110-1301, USA.
19 */
20
21 /**
22  * @file namestore/namestore_api_monitor.c
23  * @brief API to monitor changes in the NAMESTORE
24  * @author Christian Grothoff
25  */
26
27 #include "platform.h"
28 #include "gnunet_util_lib.h"
29 #include "gnunet_crypto_lib.h"
30 #include "gnunet_constants.h"
31 #include "gnunet_dnsparser_lib.h"
32 #include "gnunet_arm_service.h"
33 #include "gnunet_signatures.h"
34 #include "gnunet_namestore_service.h"
35 #include "namestore.h"
36
37
38 /**
39  * Handle for a monitoring activity.
40  */
41 struct GNUNET_NAMESTORE_ZoneMonitor
42 {
43   /**
44    * Configuration (to reconnect).
45    */
46   const struct GNUNET_CONFIGURATION_Handle *cfg;
47
48   /**
49    * Handle to namestore service.
50    */
51   struct GNUNET_MQ_Handle *mq;
52
53   /**
54    * Function to call on events.
55    */
56   GNUNET_NAMESTORE_RecordMonitor monitor;
57
58   /**
59    * Function called when we've synchronized.
60    */
61   GNUNET_NAMESTORE_RecordsSynchronizedCallback sync_cb;
62
63   /**
64    * Closure for @e monitor and @e sync_cb.
65    */
66   void *cls;
67
68   /**
69    * Monitored zone.
70    */
71   struct GNUNET_CRYPTO_EcdsaPrivateKey zone;
72
73   /**
74    * Do we first iterate over all existing records?
75    */
76   int iterate_first;
77
78 };
79
80
81 /**
82  * Reconnect to the namestore service.
83  *
84  * @param zm monitor to reconnect
85  */
86 static void
87 reconnect (struct GNUNET_NAMESTORE_ZoneMonitor *zm);
88
89
90 /**
91  * Handle SYNC message from the namestore service.
92  *
93  * @param cls the monitor
94  * @param msg the sync message
95  */
96 static void
97 handle_sync (void *cls,
98              const struct GNUNET_MessageHeader *msg)
99 {
100   struct GNUNET_NAMESTORE_ZoneMonitor *zm = cls;
101
102   if (NULL != zm->sync_cb)
103     zm->sync_cb (zm->cls);
104 }
105
106
107 /**
108  * We've received a notification about a change to our zone.
109  * Check that it is well-formed.
110  *
111  * @param cls the zone monitor handle
112  * @param lrm the message from the service.
113  */
114 static int
115 check_result (void *cls,
116               const struct RecordResultMessage *lrm)
117 {
118   size_t lrm_len;
119   size_t exp_lrm_len;
120   size_t name_len;
121   size_t rd_len;
122   unsigned rd_count;
123   const char *name_tmp;
124   const char *rd_ser_tmp;
125
126   lrm_len = ntohs (lrm->gns_header.header.size);
127   rd_len = ntohs (lrm->rd_len);
128   rd_count = ntohs (lrm->rd_count);
129   name_len = ntohs (lrm->name_len);
130   exp_lrm_len = sizeof (struct RecordResultMessage) + name_len + rd_len;
131   if (lrm_len != exp_lrm_len)
132   {
133     GNUNET_break (0);
134     return GNUNET_SYSERR;
135   }
136   if (0 == name_len)
137   {
138     GNUNET_break (0);
139     return GNUNET_SYSERR;
140   }
141   name_tmp = (const char *) &lrm[1];
142   if ((name_tmp[name_len -1] != '\0') || (name_len > MAX_NAME_LEN))
143   {
144     GNUNET_break (0);
145     return GNUNET_SYSERR;
146   }
147   rd_ser_tmp = (const char *) &name_tmp[name_len];
148   {
149     struct GNUNET_GNSRECORD_Data rd[rd_count];
150
151     if (GNUNET_OK !=
152         GNUNET_GNSRECORD_records_deserialize (rd_len,
153                                               rd_ser_tmp,
154                                               rd_count,
155                                               rd))
156     {
157       GNUNET_break (0);
158       return GNUNET_SYSERR;
159     }
160   }
161   return GNUNET_OK;
162 }
163
164
165 /**
166  * We've received a notification about a change to our zone.
167  * Forward to monitor callback.
168  *
169  * @param cls the zone monitor handle
170  * @param lrm the message from the service.
171  */
172 static void
173 handle_result (void *cls,
174                const struct RecordResultMessage *lrm)
175 {
176   struct GNUNET_NAMESTORE_ZoneMonitor *zm = cls;
177   size_t name_len;
178   size_t rd_len;
179   unsigned rd_count;
180   const char *name_tmp;
181   const char *rd_ser_tmp;
182
183   rd_len = ntohs (lrm->rd_len);
184   rd_count = ntohs (lrm->rd_count);
185   name_len = ntohs (lrm->name_len);
186   name_tmp = (const char *) &lrm[1];
187   rd_ser_tmp = (const char *) &name_tmp[name_len];
188   {
189     struct GNUNET_GNSRECORD_Data rd[rd_count];
190
191     GNUNET_assert (GNUNET_OK ==
192                    GNUNET_GNSRECORD_records_deserialize (rd_len,
193                                                          rd_ser_tmp,
194                                                          rd_count,
195                                                          rd));
196     zm->monitor (zm->cls,
197                  &lrm->private_key,
198                  name_tmp,
199                  rd_count,
200                  rd);
201   }
202 }
203
204
205 /**
206  * Generic error handler, called with the appropriate error code and
207  * the same closure specified at the creation of the message queue.
208  * Not every message queue implementation supports an error handler.
209  *
210  * @param cls closure with the `struct GNUNET_NAMESTORE_ZoneMonitor *`
211  * @param error error code
212  */
213 static void
214 mq_error_handler (void *cls,
215                   enum GNUNET_MQ_Error error)
216 {
217   struct GNUNET_NAMESTORE_ZoneMonitor *zm = cls;
218
219   reconnect (zm);
220 }
221
222
223 /**
224  * Reconnect to the namestore service.
225  *
226  * @param zm monitor to reconnect
227  */
228 static void
229 reconnect (struct GNUNET_NAMESTORE_ZoneMonitor *zm)
230 {
231   GNUNET_MQ_hd_fixed_size (sync,
232                            GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_SYNC,
233                            struct GNUNET_MessageHeader);
234   GNUNET_MQ_hd_var_size (result,
235                          GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT,
236                          struct RecordResultMessage);
237   struct GNUNET_MQ_MessageHandler handlers[] = {
238     make_sync_handler (zm),
239     make_result_handler (zm),
240     GNUNET_MQ_handler_end ()
241   };
242   struct GNUNET_MQ_Envelope *env;
243   struct ZoneMonitorStartMessage *sm;
244
245   if (NULL != zm->mq)
246   {
247     GNUNET_MQ_destroy (zm->mq);
248     zm->monitor (zm->cls,
249                  NULL,
250                  NULL,
251                  0,
252                  NULL);
253   }
254   zm->mq = GNUNET_CLIENT_connecT (zm->cfg,
255                                   "namestore",
256                                   handlers,
257                                   &mq_error_handler,
258                                   zm);
259   if (NULL == zm->mq)
260     return;
261   env = GNUNET_MQ_msg (sm,
262                        GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_START);
263   sm->iterate_first = htonl (zm->iterate_first);
264   sm->zone = zm->zone;
265   GNUNET_MQ_send (zm->mq,
266                   env);
267 }
268
269
270
271 /**
272  * Begin monitoring a zone for changes.  If @a iterate_first is set,
273  * we Will first call the @a monitor function on all existing records
274  * in the selected zone(s).  In any case, we will call @a sync and
275  * afterwards call @a monitor whenever a record changes.
276  *
277  * @param cfg configuration to use to connect to namestore
278  * @param zone zone to monitor
279  * @param iterate_first #GNUNET_YES to first iterate over all existing records,
280  *                      #GNUNET_NO to only return changes that happen from now on
281  * @param monitor function to call on zone changes
282  * @param sync_cb function called when we're in sync with the namestore
283  * @param cls closure for @a monitor and @a sync_cb
284  * @return handle to stop monitoring
285  */
286 struct GNUNET_NAMESTORE_ZoneMonitor *
287 GNUNET_NAMESTORE_zone_monitor_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
288                                      const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
289                                      int iterate_first,
290                                      GNUNET_NAMESTORE_RecordMonitor monitor,
291                                      GNUNET_NAMESTORE_RecordsSynchronizedCallback sync_cb,
292                                      void *cls)
293 {
294   struct GNUNET_NAMESTORE_ZoneMonitor *zm;
295
296   zm = GNUNET_new (struct GNUNET_NAMESTORE_ZoneMonitor);
297   if (NULL != zone)
298     zm->zone = *zone;
299   zm->iterate_first = iterate_first;
300   zm->monitor = monitor;
301   zm->sync_cb = sync_cb;
302   zm->cls = cls;
303   zm->cfg = cfg;
304   reconnect (zm);
305   if (NULL == zm->mq)
306   {
307     GNUNET_free (zm);
308     return NULL;
309   }
310   return zm;
311 }
312
313
314 /**
315  * Stop monitoring a zone for changes.
316  *
317  * @param zm handle to the monitor activity to stop
318  */
319 void
320 GNUNET_NAMESTORE_zone_monitor_stop (struct GNUNET_NAMESTORE_ZoneMonitor *zm)
321 {
322   if (NULL != zm->mq)
323   {
324     GNUNET_MQ_destroy (zm->mq);
325     zm->mq = NULL;
326   }
327   GNUNET_free (zm);
328 }
329
330 /* end of namestore_api_monitor.c */