add $(GN_LIBINTL) to Makefile.am (fixes 0005902)
[oweals/gnunet.git] / src / testbed / testbed_api_services.c
1 /*
2       This file is part of GNUnet
3       Copyright (C) 2008--2013 GNUnet e.V.
4
5       GNUnet is free software: you can redistribute it and/or modify it
6       under the terms of the GNU Affero General Public License as published
7       by the Free Software Foundation, either version 3 of the License,
8       or (at your option) any later version.
9
10       GNUnet is distributed in the hope that it will be useful, but
11       WITHOUT ANY WARRANTY; without even the implied warranty of
12       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13       Affero General Public License for more details.
14
15       You should have received a copy of the GNU Affero General Public License
16       along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18      SPDX-License-Identifier: AGPL3.0-or-later
19  */
20
21 /**
22  * @file testbed/testbed_api_services.c
23  * @brief convenience functions for accessing services
24  * @author Christian Grothoff
25  */
26 #include "platform.h"
27 #include "testbed_api.h"
28 #include "testbed_api_peers.h"
29 #include "testbed_api_operations.h"
30
31
32 /**
33  * States for Service connect operations
34  */
35 enum State
36 {
37   /**
38    * Initial state
39    */
40   INIT,
41
42   /**
43    * The configuration request has been sent
44    */
45   CFG_REQUEST_QUEUED,
46
47   /**
48    * connected to service
49    */
50   SERVICE_CONNECTED
51 };
52
53
54 /**
55  * Data accessed during service connections
56  */
57 struct ServiceConnectData
58 {
59   /**
60    * helper function callback to establish the connection
61    */
62   GNUNET_TESTBED_ConnectAdapter ca;
63
64   /**
65    * helper function callback to close the connection
66    */
67   GNUNET_TESTBED_DisconnectAdapter da;
68
69   /**
70    * Closure to the above callbacks
71    */
72   void *cada_cls;
73
74   /**
75    * Service name
76    */
77   char *service_name;
78
79   /**
80    * Closure for operation event
81    */
82   void *op_cls;
83
84   /**
85    * The operation which created this structure
86    */
87   struct GNUNET_TESTBED_Operation *operation;
88
89   /**
90    * The operation context from GNUNET_TESTBED_forward_operation_msg_()
91    */
92   struct OperationContext *opc;
93
94   /**
95    * The peer handle
96    */
97   struct GNUNET_TESTBED_Peer *peer;
98
99   /**
100    * The acquired configuration of the peer
101    */
102   struct GNUNET_CONFIGURATION_Handle *cfg;
103
104   /**
105    * The op_result pointer from ConnectAdapter
106    */
107   void *op_result;
108
109   /**
110    * The operation completion callback
111    */
112   GNUNET_TESTBED_ServiceConnectCompletionCallback cb;
113
114   /**
115    * The closure for operation completion callback
116    */
117   void *cb_cls;
118
119   /**
120    * State information
121    */
122   enum State state;
123 };
124
125
126 /**
127  * Type of a function to call when we receive a message
128  * from the service.
129  *
130  * @param cls ServiceConnectData
131  * @param msg message received, NULL on timeout or fatal error
132  */
133 static void
134 configuration_receiver (void *cls, const struct GNUNET_MessageHeader *msg)
135 {
136   struct ServiceConnectData *data = cls;
137   struct GNUNET_TESTBED_Controller *c;
138   const char *emsg;
139   struct GNUNET_TESTBED_EventInformation info;
140   uint16_t mtype;
141
142   c = data->peer->controller;
143   mtype = ntohs (msg->type);
144   emsg = NULL;
145   info.type = GNUNET_TESTBED_ET_OPERATION_FINISHED;
146   info.op = data->operation;
147   info.op_cls = data->op_cls;
148   if (GNUNET_MESSAGE_TYPE_TESTBED_OPERATION_FAIL_EVENT == mtype)
149   {
150     emsg =
151       GNUNET_TESTBED_parse_error_string_ ((const struct
152                                            GNUNET_TESTBED_OperationFailureEventMessage
153                                            *) msg);
154     if (NULL == emsg)
155       emsg = "Unknown error";
156     info.details.operation_finished.emsg = emsg;
157     info.details.operation_finished.generic = NULL;
158     goto call_cb;
159   }
160   data->cfg = GNUNET_TESTBED_extract_config_ (msg);
161   GNUNET_assert (NULL == data->op_result);
162   data->op_result = data->ca (data->cada_cls, data->cfg);
163   info.details.operation_finished.emsg = NULL;
164   info.details.operation_finished.generic = data->op_result;
165   data->state = SERVICE_CONNECTED;
166
167 call_cb:
168   if ((0 != (GNUNET_TESTBED_ET_OPERATION_FINISHED & c->event_mask)) &&
169       (NULL != c->cc))
170     c->cc (c->cc_cls, &info);
171   if (NULL != data->cb)
172     data->cb (data->cb_cls, data->operation, data->op_result, emsg);
173 }
174
175
176 /**
177  * Function called when a service connect operation is ready
178  *
179  * @param cls the closure from GNUNET_TESTBED_operation_create_()
180  */
181 static void
182 opstart_service_connect (void *cls)
183 {
184   struct ServiceConnectData *data = cls;
185   struct GNUNET_TESTBED_PeerGetConfigurationMessage *msg;
186   struct GNUNET_TESTBED_Controller *c;
187   uint64_t op_id;
188
189   GNUNET_assert (NULL != data);
190   GNUNET_assert (NULL != data->peer);
191   c = data->peer->controller;
192   op_id = GNUNET_TESTBED_get_next_op_id (c);
193   msg =
194     GNUNET_TESTBED_generate_peergetconfig_msg_ (data->peer->unique_id, op_id);
195   data->opc =
196     GNUNET_TESTBED_forward_operation_msg_ (c, op_id, &msg->header,
197                                            &configuration_receiver, data);
198   GNUNET_free (msg);
199   data->state = CFG_REQUEST_QUEUED;
200 }
201
202
203 /**
204  * Callback which will be called when service connect type operation is
205  * released
206  *
207  * @param cls the closure from GNUNET_TESTBED_operation_create_()
208  */
209 static void
210 oprelease_service_connect (void *cls)
211 {
212   struct ServiceConnectData *data = cls;
213
214   switch (data->state)
215   {
216   case INIT:
217     break;
218
219   case CFG_REQUEST_QUEUED:
220     GNUNET_assert (NULL != data->opc);
221     GNUNET_TESTBED_forward_operation_msg_cancel_ (data->opc);
222     break;
223
224   case SERVICE_CONNECTED:
225     GNUNET_assert (NULL != data->cfg);
226     GNUNET_CONFIGURATION_destroy (data->cfg);
227     if (NULL != data->da)
228       data->da (data->cada_cls, data->op_result);
229     break;
230   }
231   GNUNET_free (data);
232 }
233
234
235 /**
236  * Connect to a service offered by the given peer.  Will ensure that
237  * the request is queued to not overwhelm our ability to create and
238  * maintain connections with other systems.  The actual service
239  * handle is then returned via the 'op_result' member in the event
240  * callback.  The 'ca' callback is used to create the connection
241  * when the time is right; the 'da' callback will be used to
242  * destroy the connection (upon 'GNUNET_TESTBED_operation_done').
243  * 'GNUNET_TESTBED_operation_done' can be used to abort this
244  * operation until the event callback has been called.
245  *
246  * @param op_cls closure to pass in operation event
247  * @param peer peer that runs the service
248  * @param service_name name of the service to connect to
249  * @param cb the callback to call when this operation finishes
250  * @param cb_cls closure for the above callback
251  * @param ca helper function to establish the connection
252  * @param da helper function to close the connection
253  * @param cada_cls closure for ca and da
254  * @return handle for the operation
255  */
256 struct GNUNET_TESTBED_Operation *
257 GNUNET_TESTBED_service_connect (void *op_cls, struct GNUNET_TESTBED_Peer *peer,
258                                 const char *service_name,
259                                 GNUNET_TESTBED_ServiceConnectCompletionCallback
260                                 cb, void *cb_cls,
261                                 GNUNET_TESTBED_ConnectAdapter ca,
262                                 GNUNET_TESTBED_DisconnectAdapter da,
263                                 void *cada_cls)
264 {
265   struct ServiceConnectData *data;
266
267   data = GNUNET_new (struct ServiceConnectData);
268   data->ca = ca;
269   data->da = da;
270   data->cada_cls = cada_cls;
271   data->op_cls = op_cls;
272   data->peer = peer;
273   data->state = INIT;
274   data->cb = cb;
275   data->cb_cls = cb_cls;
276   data->operation =
277     GNUNET_TESTBED_operation_create_ (data, &opstart_service_connect,
278                                       &oprelease_service_connect);
279   GNUNET_TESTBED_operation_queue_insert_ (peer->
280                                           controller->
281                                           opq_parallel_service_connections,
282                                           data->operation);
283   GNUNET_TESTBED_operation_queue_insert_ (peer->
284                                           controller->opq_parallel_operations,
285                                           data->operation);
286   GNUNET_TESTBED_operation_begin_wait_ (data->operation);
287   return data->operation;
288 }
289
290
291 /* end of testbed_api_services.c */