a6a014839f3de7fd7945265283bf2688a6ad755b
[oweals/gnunet.git] / src / namestore / namestore_api_monitor.c
1 /*
2      This file is part of GNUnet.
3      (C) 2013 Christian Grothoff (and other contributing authors)
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., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, 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_ShortHashCode zone;
77
78   /**
79    * GNUNET_YES if we monitor all zones, GNUNET_NO if we only monitor 'zone'.
80    */
81   int all_zones;
82 };
83
84
85 /**
86  * Send our request to start monitoring to the service.
87  *
88  * @param cls the monitor handle
89  * @param size number of bytes available in buf
90  * @param buf where to copy the message to the service
91  * @return number of bytes copied to buf
92  */
93 static size_t
94 transmit_monitor_message (void *cls,
95                           size_t size,
96                           void *buf);
97
98
99 /**
100  * Reconnect to the namestore service.
101  *
102  * @param zm monitor to reconnect
103  */
104 static void
105 reconnect (struct GNUNET_NAMESTORE_ZoneMonitor *zm)
106 {
107   if (NULL != zm->h)
108     GNUNET_CLIENT_disconnect (zm->h);
109   zm->monitor (zm->cls,
110                NULL,
111                GNUNET_TIME_UNIT_ZERO_ABS,
112                NULL, 0, NULL, 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 LookupNameResponseMessage *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   struct GNUNET_TIME_Absolute expire;
144
145   if (NULL == msg)
146   {
147     reconnect (zm);
148     return;
149   }
150   if ( (ntohs (msg->size) == sizeof (struct GNUNET_MessageHeader)) &&
151        (GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_SYNC == ntohs (msg->type) ) )
152   {
153     GNUNET_CLIENT_receive (zm->h,
154                            &handle_updates,
155                            zm,
156                            GNUNET_TIME_UNIT_FOREVER_REL);
157     if (NULL != zm->sync_cb)
158       zm->sync_cb (zm->cls);
159     return;
160   }
161   if ( (ntohs (msg->size) < sizeof (struct LookupNameResponseMessage)) ||
162        (GNUNET_MESSAGE_TYPE_NAMESTORE_LOOKUP_NAME_RESPONSE != ntohs (msg->type) ) )
163   {
164     GNUNET_break (0);
165     reconnect (zm);
166     return;
167   }
168   lrm = (const struct LookupNameResponseMessage *) msg;
169   lrm_len = ntohs (lrm->gns_header.header.size);
170   rd_len = ntohs (lrm->rd_len);
171   rd_count = ntohs (lrm->rd_count);
172   name_len = ntohs (lrm->name_len);
173   expire = GNUNET_TIME_absolute_ntoh (lrm->expire);
174   exp_lrm_len = sizeof (struct LookupNameResponseMessage) + name_len + rd_len;
175   if (lrm_len != exp_lrm_len)
176   {
177     GNUNET_break (0);
178     reconnect (zm);
179     return;
180   }
181   if (0 == name_len)
182   {
183     GNUNET_break (0);
184     reconnect (zm);
185     return;
186   }
187   name_tmp = (const char *) &lrm[1];
188   if ((name_tmp[name_len -1] != '\0') || (name_len > MAX_NAME_LEN))
189   {
190     GNUNET_break (0);
191     reconnect (zm);
192     return;
193   }
194   rd_ser_tmp = (const char *) &name_tmp[name_len];
195   {
196     struct GNUNET_NAMESTORE_RecordData rd[rd_count];
197
198     if (GNUNET_OK != GNUNET_NAMESTORE_records_deserialize (rd_len, rd_ser_tmp, rd_count, rd))
199     {
200       GNUNET_break (0);
201       reconnect (zm);
202       return;
203     }  
204     GNUNET_CLIENT_receive (zm->h,
205                            &handle_updates,
206                            zm,
207                            GNUNET_TIME_UNIT_FOREVER_REL);
208     zm->monitor (zm->cls, 
209                  &lrm->public_key, expire, 
210                  name_tmp, 
211                  rd_count, rd, NULL);
212   }
213 }
214
215
216 /**
217  * Send our request to start monitoring to the service.
218  *
219  * @param cls the monitor handle
220  * @param size number of bytes available in buf
221  * @param buf where to copy the message to the service
222  * @return number of bytes copied to buf
223  */
224 static size_t
225 transmit_monitor_message (void *cls,
226                           size_t size,
227                           void *buf)
228 {
229   struct GNUNET_NAMESTORE_ZoneMonitor *zm = cls;
230   struct ZoneMonitorStartMessage sm;
231
232   zm->th = NULL;
233   if (size < sizeof (struct ZoneMonitorStartMessage))
234   {    
235     reconnect (zm);
236     return 0;
237   }
238   sm.gns_header.header.type = htons (GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_START);
239   sm.gns_header.header.size = htons (sizeof (struct ZoneMonitorStartMessage));
240   sm.gns_header.r_id = htonl (0);
241   sm.zone = zm->zone;
242   sm.all_zones = htonl (zm->all_zones);
243   memcpy (buf, &sm, sizeof (sm));
244   GNUNET_CLIENT_receive (zm->h,
245                          &handle_updates,
246                          zm,
247                          GNUNET_TIME_UNIT_FOREVER_REL);
248   return sizeof (sm);
249 }
250
251
252 /**
253  * Begin monitoring a zone for changes.  Will first call the 'monitor' function
254  * on all existing records in the selected zone(s) and then call it whenever
255  * a record changes.
256  *
257  * @param cfg configuration to use to connect to namestore
258  * @param zone zone to monitor, NULL for all zones
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 'monitor' and '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_ShortHashCode *zone,
267                                      GNUNET_NAMESTORE_RecordMonitor monitor,
268                                      GNUNET_NAMESTORE_RecordsSynchronizedCallback sync_cb,
269                                      void *cls)
270 {
271   struct GNUNET_NAMESTORE_ZoneMonitor *zm;
272   struct GNUNET_CLIENT_Connection *client;
273
274   if (NULL == (client = GNUNET_CLIENT_connect ("namestore", cfg)))
275     return NULL; 
276   zm = GNUNET_new (struct GNUNET_NAMESTORE_ZoneMonitor);
277   zm->cfg = cfg;
278   zm->h = client;
279   if (NULL == zone)
280     zm->all_zones = GNUNET_YES;
281   else
282     zm->zone = *zone;
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 */