yapf format.
[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 /**
77  * Check if barrier status message is well-formed.
78  *
79  * @param cls closure
80  * @param msg received message
81  * @return #GNUNET_OK if the message is well-formed.
82  */
83 static int
84 check_status (void *cls,
85               const struct GNUNET_TESTBED_BarrierStatusMsg *msg)
86 {
87   /* FIXME: this fails to actually check that the message
88      follows the protocol spec (0-terminations!).  However,
89      not critical as #handle_status() doesn't interpret the
90      variable-size part anyway right now. */
91   return GNUNET_OK;
92 }
93
94
95 /**
96  * Type of a function to call when we receive a message
97  * from the service.
98  *
99  * @param cls closure
100  * @param msg received message
101  */
102 static void
103 handle_status (void *cls,
104                const struct GNUNET_TESTBED_BarrierStatusMsg *msg)
105 {
106   struct GNUNET_TESTBED_BarrierWaitHandle *h = cls;
107
108   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
109               "Got barrier status %d\n",
110               (int) ntohs (msg->status));
111   switch (ntohs (msg->status))
112   {
113   case GNUNET_TESTBED_BARRIERSTATUS_ERROR:
114     h->cb (h->cb_cls,
115            h->name,
116            GNUNET_SYSERR);
117     break;
118
119   case GNUNET_TESTBED_BARRIERSTATUS_INITIALISED:
120     h->cb (h->cb_cls,
121            h->name,
122            GNUNET_SYSERR);
123     GNUNET_break (0);
124     break;
125
126   case GNUNET_TESTBED_BARRIERSTATUS_CROSSED:
127     h->cb (h->cb_cls,
128            h->name,
129            GNUNET_OK);
130     break;
131
132   default:
133     GNUNET_break_op (0);
134     h->cb (h->cb_cls,
135            h->name,
136            GNUNET_SYSERR);
137     break;
138   }
139   GNUNET_TESTBED_barrier_wait_cancel (h);
140 }
141
142
143 /**
144  * Generic error handler, called with the appropriate error code and
145  * the same closure specified at the creation of the message queue.
146  * Not every message queue implementation supports an error handler.
147  *
148  * @param cls closure with the `struct GNUNET_TESTBED_BarrierWaitHandle *`
149  * @param error error code
150  */
151 static void
152 mq_error_handler (void *cls,
153                   enum GNUNET_MQ_Error error)
154 {
155   struct GNUNET_TESTBED_BarrierWaitHandle *h = cls;
156
157   h->cb (h->cb_cls,
158          h->name,
159          GNUNET_SYSERR);
160   GNUNET_TESTBED_barrier_wait_cancel (h);
161 }
162
163
164 /**
165  * Wait for a barrier to be crossed.  This function should be called by the
166  * peers which have been started by the testbed.  If the peer is not started by
167  * testbed this function may return error
168  *
169  * @param name the name of the barrier
170  * @param cb the barrier wait callback
171  * @param cb_cls the closure for @a cb
172  * @return barrier wait handle which can be used to cancel the waiting at
173  *   anytime before the callback is called.  NULL upon error.
174  */
175 struct GNUNET_TESTBED_BarrierWaitHandle *
176 GNUNET_TESTBED_barrier_wait (const char *name,
177                              GNUNET_TESTBED_barrier_wait_cb cb,
178                              void *cb_cls)
179 {
180   struct GNUNET_TESTBED_BarrierWaitHandle *h
181     = GNUNET_new (struct GNUNET_TESTBED_BarrierWaitHandle);
182   struct GNUNET_MQ_MessageHandler handlers[] = {
183     GNUNET_MQ_hd_var_size (status,
184                            GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS,
185                            struct GNUNET_TESTBED_BarrierStatusMsg,
186                            h),
187     GNUNET_MQ_handler_end ()
188   };
189   struct GNUNET_MQ_Envelope *env;
190   struct GNUNET_TESTBED_BarrierWait *msg;
191   const char *cfg_filename;
192   size_t name_len;
193
194   GNUNET_assert (NULL != cb);
195   cfg_filename = getenv (ENV_TESTBED_CONFIG);
196   if (NULL == cfg_filename)
197   {
198     LOG (GNUNET_ERROR_TYPE_ERROR,
199          "Are you running under testbed?\n");
200     GNUNET_free (h);
201     return NULL;
202   }
203   h->cfg = GNUNET_CONFIGURATION_create ();
204   if (GNUNET_OK !=
205       GNUNET_CONFIGURATION_load (h->cfg,
206                                  cfg_filename))
207   {
208     LOG (GNUNET_ERROR_TYPE_ERROR,
209          "Unable to load configuration from file `%s'\n",
210          cfg_filename);
211     GNUNET_CONFIGURATION_destroy (h->cfg);
212     GNUNET_free (h);
213     return NULL;
214   }
215   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
216               "Waiting on barrier `%s'\n",
217               name);
218   h->name = GNUNET_strdup (name);
219   h->cb = cb;
220   h->cb_cls = cb_cls;
221   h->mq = GNUNET_CLIENT_connect (h->cfg,
222                                  "testbed-barrier",
223                                  handlers,
224                                  &mq_error_handler,
225                                  h);
226   if (NULL == h->mq)
227   {
228     LOG (GNUNET_ERROR_TYPE_ERROR,
229          "Unable to connect to local testbed-barrier service\n");
230     GNUNET_TESTBED_barrier_wait_cancel (h);
231     return NULL;
232   }
233   name_len = strlen (name);  /* NOTE: unusual to not have 0-termination, change? */
234   env = GNUNET_MQ_msg_extra (msg,
235                              name_len,
236                              GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_WAIT);
237   GNUNET_memcpy (msg->name,
238                  name,
239                  name_len);
240   GNUNET_MQ_send (h->mq,
241                   env);
242   return h;
243 }
244
245
246 /**
247  * Cancel a barrier wait handle
248  *
249  * @param h the barrier wait handle
250  */
251 void
252 GNUNET_TESTBED_barrier_wait_cancel (struct GNUNET_TESTBED_BarrierWaitHandle *h)
253 {
254   if (NULL != h->mq)
255   {
256     GNUNET_MQ_destroy (h->mq);
257     h->mq = NULL;
258   }
259   GNUNET_free (h->name);
260   GNUNET_CONFIGURATION_destroy (h->cfg);
261   GNUNET_free (h);
262 }
263
264 /* end of testbed_api_barriers.c */