gnunet-service-testbed.c 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2008--2013, 2016 GNUnet e.V.
  4. GNUnet is free software: you can redistribute it and/or modify it
  5. under the terms of the GNU Affero General Public License as published
  6. by the Free Software Foundation, either version 3 of the License,
  7. or (at your 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. Affero General Public License for more details.
  12. You should have received a copy of the GNU Affero General Public License
  13. along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. SPDX-License-Identifier: AGPL3.0-or-later
  15. */
  16. /**
  17. * @file testbed/gnunet-service-testbed.c
  18. * @brief implementation of the TESTBED service
  19. * @author Sree Harsha Totakura
  20. */
  21. #include "gnunet-service-testbed.h"
  22. #include "gnunet-service-testbed_barriers.h"
  23. #include "gnunet-service-testbed_connectionpool.h"
  24. /***********/
  25. /* Globals */
  26. /***********/
  27. /**
  28. * Our configuration
  29. */
  30. struct GNUNET_CONFIGURATION_Handle *GST_config;
  31. /**
  32. * The master context; generated with the first INIT message
  33. */
  34. struct Context *GST_context;
  35. /**
  36. * Array of hosts
  37. */
  38. struct GNUNET_TESTBED_Host **GST_host_list;
  39. /**
  40. * DLL head for forwarded operation contexts
  41. */
  42. struct ForwardedOperationContext *fopcq_head;
  43. /**
  44. * DLL tail for forwarded operation contexts
  45. */
  46. struct ForwardedOperationContext *fopcq_tail;
  47. /**
  48. * Operation queue for open file descriptors
  49. */
  50. struct OperationQueue *GST_opq_openfds;
  51. /**
  52. * Timeout for operations which may take some time
  53. */
  54. const struct GNUNET_TIME_Relative GST_timeout;
  55. /**
  56. * The size of the host list
  57. */
  58. unsigned int GST_host_list_size;
  59. /**
  60. * The size of the peer list
  61. */
  62. unsigned int GST_peer_list_size;
  63. /***********************************/
  64. /* Local definitions and variables */
  65. /***********************************/
  66. /**
  67. * Our hostname; we give this to all the peers we start
  68. */
  69. static char *hostname;
  70. /**
  71. * Function to add a host to the current list of known hosts
  72. *
  73. * @param host the host to add
  74. * @return #GNUNET_OK on success; #GNUNET_SYSERR on failure due to host-id
  75. * already in use
  76. */
  77. static int
  78. host_list_add (struct GNUNET_TESTBED_Host *host)
  79. {
  80. uint32_t host_id;
  81. host_id = GNUNET_TESTBED_host_get_id_ (host);
  82. if (GST_host_list_size <= host_id)
  83. GST_array_grow_large_enough (GST_host_list, GST_host_list_size, host_id);
  84. if (NULL != GST_host_list[host_id])
  85. {
  86. LOG_DEBUG ("A host with id: %u already exists\n", host_id);
  87. return GNUNET_SYSERR;
  88. }
  89. GST_host_list[host_id] = host;
  90. return GNUNET_OK;
  91. }
  92. /**
  93. * Send operation failure message to client
  94. *
  95. * @param client the client to which the failure message has to be sent to
  96. * @param operation_id the id of the failed operation
  97. * @param emsg the error message; can be NULL
  98. */
  99. void
  100. GST_send_operation_fail_msg (struct GNUNET_SERVICE_Client *client,
  101. uint64_t operation_id,
  102. const char *emsg)
  103. {
  104. struct GNUNET_MQ_Envelope *env;
  105. struct GNUNET_TESTBED_OperationFailureEventMessage *msg;
  106. uint16_t emsg_len;
  107. emsg_len = (NULL == emsg) ? 0 : strlen (emsg) + 1;
  108. env = GNUNET_MQ_msg_extra (msg,
  109. emsg_len,
  110. GNUNET_MESSAGE_TYPE_TESTBED_OPERATION_FAIL_EVENT);
  111. msg->event_type = htonl (GNUNET_TESTBED_ET_OPERATION_FINISHED);
  112. msg->operation_id = GNUNET_htonll (operation_id);
  113. GNUNET_memcpy (&msg[1],
  114. emsg,
  115. emsg_len);
  116. GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
  117. env);
  118. }
  119. /**
  120. * Function to send generic operation success message to given client
  121. *
  122. * @param client the client to send the message to
  123. * @param operation_id the id of the operation which was successful
  124. */
  125. void
  126. GST_send_operation_success_msg (struct GNUNET_SERVICE_Client *client,
  127. uint64_t operation_id)
  128. {
  129. struct GNUNET_MQ_Envelope *env;
  130. struct GNUNET_TESTBED_GenericOperationSuccessEventMessage *msg;
  131. env = GNUNET_MQ_msg (msg,
  132. GNUNET_MESSAGE_TYPE_TESTBED_GENERIC_OPERATION_SUCCESS);
  133. msg->operation_id = GNUNET_htonll (operation_id);
  134. msg->event_type = htonl (GNUNET_TESTBED_ET_OPERATION_FINISHED);
  135. GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
  136. env);
  137. }
  138. /**
  139. * Callback which will be called after a host registration succeeded or failed
  140. *
  141. * @param cls the handle to the slave at which the registration is completed
  142. * @param emsg the error message; NULL if host registration is successful
  143. */
  144. static void
  145. hr_completion (void *cls,
  146. const char *emsg);
  147. /**
  148. * Attempts to register the next host in the host registration queue
  149. *
  150. * @param slave the slave controller whose host registration queue is checked
  151. * for host registrations
  152. */
  153. static void
  154. register_next_host (struct Slave *slave)
  155. {
  156. struct HostRegistration *hr;
  157. hr = slave->hr_dll_head;
  158. GNUNET_assert (NULL != hr);
  159. GNUNET_assert (NULL == slave->rhandle);
  160. LOG (GNUNET_ERROR_TYPE_DEBUG, "Registering host %u at %u\n",
  161. GNUNET_TESTBED_host_get_id_ (hr->host),
  162. GNUNET_TESTBED_host_get_id_ (GST_host_list[slave->host_id]));
  163. slave->rhandle
  164. = GNUNET_TESTBED_register_host (slave->controller,
  165. hr->host,
  166. hr_completion,
  167. slave);
  168. }
  169. /**
  170. * Callback which will be called to after a host registration succeeded or failed
  171. *
  172. * @param cls the handle to the slave at which the registration is completed
  173. * @param emsg the error message; NULL if host registration is successful
  174. */
  175. static void
  176. hr_completion (void *cls,
  177. const char *emsg)
  178. {
  179. struct Slave *slave = cls;
  180. struct HostRegistration *hr;
  181. slave->rhandle = NULL;
  182. hr = slave->hr_dll_head;
  183. GNUNET_assert (NULL != hr);
  184. LOG (GNUNET_ERROR_TYPE_DEBUG,
  185. "Registering host %u at %u successful\n",
  186. GNUNET_TESTBED_host_get_id_ (hr->host),
  187. GNUNET_TESTBED_host_get_id_ (GST_host_list[slave->host_id]));
  188. GNUNET_CONTAINER_DLL_remove (slave->hr_dll_head,
  189. slave->hr_dll_tail,
  190. hr);
  191. if (NULL != hr->cb)
  192. hr->cb (hr->cb_cls,
  193. emsg);
  194. GNUNET_free (hr);
  195. if (NULL != slave->hr_dll_head)
  196. register_next_host (slave);
  197. }
  198. /**
  199. * Adds a host registration's request to a slave's registration queue
  200. *
  201. * @param slave the slave controller at which the given host has to be
  202. * registered
  203. * @param cb the host registration completion callback
  204. * @param cb_cls the closure for the host registration completion callback
  205. * @param host the host which has to be registered
  206. */
  207. void
  208. GST_queue_host_registration (struct Slave *slave,
  209. GNUNET_TESTBED_HostRegistrationCompletion cb,
  210. void *cb_cls,
  211. struct GNUNET_TESTBED_Host *host)
  212. {
  213. struct HostRegistration *hr;
  214. int call_register;
  215. LOG (GNUNET_ERROR_TYPE_DEBUG,
  216. "Queueing host registration for host %u at %u\n",
  217. GNUNET_TESTBED_host_get_id_ (host),
  218. GNUNET_TESTBED_host_get_id_ (GST_host_list[slave->host_id]));
  219. hr = GNUNET_new (struct HostRegistration);
  220. hr->cb = cb;
  221. hr->cb_cls = cb_cls;
  222. hr->host = host;
  223. call_register = (NULL == slave->hr_dll_head) ? GNUNET_YES : GNUNET_NO;
  224. GNUNET_CONTAINER_DLL_insert_tail (slave->hr_dll_head,
  225. slave->hr_dll_tail,
  226. hr);
  227. if (GNUNET_YES == call_register)
  228. register_next_host (slave);
  229. }
  230. /**
  231. * Callback to relay the reply msg of a forwarded operation back to the client
  232. *
  233. * @param cls ForwardedOperationContext
  234. * @param msg the message to relay
  235. */
  236. void
  237. GST_forwarded_operation_reply_relay (void *cls,
  238. const struct GNUNET_MessageHeader *msg)
  239. {
  240. struct ForwardedOperationContext *fopc = cls;
  241. struct GNUNET_MQ_Envelope *env;
  242. LOG_DEBUG ("Relaying message with type: %u, size: %u\n",
  243. ntohs (msg->type),
  244. ntohs (msg->size));
  245. env = GNUNET_MQ_msg_copy (msg);
  246. GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (fopc->client),
  247. env);
  248. GNUNET_SCHEDULER_cancel (fopc->timeout_task);
  249. GNUNET_CONTAINER_DLL_remove (fopcq_head,
  250. fopcq_tail,
  251. fopc);
  252. GNUNET_free (fopc);
  253. }
  254. /**
  255. * Task to free resources when forwarded operation has been timed out
  256. *
  257. * @param cls the ForwardedOperationContext
  258. */
  259. void
  260. GST_forwarded_operation_timeout (void *cls)
  261. {
  262. struct ForwardedOperationContext *fopc = cls;
  263. fopc->timeout_task = NULL;
  264. GNUNET_TESTBED_forward_operation_msg_cancel_ (fopc->opc);
  265. LOG (GNUNET_ERROR_TYPE_DEBUG,
  266. "A forwarded operation has timed out\n");
  267. GST_send_operation_fail_msg (fopc->client,
  268. fopc->operation_id,
  269. "A forwarded operation has timed out");
  270. GNUNET_CONTAINER_DLL_remove (fopcq_head,
  271. fopcq_tail,
  272. fopc);
  273. GNUNET_free (fopc);
  274. }
  275. /**
  276. * Parse service sharing specification line.
  277. * Format is "[<service:share>] [<service:share>] ..."
  278. *
  279. * @param ss_str the spec string to be parsed
  280. * @param cfg the configuration to use for shared services
  281. * @return an array suitable to pass to GNUNET_TESTING_system_create(). NULL
  282. * upon empty service sharing specification.
  283. */
  284. static struct GNUNET_TESTING_SharedService *
  285. parse_shared_services (char *ss_str,
  286. struct GNUNET_CONFIGURATION_Handle *cfg)
  287. {
  288. struct GNUNET_TESTING_SharedService ss;
  289. struct GNUNET_TESTING_SharedService *slist;
  290. char service[256];
  291. char *arg;
  292. unsigned int n;
  293. #define GROW_SS \
  294. do { \
  295. GNUNET_array_grow (slist, n, n+1); \
  296. GNUNET_memcpy (&slist[n - 1], &ss, \
  297. sizeof (struct GNUNET_TESTING_SharedService)); \
  298. } while (0)
  299. slist = NULL;
  300. n = 0;
  301. ss.cfg = cfg;
  302. for (; NULL != (arg = strtok (ss_str, " ")); ss_str = NULL)
  303. {
  304. ss.service = NULL;
  305. ss.share = 0;
  306. if (2 != sscanf (arg, "%255[^:]:%u",
  307. service,
  308. &ss.share))
  309. {
  310. LOG (GNUNET_ERROR_TYPE_WARNING,
  311. "Ignoring shared service spec: %s",
  312. arg);
  313. continue;
  314. }
  315. LOG_DEBUG ("Will be sharing %s service among %u peers\n",
  316. service,
  317. ss.share);
  318. ss.service = GNUNET_strdup (service);
  319. GROW_SS;
  320. }
  321. if (NULL != slist)
  322. {
  323. /* Add trailing NULL block */
  324. (void) memset (&ss,
  325. 0,
  326. sizeof (struct GNUNET_TESTING_SharedService));
  327. GROW_SS;
  328. }
  329. return slist;
  330. #undef GROW_SS
  331. }
  332. /**
  333. * Check #GNUNET_MESSAGE_TYPE_TESTBED_INIT messages
  334. *
  335. * @param cls identification of the client
  336. * @param message the actual message
  337. * @return #GNUNET_OK if @a message is well-formed
  338. */
  339. static int
  340. check_init (void *cls,
  341. const struct GNUNET_TESTBED_InitMessage *msg)
  342. {
  343. const char *controller_hostname;
  344. uint16_t msize;
  345. msize = ntohs (msg->header.size) - sizeof (struct GNUNET_TESTBED_InitMessage);
  346. controller_hostname = (const char *) &msg[1];
  347. if ('\0' != controller_hostname[msize - 1])
  348. {
  349. GNUNET_break (0);
  350. return GNUNET_SYSERR;
  351. }
  352. return GNUNET_OK;
  353. }
  354. /**
  355. * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_INIT messages
  356. *
  357. * @param cls identification of the client
  358. * @param message the actual message
  359. */
  360. static void
  361. handle_init (void *cls,
  362. const struct GNUNET_TESTBED_InitMessage *msg)
  363. {
  364. struct GNUNET_SERVICE_Client *client = cls;
  365. struct GNUNET_TESTBED_Host *host;
  366. const char *controller_hostname;
  367. char *ss_str;
  368. struct GNUNET_TESTING_SharedService *ss;
  369. unsigned int cnt;
  370. if (NULL != GST_context)
  371. {
  372. LOG_DEBUG ("We are being connected to laterally\n");
  373. GNUNET_SERVICE_client_continue (client);
  374. return;
  375. }
  376. controller_hostname = (const char *) &msg[1];
  377. ss_str = NULL;
  378. ss = NULL;
  379. if (GNUNET_OK ==
  380. GNUNET_CONFIGURATION_get_value_string (GST_config,
  381. "TESTBED",
  382. "SHARED_SERVICES",
  383. &ss_str))
  384. {
  385. ss = parse_shared_services (ss_str,
  386. GST_config);
  387. GNUNET_free (ss_str);
  388. ss_str = NULL;
  389. }
  390. GST_context = GNUNET_new (struct Context);
  391. GST_context->client = client;
  392. GST_context->host_id = ntohl (msg->host_id);
  393. GST_context->master_ip = GNUNET_strdup (controller_hostname);
  394. LOG_DEBUG ("Our IP: %s\n",
  395. GST_context->master_ip);
  396. GST_context->system
  397. = GNUNET_TESTING_system_create ("testbed",
  398. GST_context->master_ip,
  399. hostname,
  400. ss);
  401. if (NULL != ss)
  402. {
  403. for (cnt = 0; NULL != ss[cnt].service; cnt++)
  404. {
  405. ss_str = (char *) ss[cnt].service;
  406. GNUNET_free (ss_str);
  407. }
  408. GNUNET_free (ss);
  409. ss = NULL;
  410. }
  411. host =
  412. GNUNET_TESTBED_host_create_with_id (GST_context->host_id,
  413. GST_context->master_ip,
  414. NULL,
  415. GST_config,
  416. 0);
  417. host_list_add (host);
  418. LOG_DEBUG ("Created master context with host ID: %u\n",
  419. GST_context->host_id);
  420. GNUNET_SERVICE_client_continue (client);
  421. }
  422. /**
  423. * Check #GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
  424. *
  425. * @param cls identification of the client
  426. * @param msg the actual message
  427. * @return #GNUNET_OK if @a message is well-formed
  428. */
  429. static int
  430. check_add_host (void *cls,
  431. const struct GNUNET_TESTBED_AddHostMessage *msg)
  432. {
  433. uint16_t username_length;
  434. uint16_t hostname_length;
  435. uint16_t msize;
  436. msize = ntohs (msg->header.size) - sizeof (struct GNUNET_TESTBED_AddHostMessage);
  437. username_length = ntohs (msg->username_length);
  438. hostname_length = ntohs (msg->hostname_length);
  439. /* msg must contain hostname */
  440. if ( (msize <= username_length) ||
  441. (0 == hostname_length) )
  442. {
  443. GNUNET_break (0);
  444. return GNUNET_SYSERR;
  445. }
  446. /* msg must contain configuration */
  447. if (msize <= username_length + hostname_length)
  448. {
  449. GNUNET_break (0);
  450. return GNUNET_SYSERR;
  451. }
  452. return GNUNET_OK;
  453. }
  454. /**
  455. * Message handler for #GNUNET_MESSAGE_TYPE_TESTBED_ADDHOST messages
  456. *
  457. * @param cls identification of the client
  458. * @param msg the actual message
  459. */
  460. static void
  461. handle_add_host (void *cls,
  462. const struct GNUNET_TESTBED_AddHostMessage *msg)
  463. {
  464. struct GNUNET_SERVICE_Client *client = cls;
  465. struct GNUNET_TESTBED_Host *host;
  466. struct GNUNET_TESTBED_HostConfirmedMessage *reply;
  467. struct GNUNET_CONFIGURATION_Handle *host_cfg;
  468. char *username;
  469. char *hostname;
  470. char *emsg;
  471. const void *ptr;
  472. uint32_t host_id;
  473. uint16_t username_length;
  474. uint16_t hostname_length;
  475. struct GNUNET_MQ_Envelope *env;
  476. username_length = ntohs (msg->username_length);
  477. hostname_length = ntohs (msg->hostname_length);
  478. username = NULL;
  479. hostname = NULL;
  480. ptr = &msg[1];
  481. if (0 != username_length)
  482. {
  483. username = GNUNET_malloc (username_length + 1);
  484. GNUNET_strlcpy (username, ptr, username_length + 1);
  485. ptr += username_length;
  486. }
  487. hostname = GNUNET_malloc (hostname_length + 1);
  488. GNUNET_strlcpy (hostname, ptr, hostname_length + 1);
  489. if (NULL == (host_cfg = GNUNET_TESTBED_extract_config_ (&msg->header)))
  490. {
  491. GNUNET_free_non_null (username);
  492. GNUNET_free_non_null (hostname);
  493. GNUNET_break_op (0);
  494. GNUNET_SERVICE_client_drop (client);
  495. return;
  496. }
  497. host_id = ntohl (msg->host_id);
  498. LOG_DEBUG ("Received ADDHOST %u message\n", host_id);
  499. LOG_DEBUG ("-------host id: %u\n", host_id);
  500. LOG_DEBUG ("-------hostname: %s\n", hostname);
  501. if (NULL != username)
  502. LOG_DEBUG ("-------username: %s\n", username);
  503. else
  504. LOG_DEBUG ("-------username: <not given>\n");
  505. LOG_DEBUG ("-------ssh port: %u\n", ntohs (msg->ssh_port));
  506. host = GNUNET_TESTBED_host_create_with_id (host_id,
  507. hostname,
  508. username,
  509. host_cfg,
  510. ntohs (msg->ssh_port));
  511. GNUNET_free_non_null (username);
  512. GNUNET_free (hostname);
  513. GNUNET_CONFIGURATION_destroy (host_cfg);
  514. if (NULL == host)
  515. {
  516. GNUNET_break_op (0);
  517. GNUNET_SERVICE_client_drop (client);
  518. return;
  519. }
  520. if (GNUNET_OK != host_list_add (host))
  521. {
  522. /* We are unable to add a host */
  523. emsg = "A host exists with given host-id";
  524. LOG_DEBUG ("%s: %u",
  525. emsg,
  526. host_id);
  527. GNUNET_TESTBED_host_destroy (host);
  528. env = GNUNET_MQ_msg_extra (reply,
  529. strlen (emsg) + 1,
  530. GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST_SUCCESS);
  531. GNUNET_memcpy (&reply[1],
  532. emsg,
  533. strlen (emsg) + 1);
  534. }
  535. else
  536. {
  537. LOG_DEBUG ("Added host %u at %u\n",
  538. host_id,
  539. GST_context->host_id);
  540. env = GNUNET_MQ_msg (reply,
  541. GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST_SUCCESS);
  542. }
  543. reply->host_id = htonl (host_id);
  544. GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
  545. env);
  546. GNUNET_SERVICE_client_continue (client);
  547. }
  548. /**
  549. * Handler for #GNUNET_MESSAGE_TYPE_TESTBED_GETSLAVECONFIG messages
  550. *
  551. * @param cls identification of the client
  552. * @param msg the actual message
  553. */
  554. static void
  555. handle_slave_get_config (void *cls,
  556. const struct GNUNET_TESTBED_SlaveGetConfigurationMessage *msg)
  557. {
  558. struct GNUNET_SERVICE_Client *client = cls;
  559. struct Slave *slave;
  560. struct GNUNET_TESTBED_SlaveConfiguration *reply;
  561. const struct GNUNET_CONFIGURATION_Handle *cfg;
  562. struct GNUNET_MQ_Envelope *env;
  563. char *config;
  564. char *xconfig;
  565. size_t config_size;
  566. size_t xconfig_size;
  567. uint64_t op_id;
  568. uint32_t slave_id;
  569. slave_id = ntohl (msg->slave_id);
  570. op_id = GNUNET_ntohll (msg->operation_id);
  571. if ( (GST_slave_list_size <= slave_id) ||
  572. (NULL == GST_slave_list[slave_id]) )
  573. {
  574. /* FIXME: Add forwardings for this type of message here.. */
  575. GST_send_operation_fail_msg (client,
  576. op_id,
  577. "Slave not found");
  578. GNUNET_SERVICE_client_continue (client);
  579. return;
  580. }
  581. slave = GST_slave_list[slave_id];
  582. GNUNET_assert (NULL != (cfg = GNUNET_TESTBED_host_get_cfg_ (GST_host_list[slave->host_id])));
  583. config = GNUNET_CONFIGURATION_serialize (cfg,
  584. &config_size);
  585. /* FIXME: maybe we want to transmit the delta to the default here? */
  586. xconfig_size = GNUNET_TESTBED_compress_config_ (config,
  587. config_size,
  588. &xconfig);
  589. GNUNET_free (config);
  590. GNUNET_assert (xconfig_size + sizeof (struct GNUNET_TESTBED_SlaveConfiguration) <= UINT16_MAX);
  591. GNUNET_assert (xconfig_size <= UINT16_MAX);
  592. env = GNUNET_MQ_msg_extra (reply,
  593. xconfig_size,
  594. GNUNET_MESSAGE_TYPE_TESTBED_SLAVE_CONFIGURATION);
  595. reply->slave_id = msg->slave_id;
  596. reply->operation_id = msg->operation_id;
  597. reply->config_size = htons ((uint16_t) config_size);
  598. GNUNET_memcpy (&reply[1],
  599. xconfig,
  600. xconfig_size);
  601. GNUNET_free (xconfig);
  602. GNUNET_MQ_send (GNUNET_SERVICE_client_get_mq (client),
  603. env);
  604. GNUNET_SERVICE_client_continue (client);
  605. }
  606. /**
  607. * Clears the forwarded operations queue
  608. */
  609. void
  610. GST_clear_fopcq ()
  611. {
  612. struct ForwardedOperationContext *fopc;
  613. while (NULL != (fopc = fopcq_head))
  614. {
  615. GNUNET_CONTAINER_DLL_remove (fopcq_head,
  616. fopcq_tail,
  617. fopc);
  618. GNUNET_TESTBED_forward_operation_msg_cancel_ (fopc->opc);
  619. if (NULL != fopc->timeout_task)
  620. GNUNET_SCHEDULER_cancel (fopc->timeout_task);
  621. switch (fopc->type)
  622. {
  623. case OP_PEER_CREATE:
  624. GNUNET_free (fopc->cls);
  625. break;
  626. case OP_SHUTDOWN_PEERS:
  627. {
  628. struct HandlerContext_ShutdownPeers *hc = fopc->cls;
  629. GNUNET_assert (0 < hc->nslaves);
  630. hc->nslaves--;
  631. if (0 == hc->nslaves)
  632. GNUNET_free (hc);
  633. }
  634. break;
  635. case OP_PEER_START:
  636. case OP_PEER_STOP:
  637. case OP_PEER_DESTROY:
  638. case OP_PEER_INFO:
  639. case OP_OVERLAY_CONNECT:
  640. case OP_LINK_CONTROLLERS:
  641. case OP_GET_SLAVE_CONFIG:
  642. case OP_MANAGE_SERVICE:
  643. case OP_PEER_RECONFIGURE:
  644. break;
  645. case OP_FORWARDED:
  646. GNUNET_assert (0);
  647. };
  648. GNUNET_free (fopc);
  649. }
  650. }
  651. /**
  652. * Task to clean up and shutdown nicely
  653. *
  654. * @param cls NULL
  655. */
  656. static void
  657. shutdown_task (void *cls)
  658. {
  659. uint32_t id;
  660. LOG_DEBUG ("Shutting down testbed service\n");
  661. /* cleanup any remaining forwarded operations */
  662. GST_clear_fopcq ();
  663. GST_free_lcf ();
  664. GST_free_mctxq ();
  665. GST_free_occq ();
  666. GST_free_roccq ();
  667. GST_free_nccq ();
  668. GST_neighbour_list_clean();
  669. GST_free_prcq ();
  670. /* Clear peer list */
  671. GST_destroy_peers ();
  672. /* Clear route list */
  673. GST_route_list_clear ();
  674. /* Clear GST_slave_list */
  675. GST_slave_list_clear ();
  676. /* Clear host list */
  677. for (id = 0; id < GST_host_list_size; id++)
  678. if (NULL != GST_host_list[id])
  679. GNUNET_TESTBED_host_destroy (GST_host_list[id]);
  680. GNUNET_free_non_null (GST_host_list);
  681. if (NULL != GST_context)
  682. {
  683. GNUNET_free_non_null (GST_context->master_ip);
  684. if (NULL != GST_context->system)
  685. GNUNET_TESTING_system_destroy (GST_context->system,
  686. GNUNET_YES);
  687. GNUNET_free (GST_context);
  688. GST_context = NULL;
  689. }
  690. GNUNET_free_non_null (hostname);
  691. /* Free hello cache */
  692. GST_cache_clear ();
  693. GST_connection_pool_destroy ();
  694. GNUNET_TESTBED_operation_queue_destroy_ (GST_opq_openfds);
  695. GST_opq_openfds = NULL;
  696. GST_stats_destroy ();
  697. GST_barriers_destroy ();
  698. GNUNET_CONFIGURATION_destroy (GST_config);
  699. }
  700. /**
  701. * Callback for client connect
  702. *
  703. * @param cls NULL
  704. * @param client the client which has disconnected
  705. * @param mq queue for sending messages to @a client
  706. * @return @a client
  707. */
  708. static void *
  709. client_connect_cb (void *cls,
  710. struct GNUNET_SERVICE_Client *client,
  711. struct GNUNET_MQ_Handle *mq)
  712. {
  713. return client;
  714. }
  715. /**
  716. * Callback for client disconnect
  717. *
  718. * @param cls NULL
  719. * @param client the client which has disconnected
  720. * @param app_ctx should match @a client
  721. */
  722. static void
  723. client_disconnect_cb (void *cls,
  724. struct GNUNET_SERVICE_Client *client,
  725. void *app_ctx)
  726. {
  727. struct ForwardedOperationContext *fopc;
  728. struct ForwardedOperationContext *fopcn;
  729. GNUNET_assert (client == app_ctx);
  730. GST_notify_client_disconnect_oc (client);
  731. GST_link_notify_disconnect (client);
  732. GST_notify_client_disconnect_peers (client);
  733. for (fopc = fopcq_head; NULL != fopc; fopc = fopcn)
  734. {
  735. fopcn = fopc->next;
  736. if (fopc->client == client)
  737. {
  738. /* handle as if it were a timeout */
  739. GNUNET_SCHEDULER_cancel (fopc->timeout_task);
  740. GST_forwarded_operation_timeout (fopc);
  741. }
  742. }
  743. if (NULL == GST_context)
  744. return;
  745. if (client == GST_context->client)
  746. {
  747. LOG (GNUNET_ERROR_TYPE_DEBUG,
  748. "Master client disconnected\n");
  749. GST_context->client = NULL;
  750. /* should not be needed as we're terminated by failure to read
  751. * from stdin, but if stdin fails for some reason, this shouldn't
  752. * hurt for now --- might need to revise this later if we ever
  753. * decide that master connections might be temporarily down
  754. * for some reason */
  755. //GNUNET_SCHEDULER_shutdown ();
  756. }
  757. }
  758. /**
  759. * Testbed setup
  760. *
  761. * @param cls closure
  762. * @param cfg configuration to use
  763. * @param service the initialized server
  764. */
  765. static void
  766. testbed_run (void *cls,
  767. const struct GNUNET_CONFIGURATION_Handle *cfg,
  768. struct GNUNET_SERVICE_Handle *service)
  769. {
  770. char *logfile;
  771. unsigned long long num;
  772. LOG_DEBUG ("Starting testbed\n");
  773. if (GNUNET_OK ==
  774. GNUNET_CONFIGURATION_get_value_filename (cfg, "TESTBED", "LOG_FILE",
  775. &logfile))
  776. {
  777. GNUNET_break (GNUNET_OK ==
  778. GNUNET_log_setup ("testbed",
  779. "DEBUG",
  780. logfile));
  781. GNUNET_free (logfile);
  782. }
  783. GNUNET_assert (GNUNET_OK ==
  784. GNUNET_CONFIGURATION_get_value_number (cfg,
  785. "TESTBED",
  786. "CACHE_SIZE",
  787. &num));
  788. GST_cache_init ((unsigned int) num);
  789. GST_connection_pool_init ((unsigned int) num);
  790. GNUNET_assert (GNUNET_OK ==
  791. GNUNET_CONFIGURATION_get_value_number (cfg,
  792. "TESTBED",
  793. "MAX_OPEN_FDS",
  794. &num));
  795. GST_opq_openfds = GNUNET_TESTBED_operation_queue_create_ (OPERATION_QUEUE_TYPE_FIXED,
  796. (unsigned int) num);
  797. GNUNET_assert (GNUNET_OK ==
  798. GNUNET_CONFIGURATION_get_value_time (cfg,
  799. "TESTBED",
  800. "OPERATION_TIMEOUT",
  801. (struct GNUNET_TIME_Relative *)
  802. &GST_timeout));
  803. GNUNET_assert (GNUNET_OK ==
  804. GNUNET_CONFIGURATION_get_value_string (cfg,
  805. "testbed",
  806. "HOSTNAME",
  807. &hostname));
  808. GST_config = GNUNET_CONFIGURATION_dup (cfg);
  809. GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
  810. NULL);
  811. LOG_DEBUG ("Testbed startup complete\n");
  812. GST_stats_init (GST_config);
  813. GST_barriers_init (GST_config);
  814. }
  815. /**
  816. * Define "main" method using service macro.
  817. */
  818. GNUNET_SERVICE_MAIN
  819. ("testbed",
  820. GNUNET_SERVICE_OPTION_NONE,
  821. &testbed_run,
  822. &client_connect_cb,
  823. &client_disconnect_cb,
  824. NULL,
  825. GNUNET_MQ_hd_var_size (init,
  826. GNUNET_MESSAGE_TYPE_TESTBED_INIT,
  827. struct GNUNET_TESTBED_InitMessage,
  828. NULL),
  829. GNUNET_MQ_hd_var_size (add_host,
  830. GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST,
  831. struct GNUNET_TESTBED_AddHostMessage,
  832. NULL),
  833. GNUNET_MQ_hd_fixed_size (slave_get_config,
  834. GNUNET_MESSAGE_TYPE_TESTBED_GET_SLAVE_CONFIGURATION,
  835. struct GNUNET_TESTBED_SlaveGetConfigurationMessage,
  836. NULL),
  837. GNUNET_MQ_hd_fixed_size (link_controllers,
  838. GNUNET_MESSAGE_TYPE_TESTBED_LINK_CONTROLLERS,
  839. struct GNUNET_TESTBED_ControllerLinkRequest,
  840. NULL),
  841. GNUNET_MQ_hd_var_size (remote_overlay_connect,
  842. GNUNET_MESSAGE_TYPE_TESTBED_REMOTE_OVERLAY_CONNECT,
  843. struct GNUNET_TESTBED_RemoteOverlayConnectMessage,
  844. NULL),
  845. GNUNET_MQ_hd_fixed_size (overlay_connect,
  846. GNUNET_MESSAGE_TYPE_TESTBED_OVERLAY_CONNECT,
  847. struct GNUNET_TESTBED_OverlayConnectMessage,
  848. NULL),
  849. GNUNET_MQ_hd_var_size (peer_create,
  850. GNUNET_MESSAGE_TYPE_TESTBED_CREATE_PEER,
  851. struct GNUNET_TESTBED_PeerCreateMessage,
  852. NULL),
  853. GNUNET_MQ_hd_fixed_size (peer_destroy,
  854. GNUNET_MESSAGE_TYPE_TESTBED_DESTROY_PEER,
  855. struct GNUNET_TESTBED_PeerDestroyMessage,
  856. NULL),
  857. GNUNET_MQ_hd_fixed_size (peer_start,
  858. GNUNET_MESSAGE_TYPE_TESTBED_START_PEER,
  859. struct GNUNET_TESTBED_PeerStartMessage,
  860. NULL),
  861. GNUNET_MQ_hd_fixed_size (peer_stop,
  862. GNUNET_MESSAGE_TYPE_TESTBED_STOP_PEER,
  863. struct GNUNET_TESTBED_PeerStopMessage,
  864. NULL),
  865. GNUNET_MQ_hd_fixed_size (peer_get_config,
  866. GNUNET_MESSAGE_TYPE_TESTBED_GET_PEER_INFORMATION,
  867. struct GNUNET_TESTBED_PeerGetConfigurationMessage,
  868. NULL),
  869. GNUNET_MQ_hd_var_size (manage_peer_service,
  870. GNUNET_MESSAGE_TYPE_TESTBED_MANAGE_PEER_SERVICE,
  871. struct GNUNET_TESTBED_ManagePeerServiceMessage,
  872. NULL),
  873. GNUNET_MQ_hd_fixed_size (shutdown_peers,
  874. GNUNET_MESSAGE_TYPE_TESTBED_SHUTDOWN_PEERS,
  875. struct GNUNET_TESTBED_ShutdownPeersMessage,
  876. NULL),
  877. GNUNET_MQ_hd_var_size (peer_reconfigure,
  878. GNUNET_MESSAGE_TYPE_TESTBED_RECONFIGURE_PEER,
  879. struct GNUNET_TESTBED_PeerReconfigureMessage,
  880. NULL),
  881. GNUNET_MQ_hd_var_size (barrier_init,
  882. GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_INIT,
  883. struct GNUNET_TESTBED_BarrierInit,
  884. NULL),
  885. GNUNET_MQ_hd_var_size (barrier_cancel,
  886. GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_CANCEL,
  887. struct GNUNET_TESTBED_BarrierCancel,
  888. NULL),
  889. GNUNET_MQ_hd_var_size (barrier_status,
  890. GNUNET_MESSAGE_TYPE_TESTBED_BARRIER_STATUS,
  891. struct GNUNET_TESTBED_BarrierStatusMsg,
  892. NULL),
  893. GNUNET_MQ_handler_end ());
  894. /* end of gnunet-service-testbed.c */