diff options
author | Christian Grothoff <christian@grothoff.org> | 2016-06-23 14:22:34 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2016-06-23 14:22:34 +0000 |
commit | 5742938289524f4c5fba7883742e4dd69cccf11d (patch) | |
tree | e16fea8b9d778f9825f897237b0c1880305776a0 /src/arm/arm_api.c | |
parent | f3edb5a8d6ba6f43f5df18f2e98bc1dae90c9d7a (diff) | |
download | gnunet-5742938289524f4c5fba7883742e4dd69cccf11d.tar.gz gnunet-5742938289524f4c5fba7883742e4dd69cccf11d.zip |
refactoring ARM api to use new MQ
Diffstat (limited to 'src/arm/arm_api.c')
-rw-r--r-- | src/arm/arm_api.c | 1219 |
1 files changed, 505 insertions, 714 deletions
diff --git a/src/arm/arm_api.c b/src/arm/arm_api.c index a89d423ec..ed36c61cd 100644 --- a/src/arm/arm_api.c +++ b/src/arm/arm_api.c | |||
@@ -32,151 +32,131 @@ | |||
32 | 32 | ||
33 | #define LOG(kind,...) GNUNET_log_from (kind, "arm-api",__VA_ARGS__) | 33 | #define LOG(kind,...) GNUNET_log_from (kind, "arm-api",__VA_ARGS__) |
34 | 34 | ||
35 | |||
35 | /** | 36 | /** |
36 | * Handle for interacting with ARM. | 37 | * Entry in a doubly-linked list of operations awaiting for replies |
38 | * (in-order) from the ARM service. | ||
37 | */ | 39 | */ |
38 | struct GNUNET_ARM_Handle | 40 | struct GNUNET_ARM_Operation |
39 | { | 41 | { |
40 | /** | 42 | /** |
41 | * Our control connection to the ARM service. | 43 | * This is a doubly-linked list. |
42 | */ | ||
43 | struct GNUNET_CLIENT_Connection *client; | ||
44 | |||
45 | /** | ||
46 | * The configuration that we are using. | ||
47 | */ | ||
48 | struct GNUNET_CONFIGURATION_Handle *cfg; | ||
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 | */ | 44 | */ |
68 | struct ARMControlMessage *control_sent_head; | 45 | struct GNUNET_ARM_Operation *next; |
69 | 46 | ||
70 | /** | 47 | /** |
71 | * Tail of doubly-linked list of sent requests. | 48 | * This is a doubly-linked list. |
72 | */ | 49 | */ |
73 | struct ARMControlMessage *control_sent_tail; | 50 | struct GNUNET_ARM_Operation *prev; |
74 | 51 | ||
75 | /** | 52 | /** |
76 | * Callback to invoke on connection/disconnection. | 53 | * ARM handle. |
77 | */ | 54 | */ |
78 | GNUNET_ARM_ConnectionStatusCallback conn_status; | 55 | struct GNUNET_ARM_Handle *h; |
79 | 56 | ||
80 | /** | 57 | /** |
81 | * Closure for conn_status. | 58 | * Callback for service state change requests. |
82 | */ | 59 | */ |
83 | void *conn_status_cls; | 60 | GNUNET_ARM_ResultCallback result_cont; |
84 | 61 | ||
85 | /** | 62 | /** |
86 | * ARM control message for the 'arm_termination_handler' | 63 | * Callback for service list requests. |
87 | * with the continuation to call once the ARM shutdown is done. | ||
88 | */ | 64 | */ |
89 | struct ARMControlMessage *thm; | 65 | GNUNET_ARM_ServiceListCallback list_cont; |
90 | 66 | ||
91 | /** | 67 | /** |
92 | * ID of the reconnect task (if any). | 68 | * Closure for @e result_cont or @e list_cont. |
93 | */ | 69 | */ |
94 | struct GNUNET_SCHEDULER_Task *reconnect_task; | 70 | void *cont_cls; |
95 | 71 | ||
96 | /** | 72 | /** |
97 | * Current delay we use for re-trying to connect to core. | 73 | * Task for async completion. |
98 | */ | 74 | */ |
99 | struct GNUNET_TIME_Relative retry_backoff; | 75 | struct GNUNET_SCHEDULER_Task *async; |
100 | 76 | ||
101 | /** | 77 | /** |
102 | * Counter for request identifiers | 78 | * Unique ID for the request. |
103 | */ | 79 | */ |
104 | uint64_t request_id_counter; | 80 | uint64_t id; |
105 | 81 | ||
106 | /** | 82 | /** |
107 | * Are we currently disconnected and hence unable to send? | 83 | * Result of this operation for #notify_starting(). |
108 | */ | 84 | */ |
109 | unsigned char currently_down; | 85 | enum GNUNET_ARM_Result starting_ret; |
110 | 86 | ||
111 | /** | 87 | /** |
112 | * #GNUNET_YES if we're running a service test. | 88 | * Is this an operation to stop the ARM service? |
113 | */ | 89 | */ |
114 | unsigned char service_test_is_active; | 90 | int is_arm_stop; |
115 | }; | 91 | }; |
116 | 92 | ||
117 | 93 | ||
118 | /** | 94 | /** |
119 | * Entry in a doubly-linked list of control messages to be transmitted | 95 | * Handle for interacting with ARM. |
120 | * to the arm service. | ||
121 | * | ||
122 | * The actual message is allocated at the end of this struct. | ||
123 | */ | 96 | */ |
124 | struct ARMControlMessage | 97 | struct GNUNET_ARM_Handle |
125 | { | 98 | { |
126 | /** | 99 | /** |
127 | * This is a doubly-linked list. | 100 | * Our connection to the ARM service. |
128 | */ | 101 | */ |
129 | struct ARMControlMessage *next; | 102 | struct GNUNET_MQ_Handle *mq; |
130 | 103 | ||
131 | /** | 104 | /** |
132 | * This is a doubly-linked list. | 105 | * The configuration that we are using. |
133 | */ | 106 | */ |
134 | struct ARMControlMessage *prev; | 107 | const struct GNUNET_CONFIGURATION_Handle *cfg; |
135 | 108 | ||
136 | /** | 109 | /** |
137 | * ARM handle. | 110 | * Head of doubly-linked list of pending operations. |
138 | */ | 111 | */ |
139 | struct GNUNET_ARM_Handle *h; | 112 | struct GNUNET_ARM_Operation *operation_pending_head; |
140 | 113 | ||
141 | /** | 114 | /** |
142 | * Message to send. | 115 | * Tail of doubly-linked list of pending operations. |
143 | */ | 116 | */ |
144 | struct GNUNET_ARM_Message *msg; | 117 | struct GNUNET_ARM_Operation *operation_pending_tail; |
145 | 118 | ||
146 | /** | 119 | /** |
147 | * Callback for service state change requests. | 120 | * Callback to invoke on connection/disconnection. |
148 | */ | 121 | */ |
149 | GNUNET_ARM_ResultCallback result_cont; | 122 | GNUNET_ARM_ConnectionStatusCallback conn_status; |
150 | 123 | ||
151 | /** | 124 | /** |
152 | * Callback for service list requests. | 125 | * Closure for @e conn_status. |
153 | */ | 126 | */ |
154 | GNUNET_ARM_ServiceListCallback list_cont; | 127 | void *conn_status_cls; |
155 | 128 | ||
156 | /** | 129 | /** |
157 | * Closure for @e result_cont or @e list_cont. | 130 | * ARM operation where the goal is to wait for ARM shutdown to |
131 | * complete. This operation is special in that it waits for an | ||
132 | * error on the @e mq. So we complete it by calling the | ||
133 | * continuation in the #mq_error_handler(). Note that the operation | ||
134 | * is no longer in the @e operation_pending_head DLL once it is | ||
135 | * referenced from this field. | ||
158 | */ | 136 | */ |
159 | void *cont_cls; | 137 | struct GNUNET_ARM_Operation *thm; |
160 | 138 | ||
161 | /** | 139 | /** |
162 | * Timeout for the operation. | 140 | * ID of the reconnect task (if any). |
163 | */ | 141 | */ |
164 | struct GNUNET_TIME_Absolute timeout; | 142 | struct GNUNET_SCHEDULER_Task *reconnect_task; |
165 | 143 | ||
166 | /** | 144 | /** |
167 | * Task to run when request times out. | 145 | * Current delay we use for re-trying to connect to core. |
168 | */ | 146 | */ |
169 | struct GNUNET_SCHEDULER_Task *timeout_task_id; | 147 | struct GNUNET_TIME_Relative retry_backoff; |
170 | 148 | ||
171 | /** | 149 | /** |
172 | * Flags for passing std descriptors to ARM (when starting ARM). | 150 | * Counter for request identifiers. They are used to match replies |
151 | * from ARM to operations in the @e operation_pending_head DLL. | ||
173 | */ | 152 | */ |
174 | enum GNUNET_OS_InheritStdioFlags std_inheritance; | 153 | uint64_t request_id_counter; |
175 | 154 | ||
176 | /** | 155 | /** |
177 | * Type of the request expressed as a message type (start, stop or list). | 156 | * Have we detected that ARM is up? |
178 | */ | 157 | */ |
179 | uint16_t type; | 158 | int currently_up; |
159 | |||
180 | }; | 160 | }; |
181 | 161 | ||
182 | 162 | ||
@@ -191,18 +171,6 @@ reconnect_arm (struct GNUNET_ARM_Handle *h); | |||
191 | 171 | ||
192 | 172 | ||
193 | /** | 173 | /** |
194 | * Check the list of pending requests, send the next | ||
195 | * one to the arm. | ||
196 | * | ||
197 | * @param h arm handle | ||
198 | * @param ignore_currently_down transmit message even if not initialized? | ||
199 | */ | ||
200 | static void | ||
201 | trigger_next_request (struct GNUNET_ARM_Handle *h, | ||
202 | int ignore_currently_down); | ||
203 | |||
204 | |||
205 | /** | ||
206 | * Task scheduled to try to re-connect to arm. | 174 | * Task scheduled to try to re-connect to arm. |
207 | * | 175 | * |
208 | * @param cls the `struct GNUNET_ARM_Handle` | 176 | * @param cls the `struct GNUNET_ARM_Handle` |
@@ -213,8 +181,6 @@ reconnect_arm_task (void *cls) | |||
213 | struct GNUNET_ARM_Handle *h = cls; | 181 | struct GNUNET_ARM_Handle *h = cls; |
214 | 182 | ||
215 | h->reconnect_task = NULL; | 183 | h->reconnect_task = NULL; |
216 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
217 | "Connecting to ARM service after delay\n"); | ||
218 | reconnect_arm (h); | 184 | reconnect_arm (h); |
219 | } | 185 | } |
220 | 186 | ||
@@ -228,28 +194,33 @@ reconnect_arm_task (void *cls) | |||
228 | static void | 194 | static void |
229 | reconnect_arm_later (struct GNUNET_ARM_Handle *h) | 195 | reconnect_arm_later (struct GNUNET_ARM_Handle *h) |
230 | { | 196 | { |
231 | if (GNUNET_NO != h->currently_down) | 197 | struct GNUNET_ARM_Operation *op; |
232 | return; | 198 | |
233 | if (NULL != h->cth) | 199 | if (NULL != h->mq) |
234 | { | ||
235 | GNUNET_CLIENT_notify_transmit_ready_cancel (h->cth); | ||
236 | h->cth = NULL; | ||
237 | } | ||
238 | if (NULL != h->client) | ||
239 | { | 200 | { |
240 | GNUNET_CLIENT_disconnect (h->client); | 201 | GNUNET_MQ_destroy (h->mq); |
241 | h->client = NULL; | 202 | h->mq = NULL; |
242 | } | 203 | } |
243 | h->currently_down = GNUNET_YES; | 204 | h->currently_up = GNUNET_NO; |
244 | GNUNET_assert (NULL == h->reconnect_task); | 205 | GNUNET_assert (NULL == h->reconnect_task); |
245 | h->reconnect_task = | 206 | h->reconnect_task = |
246 | GNUNET_SCHEDULER_add_delayed (h->retry_backoff, | 207 | GNUNET_SCHEDULER_add_delayed (h->retry_backoff, |
247 | &reconnect_arm_task, | 208 | &reconnect_arm_task, |
248 | h); | 209 | h); |
249 | /* Don't clear pending messages on disconnection, deliver them later | 210 | while (NULL != (op = h->operation_pending_head)) |
250 | clear_pending_messages (h, GNUNET_ARM_REQUEST_DISCONNECTED); | 211 | { |
251 | GNUNET_assert (NULL == h->control_pending_head); | 212 | if (NULL != op->result_cont) |
252 | */ | 213 | op->result_cont (op->cont_cls, |
214 | GNUNET_ARM_REQUEST_DISCONNECTED, | ||
215 | 0); | ||
216 | if (NULL != op->list_cont) | ||
217 | op->list_cont (op->cont_cls, | ||
218 | GNUNET_ARM_REQUEST_DISCONNECTED, | ||
219 | 0, | ||
220 | NULL); | ||
221 | GNUNET_ARM_operation_cancel (op); | ||
222 | } | ||
223 | GNUNET_assert (NULL == h->operation_pending_head); | ||
253 | h->retry_backoff = GNUNET_TIME_STD_BACKOFF (h->retry_backoff); | 224 | h->retry_backoff = GNUNET_TIME_STD_BACKOFF (h->retry_backoff); |
254 | if (NULL != h->conn_status) | 225 | if (NULL != h->conn_status) |
255 | h->conn_status (h->conn_status_cls, | 226 | h->conn_status (h->conn_status_cls, |
@@ -264,176 +235,50 @@ reconnect_arm_later (struct GNUNET_ARM_Handle *h) | |||
264 | * @param id unique message ID to use for the lookup | 235 | * @param id unique message ID to use for the lookup |
265 | * @return NULL if not found | 236 | * @return NULL if not found |
266 | */ | 237 | */ |
267 | static struct ARMControlMessage * | 238 | static struct GNUNET_ARM_Operation * |
268 | find_cm_by_id (struct GNUNET_ARM_Handle *h, | 239 | find_op_by_id (struct GNUNET_ARM_Handle *h, |
269 | uint64_t id) | 240 | uint64_t id) |
270 | { | 241 | { |
271 | struct ARMControlMessage *result; | 242 | struct GNUNET_ARM_Operation *result; |
272 | 243 | ||
273 | for (result = h->control_sent_head; NULL != result; result = result->next) | 244 | for (result = h->operation_pending_head; NULL != result; result = result->next) |
274 | if (id == result->msg->request_id) | 245 | if (id == result->id) |
275 | return result; | 246 | return result; |
276 | return NULL; | 247 | return NULL; |
277 | } | 248 | } |
278 | 249 | ||
279 | 250 | ||
280 | /** | 251 | /** |
281 | * Handler for ARM 'termination' reply (failure to receive). | ||
282 | * | ||
283 | * @param cls our `struct GNUNET_ARM_Handle` | ||
284 | * @param msg expected to be NULL | ||
285 | */ | ||
286 | static void | ||
287 | arm_termination_handler (void *cls, | ||
288 | const struct GNUNET_MessageHeader *msg) | ||
289 | { | ||
290 | struct GNUNET_ARM_Handle *h = cls; | ||
291 | struct ARMControlMessage *cm; | ||
292 | |||
293 | if (NULL != msg) | ||
294 | { | ||
295 | GNUNET_break (0); | ||
296 | GNUNET_CLIENT_receive (h->client, | ||
297 | &arm_termination_handler, | ||
298 | h, | ||
299 | GNUNET_TIME_UNIT_FOREVER_REL); | ||
300 | return; | ||
301 | } | ||
302 | cm = h->thm; | ||
303 | h->thm = NULL; | ||
304 | h->currently_down = GNUNET_YES; | ||
305 | GNUNET_CLIENT_disconnect (h->client); | ||
306 | h->client = NULL; | ||
307 | if (NULL != cm->result_cont) | ||
308 | cm->result_cont (cm->cont_cls, | ||
309 | GNUNET_ARM_REQUEST_SENT_OK, | ||
310 | (const char *) &cm->msg[1], | ||
311 | GNUNET_ARM_RESULT_STOPPED); | ||
312 | GNUNET_free (cm->msg); | ||
313 | GNUNET_free (cm); | ||
314 | } | ||
315 | |||
316 | |||
317 | /** | ||
318 | * Handler for ARM replies. | 252 | * Handler for ARM replies. |
319 | * | 253 | * |
320 | * @param cls our `struct GNUNET_ARM_Handle` | 254 | * @param cls our `struct GNUNET_ARM_Handle` |
321 | * @param msg the message received from the arm service | 255 | * @param res the message received from the arm service |
322 | */ | 256 | */ |
323 | static void | 257 | static void |
324 | client_notify_handler (void *cls, | 258 | handle_arm_result (void *cls, |
325 | const struct GNUNET_MessageHeader *msg) | 259 | const struct GNUNET_ARM_ResultMessage *res) |
326 | { | 260 | { |
327 | struct GNUNET_ARM_Handle *h = cls; | 261 | struct GNUNET_ARM_Handle *h = cls; |
328 | const struct GNUNET_ARM_Message *arm_msg; | 262 | struct GNUNET_ARM_Operation *op; |
329 | const struct GNUNET_ARM_ResultMessage *res; | ||
330 | const struct GNUNET_ARM_ListResultMessage *lres; | ||
331 | struct ARMControlMessage *cm; | ||
332 | const char **list; | ||
333 | const char *pos; | ||
334 | uint64_t id; | 263 | uint64_t id; |
335 | enum GNUNET_ARM_Result result; | 264 | enum GNUNET_ARM_Result result; |
336 | uint16_t size_check; | 265 | GNUNET_ARM_ResultCallback result_cont; |
337 | uint16_t rcount; | 266 | void *result_cont_cls; |
338 | uint16_t msize; | ||
339 | unsigned char fail; | ||
340 | 267 | ||
341 | list = NULL; | 268 | id = GNUNET_ntohll (res->arm_msg.request_id); |
342 | rcount = 0; | 269 | op = find_op_by_id (h, |
343 | if (NULL == msg) | 270 | id); |
344 | { | 271 | if (NULL == op) |
345 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
346 | _("Client was disconnected from arm service, trying to reconnect.\n")); | ||
347 | reconnect_arm_later (h); | ||
348 | return; | ||
349 | } | ||
350 | msize = ntohs (msg->size); | ||
351 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
352 | "Processing message of type %u and size %u from arm service\n", | ||
353 | ntohs (msg->type), msize); | ||
354 | if (msize < sizeof (struct GNUNET_ARM_Message)) | ||
355 | { | ||
356 | GNUNET_break (0); | ||
357 | reconnect_arm_later (h); | ||
358 | return; | ||
359 | } | ||
360 | arm_msg = (const struct GNUNET_ARM_Message *) msg; | ||
361 | GNUNET_break (0 == ntohl (arm_msg->reserved)); | ||
362 | id = GNUNET_ntohll (arm_msg->request_id); | ||
363 | cm = find_cm_by_id (h, id); | ||
364 | if (NULL == cm) | ||
365 | { | 272 | { |
366 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 273 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
367 | "Message with unknown id %llu\n", | 274 | "Message with unknown id %llu\n", |
368 | id); | 275 | (unsigned long long) id); |
369 | return; | ||
370 | } | ||
371 | fail = GNUNET_NO; | ||
372 | switch (ntohs (msg->type)) | ||
373 | { | ||
374 | case GNUNET_MESSAGE_TYPE_ARM_RESULT: | ||
375 | if (msize < sizeof (struct GNUNET_ARM_ResultMessage)) | ||
376 | { | ||
377 | GNUNET_assert (0); | ||
378 | fail = GNUNET_YES; | ||
379 | } | ||
380 | break; | ||
381 | case GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT: | ||
382 | if (msize < sizeof (struct GNUNET_ARM_ListResultMessage)) | ||
383 | { | ||
384 | GNUNET_break (0); | ||
385 | fail = GNUNET_YES; | ||
386 | break; | ||
387 | } | ||
388 | size_check = 0; | ||
389 | lres = (const struct GNUNET_ARM_ListResultMessage *) msg; | ||
390 | rcount = ntohs (lres->count); | ||
391 | { | ||
392 | unsigned int i; | ||
393 | |||
394 | list = GNUNET_malloc (sizeof (const char *) * rcount); | ||
395 | pos = (const char *)&lres[1]; | ||
396 | for (i = 0; i < rcount; i++) | ||
397 | { | ||
398 | const char *end = memchr (pos, 0, msize - size_check); | ||
399 | if (NULL == end) | ||
400 | { | ||
401 | GNUNET_break (0); | ||
402 | fail = GNUNET_YES; | ||
403 | break; | ||
404 | } | ||
405 | list[i] = pos; | ||
406 | size_check += (end - pos) + 1; | ||
407 | pos = end + 1; | ||
408 | } | ||
409 | if (GNUNET_YES == fail) | ||
410 | { | ||
411 | GNUNET_free (list); | ||
412 | list = NULL; | ||
413 | } | ||
414 | } | ||
415 | break; | ||
416 | default: | ||
417 | fail = GNUNET_YES; | ||
418 | break; | ||
419 | } | ||
420 | GNUNET_assert (NULL != cm->timeout_task_id); | ||
421 | GNUNET_SCHEDULER_cancel (cm->timeout_task_id); | ||
422 | GNUNET_CONTAINER_DLL_remove (h->control_sent_head, | ||
423 | h->control_sent_tail, | ||
424 | cm); | ||
425 | if (GNUNET_YES == fail) | ||
426 | { | ||
427 | reconnect_arm_later (h); | ||
428 | GNUNET_free (cm->msg); | ||
429 | GNUNET_free (cm); | ||
430 | return; | 276 | return; |
431 | } | 277 | } |
432 | if ( (GNUNET_MESSAGE_TYPE_ARM_RESULT == ntohs (msg->type)) && | 278 | |
433 | (0 == strcasecmp ((const char *) &cm->msg[1], | 279 | result = (enum GNUNET_ARM_Result) ntohl (res->result); |
434 | "arm")) && | 280 | if ( (GNUNET_YES == op->is_arm_stop) && |
435 | (NULL != (res = (const struct GNUNET_ARM_ResultMessage *) msg)) && | 281 | (GNUNET_ARM_RESULT_STOPPING == result) ) |
436 | (GNUNET_ARM_RESULT_STOPPING == ntohl (res->result)) ) | ||
437 | { | 282 | { |
438 | /* special case: if we are stopping 'gnunet-service-arm', we do not just | 283 | /* special case: if we are stopping 'gnunet-service-arm', we do not just |
439 | wait for the result message, but also wait for the service to close | 284 | wait for the result message, but also wait for the service to close |
@@ -443,184 +288,159 @@ client_notify_handler (void *cls, | |||
443 | if (NULL != h->thm) | 288 | if (NULL != h->thm) |
444 | { | 289 | { |
445 | GNUNET_break (0); | 290 | GNUNET_break (0); |
446 | cm->result_cont (h->thm->cont_cls, | 291 | op->result_cont (h->thm->cont_cls, |
447 | GNUNET_ARM_REQUEST_SENT_OK, | 292 | GNUNET_ARM_REQUEST_SENT_OK, |
448 | (const char *) &h->thm->msg[1], | ||
449 | GNUNET_ARM_RESULT_IS_NOT_KNOWN); | 293 | GNUNET_ARM_RESULT_IS_NOT_KNOWN); |
450 | GNUNET_free (h->thm->msg); | ||
451 | GNUNET_free (h->thm); | 294 | GNUNET_free (h->thm); |
452 | } | 295 | } |
453 | h->thm = cm; | 296 | GNUNET_CONTAINER_DLL_remove (h->operation_pending_head, |
454 | GNUNET_CLIENT_receive (h->client, | 297 | h->operation_pending_tail, |
455 | &arm_termination_handler, | 298 | op); |
456 | h, | 299 | h->thm = op; |
457 | GNUNET_TIME_UNIT_FOREVER_REL); | ||
458 | return; | 300 | return; |
459 | } | 301 | } |
460 | GNUNET_CLIENT_receive (h->client, | 302 | result_cont = op->result_cont; |
461 | &client_notify_handler, | 303 | result_cont_cls = op->cont_cls; |
462 | h, | 304 | GNUNET_ARM_operation_cancel (op); |
463 | GNUNET_TIME_UNIT_FOREVER_REL); | 305 | if (NULL != result_cont) |
464 | switch (ntohs (msg->type)) | 306 | result_cont (result_cont_cls, |
465 | { | 307 | GNUNET_ARM_REQUEST_SENT_OK, |
466 | case GNUNET_MESSAGE_TYPE_ARM_RESULT: | 308 | result); |
467 | res = (const struct GNUNET_ARM_ResultMessage *) msg; | ||
468 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
469 | "Received response from ARM for service `%s': %u\n", | ||
470 | (const char *) &cm->msg[1], ntohs (msg->type)); | ||
471 | result = (enum GNUNET_ARM_Result) ntohl (res->result); | ||
472 | if (NULL != cm->result_cont) | ||
473 | cm->result_cont (cm->cont_cls, | ||
474 | GNUNET_ARM_REQUEST_SENT_OK, | ||
475 | (const char *) &cm->msg[1], | ||
476 | result); | ||
477 | break; | ||
478 | case GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT: | ||
479 | if (NULL != cm->list_cont) | ||
480 | cm->list_cont (cm->cont_cls, | ||
481 | GNUNET_ARM_REQUEST_SENT_OK, | ||
482 | rcount, | ||
483 | list); | ||
484 | GNUNET_free_non_null (list); | ||
485 | break; | ||
486 | } | ||
487 | GNUNET_free (cm->msg); | ||
488 | GNUNET_free (cm); | ||
489 | } | 309 | } |
490 | 310 | ||
491 | 311 | ||
492 | /** | 312 | /** |
493 | * Transmit the next message to the arm service. | 313 | * Checked that list result message is well-formed. |
494 | * | 314 | * |
495 | * @param cls closure with the `struct GNUNET_ARM_Handle` | 315 | * @param cls our `struct GNUNET_ARM_Handle` |
496 | * @param size number of bytes available in @a buf | 316 | * @param lres the message received from the arm service |
497 | * @param buf where the callee should write the message | 317 | * @return #GNUNET_OK if message is well-formed |
498 | * @return number of bytes written to @a buf | ||
499 | */ | 318 | */ |
500 | static size_t | 319 | static int |
501 | transmit_arm_message (void *cls, | 320 | check_arm_list_result (void *cls, |
502 | size_t size, | 321 | const struct GNUNET_ARM_ListResultMessage *lres) |
503 | void *buf) | ||
504 | { | 322 | { |
505 | struct GNUNET_ARM_Handle *h = cls; | 323 | const char *pos = (const char *) &lres[1]; |
506 | struct ARMControlMessage *cm; | 324 | uint16_t rcount = ntohs (lres->count); |
507 | struct GNUNET_ARM_Message *arm_msg; | 325 | uint16_t msize = ntohs (lres->arm_msg.header.size); |
508 | uint64_t request_id; | 326 | uint16_t size_check; |
509 | int notify_connection; | ||
510 | uint16_t msize; | ||
511 | 327 | ||
512 | notify_connection = GNUNET_NO; | 328 | size_check = 0; |
513 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 329 | for (unsigned int i = 0; i < rcount; i++) |
514 | "transmit_arm_message is running with %p buffer of size %lu. ARM is known to be %s\n", | ||
515 | buf, size, h->currently_down ? "unconnected" : "connected"); | ||
516 | GNUNET_assert (NULL == h->reconnect_task); | ||
517 | h->cth = NULL; | ||
518 | if ((GNUNET_YES == h->currently_down) && (NULL != buf)) | ||
519 | { | ||
520 | h->currently_down = GNUNET_NO; | ||
521 | notify_connection = GNUNET_YES; | ||
522 | h->retry_backoff = GNUNET_TIME_UNIT_MILLISECONDS; | ||
523 | GNUNET_CLIENT_receive (h->client, &client_notify_handler, h, | ||
524 | GNUNET_TIME_UNIT_FOREVER_REL); | ||
525 | } | ||
526 | if (NULL == buf) | ||
527 | { | 330 | { |
528 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 331 | const char *end = memchr (pos, 0, msize - size_check); |
529 | "Transmission failed, initiating reconnect\n"); | 332 | if (NULL == end) |
530 | reconnect_arm_later (h); | 333 | { |
531 | return 0; | 334 | GNUNET_break (0); |
532 | } | 335 | return GNUNET_SYSERR; |
533 | if (NULL == (cm = h->control_pending_head)) | 336 | } |
534 | { | 337 | size_check += (end - pos) + 1; |
535 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 338 | pos = end + 1; |
536 | "Queue is empty, not sending anything\n"); | ||
537 | msize = 0; | ||
538 | goto end; | ||
539 | } | ||
540 | GNUNET_assert (NULL != cm->msg); | ||
541 | msize = ntohs (cm->msg->header.size); | ||
542 | if (size < msize) | ||
543 | { | ||
544 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
545 | "Request is too big (%u < %u), not sending it\n", size, msize); | ||
546 | trigger_next_request (h, GNUNET_NO); | ||
547 | msize = 0; | ||
548 | goto end; | ||
549 | } | 339 | } |
550 | arm_msg = cm->msg; | 340 | return GNUNET_OK; |
551 | if (0 == h->request_id_counter) | ||
552 | h->request_id_counter++; | ||
553 | request_id = h->request_id_counter++; | ||
554 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
555 | "Transmitting control message with %u bytes of type %u to arm with id %llu\n", | ||
556 | (unsigned int) msize, | ||
557 | (unsigned int) ntohs (cm->msg->header.type), | ||
558 | request_id); | ||
559 | arm_msg->reserved = htonl (0); | ||
560 | arm_msg->request_id = GNUNET_htonll (request_id); | ||
561 | memcpy (buf, cm->msg, msize); | ||
562 | /* Otherwise we won't be able to find it later! */ | ||
563 | arm_msg->request_id = request_id; | ||
564 | GNUNET_CONTAINER_DLL_remove (h->control_pending_head, | ||
565 | h->control_pending_tail, | ||
566 | cm); | ||
567 | GNUNET_CONTAINER_DLL_insert_tail (h->control_sent_head, | ||
568 | h->control_sent_tail, | ||
569 | cm); | ||
570 | /* Don't free msg, keep it around (kind of wasteful, but then we don't | ||
571 | * really have many messages to handle, and it'll be freed when it times | ||
572 | * out anyway. | ||
573 | */ | ||
574 | trigger_next_request (h, GNUNET_NO); | ||
575 | |||
576 | end: | ||
577 | if ((GNUNET_YES == notify_connection) && (NULL != h->conn_status)) | ||
578 | h->conn_status (h->conn_status_cls, GNUNET_YES); | ||
579 | return msize; | ||
580 | } | 341 | } |
581 | 342 | ||
582 | 343 | ||
583 | /** | 344 | /** |
584 | * Check the list of pending requests, send the next | 345 | * Handler for ARM list replies. |
585 | * one to the arm. | ||
586 | * | 346 | * |
587 | * @param h arm handle | 347 | * @param cls our `struct GNUNET_ARM_Handle` |
588 | * @param ignore_currently_down transmit message even if not initialized? | 348 | * @param lres the message received from the arm service |
589 | */ | 349 | */ |
590 | static void | 350 | static void |
591 | trigger_next_request (struct GNUNET_ARM_Handle *h, | 351 | handle_arm_list_result (void *cls, |
592 | int ignore_currently_down) | 352 | const struct GNUNET_ARM_ListResultMessage *lres) |
593 | { | 353 | { |
594 | uint16_t msize; | 354 | struct GNUNET_ARM_Handle *h = cls; |
355 | uint16_t rcount = ntohs (lres->count); | ||
356 | const char *list[rcount]; | ||
357 | const char *pos = (const char *) &lres[1]; | ||
358 | uint16_t msize = ntohs (lres->arm_msg.header.size); | ||
359 | struct GNUNET_ARM_Operation *op; | ||
360 | uint16_t size_check; | ||
361 | uint64_t id; | ||
595 | 362 | ||
596 | msize = sizeof (struct GNUNET_MessageHeader); | 363 | id = GNUNET_ntohll (lres->arm_msg.request_id); |
597 | if ((GNUNET_YES == h->currently_down) && (ignore_currently_down == GNUNET_NO)) | 364 | op = find_op_by_id (h, |
365 | id); | ||
366 | if (NULL == op) | ||
598 | { | 367 | { |
599 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 368 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
600 | "ARM connection down, not processing queue\n"); | 369 | "Message with unknown id %llu\n", |
370 | (unsigned long long) id); | ||
601 | return; | 371 | return; |
602 | } | 372 | } |
603 | if (NULL != h->cth) | 373 | size_check = 0; |
374 | for (unsigned int i = 0; i < rcount; i++) | ||
375 | { | ||
376 | const char *end = memchr (pos, | ||
377 | 0, | ||
378 | msize - size_check); | ||
379 | |||
380 | /* Assert, as this was already checked in #check_arm_list_result() */ | ||
381 | GNUNET_assert (NULL != end); | ||
382 | list[i] = pos; | ||
383 | size_check += (end - pos) + 1; | ||
384 | pos = end + 1; | ||
385 | } | ||
386 | if (NULL != op->list_cont) | ||
387 | op->list_cont (op->cont_cls, | ||
388 | GNUNET_ARM_REQUEST_SENT_OK, | ||
389 | rcount, | ||
390 | list); | ||
391 | GNUNET_ARM_operation_cancel (op); | ||
392 | } | ||
393 | |||
394 | |||
395 | /** | ||
396 | * Receive confirmation from test, ARM service is up. | ||
397 | * | ||
398 | * @param cls closure with the `struct GNUNET_ARM_Handle` | ||
399 | * @param msg message received | ||
400 | */ | ||
401 | static void | ||
402 | handle_confirm (void *cls, | ||
403 | const struct GNUNET_MessageHeader *msg) | ||
404 | { | ||
405 | struct GNUNET_ARM_Handle *h = cls; | ||
406 | |||
407 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
408 | "Got confirmation from ARM that we are up!\n"); | ||
409 | if (GNUNET_NO == h->currently_up) | ||
604 | { | 410 | { |
605 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 411 | h->currently_up = GNUNET_YES; |
606 | "Request pending, not processing queue\n"); | 412 | if (NULL != h->conn_status) |
607 | return; | 413 | h->conn_status (h->conn_status_cls, |
414 | GNUNET_YES); | ||
608 | } | 415 | } |
609 | if (NULL != h->control_pending_head) | 416 | } |
610 | msize = | 417 | |
611 | ntohs (h->control_pending_head->msg->header.size); | 418 | |
612 | else if (GNUNET_NO == ignore_currently_down) | 419 | /** |
420 | * Generic error handler, called with the appropriate error code and | ||
421 | * the same closure specified at the creation of the message queue. | ||
422 | * Not every message queue implementation supports an error handler. | ||
423 | * | ||
424 | * @param cls closure with the `struct GNUNET_ARM_Handle *` | ||
425 | * @param error error code | ||
426 | */ | ||
427 | static void | ||
428 | mq_error_handler (void *cls, | ||
429 | enum GNUNET_MQ_Error error) | ||
430 | { | ||
431 | struct GNUNET_ARM_Handle *h = cls; | ||
432 | struct GNUNET_ARM_Operation *op; | ||
433 | |||
434 | h->currently_up = GNUNET_NO; | ||
435 | if (NULL != (op = h->thm)) | ||
613 | { | 436 | { |
614 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 437 | h->thm = NULL; |
615 | "Request queue empty, not processing queue\n"); | 438 | op->result_cont (op->cont_cls, |
616 | return; /* no pending message */ | 439 | GNUNET_ARM_REQUEST_SENT_OK, |
440 | GNUNET_ARM_RESULT_STOPPED); | ||
441 | GNUNET_free (op); | ||
617 | } | 442 | } |
618 | h->cth = | 443 | reconnect_arm_later (h); |
619 | GNUNET_CLIENT_notify_transmit_ready (h->client, | ||
620 | msize, | ||
621 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
622 | GNUNET_NO, | ||
623 | &transmit_arm_message, h); | ||
624 | } | 444 | } |
625 | 445 | ||
626 | 446 | ||
@@ -633,22 +453,47 @@ trigger_next_request (struct GNUNET_ARM_Handle *h, | |||
633 | static int | 453 | static int |
634 | reconnect_arm (struct GNUNET_ARM_Handle *h) | 454 | reconnect_arm (struct GNUNET_ARM_Handle *h) |
635 | { | 455 | { |
636 | GNUNET_assert (NULL == h->client); | 456 | GNUNET_MQ_hd_fixed_size (arm_result, |
637 | GNUNET_assert (GNUNET_YES == h->currently_down); | 457 | GNUNET_MESSAGE_TYPE_ARM_RESULT, |
638 | h->client = GNUNET_CLIENT_connect ("arm", h->cfg); | 458 | struct GNUNET_ARM_ResultMessage); |
639 | if (NULL == h->client) | 459 | GNUNET_MQ_hd_var_size (arm_list_result, |
460 | GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT, | ||
461 | struct GNUNET_ARM_ListResultMessage); | ||
462 | GNUNET_MQ_hd_fixed_size (confirm, | ||
463 | GNUNET_MESSAGE_TYPE_TEST, | ||
464 | struct GNUNET_MessageHeader); | ||
465 | struct GNUNET_MQ_MessageHandler handlers[] = { | ||
466 | make_arm_result_handler (h), | ||
467 | make_arm_list_result_handler (h), | ||
468 | make_confirm_handler (h), | ||
469 | GNUNET_MQ_handler_end () | ||
470 | }; | ||
471 | struct GNUNET_MessageHeader *test; | ||
472 | struct GNUNET_MQ_Envelope *env; | ||
473 | |||
474 | if (NULL != h->mq) | ||
475 | return GNUNET_OK; | ||
476 | GNUNET_assert (GNUNET_NO == h->currently_up); | ||
477 | h->mq = GNUNET_CLIENT_connecT (h->cfg, | ||
478 | "arm", | ||
479 | handlers, | ||
480 | &mq_error_handler, | ||
481 | h); | ||
482 | if (NULL == h->mq) | ||
640 | { | 483 | { |
641 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 484 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
642 | "arm_api, GNUNET_CLIENT_connect returned NULL\n"); | 485 | "GNUNET_CLIENT_connect returned NULL\n"); |
643 | if (NULL != h->conn_status) | 486 | if (NULL != h->conn_status) |
644 | h->conn_status (h->conn_status_cls, | 487 | h->conn_status (h->conn_status_cls, |
645 | GNUNET_SYSERR); | 488 | GNUNET_SYSERR); |
646 | return GNUNET_SYSERR; | 489 | return GNUNET_SYSERR; |
647 | } | 490 | } |
648 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 491 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
649 | "arm_api, GNUNET_CLIENT_connect returned non-NULL\n"); | 492 | "Sending TEST message to ARM\n"); |
650 | trigger_next_request (h, | 493 | env = GNUNET_MQ_msg (test, |
651 | GNUNET_YES); | 494 | GNUNET_MESSAGE_TYPE_TEST); |
495 | GNUNET_MQ_send (h->mq, | ||
496 | env); | ||
652 | return GNUNET_OK; | 497 | return GNUNET_OK; |
653 | } | 498 | } |
654 | 499 | ||
@@ -661,22 +506,20 @@ reconnect_arm (struct GNUNET_ARM_Handle *h) | |||
661 | * the ARM service may internally use a different | 506 | * the ARM service may internally use a different |
662 | * configuration to determine how to start the service). | 507 | * configuration to determine how to start the service). |
663 | * @param conn_status will be called when connecting/disconnecting | 508 | * @param conn_status will be called when connecting/disconnecting |
664 | * @param cls closure for conn_status | 509 | * @param conn_status_cls closure for @a conn_status |
665 | * @return context to use for further ARM operations, NULL on error. | 510 | * @return context to use for further ARM operations, NULL on error. |
666 | */ | 511 | */ |
667 | struct GNUNET_ARM_Handle * | 512 | struct GNUNET_ARM_Handle * |
668 | GNUNET_ARM_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, | 513 | GNUNET_ARM_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, |
669 | GNUNET_ARM_ConnectionStatusCallback conn_status, | 514 | GNUNET_ARM_ConnectionStatusCallback conn_status, |
670 | void *cls) | 515 | void *conn_status_cls) |
671 | { | 516 | { |
672 | struct GNUNET_ARM_Handle *h; | 517 | struct GNUNET_ARM_Handle *h; |
673 | 518 | ||
674 | h = GNUNET_new (struct GNUNET_ARM_Handle); | 519 | h = GNUNET_new (struct GNUNET_ARM_Handle); |
675 | h->cfg = GNUNET_CONFIGURATION_dup (cfg); | 520 | h->cfg = cfg; |
676 | h->currently_down = GNUNET_YES; | ||
677 | h->reconnect_task = NULL; | ||
678 | h->conn_status = conn_status; | 521 | h->conn_status = conn_status; |
679 | h->conn_status_cls = cls; | 522 | h->conn_status_cls = conn_status_cls; |
680 | if (GNUNET_OK != reconnect_arm (h)) | 523 | if (GNUNET_OK != reconnect_arm (h)) |
681 | { | 524 | { |
682 | GNUNET_free (h); | 525 | GNUNET_free (h); |
@@ -692,113 +535,60 @@ GNUNET_ARM_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, | |||
692 | * @param h the handle that was being used | 535 | * @param h the handle that was being used |
693 | */ | 536 | */ |
694 | void | 537 | void |
695 | GNUNET_ARM_disconnect_and_free (struct GNUNET_ARM_Handle *h) | 538 | GNUNET_ARM_disconnect (struct GNUNET_ARM_Handle *h) |
696 | { | 539 | { |
697 | struct ARMControlMessage *cm; | 540 | struct GNUNET_ARM_Operation *op; |
698 | 541 | ||
699 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 542 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
700 | "Disconnecting from ARM service\n"); | 543 | "Disconnecting from ARM service\n"); |
701 | if (NULL != h->cth) | 544 | while (NULL != (op = h->operation_pending_head)) |
702 | { | 545 | { |
703 | GNUNET_CLIENT_notify_transmit_ready_cancel (h->cth); | 546 | GNUNET_CONTAINER_DLL_remove (h->operation_pending_head, |
704 | h->cth = NULL; | 547 | h->operation_pending_tail, |
705 | } | 548 | op); |
706 | while ((NULL != (cm = h->control_pending_head)) | 549 | if (NULL != op->result_cont) |
707 | || (NULL != (cm = h->control_sent_head)) ) | 550 | op->result_cont (op->cont_cls, |
708 | { | ||
709 | if (NULL != h->control_pending_head) | ||
710 | GNUNET_CONTAINER_DLL_remove (h->control_pending_head, | ||
711 | h->control_pending_tail, | ||
712 | cm); | ||
713 | else | ||
714 | GNUNET_CONTAINER_DLL_remove (h->control_sent_head, | ||
715 | h->control_sent_tail, | ||
716 | cm); | ||
717 | GNUNET_assert (NULL != cm->timeout_task_id); | ||
718 | GNUNET_SCHEDULER_cancel (cm->timeout_task_id); | ||
719 | if (NULL != cm->result_cont) | ||
720 | cm->result_cont (cm->cont_cls, | ||
721 | GNUNET_ARM_REQUEST_DISCONNECTED, | 551 | GNUNET_ARM_REQUEST_DISCONNECTED, |
722 | NULL, | ||
723 | 0); | 552 | 0); |
724 | /* FIXME: What about list callback? */ | 553 | if (NULL != op->list_cont) |
725 | GNUNET_free_non_null (cm->msg); | 554 | op->list_cont (op->cont_cls, |
726 | GNUNET_free (cm); | 555 | GNUNET_ARM_REQUEST_DISCONNECTED, |
556 | 0, | ||
557 | NULL); | ||
558 | if (NULL != op->async) | ||
559 | { | ||
560 | GNUNET_SCHEDULER_cancel (op->async); | ||
561 | op->async = NULL; | ||
562 | } | ||
563 | GNUNET_free (op); | ||
727 | } | 564 | } |
728 | if (NULL != h->client) | 565 | if (NULL != h->mq) |
729 | { | 566 | { |
730 | GNUNET_CLIENT_disconnect (h->client); | 567 | GNUNET_MQ_destroy (h->mq); |
731 | h->client = NULL; | 568 | h->mq = NULL; |
732 | } | 569 | } |
733 | if (NULL != h->reconnect_task) | 570 | if (NULL != h->reconnect_task) |
734 | { | 571 | { |
735 | GNUNET_SCHEDULER_cancel (h->reconnect_task); | 572 | GNUNET_SCHEDULER_cancel (h->reconnect_task); |
736 | h->reconnect_task = NULL; | 573 | h->reconnect_task = NULL; |
737 | } | 574 | } |
738 | if (GNUNET_NO == h->service_test_is_active) | 575 | GNUNET_free (h); |
739 | { | ||
740 | GNUNET_CONFIGURATION_destroy (h->cfg); | ||
741 | GNUNET_free (h); | ||
742 | } | ||
743 | } | ||
744 | |||
745 | |||
746 | /** | ||
747 | * Message timed out. Remove it from the queue. | ||
748 | * | ||
749 | * @param cls the message (struct ARMControlMessage *) | ||
750 | */ | ||
751 | static void | ||
752 | control_message_timeout (void *cls) | ||
753 | { | ||
754 | struct ARMControlMessage *cm = cls; | ||
755 | struct GNUNET_ARM_Message *arm_msg; | ||
756 | |||
757 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
758 | "Control message timed out\n"); | ||
759 | arm_msg = cm->msg; | ||
760 | if ((NULL == arm_msg) || (0 == arm_msg->request_id)) | ||
761 | { | ||
762 | GNUNET_CONTAINER_DLL_remove (cm->h->control_pending_head, | ||
763 | cm->h->control_pending_tail, | ||
764 | cm); | ||
765 | } | ||
766 | else | ||
767 | { | ||
768 | GNUNET_CONTAINER_DLL_remove (cm->h->control_sent_head, | ||
769 | cm->h->control_sent_tail, | ||
770 | cm); | ||
771 | } | ||
772 | if (NULL != cm->result_cont) | ||
773 | cm->result_cont (cm->cont_cls, | ||
774 | GNUNET_ARM_REQUEST_TIMEOUT, | ||
775 | NULL, 0); | ||
776 | else if (NULL != cm->list_cont) | ||
777 | cm->list_cont (cm->cont_cls, | ||
778 | GNUNET_ARM_REQUEST_TIMEOUT, | ||
779 | 0, NULL); | ||
780 | GNUNET_free_non_null (cm->msg); | ||
781 | GNUNET_free (cm); | ||
782 | } | 576 | } |
783 | 577 | ||
784 | 578 | ||
785 | /** | 579 | /** |
786 | * A client specifically requested starting of ARM itself. | 580 | * A client specifically requested starting of ARM itself. |
787 | * This function is called with information about whether | 581 | * Starts the ARM service. |
788 | * or not ARM is running; if it is, report success. If | ||
789 | * it is not, start the ARM process. | ||
790 | * | 582 | * |
791 | * @param cls the context for the request that we will report on (struct ARMControlMessage *) | 583 | * @param h the handle with configuration details |
792 | * @param result #GNUNET_YES if ARM is running | 584 | * @param std_inheritance inheritance of std streams |
585 | * @return operation status code | ||
793 | */ | 586 | */ |
794 | static void | 587 | static enum GNUNET_ARM_Result |
795 | arm_service_report (void *cls, | 588 | start_arm_service (struct GNUNET_ARM_Handle *h, |
796 | int result) | 589 | enum GNUNET_OS_InheritStdioFlags std_inheritance) |
797 | { | 590 | { |
798 | struct ARMControlMessage *cm = cls; | ||
799 | struct GNUNET_ARM_Handle *h; | ||
800 | struct GNUNET_OS_Process *proc; | 591 | struct GNUNET_OS_Process *proc; |
801 | unsigned char test_is_active; | ||
802 | char *cbinary; | 592 | char *cbinary; |
803 | char *binary; | 593 | char *binary; |
804 | char *quotedbinary; | 594 | char *quotedbinary; |
@@ -806,51 +596,20 @@ arm_service_report (void *cls, | |||
806 | char *loprefix; | 596 | char *loprefix; |
807 | char *lopostfix; | 597 | char *lopostfix; |
808 | 598 | ||
809 | test_is_active = cm->h->service_test_is_active; | ||
810 | if ((GNUNET_YES == test_is_active) && | ||
811 | (GNUNET_YES == result)) | ||
812 | { | ||
813 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
814 | "Looks like `%s' is already running.\n", | ||
815 | "gnunet-service-arm"); | ||
816 | /* arm is running! */ | ||
817 | if (cm->result_cont) | ||
818 | cm->result_cont (cm->cont_cls, | ||
819 | GNUNET_ARM_REQUEST_SENT_OK, "arm", | ||
820 | GNUNET_ARM_RESULT_IS_STARTED_ALREADY); | ||
821 | } | ||
822 | if (GNUNET_NO == test_is_active) | ||
823 | { | ||
824 | /* User disconnected & destroyed ARM handle in the middle of | ||
825 | * the service test, so we kept the handle around until now. | ||
826 | */ | ||
827 | GNUNET_CONFIGURATION_destroy (cm->h->cfg); | ||
828 | GNUNET_free (cm->h); | ||
829 | } | ||
830 | if ((GNUNET_YES == result) || | ||
831 | (GNUNET_NO == test_is_active)) | ||
832 | { | ||
833 | GNUNET_free (cm); | ||
834 | return; | ||
835 | } | ||
836 | cm->h->service_test_is_active = GNUNET_NO; | ||
837 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
838 | "Looks like `%s' is not running, will start it.\n", | ||
839 | "gnunet-service-arm"); | ||
840 | if (GNUNET_OK != | 599 | if (GNUNET_OK != |
841 | GNUNET_CONFIGURATION_get_value_string (cm->h->cfg, | 600 | GNUNET_CONFIGURATION_get_value_string (h->cfg, |
842 | "arm", | 601 | "arm", |
843 | "PREFIX", | 602 | "PREFIX", |
844 | &loprefix)) | 603 | &loprefix)) |
845 | loprefix = GNUNET_strdup (""); | 604 | loprefix = GNUNET_strdup (""); |
846 | if (GNUNET_OK != | 605 | if (GNUNET_OK != |
847 | GNUNET_CONFIGURATION_get_value_string (cm->h->cfg, | 606 | GNUNET_CONFIGURATION_get_value_string (h->cfg, |
848 | "arm", | 607 | "arm", |
849 | "OPTIONS", | 608 | "OPTIONS", |
850 | &lopostfix)) | 609 | &lopostfix)) |
851 | lopostfix = GNUNET_strdup (""); | 610 | lopostfix = GNUNET_strdup (""); |
852 | if (GNUNET_OK != | 611 | if (GNUNET_OK != |
853 | GNUNET_CONFIGURATION_get_value_string (cm->h->cfg, | 612 | GNUNET_CONFIGURATION_get_value_string (h->cfg, |
854 | "arm", | 613 | "arm", |
855 | "BINARY", | 614 | "BINARY", |
856 | &cbinary)) | 615 | &cbinary)) |
@@ -858,18 +617,14 @@ arm_service_report (void *cls, | |||
858 | GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, | 617 | GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING, |
859 | "arm", | 618 | "arm", |
860 | "BINARY"); | 619 | "BINARY"); |
861 | if (cm->result_cont) | ||
862 | cm->result_cont (cm->cont_cls, | ||
863 | GNUNET_ARM_REQUEST_SENT_OK, "arm", | ||
864 | GNUNET_ARM_RESULT_IS_NOT_KNOWN); | ||
865 | GNUNET_free (cm); | ||
866 | GNUNET_free (loprefix); | 620 | GNUNET_free (loprefix); |
867 | GNUNET_free (lopostfix); | 621 | GNUNET_free (lopostfix); |
868 | return; | 622 | return GNUNET_ARM_RESULT_IS_NOT_KNOWN; |
869 | } | 623 | } |
870 | if (GNUNET_OK != | 624 | if (GNUNET_OK != |
871 | GNUNET_CONFIGURATION_get_value_filename (cm->h->cfg, | 625 | GNUNET_CONFIGURATION_get_value_filename (h->cfg, |
872 | "arm", "CONFIG", | 626 | "arm", |
627 | "CONFIG", | ||
873 | &config)) | 628 | &config)) |
874 | config = NULL; | 629 | config = NULL; |
875 | binary = GNUNET_OS_get_libexec_binary_path (cbinary); | 630 | binary = GNUNET_OS_get_libexec_binary_path (cbinary); |
@@ -878,15 +633,15 @@ arm_service_report (void *cls, | |||
878 | binary); | 633 | binary); |
879 | GNUNET_free (cbinary); | 634 | GNUNET_free (cbinary); |
880 | if ( (GNUNET_YES == | 635 | if ( (GNUNET_YES == |
881 | GNUNET_CONFIGURATION_have_value (cm->h->cfg, | 636 | GNUNET_CONFIGURATION_have_value (h->cfg, |
882 | "TESTING", | 637 | "TESTING", |
883 | "WEAKRANDOM")) && | 638 | "WEAKRANDOM")) && |
884 | (GNUNET_YES == | 639 | (GNUNET_YES == |
885 | GNUNET_CONFIGURATION_get_value_yesno (cm->h->cfg, | 640 | GNUNET_CONFIGURATION_get_value_yesno (h->cfg, |
886 | "TESTING", | 641 | "TESTING", |
887 | "WEAKRANDOM")) && | 642 | "WEAKRANDOM")) && |
888 | (GNUNET_NO == | 643 | (GNUNET_NO == |
889 | GNUNET_CONFIGURATION_have_value (cm->h->cfg, | 644 | GNUNET_CONFIGURATION_have_value (h->cfg, |
890 | "TESTING", | 645 | "TESTING", |
891 | "HOSTFILE"))) | 646 | "HOSTFILE"))) |
892 | { | 647 | { |
@@ -894,39 +649,43 @@ arm_service_report (void *cls, | |||
894 | /* we're clearly running a test, don't daemonize */ | 649 | /* we're clearly running a test, don't daemonize */ |
895 | if (NULL == config) | 650 | if (NULL == config) |
896 | proc = GNUNET_OS_start_process_s (GNUNET_NO, | 651 | proc = GNUNET_OS_start_process_s (GNUNET_NO, |
897 | cm->std_inheritance, | 652 | std_inheritance, |
898 | NULL, | 653 | NULL, |
899 | loprefix, | 654 | loprefix, |
900 | quotedbinary, | 655 | quotedbinary, |
901 | /* no daemonization! */ | 656 | /* no daemonization! */ |
902 | lopostfix, NULL); | 657 | lopostfix, |
658 | NULL); | ||
903 | else | 659 | else |
904 | proc = GNUNET_OS_start_process_s (GNUNET_NO, | 660 | proc = GNUNET_OS_start_process_s (GNUNET_NO, |
905 | cm->std_inheritance, | 661 | std_inheritance, |
906 | NULL, | 662 | NULL, |
907 | loprefix, | 663 | loprefix, |
908 | quotedbinary, | 664 | quotedbinary, |
909 | "-c", config, | 665 | "-c", config, |
910 | /* no daemonization! */ | 666 | /* no daemonization! */ |
911 | lopostfix, NULL); | 667 | lopostfix, |
668 | NULL); | ||
912 | } | 669 | } |
913 | else | 670 | else |
914 | { | 671 | { |
915 | if (NULL == config) | 672 | if (NULL == config) |
916 | proc = GNUNET_OS_start_process_s (GNUNET_NO, | 673 | proc = GNUNET_OS_start_process_s (GNUNET_NO, |
917 | cm->std_inheritance, | 674 | std_inheritance, |
918 | NULL, | 675 | NULL, |
919 | loprefix, | 676 | loprefix, |
920 | quotedbinary, | 677 | quotedbinary, |
921 | "-d", lopostfix, NULL); | 678 | "-d", /* do daemonize */ |
679 | lopostfix, NULL); | ||
922 | else | 680 | else |
923 | proc = GNUNET_OS_start_process_s (GNUNET_NO, | 681 | proc = GNUNET_OS_start_process_s (GNUNET_NO, |
924 | cm->std_inheritance, | 682 | std_inheritance, |
925 | NULL, | 683 | NULL, |
926 | loprefix, | 684 | loprefix, |
927 | quotedbinary, | 685 | quotedbinary, |
928 | "-c", config, | 686 | "-c", config, |
929 | "-d", lopostfix, | 687 | "-d", /* do daemonize */ |
688 | lopostfix, | ||
930 | NULL); | 689 | NULL); |
931 | } | 690 | } |
932 | GNUNET_free (binary); | 691 | GNUNET_free (binary); |
@@ -935,22 +694,32 @@ arm_service_report (void *cls, | |||
935 | GNUNET_free (loprefix); | 694 | GNUNET_free (loprefix); |
936 | GNUNET_free (lopostfix); | 695 | GNUNET_free (lopostfix); |
937 | if (NULL == proc) | 696 | if (NULL == proc) |
697 | return GNUNET_ARM_RESULT_START_FAILED; | ||
698 | GNUNET_OS_process_destroy (proc); | ||
699 | return GNUNET_ARM_RESULT_STARTING; | ||
700 | } | ||
701 | |||
702 | |||
703 | /** | ||
704 | * Abort an operation. Only prevents the callback from being | ||
705 | * called, the operation may still complete. | ||
706 | * | ||
707 | * @param op operation to cancel | ||
708 | */ | ||
709 | void | ||
710 | GNUNET_ARM_operation_cancel (struct GNUNET_ARM_Operation *op) | ||
711 | { | ||
712 | struct GNUNET_ARM_Handle *h = op->h; | ||
713 | |||
714 | if (h->thm == op) | ||
938 | { | 715 | { |
939 | if (cm->result_cont) | 716 | op->result_cont = NULL; |
940 | cm->result_cont (cm->cont_cls, | ||
941 | GNUNET_ARM_REQUEST_SENT_OK, "arm", | ||
942 | GNUNET_ARM_RESULT_START_FAILED); | ||
943 | GNUNET_free (cm); | ||
944 | return; | 717 | return; |
945 | } | 718 | } |
946 | if (cm->result_cont) | 719 | GNUNET_CONTAINER_DLL_remove (h->operation_pending_head, |
947 | cm->result_cont (cm->cont_cls, | 720 | h->operation_pending_tail, |
948 | GNUNET_ARM_REQUEST_SENT_OK, "arm", | 721 | op); |
949 | GNUNET_ARM_RESULT_STARTING); | 722 | GNUNET_free (op); |
950 | GNUNET_OS_process_destroy (proc); | ||
951 | h = cm->h; | ||
952 | GNUNET_free (cm); | ||
953 | reconnect_arm (h); | ||
954 | } | 723 | } |
955 | 724 | ||
956 | 725 | ||
@@ -959,21 +728,21 @@ arm_service_report (void *cls, | |||
959 | * | 728 | * |
960 | * @param h handle to ARM | 729 | * @param h handle to ARM |
961 | * @param service_name name of the service | 730 | * @param service_name name of the service |
962 | * @param timeout how long to wait before failing for good | ||
963 | * @param cb callback to invoke when service is ready | 731 | * @param cb callback to invoke when service is ready |
964 | * @param cb_cls closure for @a cb | 732 | * @param cb_cls closure for @a cb |
965 | * @param type type of the request | 733 | * @param type type of the request |
734 | * @return handle to queue, NULL on error | ||
966 | */ | 735 | */ |
967 | static void | 736 | static struct GNUNET_ARM_Operation * |
968 | change_service (struct GNUNET_ARM_Handle *h, | 737 | change_service (struct GNUNET_ARM_Handle *h, |
969 | const char *service_name, | 738 | const char *service_name, |
970 | struct GNUNET_TIME_Relative timeout, | ||
971 | GNUNET_ARM_ResultCallback cb, | 739 | GNUNET_ARM_ResultCallback cb, |
972 | void *cb_cls, | 740 | void *cb_cls, |
973 | uint16_t type) | 741 | uint16_t type) |
974 | { | 742 | { |
975 | struct ARMControlMessage *cm; | 743 | struct GNUNET_ARM_Operation *op; |
976 | size_t slen; | 744 | size_t slen; |
745 | struct GNUNET_MQ_Envelope *env; | ||
977 | struct GNUNET_ARM_Message *msg; | 746 | struct GNUNET_ARM_Message *msg; |
978 | 747 | ||
979 | slen = strlen (service_name) + 1; | 748 | slen = strlen (service_name) + 1; |
@@ -981,38 +750,81 @@ change_service (struct GNUNET_ARM_Handle *h, | |||
981 | GNUNET_SERVER_MAX_MESSAGE_SIZE) | 750 | GNUNET_SERVER_MAX_MESSAGE_SIZE) |
982 | { | 751 | { |
983 | GNUNET_break (0); | 752 | GNUNET_break (0); |
984 | if (cb != NULL) | 753 | return NULL; |
985 | cb (cb_cls, GNUNET_ARM_REQUEST_TOO_LONG, NULL, 0); | ||
986 | return; | ||
987 | } | 754 | } |
988 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Requesting %s of service `%s'.\n", | 755 | if (0 == h->request_id_counter) |
989 | (GNUNET_MESSAGE_TYPE_ARM_START == type) ? "start" : "termination", | 756 | h->request_id_counter++; |
990 | service_name); | 757 | op = GNUNET_new (struct GNUNET_ARM_Operation); |
991 | cm = GNUNET_malloc (sizeof (struct ARMControlMessage) + slen); | 758 | op->h = h; |
992 | cm->h = h; | 759 | op->result_cont = cb; |
993 | cm->result_cont = cb; | 760 | op->cont_cls = cb_cls; |
994 | cm->cont_cls = cb_cls; | 761 | op->id = h->request_id_counter++; |
995 | cm->timeout = GNUNET_TIME_relative_to_absolute (timeout); | 762 | GNUNET_CONTAINER_DLL_insert_tail (h->operation_pending_head, |
996 | memcpy (&cm[1], service_name, slen); | 763 | h->operation_pending_tail, |
997 | msg = GNUNET_malloc (sizeof (struct GNUNET_ARM_Message) + slen); | 764 | op); |
998 | msg->header.size = htons (sizeof (struct GNUNET_ARM_Message) + slen); | 765 | env = GNUNET_MQ_msg_extra (msg, |
999 | msg->header.type = htons (type); | 766 | slen, |
767 | type); | ||
1000 | msg->reserved = htonl (0); | 768 | msg->reserved = htonl (0); |
1001 | memcpy (&msg[1], service_name, slen); | 769 | msg->request_id = GNUNET_htonll (op->id); |
1002 | cm->msg = msg; | 770 | memcpy (&msg[1], |
771 | service_name, | ||
772 | slen); | ||
773 | GNUNET_MQ_send (h->mq, | ||
774 | env); | ||
775 | return op; | ||
776 | } | ||
777 | |||
778 | |||
779 | /** | ||
780 | * Task run to notify application that ARM is already up. | ||
781 | * | ||
782 | * @param cls the operation that asked ARM to be started | ||
783 | */ | ||
784 | static void | ||
785 | notify_running (void *cls) | ||
786 | { | ||
787 | struct GNUNET_ARM_Operation *op = cls; | ||
788 | struct GNUNET_ARM_Handle *h = op->h; | ||
789 | |||
790 | op->async = NULL; | ||
791 | GNUNET_CONTAINER_DLL_remove (h->operation_pending_head, | ||
792 | h->operation_pending_tail, | ||
793 | op); | ||
794 | if (NULL != op->result_cont) | ||
795 | op->result_cont (op->cont_cls, | ||
796 | GNUNET_ARM_REQUEST_SENT_OK, | ||
797 | GNUNET_ARM_RESULT_IS_STARTED_ALREADY); | ||
798 | if ( (GNUNET_YES == h->currently_up) && | ||
799 | (NULL != h->conn_status) ) | ||
800 | h->conn_status (h->conn_status_cls, | ||
801 | GNUNET_YES); | ||
802 | GNUNET_free (op); | ||
803 | } | ||
804 | |||
805 | |||
806 | /** | ||
807 | * Task run to notify application that ARM is being started. | ||
808 | * | ||
809 | * @param cls the operation that asked ARM to be started | ||
810 | */ | ||
811 | static void | ||
812 | notify_starting (void *cls) | ||
813 | { | ||
814 | struct GNUNET_ARM_Operation *op = cls; | ||
815 | struct GNUNET_ARM_Handle *h = op->h; | ||
816 | |||
817 | op->async = NULL; | ||
1003 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 818 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1004 | "Inserting a control message into the queue. Timeout is %s\n", | 819 | "Notifying client that we started the ARM service\n"); |
1005 | GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining (cm->timeout), | 820 | GNUNET_CONTAINER_DLL_remove (h->operation_pending_head, |
1006 | GNUNET_NO)); | 821 | h->operation_pending_tail, |
1007 | GNUNET_CONTAINER_DLL_insert_tail (h->control_pending_head, | 822 | op); |
1008 | h->control_pending_tail, | 823 | if (NULL != op->result_cont) |
1009 | cm); | 824 | op->result_cont (op->cont_cls, |
1010 | cm->timeout_task_id = | 825 | GNUNET_ARM_REQUEST_SENT_OK, |
1011 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining | 826 | op->starting_ret); |
1012 | (cm->timeout), | 827 | GNUNET_free (op); |
1013 | &control_message_timeout, | ||
1014 | cm); | ||
1015 | trigger_next_request (h, GNUNET_NO); | ||
1016 | } | 828 | } |
1017 | 829 | ||
1018 | 830 | ||
@@ -1022,132 +834,116 @@ change_service (struct GNUNET_ARM_Handle *h, | |||
1022 | * @param h handle to ARM | 834 | * @param h handle to ARM |
1023 | * @param service_name name of the service | 835 | * @param service_name name of the service |
1024 | * @param std_inheritance inheritance of std streams | 836 | * @param std_inheritance inheritance of std streams |
1025 | * @param timeout how long to wait before failing for good | ||
1026 | * @param cont callback to invoke after request is sent or not sent | 837 | * @param cont callback to invoke after request is sent or not sent |
1027 | * @param cont_cls closure for @a cont | 838 | * @param cont_cls closure for @a cont |
839 | * @return handle for the operation, NULL on error | ||
1028 | */ | 840 | */ |
1029 | void | 841 | struct GNUNET_ARM_Operation * |
1030 | GNUNET_ARM_request_service_start (struct GNUNET_ARM_Handle *h, | 842 | GNUNET_ARM_request_service_start (struct GNUNET_ARM_Handle *h, |
1031 | const char *service_name, | 843 | const char *service_name, |
1032 | enum GNUNET_OS_InheritStdioFlags std_inheritance, | 844 | enum GNUNET_OS_InheritStdioFlags std_inheritance, |
1033 | struct GNUNET_TIME_Relative timeout, | ||
1034 | GNUNET_ARM_ResultCallback cont, | 845 | GNUNET_ARM_ResultCallback cont, |
1035 | void *cont_cls) | 846 | void *cont_cls) |
1036 | { | 847 | { |
1037 | struct ARMControlMessage *cm; | 848 | struct GNUNET_ARM_Operation *op; |
1038 | size_t slen; | 849 | enum GNUNET_ARM_Result ret; |
1039 | 850 | ||
1040 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 851 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1041 | "Asked to start service `%s' within %s\n", service_name, | 852 | "Starting service `%s'\n", |
1042 | GNUNET_STRINGS_relative_time_to_string (timeout, GNUNET_NO)); | 853 | service_name); |
1043 | if (0 == strcasecmp ("arm", service_name)) | 854 | if (0 != strcasecmp ("arm", |
855 | service_name)) | ||
856 | return change_service (h, | ||
857 | service_name, | ||
858 | cont, | ||
859 | cont_cls, | ||
860 | GNUNET_MESSAGE_TYPE_ARM_START); | ||
861 | |||
862 | /* Possible cases: | ||
863 | * 1) We're connected to ARM already. Invoke the callback immediately. | ||
864 | * 2) We're not connected to ARM. | ||
865 | * Cancel any reconnection attempts temporarily, then perform | ||
866 | * a service test. | ||
867 | */ | ||
868 | if (GNUNET_YES == h->currently_up) | ||
1044 | { | 869 | { |
1045 | /* Possible cases: | 870 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1046 | * 1) We're connected to ARM already. Invoke the callback immediately. | 871 | "ARM is already running\n"); |
1047 | * 2) We're not connected to ARM. | 872 | op = GNUNET_new (struct GNUNET_ARM_Operation); |
1048 | * Cancel any reconnection attempts temporarily, then perform | 873 | op->h = h; |
1049 | * a service test. | 874 | op->result_cont = cont; |
1050 | */ | 875 | op->cont_cls = cont_cls; |
1051 | if (GNUNET_NO == h->currently_down) | 876 | GNUNET_CONTAINER_DLL_insert_tail (h->operation_pending_head, |
1052 | { | 877 | h->operation_pending_tail, |
1053 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 878 | op); |
1054 | "ARM is already running\n"); | 879 | op->async = GNUNET_SCHEDULER_add_now (¬ify_running, |
1055 | if (NULL != cont) | 880 | op); |
1056 | cont (cont_cls, | 881 | return op; |
1057 | GNUNET_ARM_REQUEST_SENT_OK, | 882 | } |
1058 | "arm", | 883 | /* This is an inherently uncertain choice, as it is of course |
1059 | GNUNET_ARM_RESULT_IS_STARTED_ALREADY); | 884 | theoretically possible that ARM is up and we just did not |
1060 | } | 885 | yet complete the MQ handshake. However, given that users |
1061 | else if (GNUNET_NO == h->service_test_is_active) | 886 | are unlikely to hammer 'gnunet-arm -s' on a busy system, |
1062 | { | 887 | the above check should catch 99.99% of the cases where ARM |
1063 | if (NULL != h->cth) | 888 | is already running. */ |
1064 | { | 889 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1065 | GNUNET_CLIENT_notify_transmit_ready_cancel (h->cth); | 890 | "Starting ARM service\n"); |
1066 | h->cth = NULL; | 891 | ret = start_arm_service (h, |
1067 | } | 892 | std_inheritance); |
1068 | if (NULL != h->client) | 893 | if (GNUNET_ARM_RESULT_STARTING == ret) |
1069 | { | 894 | reconnect_arm (h); |
1070 | GNUNET_CLIENT_disconnect (h->client); | 895 | op = GNUNET_new (struct GNUNET_ARM_Operation); |
1071 | h->client = NULL; | 896 | op->h = h; |
1072 | } | 897 | op->result_cont = cont; |
1073 | if (NULL != h->reconnect_task) | 898 | op->cont_cls = cont_cls; |
1074 | { | 899 | GNUNET_CONTAINER_DLL_insert_tail (h->operation_pending_head, |
1075 | GNUNET_SCHEDULER_cancel (h->reconnect_task); | 900 | h->operation_pending_tail, |
1076 | h->reconnect_task = NULL; | 901 | op); |
1077 | } | 902 | op->starting_ret = ret; |
1078 | 903 | op->async = GNUNET_SCHEDULER_add_now (¬ify_starting, | |
1079 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 904 | op); |
1080 | "Not connected to ARM, will do a service test\n"); | 905 | return op; |
1081 | |||
1082 | slen = strlen ("arm") + 1; | ||
1083 | cm = GNUNET_malloc (sizeof (struct ARMControlMessage) + slen); | ||
1084 | cm->h = h; | ||
1085 | cm->result_cont = cont; | ||
1086 | cm->cont_cls = cont_cls; | ||
1087 | cm->timeout = GNUNET_TIME_relative_to_absolute (timeout); | ||
1088 | cm->std_inheritance = std_inheritance; | ||
1089 | memcpy (&cm[1], service_name, slen); | ||
1090 | h->service_test_is_active = GNUNET_YES; | ||
1091 | GNUNET_CLIENT_service_test ("arm", | ||
1092 | h->cfg, | ||
1093 | timeout, | ||
1094 | &arm_service_report, | ||
1095 | cm); | ||
1096 | } | ||
1097 | else | ||
1098 | { | ||
1099 | /* Service test is already running - tell user to chill out and try | ||
1100 | * again later. | ||
1101 | */ | ||
1102 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1103 | "Service test is already in progress, we're busy\n"); | ||
1104 | if (NULL != cont) | ||
1105 | cont (cont_cls, | ||
1106 | GNUNET_ARM_REQUEST_BUSY, | ||
1107 | NULL, 0); | ||
1108 | } | ||
1109 | return; | ||
1110 | } | ||
1111 | change_service (h, | ||
1112 | service_name, | ||
1113 | timeout, | ||
1114 | cont, cont_cls, | ||
1115 | GNUNET_MESSAGE_TYPE_ARM_START); | ||
1116 | } | 906 | } |
1117 | 907 | ||
1118 | 908 | ||
1119 | /** | 909 | /** |
1120 | * Request a service to be stopped. | 910 | * Request a service to be stopped. Stopping arm itself will not |
1121 | * Stopping arm itself will not invalidate its handle, and | 911 | * invalidate its handle, and ARM API will try to restore connection |
1122 | * ARM API will try to restore connection to the ARM service, | 912 | * to the ARM service, even if ARM connection was lost because you |
1123 | * even if ARM connection was lost because you asked for ARM to be stopped. | 913 | * asked for ARM to be stopped. Call |
1124 | * Call #GNUNET_ARM_disconnect_and_free() to free the handle and prevent | 914 | * #GNUNET_ARM_disconnect() to free the handle and prevent |
1125 | * further connection attempts. | 915 | * further connection attempts. |
1126 | * | 916 | * |
1127 | * @param h handle to ARM | 917 | * @param h handle to ARM |
1128 | * @param service_name name of the service | 918 | * @param service_name name of the service |
1129 | * @param timeout how long to wait before failing for good | ||
1130 | * @param cont callback to invoke after request is sent or is not sent | 919 | * @param cont callback to invoke after request is sent or is not sent |
1131 | * @param cont_cls closure for @a cont | 920 | * @param cont_cls closure for @a cont |
921 | * @return handle for the operation, NULL on error | ||
1132 | */ | 922 | */ |
1133 | void | 923 | struct GNUNET_ARM_Operation * |
1134 | GNUNET_ARM_request_service_stop (struct GNUNET_ARM_Handle *h, | 924 | GNUNET_ARM_request_service_stop (struct GNUNET_ARM_Handle *h, |
1135 | const char *service_name, | 925 | const char *service_name, |
1136 | struct GNUNET_TIME_Relative timeout, | ||
1137 | GNUNET_ARM_ResultCallback cont, | 926 | GNUNET_ARM_ResultCallback cont, |
1138 | void *cont_cls) | 927 | void *cont_cls) |
1139 | { | 928 | { |
929 | struct GNUNET_ARM_Operation *op; | ||
930 | |||
1140 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 931 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1141 | "Stopping service `%s' within %s\n", | 932 | "Stopping service `%s'\n", |
1142 | service_name, | 933 | service_name); |
1143 | GNUNET_STRINGS_relative_time_to_string (timeout, | 934 | op = change_service (h, |
1144 | GNUNET_NO)); | 935 | service_name, |
1145 | change_service (h, | 936 | cont, |
1146 | service_name, | 937 | cont_cls, |
1147 | timeout, | 938 | GNUNET_MESSAGE_TYPE_ARM_STOP); |
1148 | cont, | 939 | if (NULL == op) |
1149 | cont_cls, | 940 | return NULL; |
1150 | GNUNET_MESSAGE_TYPE_ARM_STOP); | 941 | /* If the service is ARM, set a flag as we will use MQ errors |
942 | to detect that the process is really gone. */ | ||
943 | if (0 == strcasecmp (service_name, | ||
944 | "arm")) | ||
945 | op->is_arm_stop = GNUNET_YES; | ||
946 | return op; | ||
1151 | } | 947 | } |
1152 | 948 | ||
1153 | 949 | ||
@@ -1155,43 +951,38 @@ GNUNET_ARM_request_service_stop (struct GNUNET_ARM_Handle *h, | |||
1155 | * Request a list of running services. | 951 | * Request a list of running services. |
1156 | * | 952 | * |
1157 | * @param h handle to ARM | 953 | * @param h handle to ARM |
1158 | * @param timeout how long to wait before failing for good | ||
1159 | * @param cont callback to invoke after request is sent or is not sent | 954 | * @param cont callback to invoke after request is sent or is not sent |
1160 | * @param cont_cls closure for @a cont | 955 | * @param cont_cls closure for @a cont |
956 | * @return handle for the operation, NULL on error | ||
1161 | */ | 957 | */ |
1162 | void | 958 | struct GNUNET_ARM_Operation * |
1163 | GNUNET_ARM_request_service_list (struct GNUNET_ARM_Handle *h, | 959 | GNUNET_ARM_request_service_list (struct GNUNET_ARM_Handle *h, |
1164 | struct GNUNET_TIME_Relative timeout, | ||
1165 | GNUNET_ARM_ServiceListCallback cont, | 960 | GNUNET_ARM_ServiceListCallback cont, |
1166 | void *cont_cls) | 961 | void *cont_cls) |
1167 | { | 962 | { |
1168 | struct ARMControlMessage *cm; | 963 | struct GNUNET_ARM_Operation *op; |
964 | struct GNUNET_MQ_Envelope *env; | ||
1169 | struct GNUNET_ARM_Message *msg; | 965 | struct GNUNET_ARM_Message *msg; |
1170 | 966 | ||
1171 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 967 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1172 | "Requesting LIST from ARM service with timeout: %s\n", | 968 | "Requesting LIST from ARM service\n"); |
1173 | GNUNET_STRINGS_relative_time_to_string (timeout, | 969 | if (0 == h->request_id_counter) |
1174 | GNUNET_YES)); | 970 | h->request_id_counter++; |
1175 | cm = GNUNET_new (struct ARMControlMessage); | 971 | op = GNUNET_new (struct GNUNET_ARM_Operation); |
1176 | cm->h = h; | 972 | op->h = h; |
1177 | cm->list_cont = cont; | 973 | op->list_cont = cont; |
1178 | cm->cont_cls = cont_cls; | 974 | op->cont_cls = cont_cls; |
1179 | cm->timeout = GNUNET_TIME_relative_to_absolute (timeout); | 975 | op->id = h->request_id_counter++; |
1180 | msg = GNUNET_malloc (sizeof (struct GNUNET_ARM_Message)); | 976 | GNUNET_CONTAINER_DLL_insert_tail (h->operation_pending_head, |
1181 | msg->header.size = htons (sizeof (struct GNUNET_ARM_Message)); | 977 | h->operation_pending_tail, |
1182 | msg->header.type = htons (GNUNET_MESSAGE_TYPE_ARM_LIST); | 978 | op); |
979 | env = GNUNET_MQ_msg (msg, | ||
980 | GNUNET_MESSAGE_TYPE_ARM_LIST); | ||
1183 | msg->reserved = htonl (0); | 981 | msg->reserved = htonl (0); |
1184 | cm->msg = msg; | 982 | msg->request_id = GNUNET_htonll (op->id); |
1185 | GNUNET_CONTAINER_DLL_insert_tail (h->control_pending_head, | 983 | GNUNET_MQ_send (h->mq, |
1186 | h->control_pending_tail, | 984 | env); |
1187 | cm); | 985 | return op; |
1188 | cm->timeout_task_id = | ||
1189 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining | ||
1190 | (cm->timeout), | ||
1191 | &control_message_timeout, | ||
1192 | cm); | ||
1193 | trigger_next_request (h, | ||
1194 | GNUNET_NO); | ||
1195 | } | 986 | } |
1196 | 987 | ||
1197 | 988 | ||