summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/arm/arm.h45
-rw-r--r--src/arm/arm_api.c102
-rw-r--r--src/arm/arm_monitor_api.c8
-rw-r--r--src/arm/gnunet-arm.c51
-rw-r--r--src/arm/gnunet-service-arm.c101
-rw-r--r--src/arm/test_exponential_backoff.c2
-rw-r--r--src/arm/test_gnunet_service_arm.c10
-rw-r--r--src/include/gnunet_arm_service.h78
8 files changed, 331 insertions, 66 deletions
diff --git a/src/arm/arm.h b/src/arm/arm.h
index 983586060..bddcd7cf3 100644
--- a/src/arm/arm.h
+++ b/src/arm/arm.h
@@ -93,6 +93,44 @@ struct GNUNET_ARM_ResultMessage {
93 uint32_t result; 93 uint32_t result;
94}; 94};
95 95
96struct GNUNET_ARM_ServiceInfoMessage {
97 /**
98 * String pool index for the service's name.
99 */
100 uint16_t name_index;
101
102 /**
103 * String pool index for the service's binary.
104 */
105 uint16_t binary_index;
106
107 /**
108 * Last process exit status.
109 */
110 int16_t last_exit_status;
111
112 /**
113 * Padding.
114 */
115 uint16_t padding;
116
117 /**
118 * Status from the 'enum GNUNET_ARM_ServiceStatus'
119 */
120 uint32_t status;
121
122 /**
123 * Time when the sevice will be restarted, if applicable
124 * to the current status.
125 */
126 struct GNUNET_TIME_AbsoluteNBO restart_at;
127
128 /**
129 * Time when the sevice was first started, if applicable.
130 */
131 struct GNUNET_TIME_AbsoluteNBO last_started_at;
132};
133
96/** 134/**
97 * Reply from ARM to client for the 135 * Reply from ARM to client for the
98 * #GNUNET_MESSAGE_TYPE_ARM_LIST request followed by count 136 * #GNUNET_MESSAGE_TYPE_ARM_LIST request followed by count
@@ -107,10 +145,13 @@ struct GNUNET_ARM_ListResultMessage {
107 struct GNUNET_ARM_Message arm_msg; 145 struct GNUNET_ARM_Message arm_msg;
108 146
109 /** 147 /**
110 * Number of '\0' terminated strings that follow 148 * Number of 'struct GNUNET_ARM_ServiceInfoMessage' that
111 * this message. 149 * are at the end of this message.
112 */ 150 */
113 uint16_t count; 151 uint16_t count;
152
153 /* struct GNUNET_ARM_ServiceInfoMessage[count]; */
154 /* pool of 0-terminated strings */
114}; 155};
115 156
116GNUNET_NETWORK_STRUCT_END 157GNUNET_NETWORK_STRUCT_END
diff --git a/src/arm/arm_api.c b/src/arm/arm_api.c
index b42c95dc0..4c3bb0488 100644
--- a/src/arm/arm_api.c
+++ b/src/arm/arm_api.c
@@ -294,7 +294,32 @@ handle_arm_result(void *cls, const struct GNUNET_ARM_ResultMessage *res)
294 294
295 295
296/** 296/**
297 * Checked that list result message is well-formed. 297 * Read from a string pool.
298 *
299 * @param pool_start start of the string pool
300 * @param pool_size size of the string pool
301 * @param str_index index into the string pool
302 * @returns an index into the string pool, or
303 * NULL if the index is out of bounds
304 */
305static const char *
306pool_get (const char *pool_start, size_t pool_size, size_t str_index)
307{
308 const char *str_start;
309 const char *end;
310
311 if (str_index >= pool_size)
312 return NULL;
313 str_start = pool_start + str_index;
314 end = memchr(str_start, 0, pool_size - str_index);
315 if (NULL == end)
316 return NULL;
317 return str_start;
318}
319
320
321/**
322 * Check that list result message is well-formed.
298 * 323 *
299 * @param cls our `struct GNUNET_ARM_Handle` 324 * @param cls our `struct GNUNET_ARM_Handle`
300 * @param lres the message received from the arm service 325 * @param lres the message received from the arm service
@@ -304,23 +329,38 @@ static int
304check_arm_list_result(void *cls, 329check_arm_list_result(void *cls,
305 const struct GNUNET_ARM_ListResultMessage *lres) 330 const struct GNUNET_ARM_ListResultMessage *lres)
306{ 331{
307 const char *pos = (const char *)&lres[1];
308 uint16_t rcount = ntohs(lres->count); 332 uint16_t rcount = ntohs(lres->count);
309 uint16_t msize = ntohs(lres->arm_msg.header.size) - sizeof(*lres); 333 uint16_t msize = ntohs(lres->arm_msg.header.size) - sizeof(*lres);
310 uint16_t size_check; 334 struct GNUNET_ARM_ServiceInfoMessage *ssm;
335 size_t pool_size;
336 char *pool_start;
337
338 if ((rcount * sizeof (struct GNUNET_ARM_ServiceInfoMessage) > msize))
339 {
340 GNUNET_break_op (0);
341 return GNUNET_NO;
342 }
343
344 ssm = (struct GNUNET_ARM_ServiceInfoMessage *) &lres[1];
345 pool_start = (char *) (ssm + rcount);
346 pool_size = msize - (rcount * sizeof (struct GNUNET_ARM_ServiceInfoMessage));
311 347
312 (void)cls; 348 (void)cls;
313 size_check = 0;
314 for (unsigned int i = 0; i < rcount; i++) 349 for (unsigned int i = 0; i < rcount; i++)
315 { 350 {
316 const char *end = memchr(pos, 0, msize - size_check); 351 uint16_t name_index = ntohs (ssm->name_index);
317 if (NULL == end) 352 uint16_t binary_index = ntohs (ssm->binary_index);
318 { 353 if (NULL == pool_get (pool_start, pool_size, name_index))
319 GNUNET_break(0); 354 {
320 return GNUNET_SYSERR; 355 GNUNET_break_op (0);
321 } 356 return GNUNET_NO;
322 size_check += (end - pos) + 1; 357 }
323 pos = end + 1; 358 if (NULL == pool_get (pool_start, pool_size, binary_index))
359 {
360 GNUNET_break_op (0);
361 return GNUNET_NO;
362 }
363 ssm++;
324 } 364 }
325 return GNUNET_OK; 365 return GNUNET_OK;
326} 366}
@@ -338,12 +378,13 @@ handle_arm_list_result(void *cls,
338{ 378{
339 struct GNUNET_ARM_Handle *h = cls; 379 struct GNUNET_ARM_Handle *h = cls;
340 uint16_t rcount = ntohs(lres->count); 380 uint16_t rcount = ntohs(lres->count);
341 const char *list[rcount];
342 const char *pos = (const char *)&lres[1];
343 uint16_t msize = ntohs(lres->arm_msg.header.size) - sizeof(*lres); 381 uint16_t msize = ntohs(lres->arm_msg.header.size) - sizeof(*lres);
382 struct GNUNET_ARM_ServiceInfo list[rcount];
383 struct GNUNET_ARM_ServiceInfoMessage *ssm;
344 struct GNUNET_ARM_Operation *op; 384 struct GNUNET_ARM_Operation *op;
345 uint16_t size_check;
346 uint64_t id; 385 uint64_t id;
386 size_t pool_size;
387 char *pool_start;
347 388
348 id = GNUNET_ntohll(lres->arm_msg.request_id); 389 id = GNUNET_ntohll(lres->arm_msg.request_id);
349 op = find_op_by_id(h, id); 390 op = find_op_by_id(h, id);
@@ -354,16 +395,31 @@ handle_arm_list_result(void *cls,
354 (unsigned long long)id); 395 (unsigned long long)id);
355 return; 396 return;
356 } 397 }
357 size_check = 0; 398
399 GNUNET_assert ((rcount * sizeof (struct GNUNET_ARM_ServiceInfoMessage) <= msize));
400
401 ssm = (struct GNUNET_ARM_ServiceInfoMessage *) &lres[1];
402 pool_start = (char *) (ssm + rcount);
403 pool_size = msize - (rcount * sizeof (struct GNUNET_ARM_ServiceInfoMessage));
404
358 for (unsigned int i = 0; i < rcount; i++) 405 for (unsigned int i = 0; i < rcount; i++)
359 { 406 {
360 const char *end = memchr(pos, 0, msize - size_check); 407 uint16_t name_index = ntohs (ssm->name_index);
361 408 uint16_t binary_index = ntohs (ssm->binary_index);
362 /* Assert, as this was already checked in #check_arm_list_result() */ 409 const char *name;
363 GNUNET_assert(NULL != end); 410 const char *binary;
364 list[i] = pos; 411
365 size_check += (end - pos) + 1; 412 GNUNET_assert (NULL != (name = pool_get (pool_start, pool_size, name_index)));
366 pos = end + 1; 413 GNUNET_assert (NULL != (binary = pool_get (pool_start, pool_size, binary_index)));
414 list[i] = (struct GNUNET_ARM_ServiceInfo) {
415 .name = name,
416 .binary = binary,
417 .status = ntohl (ssm->status),
418 .last_started_at = GNUNET_TIME_absolute_ntoh (ssm->last_started_at),
419 .restart_at = GNUNET_TIME_absolute_ntoh (ssm->restart_at),
420 .last_exit_status = ntohs (ssm->last_exit_status),
421 };
422 ssm++;
367 } 423 }
368 if (NULL != op->list_cont) 424 if (NULL != op->list_cont)
369 op->list_cont(op->cont_cls, GNUNET_ARM_REQUEST_SENT_OK, rcount, list); 425 op->list_cont(op->cont_cls, GNUNET_ARM_REQUEST_SENT_OK, rcount, list);
diff --git a/src/arm/arm_monitor_api.c b/src/arm/arm_monitor_api.c
index c6e1e2683..00faaaef1 100644
--- a/src/arm/arm_monitor_api.c
+++ b/src/arm/arm_monitor_api.c
@@ -61,7 +61,7 @@ struct GNUNET_ARM_MonitorHandle {
61 /** 61 /**
62 * Callback to invoke on status updates. 62 * Callback to invoke on status updates.
63 */ 63 */
64 GNUNET_ARM_ServiceStatusCallback service_status; 64 GNUNET_ARM_ServiceMonitorCallback service_status;
65 65
66 /** 66 /**
67 * Closure for @e service_status. 67 * Closure for @e service_status.
@@ -153,9 +153,9 @@ static void
153handle_monitor_notify(void *cls, const struct GNUNET_ARM_StatusMessage *res) 153handle_monitor_notify(void *cls, const struct GNUNET_ARM_StatusMessage *res)
154{ 154{
155 struct GNUNET_ARM_MonitorHandle *h = cls; 155 struct GNUNET_ARM_MonitorHandle *h = cls;
156 enum GNUNET_ARM_ServiceStatus status; 156 enum GNUNET_ARM_ServiceMonitorStatus status;
157 157
158 status = (enum GNUNET_ARM_ServiceStatus)ntohl(res->status); 158 status = (enum GNUNET_ARM_ServiceMonitorStatus)ntohl(res->status);
159 LOG(GNUNET_ERROR_TYPE_DEBUG, 159 LOG(GNUNET_ERROR_TYPE_DEBUG,
160 "Received notification from ARM for service `%s' with status %d\n", 160 "Received notification from ARM for service `%s' with status %d\n",
161 (const char *)&res[1], 161 (const char *)&res[1],
@@ -230,7 +230,7 @@ reconnect_arm_monitor(struct GNUNET_ARM_MonitorHandle *h)
230 */ 230 */
231struct GNUNET_ARM_MonitorHandle * 231struct GNUNET_ARM_MonitorHandle *
232GNUNET_ARM_monitor_start(const struct GNUNET_CONFIGURATION_Handle *cfg, 232GNUNET_ARM_monitor_start(const struct GNUNET_CONFIGURATION_Handle *cfg,
233 GNUNET_ARM_ServiceStatusCallback cont, 233 GNUNET_ARM_ServiceMonitorCallback cont,
234 void *cont_cls) 234 void *cont_cls)
235{ 235{
236 struct GNUNET_ARM_MonitorHandle *h; 236 struct GNUNET_ARM_MonitorHandle *h;
diff --git a/src/arm/gnunet-arm.c b/src/arm/gnunet-arm.c
index 3396a4dbe..fcbff2331 100644
--- a/src/arm/gnunet-arm.c
+++ b/src/arm/gnunet-arm.c
@@ -54,6 +54,11 @@ static int delete;
54static int quiet; 54static int quiet;
55 55
56/** 56/**
57 * Set if we should print all services, including stopped ones.
58 */
59static int show_all;
60
61/**
57 * Monitor ARM activity. 62 * Monitor ARM activity.
58 */ 63 */
59static int monitor; 64static int monitor;
@@ -508,13 +513,13 @@ term_callback(void *cls,
508 * @param cls closure (unused) 513 * @param cls closure (unused)
509 * @param rs request status (success, failure, etc.) 514 * @param rs request status (success, failure, etc.)
510 * @param count number of services in the list 515 * @param count number of services in the list
511 * @param list list of services that are running 516 * @param list list of services managed by arm
512 */ 517 */
513static void 518static void
514list_callback(void *cls, 519list_callback(void *cls,
515 enum GNUNET_ARM_RequestStatus rs, 520 enum GNUNET_ARM_RequestStatus rs,
516 unsigned int count, 521 unsigned int count,
517 const char *const *list) 522 const struct GNUNET_ARM_ServiceInfo *list)
518{ 523{
519 (void)cls; 524 (void)cls;
520 op = NULL; 525 op = NULL;
@@ -540,9 +545,41 @@ list_callback(void *cls,
540 return; 545 return;
541 } 546 }
542 if (!quiet) 547 if (!quiet)
543 fprintf(stdout, "%s", _("Running services:\n")); 548 {
549 if (show_all)
550 fprintf(stdout, "%s", _("All services:\n"));
551 else
552 fprintf(stdout, "%s", _("Services (excluding stopped services):\n"));
553 }
544 for (unsigned int i = 0; i < count; i++) 554 for (unsigned int i = 0; i < count; i++)
545 fprintf(stdout, "%s\n", list[i]); 555 {
556 struct GNUNET_TIME_Relative restart_in;
557 switch (list[i].status)
558 {
559 case GNUNET_ARM_SERVICE_STATUS_STOPPED:
560 if (show_all)
561 fprintf(stdout, "%s (binary='%s', status=stopped)\n", list[i].name, list[i].binary);
562 break;
563 case GNUNET_ARM_SERVICE_STATUS_FAILED:
564 restart_in = GNUNET_TIME_absolute_get_remaining (list[i].restart_at);
565 fprintf(stdout, "%s (binary='%s', status=failed, exit_status=%d, restart_delay='%s')\n",
566 list[i].name,
567 list[i].binary,
568 list[i].last_exit_status,
569 GNUNET_STRINGS_relative_time_to_string (restart_in, GNUNET_YES));
570 break;
571 case GNUNET_ARM_SERVICE_STATUS_FINISHED:
572 fprintf(stdout, "%s (binary='%s', status=finished)\n", list[i].name, list[i].binary);
573 break;
574 case GNUNET_ARM_SERVICE_STATUS_STARTED:
575 fprintf(stdout, "%s (binary='%s', status=started)\n", list[i].name, list[i].binary);
576 break;
577 default:
578 fprintf(stdout, "%s (binary='%s', status=unknown)\n", list[i].name, list[i].binary);
579 break;
580
581 }
582 }
546 al_task = GNUNET_SCHEDULER_add_now(&action_loop, NULL); 583 al_task = GNUNET_SCHEDULER_add_now(&action_loop, NULL);
547} 584}
548 585
@@ -652,7 +689,7 @@ action_loop(void *cls)
652static void 689static void
653srv_status(void *cls, 690srv_status(void *cls,
654 const char *service, 691 const char *service,
655 enum GNUNET_ARM_ServiceStatus status) 692 enum GNUNET_ARM_ServiceMonitorStatus status)
656{ 693{
657 const char *msg; 694 const char *msg;
658 695
@@ -773,6 +810,10 @@ main(int argc, char *const *argv)
773 "SERVICE", 810 "SERVICE",
774 gettext_noop("stop a particular service"), 811 gettext_noop("stop a particular service"),
775 &term), 812 &term),
813 GNUNET_GETOPT_option_flag('a',
814 "all",
815 gettext_noop("also show stopped services (used with -I)"),
816 &show_all),
776 GNUNET_GETOPT_option_flag('s', 817 GNUNET_GETOPT_option_flag('s',
777 "start", 818 "start",
778 gettext_noop( 819 gettext_noop(
diff --git a/src/arm/gnunet-service-arm.c b/src/arm/gnunet-service-arm.c
index e02314b91..b30ae518e 100644
--- a/src/arm/gnunet-service-arm.c
+++ b/src/arm/gnunet-service-arm.c
@@ -164,6 +164,11 @@ struct ServiceList {
164 struct GNUNET_TIME_Relative backoff; 164 struct GNUNET_TIME_Relative backoff;
165 165
166 /** 166 /**
167 * Absolute time at which the process was (re-)started last.
168 */
169 struct GNUNET_TIME_Absolute last_started_at;
170
171 /**
167 * Absolute time at which the process is scheduled to restart in case of death 172 * Absolute time at which the process is scheduled to restart in case of death
168 */ 173 */
169 struct GNUNET_TIME_Absolute restart_at; 174 struct GNUNET_TIME_Absolute restart_at;
@@ -186,6 +191,11 @@ struct ServiceList {
186 * are on Windoze). 191 * are on Windoze).
187 */ 192 */
188 int pipe_control; 193 int pipe_control;
194
195 /**
196 * Last exit status of the process.
197 */
198 int last_exit_status;
189}; 199};
190 200
191/** 201/**
@@ -696,7 +706,7 @@ signal_result(struct GNUNET_SERVICE_Client *client,
696 */ 706 */
697static void 707static void
698broadcast_status(const char *name, 708broadcast_status(const char *name,
699 enum GNUNET_ARM_ServiceStatus status, 709 enum GNUNET_ARM_ServiceMonitorStatus status,
700 struct GNUNET_SERVICE_Client *unicast) 710 struct GNUNET_SERVICE_Client *unicast)
701{ 711{
702 struct GNUNET_MQ_Envelope *env; 712 struct GNUNET_MQ_Envelope *env;
@@ -914,6 +924,7 @@ start_process(struct ServiceList *sl,
914 } 924 }
915 GNUNET_free(binary); 925 GNUNET_free(binary);
916 GNUNET_free(quotedbinary); 926 GNUNET_free(quotedbinary);
927 sl->last_started_at = GNUNET_TIME_absolute_get ();
917 if (NULL == sl->proc) 928 if (NULL == sl->proc)
918 { 929 {
919 GNUNET_log(GNUNET_ERROR_TYPE_ERROR, 930 GNUNET_log(GNUNET_ERROR_TYPE_ERROR,
@@ -1300,6 +1311,29 @@ handle_stop(void *cls, const struct GNUNET_ARM_Message *amsg)
1300 1311
1301 1312
1302/** 1313/**
1314 * Write a string to a string pool.
1315 *
1316 * @param pool_start pointer to the start of the string pool
1317 * @param pool_size size of the string pool
1318 * @param[in,out] pool_pos current position index in the string pool,
1319 * will be updated
1320 * @param str string to write to the string pool
1321 * @returns GNUNET_OK if the string fits into the pool,
1322 * GNUNET_SYSERR otherwise
1323 */
1324static int
1325pool_write(char *pool_start, size_t pool_size, size_t *pool_pos, char *str)
1326{
1327 size_t next_pos = (*pool_pos) + strlen (str) + 1;
1328
1329 if (next_pos > pool_size)
1330 return GNUNET_SYSERR;
1331 memcpy (pool_start + *pool_pos, str, strlen (str) + 1);
1332 *pool_pos = next_pos;
1333 return GNUNET_OK;
1334}
1335
1336/**
1303 * Handle LIST-message. 1337 * Handle LIST-message.
1304 * 1338 *
1305 * @param cls identification of the client 1339 * @param cls identification of the client
@@ -1311,42 +1345,68 @@ handle_list(void *cls, const struct GNUNET_ARM_Message *request)
1311 struct GNUNET_SERVICE_Client *client = cls; 1345 struct GNUNET_SERVICE_Client *client = cls;
1312 struct GNUNET_MQ_Envelope *env; 1346 struct GNUNET_MQ_Envelope *env;
1313 struct GNUNET_ARM_ListResultMessage *msg; 1347 struct GNUNET_ARM_ListResultMessage *msg;
1314 size_t string_list_size; 1348 size_t extra_size;
1315 struct ServiceList *sl; 1349 struct ServiceList *sl;
1316 uint16_t count; 1350 uint16_t count;
1317 char *pos; 1351 size_t pool_size;
1352 size_t pool_pos;
1353 char *pool_start;
1354 struct GNUNET_ARM_ServiceInfoMessage *ssm;
1318 1355
1319 GNUNET_break(0 == ntohl(request->reserved)); 1356 GNUNET_break_op(0 == ntohl(request->reserved));
1320 count = 0; 1357 count = 0;
1321 string_list_size = 0; 1358 pool_size = 0;
1322 1359
1323 /* first count the running processes get their name's size */ 1360 /* Do one pass over the list to compute the number of services
1361 * and the string pool size */
1324 for (sl = running_head; NULL != sl; sl = sl->next) 1362 for (sl = running_head; NULL != sl; sl = sl->next)
1325 { 1363 {
1326 if (NULL != sl->proc) 1364 pool_size += strlen(sl->name) + 1;
1327 { 1365 pool_size += strlen(sl->binary) + 1;
1328 string_list_size += strlen(sl->name); 1366 count++;
1329 string_list_size += strlen(sl->binary);
1330 string_list_size += 4;
1331 count++;
1332 }
1333 } 1367 }
1334 1368
1369 extra_size = pool_size + (count * sizeof (struct GNUNET_ARM_ServiceInfoMessage));
1335 env = GNUNET_MQ_msg_extra(msg, 1370 env = GNUNET_MQ_msg_extra(msg,
1336 string_list_size, 1371 extra_size,
1337 GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT); 1372 GNUNET_MESSAGE_TYPE_ARM_LIST_RESULT);
1338 msg->arm_msg.request_id = request->request_id; 1373 msg->arm_msg.request_id = request->request_id;
1339 msg->count = htons(count); 1374 msg->count = htons(count);
1340 1375
1341 pos = (char *)&msg[1]; 1376 ssm = (struct GNUNET_ARM_ServiceInfoMessage *) &msg[1];
1377 pool_start = (char *) (ssm + count);
1378 pool_pos = 0;
1379
1342 for (sl = running_head; NULL != sl; sl = sl->next) 1380 for (sl = running_head; NULL != sl; sl = sl->next)
1343 { 1381 {
1344 if (NULL != sl->proc) 1382 ssm->name_index = htons ((uint16_t) pool_pos);
1383 GNUNET_assert (GNUNET_OK == pool_write (pool_start, pool_size, &pool_pos, sl->name));
1384 ssm->binary_index = htons ((uint16_t) pool_pos);
1385 GNUNET_assert (GNUNET_OK == pool_write (pool_start, pool_size, &pool_pos, sl->binary));
1386 if (NULL == sl->proc)
1387 {
1388 if (0 == sl->last_started_at.abs_value_us)
1389 {
1390 /* Process never started */
1391 ssm->status = htonl (GNUNET_ARM_SERVICE_STATUS_STOPPED);
1392 }
1393 else if (0 == sl->last_exit_status)
1345 { 1394 {
1346 size_t s = strlen(sl->name) + strlen(sl->binary) + 4; 1395 ssm->status = htonl (GNUNET_ARM_SERVICE_STATUS_FINISHED);
1347 GNUNET_snprintf(pos, s, "%s (%s)", sl->name, sl->binary);
1348 pos += s;
1349 } 1396 }
1397 else
1398 {
1399 ssm->status = htonl (GNUNET_ARM_SERVICE_STATUS_FAILED);
1400 ssm->last_exit_status = htons (sl->last_exit_status);
1401 }
1402 }
1403 else
1404 {
1405 ssm->status = htonl (GNUNET_ARM_SERVICE_STATUS_STARTED);
1406 }
1407 ssm->last_started_at = GNUNET_TIME_absolute_hton (sl->last_started_at);
1408 ssm->restart_at = GNUNET_TIME_absolute_hton (sl->restart_at);
1409 ssm++;
1350 } 1410 }
1351 GNUNET_MQ_send(GNUNET_SERVICE_client_get_mq(client), env); 1411 GNUNET_MQ_send(GNUNET_SERVICE_client_get_mq(client), env);
1352 GNUNET_SERVICE_client_continue(client); 1412 GNUNET_SERVICE_client_continue(client);
@@ -1700,6 +1760,7 @@ maint_child_death(void *cls)
1700 } 1760 }
1701 if (GNUNET_YES != in_shutdown) 1761 if (GNUNET_YES != in_shutdown)
1702 { 1762 {
1763 pos->last_exit_status = statcode;
1703 if ((statusType == GNUNET_OS_PROCESS_EXITED) && (statcode == 0)) 1764 if ((statusType == GNUNET_OS_PROCESS_EXITED) && (statcode == 0))
1704 { 1765 {
1705 /* process terminated normally, allow restart at any time */ 1766 /* process terminated normally, allow restart at any time */
@@ -1722,7 +1783,7 @@ maint_child_death(void *cls)
1722 else 1783 else
1723 { 1784 {
1724 GNUNET_log( 1785 GNUNET_log(
1725 GNUNET_ERROR_TYPE_INFO, 1786 GNUNET_ERROR_TYPE_WARNING,
1726 _("Service `%s' terminated with status %s/%d, will restart in %s\n"), 1787 _("Service `%s' terminated with status %s/%d, will restart in %s\n"),
1727 pos->name, 1788 pos->name,
1728 statstr, 1789 statstr,
diff --git a/src/arm/test_exponential_backoff.c b/src/arm/test_exponential_backoff.c
index 8190d29c2..b13ab1cb8 100644
--- a/src/arm/test_exponential_backoff.c
+++ b/src/arm/test_exponential_backoff.c
@@ -196,7 +196,7 @@ arm_stop_cb(void *cls,
196static void 196static void
197srv_status(void *cls, 197srv_status(void *cls,
198 const char *service, 198 const char *service,
199 enum GNUNET_ARM_ServiceStatus status) 199 enum GNUNET_ARM_ServiceMonitorStatus status)
200{ 200{
201 if (status == GNUNET_ARM_SERVICE_MONITORING_STARTED) 201 if (status == GNUNET_ARM_SERVICE_MONITORING_STARTED)
202 { 202 {
diff --git a/src/arm/test_gnunet_service_arm.c b/src/arm/test_gnunet_service_arm.c
index 8c8c664f9..cb2c14438 100644
--- a/src/arm/test_gnunet_service_arm.c
+++ b/src/arm/test_gnunet_service_arm.c
@@ -78,7 +78,7 @@ static void
78service_list(void *cls, 78service_list(void *cls,
79 enum GNUNET_ARM_RequestStatus rs, 79 enum GNUNET_ARM_RequestStatus rs,
80 unsigned int count, 80 unsigned int count,
81 const char *const*list) 81 const struct GNUNET_ARM_ServiceInfo *list)
82{ 82{
83 unsigned int i; 83 unsigned int i;
84 84
@@ -89,13 +89,13 @@ service_list(void *cls,
89 goto stop_arm; 89 goto stop_arm;
90 for (i = 0; i < count; i++) 90 for (i = 0; i < count; i++)
91 { 91 {
92 if (0 == strcasecmp(list[i], 92 if ((0 == strcasecmp(list[i].name, "resolver")) &&
93 "resolver (gnunet-service-resolver)")) 93 (0 == strcasecmp(list[i].binary, "gnunet-service-resolver")))
94 { 94 {
95 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, 95 GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
96 "Got service list, now stopping arm\n"); 96 "Got service list, now stopping arm\n");
97 ret = 0; 97 ret = 0;
98 } 98 }
99 } 99 }
100 100
101stop_arm: 101stop_arm:
diff --git a/src/include/gnunet_arm_service.h b/src/include/gnunet_arm_service.h
index faf89128f..9e79c26e7 100644
--- a/src/include/gnunet_arm_service.h
+++ b/src/include/gnunet_arm_service.h
@@ -70,7 +70,7 @@ enum GNUNET_ARM_RequestStatus {
70/** 70/**
71 * Statuses of services. 71 * Statuses of services.
72 */ 72 */
73enum GNUNET_ARM_ServiceStatus { 73enum GNUNET_ARM_ServiceMonitorStatus {
74 /** 74 /**
75 * Dummy message. 75 * Dummy message.
76 */ 76 */
@@ -150,6 +150,72 @@ enum GNUNET_ARM_Result {
150 150
151 151
152/** 152/**
153 * Status of a service managed by ARM.
154 */
155enum GNUNET_ARM_ServiceStatus
156{
157 /**
158 * Service is stopped.
159 */
160 GNUNET_ARM_SERVICE_STATUS_STOPPED = 0,
161
162 /**
163 * Service has been started and is currently running.
164 */
165 GNUNET_ARM_SERVICE_STATUS_STARTED = 1,
166
167 /**
168 * The service has previously failed, and
169 * will be restarted.
170 */
171 GNUNET_ARM_SERVICE_STATUS_FAILED = 2,
172
173 /**
174 * The service was started, but then exited normally.
175 */
176 GNUNET_ARM_SERVICE_STATUS_FINISHED = 3,
177};
178
179
180/**
181 * Information about a service managed by ARM.
182 */
183struct GNUNET_ARM_ServiceInfo
184{
185 /**
186 * The current status of the service.
187 */
188 enum GNUNET_ARM_ServiceStatus status;
189
190 /**
191 * The name of the service.
192 */
193 const char *name;
194
195 /**
196 * The binary used to execute the service.
197 */
198 const char *binary;
199
200 /**
201 * Time when the sevice will be restarted, if applicable
202 * to the current status.
203 */
204 struct GNUNET_TIME_Absolute restart_at;
205
206 /**
207 * Time when the sevice was first started, if applicable.
208 */
209 struct GNUNET_TIME_Absolute last_started_at;
210
211 /**
212 * Last process exit status.
213 */
214 int last_exit_status;
215};
216
217
218/**
153 * Handle for interacting with ARM. 219 * Handle for interacting with ARM.
154 */ 220 */
155struct GNUNET_ARM_Handle; 221struct GNUNET_ARM_Handle;
@@ -197,13 +263,13 @@ typedef void
197 * @param cls closure 263 * @param cls closure
198 * @param rs status of the request 264 * @param rs status of the request
199 * @param count number of strings in the list 265 * @param count number of strings in the list
200 * @param list list of running services 266 * @param list list of services managed by arm
201 */ 267 */
202typedef void 268typedef void
203(*GNUNET_ARM_ServiceListCallback) (void *cls, 269(*GNUNET_ARM_ServiceListCallback) (void *cls,
204 enum GNUNET_ARM_RequestStatus rs, 270 enum GNUNET_ARM_RequestStatus rs,
205 unsigned int count, 271 unsigned int count,
206 const char *const*list); 272 const struct GNUNET_ARM_ServiceInfo *list);
207 273
208 274
209/** 275/**
@@ -309,9 +375,9 @@ struct GNUNET_ARM_MonitorHandle;
309 * @param status status of the service 375 * @param status status of the service
310 */ 376 */
311typedef void 377typedef void
312(*GNUNET_ARM_ServiceStatusCallback) (void *cls, 378(*GNUNET_ARM_ServiceMonitorCallback) (void *cls,
313 const char *service, 379 const char *service,
314 enum GNUNET_ARM_ServiceStatus status); 380 enum GNUNET_ARM_ServiceMonitorStatus status);
315 381
316 382
317/** 383/**
@@ -327,7 +393,7 @@ typedef void
327 */ 393 */
328struct GNUNET_ARM_MonitorHandle * 394struct GNUNET_ARM_MonitorHandle *
329GNUNET_ARM_monitor_start(const struct GNUNET_CONFIGURATION_Handle *cfg, 395GNUNET_ARM_monitor_start(const struct GNUNET_CONFIGURATION_Handle *cfg,
330 GNUNET_ARM_ServiceStatusCallback cont, 396 GNUNET_ARM_ServiceMonitorCallback cont,
331 void *cont_cls); 397 void *cont_cls);
332 398
333 399