namestore_api_monitor.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 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 namestore/namestore_api_monitor.c
  18. * @brief API to monitor changes in the NAMESTORE
  19. * @author Christian Grothoff
  20. */
  21. #include "platform.h"
  22. #include "gnunet_util_lib.h"
  23. #include "gnunet_crypto_lib.h"
  24. #include "gnunet_constants.h"
  25. #include "gnunet_dnsparser_lib.h"
  26. #include "gnunet_arm_service.h"
  27. #include "gnunet_signatures.h"
  28. #include "gnunet_namestore_service.h"
  29. #include "namestore.h"
  30. /**
  31. * Handle for a monitoring activity.
  32. */
  33. struct GNUNET_NAMESTORE_ZoneMonitor
  34. {
  35. /**
  36. * Configuration (to reconnect).
  37. */
  38. const struct GNUNET_CONFIGURATION_Handle *cfg;
  39. /**
  40. * Handle to namestore service.
  41. */
  42. struct GNUNET_MQ_Handle *mq;
  43. /**
  44. * Function to call on errors.
  45. */
  46. GNUNET_SCHEDULER_TaskCallback error_cb;
  47. /**
  48. * Closure for @e error_cb.
  49. */
  50. void *error_cb_cls;
  51. /**
  52. * Function to call on events.
  53. */
  54. GNUNET_NAMESTORE_RecordMonitor monitor;
  55. /**
  56. * Closure for @e monitor.
  57. */
  58. void *monitor_cls;
  59. /**
  60. * Function called when we've synchronized.
  61. */
  62. GNUNET_SCHEDULER_TaskCallback sync_cb;
  63. /**
  64. * Closure for @e sync_cb.
  65. */
  66. void *sync_cb_cls;
  67. /**
  68. * Monitored zone.
  69. */
  70. struct GNUNET_IDENTITY_PrivateKey zone;
  71. /**
  72. * Do we first iterate over all existing records?
  73. */
  74. int iterate_first;
  75. };
  76. /**
  77. * Reconnect to the namestore service.
  78. *
  79. * @param zm monitor to reconnect
  80. */
  81. static void
  82. reconnect (struct GNUNET_NAMESTORE_ZoneMonitor *zm);
  83. /**
  84. * Handle SYNC message from the namestore service.
  85. *
  86. * @param cls the monitor
  87. * @param msg the sync message
  88. */
  89. static void
  90. handle_sync (void *cls, const struct GNUNET_MessageHeader *msg)
  91. {
  92. struct GNUNET_NAMESTORE_ZoneMonitor *zm = cls;
  93. (void) cls;
  94. (void) msg;
  95. if (NULL != zm->sync_cb)
  96. zm->sync_cb (zm->sync_cb_cls);
  97. }
  98. /**
  99. * We've received a notification about a change to our zone.
  100. * Check that it is well-formed.
  101. *
  102. * @param cls the zone monitor handle
  103. * @param lrm the message from the service.
  104. */
  105. static int
  106. check_result (void *cls, const struct RecordResultMessage *lrm)
  107. {
  108. struct GNUNET_NAMESTORE_ZoneMonitor *zm = cls;
  109. size_t lrm_len;
  110. size_t exp_lrm_len;
  111. size_t name_len;
  112. size_t rd_len;
  113. unsigned rd_count;
  114. const char *name_tmp;
  115. const char *rd_ser_tmp;
  116. (void) cls;
  117. if ((0 != GNUNET_memcmp (&lrm->private_key, &zm->zone)) &&
  118. (GNUNET_NO == GNUNET_is_zero (&zm->zone)))
  119. {
  120. GNUNET_break (0);
  121. return GNUNET_SYSERR;
  122. }
  123. lrm_len = ntohs (lrm->gns_header.header.size);
  124. rd_len = ntohs (lrm->rd_len);
  125. rd_count = ntohs (lrm->rd_count);
  126. name_len = ntohs (lrm->name_len);
  127. if (name_len > MAX_NAME_LEN)
  128. {
  129. GNUNET_break (0);
  130. return GNUNET_SYSERR;
  131. }
  132. exp_lrm_len = sizeof(struct RecordResultMessage) + name_len + rd_len;
  133. if (lrm_len != exp_lrm_len)
  134. {
  135. GNUNET_break (0);
  136. return GNUNET_SYSERR;
  137. }
  138. if (0 == name_len)
  139. {
  140. GNUNET_break (0);
  141. return GNUNET_SYSERR;
  142. }
  143. name_tmp = (const char *) &lrm[1];
  144. if (name_tmp[name_len - 1] != '\0')
  145. {
  146. GNUNET_break (0);
  147. return GNUNET_SYSERR;
  148. }
  149. rd_ser_tmp = (const char *) &name_tmp[name_len];
  150. {
  151. struct GNUNET_GNSRECORD_Data rd[rd_count];
  152. if (GNUNET_OK !=
  153. GNUNET_GNSRECORD_records_deserialize (rd_len, rd_ser_tmp, rd_count, rd))
  154. {
  155. GNUNET_break (0);
  156. return GNUNET_SYSERR;
  157. }
  158. }
  159. return GNUNET_OK;
  160. }
  161. /**
  162. * We've received a notification about a change to our zone.
  163. * Forward to monitor callback.
  164. *
  165. * @param cls the zone monitor handle
  166. * @param lrm the message from the service.
  167. */
  168. static void
  169. handle_result (void *cls, const struct RecordResultMessage *lrm)
  170. {
  171. struct GNUNET_NAMESTORE_ZoneMonitor *zm = cls;
  172. size_t name_len;
  173. size_t rd_len;
  174. unsigned rd_count;
  175. const char *name_tmp;
  176. const char *rd_ser_tmp;
  177. rd_len = ntohs (lrm->rd_len);
  178. rd_count = ntohs (lrm->rd_count);
  179. name_len = ntohs (lrm->name_len);
  180. name_tmp = (const char *) &lrm[1];
  181. rd_ser_tmp = (const char *) &name_tmp[name_len];
  182. {
  183. struct GNUNET_GNSRECORD_Data rd[rd_count];
  184. GNUNET_assert (
  185. GNUNET_OK ==
  186. GNUNET_GNSRECORD_records_deserialize (rd_len, rd_ser_tmp, rd_count, rd));
  187. zm->monitor (zm->monitor_cls, &lrm->private_key, name_tmp, rd_count, rd);
  188. }
  189. }
  190. /**
  191. * Generic error handler, called with the appropriate error code and
  192. * the same closure specified at the creation of the message queue.
  193. * Not every message queue implementation supports an error handler.
  194. *
  195. * @param cls closure with the `struct GNUNET_NAMESTORE_ZoneMonitor *`
  196. * @param error error code
  197. */
  198. static void
  199. mq_error_handler (void *cls, enum GNUNET_MQ_Error error)
  200. {
  201. struct GNUNET_NAMESTORE_ZoneMonitor *zm = cls;
  202. (void) error;
  203. reconnect (zm);
  204. }
  205. /**
  206. * Reconnect to the namestore service.
  207. *
  208. * @param zm monitor to reconnect
  209. */
  210. static void
  211. reconnect (struct GNUNET_NAMESTORE_ZoneMonitor *zm)
  212. {
  213. struct GNUNET_MQ_MessageHandler handlers[] =
  214. { GNUNET_MQ_hd_fixed_size (sync,
  215. GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_SYNC,
  216. struct GNUNET_MessageHeader,
  217. zm),
  218. GNUNET_MQ_hd_var_size (result,
  219. GNUNET_MESSAGE_TYPE_NAMESTORE_RECORD_RESULT,
  220. struct RecordResultMessage,
  221. zm),
  222. GNUNET_MQ_handler_end () };
  223. struct GNUNET_MQ_Envelope *env;
  224. struct ZoneMonitorStartMessage *sm;
  225. if (NULL != zm->mq)
  226. {
  227. GNUNET_MQ_destroy (zm->mq);
  228. zm->error_cb (zm->error_cb_cls);
  229. }
  230. zm->mq = GNUNET_CLIENT_connect (zm->cfg,
  231. "namestore",
  232. handlers,
  233. &mq_error_handler,
  234. zm);
  235. if (NULL == zm->mq)
  236. return;
  237. env = GNUNET_MQ_msg (sm, GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_START);
  238. sm->iterate_first = htonl (zm->iterate_first);
  239. sm->zone = zm->zone;
  240. GNUNET_MQ_send (zm->mq, env);
  241. }
  242. /**
  243. * Begin monitoring a zone for changes. If @a iterate_first is set,
  244. * we Will first call the @a monitor function on all existing records
  245. * in the selected zone(s). In any case, we will call @a sync and
  246. * afterwards call @a monitor whenever a record changes.
  247. *
  248. * @param cfg configuration to use to connect to namestore
  249. * @param zone zone to monitor
  250. * @param iterate_first #GNUNET_YES to first iterate over all existing records,
  251. * #GNUNET_NO to only return changes that happen from now
  252. * on
  253. * @param error_cb function to call on error (i.e. disconnect); note that
  254. * unlike the other error callbacks in this API, a call to this
  255. * function does NOT destroy the monitor handle, it merely signals
  256. * that monitoring is down. You need to still explicitly call
  257. * #GNUNET_NAMESTORE_zone_monitor_stop().
  258. * @param error_cb_cls closure for @a error_cb
  259. * @param monitor function to call on zone changes
  260. * @param monitor_cls closure for @a monitor
  261. * @param sync_cb function called when we're in sync with the namestore
  262. * @param cls closure for @a sync_cb
  263. * @return handle to stop monitoring
  264. */
  265. struct GNUNET_NAMESTORE_ZoneMonitor *
  266. GNUNET_NAMESTORE_zone_monitor_start (
  267. const struct GNUNET_CONFIGURATION_Handle *cfg,
  268. const struct GNUNET_IDENTITY_PrivateKey *zone,
  269. int iterate_first,
  270. GNUNET_SCHEDULER_TaskCallback error_cb,
  271. void *error_cb_cls,
  272. GNUNET_NAMESTORE_RecordMonitor monitor,
  273. void *monitor_cls,
  274. GNUNET_SCHEDULER_TaskCallback sync_cb,
  275. void *sync_cb_cls)
  276. {
  277. struct GNUNET_NAMESTORE_ZoneMonitor *zm;
  278. zm = GNUNET_new (struct GNUNET_NAMESTORE_ZoneMonitor);
  279. if (NULL != zone)
  280. zm->zone = *zone;
  281. zm->iterate_first = iterate_first;
  282. zm->error_cb = error_cb;
  283. zm->error_cb_cls = error_cb_cls;
  284. zm->monitor = monitor;
  285. zm->monitor_cls = monitor_cls;
  286. zm->sync_cb = sync_cb;
  287. zm->sync_cb_cls = sync_cb_cls;
  288. zm->cfg = cfg;
  289. reconnect (zm);
  290. if (NULL == zm->mq)
  291. {
  292. GNUNET_free (zm);
  293. return NULL;
  294. }
  295. return zm;
  296. }
  297. /**
  298. * Calls the monitor processor specified in #GNUNET_NAMESTORE_zone_monitor_start
  299. * for the next record(s). This function is used to allow clients that merely
  300. * monitor the NAMESTORE to still throttle namestore operations, so we can be
  301. * sure that the monitors can keep up.
  302. *
  303. * Note that #GNUNET_NAMESTORE_records_store() only waits for this
  304. * call if the previous limit set by the client was already reached.
  305. * Thus, by using a @a limit greater than 1, monitors basically enable
  306. * a queue of notifications to be processed asynchronously with some
  307. * delay. Note that even with a limit of 1 the
  308. * #GNUNET_NAMESTORE_records_store() function will run asynchronously
  309. * and the continuation may be invoked before the monitors completed
  310. * (or even started) processing the notification. Thus, monitors will
  311. * only closely track the current state of the namestore, but not
  312. * be involved in the transactions.
  313. *
  314. * @param zm the monitor
  315. * @param limit number of records to return to the iterator in one shot
  316. * (before #GNUNET_NAMESTORE_zone_monitor_next is to be called again)
  317. */
  318. void
  319. GNUNET_NAMESTORE_zone_monitor_next (struct GNUNET_NAMESTORE_ZoneMonitor *zm,
  320. uint64_t limit)
  321. {
  322. struct GNUNET_MQ_Envelope *env;
  323. struct ZoneMonitorNextMessage *nm;
  324. env = GNUNET_MQ_msg (nm, GNUNET_MESSAGE_TYPE_NAMESTORE_MONITOR_NEXT);
  325. nm->limit = GNUNET_htonll (limit);
  326. GNUNET_MQ_send (zm->mq, env);
  327. }
  328. /**
  329. * Stop monitoring a zone for changes.
  330. *
  331. * @param zm handle to the monitor activity to stop
  332. */
  333. void
  334. GNUNET_NAMESTORE_zone_monitor_stop (struct GNUNET_NAMESTORE_ZoneMonitor *zm)
  335. {
  336. if (NULL != zm->mq)
  337. {
  338. GNUNET_MQ_destroy (zm->mq);
  339. zm->mq = NULL;
  340. }
  341. GNUNET_free (zm);
  342. }
  343. /* end of namestore_api_monitor.c */