Use Suffix Extensions in Makefiles (doc, src/{arm,dht,integration,statistics}) for...
[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
6   it under the terms of the GNU General Public License as published
7   by the Free Software Foundation; either version 3, or (at your
8   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   General Public License for more details.
14
15   You should have received a copy of the GNU General Public License
16   along with GNUnet; see the file COPYING.  If not, write to the
17   Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18   Boston, MA 02110-1301, USA.
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   case GNUNET_TESTBED_BARRIERSTATUS_INITIALISED:
119     h->cb (h->cb_cls,
120            h->name,
121            GNUNET_SYSERR);
122     GNUNET_break (0);
123     break;
124   case GNUNET_TESTBED_BARRIERSTATUS_CROSSED:
125     h->cb (h->cb_cls,
126            h->name,
127            GNUNET_OK);
128     break;
129   default:
130     GNUNET_break_op (0);
131     h->cb (h->cb_cls,
132            h->name,
133            GNUNET_SYSERR);
134     break;
135   }
136   GNUNET_TESTBED_barrier_wait_cancel (h);
137 }
138
139
140 /**
141  * Generic error handler, called with the appropriate error code and
142  * the same closure specified at the creation of the message queue.
143  * Not every message queue implementation supports an error handler.
144  *
145  * @param cls closure with the `struct GNUNET_TESTBED_BarrierWaitHandle *`
146  * @param error error code
147  */
148 static void
149 mq_error_handler (void *cls,
150                   enum GNUNET_MQ_Error error)
151 {
152   struct GNUNET_TESTBED_BarrierWaitHandle *h = cls;
153
154   h->cb (h->cb_cls,
155          h->name,
156          GNUNET_SYSERR);
157   GNUNET_TESTBED_barrier_wait_cancel (h);
158 }
159
160
161 /**
162  * Wait for a barrier to be crossed.  This function should be called by the
163  * peers which have been started by the testbed.  If the peer is not started by
164  * testbed this function may return error
165  *
166  * @param name the name of the barrier
167  * @param cb the barrier wait callback
168  * @param cb_cls the closure for @a cb
169  * @return barrier wait handle which can be used to cancel the waiting at
170  *   anytime before the callback is called.  NULL upon error.
171  */
172 struct GNUNET_TESTBED_BarrierWaitHandle *
173 GNUNET_TESTBED_barrier_wait (const char *name,
174                              GNUNET_TESTBED_barrier_wait_cb cb,
175                              void *cb_cls)
176 {
177   struct GNUNET_TESTBED_BarrierWaitHandle *h
178     = GNUNET_new (struct GNUNET_TESTBED_BarrierWaitHandle);
179   struct GNUNET_MQ_MessageHandler handlers[] = {
180     GNUNET_MQ_hd_var_size (status,
181                            GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS,
182                            struct GNUNET_TESTBED_BarrierStatusMsg,
183                            h),
184     GNUNET_MQ_handler_end ()
185   };
186   struct GNUNET_MQ_Envelope *env;
187   struct GNUNET_TESTBED_BarrierWait *msg;
188   const char *cfg_filename;
189   size_t name_len;
190
191   GNUNET_assert (NULL != cb);
192   cfg_filename = getenv (ENV_TESTBED_CONFIG);
193   if (NULL == cfg_filename)
194   {
195     LOG (GNUNET_ERROR_TYPE_ERROR,
196          "Are you running under testbed?\n");
197     GNUNET_free (h);
198     return NULL;
199   }
200   h->cfg = GNUNET_CONFIGURATION_create ();
201   if (GNUNET_OK !=
202       GNUNET_CONFIGURATION_load (h->cfg,
203                                  cfg_filename))
204   {
205     LOG (GNUNET_ERROR_TYPE_ERROR,
206          "Unable to load configuration from file `%s'\n",
207          cfg_filename);
208     GNUNET_CONFIGURATION_destroy (h->cfg);
209     GNUNET_free (h);
210     return NULL;
211   }
212   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
213               "Waiting on barrier `%s'\n",
214               name);
215   h->name = GNUNET_strdup (name);
216   h->cb = cb;
217   h->cb_cls = cb_cls;
218   h->mq = GNUNET_CLIENT_connect (h->cfg,
219                                  "testbed-barrier",
220                                  handlers,
221                                  &mq_error_handler,
222                                  h);
223   if (NULL == h->mq)
224   {
225     LOG (GNUNET_ERROR_TYPE_ERROR,
226          "Unable to connect to local testbed-barrier service\n");
227     GNUNET_TESTBED_barrier_wait_cancel (h);
228     return NULL;
229   }
230   name_len = strlen (name); /* NOTE: unusual to not have 0-termination, change? */
231   env = GNUNET_MQ_msg_extra (msg,
232                              name_len,
233                              GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_WAIT);
234   GNUNET_memcpy (msg->name,
235                  name,
236                  name_len);
237   GNUNET_MQ_send (h->mq,
238                   env);
239   return h;
240 }
241
242
243 /**
244  * Cancel a barrier wait handle
245  *
246  * @param h the barrier wait handle
247  */
248 void
249 GNUNET_TESTBED_barrier_wait_cancel (struct GNUNET_TESTBED_BarrierWaitHandle *h)
250 {
251   if (NULL != h->mq)
252   {
253     GNUNET_MQ_destroy (h->mq);
254     h->mq = NULL;
255   }
256   GNUNET_free (h->name);
257   GNUNET_CONFIGURATION_destroy (h->cfg);
258   GNUNET_free (h);
259 }
260
261 /* end of testbed_api_barriers.c */