arm_api.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727
  1. /*
  2. This file is part of GNUnet.
  3. (C) 2009, 2010 Christian Grothoff (and other contributing authors)
  4. GNUnet is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published
  6. by the Free Software Foundation; either version 3, or (at your
  7. option) any later version.
  8. GNUnet is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNUnet; see the file COPYING. If not, write to the
  14. Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  15. Boston, MA 02111-1307, USA.
  16. */
  17. /**
  18. * @file arm/arm_api.c
  19. * @brief API for accessing the ARM service
  20. * @author Christian Grothoff
  21. */
  22. #include "platform.h"
  23. #include "gnunet_arm_service.h"
  24. #include "gnunet_client_lib.h"
  25. #include "gnunet_getopt_lib.h"
  26. #include "gnunet_os_lib.h"
  27. #include "gnunet_protocols.h"
  28. #include "gnunet_server_lib.h"
  29. #include "arm.h"
  30. /**
  31. * Handle for interacting with ARM.
  32. */
  33. struct GNUNET_ARM_Handle
  34. {
  35. /**
  36. * Our connection to the ARM service.
  37. */
  38. struct GNUNET_CLIENT_Connection *client;
  39. /**
  40. * The configuration that we are using.
  41. */
  42. struct GNUNET_CONFIGURATION_Handle *cfg;
  43. };
  44. /**
  45. * Context for handling the shutdown of a service.
  46. */
  47. struct ShutdownContext
  48. {
  49. /**
  50. * Connection to the service that is being shutdown.
  51. */
  52. struct GNUNET_CLIENT_Connection *sock;
  53. /**
  54. * Time allowed for shutdown to happen.
  55. */
  56. struct GNUNET_TIME_Absolute timeout;
  57. /**
  58. * Task set up to cancel the shutdown request on timeout.
  59. */
  60. GNUNET_SCHEDULER_TaskIdentifier cancel_task;
  61. /**
  62. * Task to call once shutdown complete
  63. */
  64. GNUNET_CLIENT_ShutdownTask cont;
  65. /**
  66. * Closure for shutdown continuation
  67. */
  68. void *cont_cls;
  69. /**
  70. * We received a confirmation that the service will shut down.
  71. */
  72. int confirmed;
  73. };
  74. /**
  75. * Handler receiving response to service shutdown requests.
  76. * First call with NULL: service misbehaving, or something.
  77. * First call with GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN_ACK:
  78. * - service will shutdown
  79. * Second call with NULL:
  80. * - service has now really shut down.
  81. *
  82. * @param cls closure
  83. * @param msg NULL, indicating socket closure.
  84. */
  85. static void
  86. service_shutdown_handler (void *cls, const struct GNUNET_MessageHeader *msg)
  87. {
  88. struct ShutdownContext *shutdown_ctx = cls;
  89. if ((msg == NULL) && (shutdown_ctx->confirmed != GNUNET_YES))
  90. {
  91. #if DEBUG_ARM
  92. /* Means the other side closed the connection and never confirmed a shutdown */
  93. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  94. "Service handle shutdown before ACK!\n");
  95. #endif
  96. if (shutdown_ctx->cont != NULL)
  97. shutdown_ctx->cont(shutdown_ctx->cont_cls, GNUNET_SYSERR);
  98. GNUNET_SCHEDULER_cancel(shutdown_ctx->cancel_task);
  99. GNUNET_CLIENT_disconnect (shutdown_ctx->sock, GNUNET_NO);
  100. GNUNET_free(shutdown_ctx);
  101. }
  102. else if ((msg == NULL) && (shutdown_ctx->confirmed == GNUNET_YES))
  103. {
  104. #if DEBUG_ARM
  105. GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
  106. "Service shutdown complete.\n");
  107. #endif
  108. if (shutdown_ctx->cont != NULL)
  109. shutdown_ctx->cont(shutdown_ctx->cont_cls, GNUNET_NO);
  110. GNUNET_SCHEDULER_cancel(shutdown_ctx->cancel_task);
  111. GNUNET_CLIENT_disconnect (shutdown_ctx->sock, GNUNET_NO);
  112. GNUNET_free(shutdown_ctx);
  113. }
  114. else
  115. {
  116. GNUNET_assert(ntohs(msg->size) == sizeof(struct GNUNET_MessageHeader));
  117. switch (ntohs(msg->type))
  118. {
  119. case GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN_ACK:
  120. #if DEBUG_ARM
  121. GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
  122. "Received confirmation for service shutdown.\n");
  123. #endif
  124. shutdown_ctx->confirmed = GNUNET_YES;
  125. GNUNET_CLIENT_receive (shutdown_ctx->sock,
  126. &service_shutdown_handler,
  127. shutdown_ctx,
  128. GNUNET_TIME_UNIT_FOREVER_REL);
  129. break;
  130. default: /* Fall through */
  131. #if DEBUG_ARM
  132. GNUNET_log(GNUNET_ERROR_TYPE_DEBUG,
  133. "Service shutdown refused!\n");
  134. #endif
  135. if (shutdown_ctx->cont != NULL)
  136. shutdown_ctx->cont(shutdown_ctx->cont_cls, GNUNET_YES);
  137. GNUNET_SCHEDULER_cancel(shutdown_ctx->cancel_task);
  138. GNUNET_CLIENT_disconnect (shutdown_ctx->sock, GNUNET_NO);
  139. GNUNET_free(shutdown_ctx);
  140. break;
  141. }
  142. }
  143. }
  144. /**
  145. * Shutting down took too long, cancel receive and return error.
  146. *
  147. * @param cls closure
  148. * @param tc context information (why was this task triggered now)
  149. */
  150. void service_shutdown_cancel (void *cls,
  151. const struct GNUNET_SCHEDULER_TaskContext * tc)
  152. {
  153. struct ShutdownContext *shutdown_ctx = cls;
  154. #if DEBUG_ARM
  155. GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "service_shutdown_cancel called!\n");
  156. #endif
  157. shutdown_ctx->cont(shutdown_ctx->cont_cls, GNUNET_SYSERR);
  158. GNUNET_CLIENT_disconnect (shutdown_ctx->sock, GNUNET_NO);
  159. GNUNET_free(shutdown_ctx);
  160. }
  161. /**
  162. * If possible, write a shutdown message to the target
  163. * buffer and destroy the client connection.
  164. *
  165. * @param cls the "struct GNUNET_CLIENT_Connection" to destroy
  166. * @param size number of bytes available in buf
  167. * @param buf NULL on error, otherwise target buffer
  168. * @return number of bytes written to buf
  169. */
  170. static size_t
  171. write_shutdown (void *cls, size_t size, void *buf)
  172. {
  173. struct GNUNET_MessageHeader *msg;
  174. struct ShutdownContext *shutdown_ctx = cls;
  175. if (size < sizeof (struct GNUNET_MessageHeader))
  176. {
  177. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  178. _("Failed to transmit shutdown request to client.\n"));
  179. shutdown_ctx->cont(shutdown_ctx->cont_cls, GNUNET_SYSERR);
  180. GNUNET_CLIENT_disconnect (shutdown_ctx->sock, GNUNET_NO);
  181. GNUNET_free(shutdown_ctx);
  182. return 0; /* client disconnected */
  183. }
  184. GNUNET_CLIENT_receive (shutdown_ctx->sock,
  185. &service_shutdown_handler, shutdown_ctx,
  186. GNUNET_TIME_UNIT_FOREVER_REL);
  187. shutdown_ctx->cancel_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining(shutdown_ctx->timeout),
  188. &service_shutdown_cancel,
  189. shutdown_ctx);
  190. msg = (struct GNUNET_MessageHeader *) buf;
  191. msg->type = htons (GNUNET_MESSAGE_TYPE_ARM_SHUTDOWN);
  192. msg->size = htons (sizeof (struct GNUNET_MessageHeader));
  193. return sizeof (struct GNUNET_MessageHeader);
  194. }
  195. /**
  196. * Request that the service should shutdown.
  197. * Afterwards, the connection will automatically be
  198. * disconnected. Hence the "sock" should not
  199. * be used by the caller after this call
  200. * (calling this function frees "sock" after a while).
  201. *
  202. * @param sock the socket connected to the service
  203. * @param timeout how long to wait before giving up on transmission
  204. * @param cont continuation to call once the service is really down
  205. * @param cont_cls closure for continuation
  206. *
  207. */
  208. static void
  209. arm_service_shutdown (struct GNUNET_CLIENT_Connection *sock,
  210. struct GNUNET_TIME_Relative timeout,
  211. GNUNET_CLIENT_ShutdownTask cont,
  212. void *cont_cls)
  213. {
  214. struct ShutdownContext *shutdown_ctx;
  215. shutdown_ctx = GNUNET_malloc(sizeof(struct ShutdownContext));
  216. shutdown_ctx->cont = cont;
  217. shutdown_ctx->cont_cls = cont_cls;
  218. shutdown_ctx->sock = sock;
  219. shutdown_ctx->timeout = GNUNET_TIME_relative_to_absolute(timeout);
  220. GNUNET_CLIENT_notify_transmit_ready (sock,
  221. sizeof (struct
  222. GNUNET_MessageHeader),
  223. timeout,
  224. GNUNET_YES,
  225. &write_shutdown, shutdown_ctx);
  226. }
  227. /**
  228. * Setup a context for communicating with ARM. Note that this
  229. * can be done even if the ARM service is not yet running.
  230. *
  231. * @param cfg configuration to use (needed to contact ARM;
  232. * the ARM service may internally use a different
  233. * configuration to determine how to start the service).
  234. * @param service service that *this* process is implementing/providing, can be NULL
  235. * @return context to use for further ARM operations, NULL on error
  236. */
  237. struct GNUNET_ARM_Handle *
  238. GNUNET_ARM_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
  239. const char *service)
  240. {
  241. struct GNUNET_ARM_Handle *ret;
  242. ret = GNUNET_malloc (sizeof (struct GNUNET_ARM_Handle));
  243. ret->cfg = GNUNET_CONFIGURATION_dup (cfg);
  244. return ret;
  245. }
  246. /**
  247. * Disconnect from the ARM service.
  248. *
  249. * @param h the handle that was being used
  250. */
  251. void
  252. GNUNET_ARM_disconnect (struct GNUNET_ARM_Handle *h)
  253. {
  254. if (h->client != NULL)
  255. GNUNET_CLIENT_disconnect (h->client, GNUNET_NO);
  256. GNUNET_CONFIGURATION_destroy (h->cfg);
  257. GNUNET_free (h);
  258. }
  259. struct ARM_ShutdownContext
  260. {
  261. /**
  262. * Callback to call once shutdown complete.
  263. */
  264. GNUNET_ARM_Callback cb;
  265. /**
  266. * Closure for callback.
  267. */
  268. void *cb_cls;
  269. };
  270. /**
  271. * Internal state for a request with ARM.
  272. */
  273. struct RequestContext
  274. {
  275. /**
  276. * Pointer to our handle with ARM.
  277. */
  278. struct GNUNET_ARM_Handle *h;
  279. /**
  280. * Function to call with a status code for the requested operation.
  281. */
  282. GNUNET_ARM_Callback callback;
  283. /**
  284. * Closure for "callback".
  285. */
  286. void *cls;
  287. /**
  288. * Timeout for the operation.
  289. */
  290. struct GNUNET_TIME_Absolute timeout;
  291. /**
  292. * Type of the request expressed as a message type (start or stop).
  293. */
  294. uint16_t type;
  295. };
  296. #include "do_start_process.c"
  297. /**
  298. * A client specifically requested starting of ARM itself.
  299. * This function is called with information about whether
  300. * or not ARM is running; if it is, report success. If
  301. * it is not, start the ARM process.
  302. *
  303. * @param cls the context for the request that we will report on (struct RequestContext*)
  304. * @param tc why were we called (reason says if ARM is running)
  305. */
  306. static void
  307. arm_service_report (void *cls,
  308. const struct GNUNET_SCHEDULER_TaskContext *tc)
  309. {
  310. struct RequestContext *pos = cls;
  311. struct GNUNET_OS_Process *proc;
  312. char *binary;
  313. char *config;
  314. char *loprefix;
  315. char *lopostfix;
  316. if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_PREREQ_DONE))
  317. {
  318. #if DEBUG_ARM
  319. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  320. "Looks like `%s' is already running.\n",
  321. "gnunet-service-arm");
  322. #endif
  323. /* arm is running! */
  324. if (pos->callback != NULL)
  325. pos->callback (pos->cls, GNUNET_YES);
  326. GNUNET_free (pos);
  327. return;
  328. }
  329. #if DEBUG_ARM
  330. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  331. "Looks like `%s' is not running, will start it.\n",
  332. "gnunet-service-arm");
  333. #endif
  334. /* FIXME: should we check that HOSTNAME for 'arm' is localhost? */
  335. if (GNUNET_OK !=
  336. GNUNET_CONFIGURATION_get_value_string (pos->h->cfg,
  337. "arm", "PREFIX", &loprefix))
  338. loprefix = GNUNET_strdup ("");
  339. if (GNUNET_OK !=
  340. GNUNET_CONFIGURATION_get_value_string (pos->h->cfg,
  341. "arm", "OPTIONS", &lopostfix))
  342. lopostfix = GNUNET_strdup ("");
  343. if (GNUNET_OK !=
  344. GNUNET_CONFIGURATION_get_value_string (pos->h->cfg,
  345. "arm",
  346. "BINARY",
  347. &binary))
  348. {
  349. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  350. _("Configuration failes to specify option `%s' in section `%s'!\n"),
  351. "BINARY",
  352. "arm");
  353. if (pos->callback != NULL)
  354. pos->callback (pos->cls, GNUNET_SYSERR);
  355. GNUNET_free (pos);
  356. GNUNET_free (loprefix);
  357. GNUNET_free (lopostfix);
  358. return;
  359. }
  360. if (GNUNET_OK !=
  361. GNUNET_CONFIGURATION_get_value_filename (pos->h->cfg,
  362. "arm", "CONFIG", &config))
  363. {
  364. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  365. _("Configuration fails to specify option `%s' in section `%s'!\n"),
  366. "CONFIG",
  367. "arm");
  368. if (pos->callback != NULL)
  369. pos->callback (pos->cls, GNUNET_SYSERR);
  370. GNUNET_free (binary);
  371. GNUNET_free (pos);
  372. GNUNET_free (loprefix);
  373. GNUNET_free (lopostfix);
  374. return;
  375. }
  376. if ((GNUNET_YES == GNUNET_CONFIGURATION_have_value (pos->h->cfg,
  377. "TESTING",
  378. "WEAKRANDOM")) &&
  379. (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (pos->h->cfg,
  380. "TESTING",
  381. "WEAKRANDOM")) &&
  382. (GNUNET_NO == GNUNET_CONFIGURATION_have_value (pos->h->cfg,
  383. "TESTING",
  384. "HOSTFILE")) /* Means we are ONLY running locally */
  385. )
  386. {
  387. /* we're clearly running a test, don't daemonize */
  388. proc = do_start_process (NULL,
  389. loprefix,
  390. binary,
  391. "-c", config,
  392. #if DEBUG_ARM
  393. "-L", "DEBUG",
  394. #endif
  395. /* no daemonization! */
  396. lopostfix,
  397. NULL);
  398. }
  399. else
  400. {
  401. proc = do_start_process (NULL,
  402. loprefix,
  403. binary,
  404. "-c", config,
  405. #if DEBUG_ARM
  406. "-L", "DEBUG",
  407. #endif
  408. "-d",
  409. lopostfix,
  410. NULL);
  411. }
  412. GNUNET_free (binary);
  413. GNUNET_free (config);
  414. GNUNET_free (loprefix);
  415. GNUNET_free (lopostfix);
  416. if (proc == NULL)
  417. {
  418. if (pos->callback != NULL)
  419. pos->callback (pos->cls, GNUNET_SYSERR);
  420. GNUNET_free (pos);
  421. return;
  422. }
  423. if (pos->callback != NULL)
  424. pos->callback (pos->cls, GNUNET_YES);
  425. GNUNET_free (proc);
  426. GNUNET_free (pos);
  427. }
  428. /**
  429. * Process a response from ARM to a request for a change in service
  430. * status.
  431. *
  432. * @param cls the request context
  433. * @param msg the response
  434. */
  435. static void
  436. handle_response (void *cls, const struct GNUNET_MessageHeader *msg)
  437. {
  438. struct RequestContext *sc = cls;
  439. int ret;
  440. if (msg == NULL)
  441. {
  442. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  443. _("Error receiving response to `%s' request from ARM for service `%s'\n"),
  444. (sc->type == GNUNET_MESSAGE_TYPE_ARM_START)
  445. ? "START"
  446. : "STOP",
  447. (const char*) &sc[1]);
  448. GNUNET_CLIENT_disconnect (sc->h->client, GNUNET_NO);
  449. sc->h->client = GNUNET_CLIENT_connect ("arm",
  450. sc->h->cfg);
  451. GNUNET_assert (NULL != sc->h->client);
  452. GNUNET_CLIENT_ignore_shutdown (sc->h->client, GNUNET_YES);
  453. if (sc->callback != NULL)
  454. sc->callback (sc->cls, GNUNET_SYSERR);
  455. GNUNET_free (sc);
  456. return;
  457. }
  458. #if DEBUG_ARM
  459. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  460. "Received response from ARM for service `%s': %u\n",
  461. (const char*) &sc[1],
  462. ntohs(msg->type));
  463. #endif
  464. switch (ntohs (msg->type))
  465. {
  466. case GNUNET_MESSAGE_TYPE_ARM_IS_UP:
  467. ret = GNUNET_YES;
  468. break;
  469. case GNUNET_MESSAGE_TYPE_ARM_IS_DOWN:
  470. ret = GNUNET_NO;
  471. break;
  472. case GNUNET_MESSAGE_TYPE_ARM_IS_UNKNOWN:
  473. ret = GNUNET_SYSERR;
  474. break;
  475. default:
  476. GNUNET_break (0);
  477. ret = GNUNET_SYSERR;
  478. }
  479. if (sc->callback != NULL)
  480. sc->callback (sc->cls, ret);
  481. GNUNET_free (sc);
  482. }
  483. /**
  484. * Start or stop a service.
  485. *
  486. * @param h handle to ARM
  487. * @param service_name name of the service
  488. * @param timeout how long to wait before failing for good
  489. * @param cb callback to invoke when service is ready
  490. * @param cb_cls closure for callback
  491. * @param type type of the request
  492. */
  493. static void
  494. change_service (struct GNUNET_ARM_Handle *h,
  495. const char *service_name,
  496. struct GNUNET_TIME_Relative timeout,
  497. GNUNET_ARM_Callback cb, void *cb_cls, uint16_t type)
  498. {
  499. struct RequestContext *sctx;
  500. size_t slen;
  501. struct GNUNET_MessageHeader *msg;
  502. slen = strlen (service_name) + 1;
  503. if (slen + sizeof (struct GNUNET_MessageHeader) >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
  504. {
  505. GNUNET_break (0);
  506. if (cb != NULL)
  507. cb (cb_cls, GNUNET_NO);
  508. return;
  509. }
  510. #if DEBUG_ARM
  511. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  512. (type == GNUNET_MESSAGE_TYPE_ARM_START)
  513. ? _("Requesting start of service `%s'.\n")
  514. : _("Requesting termination of service `%s'.\n"),
  515. service_name);
  516. #endif
  517. sctx = GNUNET_malloc (sizeof (struct RequestContext) + slen);
  518. sctx->h = h;
  519. sctx->callback = cb;
  520. sctx->cls = cb_cls;
  521. sctx->timeout = GNUNET_TIME_relative_to_absolute (timeout);
  522. sctx->type = type;
  523. memcpy (&sctx[1], service_name, slen);
  524. msg = GNUNET_malloc (sizeof (struct GNUNET_MessageHeader) + slen);
  525. msg->size = htons (sizeof (struct GNUNET_MessageHeader) + slen);
  526. msg->type = htons (sctx->type);
  527. memcpy (&msg[1], service_name, slen);
  528. if (GNUNET_OK !=
  529. GNUNET_CLIENT_transmit_and_get_response (sctx->h->client,
  530. msg,
  531. GNUNET_TIME_absolute_get_remaining (sctx->timeout),
  532. GNUNET_YES,
  533. &handle_response,
  534. sctx))
  535. {
  536. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  537. (type == GNUNET_MESSAGE_TYPE_ARM_START)
  538. ? _("Error while trying to transmit request to start `%s' to ARM\n")
  539. : _("Error while trying to transmit request to stop `%s' to ARM\n"),
  540. (const char*) &service_name);
  541. if (cb != NULL)
  542. cb (cb_cls, GNUNET_SYSERR);
  543. GNUNET_free (sctx);
  544. GNUNET_free (msg);
  545. return;
  546. }
  547. GNUNET_free (msg);
  548. }
  549. /**
  550. * Start a service.
  551. *
  552. * @param h handle to ARM
  553. * @param service_name name of the service
  554. * @param timeout how long to wait before failing for good
  555. * @param cb callback to invoke when service is ready
  556. * @param cb_cls closure for callback
  557. */
  558. void
  559. GNUNET_ARM_start_service (struct GNUNET_ARM_Handle *h,
  560. const char *service_name,
  561. struct GNUNET_TIME_Relative timeout,
  562. GNUNET_ARM_Callback cb, void *cb_cls)
  563. {
  564. struct RequestContext *sctx;
  565. struct GNUNET_CLIENT_Connection *client;
  566. size_t slen;
  567. #if DEBUG_ARM
  568. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  569. _("Asked to start service `%s' within %llu ms\n"), service_name,
  570. (unsigned long long) timeout.rel_value);
  571. #endif
  572. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  573. _("Asked to start service `%s' within %llu ms\n"), service_name,
  574. (unsigned long long) timeout.rel_value);
  575. if (0 == strcasecmp ("arm", service_name))
  576. {
  577. slen = strlen ("arm") + 1;
  578. sctx = GNUNET_malloc (sizeof (struct RequestContext) + slen);
  579. sctx->h = h;
  580. sctx->callback = cb;
  581. sctx->cls = cb_cls;
  582. sctx->timeout = GNUNET_TIME_relative_to_absolute (timeout);
  583. memcpy (&sctx[1], service_name, slen);
  584. GNUNET_CLIENT_service_test ("arm",
  585. h->cfg, timeout, &arm_service_report, sctx);
  586. return;
  587. }
  588. if (h->client == NULL)
  589. {
  590. client = GNUNET_CLIENT_connect ("arm", h->cfg);
  591. if (client == NULL)
  592. {
  593. GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "arm_api, GNUNET_CLIENT_connect returned NULL\n");
  594. cb (cb_cls, GNUNET_SYSERR);
  595. return;
  596. }
  597. GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "arm_api, GNUNET_CLIENT_connect returned non-NULL\n");
  598. GNUNET_CLIENT_ignore_shutdown (client, GNUNET_YES);
  599. h->client = client;
  600. }
  601. GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "arm_api, h->client non-NULL\n");
  602. change_service (h, service_name, timeout, cb, cb_cls, GNUNET_MESSAGE_TYPE_ARM_START);
  603. }
  604. /**
  605. * Callback from the arm stop service call, indicates that the arm service
  606. * is well and truly dead, won't die, or an error occurred.
  607. *
  608. * @param cls closure for the callback
  609. * @param reason reason for callback, GNUNET_NO if arm is shutdown
  610. * GNUNET_YES if arm remains running, and GNUNET_SYSERR on error
  611. */
  612. void arm_shutdown_callback (void *cls,
  613. int reason)
  614. {
  615. struct ARM_ShutdownContext *arm_shutdown_ctx = cls;
  616. if (arm_shutdown_ctx->cb != NULL)
  617. arm_shutdown_ctx->cb (arm_shutdown_ctx->cb_cls, reason);
  618. GNUNET_free(arm_shutdown_ctx);
  619. }
  620. /**
  621. * Stop a service.
  622. *
  623. * @param h handle to ARM
  624. * @param service_name name of the service
  625. * @param timeout how long to wait before failing for good
  626. * @param cb callback to invoke when service is ready
  627. * @param cb_cls closure for callback
  628. */
  629. void
  630. GNUNET_ARM_stop_service (struct GNUNET_ARM_Handle *h,
  631. const char *service_name,
  632. struct GNUNET_TIME_Relative timeout,
  633. GNUNET_ARM_Callback cb, void *cb_cls)
  634. {
  635. struct ARM_ShutdownContext *arm_shutdown_ctx;
  636. struct GNUNET_CLIENT_Connection *client;
  637. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  638. _("Stopping service `%s' within %llu ms\n"), service_name,
  639. (unsigned long long) timeout.rel_value);
  640. if (h->client == NULL)
  641. {
  642. client = GNUNET_CLIENT_connect ("arm", h->cfg);
  643. if (client == NULL)
  644. {
  645. cb (cb_cls, GNUNET_SYSERR);
  646. return;
  647. }
  648. GNUNET_CLIENT_ignore_shutdown (client, GNUNET_YES);
  649. h->client = client;
  650. }
  651. if (0 == strcasecmp ("arm", service_name))
  652. {
  653. arm_shutdown_ctx = GNUNET_malloc(sizeof(struct ARM_ShutdownContext));
  654. arm_shutdown_ctx->cb = cb;
  655. arm_shutdown_ctx->cb_cls = cb_cls;
  656. arm_service_shutdown (h->client, timeout, &arm_shutdown_callback, arm_shutdown_ctx);
  657. h->client = NULL;
  658. return;
  659. }
  660. change_service (h, service_name, timeout, cb, cb_cls, GNUNET_MESSAGE_TYPE_ARM_STOP);
  661. }
  662. /* end of arm_api.c */