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 | |
parent | 3ceae682287492ecc768aea5c4c463216a35774d (diff) | |
download | gnunet-405f776bc08486af4edb80e18149c0829732b347.tar.gz gnunet-405f776bc08486af4edb80e18149c0829732b347.zip |
All-encompassing ARM update
Diffstat (limited to 'src')
-rw-r--r-- | src/arm/Makefile.am | 2 | ||||
-rw-r--r-- | src/arm/arm.h | 53 | ||||
-rw-r--r-- | src/arm/arm_api.c | 1130 | ||||
-rw-r--r-- | src/arm/gnunet-arm.c | 521 | ||||
-rw-r--r-- | src/arm/gnunet-service-arm.c | 526 | ||||
-rw-r--r-- | src/arm/mockup-service.c | 14 | ||||
-rw-r--r-- | src/arm/test_arm_api.c | 151 | ||||
-rw-r--r-- | src/arm/test_exponential_backoff.c | 265 | ||||
-rw-r--r-- | src/arm/test_gnunet_service_arm.c | 81 | ||||
-rw-r--r-- | src/include/gnunet_arm_service.h | 295 | ||||
-rw-r--r-- | src/include/gnunet_protocols.h | 13 | ||||
-rw-r--r-- | src/include/gnunet_server_lib.h | 37 | ||||
-rw-r--r-- | src/regex/gnunet-regex-profiler.c | 147 | ||||
-rw-r--r-- | src/regex/regex_test_lib.c | 2 | ||||
-rw-r--r-- | src/util/client.c | 1 | ||||
-rw-r--r-- | src/util/connection.c | 8 | ||||
-rw-r--r-- | src/util/server.c | 78 |
17 files changed, 2069 insertions, 1255 deletions
diff --git a/src/arm/Makefile.am b/src/arm/Makefile.am index 48d9955b8..dcc0f125f 100644 --- a/src/arm/Makefile.am +++ b/src/arm/Makefile.am | |||
@@ -19,7 +19,7 @@ endif | |||
19 | lib_LTLIBRARIES = libgnunetarm.la | 19 | lib_LTLIBRARIES = libgnunetarm.la |
20 | 20 | ||
21 | libgnunetarm_la_SOURCES = \ | 21 | libgnunetarm_la_SOURCES = \ |
22 | arm_api.c arm.h | 22 | arm_api.c arm_monitor_api.c arm.h |
23 | libgnunetarm_la_LIBADD = \ | 23 | libgnunetarm_la_LIBADD = \ |
24 | $(top_builddir)/src/util/libgnunetutil.la \ | 24 | $(top_builddir)/src/util/libgnunetutil.la \ |
25 | $(GN_LIBINTL) $(XLIB) | 25 | $(GN_LIBINTL) $(XLIB) |
diff --git a/src/arm/arm.h b/src/arm/arm.h index 21884107c..aad16fd71 100644 --- a/src/arm/arm.h +++ b/src/arm/arm.h | |||
@@ -36,20 +36,60 @@ | |||
36 | GNUNET_NETWORK_STRUCT_BEGIN | 36 | GNUNET_NETWORK_STRUCT_BEGIN |
37 | 37 | ||
38 | /** | 38 | /** |
39 | * Reply from ARM to client. | 39 | * Status update from ARM to client. |
40 | */ | 40 | */ |
41 | struct GNUNET_ARM_ResultMessage | 41 | struct GNUNET_ARM_StatusMessage |
42 | { | 42 | { |
43 | 43 | ||
44 | /** | 44 | /** |
45 | * Reply to client, of type is GNUNET_MESSAGE_TYPE_ARM_RESULT. | 45 | * Reply to client, of type is GNUNET_MESSAGE_TYPE_ARM_STATUS. |
46 | */ | 46 | */ |
47 | struct GNUNET_MessageHeader header; | 47 | struct GNUNET_MessageHeader header; |
48 | 48 | ||
49 | /** | 49 | /** |
50 | * Status from the 'enum GNUNET_ARM_ProcessStatus' | 50 | * Status from the 'enum GNUNET_ARM_ServiceStatus' |
51 | */ | 51 | */ |
52 | uint32_t status; | 52 | uint32_t status; |
53 | |||
54 | /* followed by a 0-terminated service name */ | ||
55 | }; | ||
56 | |||
57 | struct GNUNET_ARM_Message | ||
58 | { | ||
59 | /** | ||
60 | * Reply to client, type is GNUNET_MESSAGE_TYPE_ARM_RESULT or | ||
61 | * GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT. | ||
62 | * OR | ||
63 | * Request from client, type is GNUNET_MESSAGE_TYPE_ARM_REQUEST | ||
64 | */ | ||
65 | struct GNUNET_MessageHeader header; | ||
66 | |||
67 | /** | ||
68 | * ID of a request that is being replied to. | ||
69 | * OR | ||
70 | * ID of a request that is being sent. | ||
71 | */ | ||
72 | uint64_t request_id; | ||
73 | |||
74 | /* For requests - followed by a 0-terminated service name */ | ||
75 | }; | ||
76 | |||
77 | |||
78 | /** | ||
79 | * Reply from ARM to client. | ||
80 | */ | ||
81 | struct GNUNET_ARM_ResultMessage | ||
82 | { | ||
83 | |||
84 | /** | ||
85 | * Reply to client, of type is GNUNET_MESSAGE_TYPE_ARM_RESULT, with an ID. | ||
86 | */ | ||
87 | struct GNUNET_ARM_Message arm_msg; | ||
88 | |||
89 | /** | ||
90 | * Result from the 'enum GNUNET_ARM_Result' | ||
91 | */ | ||
92 | uint32_t result; | ||
53 | }; | 93 | }; |
54 | 94 | ||
55 | /** | 95 | /** |
@@ -61,9 +101,10 @@ struct GNUNET_ARM_ResultMessage | |||
61 | struct GNUNET_ARM_ListResultMessage | 101 | struct GNUNET_ARM_ListResultMessage |
62 | { | 102 | { |
63 | /** | 103 | /** |
64 | * Reply to client is of type GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT | 104 | * Reply to client, of type is GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT, |
105 | * with an ID. | ||
65 | */ | 106 | */ |
66 | struct GNUNET_MessageHeader header; | 107 | struct GNUNET_ARM_Message arm_msg; |
67 | 108 | ||
68 | /** | 109 | /** |
69 | * Number of '\0' terminated strings that follow | 110 | * Number of '\0' terminated strings that follow |
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 */ |
diff --git a/src/arm/gnunet-arm.c b/src/arm/gnunet-arm.c index 8a98ba06b..9eb64e316 100644 --- a/src/arm/gnunet-arm.c +++ b/src/arm/gnunet-arm.c | |||
@@ -111,6 +111,11 @@ static int ret; | |||
111 | static struct GNUNET_ARM_Handle *h; | 111 | static struct GNUNET_ARM_Handle *h; |
112 | 112 | ||
113 | /** | 113 | /** |
114 | * Monitor connection with ARM. | ||
115 | */ | ||
116 | static struct GNUNET_ARM_MonitorHandle *m; | ||
117 | |||
118 | /** | ||
114 | * Our configuration. | 119 | * Our configuration. |
115 | */ | 120 | */ |
116 | static struct GNUNET_CONFIGURATION_Handle *cfg; | 121 | static struct GNUNET_CONFIGURATION_Handle *cfg; |
@@ -137,105 +142,6 @@ static unsigned int no_stderr; | |||
137 | 142 | ||
138 | 143 | ||
139 | /** | 144 | /** |
140 | * Main continuation-passing-style loop. Runs the various | ||
141 | * jobs that we've been asked to do in order. | ||
142 | * | ||
143 | * @param cls closure, unused | ||
144 | * @param tc context, unused | ||
145 | */ | ||
146 | static void | ||
147 | cps_loop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); | ||
148 | |||
149 | |||
150 | /** | ||
151 | * Callback invoked with the status of the last operation. Reports to the | ||
152 | * user and then runs the next phase in the FSM. | ||
153 | * | ||
154 | * @param cls pointer to "const char*" identifying service that was manipulated | ||
155 | * @param result result of the operation | ||
156 | */ | ||
157 | static void | ||
158 | confirm_cb (void *cls, | ||
159 | enum GNUNET_ARM_ProcessStatus result) | ||
160 | { | ||
161 | const char *service = cls; | ||
162 | |||
163 | switch (result) | ||
164 | { | ||
165 | case GNUNET_ARM_PROCESS_UNKNOWN: | ||
166 | FPRINTF (stderr, _("Service `%s' is unknown to ARM.\n"), service); | ||
167 | ret = 1; | ||
168 | break; | ||
169 | case GNUNET_ARM_PROCESS_DOWN: | ||
170 | if (quiet != GNUNET_YES) | ||
171 | FPRINTF (stdout, _("Service `%s' has been stopped.\n"), service); | ||
172 | break; | ||
173 | case GNUNET_ARM_PROCESS_ALREADY_RUNNING: | ||
174 | FPRINTF (stderr, _("Service `%s' was already running.\n"), service); | ||
175 | ret = 1; | ||
176 | break; | ||
177 | case GNUNET_ARM_PROCESS_STARTING: | ||
178 | if (quiet != GNUNET_YES) | ||
179 | FPRINTF (stdout, _("Service `%s' has been started.\n"), service); | ||
180 | break; | ||
181 | case GNUNET_ARM_PROCESS_ALREADY_STOPPING: | ||
182 | FPRINTF (stderr, _("Service `%s' was already being stopped.\n"), service); | ||
183 | ret = 1; | ||
184 | break; | ||
185 | case GNUNET_ARM_PROCESS_ALREADY_DOWN: | ||
186 | FPRINTF (stderr, _("Service `%s' was already not running.\n"), service); | ||
187 | ret = 1; | ||
188 | break; | ||
189 | case GNUNET_ARM_PROCESS_SHUTDOWN: | ||
190 | FPRINTF (stderr, "%s", _("Request ignored as ARM is shutting down.\n")); | ||
191 | ret = 1; | ||
192 | break; | ||
193 | case GNUNET_ARM_PROCESS_COMMUNICATION_ERROR: | ||
194 | FPRINTF (stderr, "%s", _("Error communicating with ARM service.\n")); | ||
195 | ret = 1; | ||
196 | break; | ||
197 | case GNUNET_ARM_PROCESS_COMMUNICATION_TIMEOUT: | ||
198 | FPRINTF (stderr, "%s", _("Timeout communicating with ARM service.\n")); | ||
199 | ret = 1; | ||
200 | break; | ||
201 | case GNUNET_ARM_PROCESS_FAILURE: | ||
202 | FPRINTF (stderr, "%s", _("Operation failed.\n")); | ||
203 | ret = 1; | ||
204 | break; | ||
205 | default: | ||
206 | FPRINTF (stderr, "%s", _("Unknown response code from ARM.\n")); | ||
207 | break; | ||
208 | } | ||
209 | GNUNET_SCHEDULER_add_now (&cps_loop, NULL); | ||
210 | } | ||
211 | |||
212 | |||
213 | /** | ||
214 | * Callback invoked with the list of running services. | ||
215 | * Reports to the user and then runs the next phase in the FSM. | ||
216 | * | ||
217 | * @param cls currently not used | ||
218 | * @param result result of the operation | ||
219 | * @param count number of running services | ||
220 | * @param list copy of the list of running services | ||
221 | */ | ||
222 | static void | ||
223 | list_cb (void *cls, int result, unsigned int count, const char *const*list) | ||
224 | { | ||
225 | unsigned int i; | ||
226 | |||
227 | if ( (result != GNUNET_YES) || (NULL == list) ) | ||
228 | { | ||
229 | FPRINTF (stderr, "%s", _("Error communicating with ARM. ARM not running?\n")); | ||
230 | return; | ||
231 | } | ||
232 | FPRINTF (stdout, "%s", _("Running services:\n")); | ||
233 | for (i=0; i<count; i++) | ||
234 | FPRINTF (stdout, "%s\n", list[i]); | ||
235 | } | ||
236 | |||
237 | |||
238 | /** | ||
239 | * Attempts to delete configuration file and SERVICEHOME | 145 | * Attempts to delete configuration file and SERVICEHOME |
240 | * on arm shutdown provided the end and delete options | 146 | * on arm shutdown provided the end and delete options |
241 | * were specified when gnunet-arm was run. | 147 | * were specified when gnunet-arm was run. |
@@ -273,7 +179,9 @@ static void | |||
273 | shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | 179 | shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) |
274 | { | 180 | { |
275 | GNUNET_ARM_disconnect (h); | 181 | GNUNET_ARM_disconnect (h); |
182 | GNUNET_ARM_monitor_disconnect (m); | ||
276 | h = NULL; | 183 | h = NULL; |
184 | m = NULL; | ||
277 | if ((end == GNUNET_YES) && (delete == GNUNET_YES)) | 185 | if ((end == GNUNET_YES) && (delete == GNUNET_YES)) |
278 | delete_files (); | 186 | delete_files (); |
279 | GNUNET_CONFIGURATION_destroy (cfg); | 187 | GNUNET_CONFIGURATION_destroy (cfg); |
@@ -281,68 +189,248 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
281 | } | 189 | } |
282 | 190 | ||
283 | 191 | ||
192 | static const char * | ||
193 | req_string (enum GNUNET_ARM_RequestStatus rs) | ||
194 | { | ||
195 | switch (rs) | ||
196 | { | ||
197 | case GNUNET_ARM_REQUEST_SENT_OK: | ||
198 | return _("Message was sent successfully"); | ||
199 | case GNUNET_ARM_REQUEST_CONFIGURATION_ERROR: | ||
200 | return _("Misconfiguration (can't connect to the ARM service)"); | ||
201 | case GNUNET_ARM_REQUEST_DISCONNECTED: | ||
202 | return _("We disconnected from ARM before we could send a request"); | ||
203 | case GNUNET_ARM_REQUEST_BUSY: | ||
204 | return _("ARM API is busy"); | ||
205 | case GNUNET_ARM_REQUEST_TOO_LONG: | ||
206 | return _("Request doesn't fit into a message"); | ||
207 | case GNUNET_ARM_REQUEST_TIMEOUT: | ||
208 | return _("Request timed out"); | ||
209 | default: | ||
210 | return _("Unknown request status"); | ||
211 | } | ||
212 | } | ||
213 | |||
214 | static const char * | ||
215 | ret_string (enum GNUNET_ARM_Result result) | ||
216 | { | ||
217 | switch (result) | ||
218 | { | ||
219 | case GNUNET_ARM_RESULT_STOPPED: | ||
220 | return _("%s is stopped"); | ||
221 | case GNUNET_ARM_RESULT_STARTING: | ||
222 | return _("%s is starting"); | ||
223 | case GNUNET_ARM_RESULT_IS_STARTING_ALREADY: | ||
224 | return _("%s is starting already"); | ||
225 | case GNUNET_ARM_RESULT_IS_STOPPING_ALREADY: | ||
226 | return _("%s is stopping already"); | ||
227 | case GNUNET_ARM_RESULT_IS_STARTED_ALREADY: | ||
228 | return _("%s is started already"); | ||
229 | case GNUNET_ARM_RESULT_IS_STOPPED_ALREADY: | ||
230 | return _("%s is stopped already"); | ||
231 | case GNUNET_ARM_RESULT_IS_NOT_KNOWN: | ||
232 | return _("%s service is not known to ARM"); | ||
233 | case GNUNET_ARM_RESULT_START_FAILED: | ||
234 | return _("%s service failed to start"); | ||
235 | case GNUNET_ARM_RESULT_IN_SHUTDOWN: | ||
236 | return _("%s service can't be started because ARM is shutting down"); | ||
237 | default: | ||
238 | return _("Unknown result code."); | ||
239 | } | ||
240 | } | ||
241 | |||
242 | static void action_loop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); | ||
243 | |||
284 | /** | 244 | /** |
285 | * Main function that will be run by the scheduler. | 245 | * Function called whenever we connect to or disconnect from ARM. |
286 | * | 246 | * |
287 | * @param cls closure | 247 | * @param cls closure |
288 | * @param args remaining command-line arguments | 248 | * @param connected GNUNET_YES if connected, GNUNET_NO if disconnected |
289 | * @param cfgfile name of the configuration file used (for saving, can be NULL!) | 249 | * @param error GNUNET_YES if we encountered a permanent error, and there |
290 | * @param c configuration | 250 | * will be no re-connection. |
291 | */ | 251 | */ |
252 | void | ||
253 | conn_status (void *cls, struct GNUNET_ARM_Handle *arm, unsigned char connected, unsigned char error) | ||
254 | { | ||
255 | if (GNUNET_YES == error) | ||
256 | { | ||
257 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
258 | _("Fatal error initializing ARM API.\n")); | ||
259 | GNUNET_SCHEDULER_shutdown (); | ||
260 | return; | ||
261 | } | ||
262 | /* | ||
263 | if (connected) | ||
264 | GNUNET_SCHEDULER_add_now (action_loop, NULL); | ||
265 | */ | ||
266 | } | ||
267 | |||
268 | |||
292 | static void | 269 | static void |
293 | run (void *cls, char *const *args, const char *cfgfile, | 270 | term_callback (void *cls, struct GNUNET_ARM_Handle *arm, |
294 | const struct GNUNET_CONFIGURATION_Handle *c) | 271 | enum GNUNET_ARM_RequestStatus rs, const char *service, |
272 | enum GNUNET_ARM_Result result) | ||
295 | { | 273 | { |
296 | char *armconfig; | 274 | if (GNUNET_ARM_REQUEST_SENT_OK != rs) |
275 | { | ||
276 | char *msg; | ||
277 | GNUNET_asprintf (&msg, _("Failed to send a request to kill the `%s' service: %%s\n"), term); | ||
278 | FPRINTF (stdout, msg, req_string (rs)); | ||
279 | GNUNET_free (msg); | ||
280 | GNUNET_SCHEDULER_shutdown (); | ||
281 | } | ||
282 | if ((GNUNET_ARM_RESULT_STOPPED == result) || | ||
283 | (GNUNET_ARM_RESULT_IS_STOPPED_ALREADY == result)) | ||
284 | { | ||
285 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Service %s shutdown successful\n", term); | ||
286 | term = NULL; | ||
287 | GNUNET_SCHEDULER_add_now (action_loop, NULL); | ||
288 | } | ||
289 | else | ||
290 | { | ||
291 | char *msg; | ||
292 | GNUNET_asprintf (&msg, _("Failed to kill the `%s' service: %%s\n"), term); | ||
293 | FPRINTF (stdout, msg, ret_string (result)); | ||
294 | GNUNET_free (msg); | ||
295 | GNUNET_SCHEDULER_shutdown (); | ||
296 | } | ||
297 | } | ||
297 | 298 | ||
298 | cfg = GNUNET_CONFIGURATION_dup (c); | 299 | static void |
299 | config_file = cfgfile; | 300 | end_callback (void *cls, struct GNUNET_ARM_Handle *arm, |
300 | if (GNUNET_CONFIGURATION_get_value_string | 301 | enum GNUNET_ARM_RequestStatus rs, const char *service, |
301 | (cfg, "PATHS", "SERVICEHOME", &dir) != GNUNET_OK) | 302 | enum GNUNET_ARM_Result result) |
303 | { | ||
304 | if (GNUNET_ARM_REQUEST_SENT_OK != rs) | ||
302 | { | 305 | { |
303 | GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, | 306 | char *msg; |
304 | "PATHS", "SERVICEHOME"); | 307 | GNUNET_asprintf (&msg, "%s", _("Failed to send a stop request to the ARM service: %%s\n")); |
305 | return; | 308 | FPRINTF (stdout, msg, req_string (rs)); |
306 | } | 309 | GNUNET_free (msg); |
307 | if (NULL != cfgfile) | 310 | GNUNET_SCHEDULER_shutdown (); |
311 | } | ||
312 | if ((GNUNET_ARM_RESULT_STOPPING == result) || | ||
313 | (GNUNET_ARM_RESULT_STOPPED == result) || | ||
314 | (GNUNET_ARM_RESULT_IS_STOPPED_ALREADY == result)) | ||
308 | { | 315 | { |
309 | if (GNUNET_OK != | 316 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM service shutdown successful\n"); |
310 | GNUNET_CONFIGURATION_get_value_filename (cfg, "arm", "CONFIG", | 317 | end = 0; |
311 | &armconfig)) | 318 | if (restart) |
312 | { | 319 | { |
313 | GNUNET_CONFIGURATION_set_value_string (cfg, "arm", "CONFIG", | 320 | restart = 0; |
314 | cfgfile); | 321 | start = 1; |
322 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Initiating an ARM restart\n"); | ||
315 | } | 323 | } |
316 | else | 324 | GNUNET_SCHEDULER_add_now (action_loop, NULL); |
317 | GNUNET_free (armconfig); | ||
318 | } | 325 | } |
319 | if (NULL == (h = GNUNET_ARM_connect (cfg, NULL))) | 326 | else |
320 | { | 327 | { |
321 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 328 | char *msg; |
322 | _("Fatal error initializing ARM API.\n")); | 329 | GNUNET_asprintf (&msg, "%s", _("Failed to stop the ARM service: %%s\n")); |
323 | ret = 1; | 330 | FPRINTF (stdout, msg, ret_string (result)); |
324 | GNUNET_CONFIGURATION_destroy (cfg); | 331 | GNUNET_free (msg); |
325 | cfg = NULL; | 332 | GNUNET_SCHEDULER_shutdown (); |
333 | } | ||
334 | } | ||
335 | |||
336 | static void | ||
337 | start_callback (void *cls, struct GNUNET_ARM_Handle *arm, | ||
338 | enum GNUNET_ARM_RequestStatus rs, const char *service, | ||
339 | enum GNUNET_ARM_Result result) | ||
340 | { | ||
341 | if (GNUNET_ARM_REQUEST_SENT_OK != rs) | ||
342 | { | ||
343 | char *msg; | ||
344 | GNUNET_asprintf (&msg, "%s", _("Failed to start the ARM service: %%s\n")); | ||
345 | FPRINTF (stdout, msg, req_string (rs)); | ||
346 | GNUNET_free (msg); | ||
347 | GNUNET_SCHEDULER_shutdown (); | ||
348 | } | ||
349 | if ((GNUNET_ARM_RESULT_STARTING == result) || | ||
350 | (GNUNET_ARM_RESULT_IS_STARTED_ALREADY == result)) | ||
351 | { | ||
352 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM service [re]start successful\n"); | ||
353 | start = 0; | ||
354 | GNUNET_SCHEDULER_add_now (action_loop, NULL); | ||
355 | } | ||
356 | else | ||
357 | { | ||
358 | char *msg; | ||
359 | GNUNET_asprintf (&msg, "%s", _("Failed to start the ARM service: %%s\n")); | ||
360 | FPRINTF (stdout, msg, ret_string (result)); | ||
361 | GNUNET_free (msg); | ||
362 | GNUNET_SCHEDULER_shutdown (); | ||
363 | } | ||
364 | } | ||
365 | |||
366 | |||
367 | static void | ||
368 | init_callback (void *cls, struct GNUNET_ARM_Handle *arm, | ||
369 | enum GNUNET_ARM_RequestStatus rs, const char *service, | ||
370 | enum GNUNET_ARM_Result result) | ||
371 | { | ||
372 | if (GNUNET_ARM_REQUEST_SENT_OK != rs) | ||
373 | { | ||
374 | char *msg; | ||
375 | GNUNET_asprintf (&msg, _("Failed to send a request to start the `%s' service: %%s\n"), init); | ||
376 | FPRINTF (stdout, msg, req_string (rs)); | ||
377 | GNUNET_free (msg); | ||
378 | GNUNET_SCHEDULER_shutdown (); | ||
379 | } | ||
380 | if ((GNUNET_ARM_RESULT_STARTING == result) || | ||
381 | (GNUNET_ARM_RESULT_IS_STARTED_ALREADY == result)) | ||
382 | { | ||
383 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Service %s [re]start successful\n", init); | ||
384 | init = NULL; | ||
385 | GNUNET_SCHEDULER_add_now (action_loop, NULL); | ||
386 | } | ||
387 | else | ||
388 | { | ||
389 | char *msg; | ||
390 | GNUNET_asprintf (&msg, _("Failed to start the `%s' service: %%s\n"), init); | ||
391 | FPRINTF (stdout, msg, ret_string (result)); | ||
392 | GNUNET_free (msg); | ||
393 | GNUNET_SCHEDULER_shutdown (); | ||
394 | } | ||
395 | } | ||
396 | |||
397 | |||
398 | static void | ||
399 | list_callback (void *cls, struct GNUNET_ARM_Handle *arm, | ||
400 | enum GNUNET_ARM_RequestStatus rs, unsigned int count, | ||
401 | const char *const*list) | ||
402 | { | ||
403 | unsigned int i; | ||
404 | if (GNUNET_ARM_REQUEST_SENT_OK != rs) | ||
405 | { | ||
406 | char *msg; | ||
407 | GNUNET_asprintf (&msg, "%s", _("Failed to request a list of services: %%s\n")); | ||
408 | FPRINTF (stdout, msg, req_string (rs)); | ||
409 | GNUNET_free (msg); | ||
410 | GNUNET_SCHEDULER_shutdown (); | ||
411 | } | ||
412 | if (NULL == list) | ||
413 | { | ||
414 | FPRINTF (stderr, "%s", _("Error communicating with ARM. ARM not running?\n")); | ||
326 | return; | 415 | return; |
327 | } | 416 | } |
328 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, | 417 | FPRINTF (stdout, "%s", _("Running services:\n")); |
329 | &shutdown_task, NULL); | 418 | for (i = 0; i < count; i++) |
330 | GNUNET_SCHEDULER_add_now (&cps_loop, NULL); | 419 | FPRINTF (stdout, "%s\n", list[i]); |
331 | } | 420 | } |
332 | 421 | ||
333 | 422 | ||
334 | /** | 423 | /** |
335 | * Main continuation-passing-style loop. Runs the various | 424 | * Main action loop. Runs the various |
336 | * jobs that we've been asked to do in order. | 425 | * jobs that we've been asked to do in order. |
337 | * | 426 | * |
338 | * @param cls closure, unused | 427 | * @param cls closure, unused |
339 | * @param tc context, unused | 428 | * @param tc context, unused |
340 | */ | 429 | */ |
341 | static void | 430 | static void |
342 | cps_loop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | 431 | action_loop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) |
343 | { | 432 | { |
344 | if (NULL == h) | 433 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Running requested actions\n"); |
345 | return; | ||
346 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | 434 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) |
347 | return; | 435 | return; |
348 | while (1) | 436 | while (1) |
@@ -352,82 +440,54 @@ cps_loop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
352 | case 0: | 440 | case 0: |
353 | if (NULL != term) | 441 | if (NULL != term) |
354 | { | 442 | { |
355 | GNUNET_ARM_stop_service (h, term, | 443 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Termination action\n"); |
356 | (0 == | 444 | GNUNET_ARM_request_service_stop (h, term, (0 == |
357 | timeout.rel_value) ? STOP_TIMEOUT : | 445 | timeout.rel_value) ? STOP_TIMEOUT : timeout, |
358 | timeout, &confirm_cb, term); | 446 | term_callback, NULL); |
359 | return; | 447 | return; |
360 | } | 448 | } |
361 | break; | 449 | break; |
362 | case 1: | 450 | case 1: |
363 | if ((end) || (restart)) | 451 | if (end || restart) |
364 | { | 452 | { |
365 | GNUNET_ARM_stop_service (h, "arm", | 453 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "End action\n"); |
366 | (0 == | 454 | GNUNET_ARM_request_service_stop (h, "arm", (0 == |
367 | timeout.rel_value) ? STOP_TIMEOUT_ARM | 455 | timeout.rel_value) ? STOP_TIMEOUT_ARM : timeout, |
368 | : timeout, &confirm_cb, "arm"); | 456 | end_callback, NULL); |
369 | return; | 457 | return; |
370 | } | 458 | } |
371 | break; | 459 | break; |
372 | case 2: | 460 | case 2: |
373 | if (start) | 461 | if (start) |
374 | { | 462 | { |
375 | GNUNET_ARM_start_service (h, "arm", | 463 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Start action\n"); |
376 | (no_stdout ? 0 : GNUNET_OS_INHERIT_STD_OUT) | | 464 | GNUNET_ARM_request_service_start (h, "arm", |
377 | (no_stderr ? 0 : GNUNET_OS_INHERIT_STD_ERR), | 465 | (no_stdout ? 0 : GNUNET_OS_INHERIT_STD_OUT) | |
378 | (0 == | 466 | (no_stderr ? 0 : GNUNET_OS_INHERIT_STD_ERR), |
379 | timeout.rel_value) ? START_TIMEOUT : | 467 | (0 == timeout.rel_value) ? START_TIMEOUT: timeout, |
380 | timeout, &confirm_cb, "arm"); | 468 | start_callback, NULL); |
381 | return; | 469 | return; |
382 | } | 470 | } |
383 | break; | 471 | break; |
384 | case 3: | 472 | case 3: |
385 | if (NULL != init) | 473 | if (NULL != init) |
386 | { | ||
387 | GNUNET_ARM_start_service (h, init, | ||
388 | (no_stdout ? 0 : GNUNET_OS_INHERIT_STD_OUT) | | ||
389 | (no_stderr ? 0 : GNUNET_OS_INHERIT_STD_ERR), | ||
390 | (0 == | ||
391 | timeout.rel_value) ? START_TIMEOUT : | ||
392 | timeout, &confirm_cb, init); | ||
393 | return; | ||
394 | } | ||
395 | break; | ||
396 | case 4: | ||
397 | if (restart) | ||
398 | { | 474 | { |
399 | GNUNET_ARM_disconnect (h); | 475 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Initialization action\n"); |
400 | phase = 0; | 476 | GNUNET_ARM_request_service_start (h, init, GNUNET_OS_INHERIT_STD_NONE, |
401 | end = 0; | 477 | (0 == timeout.rel_value) ? STOP_TIMEOUT : timeout, |
402 | start = 1; | 478 | init_callback, NULL); |
403 | restart = 0; | 479 | return; |
404 | if (NULL == (h = GNUNET_ARM_connect (cfg, NULL))) | ||
405 | { | ||
406 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
407 | _("Fatal error initializing ARM API.\n")); | ||
408 | ret = 1; | ||
409 | return; | ||
410 | } | ||
411 | GNUNET_SCHEDULER_add_now (&cps_loop, NULL); | ||
412 | return; | ||
413 | } | 480 | } |
414 | break; | 481 | break; |
415 | case 5: | 482 | case 4: |
416 | if (list) | 483 | if (list) |
417 | { | 484 | { |
418 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 485 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
419 | "Going to list all running services controlled by ARM.\n"); | 486 | "Going to list all running services controlled by ARM.\n"); |
420 | 487 | ||
421 | if (NULL == h) | 488 | GNUNET_ARM_request_service_list (h, |
422 | { | 489 | (0 == timeout.rel_value) ? LIST_TIMEOUT : timeout, |
423 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 490 | list_callback, &list); |
424 | _("Fatal error initializing ARM API.\n")); | ||
425 | return; | ||
426 | } | ||
427 | GNUNET_ARM_list_running_services (h, | ||
428 | (0 == | ||
429 | timeout.rel_value) ? LIST_TIMEOUT : | ||
430 | timeout, &list_cb, NULL); | ||
431 | return; | 491 | return; |
432 | } | 492 | } |
433 | /* Fall through */ | 493 | /* Fall through */ |
@@ -440,6 +500,89 @@ cps_loop (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
440 | 500 | ||
441 | 501 | ||
442 | /** | 502 | /** |
503 | * Function called when a service starts or stops. | ||
504 | * | ||
505 | * @param cls closure | ||
506 | * @param service service name | ||
507 | * @param status status of the service | ||
508 | */ | ||
509 | static void | ||
510 | srv_status (void *cls, struct GNUNET_ARM_MonitorHandle *arm, | ||
511 | const char *service, enum GNUNET_ARM_ServiceStatus status) | ||
512 | { | ||
513 | const char *msg; | ||
514 | switch (status) | ||
515 | { | ||
516 | case GNUNET_ARM_SERVICE_MONITORING_STARTED: | ||
517 | msg = _("Began monitoring ARM for service status changes\n"); | ||
518 | break; | ||
519 | case GNUNET_ARM_SERVICE_STOPPED: | ||
520 | msg = _("Stopped %s.\n"); | ||
521 | break; | ||
522 | case GNUNET_ARM_SERVICE_STARTING: | ||
523 | msg = _("Starting %s...\n"); | ||
524 | break; | ||
525 | case GNUNET_ARM_SERVICE_STOPPING: | ||
526 | msg = _("Stopping %s...\n"); | ||
527 | break; | ||
528 | default: | ||
529 | msg = NULL; | ||
530 | break; | ||
531 | } | ||
532 | if (NULL != msg) | ||
533 | FPRINTF (stderr, msg, service); | ||
534 | else | ||
535 | FPRINTF (stderr, _("Unknown status %u for service %s.\n"), status, service); | ||
536 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got service %s status %u\n", service, status); | ||
537 | } | ||
538 | |||
539 | |||
540 | /** | ||
541 | * Main function that will be run by the scheduler. | ||
542 | * | ||
543 | * @param cls closure | ||
544 | * @param args remaining command-line arguments | ||
545 | * @param cfgfile name of the configuration file used (for saving, can be NULL!) | ||
546 | * @param c configuration | ||
547 | */ | ||
548 | static void | ||
549 | run (void *cls, char *const *args, const char *cfgfile, | ||
550 | const struct GNUNET_CONFIGURATION_Handle *c) | ||
551 | { | ||
552 | char *armconfig; | ||
553 | |||
554 | cfg = GNUNET_CONFIGURATION_dup (c); | ||
555 | config_file = cfgfile; | ||
556 | if (GNUNET_CONFIGURATION_get_value_string | ||
557 | (cfg, "PATHS", "SERVICEHOME", &dir) != GNUNET_OK) | ||
558 | { | ||
559 | GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR, | ||
560 | "PATHS", "SERVICEHOME"); | ||
561 | return; | ||
562 | } | ||
563 | if (NULL != cfgfile) | ||
564 | { | ||
565 | if (GNUNET_OK != | ||
566 | GNUNET_CONFIGURATION_get_value_filename (cfg, "arm", "CONFIG", | ||
567 | &armconfig)) | ||
568 | { | ||
569 | GNUNET_CONFIGURATION_set_value_string (cfg, "arm", "CONFIG", | ||
570 | cfgfile); | ||
571 | } | ||
572 | else | ||
573 | GNUNET_free (armconfig); | ||
574 | } | ||
575 | h = GNUNET_ARM_alloc (cfg); | ||
576 | m = GNUNET_ARM_monitor_alloc (cfg); | ||
577 | GNUNET_ARM_connect (h, conn_status, NULL); | ||
578 | GNUNET_ARM_monitor (m, srv_status, NULL); | ||
579 | GNUNET_SCHEDULER_add_now (action_loop, NULL); | ||
580 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, | ||
581 | shutdown_task, NULL); | ||
582 | } | ||
583 | |||
584 | |||
585 | /** | ||
443 | * The main function to obtain arm from gnunetd. | 586 | * The main function to obtain arm from gnunetd. |
444 | * | 587 | * |
445 | * @param argc number of arguments from the command line | 588 | * @param argc number of arguments from the command line |
diff --git a/src/arm/gnunet-service-arm.c b/src/arm/gnunet-service-arm.c index 7a99b5079..b1ba5af1b 100644 --- a/src/arm/gnunet-service-arm.c +++ b/src/arm/gnunet-service-arm.c | |||
@@ -30,6 +30,13 @@ | |||
30 | #include "arm.h" | 30 | #include "arm.h" |
31 | 31 | ||
32 | /** | 32 | /** |
33 | * How many messages do we queue up at most for optional | ||
34 | * notifications to a client? (this can cause notifications | ||
35 | * about outgoing messages to be dropped). | ||
36 | */ | ||
37 | #define MAX_NOTIFY_QUEUE 1024 | ||
38 | |||
39 | /** | ||
33 | * List of our services. | 40 | * List of our services. |
34 | */ | 41 | */ |
35 | struct ServiceList; | 42 | struct ServiceList; |
@@ -125,6 +132,11 @@ struct ServiceList | |||
125 | struct GNUNET_SERVER_Client *killing_client; | 132 | struct GNUNET_SERVER_Client *killing_client; |
126 | 133 | ||
127 | /** | 134 | /** |
135 | * ID of the request that killed the service (for reporting back). | ||
136 | */ | ||
137 | uint64_t killing_client_request_id; | ||
138 | |||
139 | /** | ||
128 | * Process structure pointer of the child. | 140 | * Process structure pointer of the child. |
129 | */ | 141 | */ |
130 | struct GNUNET_OS_Process *proc; | 142 | struct GNUNET_OS_Process *proc; |
@@ -217,17 +229,154 @@ static int in_shutdown; | |||
217 | */ | 229 | */ |
218 | static struct GNUNET_SERVER_Handle *server; | 230 | static struct GNUNET_SERVER_Handle *server; |
219 | 231 | ||
232 | /** | ||
233 | * Context for notifications we need to send to our clients. | ||
234 | */ | ||
235 | static struct GNUNET_SERVER_NotificationContext *notifier; | ||
236 | |||
220 | 237 | ||
221 | #include "do_start_process.c" | 238 | #include "do_start_process.c" |
222 | 239 | ||
240 | /** | ||
241 | * Transmit a status result message. | ||
242 | * | ||
243 | * @param cls pointer to "unit16_t*" with message type | ||
244 | * @param size number of bytes available in buf | ||
245 | * @param buf where to copy the message, NULL on error | ||
246 | * @return number of bytes copied to buf | ||
247 | */ | ||
248 | static size_t | ||
249 | write_result (void *cls, size_t size, void *buf) | ||
250 | { | ||
251 | struct GNUNET_ARM_ResultMessage *msg = cls; | ||
252 | size_t msize; | ||
253 | |||
254 | if (buf == NULL) | ||
255 | { | ||
256 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
257 | _("Could not send status result to client\n")); | ||
258 | GNUNET_free (msg); | ||
259 | return 0; /* error, not much we can do */ | ||
260 | } | ||
261 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
262 | "Sending status response %u to client\n", (unsigned int) msg->result); | ||
263 | msize = msg->arm_msg.header.size; | ||
264 | GNUNET_assert (size >= msize); | ||
265 | msg->arm_msg.header.size = htons (msg->arm_msg.header.size); | ||
266 | msg->arm_msg.header.type = htons (msg->arm_msg.header.type); | ||
267 | msg->result = htonl (msg->result); | ||
268 | msg->arm_msg.request_id = GNUNET_htonll (msg->arm_msg.request_id); | ||
269 | memcpy (buf, msg, msize); | ||
270 | GNUNET_free (msg); | ||
271 | return msize; | ||
272 | } | ||
273 | |||
274 | /** | ||
275 | * Transmit the list of running services. | ||
276 | * | ||
277 | * @param cls pointer to struct GNUNET_ARM_ListResultMessage with the message | ||
278 | * @param size number of bytes available in buf | ||
279 | * @param buf where to copy the message, NULL on error | ||
280 | * @return number of bytes copied to buf | ||
281 | */ | ||
282 | static size_t | ||
283 | write_list_result (void *cls, size_t size, void *buf) | ||
284 | { | ||
285 | struct GNUNET_ARM_ListResultMessage *msg = cls; | ||
286 | size_t rslt_size; | ||
287 | |||
288 | if (buf == NULL) | ||
289 | { | ||
290 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
291 | _("Could not send list result to client\n")); | ||
292 | GNUNET_free (msg); | ||
293 | return 0; /* error, not much we can do */ | ||
294 | } | ||
295 | |||
296 | rslt_size = msg->arm_msg.header.size; | ||
297 | GNUNET_assert (size >= rslt_size); | ||
298 | msg->arm_msg.header.size = htons (msg->arm_msg.header.size); | ||
299 | msg->arm_msg.header.type = htons (msg->arm_msg.header.type); | ||
300 | msg->arm_msg.request_id = GNUNET_htonll (msg->arm_msg.request_id); | ||
301 | msg->count = htons (msg->count); | ||
302 | |||
303 | memcpy (buf, msg, rslt_size); | ||
304 | GNUNET_free (msg); | ||
305 | return rslt_size; | ||
306 | } | ||
307 | |||
308 | |||
309 | /** | ||
310 | * Signal our client that we will start or stop the | ||
311 | * service. | ||
312 | * | ||
313 | * @param client who is being signalled | ||
314 | * @param name name of the service | ||
315 | * @param result message type to send | ||
316 | * @return NULL if it was not found | ||
317 | */ | ||
318 | static void | ||
319 | signal_result (struct GNUNET_SERVER_Client *client, const char *name, | ||
320 | uint64_t request_id, enum GNUNET_ARM_Result result) | ||
321 | { | ||
322 | struct GNUNET_ARM_ResultMessage *msg; | ||
323 | size_t msize; | ||
324 | |||
325 | msize = sizeof (struct GNUNET_ARM_ResultMessage); | ||
326 | msg = GNUNET_malloc (msize); | ||
327 | msg->arm_msg.header.size = msize; | ||
328 | msg->arm_msg.header.type = GNUNET_MESSAGE_TYPE_ARM_RESULT; | ||
329 | msg->result = result; | ||
330 | msg->arm_msg.request_id = request_id; | ||
331 | |||
332 | GNUNET_SERVER_notify_transmit_ready (client, msize, | ||
333 | GNUNET_TIME_UNIT_FOREVER_REL, write_result, msg); | ||
334 | } | ||
335 | |||
336 | |||
337 | /** | ||
338 | * Tell all clients about status change of a service. | ||
339 | * | ||
340 | * @param name name of the service | ||
341 | * @param status message type to send | ||
342 | */ | ||
343 | static void | ||
344 | broadcast_status (const char *name, enum GNUNET_ARM_ServiceStatus status, | ||
345 | struct GNUNET_SERVER_Client *unicast) | ||
346 | { | ||
347 | struct GNUNET_ARM_StatusMessage *msg; | ||
348 | size_t namelen; | ||
349 | |||
350 | if (NULL == notifier) | ||
351 | return; | ||
352 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
353 | "Sending status %u of service `%s' to client\n", | ||
354 | (unsigned int) status, name); | ||
355 | namelen = strlen (name); | ||
356 | msg = GNUNET_malloc (sizeof (struct GNUNET_ARM_StatusMessage) + namelen + 1); | ||
357 | msg->header.size = htons (sizeof (struct GNUNET_ARM_StatusMessage) + namelen + 1); | ||
358 | msg->header.type = htons (GNUNET_MESSAGE_TYPE_ARM_STATUS); | ||
359 | msg->status = htonl ((uint32_t) (status)); | ||
360 | memcpy ((char *) &msg[1], name, namelen + 1); | ||
361 | |||
362 | if (NULL == unicast) | ||
363 | GNUNET_SERVER_notification_context_broadcast (notifier, | ||
364 | (struct GNUNET_MessageHeader *) msg, GNUNET_YES); | ||
365 | else | ||
366 | GNUNET_SERVER_notification_context_unicast (notifier, unicast, | ||
367 | (const struct GNUNET_MessageHeader *) msg, GNUNET_NO); | ||
368 | GNUNET_free (msg); | ||
369 | } | ||
370 | |||
223 | 371 | ||
224 | /** | 372 | /** |
225 | * Actually start the process for the given service. | 373 | * Actually start the process for the given service. |
226 | * | 374 | * |
227 | * @param sl identifies service to start | 375 | * @param sl identifies service to start |
376 | * @param client that asked to start the service (may be NULL) | ||
228 | */ | 377 | */ |
229 | static void | 378 | static void |
230 | start_process (struct ServiceList *sl) | 379 | start_process (struct ServiceList *sl, struct GNUNET_SERVER_Client *client, uint64_t request_id) |
231 | { | 380 | { |
232 | char *loprefix; | 381 | char *loprefix; |
233 | char *options; | 382 | char *options; |
@@ -342,11 +491,20 @@ start_process (struct ServiceList *sl) | |||
342 | } | 491 | } |
343 | GNUNET_free (binary); | 492 | GNUNET_free (binary); |
344 | if (sl->proc == NULL) | 493 | if (sl->proc == NULL) |
494 | { | ||
345 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to start service `%s'\n"), | 495 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to start service `%s'\n"), |
346 | sl->name); | 496 | sl->name); |
497 | if (client) | ||
498 | signal_result (client, sl->name, request_id, GNUNET_ARM_RESULT_START_FAILED); | ||
499 | } | ||
347 | else | 500 | else |
501 | { | ||
348 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Starting service `%s'\n"), | 502 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Starting service `%s'\n"), |
349 | sl->name); | 503 | sl->name); |
504 | broadcast_status (sl->name, GNUNET_ARM_SERVICE_STARTING, NULL); | ||
505 | if (client) | ||
506 | signal_result (client, sl->name, request_id, GNUNET_ARM_RESULT_STARTING); | ||
507 | } | ||
350 | /* clean up */ | 508 | /* clean up */ |
351 | GNUNET_free (loprefix); | 509 | GNUNET_free (loprefix); |
352 | GNUNET_free (options); | 510 | GNUNET_free (options); |
@@ -355,104 +513,6 @@ start_process (struct ServiceList *sl) | |||
355 | 513 | ||
356 | 514 | ||
357 | /** | 515 | /** |
358 | * Transmit a status result message. | ||
359 | * | ||
360 | * @param cls pointer to "unit16_t*" with message type | ||
361 | * @param size number of bytes available in buf | ||
362 | * @param buf where to copy the message, NULL on error | ||
363 | * @return number of bytes copied to buf | ||
364 | */ | ||
365 | static size_t | ||
366 | write_result (void *cls, size_t size, void *buf) | ||
367 | { | ||
368 | enum GNUNET_ARM_ProcessStatus *res = cls; | ||
369 | struct GNUNET_ARM_ResultMessage *msg; | ||
370 | |||
371 | if (buf == NULL) | ||
372 | { | ||
373 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
374 | _("Could not send status result to client\n")); | ||
375 | return 0; /* error, not much we can do */ | ||
376 | } | ||
377 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
378 | "Sending status response %u to client\n", (unsigned int) *res); | ||
379 | GNUNET_assert (size >= sizeof (struct GNUNET_ARM_ResultMessage)); | ||
380 | msg = buf; | ||
381 | msg->header.size = htons (sizeof (struct GNUNET_ARM_ResultMessage)); | ||
382 | msg->header.type = htons (GNUNET_MESSAGE_TYPE_ARM_RESULT); | ||
383 | msg->status = htonl ((uint32_t) (*res)); | ||
384 | GNUNET_free (res); | ||
385 | return sizeof (struct GNUNET_ARM_ResultMessage); | ||
386 | } | ||
387 | |||
388 | /** | ||
389 | * Transmit the list of running services. | ||
390 | * | ||
391 | * @param cls pointer to struct GNUNET_ARM_ListResultMessage with the message | ||
392 | * @param size number of bytes available in buf | ||
393 | * @param buf where to copy the message, NULL on error | ||
394 | * @return number of bytes copied to buf | ||
395 | */ | ||
396 | static size_t | ||
397 | write_list_result (void *cls, size_t size, void *buf) | ||
398 | { | ||
399 | struct GNUNET_ARM_ListResultMessage *msg = cls; | ||
400 | struct GNUNET_ARM_ListResultMessage *rslt; | ||
401 | size_t rslt_size; | ||
402 | |||
403 | if (buf == NULL) | ||
404 | { | ||
405 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
406 | _("Could not send list result to client\n")); | ||
407 | return 0; /* error, not much we can do */ | ||
408 | } | ||
409 | |||
410 | GNUNET_assert (size >= msg->header.size); | ||
411 | rslt = buf; | ||
412 | rslt->header.size = htons (msg->header.size); | ||
413 | rslt->header.type = htons (msg->header.type); | ||
414 | rslt->count = htons (msg->count); | ||
415 | |||
416 | size_t list_size = msg->header.size | ||
417 | - sizeof (struct GNUNET_ARM_ListResultMessage); | ||
418 | memcpy (&rslt[1], &msg[1], list_size); | ||
419 | |||
420 | rslt_size = msg->header.size; | ||
421 | GNUNET_free (msg); | ||
422 | return rslt_size; | ||
423 | } | ||
424 | |||
425 | |||
426 | /** | ||
427 | * Signal our client that we will start or stop the | ||
428 | * service. | ||
429 | * | ||
430 | * @param client who is being signalled | ||
431 | * @param name name of the service | ||
432 | * @param result message type to send | ||
433 | * @return NULL if it was not found | ||
434 | */ | ||
435 | static void | ||
436 | signal_result (struct GNUNET_SERVER_Client *client, const char *name, | ||
437 | enum GNUNET_ARM_ProcessStatus result) | ||
438 | { | ||
439 | enum GNUNET_ARM_ProcessStatus *res; | ||
440 | |||
441 | if (NULL == client) | ||
442 | return; | ||
443 | /* FIXME: this is not super-clean yet... */ | ||
444 | res = GNUNET_malloc (sizeof (enum GNUNET_ARM_ProcessStatus)); | ||
445 | *res = result; | ||
446 | GNUNET_SERVER_notify_transmit_ready (client, | ||
447 | sizeof (struct | ||
448 | GNUNET_ARM_ResultMessage), | ||
449 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
450 | &write_result, res); | ||
451 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
452 | } | ||
453 | |||
454 | |||
455 | /** | ||
456 | * Find the process with the given service | 516 | * Find the process with the given service |
457 | * name in the given list and return it. | 517 | * name in the given list and return it. |
458 | * | 518 | * |
@@ -492,7 +552,7 @@ accept_connection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
492 | GNUNET_assert (GNUNET_NO == in_shutdown); | 552 | GNUNET_assert (GNUNET_NO == in_shutdown); |
493 | if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason)) | 553 | if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason)) |
494 | return; | 554 | return; |
495 | start_process (sl); | 555 | start_process (sl, NULL, 0); |
496 | } | 556 | } |
497 | 557 | ||
498 | 558 | ||
@@ -619,10 +679,14 @@ handle_start (void *cls, struct GNUNET_SERVER_Client *client, | |||
619 | const char *servicename; | 679 | const char *servicename; |
620 | struct ServiceList *sl; | 680 | struct ServiceList *sl; |
621 | uint16_t size; | 681 | uint16_t size; |
622 | 682 | uint64_t request_id; | |
623 | size = ntohs (message->size); | 683 | struct GNUNET_ARM_Message *amsg; |
624 | size -= sizeof (struct GNUNET_MessageHeader); | 684 | |
625 | servicename = (const char *) &message[1]; | 685 | amsg = (struct GNUNET_ARM_Message *) message; |
686 | request_id = GNUNET_ntohll (amsg->request_id); | ||
687 | size = ntohs (amsg->header.size); | ||
688 | size -= sizeof (struct GNUNET_ARM_Message); | ||
689 | servicename = (const char *) &amsg[1]; | ||
626 | if ((size == 0) || (servicename[size - 1] != '\0')) | 690 | if ((size == 0) || (servicename[size - 1] != '\0')) |
627 | { | 691 | { |
628 | GNUNET_break (0); | 692 | GNUNET_break (0); |
@@ -631,23 +695,40 @@ handle_start (void *cls, struct GNUNET_SERVER_Client *client, | |||
631 | } | 695 | } |
632 | if (GNUNET_YES == in_shutdown) | 696 | if (GNUNET_YES == in_shutdown) |
633 | { | 697 | { |
634 | signal_result (client, servicename, GNUNET_ARM_PROCESS_SHUTDOWN); | 698 | signal_result (client, servicename, request_id, GNUNET_ARM_RESULT_IN_SHUTDOWN); |
699 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
635 | return; | 700 | return; |
636 | } | 701 | } |
637 | sl = find_service (servicename); | 702 | sl = find_service (servicename); |
638 | if (NULL == sl) | 703 | if (NULL == sl) |
639 | { | 704 | { |
640 | signal_result (client, servicename, GNUNET_ARM_PROCESS_UNKNOWN); | 705 | signal_result (client, servicename, request_id, GNUNET_ARM_RESULT_IS_NOT_KNOWN); |
706 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
641 | return; | 707 | return; |
642 | } | 708 | } |
643 | sl->is_default = GNUNET_YES; | 709 | sl->is_default = GNUNET_YES; |
644 | if (sl->proc != NULL) | 710 | if (sl->proc != NULL) |
645 | { | 711 | { |
646 | signal_result (client, servicename, GNUNET_ARM_PROCESS_ALREADY_RUNNING); | 712 | signal_result (client, servicename, request_id, GNUNET_ARM_RESULT_IS_STARTED_ALREADY); |
713 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
647 | return; | 714 | return; |
648 | } | 715 | } |
649 | start_process (sl); | 716 | start_process (sl, client, request_id); |
650 | signal_result (client, servicename, GNUNET_ARM_PROCESS_STARTING); | 717 | GNUNET_SERVER_receive_done (client, GNUNET_OK); |
718 | } | ||
719 | |||
720 | |||
721 | /** | ||
722 | * Start a shutdown sequence. | ||
723 | * | ||
724 | * @param cls closure (refers to service) | ||
725 | * @param tc task context | ||
726 | */ | ||
727 | static void | ||
728 | trigger_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
729 | { | ||
730 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Triggering shutdown\n"); | ||
731 | GNUNET_SCHEDULER_shutdown (); | ||
651 | } | 732 | } |
652 | 733 | ||
653 | 734 | ||
@@ -667,10 +748,14 @@ handle_stop (void *cls, struct GNUNET_SERVER_Client *client, | |||
667 | struct ServiceList *sl; | 748 | struct ServiceList *sl; |
668 | const char *servicename; | 749 | const char *servicename; |
669 | uint16_t size; | 750 | uint16_t size; |
670 | 751 | uint64_t request_id; | |
671 | size = ntohs (message->size); | 752 | struct GNUNET_ARM_Message *amsg; |
672 | size -= sizeof (struct GNUNET_MessageHeader); | 753 | |
673 | servicename = (const char *) &message[1]; | 754 | amsg = (struct GNUNET_ARM_Message *) message; |
755 | request_id = GNUNET_ntohll (amsg->request_id); | ||
756 | size = ntohs (amsg->header.size); | ||
757 | size -= sizeof (struct GNUNET_ARM_Message); | ||
758 | servicename = (const char *) &amsg[1]; | ||
674 | if ((size == 0) || (servicename[size - 1] != '\0')) | 759 | if ((size == 0) || (servicename[size - 1] != '\0')) |
675 | { | 760 | { |
676 | GNUNET_break (0); | 761 | GNUNET_break (0); |
@@ -679,40 +764,58 @@ handle_stop (void *cls, struct GNUNET_SERVER_Client *client, | |||
679 | } | 764 | } |
680 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 765 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
681 | _("Preparing to stop `%s'\n"), servicename); | 766 | _("Preparing to stop `%s'\n"), servicename); |
767 | if (0 == strcasecmp (servicename, "arm")) | ||
768 | { | ||
769 | broadcast_status (servicename, GNUNET_ARM_SERVICE_STOPPING, NULL); | ||
770 | signal_result (client, servicename, request_id, GNUNET_ARM_RESULT_STOPPING); | ||
771 | GNUNET_SERVER_client_persist_ (client); | ||
772 | GNUNET_SCHEDULER_add_now (trigger_shutdown, NULL); | ||
773 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
774 | return; | ||
775 | } | ||
682 | sl = find_service (servicename); | 776 | sl = find_service (servicename); |
683 | if (sl == NULL) | 777 | if (sl == NULL) |
684 | { | 778 | { |
685 | signal_result (client, servicename, GNUNET_ARM_PROCESS_UNKNOWN); | 779 | signal_result (client, servicename, request_id, GNUNET_ARM_RESULT_IS_NOT_KNOWN); |
780 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
686 | return; | 781 | return; |
687 | } | 782 | } |
688 | sl->is_default = GNUNET_NO; | 783 | sl->is_default = GNUNET_NO; |
689 | if (GNUNET_YES == in_shutdown) | 784 | if (GNUNET_YES == in_shutdown) |
690 | { | 785 | { |
691 | /* shutdown in progress */ | 786 | /* shutdown in progress */ |
692 | signal_result (client, servicename, GNUNET_ARM_PROCESS_SHUTDOWN); | 787 | signal_result (client, servicename, request_id, GNUNET_ARM_RESULT_IN_SHUTDOWN); |
788 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
693 | return; | 789 | return; |
694 | } | 790 | } |
695 | if (sl->killing_client != NULL) | 791 | if (sl->killing_client != NULL) |
696 | { | 792 | { |
697 | /* killing already in progress */ | 793 | /* killing already in progress */ |
698 | signal_result (client, servicename, | 794 | signal_result (client, servicename, request_id, |
699 | GNUNET_ARM_PROCESS_ALREADY_STOPPING); | 795 | GNUNET_ARM_RESULT_IS_STOPPING_ALREADY); |
796 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
700 | return; | 797 | return; |
701 | } | 798 | } |
702 | if (sl->proc == NULL) | 799 | if (sl->proc == NULL) |
703 | { | 800 | { |
704 | /* process is down */ | 801 | /* process is down */ |
705 | signal_result (client, servicename, GNUNET_ARM_PROCESS_ALREADY_DOWN); | 802 | signal_result (client, servicename, request_id, |
803 | GNUNET_ARM_RESULT_IS_STOPPED_ALREADY); | ||
804 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
706 | return; | 805 | return; |
707 | } | 806 | } |
708 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 807 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
709 | "Sending kill signal to service `%s', waiting for process to die.\n", | 808 | "Sending kill signal to service `%s', waiting for process to die.\n", |
710 | servicename); | 809 | servicename); |
810 | broadcast_status (servicename, GNUNET_ARM_SERVICE_STOPPING, NULL); | ||
811 | /* no signal_start - only when it's STOPPED */ | ||
711 | sl->killed_at = GNUNET_TIME_absolute_get (); | 812 | sl->killed_at = GNUNET_TIME_absolute_get (); |
712 | if (0 != GNUNET_OS_process_kill (sl->proc, SIGTERM)) | 813 | if (0 != GNUNET_OS_process_kill (sl->proc, SIGTERM)) |
713 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); | 814 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); |
714 | sl->killing_client = client; | 815 | sl->killing_client = client; |
816 | sl->killing_client_request_id = request_id; | ||
715 | GNUNET_SERVER_client_keep (client); | 817 | GNUNET_SERVER_client_keep (client); |
818 | GNUNET_SERVER_receive_done (client, GNUNET_YES); | ||
716 | } | 819 | } |
717 | 820 | ||
718 | /** | 821 | /** |
@@ -727,6 +830,7 @@ handle_list (void *cls, struct GNUNET_SERVER_Client *client, | |||
727 | const struct GNUNET_MessageHeader *message) | 830 | const struct GNUNET_MessageHeader *message) |
728 | { | 831 | { |
729 | struct GNUNET_ARM_ListResultMessage *msg; | 832 | struct GNUNET_ARM_ListResultMessage *msg; |
833 | struct GNUNET_ARM_Message *request; | ||
730 | size_t string_list_size; | 834 | size_t string_list_size; |
731 | size_t total_size; | 835 | size_t total_size; |
732 | struct ServiceList *sl; | 836 | struct ServiceList *sl; |
@@ -735,6 +839,7 @@ handle_list (void *cls, struct GNUNET_SERVER_Client *client, | |||
735 | if (NULL == client) | 839 | if (NULL == client) |
736 | return; | 840 | return; |
737 | 841 | ||
842 | request = (struct GNUNET_ARM_Message *) message; | ||
738 | count = 0; | 843 | count = 0; |
739 | string_list_size = 0; | 844 | string_list_size = 0; |
740 | /* first count the running processes get their name's size */ | 845 | /* first count the running processes get their name's size */ |
@@ -748,11 +853,13 @@ handle_list (void *cls, struct GNUNET_SERVER_Client *client, | |||
748 | count++; | 853 | count++; |
749 | } | 854 | } |
750 | } | 855 | } |
856 | |||
751 | total_size = sizeof (struct GNUNET_ARM_ListResultMessage) | 857 | total_size = sizeof (struct GNUNET_ARM_ListResultMessage) |
752 | + string_list_size; | 858 | + string_list_size; |
753 | msg = GNUNET_malloc (total_size); | 859 | msg = GNUNET_malloc (total_size); |
754 | msg->header.size = total_size; | 860 | msg->arm_msg.header.size = total_size; |
755 | msg->header.type = GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT; | 861 | msg->arm_msg.header.type = GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT; |
862 | msg->arm_msg.request_id = GNUNET_ntohll (request->request_id); | ||
756 | msg->count = count; | 863 | msg->count = count; |
757 | 864 | ||
758 | char *pos = (char *)&msg[1]; | 865 | char *pos = (char *)&msg[1]; |
@@ -767,9 +874,9 @@ handle_list (void *cls, struct GNUNET_SERVER_Client *client, | |||
767 | } | 874 | } |
768 | 875 | ||
769 | GNUNET_SERVER_notify_transmit_ready (client, | 876 | GNUNET_SERVER_notify_transmit_ready (client, |
770 | msg->header.size, | 877 | total_size, |
771 | GNUNET_TIME_UNIT_FOREVER_REL, | 878 | GNUNET_TIME_UNIT_FOREVER_REL, |
772 | &write_list_result, msg); | 879 | write_list_result, msg); |
773 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | 880 | GNUNET_SERVER_receive_done (client, GNUNET_OK); |
774 | } | 881 | } |
775 | 882 | ||
@@ -780,6 +887,12 @@ handle_list (void *cls, struct GNUNET_SERVER_Client *client, | |||
780 | static void | 887 | static void |
781 | do_shutdown () | 888 | do_shutdown () |
782 | { | 889 | { |
890 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Last shutdown phase\n"); | ||
891 | if (NULL != notifier) | ||
892 | { | ||
893 | GNUNET_SERVER_notification_context_destroy (notifier); | ||
894 | notifier = NULL; | ||
895 | } | ||
783 | if (NULL != server) | 896 | if (NULL != server) |
784 | { | 897 | { |
785 | GNUNET_SERVER_destroy (server); | 898 | GNUNET_SERVER_destroy (server); |
@@ -792,6 +905,15 @@ do_shutdown () | |||
792 | } | 905 | } |
793 | } | 906 | } |
794 | 907 | ||
908 | unsigned int | ||
909 | list_count (struct ServiceList *running_head) | ||
910 | { | ||
911 | struct ServiceList *i; | ||
912 | unsigned int res = 0; | ||
913 | for (res = 0, i = running_head; i; i = i->next, res++) | ||
914 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "%s\n", i->name); | ||
915 | return res; | ||
916 | } | ||
795 | 917 | ||
796 | /** | 918 | /** |
797 | * Task run for shutdown. | 919 | * Task run for shutdown. |
@@ -806,6 +928,7 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
806 | struct ServiceList *nxt; | 928 | struct ServiceList *nxt; |
807 | struct ServiceListeningInfo *sli; | 929 | struct ServiceListeningInfo *sli; |
808 | 930 | ||
931 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "First shutdown phase\n"); | ||
809 | if (GNUNET_SCHEDULER_NO_TASK != child_restart_task) | 932 | if (GNUNET_SCHEDULER_NO_TASK != child_restart_task) |
810 | { | 933 | { |
811 | GNUNET_SCHEDULER_cancel (child_restart_task); | 934 | GNUNET_SCHEDULER_cancel (child_restart_task); |
@@ -851,6 +974,9 @@ shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
851 | /* finally, should all service processes be already gone, terminate for real */ | 974 | /* finally, should all service processes be already gone, terminate for real */ |
852 | if (running_head == NULL) | 975 | if (running_head == NULL) |
853 | do_shutdown (); | 976 | do_shutdown (); |
977 | else | ||
978 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
979 | "Delaying shutdown, have %u childs still running\n", list_count (running_head)); | ||
854 | } | 980 | } |
855 | 981 | ||
856 | 982 | ||
@@ -890,7 +1016,7 @@ delayed_restart_task (void *cls, | |||
890 | /* process should run by default, start immediately */ | 1016 | /* process should run by default, start immediately */ |
891 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 1017 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
892 | _("Restarting service `%s'.\n"), sl->name); | 1018 | _("Restarting service `%s'.\n"), sl->name); |
893 | start_process (sl); | 1019 | start_process (sl, NULL, 0); |
894 | } | 1020 | } |
895 | else | 1021 | else |
896 | { | 1022 | { |
@@ -1004,74 +1130,63 @@ maint_child_death (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
1004 | } | 1130 | } |
1005 | GNUNET_OS_process_destroy (pos->proc); | 1131 | GNUNET_OS_process_destroy (pos->proc); |
1006 | pos->proc = NULL; | 1132 | pos->proc = NULL; |
1133 | broadcast_status (pos->name, GNUNET_ARM_SERVICE_STOPPED, NULL); | ||
1007 | if (NULL != pos->killing_client) | 1134 | if (NULL != pos->killing_client) |
1008 | { | 1135 | { |
1009 | signal_result (pos->killing_client, pos->name, | 1136 | signal_result (pos->killing_client, pos->name, |
1010 | GNUNET_ARM_PROCESS_DOWN); | 1137 | pos->killing_client_request_id, GNUNET_ARM_RESULT_STOPPED); |
1011 | GNUNET_SERVER_client_drop (pos->killing_client); | 1138 | GNUNET_SERVER_client_drop (pos->killing_client); |
1012 | pos->killing_client = NULL; | 1139 | pos->killing_client = NULL; |
1013 | /* process can still be re-started on-demand, ensure it is re-started if there is demand */ | 1140 | pos->killing_client_request_id = 0; |
1014 | for (sli = pos->listen_head; NULL != sli; sli = sli->next) | 1141 | /* process can still be re-started on-demand, ensure it is re-started if there is demand */ |
1015 | { | 1142 | for (sli = pos->listen_head; NULL != sli; sli = sli->next) |
1016 | GNUNET_break (GNUNET_SCHEDULER_NO_TASK == sli->accept_task); | 1143 | { |
1017 | sli->accept_task = | 1144 | GNUNET_break (GNUNET_SCHEDULER_NO_TASK == sli->accept_task); |
1018 | GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | 1145 | sli->accept_task = |
1019 | sli->listen_socket, | 1146 | GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, |
1020 | &accept_connection, sli); | 1147 | sli->listen_socket, &accept_connection, sli); |
1021 | } | 1148 | } |
1022 | } | 1149 | } |
1023 | if (GNUNET_YES != in_shutdown) | 1150 | if (GNUNET_YES != in_shutdown) |
1024 | { | 1151 | { |
1025 | if ((statusType == GNUNET_OS_PROCESS_EXITED) && (statcode == 0)) | 1152 | if ((statusType == GNUNET_OS_PROCESS_EXITED) && (statcode == 0)) |
1026 | { | 1153 | { |
1027 | /* process terminated normally, allow restart at any time */ | 1154 | /* process terminated normally, allow restart at any time */ |
1028 | pos->restart_at.abs_value = 0; | 1155 | pos->restart_at.abs_value = 0; |
1029 | } | 1156 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
1030 | else | 1157 | _("Service `%s' terminated normally, will restart at any time\n"), |
1031 | { | 1158 | pos->name); |
1032 | if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | ||
1033 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1034 | _ | ||
1035 | ("Service `%s' terminated with status %s/%d, will restart in %s\n"), | ||
1036 | pos->name, statstr, statcode, | ||
1037 | GNUNET_STRINGS_relative_time_to_string (pos->backoff, GNUNET_YES)); | ||
1038 | /* schedule restart */ | ||
1039 | pos->restart_at = GNUNET_TIME_relative_to_absolute (pos->backoff); | ||
1040 | pos->backoff = GNUNET_TIME_STD_BACKOFF (pos->backoff); | ||
1041 | } | ||
1042 | if (GNUNET_SCHEDULER_NO_TASK != child_restart_task) | ||
1043 | GNUNET_SCHEDULER_cancel (child_restart_task); | ||
1044 | child_restart_task = | ||
1045 | GNUNET_SCHEDULER_add_with_priority | ||
1046 | (GNUNET_SCHEDULER_PRIORITY_IDLE, | ||
1047 | &delayed_restart_task, NULL); | ||
1048 | } | 1159 | } |
1160 | else | ||
1161 | { | ||
1162 | if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | ||
1163 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1164 | _("Service `%s' terminated with status %s/%d, will restart in %s\n"), | ||
1165 | pos->name, statstr, statcode, | ||
1166 | GNUNET_STRINGS_relative_time_to_string (pos->backoff, GNUNET_YES)); | ||
1167 | /* schedule restart */ | ||
1168 | pos->restart_at = GNUNET_TIME_relative_to_absolute (pos->backoff); | ||
1169 | pos->backoff = GNUNET_TIME_STD_BACKOFF (pos->backoff); | ||
1170 | } | ||
1171 | if (GNUNET_SCHEDULER_NO_TASK != child_restart_task) | ||
1172 | GNUNET_SCHEDULER_cancel (child_restart_task); | ||
1173 | child_restart_task = GNUNET_SCHEDULER_add_with_priority ( | ||
1174 | GNUNET_SCHEDULER_PRIORITY_IDLE, &delayed_restart_task, NULL); | ||
1175 | } | ||
1049 | else | 1176 | else |
1050 | { | 1177 | { |
1051 | free_service (pos); | 1178 | free_service (pos); |
1052 | } | 1179 | } |
1053 | } | 1180 | } |
1054 | child_death_task = | 1181 | child_death_task = GNUNET_SCHEDULER_add_read_file ( |
1055 | GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, | 1182 | GNUNET_TIME_UNIT_FOREVER_REL, pr, &maint_child_death, NULL); |
1056 | pr, &maint_child_death, NULL); | ||
1057 | if ((NULL == running_head) && (GNUNET_YES == in_shutdown)) | 1183 | if ((NULL == running_head) && (GNUNET_YES == in_shutdown)) |
1058 | do_shutdown (); | 1184 | do_shutdown (); |
1059 | } | 1185 | else if (GNUNET_YES == in_shutdown) |
1060 | 1186 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | |
1187 | "Delaying shutdown after child's death, still have %u children\n", | ||
1188 | list_count (running_head)); | ||
1061 | 1189 | ||
1062 | /** | ||
1063 | * Handler for SHUTDOWN message. | ||
1064 | * | ||
1065 | * @param cls closure (refers to service) | ||
1066 | * @param client identification of the client | ||
1067 | * @param message the actual message | ||
1068 | */ | ||
1069 | static void | ||
1070 | handle_shutdown (void *cls, struct GNUNET_SERVER_Client *client, | ||
1071 | const struct GNUNET_MessageHeader *message) | ||
1072 | { | ||
1073 | GNUNET_SCHEDULER_shutdown (); | ||
1074 | GNUNET_SERVER_client_persist_ (client); | ||
1075 | } | 1190 | } |
1076 | 1191 | ||
1077 | 1192 | ||
@@ -1174,6 +1289,43 @@ setup_service (void *cls, const char *section) | |||
1174 | 1289 | ||
1175 | 1290 | ||
1176 | /** | 1291 | /** |
1292 | * A client connected, add it to the notification context. | ||
1293 | * | ||
1294 | * @param cls closure | ||
1295 | * @param client identification of the client | ||
1296 | */ | ||
1297 | static void | ||
1298 | handle_client_connecting (void *cls, struct GNUNET_SERVER_Client *client) | ||
1299 | { | ||
1300 | /* All clients are considered to be of the "monitor" kind | ||
1301 | * (that is, they don't affect ARM shutdown). | ||
1302 | */ | ||
1303 | if (NULL != client) | ||
1304 | GNUNET_SERVER_client_mark_monitor (client); | ||
1305 | } | ||
1306 | |||
1307 | /** | ||
1308 | * Handle MONITOR-message. | ||
1309 | * | ||
1310 | * @param cls closure (always NULL) | ||
1311 | * @param client identification of the client | ||
1312 | * @param message the actual message | ||
1313 | * @return GNUNET_OK to keep the connection open, | ||
1314 | * GNUNET_SYSERR to close it (signal serious error) | ||
1315 | */ | ||
1316 | static void | ||
1317 | handle_monitor (void *cls, struct GNUNET_SERVER_Client *client, | ||
1318 | const struct GNUNET_MessageHeader *message) | ||
1319 | { | ||
1320 | /* Removal is handled by the server implementation, internally. */ | ||
1321 | if ((NULL != client) && (NULL != notifier)) | ||
1322 | { | ||
1323 | GNUNET_SERVER_notification_context_add (notifier, client); | ||
1324 | broadcast_status ("arm", GNUNET_ARM_SERVICE_MONITORING_STARTED, client); | ||
1325 | } | ||
1326 | } | ||
1327 | |||
1328 | /** | ||
1177 | * Process arm requests. | 1329 | * Process arm requests. |
1178 | * | 1330 | * |
1179 | * @param cls closure | 1331 | * @param cls closure |
@@ -1187,8 +1339,7 @@ run (void *cls, struct GNUNET_SERVER_Handle *serv, | |||
1187 | static const struct GNUNET_SERVER_MessageHandler handlers[] = { | 1339 | static const struct GNUNET_SERVER_MessageHandler handlers[] = { |
1188 | {&handle_start, NULL, GNUNET_MESSAGE_TYPE_ARM_START, 0}, | 1340 | {&handle_start, NULL, GNUNET_MESSAGE_TYPE_ARM_START, 0}, |
1189 | {&handle_stop, NULL, GNUNET_MESSAGE_TYPE_ARM_STOP, 0}, | 1341 | {&handle_stop, NULL, GNUNET_MESSAGE_TYPE_ARM_STOP, 0}, |
1190 | {&handle_shutdown, NULL, GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN, | 1342 | {&handle_monitor, NULL, GNUNET_MESSAGE_TYPE_ARM_MONITOR, 0}, |
1191 | sizeof (struct GNUNET_MessageHeader)}, | ||
1192 | {&handle_list, NULL, GNUNET_MESSAGE_TYPE_ARM_LIST, | 1343 | {&handle_list, NULL, GNUNET_MESSAGE_TYPE_ARM_LIST, |
1193 | sizeof (struct GNUNET_MessageHeader)}, | 1344 | sizeof (struct GNUNET_MessageHeader)}, |
1194 | {NULL, NULL, 0, 0} | 1345 | {NULL, NULL, 0, 0} |
@@ -1241,7 +1392,7 @@ run (void *cls, struct GNUNET_SERVER_Handle *serv, | |||
1241 | continue; | 1392 | continue; |
1242 | } | 1393 | } |
1243 | sl->is_default = GNUNET_YES; | 1394 | sl->is_default = GNUNET_YES; |
1244 | start_process (sl); | 1395 | start_process (sl, NULL, 0); |
1245 | } | 1396 | } |
1246 | } | 1397 | } |
1247 | GNUNET_free (defaultservices); | 1398 | GNUNET_free (defaultservices); |
@@ -1253,6 +1404,9 @@ run (void *cls, struct GNUNET_SERVER_Handle *serv, | |||
1253 | ("No default services configured, GNUnet will not really start right now.\n")); | 1404 | ("No default services configured, GNUnet will not really start right now.\n")); |
1254 | } | 1405 | } |
1255 | 1406 | ||
1407 | notifier = | ||
1408 | GNUNET_SERVER_notification_context_create (server, MAX_NOTIFY_QUEUE); | ||
1409 | GNUNET_SERVER_connect_notify (server, handle_client_connecting, NULL); | ||
1256 | /* process client requests */ | 1410 | /* process client requests */ |
1257 | GNUNET_SERVER_add_handlers (server, handlers); | 1411 | GNUNET_SERVER_add_handlers (server, handlers); |
1258 | } | 1412 | } |
diff --git a/src/arm/mockup-service.c b/src/arm/mockup-service.c index d9896997b..2e021627e 100644 --- a/src/arm/mockup-service.c +++ b/src/arm/mockup-service.c | |||
@@ -29,21 +29,27 @@ | |||
29 | #include "gnunet_time_lib.h" | 29 | #include "gnunet_time_lib.h" |
30 | 30 | ||
31 | 31 | ||
32 | static int special_ret = 0; | ||
33 | |||
32 | /** | 34 | /** |
33 | * Handler for SHUTDOWN message. | 35 | * Handler for STOP message. |
34 | * | 36 | * |
35 | * @param cls closure (refers to service) | 37 | * @param cls closure (refers to service) |
36 | * @param client identification of the client | 38 | * @param client identification of the client |
37 | * @param message the actual message | 39 | * @param message the actual message |
38 | */ | 40 | */ |
39 | static void | 41 | static void |
40 | handle_shutdown (void *cls, struct GNUNET_SERVER_Client *client, | 42 | handle_stop (void *cls, struct GNUNET_SERVER_Client *client, |
41 | const struct GNUNET_MessageHeader *message) | 43 | const struct GNUNET_MessageHeader *message) |
42 | { | 44 | { |
43 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | 45 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
44 | _("Initiating shutdown as requested by client.\n")); | 46 | _("Initiating shutdown as requested by client.\n")); |
45 | GNUNET_SERVER_client_persist_ (client); | 47 | GNUNET_SERVER_client_persist_ (client); |
46 | GNUNET_SCHEDULER_shutdown (); | 48 | GNUNET_SCHEDULER_shutdown (); |
49 | /* ARM won't exponentially increase restart delay if we | ||
50 | * terminate normally. This changes the return code. | ||
51 | */ | ||
52 | special_ret = 1; | ||
47 | } | 53 | } |
48 | 54 | ||
49 | 55 | ||
@@ -52,7 +58,7 @@ run (void *cls, struct GNUNET_SERVER_Handle *server, | |||
52 | const struct GNUNET_CONFIGURATION_Handle *cfg) | 58 | const struct GNUNET_CONFIGURATION_Handle *cfg) |
53 | { | 59 | { |
54 | static const struct GNUNET_SERVER_MessageHandler handlers[] = { | 60 | static const struct GNUNET_SERVER_MessageHandler handlers[] = { |
55 | {&handle_shutdown, NULL, GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN, | 61 | {&handle_stop, NULL, GNUNET_MESSAGE_TYPE_ARM_STOP, |
56 | sizeof (struct GNUNET_MessageHeader)}, | 62 | sizeof (struct GNUNET_MessageHeader)}, |
57 | {NULL, NULL, 0, 0} | 63 | {NULL, NULL, 0, 0} |
58 | }; | 64 | }; |
@@ -70,5 +76,7 @@ main (int argc, char *const *argv) | |||
70 | (GNUNET_OK == | 76 | (GNUNET_OK == |
71 | GNUNET_SERVICE_run (argc, argv, "do-nothing", GNUNET_SERVICE_OPTION_NONE, | 77 | GNUNET_SERVICE_run (argc, argv, "do-nothing", GNUNET_SERVICE_OPTION_NONE, |
72 | &run, NULL)) ? 0 : 1; | 78 | &run, NULL)) ? 0 : 1; |
79 | if (0 != special_ret) | ||
80 | return special_ret; | ||
73 | return ret; | 81 | return ret; |
74 | } | 82 | } |
diff --git a/src/arm/test_arm_api.c b/src/arm/test_arm_api.c index 366d4e500..999bd77e6 100644 --- a/src/arm/test_arm_api.c +++ b/src/arm/test_arm_api.c | |||
@@ -42,77 +42,144 @@ static struct GNUNET_ARM_Handle *arm; | |||
42 | 42 | ||
43 | static int ok = 1; | 43 | static int ok = 1; |
44 | 44 | ||
45 | static int phase = 0; | ||
46 | |||
45 | static void | 47 | static void |
46 | arm_stopped (void *cls, enum GNUNET_ARM_ProcessStatus success) | 48 | arm_stop_cb (void *cls, struct GNUNET_ARM_Handle *h, enum GNUNET_ARM_RequestStatus status, const char *servicename, enum GNUNET_ARM_Result result) |
47 | { | 49 | { |
48 | GNUNET_break (success == GNUNET_ARM_PROCESS_DOWN); | 50 | /* (6), a stop request should be sent to ARM successfully */ |
49 | if (success != GNUNET_ARM_PROCESS_DOWN) | 51 | /* ARM should report that it is stopping */ |
50 | ok = 3; | 52 | GNUNET_break (status == GNUNET_ARM_REQUEST_SENT_OK); |
51 | else if (ok == 1) | 53 | GNUNET_break (result == GNUNET_ARM_RESULT_STOPPING); |
52 | ok = 0; | 54 | GNUNET_break (phase == 6); |
55 | phase++; | ||
56 | FPRINTF (stderr, "Sent 'STOP' request for arm to ARM %s\n", (status == GNUNET_ARM_REQUEST_SENT_OK) ? "successfully" : "unsuccessfully"); | ||
53 | } | 57 | } |
54 | 58 | ||
55 | |||
56 | static void | 59 | static void |
57 | arm_notify_stop (void *cls, enum GNUNET_ARM_ProcessStatus success) | 60 | resolver_stop_cb (void *cls, struct GNUNET_ARM_Handle *h, enum GNUNET_ARM_RequestStatus status, const char *servicename, enum GNUNET_ARM_Result result) |
58 | { | 61 | { |
59 | GNUNET_break (success == GNUNET_ARM_PROCESS_DOWN); | 62 | /* (5), a stop request should be sent to ARM successfully. |
63 | * ARM should report that resolver is stopped. | ||
64 | */ | ||
65 | GNUNET_break (status == GNUNET_ARM_REQUEST_SENT_OK); | ||
66 | GNUNET_break (result == GNUNET_ARM_RESULT_STOPPED); | ||
67 | GNUNET_break (phase == 5); | ||
68 | FPRINTF (stderr, "Sent 'STOP' request for resolver to ARM %s\n", (status == GNUNET_ARM_REQUEST_SENT_OK) ? "successfully" : "unsuccessfully"); | ||
69 | phase++; | ||
60 | #if START_ARM | 70 | #if START_ARM |
61 | GNUNET_ARM_stop_service (arm, "arm", TIMEOUT, &arm_stopped, NULL); | 71 | GNUNET_ARM_request_service_stop (arm, "arm", TIMEOUT, arm_stop_cb, NULL); |
72 | #else | ||
73 | arm_stop_cb (NULL, GNUNET_ARM_STATUS_SENT_OK, "arm", GNUNET_ARM_SERVICE_STOPPING); | ||
74 | arm_conn (NULL, GNUNET_NO, GNUNET_NO); | ||
62 | #endif | 75 | #endif |
63 | } | 76 | } |
64 | 77 | ||
65 | |||
66 | static void | 78 | static void |
67 | dns_notify (void *cls, const struct sockaddr *addr, socklen_t addrlen) | 79 | dns_notify (void *cls, const struct sockaddr *addr, socklen_t addrlen) |
68 | { | 80 | { |
69 | if (addr == NULL) | 81 | if (addr == NULL) |
70 | { | 82 | { |
83 | /* (4), resolver should finish resolving localhost */ | ||
84 | GNUNET_break (phase == 4); | ||
85 | phase++; | ||
86 | FPRINTF (stderr, "%s", "Finished resolving localhost\n"); | ||
71 | if (ok != 0) | 87 | if (ok != 0) |
72 | { | 88 | ok = 2; |
73 | GNUNET_break (0); | 89 | GNUNET_ARM_request_service_stop (arm, "resolver", TIMEOUT, resolver_stop_cb, NULL); |
74 | ok = 2; | ||
75 | } | ||
76 | GNUNET_ARM_stop_service (arm, "resolver", TIMEOUT, &arm_notify_stop, | ||
77 | NULL); | ||
78 | return; | 90 | return; |
79 | } | 91 | } |
92 | /* (3), resolver should resolve localhost */ | ||
93 | GNUNET_break (phase == 3); | ||
94 | FPRINTF (stderr, "%s", "Resolved localhost\n"); | ||
95 | phase++; | ||
80 | GNUNET_break (addr != NULL); | 96 | GNUNET_break (addr != NULL); |
81 | ok = 0; | 97 | ok = 0; |
82 | } | 98 | } |
83 | 99 | ||
84 | |||
85 | static void | 100 | static void |
86 | resolver_notify (void *cls, enum GNUNET_ARM_ProcessStatus success) | 101 | resolver_start_cb (void *cls, struct GNUNET_ARM_Handle *h, enum GNUNET_ARM_RequestStatus status, const char *servicename, enum GNUNET_ARM_Result result) |
87 | { | 102 | { |
88 | if (success != GNUNET_ARM_PROCESS_STARTING) | 103 | /* (2), the start request for resolver should be sent successfully |
89 | { | 104 | * ARM should report that resolver service is starting. |
90 | GNUNET_break (0); | 105 | */ |
91 | ok = 2; | 106 | GNUNET_assert (status == GNUNET_ARM_REQUEST_SENT_OK); |
92 | #if START_ARM | 107 | GNUNET_break (phase == 2); |
93 | GNUNET_ARM_stop_service (arm, "arm", TIMEOUT, &arm_stopped, NULL); | 108 | GNUNET_break (result == GNUNET_ARM_RESULT_STARTING); |
94 | #endif | 109 | FPRINTF (stderr, "Sent 'START' request for resolver to ARM %s\n", (status == GNUNET_ARM_REQUEST_SENT_OK) ? "successfully" : "unsuccessfully"); |
95 | return; | 110 | phase++; |
96 | } | ||
97 | GNUNET_RESOLVER_ip_get ("localhost", AF_INET, TIMEOUT, &dns_notify, NULL); | 111 | GNUNET_RESOLVER_ip_get ("localhost", AF_INET, TIMEOUT, &dns_notify, NULL); |
98 | } | 112 | } |
99 | 113 | ||
100 | |||
101 | static void | 114 | static void |
102 | arm_notify (void *cls, enum GNUNET_ARM_ProcessStatus success) | 115 | trigger_disconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) |
103 | { | 116 | { |
104 | if (success != GNUNET_ARM_PROCESS_STARTING) | 117 | GNUNET_ARM_disconnect ((struct GNUNET_ARM_Handle *) cls); |
105 | { | 118 | } |
106 | GNUNET_break (0); | 119 | |
107 | ok = 2; | 120 | |
121 | void | ||
122 | arm_conn (void *cls, struct GNUNET_ARM_Handle *arm, unsigned char connected, unsigned char error) | ||
123 | { | ||
124 | if (GNUNET_YES == error) | ||
125 | { | ||
126 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
127 | _("Fatal error initializing ARM API.\n")); | ||
128 | GNUNET_SCHEDULER_shutdown (); | ||
129 | GNUNET_assert (0); | ||
130 | return; | ||
131 | } | ||
132 | if (connected) | ||
133 | { | ||
134 | /* (1), arm connection should be established */ | ||
135 | FPRINTF (stderr, "%s", "Connected to ARM\n"); | ||
136 | GNUNET_break (phase == 1); | ||
137 | phase++; | ||
138 | GNUNET_ARM_request_service_start (arm, "resolver", GNUNET_OS_INHERIT_STD_OUT_AND_ERR, START_TIMEOUT, resolver_start_cb, NULL); | ||
139 | } | ||
140 | else | ||
141 | { | ||
142 | /* (7), ARM should stop (we disconnect from it) */ | ||
143 | FPRINTF (stderr, "%s", "Disconnected from ARM\n"); | ||
144 | GNUNET_break (phase == 7); | ||
145 | if (phase != 7) | ||
146 | ok = 3; | ||
147 | else if (ok == 1) | ||
148 | ok = 0; | ||
149 | GNUNET_SCHEDULER_add_now (trigger_disconnect, arm); | ||
150 | } | ||
151 | } | ||
152 | |||
153 | void | ||
154 | srv_status (void *cls, const char *service, enum GNUNET_ARM_ServiceStatus status) | ||
155 | { | ||
156 | FPRINTF (stderr, "Service %s is %u\n", service, status); | ||
157 | switch (phase) | ||
158 | { | ||
159 | default: | ||
160 | FPRINTF (stderr, "Unexpectedly got status %u for service %s\n", service); | ||
161 | GNUNET_break (0); | ||
162 | ok = 2; | ||
108 | #if START_ARM | 163 | #if START_ARM |
109 | GNUNET_ARM_stop_service (arm, "arm", TIMEOUT, &arm_stopped, NULL); | 164 | GNUNET_ARM_request_service_stop (arm, "arm", TIMEOUT, NULL, NULL); |
110 | #endif | 165 | #endif |
111 | } | 166 | } |
112 | GNUNET_ARM_start_service (arm, "resolver", GNUNET_OS_INHERIT_STD_OUT_AND_ERR, START_TIMEOUT, &resolver_notify, | ||
113 | NULL); | ||
114 | } | 167 | } |
115 | 168 | ||
169 | static void | ||
170 | arm_start_cb (void *cls, struct GNUNET_ARM_Handle *h, enum GNUNET_ARM_RequestStatus status, const char *servicename, enum GNUNET_ARM_Result result) | ||
171 | { | ||
172 | /* (0) The request should be "sent" successfully | ||
173 | * ("sent", because it isn't going anywhere, ARM API starts ARM service | ||
174 | * by itself). | ||
175 | * ARM API should report that ARM service is starting. | ||
176 | */ | ||
177 | GNUNET_break (status == GNUNET_ARM_REQUEST_SENT_OK); | ||
178 | GNUNET_break (phase == 0); | ||
179 | FPRINTF (stderr, "Sent 'START' request for arm to ARM %s\n", (status == GNUNET_ARM_REQUEST_SENT_OK) ? "successfully" : "unsuccessfully"); | ||
180 | GNUNET_break (result == GNUNET_ARM_RESULT_STARTING); | ||
181 | phase++; | ||
182 | } | ||
116 | 183 | ||
117 | static void | 184 | static void |
118 | task (void *cls, char *const *args, const char *cfgfile, | 185 | task (void *cls, char *const *args, const char *cfgfile, |
@@ -133,11 +200,13 @@ task (void *cls, char *const *args, const char *cfgfile, | |||
133 | else | 200 | else |
134 | GNUNET_free (armconfig); | 201 | GNUNET_free (armconfig); |
135 | } | 202 | } |
136 | arm = GNUNET_ARM_connect (cfg, NULL); | 203 | arm = GNUNET_ARM_alloc (cfg); |
204 | GNUNET_ARM_connect (arm, arm_conn, NULL); | ||
137 | #if START_ARM | 205 | #if START_ARM |
138 | GNUNET_ARM_start_service (arm, "arm", GNUNET_OS_INHERIT_STD_OUT_AND_ERR, START_TIMEOUT, &arm_notify, NULL); | 206 | GNUNET_ARM_request_service_start (arm, "arm", GNUNET_OS_INHERIT_STD_OUT_AND_ERR, START_TIMEOUT, arm_start_cb, NULL); |
139 | #else | 207 | #else |
140 | arm_notify (NULL, GNUNET_YES); | 208 | arm_start_cb (NULL, arm, GNUNET_ARM_REQUEST_SENT_OK, "arm", GNUNET_ARM_RESULT_STARTING); |
209 | arm_conn (NULL, GNUNET_YES, GNUNET_NO); | ||
141 | #endif | 210 | #endif |
142 | } | 211 | } |
143 | 212 | ||
diff --git a/src/arm/test_exponential_backoff.c b/src/arm/test_exponential_backoff.c index 3395139ea..8a0dba117 100644 --- a/src/arm/test_exponential_backoff.c +++ b/src/arm/test_exponential_backoff.c | |||
@@ -43,14 +43,20 @@ static const struct GNUNET_CONFIGURATION_Handle *cfg; | |||
43 | 43 | ||
44 | static struct GNUNET_ARM_Handle *arm; | 44 | static struct GNUNET_ARM_Handle *arm; |
45 | 45 | ||
46 | static struct GNUNET_ARM_MonitorHandle *mon; | ||
47 | |||
46 | static int ok = 1; | 48 | static int ok = 1; |
47 | 49 | ||
50 | static int phase = 0; | ||
51 | |||
48 | static int trialCount; | 52 | static int trialCount; |
49 | 53 | ||
50 | static struct GNUNET_TIME_Absolute startedWaitingAt; | 54 | static struct GNUNET_TIME_Absolute startedWaitingAt; |
51 | 55 | ||
52 | struct GNUNET_TIME_Relative waitedFor; | 56 | struct GNUNET_TIME_Relative waitedFor; |
53 | 57 | ||
58 | struct GNUNET_TIME_Relative waitedFor_prev; | ||
59 | |||
54 | #if LOG_BACKOFF | 60 | #if LOG_BACKOFF |
55 | static FILE *killLogFilePtr; | 61 | static FILE *killLogFilePtr; |
56 | 62 | ||
@@ -97,11 +103,8 @@ struct ShutdownContext | |||
97 | 103 | ||
98 | /** | 104 | /** |
99 | * Handler receiving response to service shutdown requests. | 105 | * Handler receiving response to service shutdown requests. |
100 | * First call with NULL: service misbehaving, or something. | 106 | * We expect it to be called with NULL, since the service that |
101 | * First call with GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN: | 107 | * we are shutting down will just die without replying. |
102 | * - service will shutdown | ||
103 | * Second call with NULL: | ||
104 | * - service has now really shut down. | ||
105 | * | 108 | * |
106 | * @param cls closure | 109 | * @param cls closure |
107 | * @param msg NULL, indicating socket closure. | 110 | * @param msg NULL, indicating socket closure. |
@@ -111,7 +114,7 @@ service_shutdown_handler (void *cls, const struct GNUNET_MessageHeader *msg) | |||
111 | { | 114 | { |
112 | struct ShutdownContext *shutdown_ctx = cls; | 115 | struct ShutdownContext *shutdown_ctx = cls; |
113 | 116 | ||
114 | if (msg == NULL) | 117 | if (NULL == msg) |
115 | { | 118 | { |
116 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Service shutdown complete.\n"); | 119 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Service shutdown complete.\n"); |
117 | if (shutdown_ctx->cont != NULL) | 120 | if (shutdown_ctx->cont != NULL) |
@@ -122,29 +125,7 @@ service_shutdown_handler (void *cls, const struct GNUNET_MessageHeader *msg) | |||
122 | GNUNET_free (shutdown_ctx); | 125 | GNUNET_free (shutdown_ctx); |
123 | return; | 126 | return; |
124 | } | 127 | } |
125 | GNUNET_assert (ntohs (msg->size) == | 128 | GNUNET_assert (0); |
126 | sizeof (struct GNUNET_MessageHeader)); | ||
127 | switch (ntohs (msg->type)) | ||
128 | { | ||
129 | case GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN: | ||
130 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
131 | "Received confirmation for service shutdown.\n"); | ||
132 | shutdown_ctx->confirmed = GNUNET_YES; | ||
133 | GNUNET_CLIENT_receive (shutdown_ctx->sock, | ||
134 | &service_shutdown_handler, shutdown_ctx, | ||
135 | GNUNET_TIME_UNIT_FOREVER_REL); | ||
136 | break; | ||
137 | default: /* Fall through */ | ||
138 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
139 | "Service shutdown refused!\n"); | ||
140 | if (shutdown_ctx->cont != NULL) | ||
141 | shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_YES); | ||
142 | |||
143 | GNUNET_SCHEDULER_cancel (shutdown_ctx->cancel_task); | ||
144 | GNUNET_CLIENT_disconnect (shutdown_ctx->sock); | ||
145 | GNUNET_free (shutdown_ctx); | ||
146 | break; | ||
147 | } | ||
148 | } | 129 | } |
149 | 130 | ||
150 | 131 | ||
@@ -183,25 +164,27 @@ write_shutdown (void *cls, size_t size, void *buf) | |||
183 | struct ShutdownContext *shutdown_ctx = cls; | 164 | struct ShutdownContext *shutdown_ctx = cls; |
184 | 165 | ||
185 | if (size < sizeof (struct GNUNET_MessageHeader)) | 166 | if (size < sizeof (struct GNUNET_MessageHeader)) |
186 | { | 167 | { |
187 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 168 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
188 | _("Failed to transmit shutdown request to client.\n")); | 169 | _("Failed to transmit shutdown request to client.\n")); |
189 | shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_SYSERR); | 170 | FPRINTF (stderr, "%s", "Failed to send a shutdown request\n"); |
190 | GNUNET_CLIENT_disconnect (shutdown_ctx->sock); | 171 | shutdown_ctx->cont (shutdown_ctx->cont_cls, GNUNET_SYSERR); |
191 | GNUNET_free (shutdown_ctx); | 172 | GNUNET_CLIENT_disconnect (shutdown_ctx->sock); |
192 | return 0; /* client disconnected */ | 173 | GNUNET_free (shutdown_ctx); |
193 | } | 174 | return 0; /* client disconnected */ |
175 | } | ||
194 | 176 | ||
195 | GNUNET_CLIENT_receive (shutdown_ctx->sock, &service_shutdown_handler, | 177 | GNUNET_CLIENT_receive (shutdown_ctx->sock, &service_shutdown_handler, |
196 | shutdown_ctx, GNUNET_TIME_UNIT_FOREVER_REL); | 178 | shutdown_ctx, GNUNET_TIME_UNIT_FOREVER_REL); |
197 | shutdown_ctx->cancel_task = | 179 | shutdown_ctx->cancel_task = GNUNET_SCHEDULER_add_delayed ( |
198 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining | 180 | GNUNET_TIME_absolute_get_remaining (shutdown_ctx->timeout), |
199 | (shutdown_ctx->timeout), | 181 | &service_shutdown_cancel, shutdown_ctx); |
200 | &service_shutdown_cancel, shutdown_ctx); | ||
201 | msg = (struct GNUNET_MessageHeader *) buf; | 182 | msg = (struct GNUNET_MessageHeader *) buf; |
202 | msg->type = htons (GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN); | 183 | msg->type = htons (GNUNET_MESSAGE_TYPE_ARM_STOP); |
203 | msg->size = htons (sizeof (struct GNUNET_MessageHeader)); | 184 | msg->size = htons (sizeof (struct GNUNET_MessageHeader)); |
204 | return sizeof (struct GNUNET_MessageHeader); | 185 | strcpy ((char *) &msg[1], "do-nothing"); |
186 | FPRINTF (stderr, "%s", "Sent a shutdown request\n"); | ||
187 | return sizeof (struct GNUNET_MessageHeader) + strlen ("do-nothing") + 1; | ||
205 | } | 188 | } |
206 | 189 | ||
207 | 190 | ||
@@ -219,7 +202,7 @@ write_shutdown (void *cls, size_t size, void *buf) | |||
219 | * | 202 | * |
220 | */ | 203 | */ |
221 | static void | 204 | static void |
222 | arm_service_shutdown (struct GNUNET_CLIENT_Connection *sock, | 205 | do_nothing_service_shutdown (struct GNUNET_CLIENT_Connection *sock, |
223 | struct GNUNET_TIME_Relative timeout, | 206 | struct GNUNET_TIME_Relative timeout, |
224 | GNUNET_CLIENT_ShutdownTask cont, void *cont_cls) | 207 | GNUNET_CLIENT_ShutdownTask cont, void *cont_cls) |
225 | { | 208 | { |
@@ -231,125 +214,132 @@ arm_service_shutdown (struct GNUNET_CLIENT_Connection *sock, | |||
231 | shutdown_ctx->sock = sock; | 214 | shutdown_ctx->sock = sock; |
232 | shutdown_ctx->timeout = GNUNET_TIME_relative_to_absolute (timeout); | 215 | shutdown_ctx->timeout = GNUNET_TIME_relative_to_absolute (timeout); |
233 | GNUNET_CLIENT_notify_transmit_ready (sock, | 216 | GNUNET_CLIENT_notify_transmit_ready (sock, |
234 | sizeof (struct GNUNET_MessageHeader), | 217 | sizeof (struct GNUNET_MessageHeader) + strlen ("do-nothing") + 1, |
235 | timeout, GNUNET_NO, &write_shutdown, | 218 | timeout, GNUNET_NO, &write_shutdown, |
236 | shutdown_ctx); | 219 | shutdown_ctx); |
237 | } | 220 | } |
238 | 221 | ||
239 | |||
240 | static void | ||
241 | arm_notify_stop (void *cls, enum GNUNET_ARM_ProcessStatus status) | ||
242 | { | ||
243 | GNUNET_assert ( (status == GNUNET_ARM_PROCESS_DOWN) || | ||
244 | (status == GNUNET_ARM_PROCESS_ALREADY_DOWN) ); | ||
245 | #if START_ARM | ||
246 | GNUNET_ARM_stop_service (arm, "arm", TIMEOUT, NULL, NULL); | ||
247 | #endif | ||
248 | } | ||
249 | |||
250 | |||
251 | static void | 222 | static void |
252 | kill_task (void *cbData, const struct GNUNET_SCHEDULER_TaskContext *tc); | 223 | kill_task (void *cbData, const struct GNUNET_SCHEDULER_TaskContext *tc); |
253 | 224 | ||
254 | |||
255 | static void | 225 | static void |
256 | do_nothing_notify (void *cls, enum GNUNET_ARM_ProcessStatus status) | 226 | shutdown_cont (void *cls, int reason) |
257 | { | ||
258 | GNUNET_assert (status == GNUNET_ARM_PROCESS_STARTING); | ||
259 | ok = 1; | ||
260 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &kill_task, NULL); | ||
261 | } | ||
262 | |||
263 | static void | ||
264 | arm_notify (void *cls, enum GNUNET_ARM_ProcessStatus status) | ||
265 | { | 227 | { |
266 | GNUNET_assert (status == GNUNET_ARM_PROCESS_STARTING); | 228 | if (GNUNET_NO != reason) |
267 | GNUNET_ARM_start_service (arm, "do-nothing", GNUNET_OS_INHERIT_STD_OUT_AND_ERR, TIMEOUT, &do_nothing_notify, | 229 | { |
268 | NULL); | 230 | /* Re-try shutdown */ |
231 | FPRINTF (stderr, "%s", "do-nothing didn't die, trying again\n"); | ||
232 | GNUNET_SCHEDULER_add_now (kill_task, NULL); | ||
233 | return; | ||
234 | } | ||
235 | startedWaitingAt = GNUNET_TIME_absolute_get (); | ||
236 | FPRINTF (stderr, "%s", "do-nothing is dead, starting the countdown\n"); | ||
269 | } | 237 | } |
270 | 238 | ||
271 | |||
272 | static void | 239 | static void |
273 | kill_task (void *cbData, const struct GNUNET_SCHEDULER_TaskContext *tc); | 240 | kill_task (void *cbData, const struct GNUNET_SCHEDULER_TaskContext *tc) |
274 | |||
275 | |||
276 | static void | ||
277 | do_nothing_restarted_notify_task (void *cls, | ||
278 | const struct GNUNET_SCHEDULER_TaskContext | ||
279 | *tc) | ||
280 | { | 241 | { |
281 | static char a; | 242 | static struct GNUNET_CLIENT_Connection *doNothingConnection = NULL; |
282 | |||
283 | trialCount++; | ||
284 | 243 | ||
244 | if (NULL != cbData) | ||
245 | { | ||
246 | waitedFor = GNUNET_TIME_absolute_get_duration (startedWaitingAt); | ||
247 | FPRINTF (stderr, "Waited for: %llu ms\n", waitedFor.rel_value); | ||
285 | #if LOG_BACKOFF | 248 | #if LOG_BACKOFF |
286 | if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0) | 249 | FPRINTF (killLogFilePtr, "Waited for: %llu ms\n", |
287 | { | 250 | (unsigned long long) waitedFor.rel_value); |
288 | FPRINTF (killLogFilePtr, "%d.Reason is shutdown!\n", trialCount); | ||
289 | } | ||
290 | else if ((tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT) != 0) | ||
291 | { | ||
292 | FPRINTF (killLogFilePtr, "%d.Reason is timeout!\n", trialCount); | ||
293 | } | ||
294 | else if ((tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE) != 0) | ||
295 | { | ||
296 | FPRINTF (killLogFilePtr, "%d.Service is running!\n", trialCount); | ||
297 | } | ||
298 | #endif | 251 | #endif |
299 | GNUNET_SCHEDULER_add_now (&kill_task, &a); | 252 | } |
253 | else | ||
254 | { | ||
255 | waitedFor.rel_value = 0; | ||
256 | } | ||
257 | /* Connect to the doNothing task */ | ||
258 | doNothingConnection = GNUNET_CLIENT_connect ("do-nothing", cfg); | ||
259 | GNUNET_assert (doNothingConnection != NULL); | ||
260 | if (trialCount == 12) | ||
261 | waitedFor_prev = waitedFor; | ||
262 | else if (trialCount == 13) | ||
263 | { | ||
264 | GNUNET_CLIENT_disconnect (doNothingConnection); | ||
265 | GNUNET_ARM_request_service_stop (arm, "do-nothing", TIMEOUT, NULL, NULL); | ||
266 | if (waitedFor_prev.rel_value >= waitedFor.rel_value) | ||
267 | ok = 9; | ||
268 | else | ||
269 | ok = 0; | ||
270 | trialCount += 1; | ||
271 | return; | ||
272 | } | ||
273 | trialCount += 1; | ||
274 | /* Use the created connection to kill the doNothingTask */ | ||
275 | do_nothing_service_shutdown (doNothingConnection, | ||
276 | TIMEOUT, &shutdown_cont, NULL); | ||
300 | } | 277 | } |
301 | 278 | ||
302 | |||
303 | static void | 279 | static void |
304 | do_test (void *cbData, const struct GNUNET_SCHEDULER_TaskContext *tc) | 280 | trigger_disconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) |
305 | { | 281 | { |
306 | GNUNET_CLIENT_service_test ("do-nothing", cfg, TIMEOUT, | 282 | GNUNET_ARM_disconnect (arm); |
307 | &do_nothing_restarted_notify_task, NULL); | 283 | GNUNET_ARM_monitor_disconnect (mon); |
308 | } | 284 | } |
309 | 285 | ||
310 | 286 | ||
311 | static void | 287 | static void |
312 | shutdown_cont (void *cls, int reason) | 288 | arm_stop_cb (void *cls, struct GNUNET_ARM_Handle *h, enum GNUNET_ARM_RequestStatus status, const char *servicename, enum GNUNET_ARM_Result result) |
313 | { | 289 | { |
314 | trialCount++; | 290 | GNUNET_break (status == GNUNET_ARM_REQUEST_SENT_OK); |
315 | startedWaitingAt = GNUNET_TIME_absolute_get (); | 291 | GNUNET_break (result == GNUNET_ARM_RESULT_STOPPING); |
316 | GNUNET_SCHEDULER_add_delayed (waitedFor, &do_test, NULL); | 292 | FPRINTF (stderr, "%s", "ARM service stopped\n"); |
293 | GNUNET_SCHEDULER_add_now (trigger_disconnect, NULL); | ||
317 | } | 294 | } |
318 | 295 | ||
319 | 296 | void | |
320 | static void | 297 | srv_status (void *cls, struct GNUNET_ARM_MonitorHandle *mon, const char *service, enum GNUNET_ARM_ServiceStatus status) |
321 | kill_task (void *cbData, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
322 | { | 298 | { |
323 | static struct GNUNET_CLIENT_Connection *doNothingConnection = NULL; | 299 | FPRINTF (stderr, "Service %s is %u, phase %u\n", service, status, phase); |
324 | 300 | if (status == GNUNET_ARM_SERVICE_MONITORING_STARTED) | |
325 | if (NULL != cbData) | 301 | { |
326 | { | 302 | phase++; |
327 | waitedFor = GNUNET_TIME_absolute_get_duration (startedWaitingAt); | 303 | GNUNET_ARM_request_service_start (arm, "do-nothing", |
328 | 304 | GNUNET_OS_INHERIT_STD_OUT_AND_ERR, TIMEOUT, NULL, NULL); | |
329 | #if LOG_BACKOFF | 305 | return; |
330 | FPRINTF (killLogFilePtr, "Waited for: %llu ms\n", | 306 | } |
331 | (unsigned long long) waitedFor.rel_value); | 307 | if (phase == 1) |
332 | #endif | 308 | { |
333 | } | 309 | GNUNET_break (status == GNUNET_ARM_SERVICE_STARTING); |
334 | else | 310 | GNUNET_break (0 == strcasecmp (service, "do-nothing")); |
311 | GNUNET_break (phase == 1); | ||
312 | FPRINTF (stderr, "%s", "do-nothing is starting\n"); | ||
313 | phase++; | ||
314 | ok = 1; | ||
315 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &kill_task, NULL); | ||
316 | } | ||
317 | else if ((phase == 2) && (strcasecmp ("do-nothing", service) == 0)) | ||
318 | { | ||
319 | /* We passively monitor ARM for status updates. ARM should tell us | ||
320 | * when do-nothing dies (no need to run a service upness test ourselves). | ||
321 | */ | ||
322 | if (status == GNUNET_ARM_SERVICE_STARTING) | ||
335 | { | 323 | { |
336 | waitedFor.rel_value = 0; | 324 | FPRINTF (stderr, "%s", "do-nothing is starting\n"); |
325 | GNUNET_SCHEDULER_add_now (kill_task, &ok); | ||
337 | } | 326 | } |
338 | /* Connect to the doNothing task */ | 327 | else if ((status == GNUNET_ARM_SERVICE_STOPPED) && (trialCount == 14)) |
339 | doNothingConnection = GNUNET_CLIENT_connect ("do-nothing", cfg); | ||
340 | GNUNET_assert (doNothingConnection != NULL); | ||
341 | if (trialCount == 12) | ||
342 | { | 328 | { |
343 | GNUNET_CLIENT_disconnect (doNothingConnection); | 329 | phase++; |
344 | GNUNET_ARM_stop_service (arm, "do-nothing", TIMEOUT, &arm_notify_stop, | 330 | GNUNET_ARM_request_service_stop (arm, "arm", TIMEOUT, arm_stop_cb, NULL); |
345 | NULL); | ||
346 | ok = 0; | ||
347 | return; | ||
348 | } | 331 | } |
349 | /* Use the created connection to kill the doNothingTask */ | 332 | } |
350 | arm_service_shutdown (doNothingConnection, TIMEOUT, &shutdown_cont, NULL); | ||
351 | } | 333 | } |
352 | 334 | ||
335 | static void | ||
336 | arm_start_cb (void *cls, struct GNUNET_ARM_Handle *h, enum GNUNET_ARM_RequestStatus status, const char *servicename, enum GNUNET_ARM_Result result) | ||
337 | { | ||
338 | GNUNET_break (status == GNUNET_ARM_REQUEST_SENT_OK); | ||
339 | GNUNET_break (result == GNUNET_ARM_RESULT_STARTING); | ||
340 | GNUNET_break (phase == 0); | ||
341 | FPRINTF (stderr, "Sent 'START' request for arm to ARM %s\n", (status == GNUNET_ARM_REQUEST_SENT_OK) ? "successfully" : "unsuccessfully"); | ||
342 | } | ||
353 | 343 | ||
354 | static void | 344 | static void |
355 | task (void *cls, char *const *args, const char *cfgfile, | 345 | task (void *cls, char *const *args, const char *cfgfile, |
@@ -359,9 +349,8 @@ task (void *cls, char *const *args, const char *cfgfile, | |||
359 | cfg = c; | 349 | cfg = c; |
360 | if (NULL != cfgfile) | 350 | if (NULL != cfgfile) |
361 | { | 351 | { |
362 | if (GNUNET_OK != | 352 | if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (cfg, "arm", |
363 | GNUNET_CONFIGURATION_get_value_filename (cfg, "arm", "CONFIG", | 353 | "CONFIG", &armconfig)) |
364 | &armconfig)) | ||
365 | { | 354 | { |
366 | GNUNET_CONFIGURATION_set_value_string ((struct GNUNET_CONFIGURATION_Handle | 355 | GNUNET_CONFIGURATION_set_value_string ((struct GNUNET_CONFIGURATION_Handle |
367 | *) cfg, "arm", "CONFIG", | 356 | *) cfg, "arm", "CONFIG", |
@@ -371,16 +360,18 @@ task (void *cls, char *const *args, const char *cfgfile, | |||
371 | GNUNET_free (armconfig); | 360 | GNUNET_free (armconfig); |
372 | } | 361 | } |
373 | 362 | ||
374 | arm = GNUNET_ARM_connect (cfg, NULL); | 363 | arm = GNUNET_ARM_alloc (cfg); |
364 | GNUNET_ARM_connect (arm, NULL, NULL); | ||
365 | mon = GNUNET_ARM_monitor_alloc (cfg); | ||
366 | GNUNET_ARM_monitor (mon, srv_status, NULL); | ||
375 | #if START_ARM | 367 | #if START_ARM |
376 | GNUNET_ARM_start_service (arm, "arm", GNUNET_OS_INHERIT_STD_OUT_AND_ERR, GNUNET_TIME_UNIT_ZERO, &arm_notify, | 368 | GNUNET_ARM_request_service_start (arm, "arm", |
377 | NULL); | 369 | GNUNET_OS_INHERIT_STD_OUT_AND_ERR, GNUNET_TIME_UNIT_ZERO, arm_start_cb, NULL); |
378 | #else | 370 | #else |
379 | arm_do_nothing (NULL, GNUNET_YES); | 371 | arm_start_cb (NULL, arm, GNUNET_ARM_REQUEST_SENT_OK, "arm", GNUNET_ARM_SERVICE_STARTING); |
380 | #endif | 372 | #endif |
381 | } | 373 | } |
382 | 374 | ||
383 | |||
384 | static int | 375 | static int |
385 | check () | 376 | check () |
386 | { | 377 | { |
diff --git a/src/arm/test_gnunet_service_arm.c b/src/arm/test_gnunet_service_arm.c index 9e9286ac1..bd7fe5fa9 100644 --- a/src/arm/test_gnunet_service_arm.c +++ b/src/arm/test_gnunet_service_arm.c | |||
@@ -42,23 +42,22 @@ static int ret = 1; | |||
42 | 42 | ||
43 | static struct GNUNET_ARM_Handle *arm; | 43 | static struct GNUNET_ARM_Handle *arm; |
44 | 44 | ||
45 | |||
46 | static void | 45 | static void |
47 | arm_stopped (void *cls, enum GNUNET_ARM_ProcessStatus success) | 46 | trigger_disconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) |
48 | { | 47 | { |
49 | if (success != GNUNET_ARM_PROCESS_DOWN) | ||
50 | { | ||
51 | GNUNET_break (0); | ||
52 | ret = 4; | ||
53 | } | ||
54 | else | ||
55 | { | ||
56 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ARM stopped\n"); | ||
57 | } | ||
58 | GNUNET_ARM_disconnect (arm); | 48 | GNUNET_ARM_disconnect (arm); |
59 | arm = NULL; | 49 | arm = NULL; |
60 | } | 50 | } |
61 | 51 | ||
52 | static void | ||
53 | arm_stop_cb (void *cls, struct GNUNET_ARM_Handle *h, enum GNUNET_ARM_RequestStatus status, const char *servicename, enum GNUNET_ARM_Result result) | ||
54 | { | ||
55 | GNUNET_break (status == GNUNET_ARM_REQUEST_SENT_OK); | ||
56 | GNUNET_break (result == GNUNET_ARM_RESULT_STOPPING); | ||
57 | if (result != GNUNET_ARM_RESULT_STOPPING) | ||
58 | ret = 4; | ||
59 | GNUNET_SCHEDULER_add_now (trigger_disconnect, NULL); | ||
60 | } | ||
62 | 61 | ||
63 | static void | 62 | static void |
64 | hostNameResolveCB (void *cls, const struct sockaddr *addr, socklen_t addrlen) | 63 | hostNameResolveCB (void *cls, const struct sockaddr *addr, socklen_t addrlen) |
@@ -66,43 +65,37 @@ hostNameResolveCB (void *cls, const struct sockaddr *addr, socklen_t addrlen) | |||
66 | if ((ret == 0) || (ret == 4)) | 65 | if ((ret == 0) || (ret == 4)) |
67 | return; | 66 | return; |
68 | if (NULL == addr) | 67 | if (NULL == addr) |
69 | { | 68 | { |
70 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Name not resolved!\n"); | 69 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Name not resolved!\n"); |
71 | GNUNET_ARM_stop_service (arm, "arm", TIMEOUT, &arm_stopped, NULL); | 70 | ret = 3; |
72 | ret = 3; | 71 | } |
73 | return; | 72 | else |
74 | } | 73 | { |
75 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 74 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
76 | "Resolved hostname, now stopping ARM\n"); | 75 | "Resolved hostname, now stopping ARM\n"); |
77 | ret = 0; | 76 | ret = 0; |
78 | GNUNET_ARM_stop_service (arm, "arm", TIMEOUT, &arm_stopped, NULL); | 77 | } |
78 | GNUNET_ARM_request_service_stop (arm, "arm", TIMEOUT, arm_stop_cb, NULL); | ||
79 | } | 79 | } |
80 | 80 | ||
81 | |||
82 | static void | 81 | static void |
83 | arm_notify (void *cls, enum GNUNET_ARM_ProcessStatus success) | 82 | arm_start_cb (void *cls, struct GNUNET_ARM_Handle *h, enum GNUNET_ARM_RequestStatus status, const char *servicename, enum GNUNET_ARM_Result result) |
84 | { | 83 | { |
85 | if (success != GNUNET_ARM_PROCESS_STARTING) | 84 | GNUNET_break (status == GNUNET_ARM_REQUEST_SENT_OK); |
86 | { | 85 | GNUNET_break (result == GNUNET_ARM_RESULT_STARTING); |
87 | GNUNET_break (0); | ||
88 | ret = 1; | ||
89 | return; | ||
90 | } | ||
91 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 86 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
92 | "Trying to resolve our own hostname!\n"); | 87 | "Trying to resolve our own hostname!\n"); |
93 | /* connect to the resolver service */ | 88 | /* connect to the resolver service */ |
94 | if (NULL == | 89 | if (NULL == GNUNET_RESOLVER_hostname_resolve ( |
95 | GNUNET_RESOLVER_hostname_resolve (AF_UNSPEC, TIMEOUT, | 90 | AF_UNSPEC, TIMEOUT, &hostNameResolveCB, NULL)) |
96 | &hostNameResolveCB, NULL)) | 91 | { |
97 | { | 92 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
98 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 93 | "Unable initiate connection to resolver service\n"); |
99 | "Unable initiate connection to resolver service\n"); | 94 | ret = 2; |
100 | ret = 2; | 95 | GNUNET_ARM_request_service_stop (arm, "arm", TIMEOUT, arm_stop_cb, NULL); |
101 | GNUNET_ARM_stop_service (arm, "arm", TIMEOUT, &arm_stopped, NULL); | 96 | } |
102 | } | ||
103 | } | 97 | } |
104 | 98 | ||
105 | |||
106 | static void | 99 | static void |
107 | run (void *cls, char *const *args, const char *cfgfile, | 100 | run (void *cls, char *const *args, const char *cfgfile, |
108 | const struct GNUNET_CONFIGURATION_Handle *c) | 101 | const struct GNUNET_CONFIGURATION_Handle *c) |
@@ -122,10 +115,10 @@ run (void *cls, char *const *args, const char *cfgfile, | |||
122 | else | 115 | else |
123 | GNUNET_free (armconfig); | 116 | GNUNET_free (armconfig); |
124 | } | 117 | } |
125 | arm = GNUNET_ARM_connect (c, NULL); | 118 | arm = GNUNET_ARM_alloc (c); |
126 | GNUNET_ARM_start_service (arm, "arm", | 119 | GNUNET_ARM_connect (arm, NULL, NULL); |
127 | GNUNET_OS_INHERIT_STD_OUT_AND_ERR, START_TIMEOUT, | 120 | GNUNET_ARM_request_service_start (arm, "arm", |
128 | &arm_notify, NULL); | 121 | GNUNET_OS_INHERIT_STD_OUT_AND_ERR, START_TIMEOUT, arm_start_cb, NULL); |
129 | } | 122 | } |
130 | 123 | ||
131 | 124 | ||
diff --git a/src/include/gnunet_arm_service.h b/src/include/gnunet_arm_service.h index 0aa916bd4..be46831a4 100644 --- a/src/include/gnunet_arm_service.h +++ b/src/include/gnunet_arm_service.h | |||
@@ -43,112 +43,208 @@ extern "C" | |||
43 | /** | 43 | /** |
44 | * Version of the arm API. | 44 | * Version of the arm API. |
45 | */ | 45 | */ |
46 | #define GNUNET_ARM_VERSION 0x00000001 | 46 | #define GNUNET_ARM_VERSION 0x00000002 |
47 | 47 | ||
48 | 48 | ||
49 | /** | 49 | /** |
50 | * Values characterizing GNUnet process states. | 50 | * Statuses of the requests that client can send to ARM. |
51 | */ | 51 | */ |
52 | enum GNUNET_ARM_ProcessStatus | 52 | enum GNUNET_ARM_RequestStatus |
53 | { | 53 | { |
54 | /** | 54 | /** |
55 | * Service name is unknown to ARM. | 55 | * Message was sent successfully. |
56 | */ | 56 | */ |
57 | GNUNET_ARM_PROCESS_UNKNOWN = -1, | 57 | GNUNET_ARM_REQUEST_SENT_OK = 0, |
58 | 58 | ||
59 | /** | 59 | /** |
60 | * Service is now down (due to client request). | 60 | * Misconfiguration (can't connect to the ARM service). |
61 | */ | 61 | */ |
62 | GNUNET_ARM_PROCESS_DOWN = 0, | 62 | GNUNET_ARM_REQUEST_CONFIGURATION_ERROR = 1, |
63 | 63 | ||
64 | /** | 64 | /** |
65 | * Service is already running. | 65 | * We disconnected from ARM, and request was not sent. |
66 | */ | 66 | */ |
67 | GNUNET_ARM_PROCESS_ALREADY_RUNNING = 1, | 67 | GNUNET_ARM_REQUEST_DISCONNECTED = 2, |
68 | 68 | ||
69 | /** | 69 | /** |
70 | * Service is currently being started (due to client request). | 70 | * ARM API is busy (probably trying to connect to ARM), |
71 | * and request was not sent. Try again later. | ||
71 | */ | 72 | */ |
72 | GNUNET_ARM_PROCESS_STARTING = 2, | 73 | GNUNET_ARM_REQUEST_BUSY = 3, |
73 | 74 | ||
74 | /** | 75 | /** |
75 | * Service is already being stopped by some other client. | 76 | * It was discovered that the request would be too long to fit in a message, |
77 | * and thus it was not sent. | ||
76 | */ | 78 | */ |
77 | GNUNET_ARM_PROCESS_ALREADY_STOPPING = 3, | 79 | GNUNET_ARM_REQUEST_TOO_LONG = 4, |
78 | 80 | ||
79 | /** | 81 | /** |
80 | * Service is already down (no action taken) | 82 | * Request time ran out before we had a chance to send it. |
81 | */ | 83 | */ |
82 | GNUNET_ARM_PROCESS_ALREADY_DOWN = 4, | 84 | GNUNET_ARM_REQUEST_TIMEOUT = 5 |
85 | |||
86 | }; | ||
87 | |||
83 | 88 | ||
89 | /** | ||
90 | * Statuses of services. | ||
91 | */ | ||
92 | enum GNUNET_ARM_ServiceStatus | ||
93 | { | ||
84 | /** | 94 | /** |
85 | * ARM is currently being shut down (no more process starts) | 95 | * Dummy message. |
86 | */ | 96 | */ |
87 | GNUNET_ARM_PROCESS_SHUTDOWN = 5, | 97 | GNUNET_ARM_SERVICE_MONITORING_STARTED = 0, |
88 | 98 | ||
89 | /** | 99 | /** |
90 | * Error in communication with ARM | 100 | * Service was stopped. |
91 | */ | 101 | */ |
92 | GNUNET_ARM_PROCESS_COMMUNICATION_ERROR = 6, | 102 | GNUNET_ARM_SERVICE_STOPPED = 1, |
93 | 103 | ||
94 | /** | 104 | /** |
95 | * Timeout in communication with ARM | 105 | * Service starting was initiated |
96 | */ | 106 | */ |
97 | GNUNET_ARM_PROCESS_COMMUNICATION_TIMEOUT = 7, | 107 | GNUNET_ARM_SERVICE_STARTING = 2, |
98 | 108 | ||
99 | /** | 109 | /** |
100 | * Failure to perform operation | 110 | * Service stopping was initiated |
101 | */ | 111 | */ |
102 | GNUNET_ARM_PROCESS_FAILURE = 8 | 112 | GNUNET_ARM_SERVICE_STOPPING = 3 |
103 | }; | 113 | }; |
104 | 114 | ||
115 | /** | ||
116 | * Replies to ARM requests | ||
117 | */ | ||
118 | enum GNUNET_ARM_Result | ||
119 | { | ||
120 | /** | ||
121 | * Service was stopped (never sent for ARM itself). | ||
122 | */ | ||
123 | GNUNET_ARM_RESULT_STOPPED = 0, | ||
124 | |||
125 | /** | ||
126 | * ARM stopping was initiated (there's no "stopped" for ARM itself). | ||
127 | */ | ||
128 | GNUNET_ARM_RESULT_STOPPING = 1, | ||
129 | |||
130 | /** | ||
131 | * Service starting was initiated | ||
132 | */ | ||
133 | GNUNET_ARM_RESULT_STARTING = 2, | ||
134 | |||
135 | /** | ||
136 | * Asked to start it, but it's already starting. | ||
137 | */ | ||
138 | GNUNET_ARM_RESULT_IS_STARTING_ALREADY = 3, | ||
139 | |||
140 | /** | ||
141 | * Asked to stop it, but it's already stopping. | ||
142 | */ | ||
143 | GNUNET_ARM_RESULT_IS_STOPPING_ALREADY = 4, | ||
144 | |||
145 | /** | ||
146 | * Asked to start it, but it's already started. | ||
147 | */ | ||
148 | GNUNET_ARM_RESULT_IS_STARTED_ALREADY = 5, | ||
149 | |||
150 | /** | ||
151 | * Asked to stop it, but it's already stopped. | ||
152 | */ | ||
153 | GNUNET_ARM_RESULT_IS_STOPPED_ALREADY = 6, | ||
154 | |||
155 | /** | ||
156 | * Asked to start or stop a service, but it's not known. | ||
157 | */ | ||
158 | GNUNET_ARM_RESULT_IS_NOT_KNOWN = 7, | ||
159 | |||
160 | /** | ||
161 | * Tried to start a service, but that failed for some reason. | ||
162 | */ | ||
163 | GNUNET_ARM_RESULT_START_FAILED = 8, | ||
164 | |||
165 | /** | ||
166 | * Asked to start something, but ARM is shutting down and can't comply. | ||
167 | */ | ||
168 | GNUNET_ARM_RESULT_IN_SHUTDOWN = 9 | ||
169 | }; | ||
170 | |||
171 | |||
172 | /** | ||
173 | * Handle for interacting with ARM. | ||
174 | */ | ||
175 | struct GNUNET_ARM_Handle; | ||
176 | |||
105 | 177 | ||
106 | /** | 178 | /** |
107 | * Callback function invoked when operation is complete. | 179 | * Function called whenever we connect to or disconnect from ARM. |
108 | * | 180 | * |
109 | * @param cls closure | 181 | * @param cls closure |
110 | * @param result outcome of the operation | 182 | * @param connected GNUNET_YES if connected, GNUNET_NO if disconnected |
183 | * @param error GNUNET_YES if we encountered a permanent error, and there | ||
184 | * will be no re-connection. | ||
111 | */ | 185 | */ |
112 | typedef void (*GNUNET_ARM_Callback) (void *cls, | 186 | typedef void (*GNUNET_ARM_ConnectionStatusCallback) (void *cls, struct GNUNET_ARM_Handle *arm, unsigned char connected, unsigned char error); |
113 | enum GNUNET_ARM_ProcessStatus result); | 187 | |
114 | 188 | ||
115 | /** | 189 | /** |
116 | * Callback function invoked when list operation is complete. | 190 | * Function called in response to a start/stop request. |
191 | * Will be called when request was not sent successfully, | ||
192 | * or when a reply comes. If the request was not sent successfully, | ||
193 | * 'rs' will indicate that, and 'service' and 'result' will be undefined. | ||
117 | * | 194 | * |
118 | * @param cls closure | 195 | * @param cls closure |
119 | * @param result outcome of the operation (GNUNET_YES if successful) | 196 | * @param arm handle to the arm connection |
120 | * @param count number of strings in the list | 197 | * @param rs status of the request |
121 | * @param list list of running services | 198 | * @param service service name |
199 | * @param result result of the operation | ||
122 | */ | 200 | */ |
123 | typedef void (*GNUNET_ARM_List_Callback) (void *cls, | 201 | typedef void (*GNUNET_ARM_ResultCallback) (void *cls, struct GNUNET_ARM_Handle *arm, enum GNUNET_ARM_RequestStatus rs, const char *service, enum GNUNET_ARM_Result result); |
124 | int result, | ||
125 | unsigned int count, | ||
126 | const char *const *list); | ||
127 | 202 | ||
128 | 203 | ||
129 | /** | 204 | /** |
130 | * Handle for interacting with ARM. | 205 | * Callback function invoked when list operation is complete. |
206 | * Will be called when request was not sent successfully, | ||
207 | * or when a reply comes. If the request was not sent successfully, | ||
208 | * 'rs' will indicate that, and 'count' and 'list' will be undefined. | ||
209 | * | ||
210 | * @param cls closure | ||
211 | * @param arm handle to the arm connection | ||
212 | * @param rs status of the request | ||
213 | * @param count number of strings in the list | ||
214 | * @param list list of running services | ||
131 | */ | 215 | */ |
132 | struct GNUNET_ARM_Handle; | 216 | typedef void (*GNUNET_ARM_ServiceListCallback) (void *cls, struct GNUNET_ARM_Handle *arm, enum GNUNET_ARM_RequestStatus rs, unsigned int count, const char *const*list); |
133 | 217 | ||
134 | 218 | ||
135 | /** | 219 | /** |
136 | * Setup a context for communicating with ARM. Note that this | 220 | * Setup a context for communicating with ARM. Note that this |
137 | * can be done even if the ARM service is not yet running. | 221 | * can be done even if the ARM service is not yet running. |
222 | * Never fails. | ||
138 | * | 223 | * |
139 | * @param cfg configuration to use (needed to contact ARM; | 224 | * @param cfg configuration to use (needed to contact ARM; |
140 | * the ARM service may internally use a different | 225 | * the ARM service may internally use a different |
141 | * configuration to determine how to start the service). | 226 | * configuration to determine how to start the service). |
142 | * @param service service that *this* process is implementing/providing, can be NULL | 227 | * @return context to use for further ARM operations |
143 | * @return context to use for further ARM operations, NULL on error | ||
144 | */ | 228 | */ |
145 | struct GNUNET_ARM_Handle * | 229 | struct GNUNET_ARM_Handle * |
146 | GNUNET_ARM_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, | 230 | GNUNET_ARM_alloc (const struct GNUNET_CONFIGURATION_Handle *cfg); |
147 | const char *service); | 231 | |
232 | /** | ||
233 | * Start connecting to the ARM service using the context. | ||
234 | * @param conn_status called when we (dis)connect from/to ARM. | ||
235 | * It's also called on connection errors. | ||
236 | * @param cls closure for conn_status | ||
237 | * | ||
238 | * @param h ARM handle | ||
239 | */ | ||
240 | void | ||
241 | GNUNET_ARM_connect (struct GNUNET_ARM_Handle *h, | ||
242 | GNUNET_ARM_ConnectionStatusCallback conn_status, void *cls); | ||
148 | 243 | ||
149 | 244 | ||
150 | /** | 245 | /** |
151 | * Disconnect from the ARM service. | 246 | * Disconnect from the ARM service and destroy the handle. |
247 | * Don't call this from inside an ARM callback! | ||
152 | * | 248 | * |
153 | * @param h the handle that was being used | 249 | * @param h the handle that was being used |
154 | */ | 250 | */ |
@@ -157,60 +253,107 @@ GNUNET_ARM_disconnect (struct GNUNET_ARM_Handle *h); | |||
157 | 253 | ||
158 | 254 | ||
159 | /** | 255 | /** |
160 | * Start a service. Note that this function merely asks ARM to start | 256 | * Request a list of running services. |
161 | * the service and that ARM merely confirms that it forked the | ||
162 | * respective process. The specified callback may thus return before | ||
163 | * the service has started to listen on the server socket and it may | ||
164 | * also be that the service has crashed in the meantime. Clients | ||
165 | * should repeatedly try to connect to the service at the respective | ||
166 | * port (with some delays in between) before assuming that the service | ||
167 | * actually failed to start. Note that if an error is returned to the | ||
168 | * callback, clients obviously should not bother with trying to | ||
169 | * contact the service. | ||
170 | * | 257 | * |
171 | * @param h handle to ARM | 258 | * @param h handle to ARM |
172 | * @param service_name name of the service | ||
173 | * @param std_inheritance flags controlling std descriptors inheritance | ||
174 | * @param timeout how long to wait before failing for good | 259 | * @param timeout how long to wait before failing for good |
175 | * @param cb callback to invoke when service is ready | 260 | * @param cont callback to invoke after request is sent or is not sent |
176 | * @param cb_cls closure for callback | 261 | * @param cont_cls closure for callback |
177 | */ | 262 | */ |
178 | void | 263 | void |
179 | GNUNET_ARM_start_service (struct GNUNET_ARM_Handle *h, const char *service_name, | 264 | GNUNET_ARM_request_service_list (struct GNUNET_ARM_Handle *h, |
180 | enum GNUNET_OS_InheritStdioFlags std_inheritance, | 265 | struct GNUNET_TIME_Relative timeout, |
181 | struct GNUNET_TIME_Relative timeout, | 266 | GNUNET_ARM_ServiceListCallback cont, void *cont_cls); |
182 | GNUNET_ARM_Callback cb, void *cb_cls); | ||
183 | 267 | ||
184 | 268 | ||
185 | /** | 269 | /** |
186 | * Stop a service. Note that the callback is invoked as soon | 270 | * Request a service to be stopped. |
187 | * as ARM confirms that it will ask the service to terminate. | 271 | * Stopping arm itself will not invalidate its handle, and |
188 | * The actual termination may still take some time. | 272 | * ARM API will try to restore connection to the ARM service, |
273 | * even if ARM connection was lost because you asked for ARM to be stopped. | ||
274 | * Call GNUNET_ARM_disconnect () to free the handle and prevent | ||
275 | * further connection attempts. | ||
189 | * | 276 | * |
190 | * @param h handle to ARM | 277 | * @param h handle to ARM |
191 | * @param service_name name of the service | 278 | * @param service_name name of the service |
192 | * @param timeout how long to wait before failing for good | 279 | * @param timeout how long to wait before failing for good |
193 | * @param cb callback to invoke when service is ready | 280 | * @param cont callback to invoke after request is sent or is not sent |
194 | * @param cb_cls closure for callback | 281 | * @param cont_cls closure for callback |
195 | */ | 282 | */ |
196 | void | 283 | void |
197 | GNUNET_ARM_stop_service (struct GNUNET_ARM_Handle *h, const char *service_name, | 284 | GNUNET_ARM_request_service_stop (struct GNUNET_ARM_Handle *h, |
198 | struct GNUNET_TIME_Relative timeout, | 285 | const char *service_name, struct GNUNET_TIME_Relative timeout, |
199 | GNUNET_ARM_Callback cb, void *cb_cls); | 286 | GNUNET_ARM_ResultCallback cont, void *cont_cls); |
200 | 287 | ||
201 | 288 | ||
202 | /** | 289 | /** |
203 | * List all running services. | 290 | * Request for a service to be started. |
204 | * | 291 | * |
205 | * @param h handle to ARM | 292 | * @param h handle to ARM |
293 | * @param service_name name of the service | ||
294 | * @param std_inheritance inheritance of std streams | ||
206 | * @param timeout how long to wait before failing for good | 295 | * @param timeout how long to wait before failing for good |
207 | * @param cb callback to invoke when service is ready | 296 | * @param cont callback to invoke after request is sent or not sent |
208 | * @param cb_cls closure for callback | 297 | * @param cont_cls closure for callback |
209 | */ | 298 | */ |
210 | void | 299 | void |
211 | GNUNET_ARM_list_running_services (struct GNUNET_ARM_Handle *h, | 300 | GNUNET_ARM_request_service_start (struct GNUNET_ARM_Handle *h, |
212 | struct GNUNET_TIME_Relative timeout, | 301 | const char *service_name, enum GNUNET_OS_InheritStdioFlags std_inheritance, |
213 | GNUNET_ARM_List_Callback cb, void *cb_cls); | 302 | struct GNUNET_TIME_Relative timeout, GNUNET_ARM_ResultCallback cont, |
303 | void *cont_cls); | ||
304 | |||
305 | |||
306 | /** | ||
307 | * Handle for monitoring ARM. | ||
308 | */ | ||
309 | struct GNUNET_ARM_MonitorHandle; | ||
310 | |||
311 | |||
312 | /** | ||
313 | * Function called in when a status update arrives. | ||
314 | * | ||
315 | * @param cls closure | ||
316 | * @param arm handle to the arm connection | ||
317 | * @param service service name | ||
318 | * @param status status of the service | ||
319 | */ | ||
320 | typedef void (*GNUNET_ARM_ServiceStatusCallback) (void *cls, struct GNUNET_ARM_MonitorHandle *arm, const char *service, enum GNUNET_ARM_ServiceStatus status); | ||
321 | |||
322 | |||
323 | /** | ||
324 | * Setup a context for monitoring ARM. Note that this | ||
325 | * can be done even if the ARM service is not yet running. | ||
326 | * Never fails. | ||
327 | * | ||
328 | * @param cfg configuration to use (needed to contact ARM; | ||
329 | * the ARM service may internally use a different | ||
330 | * configuration to determine how to start the service). | ||
331 | * @return context to use for further ARM monitor operations | ||
332 | */ | ||
333 | struct GNUNET_ARM_MonitorHandle * | ||
334 | GNUNET_ARM_monitor_alloc (const struct GNUNET_CONFIGURATION_Handle *cfg); | ||
335 | |||
336 | /** | ||
337 | * Start connecting to the ARM service for monitoring using the context. | ||
338 | * | ||
339 | * @param h ARM monitor handle | ||
340 | * @param cont callback to invoke on status updates | ||
341 | * @param cont_cls closure | ||
342 | */ | ||
343 | void | ||
344 | GNUNET_ARM_monitor (struct GNUNET_ARM_MonitorHandle *h, | ||
345 | GNUNET_ARM_ServiceStatusCallback cont, void *cont_cls); | ||
346 | |||
347 | |||
348 | /** | ||
349 | * Disconnect from the ARM service and destroy the handle. | ||
350 | * Don't call this from inside an ARM callback! | ||
351 | * | ||
352 | * @param h the handle that was being used | ||
353 | */ | ||
354 | void | ||
355 | GNUNET_ARM_monitor_disconnect (struct GNUNET_ARM_MonitorHandle *h); | ||
356 | |||
214 | 357 | ||
215 | #if 0 /* keep Emacsens' auto-indent happy */ | 358 | #if 0 /* keep Emacsens' auto-indent happy */ |
216 | { | 359 | { |
diff --git a/src/include/gnunet_protocols.h b/src/include/gnunet_protocols.h index 222924cf8..9d65c66c2 100644 --- a/src/include/gnunet_protocols.h +++ b/src/include/gnunet_protocols.h | |||
@@ -78,14 +78,14 @@ extern "C" | |||
78 | #define GNUNET_MESSAGE_TYPE_ARM_STOP 9 | 78 | #define GNUNET_MESSAGE_TYPE_ARM_STOP 9 |
79 | 79 | ||
80 | /** | 80 | /** |
81 | * Request ARM service itself to shutdown. | 81 | * Response from ARM. |
82 | */ | 82 | */ |
83 | #define GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN 10 | 83 | #define GNUNET_MESSAGE_TYPE_ARM_RESULT 10 |
84 | 84 | ||
85 | /** | 85 | /** |
86 | * Response from ARM. | 86 | * Status update from ARM. |
87 | */ | 87 | */ |
88 | #define GNUNET_MESSAGE_TYPE_ARM_RESULT 11 | 88 | #define GNUNET_MESSAGE_TYPE_ARM_STATUS 11 |
89 | 89 | ||
90 | /** | 90 | /** |
91 | * Request to ARM to list all currently running services | 91 | * Request to ARM to list all currently running services |
@@ -97,6 +97,11 @@ extern "C" | |||
97 | */ | 97 | */ |
98 | #define GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT 13 | 98 | #define GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT 13 |
99 | 99 | ||
100 | /** | ||
101 | * Request to ARM to notify client of service status changes | ||
102 | */ | ||
103 | #define GNUNET_MESSAGE_TYPE_ARM_MONITOR 14 | ||
104 | |||
100 | /******************************************************************************* | 105 | /******************************************************************************* |
101 | * HELLO message types | 106 | * HELLO message types |
102 | ******************************************************************************/ | 107 | ******************************************************************************/ |
diff --git a/src/include/gnunet_server_lib.h b/src/include/gnunet_server_lib.h index f59e97015..f7b526416 100644 --- a/src/include/gnunet_server_lib.h +++ b/src/include/gnunet_server_lib.h | |||
@@ -395,6 +395,17 @@ typedef void (*GNUNET_SERVER_DisconnectCallback) (void *cls, | |||
395 | struct GNUNET_SERVER_Client * | 395 | struct GNUNET_SERVER_Client * |
396 | client); | 396 | client); |
397 | 397 | ||
398 | /** | ||
399 | * Functions with this signature are called whenever a client | ||
400 | * is connected on the network level. | ||
401 | * | ||
402 | * @param cls closure | ||
403 | * @param client identification of the client | ||
404 | */ | ||
405 | typedef void (*GNUNET_SERVER_ConnectCallback) (void *cls, | ||
406 | struct GNUNET_SERVER_Client *client); | ||
407 | |||
408 | |||
398 | 409 | ||
399 | /** | 410 | /** |
400 | * Ask the server to notify us whenever a client disconnects. | 411 | * Ask the server to notify us whenever a client disconnects. |
@@ -417,6 +428,20 @@ GNUNET_SERVER_disconnect_notify (struct GNUNET_SERVER_Handle *server, | |||
417 | 428 | ||
418 | 429 | ||
419 | /** | 430 | /** |
431 | * Ask the server to notify us whenever a client connects. | ||
432 | * This function is called whenever the actual network connection | ||
433 | * is opened. | ||
434 | * | ||
435 | * @param server the server manageing the clients | ||
436 | * @param callback function to call on sconnect | ||
437 | * @param callback_cls closure for callback | ||
438 | */ | ||
439 | void | ||
440 | GNUNET_SERVER_connect_notify (struct GNUNET_SERVER_Handle *server, | ||
441 | GNUNET_SERVER_ConnectCallback callback, void *callback_cls); | ||
442 | |||
443 | |||
444 | /** | ||
420 | * Ask the server to stop notifying us whenever a client disconnects. | 445 | * Ask the server to stop notifying us whenever a client disconnects. |
421 | * | 446 | * |
422 | * @param server the server manageing the clients | 447 | * @param server the server manageing the clients |
@@ -430,6 +455,18 @@ GNUNET_SERVER_disconnect_notify_cancel (struct GNUNET_SERVER_Handle *server, | |||
430 | 455 | ||
431 | 456 | ||
432 | /** | 457 | /** |
458 | * Ask the server to stop notifying us whenever a client connects. | ||
459 | * | ||
460 | * @param server the server manageing the clients | ||
461 | * @param callback function to call on connect | ||
462 | * @param callback_cls closure for callback | ||
463 | */ | ||
464 | void | ||
465 | GNUNET_SERVER_connect_notify_cancel (struct GNUNET_SERVER_Handle *server, | ||
466 | GNUNET_SERVER_ConnectCallback callback, void *callback_cls); | ||
467 | |||
468 | |||
469 | /** | ||
433 | * Ask the server to disconnect from the given client. | 470 | * Ask the server to disconnect from the given client. |
434 | * This is the same as returning GNUNET_SYSERR from a message | 471 | * This is the same as returning GNUNET_SYSERR from a message |
435 | * handler, except that it allows dropping of a client even | 472 | * handler, except that it allows dropping of a client even |
diff --git a/src/regex/gnunet-regex-profiler.c b/src/regex/gnunet-regex-profiler.c index 0c104fab4..303f1fffc 100644 --- a/src/regex/gnunet-regex-profiler.c +++ b/src/regex/gnunet-regex-profiler.c | |||
@@ -997,6 +997,17 @@ find_next_string (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | |||
997 | } | 997 | } |
998 | 998 | ||
999 | 999 | ||
1000 | |||
1001 | /** | ||
1002 | * Start announcing the next regex in the DHT. | ||
1003 | * | ||
1004 | * @param cls Index of the next peer in the peers array. | ||
1005 | * @param tc TaskContext. | ||
1006 | */ | ||
1007 | void | ||
1008 | announce_next_regex (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); | ||
1009 | |||
1010 | |||
1000 | /** | 1011 | /** |
1001 | * ARM connect adapter. Opens a connection to the ARM service. | 1012 | * ARM connect adapter. Opens a connection to the ARM service. |
1002 | * | 1013 | * |
@@ -1010,7 +1021,8 @@ arm_ca (void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg) | |||
1010 | { | 1021 | { |
1011 | struct RegexPeer *peer = cls; | 1022 | struct RegexPeer *peer = cls; |
1012 | 1023 | ||
1013 | peer->arm_handle = GNUNET_ARM_connect (cfg, NULL); | 1024 | peer->arm_handle = GNUNET_ARM_alloc (cfg); |
1025 | GNUNET_ARM_connect (peer->arm_handle, NULL, NULL); | ||
1014 | 1026 | ||
1015 | return peer->arm_handle; | 1027 | return peer->arm_handle; |
1016 | } | 1028 | } |
@@ -1036,104 +1048,52 @@ arm_da (void *cls, void *op_result) | |||
1036 | } | 1048 | } |
1037 | } | 1049 | } |
1038 | 1050 | ||
1039 | |||
1040 | /** | ||
1041 | * Start announcing the next regex in the DHT. | ||
1042 | * | ||
1043 | * @param cls Index of the next peer in the peers array. | ||
1044 | * @param tc TaskContext. | ||
1045 | */ | ||
1046 | void | ||
1047 | announce_next_regex (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); | ||
1048 | |||
1049 | |||
1050 | /** | ||
1051 | * Callback function invoked when ARM peration is complete: deamon is started. | ||
1052 | * | ||
1053 | * @param cls Closure (RegexPeer). | ||
1054 | * @param result Outcome of the operation. | ||
1055 | */ | ||
1056 | static void | 1051 | static void |
1057 | arm_start_cb (void *cls, enum GNUNET_ARM_ProcessStatus result) | 1052 | regexprofiler_start_cb (void *cls, struct GNUNET_ARM_Handle *arm, |
1053 | enum GNUNET_ARM_RequestStatus rs, const char *service, | ||
1054 | enum GNUNET_ARM_Result result) | ||
1058 | { | 1055 | { |
1059 | struct RegexPeer *peer = (struct RegexPeer *) cls; | 1056 | struct RegexPeer *peer = (struct RegexPeer *) cls; |
1060 | static unsigned int peer_cnt; | ||
1061 | unsigned int next_p; | 1057 | unsigned int next_p; |
1062 | 1058 | ||
1063 | switch (result) | 1059 | if (rs != GNUNET_ARM_REQUEST_SENT_OK) |
1064 | { | 1060 | { |
1065 | /** | 1061 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "ARM request was not sent: %u\n", rs); |
1066 | * Service is currently being started (due to client request). | 1062 | GNUNET_abort (); |
1067 | */ | 1063 | } |
1068 | case GNUNET_ARM_PROCESS_STARTING: | 1064 | else if (result != GNUNET_ARM_RESULT_STARTING) |
1069 | GNUNET_TESTBED_operation_done (peer->op_handle); | 1065 | { |
1070 | peer->op_handle = NULL; | 1066 | /* FIXME: maybe check for other acceptable results (already starting, |
1071 | 1067 | * already started)? | |
1072 | if (peer_cnt < (num_peers - 1)) | 1068 | */ |
1073 | { | 1069 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "ARM failed to start regexprofiler: %u\n", result); |
1074 | next_p = (++peer_cnt % num_peers); | 1070 | GNUNET_abort (); |
1075 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply( | 1071 | } |
1076 | GNUNET_TIME_UNIT_MILLISECONDS, | 1072 | GNUNET_TESTBED_operation_done (peer->op_handle); |
1077 | 400), | 1073 | peer->op_handle = NULL; |
1078 | &announce_next_regex, | ||
1079 | (void *) (long) next_p); | ||
1080 | } | ||
1081 | else | ||
1082 | { | ||
1083 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1084 | "All daemons started." | ||
1085 | " Waiting %s to start string searches\n", | ||
1086 | GNUNET_STRINGS_relative_time_to_string (search_delay, | ||
1087 | GNUNET_NO)); | ||
1088 | GNUNET_SCHEDULER_add_delayed (search_delay, | ||
1089 | do_connect_by_string, | ||
1090 | NULL); | ||
1091 | } | ||
1092 | break; | ||
1093 | 1074 | ||
1094 | /** | 1075 | if (peer_cnt < (num_peers - 1)) |
1095 | * Service name is unknown to ARM. | 1076 | { |
1096 | */ | 1077 | next_p = (++peer_cnt % num_peers); |
1097 | case GNUNET_ARM_PROCESS_UNKNOWN: | 1078 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply( |
1098 | /** | 1079 | GNUNET_TIME_UNIT_MILLISECONDS, |
1099 | * Service is now down (due to client request). | 1080 | 400), |
1100 | */ | 1081 | &announce_next_regex, |
1101 | case GNUNET_ARM_PROCESS_DOWN: | 1082 | (void *) (long) next_p); |
1102 | /** | 1083 | } |
1103 | * Service is already running. | 1084 | else |
1104 | */ | 1085 | { |
1105 | case GNUNET_ARM_PROCESS_ALREADY_RUNNING: | 1086 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, |
1106 | /** | 1087 | "All daemons started." |
1107 | * Service is already being stopped by some other client. | 1088 | " Waiting %s to start string searches\n", |
1108 | */ | 1089 | GNUNET_STRINGS_relative_time_to_string (search_delay, |
1109 | case GNUNET_ARM_PROCESS_ALREADY_STOPPING: | 1090 | GNUNET_NO)); |
1110 | /** | 1091 | GNUNET_SCHEDULER_add_delayed (search_delay, |
1111 | * Service is already down (no action taken) | 1092 | do_connect_by_string, |
1112 | */ | 1093 | NULL); |
1113 | case GNUNET_ARM_PROCESS_ALREADY_DOWN: | ||
1114 | /** | ||
1115 | * ARM is currently being shut down (no more process starts) | ||
1116 | */ | ||
1117 | case GNUNET_ARM_PROCESS_SHUTDOWN: | ||
1118 | /** | ||
1119 | * Error in communication with ARM | ||
1120 | */ | ||
1121 | case GNUNET_ARM_PROCESS_COMMUNICATION_ERROR: | ||
1122 | /** | ||
1123 | * Timeout in communication with ARM | ||
1124 | */ | ||
1125 | case GNUNET_ARM_PROCESS_COMMUNICATION_TIMEOUT: | ||
1126 | /** | ||
1127 | * Failure to perform operation | ||
1128 | */ | ||
1129 | case GNUNET_ARM_PROCESS_FAILURE: | ||
1130 | default: | ||
1131 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "ARM returned %d\n", result); | ||
1132 | GNUNET_abort (); | ||
1133 | } | 1094 | } |
1134 | } | 1095 | } |
1135 | 1096 | ||
1136 | |||
1137 | /** | 1097 | /** |
1138 | * ARM connect callback. Called when we are connected to the arm service for | 1098 | * ARM connect callback. Called when we are connected to the arm service for |
1139 | * the peer in 'cls'. If successfull we start the regex deamon to start | 1099 | * the peer in 'cls'. If successfull we start the regex deamon to start |
@@ -1160,11 +1120,10 @@ arm_connect_cb (void *cls, struct GNUNET_TESTBED_Operation *op, | |||
1160 | GNUNET_assert (peer->op_handle == op); | 1120 | GNUNET_assert (peer->op_handle == op); |
1161 | GNUNET_assert (peer->arm_handle == ca_result); | 1121 | GNUNET_assert (peer->arm_handle == ca_result); |
1162 | 1122 | ||
1163 | GNUNET_ARM_start_service (ca_result, "regexprofiler", | 1123 | GNUNET_ARM_request_service_start (ca_result, "regexprofiler", |
1164 | GNUNET_OS_INHERIT_STD_NONE, | 1124 | GNUNET_OS_INHERIT_STD_NONE, |
1165 | GNUNET_TIME_UNIT_FOREVER_REL, | 1125 | GNUNET_TIME_UNIT_FOREVER_REL, |
1166 | &arm_start_cb, | 1126 | regexprofiler_start_cb, cls); |
1167 | peer); | ||
1168 | } | 1127 | } |
1169 | 1128 | ||
1170 | 1129 | ||
diff --git a/src/regex/regex_test_lib.c b/src/regex/regex_test_lib.c index 57c6b13e8..56ccb3496 100644 --- a/src/regex/regex_test_lib.c +++ b/src/regex/regex_test_lib.c | |||
@@ -267,7 +267,7 @@ GNUNET_REGEX_read_from_file (const char *filename) | |||
267 | struct GNUNET_DISK_FileHandle *f; | 267 | struct GNUNET_DISK_FileHandle *f; |
268 | unsigned int nr; | 268 | unsigned int nr; |
269 | unsigned int offset; | 269 | unsigned int offset; |
270 | off_t size; | 270 | uint64_t size; |
271 | size_t len; | 271 | size_t len; |
272 | char *buffer; | 272 | char *buffer; |
273 | char *regex; | 273 | char *regex; |
diff --git a/src/util/client.c b/src/util/client.c index 69380c9b0..8b4776201 100644 --- a/src/util/client.c +++ b/src/util/client.c | |||
@@ -1007,6 +1007,7 @@ client_notify (void *cls, size_t size, void *buf) | |||
1007 | size_t ret; | 1007 | size_t ret; |
1008 | struct GNUNET_TIME_Relative delay; | 1008 | struct GNUNET_TIME_Relative delay; |
1009 | 1009 | ||
1010 | LOG (GNUNET_ERROR_TYPE_DEBUG, "client_notify is running\n"); | ||
1010 | th->th = NULL; | 1011 | th->th = NULL; |
1011 | client->th = NULL; | 1012 | client->th = NULL; |
1012 | if (NULL == buf) | 1013 | if (NULL == buf) |
diff --git a/src/util/connection.c b/src/util/connection.c index c4795cebe..ea35b04e1 100644 --- a/src/util/connection.c +++ b/src/util/connection.c | |||
@@ -1153,14 +1153,22 @@ process_notify (struct GNUNET_CONNECTION_Handle *connection) | |||
1153 | size_t size; | 1153 | size_t size; |
1154 | GNUNET_CONNECTION_TransmitReadyNotify notify; | 1154 | GNUNET_CONNECTION_TransmitReadyNotify notify; |
1155 | 1155 | ||
1156 | LOG (GNUNET_ERROR_TYPE_DEBUG, "process_notify is running\n"); | ||
1157 | |||
1156 | GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == connection->write_task); | 1158 | GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == connection->write_task); |
1157 | if (NULL == (notify = connection->nth.notify_ready)) | 1159 | if (NULL == (notify = connection->nth.notify_ready)) |
1160 | { | ||
1161 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Noone to notify\n"); | ||
1158 | return GNUNET_NO; | 1162 | return GNUNET_NO; |
1163 | } | ||
1159 | used = connection->write_buffer_off - connection->write_buffer_pos; | 1164 | used = connection->write_buffer_off - connection->write_buffer_pos; |
1160 | avail = connection->write_buffer_size - used; | 1165 | avail = connection->write_buffer_size - used; |
1161 | size = connection->nth.notify_size; | 1166 | size = connection->nth.notify_size; |
1162 | if (size > avail) | 1167 | if (size > avail) |
1168 | { | ||
1169 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Not enough buffer\n"); | ||
1163 | return GNUNET_NO; | 1170 | return GNUNET_NO; |
1171 | } | ||
1164 | connection->nth.notify_ready = NULL; | 1172 | connection->nth.notify_ready = NULL; |
1165 | if (connection->write_buffer_size - connection->write_buffer_off < size) | 1173 | if (connection->write_buffer_size - connection->write_buffer_off < size) |
1166 | { | 1174 | { |
diff --git a/src/util/server.c b/src/util/server.c index fc5f263bf..526821477 100644 --- a/src/util/server.c +++ b/src/util/server.c | |||
@@ -111,6 +111,16 @@ struct GNUNET_SERVER_Handle | |||
111 | struct NotifyList *disconnect_notify_list_tail; | 111 | struct NotifyList *disconnect_notify_list_tail; |
112 | 112 | ||
113 | /** | 113 | /** |
114 | * Head of linked list of functions to call on connects by clients. | ||
115 | */ | ||
116 | struct NotifyList *connect_notify_list_head; | ||
117 | |||
118 | /** | ||
119 | * Tail of linked list of functions to call on connects by clients. | ||
120 | */ | ||
121 | struct NotifyList *connect_notify_list_tail; | ||
122 | |||
123 | /** | ||
114 | * Function to call for access control. | 124 | * Function to call for access control. |
115 | */ | 125 | */ |
116 | GNUNET_CONNECTION_AccessCheck access; | 126 | GNUNET_CONNECTION_AccessCheck access; |
@@ -756,6 +766,14 @@ GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *server) | |||
756 | npos); | 766 | npos); |
757 | GNUNET_free (npos); | 767 | GNUNET_free (npos); |
758 | } | 768 | } |
769 | while (NULL != (npos = server->connect_notify_list_head)) | ||
770 | { | ||
771 | npos->callback (npos->callback_cls, NULL); | ||
772 | GNUNET_CONTAINER_DLL_remove (server->connect_notify_list_head, | ||
773 | server->connect_notify_list_tail, | ||
774 | npos); | ||
775 | GNUNET_free (npos); | ||
776 | } | ||
759 | GNUNET_free (server); | 777 | GNUNET_free (server); |
760 | } | 778 | } |
761 | 779 | ||
@@ -1161,6 +1179,7 @@ GNUNET_SERVER_connect_socket (struct GNUNET_SERVER_Handle *server, | |||
1161 | struct GNUNET_CONNECTION_Handle *connection) | 1179 | struct GNUNET_CONNECTION_Handle *connection) |
1162 | { | 1180 | { |
1163 | struct GNUNET_SERVER_Client *client; | 1181 | struct GNUNET_SERVER_Client *client; |
1182 | struct NotifyList *n; | ||
1164 | 1183 | ||
1165 | client = GNUNET_malloc (sizeof (struct GNUNET_SERVER_Client)); | 1184 | client = GNUNET_malloc (sizeof (struct GNUNET_SERVER_Client)); |
1166 | client->connection = connection; | 1185 | client->connection = connection; |
@@ -1178,6 +1197,9 @@ GNUNET_SERVER_connect_socket (struct GNUNET_SERVER_Handle *server, | |||
1178 | client->mst = | 1197 | client->mst = |
1179 | GNUNET_SERVER_mst_create (&client_message_tokenizer_callback, server); | 1198 | GNUNET_SERVER_mst_create (&client_message_tokenizer_callback, server); |
1180 | GNUNET_assert (NULL != client->mst); | 1199 | GNUNET_assert (NULL != client->mst); |
1200 | for (n = server->connect_notify_list_head; NULL != n; n = n->next) | ||
1201 | n->callback (n->callback_cls, client); | ||
1202 | |||
1181 | client->receive_pending = GNUNET_YES; | 1203 | client->receive_pending = GNUNET_YES; |
1182 | GNUNET_CONNECTION_receive (client->connection, | 1204 | GNUNET_CONNECTION_receive (client->connection, |
1183 | GNUNET_SERVER_MAX_MESSAGE_SIZE - 1, | 1205 | GNUNET_SERVER_MAX_MESSAGE_SIZE - 1, |
@@ -1277,10 +1299,34 @@ GNUNET_SERVER_disconnect_notify (struct GNUNET_SERVER_Handle *server, | |||
1277 | 1299 | ||
1278 | 1300 | ||
1279 | /** | 1301 | /** |
1280 | * Ask the server to stop notifying us whenever a client disconnects. | 1302 | * Ask the server to notify us whenever a client connects. |
1303 | * This function is called whenever the actual network connection | ||
1304 | * is opened. | ||
1281 | * | 1305 | * |
1282 | * @param server the server manageing the clients | 1306 | * @param server the server manageing the clients |
1283 | * @param callback function to call on disconnect | 1307 | * @param callback function to call on sconnect |
1308 | * @param callback_cls closure for callback | ||
1309 | */ | ||
1310 | void | ||
1311 | GNUNET_SERVER_connect_notify (struct GNUNET_SERVER_Handle *server, | ||
1312 | GNUNET_SERVER_ConnectCallback callback, void *callback_cls) | ||
1313 | { | ||
1314 | struct NotifyList *n; | ||
1315 | |||
1316 | n = GNUNET_malloc (sizeof (struct NotifyList)); | ||
1317 | n->callback = callback; | ||
1318 | n->callback_cls = callback_cls; | ||
1319 | GNUNET_CONTAINER_DLL_insert (server->connect_notify_list_head, | ||
1320 | server->connect_notify_list_tail, | ||
1321 | n); | ||
1322 | } | ||
1323 | |||
1324 | |||
1325 | /** | ||
1326 | * Ask the server to stop notifying us whenever a client connects. | ||
1327 | * | ||
1328 | * @param server the server manageing the clients | ||
1329 | * @param callback function to call on connect | ||
1284 | * @param callback_cls closure for callback | 1330 | * @param callback_cls closure for callback |
1285 | */ | 1331 | */ |
1286 | void | 1332 | void |
@@ -1306,6 +1352,34 @@ GNUNET_SERVER_disconnect_notify_cancel (struct GNUNET_SERVER_Handle *server, | |||
1306 | 1352 | ||
1307 | 1353 | ||
1308 | /** | 1354 | /** |
1355 | * Ask the server to stop notifying us whenever a client disconnects. | ||
1356 | * | ||
1357 | * @param server the server manageing the clients | ||
1358 | * @param callback function to call on disconnect | ||
1359 | * @param callback_cls closure for callback | ||
1360 | */ | ||
1361 | void | ||
1362 | GNUNET_SERVER_connect_notify_cancel (struct GNUNET_SERVER_Handle *server, | ||
1363 | GNUNET_SERVER_ConnectCallback callback, void *callback_cls) | ||
1364 | { | ||
1365 | struct NotifyList *pos; | ||
1366 | |||
1367 | for (pos = server->connect_notify_list_head; NULL != pos; pos = pos->next) | ||
1368 | if ((pos->callback == callback) && (pos->callback_cls == callback_cls)) | ||
1369 | break; | ||
1370 | if (NULL == pos) | ||
1371 | { | ||
1372 | GNUNET_break (0); | ||
1373 | return; | ||
1374 | } | ||
1375 | GNUNET_CONTAINER_DLL_remove (server->connect_notify_list_head, | ||
1376 | server->connect_notify_list_tail, | ||
1377 | pos); | ||
1378 | GNUNET_free (pos); | ||
1379 | } | ||
1380 | |||
1381 | |||
1382 | /** | ||
1309 | * Destroy the connection that is passed in via 'cls'. Used | 1383 | * Destroy the connection that is passed in via 'cls'. Used |
1310 | * as calling 'GNUNET_CONNECTION_destroy' from within a function | 1384 | * as calling 'GNUNET_CONNECTION_destroy' from within a function |
1311 | * that was itself called from within 'process_notify' of | 1385 | * that was itself called from within 'process_notify' of |