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