transport_api_monitor_peers.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2009-2014, 2016 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 transport/transport_api_monitor_peers.c
  18. * @brief montoring api for transport peer status
  19. *
  20. * This api provides the ability to query the transport service about
  21. * the connection status of a specific or all peers.
  22. *
  23. * Calls back with information about peer(s) including address used, state and
  24. * state timeout for peer requests.
  25. */
  26. #include "platform.h"
  27. #include "gnunet_util_lib.h"
  28. #include "gnunet_arm_service.h"
  29. #include "gnunet_hello_lib.h"
  30. #include "gnunet_protocols.h"
  31. #include "gnunet_transport_service.h"
  32. #include "transport.h"
  33. /**
  34. * Context for iterating validation entries.
  35. */
  36. struct GNUNET_TRANSPORT_PeerMonitoringContext
  37. {
  38. /**
  39. * Function to call with the binary address.
  40. */
  41. GNUNET_TRANSPORT_PeerIterateCallback cb;
  42. /**
  43. * Closure for @e cb.
  44. */
  45. void *cb_cls;
  46. /**
  47. * Connection to the service.
  48. */
  49. struct GNUNET_MQ_Handle *mq;
  50. /**
  51. * Configuration we use.
  52. */
  53. const struct GNUNET_CONFIGURATION_Handle *cfg;
  54. /**
  55. * Backoff for reconnect.
  56. */
  57. struct GNUNET_TIME_Relative backoff;
  58. /**
  59. * Task ID for reconnect.
  60. */
  61. struct GNUNET_SCHEDULER_Task *reconnect_task;
  62. /**
  63. * Identity of the peer to monitor.
  64. */
  65. struct GNUNET_PeerIdentity peer;
  66. /**
  67. * Was this a one-shot request?
  68. */
  69. int one_shot;
  70. };
  71. /**
  72. * Check if a state is defined as connected
  73. *
  74. * @param state the state value
  75. * @return #GNUNET_YES or #GNUNET_NO
  76. */
  77. int
  78. GNUNET_TRANSPORT_is_connected (enum GNUNET_TRANSPORT_PeerState state)
  79. {
  80. switch (state)
  81. {
  82. case GNUNET_TRANSPORT_PS_NOT_CONNECTED:
  83. case GNUNET_TRANSPORT_PS_INIT_ATS:
  84. case GNUNET_TRANSPORT_PS_SYN_SENT:
  85. case GNUNET_TRANSPORT_PS_SYN_RECV_ATS:
  86. case GNUNET_TRANSPORT_PS_SYN_RECV_ACK:
  87. return GNUNET_NO;
  88. case GNUNET_TRANSPORT_PS_CONNECTED:
  89. case GNUNET_TRANSPORT_PS_RECONNECT_ATS:
  90. case GNUNET_TRANSPORT_PS_RECONNECT_SENT:
  91. case GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT:
  92. return GNUNET_YES;
  93. case GNUNET_TRANSPORT_PS_DISCONNECT:
  94. case GNUNET_TRANSPORT_PS_DISCONNECT_FINISHED:
  95. return GNUNET_NO;
  96. default:
  97. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  98. "Unhandled state `%s'\n",
  99. GNUNET_TRANSPORT_ps2s (state));
  100. GNUNET_break (0);
  101. break;
  102. }
  103. return GNUNET_SYSERR;
  104. }
  105. /**
  106. * Convert peer state to human-readable string.
  107. *
  108. * @param state the state value
  109. * @return corresponding string
  110. */
  111. const char *
  112. GNUNET_TRANSPORT_ps2s (enum GNUNET_TRANSPORT_PeerState state)
  113. {
  114. switch (state)
  115. {
  116. case GNUNET_TRANSPORT_PS_NOT_CONNECTED:
  117. return "S_NOT_CONNECTED";
  118. case GNUNET_TRANSPORT_PS_INIT_ATS:
  119. return "S_INIT_ATS";
  120. case GNUNET_TRANSPORT_PS_SYN_SENT:
  121. return "S_SYN_SENT";
  122. case GNUNET_TRANSPORT_PS_SYN_RECV_ATS:
  123. return "S_SYN_RECV_ATS";
  124. case GNUNET_TRANSPORT_PS_SYN_RECV_ACK:
  125. return "S_SYN_RECV_ACK";
  126. case GNUNET_TRANSPORT_PS_CONNECTED:
  127. return "S_CONNECTED";
  128. case GNUNET_TRANSPORT_PS_RECONNECT_ATS:
  129. return "S_RECONNECT_ATS";
  130. case GNUNET_TRANSPORT_PS_RECONNECT_SENT:
  131. return "S_RECONNECT_SENT";
  132. case GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT:
  133. return "S_SWITCH_SYN_SENT";
  134. case GNUNET_TRANSPORT_PS_DISCONNECT:
  135. return "S_DISCONNECT";
  136. case GNUNET_TRANSPORT_PS_DISCONNECT_FINISHED:
  137. return "S_DISCONNECT_FINISHED";
  138. default:
  139. GNUNET_break (0);
  140. return "UNDEFINED";
  141. }
  142. }
  143. /**
  144. * Task run to re-establish the connection.
  145. *
  146. * @param cls our `struct GNUNET_TRANSPORT_PeerMonitoringContext *`
  147. */
  148. static void
  149. do_peer_connect (void *cls);
  150. /**
  151. * Cut the existing connection and reconnect.
  152. *
  153. * @param pal_ctx our context
  154. */
  155. static void
  156. reconnect_peer_ctx (struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx)
  157. {
  158. GNUNET_assert (GNUNET_NO == pal_ctx->one_shot);
  159. GNUNET_MQ_destroy (pal_ctx->mq);
  160. pal_ctx->mq = NULL;
  161. pal_ctx->cb (pal_ctx->cb_cls,
  162. NULL,
  163. NULL,
  164. GNUNET_TRANSPORT_PS_NOT_CONNECTED,
  165. GNUNET_TIME_UNIT_ZERO_ABS);
  166. pal_ctx->backoff = GNUNET_TIME_STD_BACKOFF (pal_ctx->backoff);
  167. pal_ctx->reconnect_task = GNUNET_SCHEDULER_add_delayed (pal_ctx->backoff,
  168. &do_peer_connect,
  169. pal_ctx);
  170. }
  171. /**
  172. * Function called with responses from the service.
  173. *
  174. * @param cls our `struct GNUNET_TRANSPORT_PeerMonitoringContext *`
  175. * @param msg message from service
  176. */
  177. static void
  178. handle_response_end (void *cls,
  179. const struct GNUNET_MessageHeader *msg)
  180. {
  181. struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx = cls;
  182. if (pal_ctx->one_shot)
  183. {
  184. /* iteration finished */
  185. pal_ctx->cb (pal_ctx->cb_cls,
  186. NULL,
  187. NULL,
  188. GNUNET_TRANSPORT_PS_NOT_CONNECTED,
  189. GNUNET_TIME_UNIT_ZERO_ABS);
  190. GNUNET_TRANSPORT_monitor_peers_cancel (pal_ctx);
  191. return;
  192. }
  193. /* not quite what we expected, reconnect */
  194. GNUNET_break (0);
  195. reconnect_peer_ctx (pal_ctx);
  196. }
  197. /**
  198. * Function called to check responses from the service.
  199. *
  200. * @param cls our `struct GNUNET_TRANSPORT_PeerMonitoringContext *`
  201. * @param pir_msg message with the human-readable address
  202. * @return #GNUNET_OK if @a pir_msg is well-formed
  203. */
  204. static int
  205. check_response (void *cls,
  206. const struct PeerIterateResponseMessage *pir_msg)
  207. {
  208. uint16_t size = ntohs (pir_msg->header.size) - sizeof(*pir_msg);
  209. size_t alen = ntohl (pir_msg->addrlen);
  210. size_t tlen = ntohl (pir_msg->pluginlen);
  211. const char *addr;
  212. const char *transport_name;
  213. if (size != tlen + alen)
  214. {
  215. GNUNET_break (0);
  216. return GNUNET_SYSERR;
  217. }
  218. if ((0 == tlen) && (0 == alen))
  219. return GNUNET_OK;
  220. if (0 == tlen)
  221. {
  222. GNUNET_break (0); /* This must not happen: address without plugin */
  223. return GNUNET_SYSERR;
  224. }
  225. addr = (const char *) &pir_msg[1];
  226. transport_name = &addr[alen];
  227. if (transport_name[tlen - 1] != '\0')
  228. {
  229. GNUNET_break (0);
  230. return GNUNET_SYSERR;
  231. }
  232. return GNUNET_OK;
  233. }
  234. /**
  235. * Function called with responses from the service.
  236. *
  237. * @param cls our `struct GNUNET_TRANSPORT_PeerMonitoringContext *`
  238. * @param msg message with the human-readable address
  239. */
  240. static void
  241. handle_response (void *cls,
  242. const struct PeerIterateResponseMessage *pir_msg)
  243. {
  244. struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx = cls;
  245. struct GNUNET_HELLO_Address *address;
  246. size_t alen = ntohl (pir_msg->addrlen);
  247. size_t tlen = ntohl (pir_msg->pluginlen);
  248. const char *addr;
  249. const char *transport_name;
  250. if ((0 == tlen) &&
  251. (0 == alen))
  252. {
  253. /* No address available */
  254. pal_ctx->cb (pal_ctx->cb_cls,
  255. &pir_msg->peer,
  256. NULL,
  257. ntohl (pir_msg->state),
  258. GNUNET_TIME_absolute_ntoh (pir_msg->state_timeout));
  259. return;
  260. }
  261. addr = (const char *) &pir_msg[1];
  262. transport_name = &addr[alen];
  263. /* notify client */
  264. address = GNUNET_HELLO_address_allocate (&pir_msg->peer,
  265. transport_name,
  266. addr,
  267. alen,
  268. ntohl (pir_msg->local_address_info));
  269. pal_ctx->cb (pal_ctx->cb_cls,
  270. &pir_msg->peer,
  271. address,
  272. ntohl (pir_msg->state),
  273. GNUNET_TIME_absolute_ntoh (pir_msg->state_timeout));
  274. GNUNET_HELLO_address_free (address);
  275. }
  276. /**
  277. * Generic error handler, called with the appropriate error code and
  278. * the same closure specified at the creation of the message queue.
  279. * Not every message queue implementation supports an error handler.
  280. *
  281. * @param cls closure with the `struct GNUNET_TRANSPORT_PeerMonitoringContext *`
  282. * @param error error code
  283. */
  284. static void
  285. mq_error_handler (void *cls,
  286. enum GNUNET_MQ_Error error)
  287. {
  288. struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx = cls;
  289. if (pal_ctx->one_shot)
  290. {
  291. /* Disconnect */
  292. pal_ctx->cb (pal_ctx->cb_cls,
  293. NULL,
  294. NULL,
  295. GNUNET_TRANSPORT_PS_NOT_CONNECTED,
  296. GNUNET_TIME_UNIT_ZERO_ABS);
  297. GNUNET_TRANSPORT_monitor_peers_cancel (pal_ctx);
  298. return;
  299. }
  300. reconnect_peer_ctx (pal_ctx);
  301. }
  302. /**
  303. * Task run to re-establish the connection.
  304. *
  305. * @param cls our `struct GNUNET_TRANSPORT_PeerMonitoringContext *`
  306. */
  307. static void
  308. do_peer_connect (void *cls)
  309. {
  310. struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx = cls;
  311. struct GNUNET_MQ_MessageHandler handlers[] = {
  312. GNUNET_MQ_hd_var_size (response,
  313. GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_RESPONSE,
  314. struct PeerIterateResponseMessage,
  315. pal_ctx),
  316. GNUNET_MQ_hd_fixed_size (response_end,
  317. GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_RESPONSE_END,
  318. struct GNUNET_MessageHeader,
  319. pal_ctx),
  320. GNUNET_MQ_handler_end ()
  321. };
  322. struct PeerMonitorMessage *msg;
  323. struct GNUNET_MQ_Envelope *env;
  324. pal_ctx->reconnect_task = NULL;
  325. pal_ctx->mq = GNUNET_CLIENT_connect (pal_ctx->cfg,
  326. "transport",
  327. handlers,
  328. &mq_error_handler,
  329. pal_ctx);
  330. if (NULL == pal_ctx->mq)
  331. return;
  332. env = GNUNET_MQ_msg (msg,
  333. GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_REQUEST);
  334. msg->one_shot = htonl (pal_ctx->one_shot);
  335. msg->peer = pal_ctx->peer;
  336. GNUNET_MQ_send (pal_ctx->mq,
  337. env);
  338. }
  339. /**
  340. * Return information about a specific peer or all peers currently known to
  341. * transport service once or in monitoring mode. To obtain information about
  342. * a specific peer, a peer identity can be passed. To obtain information about
  343. * all peers currently known to transport service, NULL can be passed as peer
  344. * identity.
  345. *
  346. * For each peer, the callback is called with information about the address used
  347. * to communicate with this peer, the state this peer is currently in and the
  348. * the current timeout for this state.
  349. *
  350. * Upon completion, the 'GNUNET_TRANSPORT_PeerIterateCallback' is called one
  351. * more time with 'NULL'. After this, the operation must no longer be
  352. * explicitly canceled.
  353. *
  354. * The #GNUNET_TRANSPORT_monitor_peers_cancel call MUST not be called in the
  355. * the peer_callback!
  356. *
  357. * @param cfg configuration to use
  358. * @param peer a specific peer identity to obtain information for,
  359. * NULL for all peers
  360. * @param one_shot #GNUNET_YES to return the current state and then end (with NULL+NULL),
  361. * #GNUNET_NO to monitor peers continuously
  362. * @param peer_callback function to call with the results
  363. * @param peer_callback_cls closure for @a peer_address_callback
  364. */
  365. struct GNUNET_TRANSPORT_PeerMonitoringContext *
  366. GNUNET_TRANSPORT_monitor_peers (const struct GNUNET_CONFIGURATION_Handle *cfg,
  367. const struct GNUNET_PeerIdentity *peer,
  368. int one_shot,
  369. GNUNET_TRANSPORT_PeerIterateCallback
  370. peer_callback,
  371. void *peer_callback_cls)
  372. {
  373. struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx
  374. = GNUNET_new (struct GNUNET_TRANSPORT_PeerMonitoringContext);
  375. pal_ctx->cb = peer_callback;
  376. pal_ctx->cb_cls = peer_callback_cls;
  377. pal_ctx->cfg = cfg;
  378. if (NULL != peer)
  379. pal_ctx->peer = *peer;
  380. pal_ctx->one_shot = one_shot;
  381. do_peer_connect (pal_ctx);
  382. if (NULL == pal_ctx->mq)
  383. {
  384. GNUNET_free (pal_ctx);
  385. return NULL;
  386. }
  387. return pal_ctx;
  388. }
  389. /**
  390. * Cancel request to monitor peers
  391. *
  392. * @param pic handle for the request to cancel
  393. */
  394. void
  395. GNUNET_TRANSPORT_monitor_peers_cancel (struct
  396. GNUNET_TRANSPORT_PeerMonitoringContext *
  397. pic)
  398. {
  399. if (NULL != pic->mq)
  400. {
  401. GNUNET_MQ_destroy (pic->mq);
  402. pic->mq = NULL;
  403. }
  404. if (NULL != pic->reconnect_task)
  405. {
  406. GNUNET_SCHEDULER_cancel (pic->reconnect_task);
  407. pic->reconnect_task = NULL;
  408. }
  409. GNUNET_free (pic);
  410. }
  411. /* end of transport_api_monitor_peers.c */