gns_api.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596
  1. /*
  2. This file is part of GNUnet.
  3. (C) 2009-2013 Christian Grothoff (and other contributing authors)
  4. GNUnet is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published
  6. by the Free Software Foundation; either version 3, or (at your
  7. 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. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNUnet; see the file COPYING. If not, write to the
  14. Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  15. Boston, MA 02111-1307, USA.
  16. */
  17. /**
  18. * @file gns/gns_api.c
  19. * @brief library to access the GNS service
  20. * @author Martin Schanzenbach
  21. * @author Christian Grothoff
  22. */
  23. #include "platform.h"
  24. #include "gnunet_util_lib.h"
  25. #include "gnunet_constants.h"
  26. #include "gnunet_arm_service.h"
  27. #include "gnunet_hello_lib.h"
  28. #include "gnunet_protocols.h"
  29. #include "gnunet_dht_service.h"
  30. #include "gns.h"
  31. #include "gnunet_gns_service.h"
  32. #define LOG(kind,...) GNUNET_log_from (kind, "gns-api",__VA_ARGS__)
  33. /**
  34. * Handle to a lookup request
  35. */
  36. struct GNUNET_GNS_LookupRequest
  37. {
  38. /**
  39. * DLL
  40. */
  41. struct GNUNET_GNS_LookupRequest *next;
  42. /**
  43. * DLL
  44. */
  45. struct GNUNET_GNS_LookupRequest *prev;
  46. /**
  47. * handle to gns
  48. */
  49. struct GNUNET_GNS_Handle *gns_handle;
  50. /**
  51. * processor to call on lookup result
  52. */
  53. GNUNET_GNS_LookupResultProcessor lookup_proc;
  54. /**
  55. * processor closure
  56. */
  57. void *proc_cls;
  58. /**
  59. * request id
  60. */
  61. uint32_t r_id;
  62. };
  63. /**
  64. * Entry in our list of messages to be (re-)transmitted.
  65. */
  66. struct PendingMessage
  67. {
  68. /**
  69. * This is a doubly-linked list.
  70. */
  71. struct PendingMessage *prev;
  72. /**
  73. * This is a doubly-linked list.
  74. */
  75. struct PendingMessage *next;
  76. /**
  77. * Size of the message.
  78. */
  79. size_t size;
  80. /**
  81. * request id
  82. */
  83. uint32_t r_id;
  84. /**
  85. * This message has been transmitted. GNUNET_NO if the message is
  86. * in the "pending" DLL, GNUNET_YES if it has been transmitted to
  87. * the service via the current client connection.
  88. */
  89. int transmitted;
  90. };
  91. /**
  92. * Connection to the GNS service.
  93. */
  94. struct GNUNET_GNS_Handle
  95. {
  96. /**
  97. * Configuration to use.
  98. */
  99. const struct GNUNET_CONFIGURATION_Handle *cfg;
  100. /**
  101. * Socket (if available).
  102. */
  103. struct GNUNET_CLIENT_Connection *client;
  104. /**
  105. * Currently pending transmission request (or NULL).
  106. */
  107. struct GNUNET_CLIENT_TransmitHandle *th;
  108. /**
  109. * Head of linked list of shorten messages we would like to transmit.
  110. */
  111. struct PendingMessage *pending_head;
  112. /**
  113. * Tail of linked list of shorten messages we would like to transmit.
  114. */
  115. struct PendingMessage *pending_tail;
  116. /**
  117. * Head of linked list of lookup messages we would like to transmit.
  118. */
  119. struct GNUNET_GNS_LookupRequest *lookup_head;
  120. /**
  121. * Tail of linked list of lookup messages we would like to transmit.
  122. */
  123. struct GNUNET_GNS_LookupRequest *lookup_tail;
  124. /**
  125. * Reconnect task
  126. */
  127. GNUNET_SCHEDULER_TaskIdentifier reconnect_task;
  128. /**
  129. * How long do we wait until we try to reconnect?
  130. */
  131. struct GNUNET_TIME_Relative reconnect_backoff;
  132. /**
  133. * Request Id generator. Incremented by one for each request.
  134. */
  135. uint32_t r_id_gen;
  136. /**
  137. * Did we start our receive loop yet?
  138. */
  139. int in_receive;
  140. };
  141. /**
  142. * Try to send messages from list of messages to send
  143. * @param handle GNS_Handle
  144. */
  145. static void
  146. process_pending_messages (struct GNUNET_GNS_Handle *handle);
  147. /**
  148. * Reconnect to GNS service.
  149. *
  150. * @param handle the handle to the GNS service
  151. */
  152. static void
  153. reconnect (struct GNUNET_GNS_Handle *handle)
  154. {
  155. GNUNET_assert (NULL == handle->client);
  156. LOG (GNUNET_ERROR_TYPE_DEBUG,
  157. "Trying to connect to GNS\n");
  158. handle->client = GNUNET_CLIENT_connect ("gns", handle->cfg);
  159. GNUNET_assert (NULL != handle->client);
  160. process_pending_messages (handle);
  161. }
  162. /**
  163. * Reconnect to GNS
  164. *
  165. * @param cls the handle
  166. * @param tc task context
  167. */
  168. static void
  169. reconnect_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
  170. {
  171. struct GNUNET_GNS_Handle *handle = cls;
  172. handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
  173. reconnect (handle);
  174. }
  175. /**
  176. * Disconnect from service and then reconnect.
  177. *
  178. * @param handle our handle
  179. */
  180. static void
  181. force_reconnect (struct GNUNET_GNS_Handle *handle)
  182. {
  183. struct GNUNET_GNS_LookupRequest *lh;
  184. struct PendingMessage *p;
  185. GNUNET_CLIENT_disconnect (handle->client);
  186. handle->client = NULL;
  187. handle->in_receive = GNUNET_NO;
  188. for (lh = handle->lookup_head; NULL != lh; lh = lh->next)
  189. {
  190. p = (struct PendingMessage *) &lh[1];
  191. if (GNUNET_NO == p->transmitted)
  192. continue;
  193. p->transmitted = GNUNET_NO;
  194. GNUNET_CONTAINER_DLL_insert (handle->pending_head,
  195. handle->pending_tail,
  196. p);
  197. }
  198. handle->reconnect_backoff = GNUNET_TIME_STD_BACKOFF (handle->reconnect_backoff);
  199. handle->reconnect_task = GNUNET_SCHEDULER_add_delayed (handle->reconnect_backoff,
  200. &reconnect_task,
  201. handle);
  202. }
  203. /**
  204. * Transmit the next pending message, called by notify_transmit_ready
  205. *
  206. * @param cls the closure
  207. * @param size size of pending data
  208. * @param buf buffer with pending data
  209. * @return size data transmitted
  210. */
  211. static size_t
  212. transmit_pending (void *cls, size_t size, void *buf);
  213. /**
  214. * Handler for messages received from the GNS service
  215. *
  216. * @param cls the 'struct GNUNET_GNS_Handle'
  217. * @param msg the incoming message
  218. */
  219. static void
  220. process_message (void *cls, const struct GNUNET_MessageHeader *msg);
  221. /**
  222. * Try to send messages from list of messages to send
  223. *
  224. * @param handle the GNS handle
  225. */
  226. static void
  227. process_pending_messages (struct GNUNET_GNS_Handle *handle)
  228. {
  229. struct PendingMessage *p = handle->pending_head;
  230. if (NULL == handle->client)
  231. return; /* wait for reconnect */
  232. if (NULL != handle->th)
  233. return; /* transmission request already pending */
  234. while ((NULL != p) && (p->transmitted == GNUNET_YES))
  235. p = p->next;
  236. if (NULL == p)
  237. return; /* no messages pending */
  238. LOG (GNUNET_ERROR_TYPE_DEBUG,
  239. "Trying to transmit %u bytes\n",
  240. (unsigned int) p->size);
  241. handle->th =
  242. GNUNET_CLIENT_notify_transmit_ready (handle->client,
  243. p->size,
  244. GNUNET_TIME_UNIT_FOREVER_REL,
  245. GNUNET_NO, &transmit_pending,
  246. handle);
  247. GNUNET_break (NULL != handle->th);
  248. }
  249. /**
  250. * Transmit the next pending message, called by notify_transmit_ready
  251. *
  252. * @param cls the closure
  253. * @param size size of pending data
  254. * @param buf buffer with pending data
  255. * @return size data transmitted
  256. */
  257. static size_t
  258. transmit_pending (void *cls, size_t size, void *buf)
  259. {
  260. struct GNUNET_GNS_Handle *handle = cls;
  261. char *cbuf = buf;
  262. struct PendingMessage *p;
  263. size_t tsize;
  264. handle->th = NULL;
  265. if ((0 == size) || (NULL == buf))
  266. {
  267. LOG (GNUNET_ERROR_TYPE_DEBUG,
  268. "Transmission to GNS service failed!\n");
  269. force_reconnect (handle);
  270. return 0;
  271. }
  272. if (NULL == (p = handle->pending_head))
  273. return 0;
  274. tsize = 0;
  275. while ((NULL != (p = handle->pending_head)) && (p->size <= size))
  276. {
  277. memcpy (&cbuf[tsize], &p[1], p->size);
  278. tsize += p->size;
  279. size -= p->size;
  280. p->transmitted = GNUNET_YES;
  281. GNUNET_CONTAINER_DLL_remove (handle->pending_head,
  282. handle->pending_tail,
  283. p);
  284. if (GNUNET_YES != handle->in_receive)
  285. {
  286. GNUNET_CLIENT_receive (handle->client, &process_message, handle,
  287. GNUNET_TIME_UNIT_FOREVER_REL);
  288. handle->in_receive = GNUNET_YES;
  289. }
  290. }
  291. LOG (GNUNET_ERROR_TYPE_DEBUG,
  292. "Sending %u bytes\n",
  293. (unsigned int) tsize);
  294. process_pending_messages (handle);
  295. return tsize;
  296. }
  297. /**
  298. * Process a given reply to the lookup request
  299. *
  300. * @param qe a queue entry
  301. * @param msg the lookup message received
  302. */
  303. static void
  304. process_lookup_reply (struct GNUNET_GNS_LookupRequest *qe,
  305. const struct GNUNET_GNS_ClientLookupResultMessage *msg)
  306. {
  307. struct GNUNET_GNS_Handle *handle = qe->gns_handle;
  308. struct PendingMessage *p = (struct PendingMessage *) &qe[1];
  309. GNUNET_GNS_LookupResultProcessor proc;
  310. void *proc_cls;
  311. uint32_t rd_count = ntohl (msg->rd_count);
  312. struct GNUNET_GNSRECORD_Data rd[rd_count];
  313. size_t mlen;
  314. if (GNUNET_YES != p->transmitted)
  315. {
  316. /* service send reply to query we never managed to send!? */
  317. GNUNET_break (0);
  318. force_reconnect (handle);
  319. return;
  320. }
  321. mlen = ntohs (msg->header.size);
  322. mlen -= sizeof (struct GNUNET_GNS_ClientLookupResultMessage);
  323. proc = qe->lookup_proc;
  324. proc_cls = qe->proc_cls;
  325. GNUNET_CONTAINER_DLL_remove (handle->lookup_head, handle->lookup_tail, qe);
  326. GNUNET_free (qe);
  327. if (GNUNET_SYSERR == GNUNET_GNSRECORD_records_deserialize (mlen,
  328. (const char*) &msg[1],
  329. rd_count,
  330. rd))
  331. {
  332. LOG (GNUNET_ERROR_TYPE_ERROR,
  333. _("Failed to deserialize lookup reply from GNS service!\n"));
  334. proc (proc_cls, 0, NULL);
  335. }
  336. else
  337. {
  338. LOG (GNUNET_ERROR_TYPE_DEBUG,
  339. "Received lookup reply from GNS service (%u records)\n",
  340. (unsigned int) rd_count);
  341. proc (proc_cls, rd_count, rd);
  342. }
  343. }
  344. /**
  345. * Handler for messages received from the GNS service
  346. *
  347. * @param cls the 'struct GNUNET_GNS_Handle'
  348. * @param msg the incoming message
  349. */
  350. static void
  351. process_message (void *cls, const struct GNUNET_MessageHeader *msg)
  352. {
  353. struct GNUNET_GNS_Handle *handle = cls;
  354. struct GNUNET_GNS_LookupRequest *lr;
  355. const struct GNUNET_GNS_ClientLookupResultMessage *lookup_msg;
  356. uint32_t r_id;
  357. if (NULL == msg)
  358. {
  359. force_reconnect (handle);
  360. return;
  361. }
  362. GNUNET_CLIENT_receive (handle->client, &process_message, handle,
  363. GNUNET_TIME_UNIT_FOREVER_REL);
  364. switch (ntohs (msg->type))
  365. {
  366. case GNUNET_MESSAGE_TYPE_GNS_LOOKUP_RESULT:
  367. LOG (GNUNET_ERROR_TYPE_DEBUG,
  368. "Got LOOKUP_RESULT msg\n");
  369. if (ntohs (msg->size) < sizeof (struct GNUNET_GNS_ClientLookupResultMessage))
  370. {
  371. GNUNET_break (0);
  372. force_reconnect (handle);
  373. return;
  374. }
  375. lookup_msg = (const struct GNUNET_GNS_ClientLookupResultMessage *) msg;
  376. r_id = ntohl (lookup_msg->id);
  377. for (lr = handle->lookup_head; NULL != lr; lr = lr->next)
  378. if (lr->r_id == r_id)
  379. {
  380. process_lookup_reply(lr, lookup_msg);
  381. break;
  382. }
  383. break;
  384. default:
  385. GNUNET_break (0);
  386. force_reconnect (handle);
  387. return;
  388. }
  389. }
  390. /**
  391. * Initialize the connection with the GNS service.
  392. *
  393. * @param cfg configuration to use
  394. * @return handle to the GNS service, or NULL on error
  395. */
  396. struct GNUNET_GNS_Handle *
  397. GNUNET_GNS_connect (const struct GNUNET_CONFIGURATION_Handle *cfg)
  398. {
  399. struct GNUNET_GNS_Handle *handle;
  400. handle = GNUNET_new (struct GNUNET_GNS_Handle);
  401. handle->cfg = cfg;
  402. reconnect (handle);
  403. return handle;
  404. }
  405. /**
  406. * Shutdown connection with the GNS service.
  407. *
  408. * @param handle handle of the GNS connection to stop
  409. */
  410. void
  411. GNUNET_GNS_disconnect (struct GNUNET_GNS_Handle *handle)
  412. {
  413. if (NULL != handle->client)
  414. {
  415. GNUNET_CLIENT_disconnect (handle->client);
  416. handle->client = NULL;
  417. }
  418. if (GNUNET_SCHEDULER_NO_TASK != handle->reconnect_task)
  419. {
  420. GNUNET_SCHEDULER_cancel (handle->reconnect_task);
  421. handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
  422. }
  423. GNUNET_assert (NULL == handle->lookup_head);
  424. GNUNET_free (handle);
  425. }
  426. /**
  427. * Cancel pending lookup request
  428. *
  429. * @param lr the lookup request to cancel
  430. */
  431. void
  432. GNUNET_GNS_lookup_cancel (struct GNUNET_GNS_LookupRequest *lr)
  433. {
  434. struct PendingMessage *p = (struct PendingMessage*) &lr[1];
  435. GNUNET_assert (NULL != lr->gns_handle);
  436. if (GNUNET_NO == p->transmitted)
  437. GNUNET_CONTAINER_DLL_remove (lr->gns_handle->pending_head,
  438. lr->gns_handle->pending_tail,
  439. p);
  440. GNUNET_CONTAINER_DLL_remove (lr->gns_handle->lookup_head,
  441. lr->gns_handle->lookup_tail,
  442. lr);
  443. GNUNET_free (lr);
  444. }
  445. /**
  446. * Perform an asynchronous lookup operation on the GNS.
  447. *
  448. * @param handle handle to the GNS service
  449. * @param name the name to look up
  450. * @param zone the zone to start the resolution in
  451. * @param type the record type to look up
  452. * @param options local options for the lookup
  453. * @param shorten_zone_key the private key of the shorten zone (can be NULL)
  454. * @param proc processor to call on result
  455. * @param proc_cls closure for @a proc
  456. * @return handle to the get request
  457. */
  458. struct GNUNET_GNS_LookupRequest*
  459. GNUNET_GNS_lookup (struct GNUNET_GNS_Handle *handle,
  460. const char *name,
  461. const struct GNUNET_CRYPTO_EcdsaPublicKey *zone,
  462. uint32_t type,
  463. enum GNUNET_GNS_LocalOptions options,
  464. const struct GNUNET_CRYPTO_EcdsaPrivateKey *shorten_zone_key,
  465. GNUNET_GNS_LookupResultProcessor proc,
  466. void *proc_cls)
  467. {
  468. /* IPC to shorten gns names, return shorten_handle */
  469. struct GNUNET_GNS_ClientLookupMessage *lookup_msg;
  470. struct GNUNET_GNS_LookupRequest *lr;
  471. size_t msize;
  472. struct PendingMessage *pending;
  473. if (NULL == name)
  474. {
  475. GNUNET_break (0);
  476. return NULL;
  477. }
  478. LOG (GNUNET_ERROR_TYPE_DEBUG,
  479. "Trying to lookup `%s' in GNS\n",
  480. name);
  481. msize = sizeof (struct GNUNET_GNS_ClientLookupMessage)
  482. + strlen (name) + 1;
  483. if (msize > UINT16_MAX)
  484. {
  485. GNUNET_break (0);
  486. return NULL;
  487. }
  488. lr = GNUNET_malloc (sizeof (struct GNUNET_GNS_LookupRequest) +
  489. sizeof (struct PendingMessage) + msize);
  490. lr->gns_handle = handle;
  491. lr->lookup_proc = proc;
  492. lr->proc_cls = proc_cls;
  493. lr->r_id = handle->r_id_gen++;
  494. pending = (struct PendingMessage *)&lr[1];
  495. pending->size = msize;
  496. pending->r_id = lr->r_id;
  497. GNUNET_CONTAINER_DLL_insert_tail (handle->lookup_head,
  498. handle->lookup_tail, lr);
  499. lookup_msg = (struct GNUNET_GNS_ClientLookupMessage *) &pending[1];
  500. lookup_msg->header.type = htons (GNUNET_MESSAGE_TYPE_GNS_LOOKUP);
  501. lookup_msg->header.size = htons (msize);
  502. lookup_msg->id = htonl (lr->r_id);
  503. lookup_msg->options = htons ((uint16_t) options);
  504. lookup_msg->zone = *zone;
  505. lookup_msg->type = htonl (type);
  506. if (NULL != shorten_zone_key)
  507. {
  508. lookup_msg->have_key = htons (GNUNET_YES);
  509. lookup_msg->shorten_key = *shorten_zone_key;
  510. }
  511. memcpy (&lookup_msg[1], name, strlen (name) + 1);
  512. GNUNET_CONTAINER_DLL_insert_tail (handle->pending_head,
  513. handle->pending_tail,
  514. pending);
  515. process_pending_messages (handle);
  516. return lr;
  517. }
  518. /* end of gns_api.c */