add $(GN_LIBINTL) to Makefile.am (fixes 0005902)
[oweals/gnunet.git] / src / testbed / testbed_api_barriers.c
1 /*
2    This file is part of GNUnet.
3    Copyright (C) 2008--2013, 2016 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_barriers.c
23  * @brief API implementation for testbed barriers
24  * @author Sree Harsha Totakura <sreeharsha@totakura.in>
25  */
26 #include "platform.h"
27 #include "gnunet_testbed_service.h"
28 #include "testbed_api.h"
29
30 /**
31  * Logging shorthand
32  */
33 #define LOG(type, ...)                          \
34   GNUNET_log_from (type, "testbed-api-barriers", __VA_ARGS__);
35
36 /**
37  * Debug logging shorthand
38  */
39 #define LOG_DEBUG(...)                          \
40   LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__);
41
42
43 /**
44  * Barrier wait handle
45  */
46 struct GNUNET_TESTBED_BarrierWaitHandle
47 {
48   /**
49    * The name of the barrier
50    */
51   char *name;
52
53   /**
54    * Then configuration used for the client connection
55    */
56   struct GNUNET_CONFIGURATION_Handle *cfg;
57
58   /**
59    * The testbed-barrier service message queue.
60    */
61   struct GNUNET_MQ_Handle *mq;
62
63   /**
64    * The barrier wait callback
65    */
66   GNUNET_TESTBED_barrier_wait_cb cb;
67
68   /**
69    * The closure for @e cb.
70    */
71   void *cb_cls;
72 };
73
74
75 /**
76  * Check if barrier status message is well-formed.
77  *
78  * @param cls closure
79  * @param msg received message
80  * @return #GNUNET_OK if the message is well-formed.
81  */
82 static int
83 check_status (void *cls,
84               const struct GNUNET_TESTBED_BarrierStatusMsg *msg)
85 {
86   /* FIXME: this fails to actually check that the message
87      follows the protocol spec (0-terminations!).  However,
88      not critical as #handle_status() doesn't interpret the
89      variable-size part anyway right now. */
90   return GNUNET_OK;
91 }
92
93
94 /**
95  * Type of a function to call when we receive a message
96  * from the service.
97  *
98  * @param cls closure
99  * @param msg received message
100  */
101 static void
102 handle_status (void *cls,
103                const struct GNUNET_TESTBED_BarrierStatusMsg *msg)
104 {
105   struct GNUNET_TESTBED_BarrierWaitHandle *h = cls;
106
107   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
108               "Got barrier status %d\n",
109               (int) ntohs (msg->status));
110   switch (ntohs (msg->status))
111   {
112   case GNUNET_TESTBED_BARRIERSTATUS_ERROR:
113     h->cb (h->cb_cls,
114            h->name,
115            GNUNET_SYSERR);
116     break;
117
118   case GNUNET_TESTBED_BARRIERSTATUS_INITIALISED:
119     h->cb (h->cb_cls,
120            h->name,
121            GNUNET_SYSERR);
122     GNUNET_break (0);
123     break;
124
125   case GNUNET_TESTBED_BARRIERSTATUS_CROSSED:
126     h->cb (h->cb_cls,
127            h->name,
128            GNUNET_OK);
129     break;
130
131   default:
132     GNUNET_break_op (0);
133     h->cb (h->cb_cls,
134            h->name,
135            GNUNET_SYSERR);
136     break;
137   }
138   GNUNET_TESTBED_barrier_wait_cancel (h);
139 }
140
141
142 /**
143  * Generic error handler, called with the appropriate error code and
144  * the same closure specified at the creation of the message queue.
145  * Not every message queue implementation supports an error handler.
146  *
147  * @param cls closure with the `struct GNUNET_TESTBED_BarrierWaitHandle *`
148  * @param error error code
149  */
150 static void
151 mq_error_handler (void *cls,
152                   enum GNUNET_MQ_Error error)
153 {
154   struct GNUNET_TESTBED_BarrierWaitHandle *h = cls;
155
156   h->cb (h->cb_cls,
157          h->name,
158          GNUNET_SYSERR);
159   GNUNET_TESTBED_barrier_wait_cancel (h);
160 }
161
162
163 /**
164  * Wait for a barrier to be crossed.  This function should be called by the
165  * peers which have been started by the testbed.  If the peer is not started by
166  * testbed this function may return error
167  *
168  * @param name the name of the barrier
169  * @param cb the barrier wait callback
170  * @param cb_cls the closure for @a cb
171  * @return barrier wait handle which can be used to cancel the waiting at
172  *   anytime before the callback is called.  NULL upon error.
173  */
174 struct GNUNET_TESTBED_BarrierWaitHandle *
175 GNUNET_TESTBED_barrier_wait (const char *name,
176                              GNUNET_TESTBED_barrier_wait_cb cb,
177                              void *cb_cls)
178 {
179   struct GNUNET_TESTBED_BarrierWaitHandle *h
180     = GNUNET_new (struct GNUNET_TESTBED_BarrierWaitHandle);
181   struct GNUNET_MQ_MessageHandler handlers[] = {
182     GNUNET_MQ_hd_var_size (status,
183                            GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS,
184                            struct GNUNET_TESTBED_BarrierStatusMsg,
185                            h),
186     GNUNET_MQ_handler_end ()
187   };
188   struct GNUNET_MQ_Envelope *env;
189   struct GNUNET_TESTBED_BarrierWait *msg;
190   const char *cfg_filename;
191   size_t name_len;
192
193   GNUNET_assert (NULL != cb);
194   cfg_filename = getenv (ENV_TESTBED_CONFIG);
195   if (NULL == cfg_filename)
196   {
197     LOG (GNUNET_ERROR_TYPE_ERROR,
198          "Are you running under testbed?\n");
199     GNUNET_free (h);
200     return NULL;
201   }
202   h->cfg = GNUNET_CONFIGURATION_create ();
203   if (GNUNET_OK !=
204       GNUNET_CONFIGURATION_load (h->cfg,
205                                  cfg_filename))
206   {
207     LOG (GNUNET_ERROR_TYPE_ERROR,
208          "Unable to load configuration from file `%s'\n",
209          cfg_filename);
210     GNUNET_CONFIGURATION_destroy (h->cfg);
211     GNUNET_free (h);
212     return NULL;
213   }
214   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
215               "Waiting on barrier `%s'\n",
216               name);
217   h->name = GNUNET_strdup (name);
218   h->cb = cb;
219   h->cb_cls = cb_cls;
220   h->mq = GNUNET_CLIENT_connect (h->cfg,
221                                  "testbed-barrier",
222                                  handlers,
223                                  &mq_error_handler,
224                                  h);
225   if (NULL == h->mq)
226   {
227     LOG (GNUNET_ERROR_TYPE_ERROR,
228          "Unable to connect to local testbed-barrier service\n");
229     GNUNET_TESTBED_barrier_wait_cancel (h);
230     return NULL;
231   }
232   name_len = strlen (name);  /* NOTE: unusual to not have 0-termination, change? */
233   env = GNUNET_MQ_msg_extra (msg,
234                              name_len,
235                              GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_WAIT);
236   GNUNET_memcpy (msg->name,
237                  name,
238                  name_len);
239   GNUNET_MQ_send (h->mq,
240                   env);
241   return h;
242 }
243
244
245 /**
246  * Cancel a barrier wait handle
247  *
248  * @param h the barrier wait handle
249  */
250 void
251 GNUNET_TESTBED_barrier_wait_cancel (struct GNUNET_TESTBED_BarrierWaitHandle *h)
252 {
253   if (NULL != h->mq)
254   {
255     GNUNET_MQ_destroy (h->mq);
256     h->mq = NULL;
257   }
258   GNUNET_free (h->name);
259   GNUNET_CONFIGURATION_destroy (h->cfg);
260   GNUNET_free (h);
261 }
262
263
264 /* end of testbed_api_barriers.c */