2 This file is part of GNUnet.
3 (C) 2009 Christian Grothoff (and other contributing authors)
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 2, or (at your
8 option) any later version.
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.
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., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
23 * @brief API for accessing the ARM service
24 * @author Christian Grothoff
27 #include "gnunet_arm_service.h"
28 #include "gnunet_client_lib.h"
29 #include "gnunet_getopt_lib.h"
30 #include "gnunet_os_lib.h"
31 #include "gnunet_protocols.h"
32 #include "gnunet_server_lib.h"
45 GNUNET_ARM_Callback callback;
60 struct GNUNET_CLIENT_Connection *client;
65 const struct GNUNET_CONFIGURATION_Handle *cfg;
70 struct GNUNET_TIME_Absolute timeout;
83 arm_service_report (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
85 struct ArmContext *pos = cls;
90 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE))
92 if (pos->callback != NULL)
93 pos->callback (pos->cls, GNUNET_YES);
101 GNUNET_CONFIGURATION_get_value_filename (pos->cfg,
106 GNUNET_CONFIGURATION_get_value_filename (pos->cfg,
107 "arm", "CONFIG", &config)))
109 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
110 _("Configuration file or binary for ARM not known!\n"));
111 if (pos->callback != NULL)
112 pos->callback (pos->cls, GNUNET_SYSERR);
113 GNUNET_free_non_null (binary);
117 pid = GNUNET_OS_start_process (binary, binary, "-d", "-c", config,
122 GNUNET_free (binary);
123 GNUNET_free (config);
126 if (pos->callback != NULL)
127 pos->callback (pos->cls, GNUNET_SYSERR);
131 /* FIXME: consider checking again to see if it worked!? */
132 if (pos->callback != NULL)
133 pos->callback (pos->cls, GNUNET_YES);
139 handle_response (void *cls, const struct GNUNET_MessageHeader *msg)
141 struct ArmContext *sc = cls;
146 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
147 _("Error receiving response from ARM service\n"));
148 GNUNET_CLIENT_disconnect (sc->client);
149 if (sc->callback != NULL)
150 sc->callback (sc->cls, GNUNET_SYSERR);
155 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
156 _("Received response from ARM service\n"));
158 switch (ntohs (msg->type))
160 case GNUNET_MESSAGE_TYPE_ARM_IS_UP:
163 case GNUNET_MESSAGE_TYPE_ARM_IS_DOWN:
166 case GNUNET_MESSAGE_TYPE_ARM_IS_UNKNOWN:
173 GNUNET_CLIENT_disconnect (sc->client);
174 if (sc->callback != NULL)
175 sc->callback (sc->cls, ret);
181 send_service_msg (void *cls, size_t size, void *buf)
183 struct ArmContext *sctx = cls;
184 struct GNUNET_MessageHeader *msg;
189 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
190 _("Error while trying to transmit to ARM service\n"));
191 GNUNET_CLIENT_disconnect (sctx->client);
192 if (sctx->callback != NULL)
193 sctx->callback (sctx->cls, GNUNET_SYSERR);
194 GNUNET_free (sctx->service_name);
199 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
200 _("Transmitting service request to ARM.\n"));
202 slen = strlen (sctx->service_name) + 1;
203 GNUNET_assert (size >= slen);
205 msg->size = htons (sizeof (struct GNUNET_MessageHeader) + slen);
206 msg->type = htons (sctx->type);
207 memcpy (&msg[1], sctx->service_name, slen);
208 GNUNET_free (sctx->service_name);
209 sctx->service_name = NULL;
210 GNUNET_CLIENT_receive (sctx->client,
213 GNUNET_TIME_absolute_get_remaining (sctx->timeout));
214 return slen + sizeof (struct GNUNET_MessageHeader);
219 * Start or stop a service.
221 * @param service_name name of the service
222 * @param cfg configuration to use (needed to contact ARM;
223 * the ARM service may internally use a different
224 * configuration to determine how to start the service).
225 * @param sched scheduler to use
226 * @param timeout how long to wait before failing for good
227 * @param cb callback to invoke when service is ready
228 * @param cb_cls closure for callback
229 * @param type type of the request
232 change_service (const char *service_name,
233 const struct GNUNET_CONFIGURATION_Handle *cfg,
234 struct GNUNET_SCHEDULER_Handle *sched,
235 struct GNUNET_TIME_Relative timeout,
236 GNUNET_ARM_Callback cb, void *cb_cls, uint16_t type)
238 struct GNUNET_CLIENT_Connection *client;
239 struct ArmContext *sctx;
242 slen = strlen (service_name) + 1;
243 if (slen + sizeof (struct GNUNET_MessageHeader) >
244 GNUNET_SERVER_MAX_MESSAGE_SIZE)
248 cb (cb_cls, GNUNET_NO);
251 client = GNUNET_CLIENT_connect (sched, "arm", cfg);
254 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
255 _("Failed to connect to ARM service\n"));
257 cb (cb_cls, GNUNET_SYSERR);
261 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
262 _("ARM requests starting of service `%s'.\n"), service_name);
264 sctx = GNUNET_malloc (sizeof (struct ArmContext));
267 sctx->client = client;
268 sctx->service_name = GNUNET_strdup (service_name);
269 sctx->timeout = GNUNET_TIME_relative_to_absolute (timeout);
272 GNUNET_CLIENT_notify_transmit_ready (client,
275 GNUNET_MessageHeader),
276 timeout, &send_service_msg, sctx))
278 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
279 _("Failed to transmit request to ARM service\n"));
280 GNUNET_free (sctx->service_name);
283 cb (cb_cls, GNUNET_SYSERR);
284 GNUNET_CLIENT_disconnect (client);
293 * @param service_name name of the service
294 * @param cfg configuration to use (needed to contact ARM;
295 * the ARM service may internally use a different
296 * configuration to determine how to start the service).
297 * @param sched scheduler to use
298 * @param timeout how long to wait before failing for good
299 * @param cb callback to invoke when service is ready
300 * @param cb_cls closure for callback
303 GNUNET_ARM_start_service (const char *service_name,
304 const struct GNUNET_CONFIGURATION_Handle *cfg,
305 struct GNUNET_SCHEDULER_Handle *sched,
306 struct GNUNET_TIME_Relative timeout,
307 GNUNET_ARM_Callback cb, void *cb_cls)
309 struct ArmContext *sctx;
311 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
312 _("Starting service `%s'\n"), service_name);
313 if (0 == strcmp ("arm", service_name))
315 sctx = GNUNET_malloc (sizeof (struct ArmContext));
319 GNUNET_CLIENT_service_test (sched,
321 cfg, timeout, &arm_service_report, sctx);
324 change_service (service_name,
326 sched, timeout, cb, cb_cls, GNUNET_MESSAGE_TYPE_ARM_START);
335 * @param service_name name of the service
336 * @param cfg configuration to use (needed to contact ARM;
337 * the ARM service may internally use a different
338 * configuration to determine how to start the service).
339 * @param sched scheduler to use
340 * @param timeout how long to wait before failing for good
341 * @param cb callback to invoke when service is ready
342 * @param cb_cls closure for callback
345 GNUNET_ARM_stop_service (const char *service_name,
346 const struct GNUNET_CONFIGURATION_Handle *cfg,
347 struct GNUNET_SCHEDULER_Handle *sched,
348 struct GNUNET_TIME_Relative timeout,
349 GNUNET_ARM_Callback cb, void *cb_cls)
351 struct GNUNET_CLIENT_Connection *client;
353 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
354 _("Stopping service `%s'\n"), service_name);
355 if (0 == strcmp ("arm", service_name))
357 client = GNUNET_CLIENT_connect (sched, "arm", cfg);
361 cb (cb_cls, GNUNET_SYSERR);
364 GNUNET_CLIENT_service_shutdown (client);
365 GNUNET_CLIENT_disconnect (client);
367 cb (cb_cls, GNUNET_NO);
370 change_service (service_name,
372 sched, timeout, cb, cb_cls, GNUNET_MESSAGE_TYPE_ARM_STOP);
375 /* end of arm_api.c */