gnunet-service-namecache.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2012, 2013 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 namecache/gnunet-service-namecache.c
  18. * @brief namecache for the GNUnet naming system
  19. * @author Matthias Wachs
  20. * @author Christian Grothoff
  21. */
  22. #include "platform.h"
  23. #include "gnunet_util_lib.h"
  24. #include "gnunet_dnsparser_lib.h"
  25. #include "gnunet_statistics_service.h"
  26. #include "gnunet_namecache_service.h"
  27. #include "gnunet_namecache_plugin.h"
  28. #include "gnunet_signatures.h"
  29. #include "namecache.h"
  30. #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util", syscall, filename)
  31. /**
  32. * A namecache client
  33. */
  34. struct NamecacheClient
  35. {
  36. /**
  37. * The client
  38. */
  39. struct GNUNET_SERVICE_Client *client;
  40. /**
  41. * The message queue to talk to @e client.
  42. */
  43. struct GNUNET_MQ_Handle *mq;
  44. };
  45. /**
  46. * Configuration handle.
  47. */
  48. static const struct GNUNET_CONFIGURATION_Handle *GSN_cfg;
  49. /**
  50. * Handle to the statistics service
  51. */
  52. static struct GNUNET_STATISTICS_Handle *statistics;
  53. /**
  54. * Database handle
  55. */
  56. static struct GNUNET_NAMECACHE_PluginFunctions *GSN_database;
  57. /**
  58. * Name of the database plugin
  59. */
  60. static char *db_lib_name;
  61. /**
  62. * Task run during shutdown.
  63. *
  64. * @param cls unused
  65. */
  66. static void
  67. cleanup_task (void *cls)
  68. {
  69. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  70. "Stopping namecache service\n");
  71. GNUNET_break (NULL ==
  72. GNUNET_PLUGIN_unload (db_lib_name,
  73. GSN_database));
  74. GNUNET_free (db_lib_name);
  75. db_lib_name = NULL;
  76. if (NULL != statistics)
  77. {
  78. GNUNET_STATISTICS_destroy (statistics,
  79. GNUNET_NO);
  80. statistics = NULL;
  81. }
  82. }
  83. /**
  84. * Called whenever a client is disconnected.
  85. * Frees our resources associated with that client.
  86. *
  87. * @param cls closure
  88. * @param client identification of the client
  89. * @param app_ctx the `struct NamecacheClient` for this @a client
  90. */
  91. static void
  92. client_disconnect_cb (void *cls,
  93. struct GNUNET_SERVICE_Client *client,
  94. void *app_ctx)
  95. {
  96. struct NamecacheClient *nc = app_ctx;
  97. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  98. "Client %p disconnected\n",
  99. client);
  100. GNUNET_free (nc);
  101. }
  102. /**
  103. * Add a client to our list of active clients.
  104. *
  105. * @param cls NULL
  106. * @param client client to add
  107. * @param mq queue to talk to @a client
  108. * @return internal namecache client structure for this client
  109. */
  110. static void *
  111. client_connect_cb (void *cls,
  112. struct GNUNET_SERVICE_Client *client,
  113. struct GNUNET_MQ_Handle *mq)
  114. {
  115. struct NamecacheClient *nc;
  116. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  117. "Client %p connected\n",
  118. client);
  119. nc = GNUNET_new (struct NamecacheClient);
  120. nc->client = client;
  121. nc->mq = mq;
  122. return nc;
  123. }
  124. /**
  125. * Context for name lookups passed from #handle_lookup_block to
  126. * #handle_lookup_block_it as closure
  127. */
  128. struct LookupBlockContext
  129. {
  130. /**
  131. * The client to send the response to
  132. */
  133. struct NamecacheClient *nc;
  134. /**
  135. * Operation id for the name lookup
  136. */
  137. uint32_t request_id;
  138. /**
  139. * Lookup status
  140. */
  141. int status;
  142. };
  143. /**
  144. * A #GNUNET_NAMECACHE_BlockCallback for name lookups in #handle_lookup_block
  145. *
  146. * @param cls a `struct LookupNameContext *` with information about the request
  147. * @param block the block
  148. */
  149. static void
  150. handle_lookup_block_it (void *cls,
  151. const struct GNUNET_GNSRECORD_Block *block)
  152. {
  153. struct LookupBlockContext *lnc = cls;
  154. struct GNUNET_MQ_Envelope *env;
  155. struct LookupBlockResponseMessage *r;
  156. size_t esize;
  157. size_t bsize;
  158. bsize = ntohl (block->purpose.size);
  159. if (bsize <
  160. (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) + sizeof (struct GNUNET_TIME_AbsoluteNBO)))
  161. {
  162. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  163. "Malformed block.");
  164. lnc->status = GNUNET_SYSERR;
  165. return;
  166. }
  167. esize = ntohl (block->purpose.size)
  168. - sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose)
  169. - sizeof (struct GNUNET_TIME_AbsoluteNBO);
  170. env = GNUNET_MQ_msg_extra (r,
  171. esize,
  172. GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK_RESPONSE);
  173. r->gns_header.r_id = htonl (lnc->request_id);
  174. r->expire = block->expiration_time;
  175. r->signature = block->signature;
  176. r->derived_key = block->derived_key;
  177. GNUNET_memcpy (&r[1],
  178. &block[1],
  179. esize);
  180. GNUNET_STATISTICS_update (statistics,
  181. "blocks found in cache",
  182. 1,
  183. GNUNET_NO);
  184. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  185. "Sending NAMECACHE_LOOKUP_BLOCK_RESPONSE message with expiration time %s\n",
  186. GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh (r->expire)));
  187. GNUNET_MQ_send (lnc->nc->mq,
  188. env);
  189. }
  190. /**
  191. * Handles a #GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK message
  192. *
  193. * @param cls a `struct NamecacheClient *`
  194. * @param the inbound message
  195. */
  196. static void
  197. handle_lookup_block (void *cls,
  198. const struct LookupBlockMessage *ln_msg)
  199. {
  200. struct NamecacheClient *nc = cls;
  201. struct GNUNET_MQ_Envelope *env;
  202. struct LookupBlockContext lnc;
  203. struct LookupBlockResponseMessage *zir_end;
  204. int ret;
  205. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  206. "Received NAMECACHE_LOOKUP_BLOCK message\n");
  207. GNUNET_STATISTICS_update (statistics,
  208. "blocks looked up",
  209. 1,
  210. GNUNET_NO);
  211. lnc.request_id = ntohl (ln_msg->gns_header.r_id);
  212. lnc.nc = nc;
  213. lnc.status = GNUNET_OK;
  214. if (GNUNET_SYSERR ==
  215. (ret = GSN_database->lookup_block (GSN_database->cls,
  216. &ln_msg->query,
  217. &handle_lookup_block_it,
  218. &lnc)))
  219. {
  220. /* internal error (in database plugin); might be best to just hang up on
  221. plugin rather than to signal that there are 'no' results, which
  222. might also be false... */
  223. GNUNET_break (0);
  224. GNUNET_SERVICE_client_drop (nc->client);
  225. return;
  226. }
  227. if ((0 == ret) || (GNUNET_SYSERR == lnc.status))
  228. {
  229. /* no records match at all, generate empty response */
  230. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  231. "Sending empty NAMECACHE_LOOKUP_BLOCK_RESPONSE message\n");
  232. env = GNUNET_MQ_msg (zir_end,
  233. GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK_RESPONSE);
  234. zir_end->gns_header.r_id = ln_msg->gns_header.r_id;
  235. GNUNET_MQ_send (nc->mq,
  236. env);
  237. }
  238. GNUNET_SERVICE_client_continue (nc->client);
  239. }
  240. /**
  241. * Check a #GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE message
  242. *
  243. * @param cls our `struct NamecacheClient`
  244. * @param rp_msg message to process
  245. * @return #GNUNET_OK (always fine)
  246. */
  247. static int
  248. check_block_cache (void *cls,
  249. const struct BlockCacheMessage *rp_msg)
  250. {
  251. return GNUNET_OK;
  252. }
  253. /**
  254. * Handles a #GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE message
  255. *
  256. * @param cls our `struct NamecacheClient`
  257. * @param rp_msg message to process
  258. */
  259. static void
  260. handle_block_cache (void *cls,
  261. const struct BlockCacheMessage *rp_msg)
  262. {
  263. struct NamecacheClient *nc = cls;
  264. struct GNUNET_MQ_Envelope *env;
  265. struct BlockCacheResponseMessage *rpr_msg;
  266. struct GNUNET_GNSRECORD_Block *block;
  267. size_t esize;
  268. int res;
  269. GNUNET_STATISTICS_update (statistics,
  270. "blocks cached",
  271. 1,
  272. GNUNET_NO);
  273. esize = ntohs (rp_msg->gns_header.header.size) - sizeof (struct BlockCacheMessage);
  274. block = GNUNET_malloc (sizeof (struct GNUNET_GNSRECORD_Block) + esize);
  275. block->signature = rp_msg->signature;
  276. block->derived_key = rp_msg->derived_key;
  277. block->purpose.size = htonl (sizeof (struct GNUNET_CRYPTO_EccSignaturePurpose) +
  278. sizeof (struct GNUNET_TIME_AbsoluteNBO) +
  279. esize);
  280. block->expiration_time = rp_msg->expire;
  281. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  282. "Received NAMECACHE_BLOCK_CACHE message with expiration time %s\n",
  283. GNUNET_STRINGS_absolute_time_to_string (GNUNET_TIME_absolute_ntoh (block->expiration_time)));
  284. GNUNET_memcpy (&block[1],
  285. &rp_msg[1],
  286. esize);
  287. res = GSN_database->cache_block (GSN_database->cls,
  288. block);
  289. GNUNET_free (block);
  290. env = GNUNET_MQ_msg (rpr_msg,
  291. GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE_RESPONSE);
  292. rpr_msg->gns_header.r_id = rp_msg->gns_header.r_id;
  293. rpr_msg->op_result = htonl (res);
  294. GNUNET_MQ_send (nc->mq,
  295. env);
  296. GNUNET_SERVICE_client_continue (nc->client);
  297. }
  298. /**
  299. * Process namecache requests.
  300. *
  301. * @param cls closure
  302. * @param cfg configuration to use
  303. * @param service the initialized service
  304. */
  305. static void
  306. run (void *cls,
  307. const struct GNUNET_CONFIGURATION_Handle *cfg,
  308. struct GNUNET_SERVICE_Handle *service)
  309. {
  310. char *database;
  311. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  312. "Starting namecache service\n");
  313. GSN_cfg = cfg;
  314. /* Loading database plugin */
  315. if (GNUNET_OK !=
  316. GNUNET_CONFIGURATION_get_value_string (cfg,
  317. "namecache",
  318. "database",
  319. &database))
  320. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  321. "No database backend configured\n");
  322. GNUNET_asprintf (&db_lib_name,
  323. "libgnunet_plugin_namecache_%s",
  324. database);
  325. GSN_database = GNUNET_PLUGIN_load (db_lib_name,
  326. (void *) GSN_cfg);
  327. GNUNET_free (database);
  328. if (NULL == GSN_database)
  329. {
  330. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  331. "Could not load database backend `%s'\n",
  332. db_lib_name);
  333. GNUNET_SCHEDULER_add_now (&cleanup_task,
  334. NULL);
  335. return;
  336. }
  337. statistics = GNUNET_STATISTICS_create ("namecache",
  338. cfg);
  339. /* Configuring server handles */
  340. GNUNET_SCHEDULER_add_shutdown (&cleanup_task,
  341. NULL);
  342. }
  343. /**
  344. * Define "main" method using service macro.
  345. */
  346. GNUNET_SERVICE_MAIN
  347. ("namecache",
  348. GNUNET_SERVICE_OPTION_NONE,
  349. &run,
  350. &client_connect_cb,
  351. &client_disconnect_cb,
  352. NULL,
  353. GNUNET_MQ_hd_fixed_size (lookup_block,
  354. GNUNET_MESSAGE_TYPE_NAMECACHE_LOOKUP_BLOCK,
  355. struct LookupBlockMessage,
  356. NULL),
  357. GNUNET_MQ_hd_var_size (block_cache,
  358. GNUNET_MESSAGE_TYPE_NAMECACHE_BLOCK_CACHE,
  359. struct BlockCacheMessage,
  360. NULL),
  361. GNUNET_MQ_handler_end ());
  362. /* end of gnunet-service-namecache.c */