-fix (C) notices
[oweals/gnunet.git] / src / namestore / namestore_api_monitor.c
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
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_CLIENT_Connection *h;
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 'monitor' and 'sync_cb'.
65    */
66   void *cls;
67
68   /**
69    * Transmission handle to client.
70    */
71   struct GNUNET_CLIENT_TransmitHandle *th;
72
73   /**
74    * Monitored zone.
75    */
76   struct GNUNET_CRYPTO_EcdsaPrivateKey zone;
77
78   /**
79    * Do we first iterate over all existing records?
80    */
81   int iterate_first;
82
83 };
84
85
86 /**
87  * Send our request to start monitoring to the service.
88  *
89  * @param cls the monitor handle
90  * @param size number of bytes available in buf
91  * @param buf where to copy the message to the service
92  * @return number of bytes copied to buf
93  */
94 static size_t
95 transmit_monitor_message (void *cls,
96                           size_t size,
97                           void *buf);
98
99
100 /**
101  * Reconnect to the namestore service.
102  *
103  * @param zm monitor to reconnect
104  */
105 static void
106 reconnect (struct GNUNET_NAMESTORE_ZoneMonitor *zm)
107 {
108   if (NULL != zm->h)
109     GNUNET_CLIENT_disconnect (zm->h);
110   zm->monitor (zm->cls,
111                NULL,
112                NULL, 0, NULL);
113   GNUNET_assert (NULL != (zm->h = GNUNET_CLIENT_connect ("namestore", zm->cfg)));
114   zm->th = GNUNET_CLIENT_notify_transmit_ready (zm->h,
115                                                 sizeof (struct ZoneMonitorStartMessage),
116                                                 GNUNET_TIME_UNIT_FOREVER_REL,
117                                                 GNUNET_YES,
118                                                 &transmit_monitor_message,
119                                                 zm);
120 }
121
122
123 /**
124  * We've received a notification about a change to our zone.
125  * Forward to monitor callback.
126  *
127  * @param cls the zone monitor handle
128  * @param msg the message from the service.
129  */
130 static void
131 handle_updates (void *cls,
132                 const struct GNUNET_MessageHeader *msg)
133 {
134   struct GNUNET_NAMESTORE_ZoneMonitor *zm = cls;
135   const struct RecordResultMessage *lrm;
136   size_t lrm_len;
137   size_t exp_lrm_len;
138   size_t name_len;
139   size_t rd_len;
140   unsigned rd_count;
141   const char *name_tmp;
142   const char *rd_ser_tmp;
143
144   if (NULL == msg)
145   {
146     reconnect (zm);
147     return;
148   }
149   if ( (ntohs (msg->size) == sizeof (struct GNUNET_MessageHeader)) &&
150        (GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_SYNC == ntohs (msg->type) ) )
151   {
152     GNUNET_CLIENT_receive (zm->h,
153                            &handle_updates,
154                            zm,
155                            GNUNET_TIME_UNIT_FOREVER_REL);
156     if (NULL != zm->sync_cb)
157       zm->sync_cb (zm->cls);
158     return;
159   }
160   if ( (ntohs (msg->size) < sizeof (struct RecordResultMessage)) ||
161        (GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT != ntohs (msg->type) ) )
162   {
163     GNUNET_break (0);
164     reconnect (zm);
165     return;
166   }
167   lrm = (const struct RecordResultMessage *) msg;
168   lrm_len = ntohs (lrm->gns_header.header.size);
169   rd_len = ntohs (lrm->rd_len);
170   rd_count = ntohs (lrm->rd_count);
171   name_len = ntohs (lrm->name_len);
172   exp_lrm_len = sizeof (struct RecordResultMessage) + name_len + rd_len;
173   if (lrm_len != exp_lrm_len)
174   {
175     GNUNET_break (0);
176     reconnect (zm);
177     return;
178   }
179   if (0 == name_len)
180   {
181     GNUNET_break (0);
182     reconnect (zm);
183     return;
184   }
185   name_tmp = (const char *) &lrm[1];
186   if ((name_tmp[name_len -1] != '\0') || (name_len > MAX_NAME_LEN))
187   {
188     GNUNET_break (0);
189     reconnect (zm);
190     return;
191   }
192   rd_ser_tmp = (const char *) &name_tmp[name_len];
193   {
194     struct GNUNET_GNSRECORD_Data rd[rd_count];
195
196     if (GNUNET_OK != GNUNET_GNSRECORD_records_deserialize (rd_len, rd_ser_tmp, rd_count, rd))
197     {
198       GNUNET_break (0);
199       reconnect (zm);
200       return;
201     }
202     GNUNET_CLIENT_receive (zm->h,
203                            &handle_updates,
204                            zm,
205                            GNUNET_TIME_UNIT_FOREVER_REL);
206     zm->monitor (zm->cls,
207                  &lrm->private_key,
208                  name_tmp,
209                  rd_count, rd);
210   }
211 }
212
213
214 /**
215  * Send our request to start monitoring to the service.
216  *
217  * @param cls the monitor handle
218  * @param size number of bytes available in buf
219  * @param buf where to copy the message to the service
220  * @return number of bytes copied to buf
221  */
222 static size_t
223 transmit_monitor_message (void *cls,
224                           size_t size,
225                           void *buf)
226 {
227   struct GNUNET_NAMESTORE_ZoneMonitor *zm = cls;
228   struct ZoneMonitorStartMessage sm;
229
230   zm->th = NULL;
231   if (size < sizeof (struct ZoneMonitorStartMessage))
232   {
233     reconnect (zm);
234     return 0;
235   }
236   sm.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_START);
237   sm.header.size = htons (sizeof (struct ZoneMonitorStartMessage));
238   sm.iterate_first = htonl (zm->iterate_first);
239   sm.zone = zm->zone;
240   memcpy (buf, &sm, sizeof (sm));
241   GNUNET_CLIENT_receive (zm->h,
242                          &handle_updates,
243                          zm,
244                          GNUNET_TIME_UNIT_FOREVER_REL);
245   return sizeof (sm);
246 }
247
248
249 /**
250  * Begin monitoring a zone for changes.  If @a iterate_first is set,
251  * we Will first call the @a monitor function on all existing records
252  * in the selected zone(s).  In any case, we will call @a sync and
253  * afterwards call @a monitor whenever a record changes.
254  *
255  * @param cfg configuration to use to connect to namestore
256  * @param zone zone to monitor
257  * @param iterate_first #GNUNET_YES to first iterate over all existing records,
258  *                      #GNUNET_NO to only return changes that happen from now on
259  * @param monitor function to call on zone changes
260  * @param sync_cb function called when we're in sync with the namestore
261  * @param cls closure for @a monitor and @a sync_cb
262  * @return handle to stop monitoring
263  */
264 struct GNUNET_NAMESTORE_ZoneMonitor *
265 GNUNET_NAMESTORE_zone_monitor_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
266                                      const struct GNUNET_CRYPTO_EcdsaPrivateKey *zone,
267                                      int iterate_first,
268                                      GNUNET_NAMESTORE_RecordMonitor monitor,
269                                      GNUNET_NAMESTORE_RecordsSynchronizedCallback sync_cb,
270                                      void *cls)
271 {
272   struct GNUNET_NAMESTORE_ZoneMonitor *zm;
273   struct GNUNET_CLIENT_Connection *client;
274
275   if (NULL == (client = GNUNET_CLIENT_connect ("namestore", cfg)))
276     return NULL;
277   zm = GNUNET_new (struct GNUNET_NAMESTORE_ZoneMonitor);
278   zm->cfg = cfg;
279   zm->h = client;
280   if (NULL != zone)
281     zm->zone = *zone;
282   zm->iterate_first = iterate_first;
283   zm->monitor = monitor;
284   zm->sync_cb = sync_cb;
285   zm->cls = cls;
286   zm->th = GNUNET_CLIENT_notify_transmit_ready (zm->h,
287                                                 sizeof (struct ZoneMonitorStartMessage),
288                                                 GNUNET_TIME_UNIT_FOREVER_REL,
289                                                 GNUNET_YES,
290                                                 &transmit_monitor_message,
291                                                 zm);
292   return zm;
293 }
294
295
296 /**
297  * Stop monitoring a zone for changes.
298  *
299  * @param zm handle to the monitor activity to stop
300  */
301 void
302 GNUNET_NAMESTORE_zone_monitor_stop (struct GNUNET_NAMESTORE_ZoneMonitor *zm)
303 {
304   if (NULL != zm->th)
305   {
306     GNUNET_CLIENT_notify_transmit_ready_cancel (zm->th);
307     zm->th = NULL;
308   }
309   GNUNET_CLIENT_disconnect (zm->h);
310   GNUNET_free (zm);
311 }
312
313 /* end of namestore_api_monitor.c */