testbed_api_hosts.c 44 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539
  1. /*
  2. This file is part of GNUnet
  3. Copyright (C) 2008--2013 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/testbed_api_hosts.c
  18. * @brief API for manipulating 'hosts' controlled by the GNUnet testing service;
  19. * allows parsing hosts files, starting, stopping and communicating (via
  20. * SSH/stdin/stdout) with the remote (or local) processes
  21. * @author Christian Grothoff
  22. */
  23. #include "platform.h"
  24. #include "gnunet_util_lib.h"
  25. #include "gnunet_testbed_service.h"
  26. #include "gnunet_core_service.h"
  27. #include "gnunet_transport_service.h"
  28. #include "testbed_api.h"
  29. #include "testbed_api_hosts.h"
  30. #include "testbed_helper.h"
  31. #include "testbed_api_operations.h"
  32. #include <zlib.h>
  33. #include <regex.h>
  34. /**
  35. * Generic logging shorthand
  36. */
  37. #define LOG(kind, ...) \
  38. GNUNET_log_from (kind, "testbed-api-hosts", __VA_ARGS__);
  39. /**
  40. * Debug logging shorthand
  41. */
  42. #define LOG_DEBUG(...) \
  43. LOG (GNUNET_ERROR_TYPE_DEBUG, __VA_ARGS__);
  44. /**
  45. * Prints API violation message
  46. */
  47. #define API_VIOLATION(cond,errstr) \
  48. do { \
  49. if (cond) \
  50. break; \
  51. LOG (GNUNET_ERROR_TYPE_ERROR, "API violation detected: %s\n", errstr); \
  52. GNUNET_assert (0); \
  53. } while (0)
  54. /**
  55. * Log an error message at log-level 'level' that indicates a failure of the
  56. * command 'cmd' with the message given by gai_strerror(rc).
  57. */
  58. #define LOG_GAI(level, cmd, rc) do { LOG(level, _("`%s' failed at %s:%d with error: %s\n"), cmd, __FILE__, __LINE__, gai_strerror(rc)); } while(0)
  59. /**
  60. * Number of extra elements we create space for when we grow host list
  61. */
  62. #define HOST_LIST_GROW_STEP 10
  63. /**
  64. * A list entry for registered controllers list
  65. */
  66. struct RegisteredController
  67. {
  68. /**
  69. * The controller at which this host is registered
  70. */
  71. const struct GNUNET_TESTBED_Controller *controller;
  72. /**
  73. * The next ptr for DLL
  74. */
  75. struct RegisteredController *next;
  76. /**
  77. * The prev ptr for DLL
  78. */
  79. struct RegisteredController *prev;
  80. };
  81. /**
  82. * Opaque handle to a host running experiments managed by the testing framework.
  83. * The master process must be able to SSH to this host without password (via
  84. * ssh-agent).
  85. */
  86. struct GNUNET_TESTBED_Host
  87. {
  88. /**
  89. * The hostname of the host; NULL for localhost
  90. */
  91. const char *hostname;
  92. /**
  93. * The username to be used for SSH login
  94. */
  95. const char *username;
  96. /**
  97. * the configuration to use as a template while starting a controller on this
  98. * host. Operation queue size specific to a host are also read from this
  99. * configuration handle. After starting the controller, it points to the actual
  100. * configuration with which the controller is running
  101. */
  102. struct GNUNET_CONFIGURATION_Handle *cfg;
  103. /**
  104. * The head for the list of controllers where this host is registered
  105. */
  106. struct RegisteredController *rc_head;
  107. /**
  108. * The tail for the list of controllers where this host is registered
  109. */
  110. struct RegisteredController *rc_tail;
  111. /**
  112. * Operation queue for simultaneous overlay connect operations target at this
  113. * host
  114. */
  115. struct OperationQueue *opq_parallel_overlay_connect_operations;
  116. /**
  117. * Is a controller started on this host? FIXME: Is this needed?
  118. */
  119. int controller_started;
  120. /**
  121. * Is this host locked by GNUNET_TESTBED_controller_start()?
  122. */
  123. int locked;
  124. /**
  125. * Global ID we use to refer to a host on the network
  126. */
  127. uint32_t id;
  128. /**
  129. * The port which is to be used for SSH
  130. */
  131. uint16_t port;
  132. };
  133. /**
  134. * Array of available hosts
  135. */
  136. static struct GNUNET_TESTBED_Host **host_list;
  137. /**
  138. * The size of the available hosts list
  139. */
  140. static unsigned int host_list_size;
  141. /**
  142. * Lookup a host by ID.
  143. *
  144. * @param id global host ID assigned to the host; 0 is
  145. * reserved to always mean 'localhost'
  146. * @return handle to the host, NULL if host not found
  147. */
  148. struct GNUNET_TESTBED_Host *
  149. GNUNET_TESTBED_host_lookup_by_id_ (uint32_t id)
  150. {
  151. if (host_list_size <= id)
  152. return NULL;
  153. return host_list[id];
  154. }
  155. /**
  156. * Create a host by ID; given this host handle, we could not
  157. * run peers at the host, but we can talk about the host
  158. * internally.
  159. *
  160. * @param id global host ID assigned to the host; 0 is
  161. * reserved to always mean 'localhost'
  162. * @param cfg the configuration to use as a template while starting a controller
  163. * on this host. Operation queue sizes specific to a host are also
  164. * read from this configuration handle
  165. * @return handle to the host, NULL on error
  166. */
  167. struct GNUNET_TESTBED_Host *
  168. GNUNET_TESTBED_host_create_by_id_ (uint32_t id,
  169. const struct GNUNET_CONFIGURATION_Handle *cfg)
  170. {
  171. return GNUNET_TESTBED_host_create_with_id (id, NULL, NULL, cfg, 0);
  172. }
  173. /**
  174. * Obtain the host's unique global ID.
  175. *
  176. * @param host handle to the host, NULL means 'localhost'
  177. * @return id global host ID assigned to the host (0 is
  178. * 'localhost', but then obviously not globally unique)
  179. */
  180. uint32_t
  181. GNUNET_TESTBED_host_get_id_ (const struct GNUNET_TESTBED_Host * host)
  182. {
  183. return host->id;
  184. }
  185. /**
  186. * Obtain the host's hostname.
  187. *
  188. * @param host handle to the host, NULL means 'localhost'
  189. * @return hostname of the host
  190. */
  191. const char *
  192. GNUNET_TESTBED_host_get_hostname (const struct GNUNET_TESTBED_Host *host)
  193. {
  194. return host->hostname;
  195. }
  196. /**
  197. * Obtain the host's username
  198. *
  199. * @param host handle to the host, NULL means 'localhost'
  200. * @return username to login to the host
  201. */
  202. const char *
  203. GNUNET_TESTBED_host_get_username_ (const struct GNUNET_TESTBED_Host *host)
  204. {
  205. return host->username;
  206. }
  207. /**
  208. * Obtain the host's ssh port
  209. *
  210. * @param host handle to the host, NULL means 'localhost'
  211. * @return username to login to the host
  212. */
  213. uint16_t
  214. GNUNET_TESTBED_host_get_ssh_port_ (const struct GNUNET_TESTBED_Host * host)
  215. {
  216. return host->port;
  217. }
  218. /**
  219. * Check whether a controller is already started on the given host
  220. *
  221. * @param host the handle to the host
  222. * @return GNUNET_YES if the controller is already started; GNUNET_NO if not
  223. */
  224. int
  225. GNUNET_TESTBED_host_controller_started (const struct GNUNET_TESTBED_Host *host)
  226. {
  227. return host->controller_started;
  228. }
  229. /**
  230. * Obtain the host's configuration template
  231. *
  232. * @param host handle to the host
  233. * @return the host's configuration template
  234. */
  235. const struct GNUNET_CONFIGURATION_Handle *
  236. GNUNET_TESTBED_host_get_cfg_ (const struct GNUNET_TESTBED_Host *host)
  237. {
  238. return host->cfg;
  239. }
  240. /**
  241. * Function to replace host's configuration
  242. *
  243. * @param host the host handle
  244. * @param new_cfg the new configuration to replace the old one
  245. */
  246. void
  247. GNUNET_TESTBED_host_replace_cfg_ (struct GNUNET_TESTBED_Host *host,
  248. const struct GNUNET_CONFIGURATION_Handle *new_cfg)
  249. {
  250. GNUNET_CONFIGURATION_destroy (host->cfg);
  251. host->cfg = GNUNET_CONFIGURATION_dup (new_cfg);
  252. }
  253. /**
  254. * Create a host to run peers and controllers on.
  255. *
  256. * @param id global host ID assigned to the host; 0 is
  257. * reserved to always mean 'localhost'
  258. * @param hostname name of the host, use "NULL" for localhost
  259. * @param username username to use for the login; may be NULL
  260. * @param cfg the configuration to use as a template while starting a controller
  261. * on this host. Operation queue sizes specific to a host are also
  262. * read from this configuration handle
  263. * @param port port number to use for ssh; use 0 to let ssh decide
  264. * @return handle to the host, NULL on error
  265. */
  266. struct GNUNET_TESTBED_Host *
  267. GNUNET_TESTBED_host_create_with_id (uint32_t id, const char *hostname,
  268. const char *username,
  269. const struct GNUNET_CONFIGURATION_Handle
  270. *cfg,
  271. uint16_t port)
  272. {
  273. struct GNUNET_TESTBED_Host *host;
  274. unsigned int new_size;
  275. if ((id < host_list_size) && (NULL != host_list[id]))
  276. {
  277. LOG (GNUNET_ERROR_TYPE_WARNING, "Host with id: %u already created\n", id);
  278. return NULL;
  279. }
  280. host = GNUNET_new (struct GNUNET_TESTBED_Host);
  281. host->hostname = (NULL != hostname) ? GNUNET_strdup (hostname) : NULL;
  282. host->username = (NULL != username) ? GNUNET_strdup (username) : NULL;
  283. host->id = id;
  284. host->port = (0 == port) ? 22 : port;
  285. host->cfg = GNUNET_CONFIGURATION_dup (cfg);
  286. host->opq_parallel_overlay_connect_operations =
  287. GNUNET_TESTBED_operation_queue_create_ (OPERATION_QUEUE_TYPE_ADAPTIVE,
  288. UINT_MAX);
  289. new_size = host_list_size;
  290. while (id >= new_size)
  291. new_size += HOST_LIST_GROW_STEP;
  292. if (new_size != host_list_size)
  293. GNUNET_array_grow (host_list, host_list_size, new_size);
  294. GNUNET_assert (id < host_list_size);
  295. LOG (GNUNET_ERROR_TYPE_DEBUG, "Adding host with id: %u\n", host->id);
  296. host_list[id] = host;
  297. return host;
  298. }
  299. /**
  300. * Create a host to run peers and controllers on.
  301. *
  302. * @param hostname name of the host, use "NULL" for localhost
  303. * @param username username to use for the login; may be NULL
  304. * @param cfg the configuration to use as a template while starting a controller
  305. * on this host. Operation queue sizes specific to a host are also
  306. * read from this configuration handle
  307. * @param port port number to use for ssh; use 0 to let ssh decide
  308. * @return handle to the host, NULL on error
  309. */
  310. struct GNUNET_TESTBED_Host *
  311. GNUNET_TESTBED_host_create (const char *hostname, const char *username,
  312. const struct GNUNET_CONFIGURATION_Handle *cfg,
  313. uint16_t port)
  314. {
  315. static uint32_t uid_generator;
  316. if (NULL == hostname)
  317. return GNUNET_TESTBED_host_create_with_id (0, hostname, username,
  318. cfg, port);
  319. return GNUNET_TESTBED_host_create_with_id (++uid_generator, hostname,
  320. username, cfg, port);
  321. }
  322. /**
  323. * Load a set of hosts from a configuration file.
  324. *
  325. * @param filename file with the host specification
  326. * @param cfg the configuration to use as a template while starting a controller
  327. * on any of the loaded hosts. Operation queue sizes specific to a host
  328. * are also read from this configuration handle
  329. * @param hosts set to the hosts found in the file; caller must free this if
  330. * number of hosts returned is greater than 0
  331. * @return number of hosts returned in 'hosts', 0 on error
  332. */
  333. unsigned int
  334. GNUNET_TESTBED_hosts_load_from_file (const char *filename,
  335. const struct GNUNET_CONFIGURATION_Handle
  336. *cfg,
  337. struct GNUNET_TESTBED_Host ***hosts)
  338. {
  339. struct GNUNET_TESTBED_Host *starting_host;
  340. char *data;
  341. char *buf;
  342. char *username;
  343. char *hostname;
  344. regex_t rex;
  345. regmatch_t pmatch[6];
  346. uint64_t fs;
  347. short int port;
  348. unsigned int offset;
  349. unsigned int count;
  350. GNUNET_assert (NULL != filename);
  351. if (GNUNET_YES != GNUNET_DISK_file_test (filename))
  352. {
  353. LOG (GNUNET_ERROR_TYPE_WARNING, _("Hosts file %s not found\n"), filename);
  354. return 0;
  355. }
  356. if (GNUNET_OK !=
  357. GNUNET_DISK_file_size (filename, &fs, GNUNET_YES, GNUNET_YES))
  358. fs = 0;
  359. if (0 == fs)
  360. {
  361. LOG (GNUNET_ERROR_TYPE_WARNING, _("Hosts file %s has no data\n"), filename);
  362. return 0;
  363. }
  364. data = GNUNET_malloc (fs);
  365. if (fs != GNUNET_DISK_fn_read (filename, data, fs))
  366. {
  367. GNUNET_free (data);
  368. LOG (GNUNET_ERROR_TYPE_WARNING, _("Hosts file %s cannot be read\n"),
  369. filename);
  370. return 0;
  371. }
  372. buf = data;
  373. offset = 0;
  374. starting_host = NULL;
  375. count = 0;
  376. /* refer RFC 952 and RFC 1123 for valid hostnames */
  377. GNUNET_assert (0 == regcomp (&rex,
  378. "^(([[:alnum:]]+)@)?" /* username */
  379. "([[:alnum:]]+[-[:alnum:]_\\.]+)" /* hostname */
  380. "(:([[:digit:]]{1,5}))?", /* port */
  381. REG_EXTENDED | REG_ICASE));
  382. while (offset < (fs - 1))
  383. {
  384. offset++;
  385. if (((data[offset] == '\n')) && (buf != &data[offset]))
  386. {
  387. unsigned int size;
  388. data[offset] = '\0';
  389. username = NULL;
  390. hostname = NULL;
  391. port = 0;
  392. if ((REG_NOMATCH == regexec (&rex, buf, 6, pmatch, 0))
  393. || (-1 == pmatch[3].rm_so))
  394. {
  395. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  396. "Error reading line `%s' in hostfile\n", buf);
  397. buf = &data[offset + 1];
  398. continue;
  399. }
  400. if (-1 != pmatch[2].rm_so)
  401. {
  402. size = pmatch[2].rm_eo - pmatch[2].rm_so;
  403. username = GNUNET_malloc (size + 1);
  404. username[size] = '\0';
  405. GNUNET_assert (NULL != strncpy (username, buf + pmatch[2].rm_so, size));
  406. }
  407. if (-1 != pmatch[5].rm_so)
  408. {
  409. (void) SSCANF (buf + pmatch[5].rm_so, "%5hd", &port);
  410. }
  411. size = pmatch[3].rm_eo - pmatch[3].rm_so;
  412. hostname = GNUNET_malloc (size + 1);
  413. hostname[size] = '\0';
  414. GNUNET_assert (NULL != strncpy (hostname, buf + pmatch[3].rm_so, size));
  415. LOG (GNUNET_ERROR_TYPE_DEBUG,
  416. "Successfully read host %s, port %d and user %s from file\n",
  417. (NULL == hostname) ? "NULL" : hostname,
  418. port,
  419. (NULL == username) ? "NULL" : username);
  420. /* We store hosts in a static list; hence we only require the starting
  421. * host pointer in that list to access the newly created list of hosts */
  422. if (NULL == starting_host)
  423. starting_host = GNUNET_TESTBED_host_create (hostname, username, cfg,
  424. port);
  425. else
  426. (void) GNUNET_TESTBED_host_create (hostname, username, cfg, port);
  427. count++;
  428. GNUNET_free_non_null (username);
  429. GNUNET_free (hostname);
  430. buf = &data[offset + 1];
  431. }
  432. else if ((data[offset] == '\n') || (data[offset] == '\0'))
  433. buf = &data[offset + 1];
  434. }
  435. regfree (&rex);
  436. GNUNET_free (data);
  437. if (NULL == starting_host)
  438. return 0;
  439. *hosts = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Host *) * count);
  440. GNUNET_memcpy (*hosts,
  441. &host_list[GNUNET_TESTBED_host_get_id_ (starting_host)],
  442. sizeof (struct GNUNET_TESTBED_Host *) * count);
  443. return count;
  444. }
  445. /**
  446. * Resolves a hostname using getaddrinfo
  447. *
  448. * @param host the hostname
  449. * @return the string representing the IPv4 address of the given host; NULL upon error
  450. */
  451. const char *
  452. simple_resolve (const char *host)
  453. {
  454. struct addrinfo *res;
  455. const struct sockaddr_in *in_addr;
  456. char *hostip;
  457. struct addrinfo hint;
  458. unsigned int rc;
  459. hint.ai_family = AF_INET; /* IPv4 */
  460. hint.ai_socktype = 0;
  461. hint.ai_protocol = 0;
  462. hint.ai_addrlen = 0;
  463. hint.ai_addr = NULL;
  464. hint.ai_canonname = NULL;
  465. hint.ai_next = NULL;
  466. hint.ai_flags = AI_NUMERICSERV;
  467. res = NULL;
  468. LOG_DEBUG ("Resolving [%s]\n", host);
  469. if (0 != (rc = getaddrinfo (host, "22", &hint, &res)))
  470. {
  471. LOG_GAI (GNUNET_ERROR_TYPE_ERROR, "getaddrinfo", rc);
  472. return NULL;
  473. }
  474. GNUNET_assert (NULL != res);
  475. GNUNET_assert (NULL != res->ai_addr);
  476. GNUNET_assert (sizeof (struct sockaddr_in) == res->ai_addrlen);
  477. in_addr = (const struct sockaddr_in *) res->ai_addr;
  478. hostip = inet_ntoa (in_addr->sin_addr);
  479. GNUNET_assert (NULL != hostip);
  480. freeaddrinfo (res);
  481. LOG_DEBUG ("Resolved [%s] to [%s]\n", host, hostip);
  482. return hostip;
  483. }
  484. /**
  485. * Loads the set of host allocated by the LoadLeveler Job Scheduler. This
  486. * function is only available when compiled with support for LoadLeveler and is
  487. * used for running on the SuperMUC
  488. *
  489. * @param cfg the configuration to use as a template while starting a controller
  490. * on any of the loaded hosts. Operation queue sizes specific to a host
  491. * are also read from this configuration handle
  492. * @param hosts set to the hosts found in the file; caller must free this if
  493. * number of hosts returned is greater than 0
  494. * @return number of hosts returned in 'hosts', 0 on error
  495. */
  496. unsigned int
  497. GNUNET_TESTBED_hosts_load_from_loadleveler (const struct
  498. GNUNET_CONFIGURATION_Handle *cfg,
  499. struct GNUNET_TESTBED_Host ***hosts)
  500. {
  501. #if !ENABLE_SUPERMUC
  502. LOG (GNUNET_ERROR_TYPE_ERROR,
  503. _("The function %s is only available when compiled with (--with-ll)\n"),
  504. __func__);
  505. GNUNET_assert (0);
  506. #else
  507. const char *hostfile;
  508. if (NULL == (hostfile = getenv ("MP_SAVEHOSTFILE")))
  509. {
  510. GNUNET_break (0);
  511. return 0;
  512. }
  513. return GNUNET_TESTBED_hosts_load_from_file (hostfile, cfg, hosts);
  514. #endif
  515. }
  516. /**
  517. * Destroy a host handle. Must only be called once everything
  518. * running on that host has been stopped.
  519. *
  520. * @param host handle to destroy
  521. */
  522. void
  523. GNUNET_TESTBED_host_destroy (struct GNUNET_TESTBED_Host *host)
  524. {
  525. struct RegisteredController *rc;
  526. uint32_t id;
  527. GNUNET_assert (host->id < host_list_size);
  528. GNUNET_assert (host_list[host->id] == host);
  529. host_list[host->id] = NULL;
  530. /* clear registered controllers list */
  531. for (rc = host->rc_head; NULL != rc; rc = host->rc_head)
  532. {
  533. GNUNET_CONTAINER_DLL_remove (host->rc_head, host->rc_tail, rc);
  534. GNUNET_free (rc);
  535. }
  536. GNUNET_free_non_null ((char *) host->username);
  537. GNUNET_free_non_null ((char *) host->hostname);
  538. GNUNET_TESTBED_operation_queue_destroy_
  539. (host->opq_parallel_overlay_connect_operations);
  540. GNUNET_CONFIGURATION_destroy (host->cfg);
  541. GNUNET_free (host);
  542. while (host_list_size >= HOST_LIST_GROW_STEP)
  543. {
  544. for (id = host_list_size - 1; id > host_list_size - HOST_LIST_GROW_STEP;
  545. id--)
  546. if (NULL != host_list[id])
  547. break;
  548. if (id != host_list_size - HOST_LIST_GROW_STEP)
  549. break;
  550. if (NULL != host_list[id])
  551. break;
  552. host_list_size -= HOST_LIST_GROW_STEP;
  553. }
  554. host_list =
  555. GNUNET_realloc (host_list,
  556. sizeof (struct GNUNET_TESTBED_Host *) * host_list_size);
  557. }
  558. /**
  559. * Marks a host as registered with a controller
  560. *
  561. * @param host the host to mark
  562. * @param controller the controller at which this host is registered
  563. */
  564. void
  565. GNUNET_TESTBED_mark_host_registered_at_ (struct GNUNET_TESTBED_Host *host,
  566. const struct GNUNET_TESTBED_Controller
  567. *const controller)
  568. {
  569. struct RegisteredController *rc;
  570. for (rc = host->rc_head; NULL != rc; rc = rc->next)
  571. {
  572. if (controller == rc->controller) /* already registered at controller */
  573. {
  574. GNUNET_break (0);
  575. return;
  576. }
  577. }
  578. rc = GNUNET_new (struct RegisteredController);
  579. rc->controller = controller;
  580. GNUNET_CONTAINER_DLL_insert_tail (host->rc_head, host->rc_tail, rc);
  581. }
  582. /**
  583. * Unmarks a host registered at a controller
  584. *
  585. * @param host the host to unmark
  586. * @param controller the controller at which this host has to be unmarked
  587. */
  588. void
  589. GNUNET_TESTBED_deregister_host_at_ (struct GNUNET_TESTBED_Host *host,
  590. const struct GNUNET_TESTBED_Controller
  591. *const controller)
  592. {
  593. struct RegisteredController *rc;
  594. for (rc = host->rc_head; NULL != rc; rc=rc->next)
  595. if (controller == rc->controller)
  596. break;
  597. if (NULL == rc)
  598. {
  599. GNUNET_break (0);
  600. return;
  601. }
  602. GNUNET_CONTAINER_DLL_remove (host->rc_head, host->rc_tail, rc);
  603. GNUNET_free (rc);
  604. }
  605. /**
  606. * Checks whether a host has been registered
  607. *
  608. * @param host the host to check
  609. * @param controller the controller at which host's registration is checked
  610. * @return GNUNET_YES if registered; GNUNET_NO if not
  611. */
  612. int
  613. GNUNET_TESTBED_is_host_registered_ (const struct GNUNET_TESTBED_Host *host,
  614. const struct GNUNET_TESTBED_Controller
  615. *const controller)
  616. {
  617. struct RegisteredController *rc;
  618. for (rc = host->rc_head; NULL != rc; rc = rc->next)
  619. {
  620. if (controller == rc->controller) /* already registered at controller */
  621. {
  622. return GNUNET_YES;
  623. }
  624. }
  625. return GNUNET_NO;
  626. }
  627. /**
  628. * Handle for controller process
  629. */
  630. struct GNUNET_TESTBED_ControllerProc
  631. {
  632. /**
  633. * The process handle
  634. */
  635. struct GNUNET_HELPER_Handle *helper;
  636. /**
  637. * The arguments used to start the helper
  638. */
  639. char **helper_argv;
  640. /**
  641. * The host where the helper is run
  642. */
  643. struct GNUNET_TESTBED_Host *host;
  644. /**
  645. * The controller error callback
  646. */
  647. GNUNET_TESTBED_ControllerStatusCallback cb;
  648. /**
  649. * The closure for the above callback
  650. */
  651. void *cls;
  652. /**
  653. * The send handle for the helper
  654. */
  655. struct GNUNET_HELPER_SendHandle *shandle;
  656. /**
  657. * The message corresponding to send handle
  658. */
  659. struct GNUNET_MessageHeader *msg;
  660. };
  661. /**
  662. * Function to copy NULL terminated list of arguments
  663. *
  664. * @param argv the NULL terminated list of arguments. Cannot be NULL.
  665. * @return the copied NULL terminated arguments
  666. */
  667. static char **
  668. copy_argv (const char *const *argv)
  669. {
  670. char **argv_dup;
  671. unsigned int argp;
  672. GNUNET_assert (NULL != argv);
  673. for (argp = 0; NULL != argv[argp]; argp++) ;
  674. argv_dup = GNUNET_malloc (sizeof (char *) * (argp + 1));
  675. for (argp = 0; NULL != argv[argp]; argp++)
  676. argv_dup[argp] = GNUNET_strdup (argv[argp]);
  677. return argv_dup;
  678. }
  679. /**
  680. * Function to join NULL terminated list of arguments
  681. *
  682. * @param argv1 the NULL terminated list of arguments. Cannot be NULL.
  683. * @param argv2 the NULL terminated list of arguments. Cannot be NULL.
  684. * @return the joined NULL terminated arguments
  685. */
  686. static char **
  687. join_argv (const char *const *argv1, const char *const *argv2)
  688. {
  689. char **argvj;
  690. char *argv;
  691. unsigned int carg;
  692. unsigned int cnt;
  693. carg = 0;
  694. argvj = NULL;
  695. for (cnt = 0; NULL != argv1[cnt]; cnt++)
  696. {
  697. argv = GNUNET_strdup (argv1[cnt]);
  698. GNUNET_array_append (argvj, carg, argv);
  699. }
  700. for (cnt = 0; NULL != argv2[cnt]; cnt++)
  701. {
  702. argv = GNUNET_strdup (argv2[cnt]);
  703. GNUNET_array_append (argvj, carg, argv);
  704. }
  705. GNUNET_array_append (argvj, carg, NULL);
  706. return argvj;
  707. }
  708. /**
  709. * Frees the given NULL terminated arguments
  710. *
  711. * @param argv the NULL terminated list of arguments
  712. */
  713. static void
  714. free_argv (char **argv)
  715. {
  716. unsigned int argp;
  717. for (argp = 0; NULL != argv[argp]; argp++)
  718. GNUNET_free (argv[argp]);
  719. GNUNET_free (argv);
  720. }
  721. /**
  722. * Generates arguments for opening a remote shell. Builds up the arguments
  723. * from the environment variable GNUNET_TESTBED_RSH_CMD. The variable
  724. * should not mention `-p' (port) option and destination address as these will
  725. * be set locally in the function from its parameteres. If the environmental
  726. * variable is not found then it defaults to `ssh -o BatchMode=yes -o
  727. * NoHostAuthenticationForLocalhost=yes -o StrictHostkeyChecking=no -o
  728. * PasswordAuthentication=noc'
  729. *
  730. * @param port the destination port number
  731. * @param hostname the hostname of the target host
  732. * @param username the username to use while connecting to target host
  733. * @return NULL terminated list of arguments
  734. */
  735. static char **
  736. gen_rsh_args (const char *port, const char *hostname, const char *username)
  737. {
  738. static const char *default_ssh_args[] = {
  739. "ssh",
  740. "-o",
  741. "BatchMode=yes",
  742. "-o",
  743. "NoHostAuthenticationForLocalhost=yes",
  744. "-o",
  745. "StrictHostKeyChecking=no",
  746. "-o",
  747. "PasswordAuthentication=no",
  748. "%h",
  749. NULL
  750. };
  751. char **ssh_args;
  752. char *ssh_cmd;
  753. char *ssh_cmd_cp;
  754. char *arg;
  755. const char *new_arg;
  756. unsigned int size;
  757. unsigned int cnt;
  758. ssh_args = NULL;
  759. if (NULL != (ssh_cmd = getenv ("GNUNET_TESTBED_RSH_CMD")))
  760. {
  761. ssh_cmd = GNUNET_strdup (ssh_cmd);
  762. ssh_cmd_cp = ssh_cmd;
  763. for (size = 0; NULL != (arg = strtok (ssh_cmd, " ")); ssh_cmd = NULL)
  764. GNUNET_array_append (ssh_args, size, GNUNET_strdup (arg));
  765. GNUNET_free (ssh_cmd_cp);
  766. }
  767. else
  768. {
  769. ssh_args = copy_argv (default_ssh_args);
  770. size = (sizeof (default_ssh_args)) / (sizeof (const char *));
  771. GNUNET_array_grow (ssh_args, size, size - 1);
  772. }
  773. for (cnt = 0; cnt < size; cnt++)
  774. {
  775. arg = ssh_args[cnt];
  776. if ('%' != arg[0])
  777. continue;
  778. switch (arg[1])
  779. {
  780. case 'p':
  781. new_arg = port;
  782. break;
  783. case 'u':
  784. new_arg = username;
  785. break;
  786. case 'h':
  787. new_arg = hostname;
  788. break;
  789. default:
  790. continue;
  791. }
  792. if (NULL == new_arg)
  793. continue;
  794. GNUNET_free (arg);
  795. ssh_args[cnt] = GNUNET_strdup (new_arg);
  796. }
  797. GNUNET_array_append (ssh_args, size, NULL);
  798. return ssh_args;
  799. }
  800. /**
  801. * Generates the arguments needed for executing the given binary in a remote
  802. * shell. Builds the arguments from the environmental variable
  803. * GNUNET_TETSBED_RSH_CMD_SUFFIX. If the environmental variable is not found,
  804. * only the given binary name will be present in the returned arguments
  805. *
  806. * @param append_args the arguments to append after generating the suffix
  807. * arguments. Can be NULL; if not must be NULL terminated 'char *' array
  808. * @return NULL-terminated args
  809. */
  810. static char **
  811. gen_rsh_suffix_args (const char * const *append_args)
  812. {
  813. char **rshell_args;
  814. char *rshell_cmd;
  815. char *rshell_cmd_cp;
  816. char *arg;
  817. unsigned int cnt;
  818. unsigned int append_cnt;
  819. rshell_args = NULL;
  820. cnt = 0;
  821. if (NULL != (rshell_cmd = getenv ("GNUNET_TESTBED_RSH_CMD_SUFFIX")))
  822. {
  823. rshell_cmd = GNUNET_strdup (rshell_cmd);
  824. rshell_cmd_cp = rshell_cmd;
  825. for (; NULL != (arg = strtok (rshell_cmd, " ")); rshell_cmd = NULL)
  826. GNUNET_array_append (rshell_args, cnt, GNUNET_strdup (arg));
  827. GNUNET_free (rshell_cmd_cp);
  828. }
  829. if (NULL != append_args)
  830. {
  831. for (append_cnt = 0; NULL != append_args[append_cnt]; append_cnt++)
  832. GNUNET_array_append (rshell_args, cnt, GNUNET_strdup (append_args[append_cnt]));
  833. }
  834. GNUNET_array_append (rshell_args, cnt, NULL);
  835. return rshell_args;
  836. }
  837. /**
  838. * Functions with this signature are called whenever a
  839. * complete message is received by the tokenizer.
  840. *
  841. * Do not call GNUNET_SERVER_mst_destroy in callback
  842. *
  843. * @param cls closure
  844. * @param client identification of the client
  845. * @param message the actual message
  846. *
  847. * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing
  848. */
  849. static int
  850. helper_mst (void *cls,
  851. const struct GNUNET_MessageHeader *message)
  852. {
  853. struct GNUNET_TESTBED_ControllerProc *cp = cls;
  854. const struct GNUNET_TESTBED_HelperReply *msg;
  855. const char *hostname;
  856. char *config;
  857. uLongf config_size;
  858. uLongf xconfig_size;
  859. msg = (const struct GNUNET_TESTBED_HelperReply *) message;
  860. GNUNET_assert (sizeof (struct GNUNET_TESTBED_HelperReply) <
  861. ntohs (msg->header.size));
  862. GNUNET_assert (GNUNET_MESSAGE_TYPE_TESTBED_HELPER_REPLY ==
  863. ntohs (msg->header.type));
  864. config_size = (uLongf) ntohs (msg->config_size);
  865. xconfig_size =
  866. (uLongf) (ntohs (msg->header.size) -
  867. sizeof (struct GNUNET_TESTBED_HelperReply));
  868. config = GNUNET_malloc (config_size);
  869. GNUNET_assert (Z_OK ==
  870. uncompress ((Bytef *) config, &config_size,
  871. (const Bytef *) &msg[1], xconfig_size));
  872. /* Replace the configuration template present in the host with the
  873. controller's running configuration */
  874. GNUNET_CONFIGURATION_destroy (cp->host->cfg);
  875. cp->host->cfg = GNUNET_CONFIGURATION_create ();
  876. GNUNET_assert (GNUNET_CONFIGURATION_deserialize
  877. (cp->host->cfg,
  878. config,
  879. config_size,
  880. NULL));
  881. GNUNET_free (config);
  882. if (NULL == (hostname = GNUNET_TESTBED_host_get_hostname (cp->host)))
  883. hostname = "localhost";
  884. /* Change the hostname so that we can connect to it */
  885. GNUNET_CONFIGURATION_set_value_string (cp->host->cfg, "testbed", "hostname",
  886. hostname);
  887. cp->host->locked = GNUNET_NO;
  888. cp->host->controller_started = GNUNET_YES;
  889. cp->cb (cp->cls, cp->host->cfg, GNUNET_OK);
  890. return GNUNET_OK;
  891. }
  892. /**
  893. * Continuation function from GNUNET_HELPER_send()
  894. *
  895. * @param cls closure
  896. * @param result GNUNET_OK on success,
  897. * GNUNET_NO if helper process died
  898. * GNUNET_SYSERR during GNUNET_HELPER_stop
  899. */
  900. static void
  901. clear_msg (void *cls, int result)
  902. {
  903. struct GNUNET_TESTBED_ControllerProc *cp = cls;
  904. GNUNET_assert (NULL != cp->shandle);
  905. cp->shandle = NULL;
  906. GNUNET_free (cp->msg);
  907. cp->msg = NULL;
  908. }
  909. /**
  910. * Callback that will be called when the helper process dies. This is not called
  911. * when the helper process is stoped using GNUNET_HELPER_stop()
  912. *
  913. * @param cls the closure from GNUNET_HELPER_start()
  914. */
  915. static void
  916. helper_exp_cb (void *cls)
  917. {
  918. struct GNUNET_TESTBED_ControllerProc *cp = cls;
  919. GNUNET_TESTBED_ControllerStatusCallback cb;
  920. void *cb_cls;
  921. cb = cp->cb;
  922. cb_cls = cp->cls;
  923. cp->helper = NULL;
  924. GNUNET_TESTBED_controller_stop (cp);
  925. if (NULL != cb)
  926. cb (cb_cls, NULL, GNUNET_SYSERR);
  927. }
  928. /**
  929. * Starts a controller process at the given host. The given host's configuration
  930. * is used as a Template configuration to use for the remote controller; the
  931. * remote controller will be started with a slightly modified configuration
  932. * (port numbers, unix domain sockets and service home values are changed as per
  933. * TESTING library on the remote host). The modified configuration replaces the
  934. * host's existing configuration before signalling success through the
  935. * GNUNET_TESTBED_ControllerStatusCallback()
  936. *
  937. * @param trusted_ip the ip address of the controller which will be set as TRUSTED
  938. * HOST(all connections form this ip are permitted by the testbed) when
  939. * starting testbed controller at host. This can either be a single ip
  940. * address or a network address in CIDR notation.
  941. * @param host the host where the controller has to be started. CANNOT be NULL.
  942. * @param cb function called when the controller is successfully started or
  943. * dies unexpectedly; GNUNET_TESTBED_controller_stop shouldn't be
  944. * called if cb is called with GNUNET_SYSERR as status. Will never be
  945. * called in the same task as 'GNUNET_TESTBED_controller_start'
  946. * (synchronous errors will be signalled by returning NULL). This
  947. * parameter cannot be NULL.
  948. * @param cls closure for above callbacks
  949. * @return the controller process handle, NULL on errors
  950. */
  951. struct GNUNET_TESTBED_ControllerProc *
  952. GNUNET_TESTBED_controller_start (const char *trusted_ip,
  953. struct GNUNET_TESTBED_Host *host,
  954. GNUNET_TESTBED_ControllerStatusCallback cb,
  955. void *cls)
  956. {
  957. struct GNUNET_TESTBED_ControllerProc *cp;
  958. struct GNUNET_TESTBED_HelperInit *msg;
  959. const struct GNUNET_CONFIGURATION_Handle *cfg;
  960. const char *hostname;
  961. static char *const binary_argv[] = {
  962. HELPER_TESTBED_BINARY, NULL
  963. };
  964. GNUNET_assert (NULL != host);
  965. GNUNET_assert (NULL != (cfg = GNUNET_TESTBED_host_get_cfg_ (host)));
  966. hostname = NULL;
  967. API_VIOLATION (GNUNET_NO == host->locked,
  968. "Host is already locked by a previous call to GNUNET_TESTBED_controller_start()");
  969. host->locked = GNUNET_YES;
  970. API_VIOLATION (GNUNET_NO == host->controller_started,
  971. "Attempting to start a controller on a host which is already started a controller");
  972. cp = GNUNET_new (struct GNUNET_TESTBED_ControllerProc);
  973. if (0 == GNUNET_TESTBED_host_get_id_ (host))
  974. {
  975. cp->helper =
  976. GNUNET_HELPER_start (GNUNET_YES, HELPER_TESTBED_BINARY, binary_argv,
  977. &helper_mst, &helper_exp_cb, cp);
  978. }
  979. else
  980. {
  981. char *helper_binary_path_args[2];
  982. char **rsh_args;
  983. char **rsh_suffix_args;
  984. const char *username;
  985. char *port;
  986. char *argstr;
  987. char *aux;
  988. unsigned int cnt;
  989. username = host->username;
  990. hostname = host->hostname;
  991. GNUNET_asprintf (&port, "%u", host->port);
  992. LOG_DEBUG ("Starting remote connection to destination %s\n", hostname);
  993. if (GNUNET_OK !=
  994. GNUNET_CONFIGURATION_get_value_filename (cfg, "testbed",
  995. "HELPER_BINARY_PATH",
  996. &helper_binary_path_args[0]))
  997. helper_binary_path_args[0] =
  998. GNUNET_OS_get_libexec_binary_path (HELPER_TESTBED_BINARY);
  999. helper_binary_path_args[1] = NULL;
  1000. rsh_args = gen_rsh_args (port, hostname, username);
  1001. rsh_suffix_args = gen_rsh_suffix_args ((const char **) helper_binary_path_args);
  1002. cp->helper_argv =
  1003. join_argv ((const char **) rsh_args, (const char **) rsh_suffix_args);
  1004. free_argv (rsh_args);
  1005. free_argv (rsh_suffix_args);
  1006. GNUNET_free (port);
  1007. argstr = GNUNET_strdup ("");
  1008. for (cnt = 0; NULL != cp->helper_argv[cnt]; cnt++)
  1009. {
  1010. aux = argstr;
  1011. GNUNET_assert (0 < GNUNET_asprintf (&argstr, "%s %s", aux, cp->helper_argv[cnt]));
  1012. GNUNET_free (aux);
  1013. }
  1014. LOG_DEBUG ("Helper cmd str: %s\n", argstr);
  1015. GNUNET_free (argstr);
  1016. cp->helper =
  1017. GNUNET_HELPER_start (GNUNET_NO, cp->helper_argv[0], cp->helper_argv, &helper_mst,
  1018. &helper_exp_cb, cp);
  1019. GNUNET_free (helper_binary_path_args[0]);
  1020. }
  1021. if (NULL == cp->helper)
  1022. {
  1023. if (NULL != cp->helper_argv)
  1024. free_argv (cp->helper_argv);
  1025. GNUNET_free (cp);
  1026. return NULL;
  1027. }
  1028. cp->host = host;
  1029. cp->cb = cb;
  1030. cp->cls = cls;
  1031. msg = GNUNET_TESTBED_create_helper_init_msg_ (trusted_ip, hostname, cfg);
  1032. cp->msg = &msg->header;
  1033. cp->shandle =
  1034. GNUNET_HELPER_send (cp->helper, &msg->header, GNUNET_NO, &clear_msg, cp);
  1035. if (NULL == cp->shandle)
  1036. {
  1037. GNUNET_free (msg);
  1038. GNUNET_TESTBED_controller_stop (cp);
  1039. return NULL;
  1040. }
  1041. return cp;
  1042. }
  1043. /**
  1044. * Sends termination signal to the controller's helper process
  1045. *
  1046. * @param cproc the handle to the controller's helper process
  1047. */
  1048. void
  1049. GNUNET_TESTBED_controller_kill_ (struct GNUNET_TESTBED_ControllerProc *cproc)
  1050. {
  1051. if (NULL != cproc->shandle)
  1052. GNUNET_HELPER_send_cancel (cproc->shandle);
  1053. if (NULL != cproc->helper)
  1054. GNUNET_HELPER_kill (cproc->helper, GNUNET_YES);
  1055. }
  1056. /**
  1057. * Cleans-up the controller's helper process handle
  1058. *
  1059. * @param cproc the handle to the controller's helper process
  1060. */
  1061. void
  1062. GNUNET_TESTBED_controller_destroy_ (struct GNUNET_TESTBED_ControllerProc *cproc)
  1063. {
  1064. if (NULL != cproc->helper)
  1065. {
  1066. GNUNET_break (GNUNET_OK == GNUNET_HELPER_wait (cproc->helper));
  1067. GNUNET_HELPER_destroy (cproc->helper);
  1068. }
  1069. if (NULL != cproc->helper_argv)
  1070. free_argv (cproc->helper_argv);
  1071. cproc->host->controller_started = GNUNET_NO;
  1072. cproc->host->locked = GNUNET_NO;
  1073. GNUNET_free_non_null (cproc->msg);
  1074. GNUNET_free (cproc);
  1075. }
  1076. /**
  1077. * Stop the controller process (also will terminate all peers and controllers
  1078. * dependent on this controller). This function blocks until the testbed has
  1079. * been fully terminated (!). The controller status cb from
  1080. * GNUNET_TESTBED_controller_start() will not be called.
  1081. *
  1082. * @param cproc the controller process handle
  1083. */
  1084. void
  1085. GNUNET_TESTBED_controller_stop (struct GNUNET_TESTBED_ControllerProc *cproc)
  1086. {
  1087. GNUNET_TESTBED_controller_kill_ (cproc);
  1088. GNUNET_TESTBED_controller_destroy_ (cproc);
  1089. }
  1090. /**
  1091. * The handle for whether a host is habitable or not
  1092. */
  1093. struct GNUNET_TESTBED_HostHabitableCheckHandle
  1094. {
  1095. /**
  1096. * The host to check
  1097. */
  1098. const struct GNUNET_TESTBED_Host *host;
  1099. /**
  1100. * The callback to call once we have the status
  1101. */
  1102. GNUNET_TESTBED_HostHabitableCallback cb;
  1103. /**
  1104. * The callback closure
  1105. */
  1106. void *cb_cls;
  1107. /**
  1108. * The process handle for the SSH process
  1109. */
  1110. struct GNUNET_OS_Process *auxp;
  1111. /**
  1112. * The arguments used to start the helper
  1113. */
  1114. char **helper_argv;
  1115. /**
  1116. * Task id for the habitability check task
  1117. */
  1118. struct GNUNET_SCHEDULER_Task * habitability_check_task;
  1119. /**
  1120. * How long we wait before checking the process status. Should grow
  1121. * exponentially
  1122. */
  1123. struct GNUNET_TIME_Relative wait_time;
  1124. };
  1125. /**
  1126. * Task for checking whether a host is habitable or not
  1127. *
  1128. * @param cls GNUNET_TESTBED_HostHabitableCheckHandle
  1129. */
  1130. static void
  1131. habitability_check (void *cls)
  1132. {
  1133. struct GNUNET_TESTBED_HostHabitableCheckHandle *h = cls;
  1134. void *cb_cls;
  1135. GNUNET_TESTBED_HostHabitableCallback cb;
  1136. const struct GNUNET_TESTBED_Host *host;
  1137. unsigned long code;
  1138. enum GNUNET_OS_ProcessStatusType type;
  1139. int ret;
  1140. h->habitability_check_task = NULL;
  1141. ret = GNUNET_OS_process_status (h->auxp, &type, &code);
  1142. if (GNUNET_SYSERR == ret)
  1143. {
  1144. GNUNET_break (0);
  1145. ret = GNUNET_NO;
  1146. goto call_cb;
  1147. }
  1148. if (GNUNET_NO == ret)
  1149. {
  1150. h->wait_time = GNUNET_TIME_STD_BACKOFF (h->wait_time);
  1151. h->habitability_check_task =
  1152. GNUNET_SCHEDULER_add_delayed (h->wait_time, &habitability_check, h);
  1153. return;
  1154. }
  1155. GNUNET_OS_process_destroy (h->auxp);
  1156. h->auxp = NULL;
  1157. ret = (0 != code) ? GNUNET_NO : GNUNET_YES;
  1158. call_cb:
  1159. if (NULL != h->auxp)
  1160. GNUNET_OS_process_destroy (h->auxp);
  1161. cb = h->cb;
  1162. cb_cls = h->cb_cls;
  1163. host = h->host;
  1164. free_argv (h->helper_argv);
  1165. GNUNET_free (h);
  1166. if (NULL != cb)
  1167. cb (cb_cls, host, ret);
  1168. }
  1169. /**
  1170. * Checks whether a host can be used to start testbed service
  1171. *
  1172. * @param host the host to check
  1173. * @param config the configuration handle to lookup the path of the testbed
  1174. * helper
  1175. * @param cb the callback to call to inform about habitability of the given host
  1176. * @param cb_cls the closure for the callback
  1177. * @return NULL upon any error or a handle which can be passed to
  1178. * GNUNET_TESTBED_is_host_habitable_cancel()
  1179. */
  1180. struct GNUNET_TESTBED_HostHabitableCheckHandle *
  1181. GNUNET_TESTBED_is_host_habitable (const struct GNUNET_TESTBED_Host *host,
  1182. const struct GNUNET_CONFIGURATION_Handle
  1183. *config,
  1184. GNUNET_TESTBED_HostHabitableCallback cb,
  1185. void *cb_cls)
  1186. {
  1187. struct GNUNET_TESTBED_HostHabitableCheckHandle *h;
  1188. char **rsh_args;
  1189. char **rsh_suffix_args;
  1190. char *stat_args[3];
  1191. const char *hostname;
  1192. char *port;
  1193. h = GNUNET_new (struct GNUNET_TESTBED_HostHabitableCheckHandle);
  1194. h->cb = cb;
  1195. h->cb_cls = cb_cls;
  1196. h->host = host;
  1197. hostname = (NULL == host->hostname) ? "127.0.0.1" : host->hostname;
  1198. if (GNUNET_OK !=
  1199. GNUNET_CONFIGURATION_get_value_filename (config, "testbed",
  1200. "HELPER_BINARY_PATH",
  1201. &stat_args[1]))
  1202. stat_args[1] =
  1203. GNUNET_OS_get_libexec_binary_path (HELPER_TESTBED_BINARY);
  1204. GNUNET_asprintf (&port, "%u", host->port);
  1205. rsh_args = gen_rsh_args (port, hostname, host->username);
  1206. GNUNET_free (port);
  1207. port = NULL;
  1208. stat_args[0] = "stat";
  1209. stat_args[2] = NULL;
  1210. rsh_suffix_args = gen_rsh_suffix_args ((const char **) stat_args);
  1211. GNUNET_free (stat_args[1]);
  1212. h->helper_argv = join_argv ((const char **) rsh_args,
  1213. (const char **) rsh_suffix_args);
  1214. free_argv (rsh_suffix_args);
  1215. free_argv (rsh_args);
  1216. h->auxp =
  1217. GNUNET_OS_start_process_vap (GNUNET_NO, GNUNET_OS_INHERIT_STD_ERR, NULL,
  1218. NULL, NULL, h->helper_argv[0], h->helper_argv);
  1219. if (NULL == h->auxp)
  1220. {
  1221. GNUNET_break (0); /* Cannot exec SSH? */
  1222. GNUNET_free (h);
  1223. return NULL;
  1224. }
  1225. h->wait_time = GNUNET_TIME_STD_BACKOFF (h->wait_time);
  1226. h->habitability_check_task =
  1227. GNUNET_SCHEDULER_add_delayed (h->wait_time, &habitability_check, h);
  1228. return h;
  1229. }
  1230. /**
  1231. * Function to cancel a request started using GNUNET_TESTBED_is_host_habitable()
  1232. *
  1233. * @param handle the habitability check handle
  1234. */
  1235. void
  1236. GNUNET_TESTBED_is_host_habitable_cancel (struct
  1237. GNUNET_TESTBED_HostHabitableCheckHandle
  1238. *handle)
  1239. {
  1240. GNUNET_SCHEDULER_cancel (handle->habitability_check_task);
  1241. (void) GNUNET_OS_process_kill (handle->auxp, GNUNET_TERM_SIG);
  1242. (void) GNUNET_OS_process_wait (handle->auxp);
  1243. GNUNET_OS_process_destroy (handle->auxp);
  1244. free_argv (handle->helper_argv);
  1245. GNUNET_free (handle);
  1246. }
  1247. /**
  1248. * Register a host with the controller
  1249. *
  1250. * @param controller the controller handle
  1251. * @param host the host to register
  1252. * @param cc the completion callback to call to inform the status of
  1253. * registration. After calling this callback the registration handle
  1254. * will be invalid. Cannot be NULL.
  1255. * @param cc_cls the closure for the cc
  1256. * @return handle to the host registration which can be used to cancel the
  1257. * registration
  1258. */
  1259. struct GNUNET_TESTBED_HostRegistrationHandle *
  1260. GNUNET_TESTBED_register_host (struct GNUNET_TESTBED_Controller *controller,
  1261. struct GNUNET_TESTBED_Host *host,
  1262. GNUNET_TESTBED_HostRegistrationCompletion cc,
  1263. void *cc_cls)
  1264. {
  1265. struct GNUNET_TESTBED_HostRegistrationHandle *rh;
  1266. struct GNUNET_TESTBED_AddHostMessage *msg;
  1267. const char *username;
  1268. const char *hostname;
  1269. char *config;
  1270. char *cconfig;
  1271. void *ptr;
  1272. size_t cc_size;
  1273. size_t config_size;
  1274. uint16_t msg_size;
  1275. uint16_t username_length;
  1276. uint16_t hostname_length;
  1277. if (NULL != controller->rh)
  1278. return NULL;
  1279. hostname = GNUNET_TESTBED_host_get_hostname (host);
  1280. if (GNUNET_YES == GNUNET_TESTBED_is_host_registered_ (host, controller))
  1281. {
  1282. LOG (GNUNET_ERROR_TYPE_WARNING, "Host hostname: %s already registered\n",
  1283. (NULL == hostname) ? "localhost" : hostname);
  1284. return NULL;
  1285. }
  1286. rh = GNUNET_new (struct GNUNET_TESTBED_HostRegistrationHandle);
  1287. rh->host = host;
  1288. rh->c = controller;
  1289. GNUNET_assert (NULL != cc);
  1290. rh->cc = cc;
  1291. rh->cc_cls = cc_cls;
  1292. controller->rh = rh;
  1293. username = GNUNET_TESTBED_host_get_username_ (host);
  1294. username_length = 0;
  1295. if (NULL != username)
  1296. username_length = strlen (username);
  1297. GNUNET_assert (NULL != hostname); /* Hostname must be present */
  1298. hostname_length = strlen (hostname);
  1299. GNUNET_assert (NULL != host->cfg);
  1300. config = GNUNET_CONFIGURATION_serialize (host->cfg, &config_size);
  1301. cc_size = GNUNET_TESTBED_compress_config_ (config, config_size, &cconfig);
  1302. GNUNET_free (config);
  1303. msg_size = (sizeof (struct GNUNET_TESTBED_AddHostMessage));
  1304. msg_size += username_length;
  1305. msg_size += hostname_length;
  1306. msg_size += cc_size;
  1307. msg = GNUNET_malloc (msg_size);
  1308. msg->header.size = htons (msg_size);
  1309. msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST);
  1310. msg->host_id = htonl (GNUNET_TESTBED_host_get_id_ (host));
  1311. msg->ssh_port = htons (GNUNET_TESTBED_host_get_ssh_port_ (host));
  1312. ptr = &msg[1];
  1313. if (NULL != username)
  1314. {
  1315. msg->username_length = htons (username_length);
  1316. GNUNET_memcpy (ptr, username, username_length);
  1317. ptr += username_length;
  1318. }
  1319. msg->hostname_length = htons (hostname_length);
  1320. GNUNET_memcpy (ptr, hostname, hostname_length);
  1321. ptr += hostname_length;
  1322. msg->config_size = htons (config_size);
  1323. GNUNET_memcpy (ptr, cconfig, cc_size);
  1324. ptr += cc_size;
  1325. GNUNET_assert ((ptr - (void *) msg) == msg_size);
  1326. GNUNET_free (cconfig);
  1327. GNUNET_TESTBED_queue_message_ (controller,
  1328. (struct GNUNET_MessageHeader *) msg);
  1329. return rh;
  1330. }
  1331. /**
  1332. * Cancel the pending registration. Note that if the registration message is
  1333. * already sent to the service the cancellation has only the effect that the
  1334. * registration completion callback for the registration is never called.
  1335. *
  1336. * @param handle the registration handle to cancel
  1337. */
  1338. void
  1339. GNUNET_TESTBED_cancel_registration (struct GNUNET_TESTBED_HostRegistrationHandle
  1340. *handle)
  1341. {
  1342. if (handle != handle->c->rh)
  1343. {
  1344. GNUNET_break (0);
  1345. return;
  1346. }
  1347. handle->c->rh = NULL;
  1348. GNUNET_free (handle);
  1349. }
  1350. /**
  1351. * Queues the given operation in the queue for parallel overlay connects of the
  1352. * given host
  1353. *
  1354. * @param h the host handle
  1355. * @param op the operation to queue in the given host's parally overlay connect
  1356. * queue
  1357. */
  1358. void
  1359. GNUNET_TESTBED_host_queue_oc_ (struct GNUNET_TESTBED_Host *h,
  1360. struct GNUNET_TESTBED_Operation *op)
  1361. {
  1362. GNUNET_TESTBED_operation_queue_insert_
  1363. (h->opq_parallel_overlay_connect_operations, op);
  1364. }
  1365. /**
  1366. * Resolves the hostname of the host to an ip address
  1367. *
  1368. * @param host the host whose hostname is to be resolved
  1369. */
  1370. void
  1371. GNUNET_TESTBED_host_resolve_ (struct GNUNET_TESTBED_Host *host)
  1372. {
  1373. char *hostname;
  1374. hostname = (char *) host->hostname;
  1375. host->hostname = simple_resolve (hostname);
  1376. if (NULL == host->hostname)
  1377. {
  1378. GNUNET_break (0);
  1379. host->hostname = hostname;
  1380. return;
  1381. }
  1382. GNUNET_free (hostname);
  1383. host->hostname = GNUNET_strdup (host->hostname);
  1384. }
  1385. /* end of testbed_api_hosts.c */