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