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