diff options
author | LRN <lrn1986@gmail.com> | 2013-03-13 17:49:26 +0000 |
---|---|---|
committer | LRN <lrn1986@gmail.com> | 2013-03-13 17:49:26 +0000 |
commit | 405f776bc08486af4edb80e18149c0829732b347 (patch) | |
tree | d5fc635a51641dec6b53cb2540276f34ae8f6210 /src/arm/arm_api.c | |
parent | 3ceae682287492ecc768aea5c4c463216a35774d (diff) | |
download | gnunet-405f776bc08486af4edb80e18149c0829732b347.tar.gz gnunet-405f776bc08486af4edb80e18149c0829732b347.zip |
All-encompassing ARM update
Diffstat (limited to 'src/arm/arm_api.c')
-rw-r--r-- | src/arm/arm_api.c | 1130 |
1 files changed, 659 insertions, 471 deletions
diff --git a/src/arm/arm_api.c b/src/arm/arm_api.c index aee9afb24..d434ff3af 100644 --- a/src/arm/arm_api.c +++ b/src/arm/arm_api.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet. | 2 | This file is part of GNUnet. |
3 | (C) 2009, 2010, 2012 Christian Grothoff (and other contributing authors) | 3 | (C) 2009, 2010, 2012, 2013 Christian Grothoff (and other contributing authors) |
4 | 4 | ||
5 | GNUnet is free software; you can redistribute it and/or modify | 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 | 6 | it under the terms of the GNU General Public License as published |
@@ -21,7 +21,7 @@ | |||
21 | /** | 21 | /** |
22 | * @file arm/arm_api.c | 22 | * @file arm/arm_api.c |
23 | * @brief API for accessing the ARM service | 23 | * @brief API for accessing the ARM service |
24 | * @author Christian Grothoff | 24 | * @author Christian Grothoff, LRN |
25 | */ | 25 | */ |
26 | #include "platform.h" | 26 | #include "platform.h" |
27 | #include "gnunet_arm_service.h" | 27 | #include "gnunet_arm_service.h" |
@@ -38,7 +38,7 @@ struct GNUNET_ARM_Handle | |||
38 | { | 38 | { |
39 | 39 | ||
40 | /** | 40 | /** |
41 | * Our connection to the ARM service. | 41 | * Our control connection to the ARM service. |
42 | */ | 42 | */ |
43 | struct GNUNET_CLIENT_Connection *client; | 43 | struct GNUNET_CLIENT_Connection *client; |
44 | 44 | ||
@@ -47,257 +47,469 @@ struct GNUNET_ARM_Handle | |||
47 | */ | 47 | */ |
48 | struct GNUNET_CONFIGURATION_Handle *cfg; | 48 | struct GNUNET_CONFIGURATION_Handle *cfg; |
49 | 49 | ||
50 | /** | ||
51 | * Handle for our current transmission request. | ||
52 | */ | ||
53 | struct GNUNET_CLIENT_TransmitHandle *cth; | ||
54 | |||
55 | /** | ||
56 | * Head of doubly-linked list of pending requests. | ||
57 | */ | ||
58 | struct ARMControlMessage *control_pending_head; | ||
59 | |||
60 | /** | ||
61 | * Tail of doubly-linked list of pending requests. | ||
62 | */ | ||
63 | struct ARMControlMessage *control_pending_tail; | ||
64 | |||
65 | /** | ||
66 | * Head of doubly-linked list of sent requests. | ||
67 | */ | ||
68 | struct ARMControlMessage *control_sent_head; | ||
69 | |||
70 | /** | ||
71 | * Tail of doubly-linked list of sent requests. | ||
72 | */ | ||
73 | struct ARMControlMessage *control_sent_tail; | ||
74 | |||
75 | /** | ||
76 | * ID of the reconnect task (if any). | ||
77 | */ | ||
78 | GNUNET_SCHEDULER_TaskIdentifier reconnect_task; | ||
79 | |||
80 | /** | ||
81 | * Current delay we use for re-trying to connect to core. | ||
82 | */ | ||
83 | struct GNUNET_TIME_Relative retry_backoff; | ||
84 | |||
85 | /** | ||
86 | * Are we currently disconnected and hence unable to send? | ||
87 | */ | ||
88 | unsigned char currently_down; | ||
89 | |||
90 | /** | ||
91 | * Callback to invoke on connection/disconnection. | ||
92 | */ | ||
93 | GNUNET_ARM_ConnectionStatusCallback conn_status; | ||
94 | |||
95 | /** | ||
96 | * Closure for conn_status. | ||
97 | */ | ||
98 | void *conn_status_cls; | ||
99 | |||
100 | /** | ||
101 | * GNUNET_YES if we're running a service test. | ||
102 | */ | ||
103 | unsigned char service_test_is_active; | ||
104 | |||
105 | /** | ||
106 | * Counter for request identifiers | ||
107 | */ | ||
108 | uint64_t request_id_counter; | ||
50 | }; | 109 | }; |
51 | 110 | ||
111 | |||
52 | /** | 112 | /** |
53 | * Context for handling the shutdown of a service. | 113 | * Entry in a doubly-linked list of control messages to be transmitted |
114 | * to the arm service. | ||
115 | * | ||
116 | * The actual message is allocated at the end of this struct. | ||
54 | */ | 117 | */ |
55 | struct ShutdownContext | 118 | struct ARMControlMessage |
56 | { | 119 | { |
57 | /** | 120 | /** |
58 | * Connection to the service that is being shutdown. | 121 | * This is a doubly-linked list. |
59 | */ | 122 | */ |
60 | struct GNUNET_CLIENT_Connection *sock; | 123 | struct ARMControlMessage *next; |
61 | 124 | ||
62 | /** | 125 | /** |
63 | * Time allowed for shutdown to happen. | 126 | * This is a doubly-linked list. |
64 | */ | 127 | */ |
65 | struct GNUNET_TIME_Absolute timeout; | 128 | struct ARMControlMessage *prev; |
66 | 129 | ||
67 | /** | 130 | /** |
68 | * Task set up to cancel the shutdown request on timeout. | 131 | * Callback for service state change requests. |
69 | */ | 132 | */ |
70 | GNUNET_SCHEDULER_TaskIdentifier cancel_task; | 133 | GNUNET_ARM_ResultCallback result_cont; |
71 | 134 | ||
72 | /** | 135 | /** |
73 | * Task to call once shutdown complete | 136 | * Callback for service list requests. |
74 | */ | 137 | */ |
75 | GNUNET_CLIENT_ShutdownTask cont; | 138 | GNUNET_ARM_ServiceListCallback list_cont; |
76 | 139 | ||
77 | /** | 140 | /** |
78 | * Closure for shutdown continuation | 141 | * Closure for 'result_cont' or 'list_cont'. |
79 | */ | 142 | */ |
80 | void *cont_cls; | 143 | void *cont_cls; |
81 | 144 | ||
82 | /** | 145 | /** |
83 | * Handle for transmission request. | 146 | * Timeout for the operation. |
84 | */ | 147 | */ |
85 | struct GNUNET_CLIENT_TransmitHandle *th; | 148 | struct GNUNET_TIME_Absolute timeout; |
86 | 149 | ||
150 | /** | ||
151 | * Type of the request expressed as a message type (start, stop or list). | ||
152 | */ | ||
153 | uint16_t type; | ||
154 | |||
155 | /** | ||
156 | * Flags for passing std descriptors to ARM (when starting ARM). | ||
157 | */ | ||
158 | enum GNUNET_OS_InheritStdioFlags std_inheritance; | ||
159 | |||
160 | /** | ||
161 | * ARM handle. | ||
162 | */ | ||
163 | struct GNUNET_ARM_Handle *h; | ||
164 | |||
165 | /** | ||
166 | * Message to send. | ||
167 | */ | ||
168 | struct GNUNET_ARM_Message *msg; | ||
169 | |||
170 | /** | ||
171 | * Task to run when request times out. | ||
172 | */ | ||
173 | GNUNET_SCHEDULER_TaskIdentifier timeout_task_id; | ||
87 | }; | 174 | }; |
88 | 175 | ||
176 | static void | ||
177 | client_notify_handler (void *cls, const struct GNUNET_MessageHeader *msg); | ||
178 | |||
179 | static void | ||
180 | reconnect_arm (struct GNUNET_ARM_Handle *h); | ||
181 | |||
182 | static void | ||
183 | trigger_next_request (struct GNUNET_ARM_Handle *h, int ignore_currently_down); | ||
184 | |||
89 | 185 | ||
90 | /** | 186 | /** |
91 | * Handler receiving response to service shutdown requests. | 187 | * Task scheduled to try to re-connect to arm. |
92 | * First call with NULL: service misbehaving, or something. | ||
93 | * First call with GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN_ACK: | ||
94 | * - service will shutdown | ||
95 | * Second call with NULL: | ||
96 | * - service has now really shut down. | ||
97 | * | 188 | * |
98 | * @param cls closure | 189 | * @param cls the 'struct GNUNET_ARM_Handle' |
99 | * @param msg NULL, indicating socket closure. | 190 | * @param tc task context |
100 | */ | 191 | */ |
101 | static void | 192 | static void |
102 | service_shutdown_handler (void *cls, const struct GNUNET_MessageHeader *msg) | 193 | reconnect_arm_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) |
194 | { | ||
195 | struct GNUNET_ARM_Handle *h = cls; | ||
196 | |||
197 | h->reconnect_task = GNUNET_SCHEDULER_NO_TASK; | ||
198 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to ARM service after delay\n"); | ||
199 | reconnect_arm (h); | ||
200 | } | ||
201 | |||
202 | |||
203 | static void | ||
204 | clear_pending_messages (struct GNUNET_ARM_Handle *h, enum GNUNET_ARM_RequestStatus result) | ||
103 | { | 205 | { |
104 | struct ShutdownContext *shutdown_ctx = cls; | 206 | struct ARMControlMessage *cm; |
105 | 207 | ||
106 | if (NULL != msg) | 208 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
209 | "Clearing pending messages\n"); | ||
210 | |||
211 | while (NULL != (cm = h->control_pending_head)) | ||
107 | { | 212 | { |
108 | /* We just expected a disconnect! Report the error and be done with it... */ | 213 | GNUNET_CONTAINER_DLL_remove (h->control_pending_head, |
109 | GNUNET_break (0); | 214 | h->control_pending_tail, cm); |
110 | shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_ARM_PROCESS_COMMUNICATION_ERROR); | 215 | GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != cm->timeout_task_id); |
111 | GNUNET_SCHEDULER_cancel (shutdown_ctx->cancel_task); | 216 | GNUNET_SCHEDULER_cancel (cm->timeout_task_id); |
112 | GNUNET_CLIENT_disconnect (shutdown_ctx->sock); | 217 | if (NULL != cm->result_cont) |
113 | GNUNET_free (shutdown_ctx); | 218 | cm->result_cont (cm->cont_cls, cm->h, result, NULL, 0); |
114 | return; | 219 | GNUNET_free_non_null (cm->msg); |
220 | GNUNET_free (cm); | ||
115 | } | 221 | } |
116 | if (NULL != shutdown_ctx->cont) | ||
117 | /* shutdown is now complete, as we waited for the network disconnect... */ | ||
118 | shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_ARM_PROCESS_DOWN); | ||
119 | GNUNET_SCHEDULER_cancel (shutdown_ctx->cancel_task); | ||
120 | GNUNET_CLIENT_disconnect (shutdown_ctx->sock); | ||
121 | GNUNET_free (shutdown_ctx); | ||
122 | } | 222 | } |
123 | 223 | ||
124 | |||
125 | /** | 224 | /** |
126 | * Shutting down took too long, cancel receive and return error. | 225 | * Close down any existing connection to the ARM service and |
226 | * try re-establishing it later. | ||
127 | * | 227 | * |
128 | * @param cls closure | 228 | * @param h our handle |
129 | * @param tc context information (why was this task triggered now) | ||
130 | */ | 229 | */ |
131 | static void | 230 | static void |
132 | service_shutdown_cancel (void *cls, | 231 | reconnect_arm_later (struct GNUNET_ARM_Handle *h) |
133 | const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
134 | { | 232 | { |
135 | struct ShutdownContext *shutdown_ctx = cls; | 233 | if (GNUNET_NO != h->currently_down) |
234 | return; | ||
136 | 235 | ||
137 | shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_ARM_PROCESS_COMMUNICATION_TIMEOUT); | 236 | if (NULL != h->cth) |
138 | GNUNET_CLIENT_disconnect (shutdown_ctx->sock); | 237 | { |
139 | GNUNET_free (shutdown_ctx); | 238 | GNUNET_CLIENT_notify_transmit_ready_cancel (h->cth); |
140 | } | 239 | h->cth = NULL; |
240 | } | ||
241 | |||
242 | if (NULL != h->client) | ||
243 | { | ||
244 | GNUNET_CLIENT_disconnect (h->client); | ||
245 | h->client = NULL; | ||
246 | } | ||
247 | |||
248 | if (NULL != h->conn_status) | ||
249 | h->conn_status (h->conn_status_cls, h, GNUNET_NO, GNUNET_NO); | ||
250 | |||
251 | h->currently_down = GNUNET_YES; | ||
141 | 252 | ||
253 | GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == h->reconnect_task); | ||
254 | h->reconnect_task = | ||
255 | GNUNET_SCHEDULER_add_delayed (h->retry_backoff, &reconnect_arm_task, h); | ||
256 | /* Don't clear pending messages on disconnection, deliver them later | ||
257 | clear_pending_messages (h, GNUNET_ARM_REQUEST_DISCONNECTED); | ||
258 | GNUNET_assert (NULL == h->control_pending_head); | ||
259 | */ | ||
260 | h->retry_backoff = GNUNET_TIME_STD_BACKOFF (h->retry_backoff); | ||
261 | } | ||
142 | 262 | ||
143 | /** | 263 | /** |
144 | * If possible, write a shutdown message to the target | 264 | * Transmit the next message to the arm service. |
145 | * buffer and destroy the client connection. | ||
146 | * | 265 | * |
147 | * @param cls the "struct GNUNET_CLIENT_Connection" to destroy | 266 | * @param cls closure with the 'struct GNUNET_ARM_Handle' |
148 | * @param size number of bytes available in buf | 267 | * @param size number of bytes available in buf |
149 | * @param buf NULL on error, otherwise target buffer | 268 | * @param buf where the callee should write the message |
150 | * @return number of bytes written to buf | 269 | * @return number of bytes written to buf |
151 | */ | 270 | */ |
152 | static size_t | 271 | static size_t |
153 | write_shutdown (void *cls, size_t size, void *buf) | 272 | transmit_arm_message (void *cls, size_t size, void *buf) |
154 | { | 273 | { |
155 | struct ShutdownContext *shutdown_ctx = cls; | 274 | struct GNUNET_ARM_Handle *h = cls; |
156 | struct GNUNET_MessageHeader *msg; | 275 | struct ARMControlMessage *cm; |
276 | struct GNUNET_ARM_Message *arm_msg; | ||
277 | uint16_t msize; | ||
278 | uint64_t request_id; | ||
157 | 279 | ||
158 | shutdown_ctx->th = NULL; | 280 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
159 | if (size < sizeof (struct GNUNET_MessageHeader)) | 281 | "transmit_arm_message is running with %p buffer of size %lu. ARM is known to be %s\n", |
282 | buf, size, h->currently_down ? "unconnected" : "connected"); | ||
283 | GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == h->reconnect_task); | ||
284 | h->cth = NULL; | ||
285 | if ((GNUNET_YES == h->currently_down) && (NULL != buf)) | ||
286 | { | ||
287 | h->currently_down = GNUNET_NO; | ||
288 | if (NULL != h->conn_status) | ||
289 | h->conn_status (h->conn_status_cls, h, GNUNET_YES, GNUNET_NO); | ||
290 | h->retry_backoff = GNUNET_TIME_UNIT_MILLISECONDS; | ||
291 | GNUNET_CLIENT_receive (h->client, &client_notify_handler, h, | ||
292 | GNUNET_TIME_UNIT_FOREVER_REL); | ||
293 | } | ||
294 | if (NULL == buf) | ||
295 | { | ||
296 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
297 | "Transmission failed, initiating reconnect\n"); | ||
298 | reconnect_arm_later (h); | ||
299 | return 0; | ||
300 | } | ||
301 | if (NULL == (cm = h->control_pending_head)) | ||
160 | { | 302 | { |
161 | LOG (GNUNET_ERROR_TYPE_WARNING, | 303 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Queue is empty, not sending anything\n"); |
162 | _("Failed to transmit shutdown request to client.\n")); | 304 | return 0; |
163 | shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_ARM_PROCESS_COMMUNICATION_ERROR); | ||
164 | GNUNET_CLIENT_disconnect (shutdown_ctx->sock); | ||
165 | GNUNET_free (shutdown_ctx); | ||
166 | return 0; /* client disconnected */ | ||
167 | } | 305 | } |
168 | GNUNET_CLIENT_receive (shutdown_ctx->sock, &service_shutdown_handler, | 306 | |
169 | shutdown_ctx, GNUNET_TIME_UNIT_FOREVER_REL); | 307 | GNUNET_assert (NULL != cm->msg); |
170 | shutdown_ctx->cancel_task = | 308 | msize = ntohs (cm->msg->header.size); |
171 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining | 309 | if (size < msize) |
172 | (shutdown_ctx->timeout), | 310 | { |
173 | &service_shutdown_cancel, shutdown_ctx); | 311 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
174 | msg = (struct GNUNET_MessageHeader *) buf; | 312 | "Request is too big (%u < %u), not sending it\n", size, msize); |
175 | msg->type = htons (GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN); | 313 | trigger_next_request (h, GNUNET_NO); |
176 | msg->size = htons (sizeof (struct GNUNET_MessageHeader)); | 314 | return 0; |
177 | return sizeof (struct GNUNET_MessageHeader); | 315 | } |
316 | arm_msg = cm->msg; | ||
317 | if (0 == h->request_id_counter) | ||
318 | h->request_id_counter++; | ||
319 | request_id = h->request_id_counter++; | ||
320 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
321 | "Transmitting control message with %u bytes of type %u to arm with id %llu\n", | ||
322 | (unsigned int) msize, (unsigned int) ntohs (cm->msg->header.type), request_id); | ||
323 | arm_msg->request_id = GNUNET_htonll (request_id); | ||
324 | memcpy (buf, cm->msg, msize); | ||
325 | /* Otherwise we won't be able to find it later! */ | ||
326 | arm_msg->request_id = request_id; | ||
327 | |||
328 | GNUNET_CONTAINER_DLL_remove (h->control_pending_head, | ||
329 | h->control_pending_tail, cm); | ||
330 | GNUNET_CONTAINER_DLL_insert_tail (h->control_sent_head, | ||
331 | h->control_sent_tail, cm); | ||
332 | |||
333 | /* Don't free msg, keep it around (kind of wasteful, but then we don't | ||
334 | * really have many messages to handle, and it'll be freed when it times | ||
335 | * out anyway. | ||
336 | */ | ||
337 | trigger_next_request (h, GNUNET_NO); | ||
338 | return msize; | ||
178 | } | 339 | } |
179 | 340 | ||
180 | 341 | ||
181 | /** | 342 | /** |
182 | * Request that the service should shutdown. | 343 | * Check the list of pending requests, send the next |
183 | * Afterwards, the connection will automatically be | 344 | * one to the arm. |
184 | * disconnected. Hence the "sock" should not | ||
185 | * be used by the caller after this call | ||
186 | * (calling this function frees "sock" after a while). | ||
187 | * | 345 | * |
188 | * @param sock the socket connected to the service | 346 | * @param h arm handle |
189 | * @param timeout how long to wait before giving up on transmission | 347 | * @param ignore_currently_down transmit message even if not initialized? |
190 | * @param cont continuation to call once the service is really down | 348 | */ |
191 | * @param cont_cls closure for continuation | 349 | static void |
350 | trigger_next_request (struct GNUNET_ARM_Handle *h, int ignore_currently_down) | ||
351 | { | ||
352 | uint16_t msize; | ||
353 | |||
354 | if ((GNUNET_YES == h->currently_down) && (ignore_currently_down == GNUNET_NO)) | ||
355 | { | ||
356 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
357 | "ARM connection down, not processing queue\n"); | ||
358 | return; | ||
359 | } | ||
360 | if (NULL != h->cth) | ||
361 | { | ||
362 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Request pending, not processing queue\n"); | ||
363 | return; | ||
364 | } | ||
365 | if (NULL != h->control_pending_head) | ||
366 | msize = | ||
367 | ntohs (((struct GNUNET_MessageHeader *) &h-> | ||
368 | control_pending_head[1])->size); | ||
369 | else if (GNUNET_NO == ignore_currently_down) | ||
370 | { | ||
371 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
372 | "Request queue empty, not processing queue\n"); | ||
373 | return; /* no pending message */ | ||
374 | } | ||
375 | h->cth = | ||
376 | GNUNET_CLIENT_notify_transmit_ready (h->client, msize, | ||
377 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
378 | GNUNET_NO, &transmit_arm_message, h); | ||
379 | } | ||
380 | |||
381 | |||
382 | /** | ||
383 | * Connect to arm. | ||
192 | * | 384 | * |
385 | * @param h arm handle | ||
193 | */ | 386 | */ |
194 | static void | 387 | static void |
195 | arm_service_shutdown (struct GNUNET_CLIENT_Connection *sock, | 388 | reconnect_arm (struct GNUNET_ARM_Handle *h) |
196 | struct GNUNET_TIME_Relative timeout, | ||
197 | GNUNET_CLIENT_ShutdownTask cont, void *cont_cls) | ||
198 | { | 389 | { |
199 | struct ShutdownContext *shutdown_ctx; | 390 | GNUNET_assert (NULL == h->client); |
200 | 391 | GNUNET_assert (GNUNET_YES == h->currently_down); | |
201 | shutdown_ctx = GNUNET_malloc (sizeof (struct ShutdownContext)); | 392 | h->client = GNUNET_CLIENT_connect ("arm", h->cfg); |
202 | shutdown_ctx->cont = cont; | 393 | if (NULL == h->client) |
203 | shutdown_ctx->cont_cls = cont_cls; | 394 | { |
204 | shutdown_ctx->sock = sock; | 395 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
205 | shutdown_ctx->timeout = GNUNET_TIME_relative_to_absolute (timeout); | 396 | "arm_api, GNUNET_CLIENT_connect returned NULL\n"); |
206 | shutdown_ctx->th = GNUNET_CLIENT_notify_transmit_ready (sock, | 397 | if (NULL != h->conn_status) |
207 | sizeof (struct GNUNET_MessageHeader), | 398 | h->conn_status (h->conn_status_cls, h, GNUNET_NO, GNUNET_YES); |
208 | timeout, GNUNET_NO, &write_shutdown, | 399 | return; |
209 | shutdown_ctx); | 400 | } |
401 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
402 | "arm_api, GNUNET_CLIENT_connect returned non-NULL\n"); | ||
403 | trigger_next_request (h, GNUNET_YES); | ||
210 | } | 404 | } |
211 | 405 | ||
212 | 406 | ||
213 | /** | 407 | /** |
214 | * Setup a context for communicating with ARM. Note that this | 408 | * Set up a context for communicating with ARM. Note that this |
215 | * can be done even if the ARM service is not yet running. | 409 | * can be done even if the ARM service is not yet running. |
410 | * Never fails. | ||
216 | * | 411 | * |
217 | * @param cfg configuration to use (needed to contact ARM; | 412 | * @param cfg configuration to use (needed to contact ARM; |
218 | * the ARM service may internally use a different | 413 | * the ARM service may internally use a different |
219 | * configuration to determine how to start the service). | 414 | * configuration to determine how to start the service). |
220 | * @param service service that *this* process is implementing/providing, can be NULL | 415 | * @return context to use for further ARM operations |
221 | * @return context to use for further ARM operations, NULL on error | ||
222 | */ | 416 | */ |
223 | struct GNUNET_ARM_Handle * | 417 | struct GNUNET_ARM_Handle * |
224 | GNUNET_ARM_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, | 418 | GNUNET_ARM_alloc (const struct GNUNET_CONFIGURATION_Handle *cfg) |
225 | const char *service) | ||
226 | { | 419 | { |
227 | struct GNUNET_ARM_Handle *ret; | 420 | struct GNUNET_ARM_Handle *ret; |
228 | 421 | ||
229 | ret = GNUNET_malloc (sizeof (struct GNUNET_ARM_Handle)); | 422 | ret = GNUNET_malloc (sizeof (struct GNUNET_ARM_Handle)); |
230 | ret->cfg = GNUNET_CONFIGURATION_dup (cfg); | 423 | ret->cfg = GNUNET_CONFIGURATION_dup (cfg); |
424 | ret->currently_down = GNUNET_YES; | ||
425 | ret->reconnect_task = GNUNET_SCHEDULER_NO_TASK; | ||
231 | return ret; | 426 | return ret; |
232 | } | 427 | } |
233 | 428 | ||
234 | 429 | ||
235 | /** | 430 | /** |
236 | * Disconnect from the ARM service. | 431 | * Start connecting to the ARM service using the context. |
237 | * | 432 | * |
238 | * @param h the handle that was being used | 433 | * @param h ARM handle |
434 | * @param conn_status will be called when connecting/disconnecting | ||
435 | * @param cls closure for conn_status | ||
239 | */ | 436 | */ |
240 | void | 437 | void |
241 | GNUNET_ARM_disconnect (struct GNUNET_ARM_Handle *h) | 438 | GNUNET_ARM_connect (struct GNUNET_ARM_Handle *h, |
439 | GNUNET_ARM_ConnectionStatusCallback conn_status, void *cls) | ||
242 | { | 440 | { |
243 | if (h->client != NULL) | 441 | h->conn_status = conn_status; |
244 | GNUNET_CLIENT_disconnect (h->client); | 442 | h->conn_status_cls = cls; |
245 | GNUNET_CONFIGURATION_destroy (h->cfg); | 443 | reconnect_arm (h); |
246 | GNUNET_free (h); | ||
247 | } | 444 | } |
248 | 445 | ||
249 | 446 | ||
250 | struct ARM_ShutdownContext | 447 | /** |
448 | * Disconnect from the ARM service (if connected) and destroy the context. | ||
449 | * Don't call inside an ARM callback! | ||
450 | * | ||
451 | * @param h the handle that was being used | ||
452 | */ | ||
453 | void | ||
454 | GNUNET_ARM_disconnect (struct GNUNET_ARM_Handle *handle) | ||
251 | { | 455 | { |
252 | /** | 456 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from ARM service\n"); |
253 | * Callback to call once shutdown complete. | 457 | if (NULL != handle->cth) |
254 | */ | 458 | { |
255 | GNUNET_ARM_Callback cb; | 459 | GNUNET_CLIENT_notify_transmit_ready_cancel (handle->cth); |
256 | 460 | handle->cth = NULL; | |
257 | /** | 461 | } |
258 | * Closure for callback. | 462 | clear_pending_messages (handle, GNUNET_ARM_REQUEST_DISCONNECTED); |
259 | */ | 463 | if (NULL != handle->client) |
260 | void *cb_cls; | 464 | { |
261 | }; | 465 | GNUNET_CLIENT_disconnect (handle->client); |
466 | handle->client = NULL; | ||
467 | } | ||
468 | if (GNUNET_SCHEDULER_NO_TASK != handle->reconnect_task) | ||
469 | { | ||
470 | GNUNET_SCHEDULER_cancel (handle->reconnect_task); | ||
471 | handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK; | ||
472 | } | ||
473 | if (GNUNET_NO == handle->service_test_is_active) | ||
474 | { | ||
475 | GNUNET_CONFIGURATION_destroy (handle->cfg); | ||
476 | GNUNET_free (handle); | ||
477 | } | ||
478 | } | ||
262 | 479 | ||
263 | 480 | ||
264 | /** | 481 | /** |
265 | * Internal state for a request with ARM. | 482 | * Message timed out. Remove it from the queue. |
483 | * | ||
484 | * @param cls the message (struct ARMControlMessage *) | ||
485 | * @param tc task context | ||
266 | */ | 486 | */ |
267 | struct RequestContext | 487 | static void |
488 | control_message_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
268 | { | 489 | { |
490 | struct ARMControlMessage *cm = cls; | ||
491 | struct GNUNET_ARM_Message *arm_msg; | ||
492 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
493 | "Control message timed out\n"); | ||
494 | arm_msg = cm->msg; | ||
495 | if ((NULL == arm_msg) || (0 == arm_msg->request_id)) | ||
496 | { | ||
497 | GNUNET_CONTAINER_DLL_remove (cm->h->control_pending_head, | ||
498 | cm->h->control_pending_tail, cm); | ||
499 | } | ||
500 | else | ||
501 | { | ||
502 | GNUNET_CONTAINER_DLL_remove (cm->h->control_sent_head, | ||
503 | cm->h->control_sent_tail, cm); | ||
504 | } | ||
505 | if (NULL != cm->result_cont) | ||
506 | cm->result_cont (cm->cont_cls, cm->h, GNUNET_ARM_REQUEST_TIMEOUT, NULL, 0); | ||
507 | else if (NULL != cm->list_cont) | ||
508 | cm->list_cont (cm->cont_cls, cm->h, GNUNET_ARM_REQUEST_TIMEOUT, 0, NULL); | ||
509 | GNUNET_free_non_null (cm->msg); | ||
510 | GNUNET_free (cm); | ||
511 | } | ||
269 | 512 | ||
270 | /** | ||
271 | * Pointer to our handle with ARM. | ||
272 | */ | ||
273 | struct GNUNET_ARM_Handle *h; | ||
274 | |||
275 | /** | ||
276 | * Function to call with a status code for the requested operation. | ||
277 | */ | ||
278 | GNUNET_ARM_Callback callback; | ||
279 | |||
280 | /** | ||
281 | * Closure for "callback". | ||
282 | */ | ||
283 | void *cls; | ||
284 | |||
285 | /** | ||
286 | * Timeout for the operation. | ||
287 | */ | ||
288 | struct GNUNET_TIME_Absolute timeout; | ||
289 | |||
290 | /** | ||
291 | * Type of the request expressed as a message type (start or stop). | ||
292 | */ | ||
293 | uint16_t type; | ||
294 | |||
295 | /** | ||
296 | * Flags for passing std descriptors to ARM (when starting ARM). | ||
297 | */ | ||
298 | enum GNUNET_OS_InheritStdioFlags std_inheritance; | ||
299 | |||
300 | }; | ||
301 | 513 | ||
302 | #include "do_start_process.c" | 514 | #include "do_start_process.c" |
303 | 515 | ||
@@ -308,78 +520,89 @@ struct RequestContext | |||
308 | * or not ARM is running; if it is, report success. If | 520 | * or not ARM is running; if it is, report success. If |
309 | * it is not, start the ARM process. | 521 | * it is not, start the ARM process. |
310 | * | 522 | * |
311 | * @param cls the context for the request that we will report on (struct RequestContext*) | 523 | * @param cls the context for the request that we will report on (struct ARMControlMessage *) |
312 | * @param tc why were we called (reason says if ARM is running) | 524 | * @param tc why were we called (reason says if ARM is running) |
313 | */ | 525 | */ |
314 | static void | 526 | static void |
315 | arm_service_report (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | 527 | arm_service_report (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) |
316 | { | 528 | { |
317 | struct RequestContext *pos = cls; | 529 | struct ARMControlMessage *cm = cls; |
318 | struct GNUNET_OS_Process *proc; | 530 | struct GNUNET_OS_Process *proc; |
531 | unsigned char test_is_active; | ||
319 | char *cbinary; | 532 | char *cbinary; |
320 | char *binary; | 533 | char *binary; |
321 | char *config; | 534 | char *config; |
322 | char *loprefix; | 535 | char *loprefix; |
323 | char *lopostfix; | 536 | char *lopostfix; |
324 | 537 | ||
325 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE)) | 538 | test_is_active = cm->h->service_test_is_active; |
539 | |||
540 | /* FIXME: shouldn't we check for GNUNET_SCHEDULER_REASON_SHUTDOWN ? */ | ||
541 | if ((GNUNET_YES == test_is_active) && | ||
542 | (0 != (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE))) | ||
326 | { | 543 | { |
327 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Looks like `%s' is already running.\n", | 544 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Looks like `%s' is already running.\n", |
328 | "gnunet-service-arm"); | 545 | "gnunet-service-arm"); |
329 | /* arm is running! */ | 546 | /* arm is running! */ |
330 | if (pos->callback != NULL) | 547 | if (cm->result_cont) |
331 | pos->callback (pos->cls, GNUNET_ARM_PROCESS_ALREADY_RUNNING); | 548 | cm->result_cont (cm->cont_cls, cm->h, GNUNET_ARM_REQUEST_SENT_OK, "arm", GNUNET_ARM_RESULT_IS_STARTED_ALREADY); |
332 | GNUNET_free (pos); | 549 | } |
550 | if (GNUNET_NO == test_is_active) | ||
551 | { | ||
552 | /* User disconnected & destroyed ARM handle in the middle of | ||
553 | * the service test, so we kept the handle around until now. | ||
554 | */ | ||
555 | GNUNET_CONFIGURATION_destroy (cm->h->cfg); | ||
556 | GNUNET_free (cm->h); | ||
557 | } | ||
558 | if ((0 != (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE)) || | ||
559 | (GNUNET_NO == test_is_active)) | ||
560 | { | ||
561 | GNUNET_free (cm); | ||
333 | return; | 562 | return; |
334 | } | 563 | } |
564 | cm->h->service_test_is_active = GNUNET_NO; | ||
335 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 565 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
336 | "Looks like `%s' is not running, will start it.\n", | 566 | "Looks like `%s' is not running, will start it.\n", |
337 | "gnunet-service-arm"); | 567 | "gnunet-service-arm"); |
338 | if (GNUNET_OK != | 568 | if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string ( |
339 | GNUNET_CONFIGURATION_get_value_string (pos->h->cfg, "arm", "PREFIX", | 569 | cm->h->cfg, "arm", "PREFIX", &loprefix)) |
340 | &loprefix)) | ||
341 | loprefix = GNUNET_strdup (""); | 570 | loprefix = GNUNET_strdup (""); |
342 | if (GNUNET_OK != | 571 | if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string ( |
343 | GNUNET_CONFIGURATION_get_value_string (pos->h->cfg, "arm", "OPTIONS", | 572 | cm->h->cfg, "arm", "OPTIONS", &lopostfix)) |
344 | &lopostfix)) | ||
345 | lopostfix = GNUNET_strdup (""); | 573 | lopostfix = GNUNET_strdup (""); |
346 | if (GNUNET_OK != | 574 | if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string ( |
347 | GNUNET_CONFIGURATION_get_value_string (pos->h->cfg, "arm", "BINARY", | 575 | cm->h->cfg, "arm", "BINARY", &cbinary)) |
348 | &cbinary)) | ||
349 | { | 576 | { |
350 | GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, | 577 | GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, "arm", "BINARY"); |
351 | "arm", "BINARY"); | 578 | if (cm->result_cont) |
352 | if (pos->callback != NULL) | 579 | cm->result_cont (cm->cont_cls, cm->h, GNUNET_ARM_REQUEST_SENT_OK, "arm", GNUNET_ARM_RESULT_IS_NOT_KNOWN); |
353 | pos->callback (pos->cls, GNUNET_ARM_PROCESS_UNKNOWN); | 580 | GNUNET_free (cm); |
354 | GNUNET_free (pos); | ||
355 | GNUNET_free (loprefix); | 581 | GNUNET_free (loprefix); |
356 | GNUNET_free (lopostfix); | 582 | GNUNET_free (lopostfix); |
357 | return; | 583 | return; |
358 | } | 584 | } |
359 | if (GNUNET_OK != | 585 | if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename ( |
360 | GNUNET_CONFIGURATION_get_value_filename (pos->h->cfg, "arm", "CONFIG", | 586 | cm->h->cfg, "arm", "CONFIG", &config)) |
361 | &config)) | ||
362 | config = NULL; | 587 | config = NULL; |
363 | binary = GNUNET_OS_get_libexec_binary_path (cbinary); | 588 | binary = GNUNET_OS_get_libexec_binary_path (cbinary); |
364 | GNUNET_free (cbinary); | 589 | GNUNET_free (cbinary); |
365 | if ((GNUNET_YES == | 590 | if ((GNUNET_YES == GNUNET_CONFIGURATION_have_value ( |
366 | GNUNET_CONFIGURATION_have_value (pos->h->cfg, "TESTING", "WEAKRANDOM")) | 591 | cm->h->cfg, "TESTING", "WEAKRANDOM")) && |
367 | && (GNUNET_YES == | 592 | (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno ( |
368 | GNUNET_CONFIGURATION_get_value_yesno (pos->h->cfg, "TESTING", | 593 | cm->h->cfg, "TESTING", "WEAKRANDOM")) && |
369 | "WEAKRANDOM")) | 594 | (GNUNET_NO == GNUNET_CONFIGURATION_have_value ( |
370 | && (GNUNET_NO == | 595 | cm->h->cfg, "TESTING", "HOSTFILE"))) |
371 | GNUNET_CONFIGURATION_have_value (pos->h->cfg, "TESTING", | ||
372 | "HOSTFILE"))) | ||
373 | { | 596 | { |
374 | /* Means we are ONLY running locally */ | 597 | /* Means we are ONLY running locally */ |
375 | /* we're clearly running a test, don't daemonize */ | 598 | /* we're clearly running a test, don't daemonize */ |
376 | if (NULL == config) | 599 | if (NULL == config) |
377 | proc = do_start_process (GNUNET_NO, pos->std_inheritance, | 600 | proc = do_start_process (GNUNET_NO, cm->std_inheritance, |
378 | NULL, loprefix, binary, | 601 | NULL, loprefix, binary, |
379 | /* no daemonization! */ | 602 | /* no daemonization! */ |
380 | lopostfix, NULL); | 603 | lopostfix, NULL); |
381 | else | 604 | else |
382 | proc = do_start_process (GNUNET_NO, pos->std_inheritance, | 605 | proc = do_start_process (GNUNET_NO, cm->std_inheritance, |
383 | NULL, loprefix, binary, "-c", config, | 606 | NULL, loprefix, binary, "-c", config, |
384 | /* no daemonization! */ | 607 | /* no daemonization! */ |
385 | lopostfix, NULL); | 608 | lopostfix, NULL); |
@@ -387,11 +610,11 @@ arm_service_report (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
387 | else | 610 | else |
388 | { | 611 | { |
389 | if (NULL == config) | 612 | if (NULL == config) |
390 | proc = do_start_process (GNUNET_NO, pos->std_inheritance, | 613 | proc = do_start_process (GNUNET_NO, cm->std_inheritance, |
391 | NULL, loprefix, binary, | 614 | NULL, loprefix, binary, |
392 | "-d", lopostfix, NULL); | 615 | "-d", lopostfix, NULL); |
393 | else | 616 | else |
394 | proc = do_start_process (GNUNET_NO, pos->std_inheritance, | 617 | proc = do_start_process (GNUNET_NO, cm->std_inheritance, |
395 | NULL, loprefix, binary, "-c", config, | 618 | NULL, loprefix, binary, "-c", config, |
396 | "-d", lopostfix, NULL); | 619 | "-d", lopostfix, NULL); |
397 | } | 620 | } |
@@ -401,52 +624,18 @@ arm_service_report (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
401 | GNUNET_free (lopostfix); | 624 | GNUNET_free (lopostfix); |
402 | if (NULL == proc) | 625 | if (NULL == proc) |
403 | { | 626 | { |
404 | if (pos->callback != NULL) | 627 | if (cm->result_cont) |
405 | pos->callback (pos->cls, GNUNET_ARM_PROCESS_FAILURE); | 628 | cm->result_cont (cm->cont_cls, cm->h, GNUNET_ARM_REQUEST_SENT_OK, "arm", |
406 | GNUNET_free (pos); | 629 | GNUNET_ARM_RESULT_START_FAILED); |
630 | GNUNET_free (cm); | ||
407 | return; | 631 | return; |
408 | } | 632 | } |
409 | if (pos->callback != NULL) | 633 | if (cm->result_cont) |
410 | pos->callback (pos->cls, GNUNET_ARM_PROCESS_STARTING); | 634 | cm->result_cont (cm->cont_cls, cm->h, GNUNET_ARM_REQUEST_SENT_OK, "arm", |
635 | GNUNET_ARM_RESULT_STARTING); | ||
411 | GNUNET_OS_process_destroy (proc); | 636 | GNUNET_OS_process_destroy (proc); |
412 | GNUNET_free (pos); | 637 | reconnect_arm (cm->h); |
413 | } | 638 | GNUNET_free (cm); |
414 | |||
415 | |||
416 | /** | ||
417 | * Process a response from ARM to a request for a change in service | ||
418 | * status. | ||
419 | * | ||
420 | * @param cls the request context | ||
421 | * @param msg the response | ||
422 | */ | ||
423 | static void | ||
424 | handle_response (void *cls, const struct GNUNET_MessageHeader *msg) | ||
425 | { | ||
426 | struct RequestContext *sc = cls; | ||
427 | const struct GNUNET_ARM_ResultMessage *res; | ||
428 | enum GNUNET_ARM_ProcessStatus status; | ||
429 | |||
430 | if ((msg == NULL) || | ||
431 | (ntohs (msg->size) != sizeof (struct GNUNET_ARM_ResultMessage))) | ||
432 | { | ||
433 | GNUNET_break (0); | ||
434 | GNUNET_CLIENT_disconnect (sc->h->client); | ||
435 | sc->h->client = GNUNET_CLIENT_connect ("arm", sc->h->cfg); | ||
436 | GNUNET_assert (NULL != sc->h->client); | ||
437 | if (sc->callback != NULL) | ||
438 | sc->callback (sc->cls, GNUNET_ARM_PROCESS_COMMUNICATION_ERROR); | ||
439 | GNUNET_free (sc); | ||
440 | return; | ||
441 | } | ||
442 | res = (const struct GNUNET_ARM_ResultMessage *) msg; | ||
443 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
444 | "Received response from ARM for service `%s': %u\n", | ||
445 | (const char *) &sc[1], ntohs (msg->type)); | ||
446 | status = (enum GNUNET_ARM_ProcessStatus) ntohl (res->status); | ||
447 | if (sc->callback != NULL) | ||
448 | sc->callback (sc->cls, status); | ||
449 | GNUNET_free (sc); | ||
450 | } | 639 | } |
451 | 640 | ||
452 | 641 | ||
@@ -462,74 +651,65 @@ handle_response (void *cls, const struct GNUNET_MessageHeader *msg) | |||
462 | */ | 651 | */ |
463 | static void | 652 | static void |
464 | change_service (struct GNUNET_ARM_Handle *h, const char *service_name, | 653 | change_service (struct GNUNET_ARM_Handle *h, const char *service_name, |
465 | struct GNUNET_TIME_Relative timeout, GNUNET_ARM_Callback cb, | 654 | struct GNUNET_TIME_Relative timeout, GNUNET_ARM_ResultCallback cb, |
466 | void *cb_cls, uint16_t type) | 655 | void *cb_cls, uint16_t type) |
467 | { | 656 | { |
468 | struct RequestContext *sctx; | 657 | struct ARMControlMessage *cm; |
469 | size_t slen; | 658 | size_t slen; |
470 | struct GNUNET_MessageHeader *msg; | 659 | struct GNUNET_ARM_Message *msg; |
471 | 660 | ||
472 | slen = strlen (service_name) + 1; | 661 | slen = strlen (service_name) + 1; |
473 | if (slen + sizeof (struct GNUNET_MessageHeader) >= | 662 | if (slen + sizeof (struct GNUNET_ARM_Message) >= |
474 | GNUNET_SERVER_MAX_MESSAGE_SIZE) | 663 | GNUNET_SERVER_MAX_MESSAGE_SIZE) |
475 | { | 664 | { |
476 | GNUNET_break (0); | 665 | GNUNET_break (0); |
477 | if (cb != NULL) | 666 | if (cb != NULL) |
478 | cb (cb_cls, GNUNET_NO); | 667 | cb (cb_cls, h, GNUNET_ARM_REQUEST_TOO_LONG, NULL, 0); |
479 | return; | 668 | return; |
480 | } | 669 | } |
481 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 670 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Requesting %s of service `%s'.\n", |
482 | (type == | 671 | (GNUNET_MESSAGE_TYPE_ARM_START == type) ? "start" : "termination", |
483 | GNUNET_MESSAGE_TYPE_ARM_START) ? | 672 | service_name); |
484 | "Requesting start of service `%s'.\n" : | 673 | cm = GNUNET_malloc (sizeof (struct ARMControlMessage) + slen); |
485 | "Requesting termination of service `%s'.\n", service_name); | 674 | cm->h = h; |
486 | sctx = GNUNET_malloc (sizeof (struct RequestContext) + slen); | 675 | cm->result_cont = cb; |
487 | sctx->h = h; | 676 | cm->cont_cls = cb_cls; |
488 | sctx->callback = cb; | 677 | cm->timeout = GNUNET_TIME_relative_to_absolute (timeout); |
489 | sctx->cls = cb_cls; | 678 | memcpy (&cm[1], service_name, slen); |
490 | sctx->timeout = GNUNET_TIME_relative_to_absolute (timeout); | 679 | msg = GNUNET_malloc (sizeof (struct GNUNET_ARM_Message) + slen); |
491 | sctx->type = type; | 680 | msg->header.size = htons (sizeof (struct GNUNET_ARM_Message) + slen); |
492 | memcpy (&sctx[1], service_name, slen); | 681 | msg->header.type = htons (type); |
493 | msg = GNUNET_malloc (sizeof (struct GNUNET_MessageHeader) + slen); | ||
494 | msg->size = htons (sizeof (struct GNUNET_MessageHeader) + slen); | ||
495 | msg->type = htons (sctx->type); | ||
496 | memcpy (&msg[1], service_name, slen); | 682 | memcpy (&msg[1], service_name, slen); |
497 | if (GNUNET_OK != | 683 | cm->msg = msg; |
498 | GNUNET_CLIENT_transmit_and_get_response (sctx->h->client, msg, | 684 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
499 | GNUNET_TIME_absolute_get_remaining | 685 | "Inserting a control message into the queue. Timeout is %llu\n", |
500 | (sctx->timeout), GNUNET_YES, | 686 | GNUNET_TIME_absolute_get_remaining (cm->timeout).rel_value); |
501 | &handle_response, sctx)) | 687 | GNUNET_CONTAINER_DLL_insert_tail (h->control_pending_head, |
502 | { | 688 | h->control_pending_tail, cm); |
503 | GNUNET_break (0); | 689 | cm->timeout_task_id = |
504 | if (cb != NULL) | 690 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining |
505 | cb (cb_cls, GNUNET_SYSERR); | 691 | (cm->timeout), &control_message_timeout, cm); |
506 | GNUNET_free (sctx); | 692 | trigger_next_request (h, GNUNET_NO); |
507 | GNUNET_free (msg); | ||
508 | return; | ||
509 | } | ||
510 | GNUNET_free (msg); | ||
511 | } | 693 | } |
512 | 694 | ||
513 | 695 | ||
514 | /** | 696 | /** |
515 | * Start a service. | 697 | * Request for a service to be started. |
516 | * | 698 | * |
517 | * @param h handle to ARM | 699 | * @param h handle to ARM |
518 | * @param service_name name of the service | 700 | * @param service_name name of the service |
519 | * @param std_inheritance inheritance of std streams | 701 | * @param std_inheritance inheritance of std streams |
520 | * @param timeout how long to wait before failing for good | 702 | * @param timeout how long to wait before failing for good |
521 | * @param cb callback to invoke when service is ready | 703 | * @param cont callback to invoke after request is sent or not sent |
522 | * @param cb_cls closure for callback | 704 | * @param cont_cls closure for callback |
523 | */ | 705 | */ |
524 | void | 706 | void |
525 | GNUNET_ARM_start_service (struct GNUNET_ARM_Handle *h, | 707 | GNUNET_ARM_request_service_start (struct GNUNET_ARM_Handle *h, |
526 | const char *service_name, | 708 | const char *service_name, enum GNUNET_OS_InheritStdioFlags std_inheritance, |
527 | enum GNUNET_OS_InheritStdioFlags std_inheritance, | 709 | struct GNUNET_TIME_Relative timeout, GNUNET_ARM_ResultCallback cont, |
528 | struct GNUNET_TIME_Relative timeout, | 710 | void *cont_cls) |
529 | GNUNET_ARM_Callback cb, void *cb_cls) | ||
530 | { | 711 | { |
531 | struct RequestContext *sctx; | 712 | struct ARMControlMessage *cm; |
532 | struct GNUNET_CLIENT_Connection *client; | ||
533 | size_t slen; | 713 | size_t slen; |
534 | 714 | ||
535 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 715 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
@@ -537,258 +717,266 @@ GNUNET_ARM_start_service (struct GNUNET_ARM_Handle *h, | |||
537 | GNUNET_STRINGS_relative_time_to_string (timeout, GNUNET_NO)); | 717 | GNUNET_STRINGS_relative_time_to_string (timeout, GNUNET_NO)); |
538 | if (0 == strcasecmp ("arm", service_name)) | 718 | if (0 == strcasecmp ("arm", service_name)) |
539 | { | 719 | { |
540 | slen = strlen ("arm") + 1; | 720 | /* Possible cases: |
541 | sctx = GNUNET_malloc (sizeof (struct RequestContext) + slen); | 721 | * 1) We're connected to ARM already. Invoke the callback immediately. |
542 | sctx->h = h; | 722 | * 2) We're not connected to ARM. |
543 | sctx->callback = cb; | 723 | * Cancel any reconnection attempts temporarily, then perform |
544 | sctx->cls = cb_cls; | 724 | * a service test. |
545 | sctx->timeout = GNUNET_TIME_relative_to_absolute (timeout); | 725 | */ |
546 | sctx->std_inheritance = std_inheritance; | 726 | if (GNUNET_NO == h->currently_down) |
547 | memcpy (&sctx[1], service_name, slen); | 727 | { |
548 | GNUNET_CLIENT_service_test ("arm", h->cfg, timeout, &arm_service_report, | 728 | LOG (GNUNET_ERROR_TYPE_DEBUG, "ARM is already running\n"); |
549 | sctx); | 729 | if (NULL != cont) |
550 | return; | 730 | cont (cont_cls, h, GNUNET_ARM_REQUEST_SENT_OK, "arm", GNUNET_ARM_RESULT_IS_STARTED_ALREADY); |
551 | } | 731 | } |
552 | if (NULL == h->client) | 732 | else if (GNUNET_NO == h->service_test_is_active) |
553 | { | ||
554 | client = GNUNET_CLIENT_connect ("arm", h->cfg); | ||
555 | if (client == NULL) | ||
556 | { | 733 | { |
734 | if (NULL != h->cth) | ||
735 | { | ||
736 | GNUNET_CLIENT_notify_transmit_ready_cancel (h->cth); | ||
737 | h->cth = NULL; | ||
738 | } | ||
739 | if (NULL != h->client) | ||
740 | { | ||
741 | GNUNET_CLIENT_disconnect (h->client); | ||
742 | h->client = NULL; | ||
743 | } | ||
744 | if (GNUNET_SCHEDULER_NO_TASK != h->reconnect_task) | ||
745 | { | ||
746 | GNUNET_SCHEDULER_cancel (h->reconnect_task); | ||
747 | h->reconnect_task = GNUNET_SCHEDULER_NO_TASK; | ||
748 | } | ||
749 | |||
557 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 750 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
558 | "arm_api, GNUNET_CLIENT_connect returned NULL\n"); | 751 | "Not connected to ARM, will do a service test\n"); |
559 | cb (cb_cls, GNUNET_ARM_PROCESS_COMMUNICATION_ERROR); | 752 | |
560 | return; | 753 | slen = strlen ("arm") + 1; |
754 | cm = GNUNET_malloc (sizeof (struct ARMControlMessage) + slen); | ||
755 | cm->h = h; | ||
756 | cm->result_cont = cont; | ||
757 | cm->cont_cls = cont_cls; | ||
758 | cm->timeout = GNUNET_TIME_relative_to_absolute (timeout); | ||
759 | cm->std_inheritance = std_inheritance; | ||
760 | memcpy (&cm[1], service_name, slen); | ||
761 | h->service_test_is_active = GNUNET_YES; | ||
762 | GNUNET_CLIENT_service_test ("arm", h->cfg, timeout, &arm_service_report, | ||
763 | cm); | ||
561 | } | 764 | } |
562 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 765 | else |
563 | "arm_api, GNUNET_CLIENT_connect returned non-NULL\n"); | 766 | { |
564 | h->client = client; | 767 | /* Service test is already running - tell user to chill out and try |
768 | * again later. | ||
769 | */ | ||
770 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Service test is already in progress, we're busy\n"); | ||
771 | if (NULL != cont) | ||
772 | cont (cont_cls, h, GNUNET_ARM_REQUEST_BUSY, NULL, 0); | ||
773 | } | ||
774 | return; | ||
565 | } | 775 | } |
566 | LOG (GNUNET_ERROR_TYPE_DEBUG, "arm_api, h->client non-NULL\n"); | 776 | change_service (h, service_name, timeout, cont, cont_cls, |
567 | change_service (h, service_name, timeout, cb, cb_cls, | ||
568 | GNUNET_MESSAGE_TYPE_ARM_START); | 777 | GNUNET_MESSAGE_TYPE_ARM_START); |
569 | } | 778 | } |
570 | 779 | ||
571 | 780 | ||
572 | /** | 781 | /** |
573 | * Callback from the arm stop service call, indicates that the arm service | 782 | * Request a service to be stopped. |
574 | * is well and truly dead, won't die, or an error occurred. | 783 | * Stopping arm itself will not invalidate its handle, and |
575 | * | 784 | * ARM API will try to restore connection to the ARM service, |
576 | * @param cls closure for the callback | 785 | * even if ARM connection was lost because you asked for ARM to be stopped. |
577 | * @param reason reason for callback | 786 | * Call GNUNET_ARM_disconnect () to free the handle and prevent |
578 | */ | 787 | * further connection attempts. |
579 | static void | ||
580 | arm_shutdown_callback (void *cls, enum GNUNET_ARM_ProcessStatus reason) | ||
581 | { | ||
582 | struct ARM_ShutdownContext *arm_shutdown_ctx = cls; | ||
583 | |||
584 | if (arm_shutdown_ctx->cb != NULL) | ||
585 | arm_shutdown_ctx->cb (arm_shutdown_ctx->cb_cls, reason); | ||
586 | GNUNET_free (arm_shutdown_ctx); | ||
587 | } | ||
588 | |||
589 | |||
590 | /** | ||
591 | * Stop a service. | ||
592 | * | 788 | * |
593 | * @param h handle to ARM | 789 | * @param h handle to ARM |
594 | * @param service_name name of the service | 790 | * @param service_name name of the service |
595 | * @param timeout how long to wait before failing for good | 791 | * @param timeout how long to wait before failing for good |
596 | * @param cb callback to invoke when service is ready | 792 | * @param cont callback to invoke after request is sent or is not sent |
597 | * @param cb_cls closure for callback | 793 | * @param cont_cls closure for callback |
598 | */ | 794 | */ |
599 | void | 795 | void |
600 | GNUNET_ARM_stop_service (struct GNUNET_ARM_Handle *h, | 796 | GNUNET_ARM_request_service_stop (struct GNUNET_ARM_Handle *h, |
601 | const char *service_name, | 797 | const char *service_name, struct GNUNET_TIME_Relative timeout, |
602 | struct GNUNET_TIME_Relative timeout, | 798 | GNUNET_ARM_ResultCallback cont, void *cont_cls) |
603 | GNUNET_ARM_Callback cb, void *cb_cls) | ||
604 | { | 799 | { |
605 | struct ARM_ShutdownContext *arm_shutdown_ctx; | ||
606 | struct GNUNET_CLIENT_Connection *client; | ||
607 | |||
608 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 800 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
609 | "Stopping service `%s' within %s\n", | 801 | "Stopping service `%s' within %s\n", |
610 | service_name, | 802 | service_name, |
611 | GNUNET_STRINGS_relative_time_to_string (timeout, GNUNET_NO)); | 803 | GNUNET_STRINGS_relative_time_to_string (timeout, GNUNET_NO)); |
612 | if (h->client == NULL) | 804 | change_service (h, service_name, timeout, cont, cont_cls, |
613 | { | ||
614 | client = GNUNET_CLIENT_connect ("arm", h->cfg); | ||
615 | if (client == NULL) | ||
616 | { | ||
617 | cb (cb_cls, GNUNET_SYSERR); | ||
618 | return; | ||
619 | } | ||
620 | h->client = client; | ||
621 | } | ||
622 | if (0 == strcasecmp ("arm", service_name)) | ||
623 | { | ||
624 | arm_shutdown_ctx = GNUNET_malloc (sizeof (struct ARM_ShutdownContext)); | ||
625 | arm_shutdown_ctx->cb = cb; | ||
626 | arm_shutdown_ctx->cb_cls = cb_cls; | ||
627 | arm_service_shutdown (h->client, timeout, &arm_shutdown_callback, | ||
628 | arm_shutdown_ctx); | ||
629 | h->client = NULL; | ||
630 | return; | ||
631 | } | ||
632 | change_service (h, service_name, timeout, cb, cb_cls, | ||
633 | GNUNET_MESSAGE_TYPE_ARM_STOP); | 805 | GNUNET_MESSAGE_TYPE_ARM_STOP); |
634 | } | 806 | } |
635 | 807 | ||
636 | 808 | ||
637 | /** | 809 | /** |
638 | * Internal state for a list request with ARM. | 810 | * Request a list of running services. |
811 | * | ||
812 | * @param h handle to ARM | ||
813 | * @param timeout how long to wait before failing for good | ||
814 | * @param cont callback to invoke after request is sent or is not sent | ||
815 | * @param cont_cls closure for callback | ||
639 | */ | 816 | */ |
640 | struct ListRequestContext | 817 | void |
818 | GNUNET_ARM_request_service_list (struct GNUNET_ARM_Handle *h, | ||
819 | struct GNUNET_TIME_Relative timeout, | ||
820 | GNUNET_ARM_ServiceListCallback cont, void *cont_cls) | ||
641 | { | 821 | { |
822 | struct ARMControlMessage *cm; | ||
823 | struct GNUNET_ARM_Message *msg; | ||
642 | 824 | ||
643 | /** | 825 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
644 | * Pointer to our handle with ARM. | 826 | "Requesting LIST from ARM service with timeout: %s\n", |
645 | */ | 827 | GNUNET_STRINGS_relative_time_to_string (timeout, GNUNET_YES)); |
646 | struct GNUNET_ARM_Handle *h; | ||
647 | |||
648 | /** | ||
649 | * Function to call with a status code for the requested operation. | ||
650 | */ | ||
651 | GNUNET_ARM_List_Callback callback; | ||
652 | 828 | ||
653 | /** | 829 | cm = GNUNET_malloc (sizeof (struct ARMControlMessage)); |
654 | * Closure for "callback". | 830 | cm->h = h; |
655 | */ | 831 | cm->list_cont = cont; |
656 | void *cls; | 832 | cm->cont_cls = cont_cls; |
833 | cm->timeout = GNUNET_TIME_relative_to_absolute (timeout); | ||
834 | msg = GNUNET_malloc (sizeof (struct GNUNET_ARM_Message)); | ||
835 | msg->header.size = htons (sizeof (struct GNUNET_ARM_Message)); | ||
836 | msg->header.type = htons (GNUNET_MESSAGE_TYPE_ARM_LIST); | ||
837 | cm->msg = msg; | ||
838 | GNUNET_CONTAINER_DLL_insert_tail (h->control_pending_head, | ||
839 | h->control_pending_tail, cm); | ||
840 | cm->timeout_task_id = | ||
841 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining | ||
842 | (cm->timeout), &control_message_timeout, cm); | ||
843 | trigger_next_request (h, GNUNET_NO); | ||
844 | } | ||
657 | 845 | ||
658 | /** | 846 | static struct ARMControlMessage * |
659 | * Timeout for the operation. | 847 | find_cm_by_id (struct GNUNET_ARM_Handle *h, uint64_t id) |
660 | */ | 848 | { |
661 | struct GNUNET_TIME_Absolute timeout; | 849 | struct ARMControlMessage *result; |
662 | }; | 850 | for (result = h->control_sent_head; result; result = result->next) |
851 | if (id == result->msg->request_id) | ||
852 | return result; | ||
853 | return NULL; | ||
854 | } | ||
663 | 855 | ||
664 | 856 | ||
665 | /** | 857 | /** |
666 | * Process a response from ARM for the list request. | 858 | * Handler for ARM replies. |
667 | * | 859 | * |
668 | * @param cls the list request context | 860 | * @param cls our "struct GNUNET_ARM_Handle" |
669 | * @param msg the response | 861 | * @param msg the message received from the arm service |
670 | */ | 862 | */ |
671 | static void | 863 | static void |
672 | handle_list_response (void *cls, const struct GNUNET_MessageHeader *msg) | 864 | client_notify_handler (void *cls, const struct GNUNET_MessageHeader *msg) |
673 | { | 865 | { |
674 | struct ListRequestContext *sc = cls; | 866 | struct GNUNET_ARM_Handle *h = cls; |
675 | const struct GNUNET_ARM_ListResultMessage *res; | 867 | |
868 | uint16_t msize; | ||
869 | uint64_t id; | ||
870 | unsigned char fail; | ||
871 | |||
872 | const struct GNUNET_ARM_Message *arm_msg; | ||
873 | const struct GNUNET_ARM_ResultMessage *res; | ||
874 | const struct GNUNET_ARM_ListResultMessage *lres; | ||
875 | enum GNUNET_ARM_Result result; | ||
876 | struct ARMControlMessage *cm; | ||
877 | |||
676 | const char *pos; | 878 | const char *pos; |
677 | uint16_t size_check; | 879 | uint16_t size_check; |
678 | uint16_t rcount; | 880 | uint16_t rcount; |
679 | uint16_t msize; | 881 | |
680 | |||
681 | if (NULL == msg) | 882 | if (NULL == msg) |
682 | { | 883 | { |
683 | GNUNET_break (0); | 884 | LOG (GNUNET_ERROR_TYPE_INFO, |
684 | GNUNET_CLIENT_disconnect (sc->h->client); | 885 | _("Client was disconnected from arm service, trying to reconnect.\n")); |
685 | sc->h->client = GNUNET_CLIENT_connect ("arm", sc->h->cfg); | 886 | reconnect_arm_later (h); |
686 | GNUNET_assert (NULL != sc->h->client); | ||
687 | if (sc->callback != NULL) | ||
688 | sc->callback (sc->cls, GNUNET_ARM_PROCESS_COMMUNICATION_ERROR, 0, NULL); | ||
689 | GNUNET_free (sc); | ||
690 | return; | 887 | return; |
691 | } | 888 | } |
692 | |||
693 | if (NULL == sc->callback) | ||
694 | { | ||
695 | GNUNET_break (0); | ||
696 | GNUNET_free (sc); | ||
697 | return; | ||
698 | } | ||
699 | msize = ntohs (msg->size); | 889 | msize = ntohs (msg->size); |
700 | if ( (msize < sizeof ( struct GNUNET_ARM_ListResultMessage)) || | 890 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
701 | (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT) ) | 891 | "Processing message of type %u and size %u from arm service\n", |
892 | ntohs (msg->type), msize); | ||
893 | if (msize < sizeof (struct GNUNET_ARM_Message)) | ||
702 | { | 894 | { |
703 | GNUNET_break (0); | 895 | GNUNET_break (0); |
704 | sc->callback (sc->cls, GNUNET_NO, 0, NULL); | 896 | reconnect_arm_later (h); |
705 | GNUNET_free (sc); | ||
706 | return; | 897 | return; |
707 | } | 898 | } |
708 | size_check = 0; | 899 | arm_msg = (const struct GNUNET_ARM_Message *) msg; |
709 | res = (const struct GNUNET_ARM_ListResultMessage *) msg; | 900 | id = GNUNET_ntohll (arm_msg->request_id); |
710 | rcount = ntohs (res->count); | 901 | cm = find_cm_by_id (h, id); |
902 | if (NULL == cm) | ||
711 | { | 903 | { |
712 | const char *list[rcount]; | 904 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Message with unknown id %llu\n", id); |
713 | unsigned int i; | 905 | return; |
714 | |||
715 | pos = (const char *)&res[1]; | ||
716 | for (i=0; i<rcount; i++) | ||
717 | { | ||
718 | const char *end = memchr (pos, 0, msize - size_check); | ||
719 | if (NULL == end) | ||
720 | { | ||
721 | GNUNET_break (0); | ||
722 | sc->callback (sc->cls, GNUNET_NO, 0, NULL); | ||
723 | GNUNET_free (sc); | ||
724 | return; | ||
725 | } | ||
726 | list[i] = pos; | ||
727 | size_check += (end - pos) + 1; | ||
728 | pos = end + 1; | ||
729 | } | ||
730 | sc->callback (sc->cls, GNUNET_YES, rcount, list); | ||
731 | } | 906 | } |
732 | GNUNET_free (sc); | ||
733 | } | ||
734 | |||
735 | |||
736 | /** | ||
737 | * List all running services. | ||
738 | * | ||
739 | * @param h handle to ARM | ||
740 | * @param timeout how long to wait before failing for good | ||
741 | * @param cb callback to invoke when service is ready | ||
742 | * @param cb_cls closure for callback | ||
743 | */ | ||
744 | void | ||
745 | GNUNET_ARM_list_running_services (struct GNUNET_ARM_Handle *h, | ||
746 | struct GNUNET_TIME_Relative timeout, | ||
747 | GNUNET_ARM_List_Callback cb, void *cb_cls) | ||
748 | { | ||
749 | struct ListRequestContext *sctx; | ||
750 | struct GNUNET_MessageHeader msg; | ||
751 | struct GNUNET_CLIENT_Connection *client; | ||
752 | 907 | ||
753 | if (h->client == NULL) | 908 | fail = GNUNET_NO; |
909 | switch (ntohs (msg->type)) | ||
754 | { | 910 | { |
755 | client = GNUNET_CLIENT_connect ("arm", h->cfg); | 911 | case GNUNET_MESSAGE_TYPE_ARM_RESULT: |
756 | if (client == NULL) | 912 | if (msize < sizeof (struct GNUNET_ARM_ResultMessage)) |
913 | { | ||
914 | GNUNET_assert (0); | ||
915 | fail = GNUNET_YES; | ||
916 | break; | ||
917 | } | ||
918 | res = (const struct GNUNET_ARM_ResultMessage *) msg; | ||
919 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
920 | "Received response from ARM for service `%s': %u\n", | ||
921 | (const char *) &cm->msg[1], ntohs (msg->type)); | ||
922 | result = (enum GNUNET_ARM_Result) ntohl (res->result); | ||
923 | if (NULL != cm->result_cont) | ||
924 | cm->result_cont (cm->cont_cls, h, GNUNET_ARM_REQUEST_SENT_OK, (const char *) &cm->msg[1], result); | ||
925 | break; | ||
926 | case GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT: | ||
927 | if (msize < sizeof (struct GNUNET_ARM_ListResultMessage)) | ||
757 | { | 928 | { |
758 | GNUNET_break (0); | 929 | GNUNET_break (0); |
759 | cb (cb_cls, GNUNET_ARM_PROCESS_COMMUNICATION_ERROR, 0, NULL); | 930 | fail = GNUNET_YES; |
760 | return; | 931 | return; |
761 | } | 932 | } |
762 | h->client = client; | 933 | else |
763 | } | 934 | { |
764 | 935 | size_check = 0; | |
765 | sctx = GNUNET_malloc (sizeof (struct RequestContext)); | 936 | lres = (const struct GNUNET_ARM_ListResultMessage *) msg; |
766 | sctx->h = h; | 937 | rcount = ntohs (lres->count); |
767 | sctx->callback = cb; | 938 | { |
768 | sctx->cls = cb_cls; | 939 | const char *list[rcount]; |
769 | sctx->timeout = GNUNET_TIME_relative_to_absolute (timeout); | 940 | unsigned int i; |
770 | msg.size = htons (sizeof (struct GNUNET_MessageHeader)); | 941 | |
771 | msg.type = htons (GNUNET_MESSAGE_TYPE_ARM_LIST); | 942 | pos = (const char *)&lres[1]; |
772 | 943 | for (i = 0; i < rcount; i++) | |
773 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 944 | { |
774 | "Requesting LIST from ARM service with timeout: %s\n", | 945 | const char *end = memchr (pos, 0, msize - size_check); |
775 | GNUNET_STRINGS_relative_time_to_string (timeout, GNUNET_YES)); | 946 | if (NULL == end) |
776 | 947 | { | |
777 | if (GNUNET_OK != | 948 | GNUNET_break (0); |
778 | GNUNET_CLIENT_transmit_and_get_response (sctx->h->client, | 949 | fail = GNUNET_YES; |
779 | &msg, | 950 | break; |
780 | GNUNET_TIME_absolute_get_remaining | 951 | } |
781 | (sctx->timeout), | 952 | list[i] = pos; |
782 | GNUNET_YES, | 953 | size_check += (end - pos) + 1; |
783 | &handle_list_response, | 954 | pos = end + 1; |
784 | sctx)) | 955 | } |
785 | { | 956 | if (GNUNET_YES == fail) |
786 | GNUNET_break (0); | 957 | break; |
787 | if (cb != NULL) | 958 | if (NULL != cm->list_cont) |
788 | cb (cb_cls, GNUNET_SYSERR, 0, NULL); | 959 | cm->list_cont (cm->cont_cls, h, GNUNET_ARM_REQUEST_SENT_OK, rcount, list); |
789 | GNUNET_free (sctx); | 960 | } |
961 | } | ||
962 | break; | ||
963 | default: | ||
964 | fail = GNUNET_YES; | ||
790 | return; | 965 | return; |
791 | } | 966 | } |
967 | |||
968 | GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != cm->timeout_task_id); | ||
969 | GNUNET_SCHEDULER_cancel (cm->timeout_task_id); | ||
970 | GNUNET_CONTAINER_DLL_remove (h->control_sent_head, | ||
971 | h->control_sent_tail, cm); | ||
972 | GNUNET_free (cm->msg); | ||
973 | GNUNET_free (cm); | ||
974 | |||
975 | if (GNUNET_YES == fail) | ||
976 | reconnect_arm_later (h); | ||
977 | else | ||
978 | GNUNET_CLIENT_receive (h->client, &client_notify_handler, h, | ||
979 | GNUNET_TIME_UNIT_FOREVER_REL); | ||
792 | } | 980 | } |
793 | 981 | ||
794 | /* end of arm_api.c */ | 982 | /* end of arm_api.c */ |