NAMESTORE/JSON: fix parsing exp and flags
[oweals/gnunet.git] / src / gns / gns_api.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2009-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      SPDX-License-Identifier: AGPL3.0-or-later
19 */
20 /**
21  * @file gns/gns_api.c
22  * @brief library to access the GNS service
23  * @author Martin Schanzenbach
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "gnunet_util_lib.h"
28 #include "gnunet_constants.h"
29 #include "gnunet_arm_service.h"
30 #include "gnunet_hello_lib.h"
31 #include "gnunet_protocols.h"
32 #include "gnunet_dht_service.h"
33 #include "gns.h"
34 #include "gns_api.h"
35
36
37 #define LOG(kind,...) GNUNET_log_from (kind, "gns-api",__VA_ARGS__)
38
39 /**
40  * Handle to a lookup request
41  */
42 struct GNUNET_GNS_LookupRequest
43 {
44
45   /**
46    * DLL
47    */
48   struct GNUNET_GNS_LookupRequest *next;
49
50   /**
51    * DLL
52    */
53   struct GNUNET_GNS_LookupRequest *prev;
54
55   /**
56    * handle to gns
57    */
58   struct GNUNET_GNS_Handle *gns_handle;
59
60   /**
61    * processor to call on lookup result
62    */
63   GNUNET_GNS_LookupResultProcessor lookup_proc;
64
65   /**
66    * @e lookup_proc closure
67    */
68   void *proc_cls;
69
70   /**
71    * Envelope with the message for this queue entry.
72    */
73   struct GNUNET_MQ_Envelope *env;
74
75   /**
76    * request id
77    */
78   uint32_t r_id;
79
80 };
81
82
83 /**
84  * Reconnect to GNS service.
85  *
86  * @param handle the handle to the GNS service
87  */
88 static void
89 reconnect (struct GNUNET_GNS_Handle *handle);
90
91
92 /**
93  * Reconnect to GNS
94  *
95  * @param cls the handle
96  */
97 static void
98 reconnect_task (void *cls)
99 {
100   struct GNUNET_GNS_Handle *handle = cls;
101
102   handle->reconnect_task = NULL;
103   reconnect (handle);
104 }
105
106
107 /**
108  * Disconnect from service and then reconnect.
109  *
110  * @param handle our handle
111  */
112 static void
113 force_reconnect (struct GNUNET_GNS_Handle *handle)
114 {
115   GNUNET_MQ_destroy (handle->mq);
116   handle->mq = NULL;
117   handle->reconnect_backoff
118     = GNUNET_TIME_STD_BACKOFF (handle->reconnect_backoff);
119   handle->reconnect_task
120     = GNUNET_SCHEDULER_add_delayed (handle->reconnect_backoff,
121                                     &reconnect_task,
122                                     handle);
123 }
124
125
126 /**
127  * Generic error handler, called with the appropriate error code and
128  * the same closure specified at the creation of the message queue.
129  * Not every message queue implementation supports an error handler.
130  *
131  * @param cls closure with the `struct GNUNET_GNS_Handle *`
132  * @param error error code
133  */
134 static void
135 mq_error_handler (void *cls,
136                   enum GNUNET_MQ_Error error)
137 {
138   struct GNUNET_GNS_Handle *handle = cls;
139
140   LOG (GNUNET_ERROR_TYPE_WARNING,
141        "Problem with message queue. error: %i\n",
142        error);
143   force_reconnect (handle);
144 }
145
146
147 /**
148  * Check validity of message received from the GNS service
149  *
150  * @param cls the `struct GNUNET_GNS_Handle *`
151  * @param loookup_msg the incoming message
152  */
153 static int
154 check_result (void *cls,
155               const struct LookupResultMessage *lookup_msg)
156 {
157   size_t mlen = ntohs (lookup_msg->header.size) - sizeof (*lookup_msg);
158   uint32_t rd_count = ntohl (lookup_msg->rd_count);
159   struct GNUNET_GNSRECORD_Data rd[rd_count];
160
161   (void) cls;
162   if (GNUNET_SYSERR ==
163       GNUNET_GNSRECORD_records_deserialize (mlen,
164                                             (const char*) &lookup_msg[1],
165                                             rd_count,
166                                             rd))
167   {
168     GNUNET_break (0);
169     return GNUNET_SYSERR;
170   }
171   return GNUNET_OK;
172 }
173
174
175 /**
176  * Handler for messages received from the GNS service
177  *
178  * @param cls the `struct GNUNET_GNS_Handle *`
179  * @param loookup_msg the incoming message
180  */
181 static void
182 handle_result (void *cls,
183                const struct LookupResultMessage *lookup_msg)
184 {
185   struct GNUNET_GNS_Handle *handle = cls;
186   size_t mlen = ntohs (lookup_msg->header.size) - sizeof (*lookup_msg);
187   uint32_t rd_count = ntohl (lookup_msg->rd_count);
188   struct GNUNET_GNSRECORD_Data rd[rd_count];
189   uint32_t r_id = ntohl (lookup_msg->id);
190   struct GNUNET_GNS_LookupRequest *lr;
191   GNUNET_GNS_LookupResultProcessor proc;
192   void *proc_cls;
193
194   LOG (GNUNET_ERROR_TYPE_DEBUG,
195        "Received lookup reply from GNS service (%u records)\n",
196        (unsigned int) rd_count);
197   for (lr = handle->lookup_head; NULL != lr; lr = lr->next)
198     if (lr->r_id == r_id)
199       break;
200   if (NULL == lr)
201     return;
202   proc = lr->lookup_proc;
203   proc_cls = lr->proc_cls;
204
205   GNUNET_assert (GNUNET_OK ==
206                  GNUNET_GNSRECORD_records_deserialize (mlen,
207                                                        (const char*) &lookup_msg[1],
208                                                        rd_count,
209                                                        rd));
210   proc (proc_cls,
211         rd_count,
212         rd);
213   GNUNET_CONTAINER_DLL_remove (handle->lookup_head,
214                                handle->lookup_tail,
215                                lr);
216   if (NULL != lr->env)
217     GNUNET_MQ_discard (lr->env);
218   GNUNET_free (lr);
219 }
220
221
222 /**
223  * Reconnect to GNS service.
224  *
225  * @param handle the handle to the GNS service
226  */
227 static void
228 reconnect (struct GNUNET_GNS_Handle *handle)
229 {
230   struct GNUNET_MQ_MessageHandler handlers[] = {
231     GNUNET_MQ_hd_var_size (result,
232                            GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT,
233                            struct LookupResultMessage,
234                            handle),
235     GNUNET_MQ_handler_end ()
236   };
237
238   GNUNET_assert (NULL == handle->mq);
239   LOG (GNUNET_ERROR_TYPE_DEBUG,
240        "Trying to connect to GNS\n");
241   handle->mq = GNUNET_CLIENT_connect (handle->cfg,
242                                       "gns",
243                                       handlers,
244                                       &mq_error_handler,
245                                       handle);
246   if (NULL == handle->mq)
247     return;
248   for (struct GNUNET_GNS_LookupRequest *lh = handle->lookup_head;
249        NULL != lh;
250        lh = lh->next)
251     GNUNET_MQ_send_copy (handle->mq,
252                          lh->env);
253 }
254
255
256 /**
257  * Initialize the connection with the GNS service.
258  *
259  * @param cfg configuration to use
260  * @return handle to the GNS service, or NULL on error
261  */
262 struct GNUNET_GNS_Handle *
263 GNUNET_GNS_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
264 {
265   struct GNUNET_GNS_Handle *handle;
266
267   handle = GNUNET_new (struct GNUNET_GNS_Handle);
268   handle->cfg = cfg;
269   reconnect (handle);
270   if (NULL == handle->mq)
271   {
272     GNUNET_free (handle);
273     return NULL;
274   }
275   return handle;
276 }
277
278
279 /**
280  * Shutdown connection with the GNS service.
281  *
282  * @param handle handle of the GNS connection to stop
283  */
284 void
285 GNUNET_GNS_disconnect (struct GNUNET_GNS_Handle *handle)
286 {
287   if (NULL != handle->mq)
288   {
289     GNUNET_MQ_destroy (handle->mq);
290     handle->mq = NULL;
291   }
292   if (NULL != handle->reconnect_task)
293   {
294     GNUNET_SCHEDULER_cancel (handle->reconnect_task);
295     handle->reconnect_task = NULL;
296   }
297   GNUNET_assert (NULL == handle->lookup_head);
298   GNUNET_free (handle);
299 }
300
301
302 /**
303  * Cancel pending lookup request
304  *
305  * @param lr the lookup request to cancel
306  * @return closure from the lookup result processor
307  */
308 void *
309 GNUNET_GNS_lookup_cancel (struct GNUNET_GNS_LookupRequest *lr)
310 {
311   struct GNUNET_GNS_Handle *handle = lr->gns_handle;
312   void *ret;
313
314   GNUNET_CONTAINER_DLL_remove (handle->lookup_head,
315                                handle->lookup_tail,
316                                lr);
317   GNUNET_MQ_discard (lr->env);
318   ret = lr->proc_cls;
319   GNUNET_free (lr);
320   return ret;
321 }
322
323
324 /**
325  * Perform an asynchronous lookup operation on the GNS.
326  *
327  * @param handle handle to the GNS service
328  * @param name the name to look up
329  * @param zone the zone to start the resolution in
330  * @param type the record type to look up
331  * @param options local options for the lookup
332  * @param proc processor to call on result
333  * @param proc_cls closure for @a proc
334  * @return handle to the get request
335  */
336 struct GNUNET_GNS_LookupRequest*
337 GNUNET_GNS_lookup (struct GNUNET_GNS_Handle *handle,
338                    const char *name,
339                    const struct GNUNET_CRYPTO_EcdsaPublicKey *zone,
340                    uint32_t type,
341                    enum GNUNET_GNS_LocalOptions options,
342                    GNUNET_GNS_LookupResultProcessor proc,
343                    void *proc_cls)
344 {
345   /* IPC to shorten gns names, return shorten_handle */
346   struct LookupMessage *lookup_msg;
347   struct GNUNET_GNS_LookupRequest *lr;
348   size_t nlen;
349
350   if (NULL == name)
351   {
352     GNUNET_break (0);
353     return NULL;
354   }
355   LOG (GNUNET_ERROR_TYPE_DEBUG,
356        "Trying to lookup `%s' in GNS\n",
357        name);
358   nlen = strlen (name) + 1;
359   if (nlen >= GNUNET_MAX_MESSAGE_SIZE - sizeof (*lr))
360   {
361     GNUNET_break (0);
362     return NULL;
363   }
364   lr = GNUNET_new (struct GNUNET_GNS_LookupRequest);
365   lr->gns_handle = handle;
366   lr->lookup_proc = proc;
367   lr->proc_cls = proc_cls;
368   lr->r_id = handle->r_id_gen++;
369   lr->env = GNUNET_MQ_msg_extra (lookup_msg,
370                                  nlen,
371                                  GNUNET_MESSAGE_TYPE_GNS_LOOKUP);
372   lookup_msg->id = htonl (lr->r_id);
373   lookup_msg->options = htons ((uint16_t) options);
374   lookup_msg->zone = *zone;
375   lookup_msg->type = htonl (type);
376   GNUNET_memcpy (&lookup_msg[1],
377                  name,
378                  nlen);
379   GNUNET_CONTAINER_DLL_insert (handle->lookup_head,
380                                handle->lookup_tail,
381                                lr);
382   if (NULL != handle->mq)
383     GNUNET_MQ_send_copy (handle->mq,
384                          lr->env);
385   return lr;
386 }
387
388
389 /* end of gns_api.c */