aboutsummaryrefslogtreecommitdiff
path: root/src/arm/arm_api.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/arm/arm_api.c')
-rw-r--r--src/arm/arm_api.c337
1 files changed, 337 insertions, 0 deletions
diff --git a/src/arm/arm_api.c b/src/arm/arm_api.c
new file mode 100644
index 000000000..c5bb15fd3
--- /dev/null
+++ b/src/arm/arm_api.c
@@ -0,0 +1,337 @@
1/*
2 This file is part of GNUnet.
3 (C) 2009 Christian Grothoff (and other contributing authors)
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 2, 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., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file arm/arm_api.c
23 * @brief API for accessing the ARM service
24 * @author Christian Grothoff
25 */
26#include "platform.h"
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"
33#include "arm.h"
34
35
36struct ArmContext
37{
38 GNUNET_ARM_Callback callback;
39 void *cls;
40 char *service_name;
41 struct GNUNET_CLIENT_Connection *client;
42 struct GNUNET_CONFIGURATION_Handle *cfg;
43 struct GNUNET_TIME_Absolute timeout;
44 uint16_t type;
45};
46
47
48static void
49arm_service_report (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
50{
51 struct ArmContext *pos = cls;
52 pid_t pid;
53 char *binary;
54 char *config;
55
56 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE))
57 {
58 if (pos->callback != NULL)
59 pos->callback (pos->cls, GNUNET_YES);
60 GNUNET_free (pos);
61 return;
62 }
63 binary = NULL;
64 config = NULL;
65 /* start service */
66 if ((GNUNET_OK !=
67 GNUNET_CONFIGURATION_get_value_filename (pos->cfg,
68 "arm",
69 "BINARY",
70 &binary)) ||
71 (GNUNET_OK !=
72 GNUNET_CONFIGURATION_get_value_filename (pos->cfg,
73 "arm", "CONFIG", &config)))
74 {
75 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
76 _("Configuration file or binary for ARM not known!\n"));
77 if (pos->callback != NULL)
78 pos->callback (pos->cls, GNUNET_SYSERR);
79 GNUNET_free_non_null (binary);
80 GNUNET_free (pos);
81 return;
82 }
83 pid = GNUNET_OS_start_process (binary, binary, "-d", "-c", config,
84#if DEBUG_ARM
85 "-L", "DEBUG",
86#endif
87 NULL);
88 GNUNET_free (binary);
89 GNUNET_free (config);
90 if (pid == -1)
91 {
92 if (pos->callback != NULL)
93 pos->callback (pos->cls, GNUNET_SYSERR);
94 GNUNET_free (pos);
95 return;
96 }
97 /* FIXME: consider checking again to see if it worked!? */
98 if (pos->callback != NULL)
99 pos->callback (pos->cls, GNUNET_YES);
100 GNUNET_free (pos);
101}
102
103
104static void
105handle_response (void *cls, const struct GNUNET_MessageHeader *msg)
106{
107 struct ArmContext *sc = cls;
108 int ret;
109
110 if (msg == NULL)
111 {
112 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
113 _("Error receiving response from ARM service\n"));
114 GNUNET_CLIENT_disconnect (sc->client);
115 if (sc->callback != NULL)
116 sc->callback (sc->cls, GNUNET_SYSERR);
117 GNUNET_free (sc);
118 return;
119 }
120#if DEBUG_ARM
121 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
122 _("Received response from ARM service\n"));
123#endif
124 switch (ntohs (msg->type))
125 {
126 case GNUNET_MESSAGE_TYPE_ARM_IS_UP:
127 ret = GNUNET_YES;
128 break;
129 case GNUNET_MESSAGE_TYPE_ARM_IS_DOWN:
130 ret = GNUNET_NO;
131 break;
132 default:
133 GNUNET_break (0);
134 ret = GNUNET_SYSERR;
135 }
136 GNUNET_CLIENT_disconnect (sc->client);
137 if (sc->callback != NULL)
138 sc->callback (sc->cls, ret);
139 GNUNET_free (sc);
140}
141
142
143static size_t
144send_service_msg (void *cls, size_t size, void *buf)
145{
146 struct ArmContext *sctx = cls;
147 struct GNUNET_MessageHeader *msg;
148 size_t slen;
149
150 if (buf == NULL)
151 {
152 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
153 _("Error while trying to transmit to ARM service\n"));
154 GNUNET_CLIENT_disconnect (sctx->client);
155 if (sctx->callback != NULL)
156 sctx->callback (sctx->cls, GNUNET_SYSERR);
157 GNUNET_free (sctx->service_name);
158 GNUNET_free (sctx);
159 return 0;
160 }
161#if DEBUG_ARM
162 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
163 _("Transmitting service request to ARM.\n"));
164#endif
165 slen = strlen (sctx->service_name) + 1;
166 GNUNET_assert (size >= slen);
167 msg = buf;
168 msg->size = htons (sizeof (struct GNUNET_MessageHeader) + slen);
169 msg->type = htons (sctx->type);
170 memcpy (&msg[1], sctx->service_name, slen);
171 GNUNET_free (sctx->service_name);
172 sctx->service_name = NULL;
173 GNUNET_CLIENT_receive (sctx->client,
174 &handle_response,
175 sctx,
176 GNUNET_TIME_absolute_get_remaining (sctx->timeout));
177 return slen + sizeof (struct GNUNET_MessageHeader);
178}
179
180
181/**
182 * Start or stop a service.
183 *
184 * @param service_name name of the service
185 * @param cfg configuration to use (needed to contact ARM;
186 * the ARM service may internally use a different
187 * configuration to determine how to start the service).
188 * @param sched scheduler to use
189 * @param timeout how long to wait before failing for good
190 * @param cb callback to invoke when service is ready
191 * @param cb_cls closure for callback
192 */
193static void
194change_service (const char *service_name,
195 struct GNUNET_CONFIGURATION_Handle *cfg,
196 struct GNUNET_SCHEDULER_Handle *sched,
197 struct GNUNET_TIME_Relative timeout,
198 GNUNET_ARM_Callback cb, void *cb_cls, uint16_t type)
199{
200 struct GNUNET_CLIENT_Connection *client;
201 struct ArmContext *sctx;
202 size_t slen;
203
204 slen = strlen (service_name) + 1;
205 if (slen + sizeof (struct GNUNET_MessageHeader) >
206 GNUNET_SERVER_MAX_MESSAGE_SIZE)
207 {
208 GNUNET_break (0);
209 if (cb != NULL)
210 cb (cb_cls, GNUNET_NO);
211 return;
212 }
213 client = GNUNET_CLIENT_connect (sched, "arm", cfg);
214 if (client == NULL)
215 {
216 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
217 _("Failed to connect to ARM service\n"));
218 if (cb != NULL)
219 cb (cb_cls, GNUNET_SYSERR);
220 return;
221 }
222#if DEBUG_ARM
223 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
224 _("ARM requests starting of service `%s'.\n"), service_name);
225#endif
226 sctx = GNUNET_malloc (sizeof (struct ArmContext));
227 sctx->callback = cb;
228 sctx->cls = cb_cls;
229 sctx->client = client;
230 sctx->service_name = GNUNET_strdup (service_name);
231 sctx->timeout = GNUNET_TIME_relative_to_absolute (timeout);
232 sctx->type = type;
233 if (NULL ==
234 GNUNET_CLIENT_notify_transmit_ready (client,
235 slen +
236 sizeof (struct
237 GNUNET_MessageHeader),
238 timeout, &send_service_msg, sctx))
239 {
240 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
241 _("Failed to transmit request to ARM service\n"));
242 GNUNET_free (sctx->service_name);
243 GNUNET_free (sctx);
244 if (cb != NULL)
245 cb (cb_cls, GNUNET_SYSERR);
246 GNUNET_CLIENT_disconnect (client);
247 return;
248 }
249}
250
251
252/**
253 * Start a service.
254 *
255 * @param service_name name of the service
256 * @param cfg configuration to use (needed to contact ARM;
257 * the ARM service may internally use a different
258 * configuration to determine how to start the service).
259 * @param sched scheduler to use
260 * @param timeout how long to wait before failing for good
261 * @param cb callback to invoke when service is ready
262 * @param cb_cls closure for callback
263 */
264void
265GNUNET_ARM_start_service (const char *service_name,
266 struct GNUNET_CONFIGURATION_Handle *cfg,
267 struct GNUNET_SCHEDULER_Handle *sched,
268 struct GNUNET_TIME_Relative timeout,
269 GNUNET_ARM_Callback cb, void *cb_cls)
270{
271 struct ArmContext *sctx;
272
273 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
274 _("Starting service `%s'\n"), service_name);
275 if (0 == strcmp ("arm", service_name))
276 {
277 sctx = GNUNET_malloc (sizeof (struct ArmContext));
278 sctx->callback = cb;
279 sctx->cls = cb_cls;
280 sctx->cfg = cfg;
281 GNUNET_CLIENT_service_test (sched,
282 "arm",
283 cfg, timeout, &arm_service_report, sctx);
284 return;
285 }
286 change_service (service_name,
287 cfg,
288 sched, timeout, cb, cb_cls, GNUNET_MESSAGE_TYPE_ARM_START);
289}
290
291
292
293
294/**
295 * Stop a service.
296 *
297 * @param service_name name of the service
298 * @param cfg configuration to use (needed to contact ARM;
299 * the ARM service may internally use a different
300 * configuration to determine how to start the service).
301 * @param sched scheduler to use
302 * @param timeout how long to wait before failing for good
303 * @param cb callback to invoke when service is ready
304 * @param cb_cls closure for callback
305 */
306void
307GNUNET_ARM_stop_service (const char *service_name,
308 struct GNUNET_CONFIGURATION_Handle *cfg,
309 struct GNUNET_SCHEDULER_Handle *sched,
310 struct GNUNET_TIME_Relative timeout,
311 GNUNET_ARM_Callback cb, void *cb_cls)
312{
313 struct GNUNET_CLIENT_Connection *client;
314
315 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
316 _("Stopping service `%s'\n"), service_name);
317 if (0 == strcmp ("arm", service_name))
318 {
319 client = GNUNET_CLIENT_connect (sched, "arm", cfg);
320 if (client == NULL)
321 {
322 if (cb != NULL)
323 cb (cb_cls, GNUNET_SYSERR);
324 return;
325 }
326 GNUNET_CLIENT_service_shutdown (client);
327 GNUNET_CLIENT_disconnect (client);
328 if (cb != NULL)
329 cb (cb_cls, GNUNET_NO);
330 return;
331 }
332 change_service (service_name,
333 cfg,
334 sched, timeout, cb, cb_cls, GNUNET_MESSAGE_TYPE_ARM_STOP);
335}
336
337/* end of arm_api.c */