2 This file is part of GNUnet.
3 Copyright (C) 2009-2013, 2016, 2018 GNUnet e.V.
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.
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.
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/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
22 * @brief library to access the GNS service
23 * @author Martin Schanzenbach
24 * @author Christian Grothoff
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"
37 #define LOG(kind, ...) GNUNET_log_from(kind, "gns-api", __VA_ARGS__)
40 * Handle to a lookup request
42 struct GNUNET_GNS_LookupRequest {
46 struct GNUNET_GNS_LookupRequest *next;
51 struct GNUNET_GNS_LookupRequest *prev;
56 struct GNUNET_GNS_Handle *gns_handle;
59 * processor to call on lookup result
61 GNUNET_GNS_LookupResultProcessor lookup_proc;
64 * @e lookup_proc closure
69 * Envelope with the message for this queue entry.
71 struct GNUNET_MQ_Envelope *env;
81 * Reconnect to GNS service.
83 * @param handle the handle to the GNS service
86 reconnect(struct GNUNET_GNS_Handle *handle);
92 * @param cls the handle
95 reconnect_task(void *cls)
97 struct GNUNET_GNS_Handle *handle = cls;
99 handle->reconnect_task = NULL;
105 * Disconnect from service and then reconnect.
107 * @param handle our handle
110 force_reconnect(struct GNUNET_GNS_Handle *handle)
112 GNUNET_MQ_destroy(handle->mq);
114 handle->reconnect_backoff
115 = GNUNET_TIME_STD_BACKOFF(handle->reconnect_backoff);
116 handle->reconnect_task
117 = GNUNET_SCHEDULER_add_delayed(handle->reconnect_backoff,
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.
128 * @param cls closure with the `struct GNUNET_GNS_Handle *`
129 * @param error error code
132 mq_error_handler(void *cls,
133 enum GNUNET_MQ_Error error)
135 struct GNUNET_GNS_Handle *handle = cls;
137 LOG(GNUNET_ERROR_TYPE_WARNING,
138 "Problem with message queue. error: %i\n",
140 force_reconnect(handle);
145 * Check validity of message received from the GNS service
147 * @param cls the `struct GNUNET_GNS_Handle *`
148 * @param loookup_msg the incoming message
151 check_result(void *cls,
152 const struct LookupResultMessage *lookup_msg)
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];
160 GNUNET_GNSRECORD_records_deserialize(mlen,
161 (const char*)&lookup_msg[1],
166 return GNUNET_SYSERR;
173 * Handler for messages received from the GNS service
175 * @param cls the `struct GNUNET_GNS_Handle *`
176 * @param loookup_msg the incoming message
179 handle_result(void *cls,
180 const struct LookupResultMessage *lookup_msg)
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;
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)
199 proc = lr->lookup_proc;
200 proc_cls = lr->proc_cls;
202 GNUNET_assert(GNUNET_OK ==
203 GNUNET_GNSRECORD_records_deserialize(mlen,
204 (const char*)&lookup_msg[1],
210 GNUNET_CONTAINER_DLL_remove(handle->lookup_head,
214 GNUNET_MQ_discard(lr->env);
220 * Reconnect to GNS service.
222 * @param handle the handle to the GNS service
225 reconnect(struct GNUNET_GNS_Handle *handle)
227 struct GNUNET_MQ_MessageHandler handlers[] = {
228 GNUNET_MQ_hd_var_size(result,
229 GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT,
230 struct LookupResultMessage,
232 GNUNET_MQ_handler_end()
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,
243 if (NULL == handle->mq)
245 for (struct GNUNET_GNS_LookupRequest *lh = handle->lookup_head;
248 GNUNET_MQ_send_copy(handle->mq,
254 * Initialize the connection with the GNS service.
256 * @param cfg configuration to use
257 * @return handle to the GNS service, or NULL on error
259 struct GNUNET_GNS_Handle *
260 GNUNET_GNS_connect(const struct GNUNET_CONFIGURATION_Handle *cfg)
262 struct GNUNET_GNS_Handle *handle;
264 handle = GNUNET_new(struct GNUNET_GNS_Handle);
267 if (NULL == handle->mq)
277 * Shutdown connection with the GNS service.
279 * @param handle handle of the GNS connection to stop
282 GNUNET_GNS_disconnect(struct GNUNET_GNS_Handle *handle)
284 if (NULL != handle->mq)
286 GNUNET_MQ_destroy(handle->mq);
289 if (NULL != handle->reconnect_task)
291 GNUNET_SCHEDULER_cancel(handle->reconnect_task);
292 handle->reconnect_task = NULL;
294 GNUNET_assert(NULL == handle->lookup_head);
300 * Cancel pending lookup request
302 * @param lr the lookup request to cancel
303 * @return closure from the lookup result processor
306 GNUNET_GNS_lookup_cancel(struct GNUNET_GNS_LookupRequest *lr)
308 struct GNUNET_GNS_Handle *handle = lr->gns_handle;
311 GNUNET_CONTAINER_DLL_remove(handle->lookup_head,
314 GNUNET_MQ_discard(lr->env);
322 * Perform an asynchronous lookup operation on the GNS.
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
333 struct GNUNET_GNS_LookupRequest*
334 GNUNET_GNS_lookup(struct GNUNET_GNS_Handle *handle,
336 const struct GNUNET_CRYPTO_EcdsaPublicKey *zone,
338 enum GNUNET_GNS_LocalOptions options,
339 GNUNET_GNS_LookupResultProcessor proc,
342 /* IPC to shorten gns names, return shorten_handle */
343 struct LookupMessage *lookup_msg;
344 struct GNUNET_GNS_LookupRequest *lr;
352 LOG(GNUNET_ERROR_TYPE_DEBUG,
353 "Trying to lookup `%s' in GNS\n",
355 nlen = strlen(name) + 1;
356 if (nlen >= GNUNET_MAX_MESSAGE_SIZE - sizeof(*lr))
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,
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],
376 GNUNET_CONTAINER_DLL_insert(handle->lookup_head,
379 if (NULL != handle->mq)
380 GNUNET_MQ_send_copy(handle->mq,
386 /* end of gns_api.c */