testbed_api_hosts.c 45 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541
  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. GNUNET_assert(0 != GNUNET_strlcpy (username,
  405. buf + pmatch[2].rm_so,
  406. size + 1));
  407. }
  408. if (-1 != pmatch[5].rm_so)
  409. {
  410. (void) SSCANF (buf + pmatch[5].rm_so, "%5hd", &port);
  411. }
  412. size = pmatch[3].rm_eo - pmatch[3].rm_so;
  413. hostname = GNUNET_malloc (size + 1);
  414. GNUNET_assert(0 != GNUNET_strlcpy (hostname,
  415. buf + pmatch[3].rm_so,
  416. size + 1));
  417. LOG (GNUNET_ERROR_TYPE_DEBUG,
  418. "Successfully read host %s, port %d and user %s from file\n",
  419. (NULL == hostname) ? "NULL" : hostname,
  420. port,
  421. (NULL == username) ? "NULL" : username);
  422. /* We store hosts in a static list; hence we only require the starting
  423. * host pointer in that list to access the newly created list of hosts */
  424. if (NULL == starting_host)
  425. starting_host = GNUNET_TESTBED_host_create (hostname, username, cfg,
  426. port);
  427. else
  428. (void) GNUNET_TESTBED_host_create (hostname, username, cfg, port);
  429. count++;
  430. GNUNET_free_non_null (username);
  431. GNUNET_free (hostname);
  432. buf = &data[offset + 1];
  433. }
  434. else if ((data[offset] == '\n') || (data[offset] == '\0'))
  435. buf = &data[offset + 1];
  436. }
  437. regfree (&rex);
  438. GNUNET_free (data);
  439. if (NULL == starting_host)
  440. return 0;
  441. *hosts = GNUNET_malloc (sizeof (struct GNUNET_TESTBED_Host *) * count);
  442. GNUNET_memcpy (*hosts,
  443. &host_list[GNUNET_TESTBED_host_get_id_ (starting_host)],
  444. sizeof (struct GNUNET_TESTBED_Host *) * count);
  445. return count;
  446. }
  447. /**
  448. * Resolves a hostname using getaddrinfo
  449. *
  450. * @param host the hostname
  451. * @return the string representing the IPv4 address of the given host; NULL upon error
  452. */
  453. const char *
  454. simple_resolve (const char *host)
  455. {
  456. struct addrinfo *res;
  457. const struct sockaddr_in *in_addr;
  458. char *hostip;
  459. struct addrinfo hint;
  460. unsigned int rc;
  461. hint.ai_family = AF_INET; /* IPv4 */
  462. hint.ai_socktype = 0;
  463. hint.ai_protocol = 0;
  464. hint.ai_addrlen = 0;
  465. hint.ai_addr = NULL;
  466. hint.ai_canonname = NULL;
  467. hint.ai_next = NULL;
  468. hint.ai_flags = AI_NUMERICSERV;
  469. res = NULL;
  470. LOG_DEBUG ("Resolving [%s]\n", host);
  471. if (0 != (rc = getaddrinfo (host, "22", &hint, &res)))
  472. {
  473. LOG_GAI (GNUNET_ERROR_TYPE_ERROR, "getaddrinfo", rc);
  474. return NULL;
  475. }
  476. GNUNET_assert (NULL != res);
  477. GNUNET_assert (NULL != res->ai_addr);
  478. GNUNET_assert (sizeof (struct sockaddr_in) == res->ai_addrlen);
  479. in_addr = (const struct sockaddr_in *) res->ai_addr;
  480. hostip = inet_ntoa (in_addr->sin_addr);
  481. GNUNET_assert (NULL != hostip);
  482. freeaddrinfo (res);
  483. LOG_DEBUG ("Resolved [%s] to [%s]\n", host, hostip);
  484. return hostip;
  485. }
  486. /**
  487. * Loads the set of host allocated by the LoadLeveler Job Scheduler. This
  488. * function is only available when compiled with support for LoadLeveler and is
  489. * used for running on the SuperMUC
  490. *
  491. * @param cfg the configuration to use as a template while starting a controller
  492. * on any of the loaded hosts. Operation queue sizes specific to a host
  493. * are also read from this configuration handle
  494. * @param hosts set to the hosts found in the file; caller must free this if
  495. * number of hosts returned is greater than 0
  496. * @return number of hosts returned in 'hosts', 0 on error
  497. */
  498. unsigned int
  499. GNUNET_TESTBED_hosts_load_from_loadleveler (const struct
  500. GNUNET_CONFIGURATION_Handle *cfg,
  501. struct GNUNET_TESTBED_Host ***hosts)
  502. {
  503. #if !ENABLE_SUPERMUC
  504. LOG (GNUNET_ERROR_TYPE_ERROR,
  505. _("The function %s is only available when compiled with (--with-ll)\n"),
  506. __func__);
  507. GNUNET_assert (0);
  508. #else
  509. const char *hostfile;
  510. if (NULL == (hostfile = getenv ("MP_SAVEHOSTFILE")))
  511. {
  512. GNUNET_break (0);
  513. return 0;
  514. }
  515. return GNUNET_TESTBED_hosts_load_from_file (hostfile, cfg, hosts);
  516. #endif
  517. }
  518. /**
  519. * Destroy a host handle. Must only be called once everything
  520. * running on that host has been stopped.
  521. *
  522. * @param host handle to destroy
  523. */
  524. void
  525. GNUNET_TESTBED_host_destroy (struct GNUNET_TESTBED_Host *host)
  526. {
  527. struct RegisteredController *rc;
  528. uint32_t id;
  529. GNUNET_assert (host->id < host_list_size);
  530. GNUNET_assert (host_list[host->id] == host);
  531. host_list[host->id] = NULL;
  532. /* clear registered controllers list */
  533. for (rc = host->rc_head; NULL != rc; rc = host->rc_head)
  534. {
  535. GNUNET_CONTAINER_DLL_remove (host->rc_head, host->rc_tail, rc);
  536. GNUNET_free (rc);
  537. }
  538. GNUNET_free_non_null ((char *) host->username);
  539. GNUNET_free_non_null ((char *) host->hostname);
  540. GNUNET_TESTBED_operation_queue_destroy_
  541. (host->opq_parallel_overlay_connect_operations);
  542. GNUNET_CONFIGURATION_destroy (host->cfg);
  543. GNUNET_free (host);
  544. while (host_list_size >= HOST_LIST_GROW_STEP)
  545. {
  546. for (id = host_list_size - 1; id > host_list_size - HOST_LIST_GROW_STEP;
  547. id--)
  548. if (NULL != host_list[id])
  549. break;
  550. if (id != host_list_size - HOST_LIST_GROW_STEP)
  551. break;
  552. if (NULL != host_list[id])
  553. break;
  554. host_list_size -= HOST_LIST_GROW_STEP;
  555. }
  556. host_list =
  557. GNUNET_realloc (host_list,
  558. sizeof (struct GNUNET_TESTBED_Host *) * host_list_size);
  559. }
  560. /**
  561. * Marks a host as registered with a controller
  562. *
  563. * @param host the host to mark
  564. * @param controller the controller at which this host is registered
  565. */
  566. void
  567. GNUNET_TESTBED_mark_host_registered_at_ (struct GNUNET_TESTBED_Host *host,
  568. const struct GNUNET_TESTBED_Controller
  569. *const controller)
  570. {
  571. struct RegisteredController *rc;
  572. for (rc = host->rc_head; NULL != rc; rc = rc->next)
  573. {
  574. if (controller == rc->controller) /* already registered at controller */
  575. {
  576. GNUNET_break (0);
  577. return;
  578. }
  579. }
  580. rc = GNUNET_new (struct RegisteredController);
  581. rc->controller = controller;
  582. GNUNET_CONTAINER_DLL_insert_tail (host->rc_head, host->rc_tail, rc);
  583. }
  584. /**
  585. * Unmarks a host registered at a controller
  586. *
  587. * @param host the host to unmark
  588. * @param controller the controller at which this host has to be unmarked
  589. */
  590. void
  591. GNUNET_TESTBED_deregister_host_at_ (struct GNUNET_TESTBED_Host *host,
  592. const struct GNUNET_TESTBED_Controller
  593. *const controller)
  594. {
  595. struct RegisteredController *rc;
  596. for (rc = host->rc_head; NULL != rc; rc=rc->next)
  597. if (controller == rc->controller)
  598. break;
  599. if (NULL == rc)
  600. {
  601. GNUNET_break (0);
  602. return;
  603. }
  604. GNUNET_CONTAINER_DLL_remove (host->rc_head, host->rc_tail, rc);
  605. GNUNET_free (rc);
  606. }
  607. /**
  608. * Checks whether a host has been registered
  609. *
  610. * @param host the host to check
  611. * @param controller the controller at which host's registration is checked
  612. * @return GNUNET_YES if registered; GNUNET_NO if not
  613. */
  614. int
  615. GNUNET_TESTBED_is_host_registered_ (const struct GNUNET_TESTBED_Host *host,
  616. const struct GNUNET_TESTBED_Controller
  617. *const controller)
  618. {
  619. struct RegisteredController *rc;
  620. for (rc = host->rc_head; NULL != rc; rc = rc->next)
  621. {
  622. if (controller == rc->controller) /* already registered at controller */
  623. {
  624. return GNUNET_YES;
  625. }
  626. }
  627. return GNUNET_NO;
  628. }
  629. /**
  630. * Handle for controller process
  631. */
  632. struct GNUNET_TESTBED_ControllerProc
  633. {
  634. /**
  635. * The process handle
  636. */
  637. struct GNUNET_HELPER_Handle *helper;
  638. /**
  639. * The arguments used to start the helper
  640. */
  641. char **helper_argv;
  642. /**
  643. * The host where the helper is run
  644. */
  645. struct GNUNET_TESTBED_Host *host;
  646. /**
  647. * The controller error callback
  648. */
  649. GNUNET_TESTBED_ControllerStatusCallback cb;
  650. /**
  651. * The closure for the above callback
  652. */
  653. void *cls;
  654. /**
  655. * The send handle for the helper
  656. */
  657. struct GNUNET_HELPER_SendHandle *shandle;
  658. /**
  659. * The message corresponding to send handle
  660. */
  661. struct GNUNET_MessageHeader *msg;
  662. };
  663. /**
  664. * Function to copy NULL terminated list of arguments
  665. *
  666. * @param argv the NULL terminated list of arguments. Cannot be NULL.
  667. * @return the copied NULL terminated arguments
  668. */
  669. static char **
  670. copy_argv (const char *const *argv)
  671. {
  672. char **argv_dup;
  673. unsigned int argp;
  674. GNUNET_assert (NULL != argv);
  675. for (argp = 0; NULL != argv[argp]; argp++) ;
  676. argv_dup = GNUNET_malloc (sizeof (char *) * (argp + 1));
  677. for (argp = 0; NULL != argv[argp]; argp++)
  678. argv_dup[argp] = GNUNET_strdup (argv[argp]);
  679. return argv_dup;
  680. }
  681. /**
  682. * Function to join NULL terminated list of arguments
  683. *
  684. * @param argv1 the NULL terminated list of arguments. Cannot be NULL.
  685. * @param argv2 the NULL terminated list of arguments. Cannot be NULL.
  686. * @return the joined NULL terminated arguments
  687. */
  688. static char **
  689. join_argv (const char *const *argv1, const char *const *argv2)
  690. {
  691. char **argvj;
  692. char *argv;
  693. unsigned int carg;
  694. unsigned int cnt;
  695. carg = 0;
  696. argvj = NULL;
  697. for (cnt = 0; NULL != argv1[cnt]; cnt++)
  698. {
  699. argv = GNUNET_strdup (argv1[cnt]);
  700. GNUNET_array_append (argvj, carg, argv);
  701. }
  702. for (cnt = 0; NULL != argv2[cnt]; cnt++)
  703. {
  704. argv = GNUNET_strdup (argv2[cnt]);
  705. GNUNET_array_append (argvj, carg, argv);
  706. }
  707. GNUNET_array_append (argvj, carg, NULL);
  708. return argvj;
  709. }
  710. /**
  711. * Frees the given NULL terminated arguments
  712. *
  713. * @param argv the NULL terminated list of arguments
  714. */
  715. static void
  716. free_argv (char **argv)
  717. {
  718. unsigned int argp;
  719. for (argp = 0; NULL != argv[argp]; argp++)
  720. GNUNET_free (argv[argp]);
  721. GNUNET_free (argv);
  722. }
  723. /**
  724. * Generates arguments for opening a remote shell. Builds up the arguments
  725. * from the environment variable GNUNET_TESTBED_RSH_CMD. The variable
  726. * should not mention `-p' (port) option and destination address as these will
  727. * be set locally in the function from its parameteres. If the environmental
  728. * variable is not found then it defaults to `ssh -o BatchMode=yes -o
  729. * NoHostAuthenticationForLocalhost=yes -o StrictHostkeyChecking=no -o
  730. * PasswordAuthentication=noc'
  731. *
  732. * @param port the destination port number
  733. * @param hostname the hostname of the target host
  734. * @param username the username to use while connecting to target host
  735. * @return NULL terminated list of arguments
  736. */
  737. static char **
  738. gen_rsh_args (const char *port, const char *hostname, const char *username)
  739. {
  740. static const char *default_ssh_args[] = {
  741. "ssh",
  742. "-o",
  743. "BatchMode=yes",
  744. "-o",
  745. "NoHostAuthenticationForLocalhost=yes",
  746. "-o",
  747. "StrictHostKeyChecking=no",
  748. "-o",
  749. "PasswordAuthentication=no",
  750. "%h",
  751. NULL
  752. };
  753. char **ssh_args;
  754. char *ssh_cmd;
  755. char *ssh_cmd_cp;
  756. char *arg;
  757. const char *new_arg;
  758. unsigned int size;
  759. unsigned int cnt;
  760. ssh_args = NULL;
  761. if (NULL != (ssh_cmd = getenv ("GNUNET_TESTBED_RSH_CMD")))
  762. {
  763. ssh_cmd = GNUNET_strdup (ssh_cmd);
  764. ssh_cmd_cp = ssh_cmd;
  765. for (size = 0; NULL != (arg = strtok (ssh_cmd, " ")); ssh_cmd = NULL)
  766. GNUNET_array_append (ssh_args, size, GNUNET_strdup (arg));
  767. GNUNET_free (ssh_cmd_cp);
  768. }
  769. else
  770. {
  771. ssh_args = copy_argv (default_ssh_args);
  772. size = (sizeof (default_ssh_args)) / (sizeof (const char *));
  773. GNUNET_array_grow (ssh_args, size, size - 1);
  774. }
  775. for (cnt = 0; cnt < size; cnt++)
  776. {
  777. arg = ssh_args[cnt];
  778. if ('%' != arg[0])
  779. continue;
  780. switch (arg[1])
  781. {
  782. case 'p':
  783. new_arg = port;
  784. break;
  785. case 'u':
  786. new_arg = username;
  787. break;
  788. case 'h':
  789. new_arg = hostname;
  790. break;
  791. default:
  792. continue;
  793. }
  794. if (NULL == new_arg)
  795. continue;
  796. GNUNET_free (arg);
  797. ssh_args[cnt] = GNUNET_strdup (new_arg);
  798. }
  799. GNUNET_array_append (ssh_args, size, NULL);
  800. return ssh_args;
  801. }
  802. /**
  803. * Generates the arguments needed for executing the given binary in a remote
  804. * shell. Builds the arguments from the environmental variable
  805. * GNUNET_TETSBED_RSH_CMD_SUFFIX. If the environmental variable is not found,
  806. * only the given binary name will be present in the returned arguments
  807. *
  808. * @param append_args the arguments to append after generating the suffix
  809. * arguments. Can be NULL; if not must be NULL terminated 'char *' array
  810. * @return NULL-terminated args
  811. */
  812. static char **
  813. gen_rsh_suffix_args (const char * const *append_args)
  814. {
  815. char **rshell_args;
  816. char *rshell_cmd;
  817. char *rshell_cmd_cp;
  818. char *arg;
  819. unsigned int cnt;
  820. unsigned int append_cnt;
  821. rshell_args = NULL;
  822. cnt = 0;
  823. if (NULL != (rshell_cmd = getenv ("GNUNET_TESTBED_RSH_CMD_SUFFIX")))
  824. {
  825. rshell_cmd = GNUNET_strdup (rshell_cmd);
  826. rshell_cmd_cp = rshell_cmd;
  827. for (; NULL != (arg = strtok (rshell_cmd, " ")); rshell_cmd = NULL)
  828. GNUNET_array_append (rshell_args, cnt, GNUNET_strdup (arg));
  829. GNUNET_free (rshell_cmd_cp);
  830. }
  831. if (NULL != append_args)
  832. {
  833. for (append_cnt = 0; NULL != append_args[append_cnt]; append_cnt++)
  834. GNUNET_array_append (rshell_args, cnt, GNUNET_strdup (append_args[append_cnt]));
  835. }
  836. GNUNET_array_append (rshell_args, cnt, NULL);
  837. return rshell_args;
  838. }
  839. /**
  840. * Functions with this signature are called whenever a
  841. * complete message is received by the tokenizer.
  842. *
  843. * Do not call GNUNET_SERVER_mst_destroy in callback
  844. *
  845. * @param cls closure
  846. * @param client identification of the client
  847. * @param message the actual message
  848. *
  849. * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing
  850. */
  851. static int
  852. helper_mst (void *cls,
  853. const struct GNUNET_MessageHeader *message)
  854. {
  855. struct GNUNET_TESTBED_ControllerProc *cp = cls;
  856. const struct GNUNET_TESTBED_HelperReply *msg;
  857. const char *hostname;
  858. char *config;
  859. uLongf config_size;
  860. uLongf xconfig_size;
  861. msg = (const struct GNUNET_TESTBED_HelperReply *) message;
  862. GNUNET_assert (sizeof (struct GNUNET_TESTBED_HelperReply) <
  863. ntohs (msg->header.size));
  864. GNUNET_assert (GNUNET_MESSAGE_TYPE_TESTBED_HELPER_REPLY ==
  865. ntohs (msg->header.type));
  866. config_size = (uLongf) ntohs (msg->config_size);
  867. xconfig_size =
  868. (uLongf) (ntohs (msg->header.size) -
  869. sizeof (struct GNUNET_TESTBED_HelperReply));
  870. config = GNUNET_malloc (config_size);
  871. GNUNET_assert (Z_OK ==
  872. uncompress ((Bytef *) config, &config_size,
  873. (const Bytef *) &msg[1], xconfig_size));
  874. /* Replace the configuration template present in the host with the
  875. controller's running configuration */
  876. GNUNET_CONFIGURATION_destroy (cp->host->cfg);
  877. cp->host->cfg = GNUNET_CONFIGURATION_create ();
  878. GNUNET_assert (GNUNET_CONFIGURATION_deserialize
  879. (cp->host->cfg,
  880. config,
  881. config_size,
  882. NULL));
  883. GNUNET_free (config);
  884. if (NULL == (hostname = GNUNET_TESTBED_host_get_hostname (cp->host)))
  885. hostname = "localhost";
  886. /* Change the hostname so that we can connect to it */
  887. GNUNET_CONFIGURATION_set_value_string (cp->host->cfg, "testbed", "hostname",
  888. hostname);
  889. cp->host->locked = GNUNET_NO;
  890. cp->host->controller_started = GNUNET_YES;
  891. cp->cb (cp->cls, cp->host->cfg, GNUNET_OK);
  892. return GNUNET_OK;
  893. }
  894. /**
  895. * Continuation function from GNUNET_HELPER_send()
  896. *
  897. * @param cls closure
  898. * @param result GNUNET_OK on success,
  899. * GNUNET_NO if helper process died
  900. * GNUNET_SYSERR during GNUNET_HELPER_stop
  901. */
  902. static void
  903. clear_msg (void *cls, int result)
  904. {
  905. struct GNUNET_TESTBED_ControllerProc *cp = cls;
  906. GNUNET_assert (NULL != cp->shandle);
  907. cp->shandle = NULL;
  908. GNUNET_free (cp->msg);
  909. cp->msg = NULL;
  910. }
  911. /**
  912. * Callback that will be called when the helper process dies. This is not called
  913. * when the helper process is stoped using GNUNET_HELPER_stop()
  914. *
  915. * @param cls the closure from GNUNET_HELPER_start()
  916. */
  917. static void
  918. helper_exp_cb (void *cls)
  919. {
  920. struct GNUNET_TESTBED_ControllerProc *cp = cls;
  921. GNUNET_TESTBED_ControllerStatusCallback cb;
  922. void *cb_cls;
  923. cb = cp->cb;
  924. cb_cls = cp->cls;
  925. cp->helper = NULL;
  926. GNUNET_TESTBED_controller_stop (cp);
  927. if (NULL != cb)
  928. cb (cb_cls, NULL, GNUNET_SYSERR);
  929. }
  930. /**
  931. * Starts a controller process at the given host. The given host's configuration
  932. * is used as a Template configuration to use for the remote controller; the
  933. * remote controller will be started with a slightly modified configuration
  934. * (port numbers, unix domain sockets and service home values are changed as per
  935. * TESTING library on the remote host). The modified configuration replaces the
  936. * host's existing configuration before signalling success through the
  937. * GNUNET_TESTBED_ControllerStatusCallback()
  938. *
  939. * @param trusted_ip the ip address of the controller which will be set as TRUSTED
  940. * HOST(all connections form this ip are permitted by the testbed) when
  941. * starting testbed controller at host. This can either be a single ip
  942. * address or a network address in CIDR notation.
  943. * @param host the host where the controller has to be started. CANNOT be NULL.
  944. * @param cb function called when the controller is successfully started or
  945. * dies unexpectedly; GNUNET_TESTBED_controller_stop shouldn't be
  946. * called if cb is called with GNUNET_SYSERR as status. Will never be
  947. * called in the same task as 'GNUNET_TESTBED_controller_start'
  948. * (synchronous errors will be signalled by returning NULL). This
  949. * parameter cannot be NULL.
  950. * @param cls closure for above callbacks
  951. * @return the controller process handle, NULL on errors
  952. */
  953. struct GNUNET_TESTBED_ControllerProc *
  954. GNUNET_TESTBED_controller_start (const char *trusted_ip,
  955. struct GNUNET_TESTBED_Host *host,
  956. GNUNET_TESTBED_ControllerStatusCallback cb,
  957. void *cls)
  958. {
  959. struct GNUNET_TESTBED_ControllerProc *cp;
  960. struct GNUNET_TESTBED_HelperInit *msg;
  961. const struct GNUNET_CONFIGURATION_Handle *cfg;
  962. const char *hostname;
  963. static char *const binary_argv[] = {
  964. HELPER_TESTBED_BINARY, NULL
  965. };
  966. GNUNET_assert (NULL != host);
  967. GNUNET_assert (NULL != (cfg = GNUNET_TESTBED_host_get_cfg_ (host)));
  968. hostname = NULL;
  969. API_VIOLATION (GNUNET_NO == host->locked,
  970. "Host is already locked by a previous call to GNUNET_TESTBED_controller_start()");
  971. host->locked = GNUNET_YES;
  972. API_VIOLATION (GNUNET_NO == host->controller_started,
  973. "Attempting to start a controller on a host which is already started a controller");
  974. cp = GNUNET_new (struct GNUNET_TESTBED_ControllerProc);
  975. if (0 == GNUNET_TESTBED_host_get_id_ (host))
  976. {
  977. cp->helper =
  978. GNUNET_HELPER_start (GNUNET_YES, HELPER_TESTBED_BINARY, binary_argv,
  979. &helper_mst, &helper_exp_cb, cp);
  980. }
  981. else
  982. {
  983. char *helper_binary_path_args[2];
  984. char **rsh_args;
  985. char **rsh_suffix_args;
  986. const char *username;
  987. char *port;
  988. char *argstr;
  989. char *aux;
  990. unsigned int cnt;
  991. username = host->username;
  992. hostname = host->hostname;
  993. GNUNET_asprintf (&port, "%u", host->port);
  994. LOG_DEBUG ("Starting remote connection to destination %s\n", hostname);
  995. if (GNUNET_OK !=
  996. GNUNET_CONFIGURATION_get_value_filename (cfg, "testbed",
  997. "HELPER_BINARY_PATH",
  998. &helper_binary_path_args[0]))
  999. helper_binary_path_args[0] =
  1000. GNUNET_OS_get_libexec_binary_path (HELPER_TESTBED_BINARY);
  1001. helper_binary_path_args[1] = NULL;
  1002. rsh_args = gen_rsh_args (port, hostname, username);
  1003. rsh_suffix_args = gen_rsh_suffix_args ((const char **) helper_binary_path_args);
  1004. cp->helper_argv =
  1005. join_argv ((const char **) rsh_args, (const char **) rsh_suffix_args);
  1006. free_argv (rsh_args);
  1007. free_argv (rsh_suffix_args);
  1008. GNUNET_free (port);
  1009. argstr = GNUNET_strdup ("");
  1010. for (cnt = 0; NULL != cp->helper_argv[cnt]; cnt++)
  1011. {
  1012. aux = argstr;
  1013. GNUNET_assert (0 < GNUNET_asprintf (&argstr, "%s %s", aux, cp->helper_argv[cnt]));
  1014. GNUNET_free (aux);
  1015. }
  1016. LOG_DEBUG ("Helper cmd str: %s\n", argstr);
  1017. GNUNET_free (argstr);
  1018. cp->helper =
  1019. GNUNET_HELPER_start (GNUNET_NO, cp->helper_argv[0], cp->helper_argv, &helper_mst,
  1020. &helper_exp_cb, cp);
  1021. GNUNET_free (helper_binary_path_args[0]);
  1022. }
  1023. if (NULL == cp->helper)
  1024. {
  1025. if (NULL != cp->helper_argv)
  1026. free_argv (cp->helper_argv);
  1027. GNUNET_free (cp);
  1028. return NULL;
  1029. }
  1030. cp->host = host;
  1031. cp->cb = cb;
  1032. cp->cls = cls;
  1033. msg = GNUNET_TESTBED_create_helper_init_msg_ (trusted_ip, hostname, cfg);
  1034. cp->msg = &msg->header;
  1035. cp->shandle =
  1036. GNUNET_HELPER_send (cp->helper, &msg->header, GNUNET_NO, &clear_msg, cp);
  1037. if (NULL == cp->shandle)
  1038. {
  1039. GNUNET_free (msg);
  1040. GNUNET_TESTBED_controller_stop (cp);
  1041. return NULL;
  1042. }
  1043. return cp;
  1044. }
  1045. /**
  1046. * Sends termination signal to the controller's helper process
  1047. *
  1048. * @param cproc the handle to the controller's helper process
  1049. */
  1050. void
  1051. GNUNET_TESTBED_controller_kill_ (struct GNUNET_TESTBED_ControllerProc *cproc)
  1052. {
  1053. if (NULL != cproc->shandle)
  1054. GNUNET_HELPER_send_cancel (cproc->shandle);
  1055. if (NULL != cproc->helper)
  1056. GNUNET_HELPER_kill (cproc->helper, GNUNET_YES);
  1057. }
  1058. /**
  1059. * Cleans-up the controller's helper process handle
  1060. *
  1061. * @param cproc the handle to the controller's helper process
  1062. */
  1063. void
  1064. GNUNET_TESTBED_controller_destroy_ (struct GNUNET_TESTBED_ControllerProc *cproc)
  1065. {
  1066. if (NULL != cproc->helper)
  1067. {
  1068. GNUNET_break (GNUNET_OK == GNUNET_HELPER_wait (cproc->helper));
  1069. GNUNET_HELPER_destroy (cproc->helper);
  1070. }
  1071. if (NULL != cproc->helper_argv)
  1072. free_argv (cproc->helper_argv);
  1073. cproc->host->controller_started = GNUNET_NO;
  1074. cproc->host->locked = GNUNET_NO;
  1075. GNUNET_free_non_null (cproc->msg);
  1076. GNUNET_free (cproc);
  1077. }
  1078. /**
  1079. * Stop the controller process (also will terminate all peers and controllers
  1080. * dependent on this controller). This function blocks until the testbed has
  1081. * been fully terminated (!). The controller status cb from
  1082. * GNUNET_TESTBED_controller_start() will not be called.
  1083. *
  1084. * @param cproc the controller process handle
  1085. */
  1086. void
  1087. GNUNET_TESTBED_controller_stop (struct GNUNET_TESTBED_ControllerProc *cproc)
  1088. {
  1089. GNUNET_TESTBED_controller_kill_ (cproc);
  1090. GNUNET_TESTBED_controller_destroy_ (cproc);
  1091. }
  1092. /**
  1093. * The handle for whether a host is habitable or not
  1094. */
  1095. struct GNUNET_TESTBED_HostHabitableCheckHandle
  1096. {
  1097. /**
  1098. * The host to check
  1099. */
  1100. const struct GNUNET_TESTBED_Host *host;
  1101. /**
  1102. * The callback to call once we have the status
  1103. */
  1104. GNUNET_TESTBED_HostHabitableCallback cb;
  1105. /**
  1106. * The callback closure
  1107. */
  1108. void *cb_cls;
  1109. /**
  1110. * The process handle for the SSH process
  1111. */
  1112. struct GNUNET_OS_Process *auxp;
  1113. /**
  1114. * The arguments used to start the helper
  1115. */
  1116. char **helper_argv;
  1117. /**
  1118. * Task id for the habitability check task
  1119. */
  1120. struct GNUNET_SCHEDULER_Task * habitability_check_task;
  1121. /**
  1122. * How long we wait before checking the process status. Should grow
  1123. * exponentially
  1124. */
  1125. struct GNUNET_TIME_Relative wait_time;
  1126. };
  1127. /**
  1128. * Task for checking whether a host is habitable or not
  1129. *
  1130. * @param cls GNUNET_TESTBED_HostHabitableCheckHandle
  1131. */
  1132. static void
  1133. habitability_check (void *cls)
  1134. {
  1135. struct GNUNET_TESTBED_HostHabitableCheckHandle *h = cls;
  1136. void *cb_cls;
  1137. GNUNET_TESTBED_HostHabitableCallback cb;
  1138. const struct GNUNET_TESTBED_Host *host;
  1139. unsigned long code;
  1140. enum GNUNET_OS_ProcessStatusType type;
  1141. int ret;
  1142. h->habitability_check_task = NULL;
  1143. ret = GNUNET_OS_process_status (h->auxp, &type, &code);
  1144. if (GNUNET_SYSERR == ret)
  1145. {
  1146. GNUNET_break (0);
  1147. ret = GNUNET_NO;
  1148. goto call_cb;
  1149. }
  1150. if (GNUNET_NO == ret)
  1151. {
  1152. h->wait_time = GNUNET_TIME_STD_BACKOFF (h->wait_time);
  1153. h->habitability_check_task =
  1154. GNUNET_SCHEDULER_add_delayed (h->wait_time, &habitability_check, h);
  1155. return;
  1156. }
  1157. GNUNET_OS_process_destroy (h->auxp);
  1158. h->auxp = NULL;
  1159. ret = (0 != code) ? GNUNET_NO : GNUNET_YES;
  1160. call_cb:
  1161. if (NULL != h->auxp)
  1162. GNUNET_OS_process_destroy (h->auxp);
  1163. cb = h->cb;
  1164. cb_cls = h->cb_cls;
  1165. host = h->host;
  1166. free_argv (h->helper_argv);
  1167. GNUNET_free (h);
  1168. if (NULL != cb)
  1169. cb (cb_cls, host, ret);
  1170. }
  1171. /**
  1172. * Checks whether a host can be used to start testbed service
  1173. *
  1174. * @param host the host to check
  1175. * @param config the configuration handle to lookup the path of the testbed
  1176. * helper
  1177. * @param cb the callback to call to inform about habitability of the given host
  1178. * @param cb_cls the closure for the callback
  1179. * @return NULL upon any error or a handle which can be passed to
  1180. * GNUNET_TESTBED_is_host_habitable_cancel()
  1181. */
  1182. struct GNUNET_TESTBED_HostHabitableCheckHandle *
  1183. GNUNET_TESTBED_is_host_habitable (const struct GNUNET_TESTBED_Host *host,
  1184. const struct GNUNET_CONFIGURATION_Handle
  1185. *config,
  1186. GNUNET_TESTBED_HostHabitableCallback cb,
  1187. void *cb_cls)
  1188. {
  1189. struct GNUNET_TESTBED_HostHabitableCheckHandle *h;
  1190. char **rsh_args;
  1191. char **rsh_suffix_args;
  1192. char *stat_args[3];
  1193. const char *hostname;
  1194. char *port;
  1195. h = GNUNET_new (struct GNUNET_TESTBED_HostHabitableCheckHandle);
  1196. h->cb = cb;
  1197. h->cb_cls = cb_cls;
  1198. h->host = host;
  1199. hostname = (NULL == host->hostname) ? "127.0.0.1" : host->hostname;
  1200. if (GNUNET_OK !=
  1201. GNUNET_CONFIGURATION_get_value_filename (config, "testbed",
  1202. "HELPER_BINARY_PATH",
  1203. &stat_args[1]))
  1204. stat_args[1] =
  1205. GNUNET_OS_get_libexec_binary_path (HELPER_TESTBED_BINARY);
  1206. GNUNET_asprintf (&port, "%u", host->port);
  1207. rsh_args = gen_rsh_args (port, hostname, host->username);
  1208. GNUNET_free (port);
  1209. port = NULL;
  1210. stat_args[0] = "stat";
  1211. stat_args[2] = NULL;
  1212. rsh_suffix_args = gen_rsh_suffix_args ((const char **) stat_args);
  1213. GNUNET_free (stat_args[1]);
  1214. h->helper_argv = join_argv ((const char **) rsh_args,
  1215. (const char **) rsh_suffix_args);
  1216. free_argv (rsh_suffix_args);
  1217. free_argv (rsh_args);
  1218. h->auxp =
  1219. GNUNET_OS_start_process_vap (GNUNET_NO, GNUNET_OS_INHERIT_STD_ERR, NULL,
  1220. NULL, NULL, h->helper_argv[0], h->helper_argv);
  1221. if (NULL == h->auxp)
  1222. {
  1223. GNUNET_break (0); /* Cannot exec SSH? */
  1224. GNUNET_free (h);
  1225. return NULL;
  1226. }
  1227. h->wait_time = GNUNET_TIME_STD_BACKOFF (h->wait_time);
  1228. h->habitability_check_task =
  1229. GNUNET_SCHEDULER_add_delayed (h->wait_time, &habitability_check, h);
  1230. return h;
  1231. }
  1232. /**
  1233. * Function to cancel a request started using GNUNET_TESTBED_is_host_habitable()
  1234. *
  1235. * @param handle the habitability check handle
  1236. */
  1237. void
  1238. GNUNET_TESTBED_is_host_habitable_cancel (struct
  1239. GNUNET_TESTBED_HostHabitableCheckHandle
  1240. *handle)
  1241. {
  1242. GNUNET_SCHEDULER_cancel (handle->habitability_check_task);
  1243. (void) GNUNET_OS_process_kill (handle->auxp, GNUNET_TERM_SIG);
  1244. (void) GNUNET_OS_process_wait (handle->auxp);
  1245. GNUNET_OS_process_destroy (handle->auxp);
  1246. free_argv (handle->helper_argv);
  1247. GNUNET_free (handle);
  1248. }
  1249. /**
  1250. * Register a host with the controller
  1251. *
  1252. * @param controller the controller handle
  1253. * @param host the host to register
  1254. * @param cc the completion callback to call to inform the status of
  1255. * registration. After calling this callback the registration handle
  1256. * will be invalid. Cannot be NULL.
  1257. * @param cc_cls the closure for the cc
  1258. * @return handle to the host registration which can be used to cancel the
  1259. * registration
  1260. */
  1261. struct GNUNET_TESTBED_HostRegistrationHandle *
  1262. GNUNET_TESTBED_register_host (struct GNUNET_TESTBED_Controller *controller,
  1263. struct GNUNET_TESTBED_Host *host,
  1264. GNUNET_TESTBED_HostRegistrationCompletion cc,
  1265. void *cc_cls)
  1266. {
  1267. struct GNUNET_TESTBED_HostRegistrationHandle *rh;
  1268. struct GNUNET_TESTBED_AddHostMessage *msg;
  1269. const char *username;
  1270. const char *hostname;
  1271. char *config;
  1272. char *cconfig;
  1273. void *ptr;
  1274. size_t cc_size;
  1275. size_t config_size;
  1276. uint16_t msg_size;
  1277. uint16_t username_length;
  1278. uint16_t hostname_length;
  1279. if (NULL != controller->rh)
  1280. return NULL;
  1281. hostname = GNUNET_TESTBED_host_get_hostname (host);
  1282. if (GNUNET_YES == GNUNET_TESTBED_is_host_registered_ (host, controller))
  1283. {
  1284. LOG (GNUNET_ERROR_TYPE_WARNING, "Host hostname: %s already registered\n",
  1285. (NULL == hostname) ? "localhost" : hostname);
  1286. return NULL;
  1287. }
  1288. rh = GNUNET_new (struct GNUNET_TESTBED_HostRegistrationHandle);
  1289. rh->host = host;
  1290. rh->c = controller;
  1291. GNUNET_assert (NULL != cc);
  1292. rh->cc = cc;
  1293. rh->cc_cls = cc_cls;
  1294. controller->rh = rh;
  1295. username = GNUNET_TESTBED_host_get_username_ (host);
  1296. username_length = 0;
  1297. if (NULL != username)
  1298. username_length = strlen (username);
  1299. GNUNET_assert (NULL != hostname); /* Hostname must be present */
  1300. hostname_length = strlen (hostname);
  1301. GNUNET_assert (NULL != host->cfg);
  1302. config = GNUNET_CONFIGURATION_serialize (host->cfg, &config_size);
  1303. cc_size = GNUNET_TESTBED_compress_config_ (config, config_size, &cconfig);
  1304. GNUNET_free (config);
  1305. msg_size = (sizeof (struct GNUNET_TESTBED_AddHostMessage));
  1306. msg_size += username_length;
  1307. msg_size += hostname_length;
  1308. msg_size += cc_size;
  1309. msg = GNUNET_malloc (msg_size);
  1310. msg->header.size = htons (msg_size);
  1311. msg->header.type = htons (GNUNET_MESSAGE_TYPE_TESTBED_ADD_HOST);
  1312. msg->host_id = htonl (GNUNET_TESTBED_host_get_id_ (host));
  1313. msg->ssh_port = htons (GNUNET_TESTBED_host_get_ssh_port_ (host));
  1314. ptr = &msg[1];
  1315. if (NULL != username)
  1316. {
  1317. msg->username_length = htons (username_length);
  1318. GNUNET_memcpy (ptr, username, username_length);
  1319. ptr += username_length;
  1320. }
  1321. msg->hostname_length = htons (hostname_length);
  1322. GNUNET_memcpy (ptr, hostname, hostname_length);
  1323. ptr += hostname_length;
  1324. msg->config_size = htons (config_size);
  1325. GNUNET_memcpy (ptr, cconfig, cc_size);
  1326. ptr += cc_size;
  1327. GNUNET_assert ((ptr - (void *) msg) == msg_size);
  1328. GNUNET_free (cconfig);
  1329. GNUNET_TESTBED_queue_message_ (controller,
  1330. (struct GNUNET_MessageHeader *) msg);
  1331. return rh;
  1332. }
  1333. /**
  1334. * Cancel the pending registration. Note that if the registration message is
  1335. * already sent to the service the cancellation has only the effect that the
  1336. * registration completion callback for the registration is never called.
  1337. *
  1338. * @param handle the registration handle to cancel
  1339. */
  1340. void
  1341. GNUNET_TESTBED_cancel_registration (struct GNUNET_TESTBED_HostRegistrationHandle
  1342. *handle)
  1343. {
  1344. if (handle != handle->c->rh)
  1345. {
  1346. GNUNET_break (0);
  1347. return;
  1348. }
  1349. handle->c->rh = NULL;
  1350. GNUNET_free (handle);
  1351. }
  1352. /**
  1353. * Queues the given operation in the queue for parallel overlay connects of the
  1354. * given host
  1355. *
  1356. * @param h the host handle
  1357. * @param op the operation to queue in the given host's parally overlay connect
  1358. * queue
  1359. */
  1360. void
  1361. GNUNET_TESTBED_host_queue_oc_ (struct GNUNET_TESTBED_Host *h,
  1362. struct GNUNET_TESTBED_Operation *op)
  1363. {
  1364. GNUNET_TESTBED_operation_queue_insert_
  1365. (h->opq_parallel_overlay_connect_operations, op);
  1366. }
  1367. /**
  1368. * Resolves the hostname of the host to an ip address
  1369. *
  1370. * @param host the host whose hostname is to be resolved
  1371. */
  1372. void
  1373. GNUNET_TESTBED_host_resolve_ (struct GNUNET_TESTBED_Host *host)
  1374. {
  1375. char *hostname;
  1376. hostname = (char *) host->hostname;
  1377. host->hostname = simple_resolve (hostname);
  1378. if (NULL == host->hostname)
  1379. {
  1380. GNUNET_break (0);
  1381. host->hostname = hostname;
  1382. return;
  1383. }
  1384. GNUNET_free (hostname);
  1385. host->hostname = GNUNET_strdup (host->hostname);
  1386. }
  1387. /* end of testbed_api_hosts.c */