testbed_api_services.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. /*
  2. This file is part of GNUnet
  3. Copyright (C) 2008--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 testbed/testbed_api_services.c
  18. * @brief convenience functions for accessing services
  19. * @author Christian Grothoff
  20. */
  21. #include "platform.h"
  22. #include "testbed_api.h"
  23. #include "testbed_api_peers.h"
  24. #include "testbed_api_operations.h"
  25. /**
  26. * States for Service connect operations
  27. */
  28. enum State
  29. {
  30. /**
  31. * Initial state
  32. */
  33. INIT,
  34. /**
  35. * The configuration request has been sent
  36. */
  37. CFG_REQUEST_QUEUED,
  38. /**
  39. * connected to service
  40. */
  41. SERVICE_CONNECTED
  42. };
  43. /**
  44. * Data accessed during service connections
  45. */
  46. struct ServiceConnectData
  47. {
  48. /**
  49. * helper function callback to establish the connection
  50. */
  51. GNUNET_TESTBED_ConnectAdapter ca;
  52. /**
  53. * helper function callback to close the connection
  54. */
  55. GNUNET_TESTBED_DisconnectAdapter da;
  56. /**
  57. * Closure to the above callbacks
  58. */
  59. void *cada_cls;
  60. /**
  61. * Service name
  62. */
  63. char *service_name;
  64. /**
  65. * Closure for operation event
  66. */
  67. void *op_cls;
  68. /**
  69. * The operation which created this structure
  70. */
  71. struct GNUNET_TESTBED_Operation *operation;
  72. /**
  73. * The operation context from GNUNET_TESTBED_forward_operation_msg_()
  74. */
  75. struct OperationContext *opc;
  76. /**
  77. * The peer handle
  78. */
  79. struct GNUNET_TESTBED_Peer *peer;
  80. /**
  81. * The acquired configuration of the peer
  82. */
  83. struct GNUNET_CONFIGURATION_Handle *cfg;
  84. /**
  85. * The op_result pointer from ConnectAdapter
  86. */
  87. void *op_result;
  88. /**
  89. * The operation completion callback
  90. */
  91. GNUNET_TESTBED_ServiceConnectCompletionCallback cb;
  92. /**
  93. * The closure for operation completion callback
  94. */
  95. void *cb_cls;
  96. /**
  97. * State information
  98. */
  99. enum State state;
  100. };
  101. /**
  102. * Type of a function to call when we receive a message
  103. * from the service.
  104. *
  105. * @param cls ServiceConnectData
  106. * @param msg message received, NULL on timeout or fatal error
  107. */
  108. static void
  109. configuration_receiver (void *cls, const struct GNUNET_MessageHeader *msg)
  110. {
  111. struct ServiceConnectData *data = cls;
  112. struct GNUNET_TESTBED_Controller *c;
  113. const char *emsg;
  114. struct GNUNET_TESTBED_EventInformation info;
  115. uint16_t mtype;
  116. c = data->peer->controller;
  117. mtype = ntohs (msg->type);
  118. emsg = NULL;
  119. info.type = GNUNET_TESTBED_ET_OPERATION_FINISHED;
  120. info.op = data->operation;
  121. info.op_cls = data->op_cls;
  122. if (GNUNET_MESSAGE_TYPE_TESTBED_OPERATION_FAIL_EVENT == mtype)
  123. {
  124. emsg =
  125. GNUNET_TESTBED_parse_error_string_ ((const struct
  126. GNUNET_TESTBED_OperationFailureEventMessage
  127. *) msg);
  128. if (NULL == emsg)
  129. emsg = "Unknown error";
  130. info.details.operation_finished.emsg = emsg;
  131. info.details.operation_finished.generic = NULL;
  132. goto call_cb;
  133. }
  134. data->cfg = GNUNET_TESTBED_extract_config_ (msg);
  135. GNUNET_assert (NULL == data->op_result);
  136. data->op_result = data->ca (data->cada_cls, data->cfg);
  137. info.details.operation_finished.emsg = NULL;
  138. info.details.operation_finished.generic = data->op_result;
  139. data->state = SERVICE_CONNECTED;
  140. call_cb:
  141. if ((0 != (GNUNET_TESTBED_ET_OPERATION_FINISHED & c->event_mask)) &&
  142. (NULL != c->cc))
  143. c->cc (c->cc_cls, &info);
  144. if (NULL != data->cb)
  145. data->cb (data->cb_cls, data->operation, data->op_result, emsg);
  146. }
  147. /**
  148. * Function called when a service connect operation is ready
  149. *
  150. * @param cls the closure from GNUNET_TESTBED_operation_create_()
  151. */
  152. static void
  153. opstart_service_connect (void *cls)
  154. {
  155. struct ServiceConnectData *data = cls;
  156. struct GNUNET_TESTBED_PeerGetConfigurationMessage *msg;
  157. struct GNUNET_TESTBED_Controller *c;
  158. uint64_t op_id;
  159. GNUNET_assert (NULL != data);
  160. GNUNET_assert (NULL != data->peer);
  161. c = data->peer->controller;
  162. op_id = GNUNET_TESTBED_get_next_op_id (c);
  163. msg =
  164. GNUNET_TESTBED_generate_peergetconfig_msg_ (data->peer->unique_id, op_id);
  165. data->opc =
  166. GNUNET_TESTBED_forward_operation_msg_ (c, op_id, &msg->header,
  167. &configuration_receiver, data);
  168. GNUNET_free (msg);
  169. data->state = CFG_REQUEST_QUEUED;
  170. }
  171. /**
  172. * Callback which will be called when service connect type operation is
  173. * released
  174. *
  175. * @param cls the closure from GNUNET_TESTBED_operation_create_()
  176. */
  177. static void
  178. oprelease_service_connect (void *cls)
  179. {
  180. struct ServiceConnectData *data = cls;
  181. switch (data->state)
  182. {
  183. case INIT:
  184. break;
  185. case CFG_REQUEST_QUEUED:
  186. GNUNET_assert (NULL != data->opc);
  187. GNUNET_TESTBED_forward_operation_msg_cancel_ (data->opc);
  188. break;
  189. case SERVICE_CONNECTED:
  190. GNUNET_assert (NULL != data->cfg);
  191. GNUNET_CONFIGURATION_destroy (data->cfg);
  192. if (NULL != data->da)
  193. data->da (data->cada_cls, data->op_result);
  194. break;
  195. }
  196. GNUNET_free (data);
  197. }
  198. /**
  199. * Connect to a service offered by the given peer. Will ensure that
  200. * the request is queued to not overwhelm our ability to create and
  201. * maintain connections with other systems. The actual service
  202. * handle is then returned via the 'op_result' member in the event
  203. * callback. The 'ca' callback is used to create the connection
  204. * when the time is right; the 'da' callback will be used to
  205. * destroy the connection (upon 'GNUNET_TESTBED_operation_done').
  206. * 'GNUNET_TESTBED_operation_done' can be used to abort this
  207. * operation until the event callback has been called.
  208. *
  209. * @param op_cls closure to pass in operation event
  210. * @param peer peer that runs the service
  211. * @param service_name name of the service to connect to
  212. * @param cb the callback to call when this operation finishes
  213. * @param cb_cls closure for the above callback
  214. * @param ca helper function to establish the connection
  215. * @param da helper function to close the connection
  216. * @param cada_cls closure for ca and da
  217. * @return handle for the operation
  218. */
  219. struct GNUNET_TESTBED_Operation *
  220. GNUNET_TESTBED_service_connect (void *op_cls, struct GNUNET_TESTBED_Peer *peer,
  221. const char *service_name,
  222. GNUNET_TESTBED_ServiceConnectCompletionCallback
  223. cb, void *cb_cls,
  224. GNUNET_TESTBED_ConnectAdapter ca,
  225. GNUNET_TESTBED_DisconnectAdapter da,
  226. void *cada_cls)
  227. {
  228. struct ServiceConnectData *data;
  229. data = GNUNET_new (struct ServiceConnectData);
  230. data->ca = ca;
  231. data->da = da;
  232. data->cada_cls = cada_cls;
  233. data->op_cls = op_cls;
  234. data->peer = peer;
  235. data->state = INIT;
  236. data->cb = cb;
  237. data->cb_cls = cb_cls;
  238. data->operation =
  239. GNUNET_TESTBED_operation_create_ (data, &opstart_service_connect,
  240. &oprelease_service_connect);
  241. GNUNET_TESTBED_operation_queue_insert_ (peer->
  242. controller->opq_parallel_service_connections,
  243. data->operation);
  244. GNUNET_TESTBED_operation_queue_insert_ (peer->
  245. controller->opq_parallel_operations,
  246. data->operation);
  247. GNUNET_TESTBED_operation_begin_wait_ (data->operation);
  248. return data->operation;
  249. }
  250. /* end of testbed_api_services.c */