gnunet-rest-server.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815
  1. /*
  2. This file is part of GNUnet.
  3. Copyright (C) 2012-2015 GNUnet e.V.
  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., 51 Franklin Street, Fifth Floor,
  15. Boston, MA 02110-1301, USA.
  16. */
  17. /**
  18. * @author Martin Schanzenbach
  19. * @file src/rest/gnunet-rest-server.c
  20. * @brief REST service for GNUnet services
  21. *
  22. */
  23. #include "platform.h"
  24. #include <microhttpd.h>
  25. #include "gnunet_util_lib.h"
  26. #include "gnunet_rest_plugin.h"
  27. /**
  28. * Default Socks5 listen port.
  29. */
  30. #define GNUNET_REST_SERVICE_PORT 7776
  31. /**
  32. * Maximum supported length for a URI.
  33. * Should die. @deprecated
  34. */
  35. #define MAX_HTTP_URI_LENGTH 2048
  36. /**
  37. * Port for plaintext HTTP.
  38. */
  39. #define HTTP_PORT 80
  40. /**
  41. * Port for HTTPS.
  42. */
  43. #define HTTPS_PORT 443
  44. /**
  45. * After how long do we clean up unused MHD SSL/TLS instances?
  46. */
  47. #define MHD_CACHE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
  48. #define GN_REST_STATE_INIT 0
  49. #define GN_REST_STATE_PROCESSING 1
  50. /**
  51. * The task ID
  52. */
  53. static struct GNUNET_SCHEDULER_Task *httpd_task;
  54. /**
  55. * The port the service is running on (default 7776)
  56. */
  57. static unsigned long long port = GNUNET_REST_SERVICE_PORT;
  58. /**
  59. * The listen socket of the service for IPv4
  60. */
  61. static struct GNUNET_NETWORK_Handle *lsock4;
  62. /**
  63. * The listen socket of the service for IPv6
  64. */
  65. static struct GNUNET_NETWORK_Handle *lsock6;
  66. /**
  67. * The listen task ID for IPv4
  68. */
  69. static struct GNUNET_SCHEDULER_Task * ltask4;
  70. /**
  71. * The listen task ID for IPv6
  72. */
  73. static struct GNUNET_SCHEDULER_Task * ltask6;
  74. /**
  75. * Daemon for HTTP
  76. */
  77. static struct MHD_Daemon *httpd;
  78. /**
  79. * Response we return on failures.
  80. */
  81. static struct MHD_Response *failure_response;
  82. /**
  83. * Our configuration.
  84. */
  85. static const struct GNUNET_CONFIGURATION_Handle *cfg;
  86. /**
  87. * Map of loaded plugins.
  88. */
  89. static struct GNUNET_CONTAINER_MultiHashMap *plugin_map;
  90. /**
  91. * Allowed Origins (CORS)
  92. */
  93. static char* allow_origin;
  94. /**
  95. * Allowed Headers (CORS)
  96. */
  97. static char* allow_headers;
  98. /**
  99. * MHD Connection handle
  100. */
  101. struct MhdConnectionHandle
  102. {
  103. struct MHD_Connection *con;
  104. struct MHD_Response *response;
  105. struct GNUNET_REST_Plugin *plugin;
  106. struct GNUNET_REST_RequestHandle *data_handle;
  107. int status;
  108. int state;
  109. };
  110. /* ************************* Global helpers ********************* */
  111. /**
  112. * Task run whenever HTTP server operations are pending.
  113. *
  114. * @param cls NULL
  115. */
  116. static void
  117. do_httpd (void *cls);
  118. /**
  119. * Run MHD now, we have extra data ready for the callback.
  120. */
  121. static void
  122. run_mhd_now ()
  123. {
  124. if (NULL !=
  125. httpd_task)
  126. GNUNET_SCHEDULER_cancel (httpd_task);
  127. httpd_task = GNUNET_SCHEDULER_add_now (&do_httpd,
  128. NULL);
  129. }
  130. /**
  131. * Plugin result callback
  132. *
  133. * @param cls closure (MHD connection handle)
  134. * @param data the data to return to the caller
  135. * @param len length of the data
  136. * @param status #GNUNET_OK if successful
  137. */
  138. static void
  139. plugin_callback (void *cls,
  140. struct MHD_Response *resp,
  141. int status)
  142. {
  143. struct MhdConnectionHandle *handle = cls;
  144. handle->status = status;
  145. handle->response = resp;
  146. run_mhd_now();
  147. }
  148. static int
  149. cleanup_url_map (void *cls,
  150. const struct GNUNET_HashCode *key,
  151. void *value)
  152. {
  153. GNUNET_free_non_null (value);
  154. return GNUNET_YES;
  155. }
  156. static void
  157. cleanup_handle (struct MhdConnectionHandle *handle)
  158. {
  159. if (NULL != handle->response)
  160. MHD_destroy_response (handle->response);
  161. if (NULL != handle->data_handle)
  162. {
  163. if (NULL != handle->data_handle->url_param_map)
  164. {
  165. GNUNET_CONTAINER_multihashmap_iterate (handle->data_handle->url_param_map,
  166. &cleanup_url_map,
  167. NULL);
  168. GNUNET_CONTAINER_multihashmap_destroy (handle->data_handle->url_param_map);
  169. }
  170. GNUNET_free (handle->data_handle);
  171. }
  172. GNUNET_free (handle);
  173. }
  174. static int
  175. url_iterator (void *cls,
  176. enum MHD_ValueKind kind,
  177. const char *key,
  178. const char *value)
  179. {
  180. struct GNUNET_REST_RequestHandle *handle = cls;
  181. struct GNUNET_HashCode hkey;
  182. char *val;
  183. GNUNET_CRYPTO_hash (key, strlen (key), &hkey);
  184. GNUNET_asprintf (&val, "%s", value);
  185. if (GNUNET_OK !=
  186. GNUNET_CONTAINER_multihashmap_put (handle->url_param_map,
  187. &hkey,
  188. val,
  189. GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
  190. {
  191. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  192. "Could not load add url param `%s'=%s\n",
  193. key, value);
  194. }
  195. return MHD_YES;
  196. }
  197. /* ********************************* MHD response generation ******************* */
  198. /**
  199. * Main MHD callback for handling requests.
  200. *
  201. * @param cls unused
  202. * @param con MHD connection handle
  203. * @param url the url in the request
  204. * @param meth the HTTP method used ("GET", "PUT", etc.)
  205. * @param ver the HTTP version string (i.e. "HTTP/1.1")
  206. * @param upload_data the data being uploaded (excluding HEADERS,
  207. * for a POST that fits into memory and that is encoded
  208. * with a supported encoding, the POST data will NOT be
  209. * given in upload_data and is instead available as
  210. * part of MHD_get_connection_values; very large POST
  211. * data *will* be made available incrementally in
  212. * upload_data)
  213. * @param upload_data_size set initially to the size of the
  214. * @a upload_data provided; the method must update this
  215. * value to the number of bytes NOT processed;
  216. * @param con_cls pointer to location where we store the 'struct Request'
  217. * @return MHD_YES if the connection was handled successfully,
  218. * MHD_NO if the socket must be closed due to a serious
  219. * error while handling the request
  220. */
  221. static int
  222. create_response (void *cls,
  223. struct MHD_Connection *con,
  224. const char *url,
  225. const char *meth,
  226. const char *ver,
  227. const char *upload_data,
  228. size_t *upload_data_size,
  229. void **con_cls)
  230. {
  231. char *plugin_name;
  232. struct GNUNET_HashCode key;
  233. struct MhdConnectionHandle *con_handle;
  234. struct GNUNET_REST_RequestHandle *rest_conndata_handle;
  235. con_handle = *con_cls;
  236. if (NULL == *con_cls)
  237. {
  238. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  239. "New connection %s\n", url);
  240. char tmp_url[strlen(url)+1];
  241. strcpy (tmp_url, url);
  242. con_handle = GNUNET_new (struct MhdConnectionHandle);
  243. con_handle->con = con;
  244. con_handle->state = GN_REST_STATE_INIT;
  245. *con_cls = con_handle;
  246. plugin_name = strtok(tmp_url, "/");
  247. if (NULL != plugin_name)
  248. {
  249. GNUNET_CRYPTO_hash (plugin_name, strlen (plugin_name), &key);
  250. con_handle->plugin = GNUNET_CONTAINER_multihashmap_get (plugin_map,
  251. &key);
  252. }
  253. if (NULL == con_handle->plugin)
  254. {
  255. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  256. "Queueing response with MHD\n");
  257. GNUNET_free (con_handle);
  258. return MHD_queue_response (con,
  259. MHD_HTTP_NOT_FOUND,
  260. failure_response);
  261. }
  262. return MHD_YES;
  263. }
  264. if (GN_REST_STATE_INIT == con_handle->state)
  265. {
  266. rest_conndata_handle = GNUNET_new (struct GNUNET_REST_RequestHandle);
  267. rest_conndata_handle->method = meth;
  268. rest_conndata_handle->url = url;
  269. rest_conndata_handle->data = upload_data;
  270. rest_conndata_handle->data_size = *upload_data_size;
  271. rest_conndata_handle->url_param_map = GNUNET_CONTAINER_multihashmap_create (16,
  272. GNUNET_NO);
  273. con_handle->data_handle = rest_conndata_handle;
  274. MHD_get_connection_values (con,
  275. MHD_GET_ARGUMENT_KIND,
  276. &url_iterator,
  277. rest_conndata_handle);
  278. con_handle->state = GN_REST_STATE_PROCESSING;
  279. con_handle->plugin->process_request (rest_conndata_handle,
  280. &plugin_callback,
  281. con_handle);
  282. *upload_data_size = 0;
  283. }
  284. if (NULL != con_handle->response)
  285. {
  286. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  287. "Queueing response from plugin with MHD\n");
  288. //Handle Preflights
  289. if (NULL != allow_origin)
  290. {
  291. MHD_add_response_header (con_handle->response,
  292. MHD_HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN,
  293. allow_origin);
  294. }
  295. if (NULL != allow_headers)
  296. {
  297. MHD_add_response_header (con_handle->response,
  298. "Access-Control-Allow-Headers",
  299. allow_headers);
  300. }
  301. //Always add JSONAPI content type. TODO
  302. MHD_add_response_header (con_handle->response,
  303. MHD_HTTP_HEADER_CONTENT_TYPE,
  304. "application/vnd.api+json");
  305. int ret = MHD_queue_response (con,
  306. con_handle->status,
  307. con_handle->response);
  308. cleanup_handle (con_handle);
  309. return ret;
  310. }
  311. return MHD_YES;
  312. }
  313. /* ******************** MHD HTTP setup and event loop ******************** */
  314. /**
  315. * Function called when MHD decides that we are done with a connection.
  316. *
  317. * @param cls NULL
  318. * @param connection connection handle
  319. * @param con_cls value as set by the last call to
  320. * the MHD_AccessHandlerCallback, should be our handle
  321. * @param toe reason for request termination (ignored)
  322. */
  323. static void
  324. mhd_completed_cb (void *cls,
  325. struct MHD_Connection *connection,
  326. void **con_cls,
  327. enum MHD_RequestTerminationCode toe)
  328. {
  329. if (MHD_REQUEST_TERMINATED_COMPLETED_OK != toe)
  330. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  331. "MHD encountered error handling request: %d\n",
  332. toe);
  333. }
  334. /**
  335. * Kill the MHD daemon.
  336. */
  337. static void
  338. kill_httpd ()
  339. {
  340. if (NULL != httpd)
  341. {
  342. MHD_stop_daemon (httpd);
  343. httpd = NULL;
  344. }
  345. if (NULL != httpd_task)
  346. {
  347. GNUNET_SCHEDULER_cancel (httpd_task);
  348. httpd_task = NULL;
  349. }
  350. if (NULL != ltask4)
  351. {
  352. GNUNET_SCHEDULER_cancel (ltask4);
  353. ltask4 = NULL;
  354. }
  355. if (NULL != ltask6)
  356. {
  357. GNUNET_SCHEDULER_cancel (ltask6);
  358. ltask6 = NULL;
  359. }
  360. }
  361. /**
  362. * Schedule MHD. This function should be called initially when an
  363. * MHD is first getting its client socket, and will then automatically
  364. * always be called later whenever there is work to be done.
  365. *
  366. * @param hd the daemon to schedule
  367. */
  368. static void
  369. schedule_httpd ()
  370. {
  371. fd_set rs;
  372. fd_set ws;
  373. fd_set es;
  374. struct GNUNET_NETWORK_FDSet *wrs;
  375. struct GNUNET_NETWORK_FDSet *wws;
  376. int max;
  377. int haveto;
  378. MHD_UNSIGNED_LONG_LONG timeout;
  379. struct GNUNET_TIME_Relative tv;
  380. FD_ZERO (&rs);
  381. FD_ZERO (&ws);
  382. FD_ZERO (&es);
  383. max = -1;
  384. if (MHD_YES != MHD_get_fdset (httpd, &rs, &ws, &es, &max))
  385. {
  386. kill_httpd ();
  387. return;
  388. }
  389. haveto = MHD_get_timeout (httpd, &timeout);
  390. if (MHD_YES == haveto)
  391. tv.rel_value_us = (uint64_t) timeout * 1000LL;
  392. else
  393. tv = GNUNET_TIME_UNIT_FOREVER_REL;
  394. if (-1 != max)
  395. {
  396. wrs = GNUNET_NETWORK_fdset_create ();
  397. wws = GNUNET_NETWORK_fdset_create ();
  398. GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1);
  399. GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1);
  400. }
  401. else
  402. {
  403. wrs = NULL;
  404. wws = NULL;
  405. }
  406. if (NULL != httpd_task)
  407. GNUNET_SCHEDULER_cancel (httpd_task);
  408. if ( (MHD_YES == haveto) ||
  409. (-1 != max))
  410. {
  411. httpd_task =
  412. GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
  413. tv, wrs, wws,
  414. &do_httpd, NULL);
  415. }
  416. if (NULL != wrs)
  417. GNUNET_NETWORK_fdset_destroy (wrs);
  418. if (NULL != wws)
  419. GNUNET_NETWORK_fdset_destroy (wws);
  420. }
  421. /**
  422. * Task run whenever HTTP server operations are pending.
  423. *
  424. * @param cls NULL
  425. */
  426. static void
  427. do_httpd (void *cls)
  428. {
  429. httpd_task = NULL;
  430. MHD_run (httpd);
  431. schedule_httpd ();
  432. }
  433. /**
  434. * Accept new incoming connections
  435. *
  436. * @param cls the closure with the lsock4 or lsock6
  437. * @param tc the scheduler context
  438. */
  439. static void
  440. do_accept (void *cls)
  441. {
  442. struct GNUNET_NETWORK_Handle *lsock = cls;
  443. struct GNUNET_NETWORK_Handle *s;
  444. int fd;
  445. const struct sockaddr *addr;
  446. socklen_t len;
  447. if (lsock == lsock4)
  448. ltask4 = NULL;
  449. else
  450. ltask6 = NULL;
  451. if (lsock == lsock4)
  452. ltask4 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
  453. lsock,
  454. &do_accept, lsock);
  455. else
  456. ltask6 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
  457. lsock,
  458. &do_accept, lsock);
  459. s = GNUNET_NETWORK_socket_accept (lsock, NULL, NULL);
  460. if (NULL == s)
  461. {
  462. GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "accept");
  463. return;
  464. }
  465. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  466. "Got an inbound connection, waiting for data\n");
  467. fd = GNUNET_NETWORK_get_fd (s);
  468. addr = GNUNET_NETWORK_get_addr (s);
  469. len = GNUNET_NETWORK_get_addrlen (s);
  470. if (MHD_YES != MHD_add_connection (httpd, fd, addr, len))
  471. {
  472. GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
  473. _("Failed to pass client to MHD\n"));
  474. return;
  475. }
  476. schedule_httpd ();
  477. }
  478. /**
  479. * Task run on shutdown
  480. *
  481. * @param cls closure
  482. */
  483. static void
  484. do_shutdown (void *cls)
  485. {
  486. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  487. "Shutting down...\n");
  488. kill_httpd ();
  489. GNUNET_free_non_null (allow_origin);
  490. GNUNET_free_non_null (allow_headers);
  491. }
  492. /**
  493. * Create an IPv4 listen socket bound to our port.
  494. *
  495. * @return NULL on error
  496. */
  497. static struct GNUNET_NETWORK_Handle *
  498. bind_v4 ()
  499. {
  500. struct GNUNET_NETWORK_Handle *ls;
  501. struct sockaddr_in sa4;
  502. int eno;
  503. memset (&sa4, 0, sizeof (sa4));
  504. sa4.sin_family = AF_INET;
  505. sa4.sin_port = htons (port);
  506. #if HAVE_SOCKADDR_IN_SIN_LEN
  507. sa4.sin_len = sizeof (sa4);
  508. #endif
  509. ls = GNUNET_NETWORK_socket_create (AF_INET,
  510. SOCK_STREAM,
  511. 0);
  512. if (NULL == ls)
  513. return NULL;
  514. if (GNUNET_OK !=
  515. GNUNET_NETWORK_socket_bind (ls, (const struct sockaddr *) &sa4,
  516. sizeof (sa4)))
  517. {
  518. eno = errno;
  519. GNUNET_NETWORK_socket_close (ls);
  520. errno = eno;
  521. return NULL;
  522. }
  523. return ls;
  524. }
  525. /**
  526. * Create an IPv6 listen socket bound to our port.
  527. *
  528. * @return NULL on error
  529. */
  530. static struct GNUNET_NETWORK_Handle *
  531. bind_v6 ()
  532. {
  533. struct GNUNET_NETWORK_Handle *ls;
  534. struct sockaddr_in6 sa6;
  535. int eno;
  536. memset (&sa6, 0, sizeof (sa6));
  537. sa6.sin6_family = AF_INET6;
  538. sa6.sin6_port = htons (port);
  539. #if HAVE_SOCKADDR_IN_SIN_LEN
  540. sa6.sin6_len = sizeof (sa6);
  541. #endif
  542. ls = GNUNET_NETWORK_socket_create (AF_INET6,
  543. SOCK_STREAM,
  544. 0);
  545. if (NULL == ls)
  546. return NULL;
  547. if (GNUNET_OK !=
  548. GNUNET_NETWORK_socket_bind (ls, (const struct sockaddr *) &sa6,
  549. sizeof (sa6)))
  550. {
  551. eno = errno;
  552. GNUNET_NETWORK_socket_close (ls);
  553. errno = eno;
  554. return NULL;
  555. }
  556. return ls;
  557. }
  558. /**
  559. * Callback for plugin load
  560. *
  561. * @param cls NULL
  562. * @param libname the name of the library loaded
  563. * @param lib_ret the object returned by the plugin initializer
  564. */
  565. static void
  566. load_plugin (void *cls,
  567. const char *libname,
  568. void *lib_ret)
  569. {
  570. struct GNUNET_REST_Plugin *plugin = lib_ret;
  571. struct GNUNET_HashCode key;
  572. if (NULL == lib_ret)
  573. {
  574. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  575. "Could not load plugin `%s'\n",
  576. libname);
  577. return;
  578. }
  579. GNUNET_assert (1 < strlen (plugin->name));
  580. GNUNET_assert ('/' == *plugin->name);
  581. GNUNET_CRYPTO_hash (plugin->name+1, strlen (plugin->name+1), &key);
  582. if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_put (plugin_map,
  583. &key,
  584. plugin,
  585. GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
  586. {
  587. GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
  588. "Could not load add plugin `%s'\n",
  589. libname);
  590. return;
  591. }
  592. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  593. "Loaded plugin `%s'\n",
  594. libname);
  595. }
  596. /**
  597. * Main function that will be run
  598. *
  599. * @param cls closure
  600. * @param args remaining command-line arguments
  601. * @param cfgfile name of the configuration file used (for saving, can be NULL)
  602. * @param c configuration
  603. */
  604. static void
  605. run (void *cls,
  606. char *const *args,
  607. const char *cfgfile,
  608. const struct GNUNET_CONFIGURATION_Handle *c)
  609. {
  610. cfg = c;
  611. plugin_map = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
  612. /* Get CORS data from cfg */
  613. if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "rest",
  614. "REST_ALLOW_ORIGIN",
  615. &allow_origin))
  616. {
  617. //No origin specified
  618. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  619. "No CORS Access-Control-Allow-Origin Header will be sent...\n");
  620. }
  621. if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (cfg, "rest",
  622. "REST_ALLOW_HEADERS",
  623. &allow_headers))
  624. {
  625. //No origin specified
  626. GNUNET_log (GNUNET_ERROR_TYPE_INFO,
  627. "No CORS Access-Control-Allow-Headers Header will be sent...\n");
  628. }
  629. /* Open listen socket proxy */
  630. lsock6 = bind_v6 ();
  631. if (NULL == lsock6)
  632. {
  633. GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
  634. }
  635. else
  636. {
  637. if (GNUNET_OK != GNUNET_NETWORK_socket_listen (lsock6, 5))
  638. {
  639. GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "listen");
  640. GNUNET_NETWORK_socket_close (lsock6);
  641. lsock6 = NULL;
  642. }
  643. else
  644. {
  645. ltask6 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
  646. lsock6, &do_accept, lsock6);
  647. }
  648. }
  649. lsock4 = bind_v4 ();
  650. if (NULL == lsock4)
  651. {
  652. GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
  653. }
  654. else
  655. {
  656. if (GNUNET_OK != GNUNET_NETWORK_socket_listen (lsock4, 5))
  657. {
  658. GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "listen");
  659. GNUNET_NETWORK_socket_close (lsock4);
  660. lsock4 = NULL;
  661. }
  662. else
  663. {
  664. ltask4 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
  665. lsock4, &do_accept, lsock4);
  666. }
  667. }
  668. if ( (NULL == lsock4) &&
  669. (NULL == lsock6) )
  670. {
  671. GNUNET_SCHEDULER_shutdown ();
  672. return;
  673. }
  674. GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
  675. "Service listens on port %llu\n",
  676. port);
  677. httpd = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_NO_LISTEN_SOCKET,
  678. 0,
  679. NULL, NULL,
  680. &create_response, NULL,
  681. MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) 16,
  682. MHD_OPTION_NOTIFY_COMPLETED, &mhd_completed_cb, NULL,
  683. MHD_OPTION_END);
  684. if (NULL == httpd)
  685. {
  686. GNUNET_SCHEDULER_shutdown ();
  687. return;
  688. }
  689. /* Load plugins */
  690. GNUNET_PLUGIN_load_all ("libgnunet_plugin_rest",
  691. (void *) cfg,
  692. &load_plugin,
  693. NULL);
  694. GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
  695. }
  696. /**
  697. *
  698. * The main function for gnunet-rest-service
  699. *
  700. * @param argc number of arguments from the cli
  701. * @param argv command line arguments
  702. * @return 0 ok, 1 on error
  703. *
  704. */
  705. int
  706. main (int argc, char *const *argv)
  707. {
  708. struct GNUNET_GETOPT_CommandLineOption options[] = {
  709. GNUNET_GETOPT_option_ulong ('p',
  710. "port",
  711. "PORT",
  712. gettext_noop ("listen on specified port (default: 7776)"),
  713. &port),
  714. GNUNET_GETOPT_OPTION_END
  715. };
  716. static const char* err_page =
  717. "{}";
  718. int ret;
  719. if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
  720. return 2;
  721. GNUNET_log_setup ("gnunet-rest-server", "WARNING", NULL);
  722. failure_response = MHD_create_response_from_buffer (strlen(err_page),
  723. (void*)err_page,
  724. MHD_RESPMEM_PERSISTENT);
  725. ret =
  726. (GNUNET_OK ==
  727. GNUNET_PROGRAM_run (argc, argv, "gnunet-rest-server",
  728. _("GNUnet REST server"),
  729. options,
  730. &run, NULL)) ? 0: 1;
  731. MHD_destroy_response (failure_response);
  732. GNUNET_free_non_null ((char *) argv);
  733. return ret;
  734. }
  735. /* end of gnunet-rest-server.c */