transport_api2_monitor.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 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 transport/transport_api2_monitor.c
  18. * @brief implementation of the gnunet_transport_monitor_service.h API
  19. * @author Christian Grothoff
  20. */
  21. #include "platform.h"
  22. #include "gnunet_util_lib.h"
  23. #include "gnunet_protocols.h"
  24. #include "gnunet_transport_monitor_service.h"
  25. #include "transport.h"
  26. /**
  27. * Opaque handle to the transport service for monitors.
  28. */
  29. struct GNUNET_TRANSPORT_MonitorContext
  30. {
  31. /**
  32. * Our configuration.
  33. */
  34. const struct GNUNET_CONFIGURATION_Handle *cfg;
  35. /**
  36. * Queue to talk to the transport service.
  37. */
  38. struct GNUNET_MQ_Handle *mq;
  39. /**
  40. * Peer we monitor, all zeros for "all"
  41. */
  42. struct GNUNET_PeerIdentity peer;
  43. /**
  44. * #GNUNET_YES to return the current state and then end.
  45. */
  46. int one_shot;
  47. /**
  48. * Function to call with monitor data.
  49. */
  50. GNUNET_TRANSPORT_MonitorCallback cb;
  51. /**
  52. * Closure for @e cb.
  53. */
  54. void *cb_cls;
  55. };
  56. /**
  57. * (re)connect our monitor to the transport service
  58. *
  59. * @param mc handle to reconnect
  60. */
  61. static void
  62. reconnect (struct GNUNET_TRANSPORT_MonitorContext *mc);
  63. /**
  64. * Send message to the transport service about our montoring
  65. * desire.
  66. *
  67. * @param ai address to delete
  68. */
  69. static void
  70. send_start_monitor (struct GNUNET_TRANSPORT_MonitorContext *mc)
  71. {
  72. struct GNUNET_MQ_Envelope *env;
  73. struct GNUNET_TRANSPORT_MonitorStart *smm;
  74. if (NULL == mc->mq)
  75. return;
  76. env = GNUNET_MQ_msg (smm, GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_START);
  77. smm->one_shot = htonl ((uint32_t) mc->one_shot);
  78. smm->peer = mc->peer;
  79. GNUNET_MQ_send (mc->mq, env);
  80. }
  81. /**
  82. * Disconnect from the transport service.
  83. *
  84. * @param mc service to disconnect from
  85. */
  86. static void
  87. disconnect (struct GNUNET_TRANSPORT_MonitorContext *mc)
  88. {
  89. if (NULL == mc->mq)
  90. return;
  91. GNUNET_MQ_destroy (mc->mq);
  92. mc->mq = NULL;
  93. }
  94. /**
  95. * Function called on MQ errors. Reconnects to the service.
  96. *
  97. * @param cls our `struct GNUNET_TRANSPORT_MonitorContext *`
  98. * @param error what error happened?
  99. */
  100. static void
  101. error_handler (void *cls, enum GNUNET_MQ_Error error)
  102. {
  103. struct GNUNET_TRANSPORT_MonitorContext *mc = cls;
  104. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  105. "MQ failure %d, reconnecting to transport service.\n",
  106. error);
  107. disconnect (mc);
  108. /* TODO: maybe do this with exponential backoff/delay */
  109. reconnect (mc);
  110. }
  111. /**
  112. * Transport service sends us information about what is going on.
  113. * Check if @a md is well-formed.
  114. *
  115. * @param cls our `struct GNUNET_TRANSPORT_MonitorContext *`
  116. * @param md the monitor data we got
  117. * @return #GNUNET_OK if @a smt is well-formed
  118. */
  119. static int
  120. check_monitor_data (void *cls, const struct GNUNET_TRANSPORT_MonitorData *md)
  121. {
  122. (void) cls;
  123. GNUNET_MQ_check_zero_termination (md);
  124. return GNUNET_OK;
  125. }
  126. /**
  127. * Transport service sends us information about what is going on.
  128. *
  129. * @param cls our `struct GNUNET_TRANSPORT_MonitorContext *`
  130. * @param md monitor data
  131. */
  132. static void
  133. handle_monitor_data (void *cls, const struct GNUNET_TRANSPORT_MonitorData *md)
  134. {
  135. struct GNUNET_TRANSPORT_MonitorContext *mc = cls;
  136. struct GNUNET_TRANSPORT_MonitorInformation mi;
  137. mi.address = (const char *) &md[1];
  138. mi.nt = (enum GNUNET_NetworkType) ntohl (md->nt);
  139. mi.cs = (enum GNUNET_TRANSPORT_ConnectionStatus) ntohl (md->cs);
  140. mi.num_msg_pending = ntohl (md->num_msg_pending);
  141. mi.num_bytes_pending = ntohl (md->num_bytes_pending);
  142. mi.last_validation = GNUNET_TIME_absolute_ntoh (md->last_validation);
  143. mi.valid_until = GNUNET_TIME_absolute_ntoh (md->valid_until);
  144. mi.next_validation = GNUNET_TIME_absolute_ntoh (md->next_validation);
  145. mi.rtt = GNUNET_TIME_relative_ntoh (md->rtt);
  146. mc->cb (mc->cb_cls, &md->peer, &mi);
  147. }
  148. /**
  149. * One shot was requested, and transport service is done.
  150. *
  151. * @param cls our `struct GNUNET_TRANSPORT_MonitorContext *`
  152. * @param me end message
  153. */
  154. static void
  155. handle_monitor_end (void *cls, const struct GNUNET_MessageHeader *me)
  156. {
  157. struct GNUNET_TRANSPORT_MonitorContext *mc = cls;
  158. if (GNUNET_YES != mc->one_shot)
  159. {
  160. GNUNET_break (0);
  161. disconnect (mc);
  162. reconnect (mc);
  163. return;
  164. }
  165. mc->cb (mc->cb_cls, NULL, NULL);
  166. GNUNET_TRANSPORT_monitor_cancel (mc);
  167. }
  168. /**
  169. * (re)connect our monitor to the transport service
  170. *
  171. * @param mc handle to reconnect
  172. */
  173. static void
  174. reconnect (struct GNUNET_TRANSPORT_MonitorContext *mc)
  175. {
  176. struct GNUNET_MQ_MessageHandler handlers[] =
  177. { GNUNET_MQ_hd_var_size (monitor_data,
  178. GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_DATA,
  179. struct GNUNET_TRANSPORT_MonitorData,
  180. mc),
  181. GNUNET_MQ_hd_fixed_size (monitor_end,
  182. GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_END,
  183. struct GNUNET_MessageHeader,
  184. mc),
  185. GNUNET_MQ_handler_end () };
  186. mc->mq =
  187. GNUNET_CLIENT_connect (mc->cfg, "transport", handlers, &error_handler, mc);
  188. if (NULL == mc->mq)
  189. return;
  190. send_start_monitor (mc);
  191. }
  192. /**
  193. * Return information about a specific peer or all peers currently known to
  194. * transport service once or in monitoring mode. To obtain information about
  195. * a specific peer, a peer identity can be passed. To obtain information about
  196. * all peers currently known to transport service, NULL can be passed as peer
  197. * identity.
  198. *
  199. * For each peer, the callback is called with information about the address used
  200. * to communicate with this peer, the state this peer is currently in and the
  201. * the current timeout for this state.
  202. *
  203. * Upon completion, the #GNUNET_TRANSPORT_PeerIterateCallback is called one
  204. * more time with `NULL`. After this, the operation must no longer be
  205. * explicitly canceled.
  206. *
  207. * The #GNUNET_TRANSPORT_monitor_peers_cancel call MUST not be called in the
  208. * the peer_callback!
  209. *
  210. * @param cfg configuration to use
  211. * @param peer a specific peer identity to obtain information for,
  212. * NULL for all peers
  213. * @param one_shot #GNUNET_YES to return the current state and then end (with NULL+NULL),
  214. * #GNUNET_NO to monitor peers continuously
  215. * @param cb function to call with the results
  216. * @param cb_cls closure for @a mc
  217. */
  218. struct GNUNET_TRANSPORT_MonitorContext *
  219. GNUNET_TRANSPORT_monitor (const struct GNUNET_CONFIGURATION_Handle *cfg,
  220. const struct GNUNET_PeerIdentity *peer,
  221. int one_shot,
  222. GNUNET_TRANSPORT_MonitorCallback cb,
  223. void *cb_cls)
  224. {
  225. struct GNUNET_TRANSPORT_MonitorContext *mc;
  226. mc = GNUNET_new (struct GNUNET_TRANSPORT_MonitorContext);
  227. mc->cfg = cfg;
  228. if (NULL != peer)
  229. mc->peer = *peer;
  230. mc->one_shot = one_shot;
  231. mc->cb = cb;
  232. mc->cb_cls = cb_cls;
  233. reconnect (mc);
  234. if (NULL == mc->mq)
  235. {
  236. GNUNET_free (mc);
  237. return NULL;
  238. }
  239. return mc;
  240. }
  241. /**
  242. * Cancel request to monitor peers
  243. *
  244. * @param pmc handle for the request to cancel
  245. */
  246. void
  247. GNUNET_TRANSPORT_monitor_cancel (struct GNUNET_TRANSPORT_MonitorContext *mc)
  248. {
  249. disconnect (mc);
  250. GNUNET_free (mc);
  251. }
  252. /* end of transport_api2_monitor.c */