gns_api.c 9.8 KB

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