gnunet-service-testbed.c 30 KB

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