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