527a86554b819b9cf8c1a0da60214cd27125f171
[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 client connection
60    */
61   struct GNUNET_CLIENT_Connection *conn;
62
63   /**
64    * Transmit handle
65    */
66   struct GNUNET_CLIENT_TransmitHandle *tx;
67
68   /**
69    * The message to transmit with tx
70    */
71   struct GNUNET_MessageHeader *msg;
72
73   /**
74    * The barrier wait callback
75    */
76   GNUNET_TESTBED_barrier_wait_cb cb;
77
78   /**
79    * The closure for the above callback
80    */
81   void *cls;
82 };
83
84
85 /**
86  * Function to destroy barrier wait handle
87  *
88  * @param h the handle to destroy
89  */
90 static void
91 destroy_handle (struct GNUNET_TESTBED_BarrierWaitHandle *h)
92 {
93   GNUNET_free (h->name);
94   if (NULL != h->tx)
95     GNUNET_CLIENT_notify_transmit_ready_cancel (h->tx);
96   if (NULL != h->conn)
97     GNUNET_CLIENT_disconnect (h->conn);
98   if (NULL != h->msg)
99     GNUNET_free (h->msg);
100   GNUNET_CONFIGURATION_destroy (h->cfg);
101   GNUNET_free (h);
102 }
103
104
105 /**
106  * Type of a function to call when we receive a message
107  * from the service.
108  *
109  * @param cls closure
110  * @param message received message; NULL on timeout or fatal error
111  */
112 static void
113 receive_handler (void *cls,
114                  const struct GNUNET_MessageHeader *message)
115 {
116   struct GNUNET_TESTBED_BarrierWaitHandle *h = cls;
117   const struct GNUNET_TESTBED_BarrierStatusMsg *msg;
118   uint16_t msize;
119
120   if (NULL == message)
121   {
122     GNUNET_break_op (0);
123     goto fail;
124   }
125   if (GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS != ntohs (message->type))
126   {
127     GNUNET_break_op (0);
128     goto fail;
129   }
130   msize = ntohs (message->size);
131   if (msize <= sizeof (struct GNUNET_TESTBED_BarrierStatusMsg))
132   {
133     GNUNET_break_op (0);
134     goto fail;
135   }
136   msg = (const struct GNUNET_TESTBED_BarrierStatusMsg *) message;
137   switch (ntohs (msg->status))
138   {
139   case GNUNET_TESTBED_BARRIERSTATUS_ERROR:
140     goto fail;
141   case GNUNET_TESTBED_BARRIERSTATUS_INITIALISED:
142     GNUNET_break (0);           /* FIXME */
143     goto destroy;
144   case GNUNET_TESTBED_BARRIERSTATUS_CROSSED:
145     h->cb (h->cls, h->name, GNUNET_OK);
146     goto destroy;
147   default:
148     GNUNET_break_op (0);
149   }
150
151  fail:
152   h->cb (h->cls, h->name, GNUNET_SYSERR);
153
154  destroy:
155   destroy_handle (h);
156 }
157
158
159 /**
160  * Function called to notify a client about the connection
161  * begin ready to queue more data.  "buf" will be
162  * NULL and "size" zero if the connection was closed for
163  * writing in the meantime.
164  *
165  * @param cls closure
166  * @param size number of bytes available in buf
167  * @param buf where the callee should write the message
168  * @return number of bytes written to buf
169  */
170 static size_t
171 transmit_notify (void *cls, size_t size, void *buf)
172 {
173   struct GNUNET_TESTBED_BarrierWaitHandle *h = cls;
174   uint16_t msize;
175
176   h->tx = NULL;
177   if ((0 == size) || (NULL == buf))
178   {
179     destroy_handle (h);
180     return 0;
181   }
182   msize = htons (h->msg->size);
183   GNUNET_assert (msize <= size);
184   (void) memcpy (buf, h->msg, msize);
185   GNUNET_free (h->msg);
186   h->msg = NULL;
187   GNUNET_CLIENT_receive (h->conn, &receive_handler, h, GNUNET_TIME_UNIT_FOREVER_REL);
188   return msize;
189 }
190
191
192 /**
193  * Wait for a barrier to be crossed.  This function should be called by the
194  * peers which have been started by the testbed.  If the peer is not started by
195  * testbed this function may return error
196  *
197  * @param name the name of the barrier
198  * @param cb the barrier wait callback
199  * @param cls the closure for the above callback
200  * @return barrier wait handle which can be used to cancel the waiting at
201  *   anytime before the callback is called.  NULL upon error.
202  */
203 struct GNUNET_TESTBED_BarrierWaitHandle *
204 GNUNET_TESTBED_barrier_wait (const char *name,
205                              GNUNET_TESTBED_barrier_wait_cb cb,
206                              void *cls)
207 {
208   struct GNUNET_TESTBED_BarrierWait *msg;
209   struct GNUNET_CONFIGURATION_Handle *cfg;
210   struct GNUNET_TESTBED_BarrierWaitHandle *h;
211   char *cfg_filename;
212   size_t name_len;
213   uint16_t msize;
214
215   GNUNET_assert (NULL != cb);
216   GNUNET_assert (NULL != name);
217   cfg_filename = getenv (ENV_TESTBED_CONFIG);
218   if (NULL == cfg_filename)
219   {
220     LOG (GNUNET_ERROR_TYPE_ERROR, "Are you running under testbed?\n");
221     return NULL;
222   }
223   cfg = GNUNET_CONFIGURATION_create ();
224   if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, cfg_filename))
225   {
226     LOG (GNUNET_ERROR_TYPE_ERROR, "Unable to load configuration from file `%s'\n",
227          cfg_filename);
228     GNUNET_CONFIGURATION_destroy (cfg);
229     return NULL;
230   }
231   h = GNUNET_new (struct GNUNET_TESTBED_BarrierWaitHandle);
232   h->name = GNUNET_strdup (name);
233   h->cfg = cfg;
234   h->conn = GNUNET_CLIENT_connect ("testbed-barrier", h->cfg);
235   h->cb = cb;
236   h->cls = cls;
237   if (NULL == h->conn)
238   {
239     LOG (GNUNET_ERROR_TYPE_ERROR,
240          "Unable to connect to local testbed-barrier service\n");
241     destroy_handle (h);
242     return NULL;
243   }
244   name_len = strlen (name);
245   msize = sizeof (struct GNUNET_TESTBED_BarrierWait) + name_len;
246   msg = GNUNET_malloc (msize);
247   msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_WAIT);
248   msg->header.size = htons (msize);
249   (void) memcpy (msg->name, name, name_len);
250   h->msg = &msg->header;
251   h->tx =
252       GNUNET_CLIENT_notify_transmit_ready (h->conn, msize,
253                                            GNUNET_TIME_UNIT_FOREVER_REL,
254                                            GNUNET_NO,
255                                            &transmit_notify,
256                                            h);
257   return h;
258 }
259
260
261 /**
262  * Cancel a barrier wait handle
263  *
264  * @param h the barrier wait handle
265  */
266 void
267 GNUNET_TESTBED_barrier_wait_cancel (struct GNUNET_TESTBED_BarrierWaitHandle *h)
268 {
269   destroy_handle (h);
270 }
271
272 /* end of testbed_api_barriers.c */