GNUnet  0.11.x
gnunet-rest-server.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet.
3  Copyright (C) 2012-2015 GNUnet e.V.
4 
5  GNUnet is free software: you can redistribute it and/or modify it
6  under the terms of the GNU Affero General Public License as published
7  by the Free Software Foundation, either version 3 of the License,
8  or (at your option) any later version.
9 
10  GNUnet is distributed in the hope that it will be useful, but
11  WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Affero General Public License for more details.
14 
15  You should have received a copy of the GNU Affero General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 
18  SPDX-License-Identifier: AGPL3.0-or-later
19  */
26 #include "platform.h"
27 #include <microhttpd.h>
28 #include "gnunet_util_lib.h"
29 #include "gnunet_rest_plugin.h"
30 #include "gnunet_mhd_compat.h"
31 
35 #define GNUNET_REST_SERVICE_PORT 7776
36 
41 #define MAX_HTTP_URI_LENGTH 2048
42 
46 #define HTTP_PORT 80
47 
51 #define HTTPS_PORT 443
52 
56 #define MHD_CACHE_TIMEOUT \
57  GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
58 
59 #define GN_REST_STATE_INIT 0
60 #define GN_REST_STATE_PROCESSING 1
61 
66 
70 static in_addr_t address;
71 
75 static struct in6_addr address6;
76 
80 static unsigned long long port = GNUNET_REST_SERVICE_PORT;
81 
86 
91 
96 
101 
105 static struct MHD_Daemon *httpd;
106 
110 static struct MHD_Response *failure_response;
111 
115 static const struct GNUNET_CONFIGURATION_Handle *cfg;
116 
120 static int echo_origin;
121 
125 static char *allow_origins;
126 
130 static char *allow_headers;
131 
135 static char *allow_credentials;
136 
141 
146 
151 {
152  /* DLL */
154 
155  /* DLL */
157 
161  char *libname;
162 
167 };
168 
173 {
174  struct MHD_Connection *con;
175 
176  struct MHD_Response *response;
177 
179 
180  struct MHD_PostProcessor *pp;
181 
182  int status;
183 
184  int state;
185 };
186 
191 {
196 
201 
206 
211 
216 };
217 
222 
227 
228 /* ************************* Global helpers ********************* */
229 
230 
236 static void
237 do_httpd (void *cls);
238 
239 
243 static void
245 {
246  if (NULL != httpd_task)
247  {
248  GNUNET_SCHEDULER_cancel (httpd_task);
249  httpd_task = NULL;
250  }
251  httpd_task = GNUNET_SCHEDULER_add_now (&do_httpd, NULL);
252 }
253 
254 
263 static void
264 plugin_callback (void *cls, struct MHD_Response *resp, int status)
265 {
266  struct MhdConnectionHandle *handle = cls;
267 
268  handle->status = status;
269  handle->response = resp;
270  MHD_resume_connection (handle->con);
271  run_mhd_now ();
272 }
273 
274 
275 static int
276 cleanup_url_map (void *cls, const struct GNUNET_HashCode *key, void *value)
277 {
278  GNUNET_free (value);
279  return GNUNET_YES;
280 }
281 
282 static void
284 {
285  if (NULL != handle->response)
286  MHD_destroy_response (handle->response);
287  if (NULL != handle->data_handle)
288  {
289  if (NULL != handle->data_handle->header_param_map)
290  {
294  NULL);
296  handle->data_handle->header_param_map);
297  }
298  if (NULL != handle->data_handle->url_param_map)
299  {
302  NULL);
304  handle->data_handle->url_param_map);
305  }
306  GNUNET_free (handle->data_handle);
307  }
308  GNUNET_free (handle);
309 }
310 
311 static void
313 {
314  if (NULL != ar->con_handle)
315  {
317  }
318  if (GNUNET_YES == ar->socket_with_mhd)
319  {
321  } else {
323  }
324  ar->sock = NULL;
325  GNUNET_CONTAINER_DLL_remove (req_list_head,
326  req_list_tail,
327  ar);
328  GNUNET_free (ar);
329 }
330 
331 static int
332 header_iterator (void *cls,
333  enum MHD_ValueKind kind,
334  const char *key,
335  const char *value)
336 {
337  struct GNUNET_REST_RequestHandle *handle = cls;
338  struct GNUNET_HashCode hkey;
339  char *val;
340  char *lowerkey;
341 
342  lowerkey = GNUNET_strdup (key);
343  GNUNET_STRINGS_utf8_tolower (key, lowerkey);
344  GNUNET_CRYPTO_hash (lowerkey, strlen (lowerkey), &hkey);
345  GNUNET_asprintf (&val, "%s", value);
347  handle->header_param_map,
348  &hkey,
349  val,
351  {
353  "Could not load add header `%s'=%s\n",
354  lowerkey,
355  value);
356  }
357  GNUNET_free (lowerkey);
358  return MHD_YES;
359 }
360 
361 
362 static int
363 url_iterator (void *cls,
364  enum MHD_ValueKind kind,
365  const char *key,
366  const char *value)
367 {
368  struct GNUNET_REST_RequestHandle *handle = cls;
369  struct GNUNET_HashCode hkey;
370  char *val;
371 
372  GNUNET_CRYPTO_hash (key, strlen (key), &hkey);
373  GNUNET_asprintf (&val, "%s", value);
375  handle->url_param_map,
376  &hkey,
377  val,
379  {
381  "Could not load add url param `%s'=%s\n",
382  key,
383  value);
384  }
385  return MHD_YES;
386 }
387 
388 
389 static MHD_RESULT
390 post_data_iter (void *cls,
391  enum MHD_ValueKind kind,
392  const char *key,
393  const char *filename,
394  const char *content_type,
395  const char *transfer_encoding,
396  const char *data,
397  uint64_t off,
398  size_t size)
399 {
400  struct GNUNET_REST_RequestHandle *handle = cls;
401  struct GNUNET_HashCode hkey;
402  char *val;
403 
404  if (MHD_POSTDATA_KIND != kind)
405  return MHD_YES;
406 
407  GNUNET_CRYPTO_hash (key, strlen (key), &hkey);
409  &hkey);
410  if (NULL == val)
411  {
412  val = GNUNET_malloc (65536);
414  handle->url_param_map,
415  &hkey,
416  val,
418  {
420  "Could not add url param '%s'\n",
421  key);
422  GNUNET_free (val);
423  }
424  }
425  memcpy (val + off, data, size);
426  return MHD_YES;
427 }
428 
429 
430 /* ********************************* MHD response generation ******************* */
431 
455 static MHD_RESULT
456 create_response (void *cls,
457  struct MHD_Connection *con,
458  const char *url,
459  const char *meth,
460  const char *ver,
461  const char *upload_data,
462  size_t *upload_data_size,
463  void **con_cls)
464 {
465  char *origin;
466  struct AcceptedRequest *ar;
467  struct GNUNET_HashCode key;
468  struct MhdConnectionHandle *con_handle;
469  struct GNUNET_REST_RequestHandle *rest_conndata_handle;
470  struct PluginListEntry *ple;
471 
472  ar = *con_cls;
473  if (NULL == ar)
474  {
475  GNUNET_break (0);
476  return MHD_NO;
477  }
478 
479  if (NULL == ar->con_handle)
480  {
481  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "New connection %s\n", url);
482  con_handle = GNUNET_new (struct MhdConnectionHandle);
483  con_handle->con = con;
484  con_handle->state = GN_REST_STATE_INIT;
485  ar->con_handle = con_handle;
486  return MHD_YES;
487  }
488  con_handle = ar->con_handle;
489  if (GN_REST_STATE_INIT == con_handle->state)
490  {
491  rest_conndata_handle = GNUNET_new (struct GNUNET_REST_RequestHandle);
492  rest_conndata_handle->method = meth;
493  rest_conndata_handle->url = url;
494  rest_conndata_handle->data = upload_data;
495  rest_conndata_handle->data_size = *upload_data_size;
496  rest_conndata_handle->url_param_map =
498  rest_conndata_handle->header_param_map =
500  con_handle->data_handle = rest_conndata_handle;
501  MHD_get_connection_values (con,
502  MHD_GET_ARGUMENT_KIND,
503  (MHD_KeyValueIterator) & url_iterator,
504  rest_conndata_handle);
505  MHD_get_connection_values (con,
506  MHD_HEADER_KIND,
507  (MHD_KeyValueIterator) & header_iterator,
508  rest_conndata_handle);
509 
510  con_handle->pp = MHD_create_post_processor (con,
511  65536,
513  rest_conndata_handle);
514  if (*upload_data_size)
515  {
516  MHD_post_process (con_handle->pp, upload_data, *upload_data_size);
517  }
518  MHD_destroy_post_processor (con_handle->pp);
519 
520  con_handle->state = GN_REST_STATE_PROCESSING;
521  for (ple = plugins_head; NULL != ple; ple = ple->next)
522  {
523  if (GNUNET_YES == ple->plugin->process_request (rest_conndata_handle,
525  con_handle))
526  break; /* Request handled */
527  }
528  if (NULL == ple)
529  {
531  MHD_queue_response (con, MHD_HTTP_NOT_FOUND, failure_response);
532  }
533  *upload_data_size = 0;
534  run_mhd_now ();
535  return MHD_YES;
536  }
537  if (NULL == con_handle->response)
538  {
539  // Suspend connection until plugin is done
540  MHD_suspend_connection (con_handle->con);
541  return MHD_YES;
542  }
543  //MHD_resume_connection (con_handle->con);
545  "Queueing response from plugin with MHD\n");
546  // Handle Preflights for extensions
547  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Checking origin\n");
548  GNUNET_CRYPTO_hash ("origin", strlen ("origin"), &key);
549  origin = GNUNET_CONTAINER_multihashmap_get (con_handle->data_handle
551  &key);
552  if (NULL != origin)
553  {
554  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Origin: %s\n", origin);
555  // Only echo for browser plugins
556  if (GNUNET_YES == echo_origin)
557  {
558  if ((0 ==
559  strncmp ("moz-extension://", origin, strlen ("moz-extension://"))) ||
560  (0 == strncmp ("chrome-extension://",
561  origin,
562  strlen ("chrome-extension://"))))
563  {
564  MHD_add_response_header (con_handle->response,
565  MHD_HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN,
566  origin);
567  }
568  }
569  if (NULL != allow_origins)
570  {
571  char *tmp = GNUNET_strdup (allow_origins);
572  char *allow_origin = strtok (tmp, ",");
573  while (NULL != allow_origin)
574  {
575  if (0 == strncmp (allow_origin, origin, strlen (allow_origin)))
576  {
577  MHD_add_response_header (con_handle->response,
578  MHD_HTTP_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN,
579  allow_origin);
580  break;
581  }
582  allow_origin = strtok (NULL, ",");
583  }
584  GNUNET_free (tmp);
585  }
586  }
587  if (NULL != allow_credentials)
588  {
589  MHD_add_response_header (con_handle->response,
590  "Access-Control-Allow-Credentials",
592  }
593  if (NULL != allow_headers)
594  {
595  MHD_add_response_header (con_handle->response,
596  "Access-Control-Allow-Headers",
597  allow_headers);
598  }
599  run_mhd_now ();
600  {
601  MHD_RESULT ret = MHD_queue_response (con,
602  con_handle->status,
603  con_handle->response);
604  //cleanup_handle (con_handle);
605  return ret;
606  }
607 }
608 
609 
610 /* ******************** MHD HTTP setup and event loop ******************** */
611 
612 
616 static void
618 {
619  if (NULL != httpd)
620  {
621  MHD_stop_daemon (httpd);
622  httpd = NULL;
623  }
624  if (NULL != httpd_task)
625  {
626  GNUNET_SCHEDULER_cancel (httpd_task);
627  httpd_task = NULL;
628  }
629  if (NULL != ltask4)
630  {
631  GNUNET_SCHEDULER_cancel (ltask4);
632  ltask4 = NULL;
633  }
634  if (NULL != ltask6)
635  {
636  GNUNET_SCHEDULER_cancel (ltask6);
637  ltask6 = NULL;
638  }
639 
640  if (NULL != lsock4)
641  {
643  lsock4 = NULL;
644  }
645  if (NULL != lsock6)
646  {
648  lsock6 = NULL;
649  }
650 }
651 
652 
660 static void
662 {
663  fd_set rs;
664  fd_set ws;
665  fd_set es;
666  struct GNUNET_NETWORK_FDSet *wrs;
667  struct GNUNET_NETWORK_FDSet *wws;
668  int max;
669  int haveto;
670  MHD_UNSIGNED_LONG_LONG timeout;
671  struct GNUNET_TIME_Relative tv;
672 
673  FD_ZERO (&rs);
674  FD_ZERO (&ws);
675  FD_ZERO (&es);
676  max = -1;
677  if (MHD_YES != MHD_get_fdset (httpd, &rs, &ws, &es, &max))
678  {
679  kill_httpd ();
680  return;
681  }
682  haveto = MHD_get_timeout (httpd, &timeout);
683  if (MHD_YES == haveto)
684  tv.rel_value_us = (uint64_t) timeout * 1000LL;
685  else
687  if (-1 != max)
688  {
691  GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1);
692  GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1);
693  }
694  else
695  {
696  wrs = NULL;
697  wws = NULL;
698  }
699  if (NULL != httpd_task)
700  {
701  GNUNET_SCHEDULER_cancel (httpd_task);
702  httpd_task = NULL;
703  }
704  if ((MHD_YES == haveto) || (-1 != max))
705  {
707  tv,
708  wrs,
709  wws,
710  &do_httpd,
711  NULL);
712  }
713  if (NULL != wrs)
715  if (NULL != wws)
717 }
718 
732 static void *
733 mhd_log_callback (void *cls,
734  const char *url,
735  struct MHD_Connection *connection)
736 {
737  struct AcceptedRequest *ar;
738  const union MHD_ConnectionInfo *ci;
739 
740  ci = MHD_get_connection_info (connection,
741  MHD_CONNECTION_INFO_SOCKET_CONTEXT);
742  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Processing %s\n", url);
743  if (NULL == ci)
744  {
745  GNUNET_break (0);
746  return NULL;
747  }
748  ar = ci->socket_context;
749  return ar;
750 }
751 
752 
753 
763 static void
764 mhd_completed_cb (void *cls,
765  struct MHD_Connection *connection,
766  void **con_cls,
767  enum MHD_RequestTerminationCode toe)
768 {
769  struct AcceptedRequest *ar = *con_cls;
770  if (MHD_REQUEST_TERMINATED_COMPLETED_OK != toe)
772  "MHD encountered error handling request: %d\n",
773  toe);
774  if (NULL == ar)
775  return;
776  if (NULL != ar->con_handle)
777  {
779  ar->con_handle = NULL;
780  }
782  *con_cls = NULL;
783 }
784 
794 static void
795 mhd_connection_cb (void *cls,
796  struct MHD_Connection *connection,
797  void **con_cls,
798  enum MHD_ConnectionNotificationCode cnc)
799 {
800  struct AcceptedRequest *ar;
801  const union MHD_ConnectionInfo *ci;
802  int sock;
803 
804  switch (cnc)
805  {
806  case MHD_CONNECTION_NOTIFY_STARTED:
807  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Connection started...\n");
808  ci = MHD_get_connection_info (connection,
809  MHD_CONNECTION_INFO_CONNECTION_FD);
810  if (NULL == ci)
811  {
812  GNUNET_break (0);
813  return;
814  }
815  sock = ci->connect_fd;
816  for (ar = req_list_head; NULL != ar; ar = ar->next)
817  {
818  if (GNUNET_NETWORK_get_fd (ar->sock) == sock)
819  {
821  "Context set...\n");
822  *con_cls = ar;
823  break;
824  }
825  }
826  break;
827 
828  case MHD_CONNECTION_NOTIFY_CLOSED:
830  "Connection closed... cleaning up\n");
831  ar = *con_cls;
832  if (NULL == ar)
833  {
835  "Connection stale!\n");
836  return;
837  }
838  cleanup_ar (ar);
839  *con_cls = NULL;
840  break;
841 
842  default:
843  GNUNET_break (0);
844  }
845 }
846 
847 
848 
854 static void
855 do_httpd (void *cls)
856 {
857  httpd_task = NULL;
858  MHD_run (httpd);
859  schedule_httpd ();
860 }
861 
862 
869 static void
870 do_accept (void *cls)
871 {
872  struct GNUNET_NETWORK_Handle *lsock = cls;
873  struct AcceptedRequest *ar;
874  int fd;
875  const struct sockaddr *addr;
876  socklen_t len;
877 
878  GNUNET_assert (NULL != lsock);
879  if (lsock == lsock4)
880  {
882  lsock,
883  &do_accept,
884  lsock);
885  }
886  else if (lsock == lsock6)
887  {
889  lsock,
890  &do_accept,
891  lsock);
892  }
893  else
894  GNUNET_assert (0);
895  ar = GNUNET_new (struct AcceptedRequest);
897  ar->sock = GNUNET_NETWORK_socket_accept (lsock, NULL, NULL);
898  if (NULL == ar->sock)
899  {
900  GNUNET_free (ar);
902  return;
903  }
905  "Got an inbound connection, waiting for data\n");
906  fd = GNUNET_NETWORK_get_fd (ar->sock);
907  addr = GNUNET_NETWORK_get_addr (ar->sock);
908  len = GNUNET_NETWORK_get_addrlen (ar->sock);
909  GNUNET_CONTAINER_DLL_insert (req_list_head,
910  req_list_tail,
911  ar);
912  if (MHD_YES != MHD_add_connection (httpd, fd, addr, len))
913  {
915  GNUNET_free (ar);
917  _ ("Failed to pass client to MHD\n"));
918  return;
919  }
920  schedule_httpd ();
921 }
922 
923 
929 static void
930 do_shutdown (void *cls)
931 {
932  struct PluginListEntry *ple;
933 
934  while (NULL != plugins_head)
935  {
936  ple = plugins_head;
937  GNUNET_CONTAINER_DLL_remove (plugins_head,
938  plugins_tail,
939  ple);
940  GNUNET_PLUGIN_unload (ple->libname, ple->plugin);
941  GNUNET_free (ple->libname);
942  GNUNET_free (ple);
943  }
944  GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Shutting down...\n");
945  kill_httpd ();
948 }
949 
950 
956 static struct GNUNET_NETWORK_Handle *
958 {
959  struct GNUNET_NETWORK_Handle *ls;
960  struct sockaddr_in sa4;
961  int eno;
962 
963  memset (&sa4, 0, sizeof(sa4));
964  sa4.sin_family = AF_INET;
965  sa4.sin_port = htons (port);
966  sa4.sin_addr.s_addr = address;
967 #if HAVE_SOCKADDR_IN_SIN_LEN
968  sa4.sin_len = sizeof(sa4);
969 #endif
970  ls = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0);
971  if (NULL == ls)
972  return NULL;
974  (const struct sockaddr *) &sa4,
975  sizeof(sa4)))
976  {
977  eno = errno;
979  errno = eno;
980  return NULL;
981  }
982  return ls;
983 }
984 
985 
991 static struct GNUNET_NETWORK_Handle *
993 {
994  struct GNUNET_NETWORK_Handle *ls;
995  struct sockaddr_in6 sa6;
996  int eno;
997 
998  memset (&sa6, 0, sizeof(sa6));
999  sa6.sin6_family = AF_INET6;
1000  sa6.sin6_port = htons (port);
1001  sa6.sin6_addr = address6;
1002 #if HAVE_SOCKADDR_IN_SIN_LEN
1003  sa6.sin6_len = sizeof(sa6);
1004 #endif
1005  ls = GNUNET_NETWORK_socket_create (AF_INET6, SOCK_STREAM, 0);
1006  if (NULL == ls)
1007  return NULL;
1009  (const struct sockaddr *) &sa6,
1010  sizeof(sa6)))
1011  {
1012  eno = errno;
1014  errno = eno;
1015  return NULL;
1016  }
1017  return ls;
1018 }
1019 
1020 
1028 static void
1029 load_plugin (void *cls, const char *libname, void *lib_ret)
1030 {
1031  struct GNUNET_REST_Plugin *plugin = lib_ret;
1032  struct PluginListEntry *ple;
1033 
1034  if (NULL == lib_ret)
1035  {
1037  "Could not load plugin `%s'\n",
1038  libname);
1039  return;
1040  }
1041  GNUNET_assert (1 < strlen (plugin->name));
1042  GNUNET_assert ('/' == *plugin->name);
1043  ple = GNUNET_new (struct PluginListEntry);
1044  ple->libname = GNUNET_strdup (libname);
1045  ple->plugin = plugin;
1046  GNUNET_CONTAINER_DLL_insert (plugins_head,
1047  plugins_tail,
1048  ple);
1049  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Loaded plugin `%s'\n", libname);
1050 }
1051 
1052 
1061 static void
1062 run (void *cls,
1063  char *const *args,
1064  const char *cfgfile,
1065  const struct GNUNET_CONFIGURATION_Handle *c)
1066 {
1067  char *addr_str;
1068 
1069  cfg = c;
1070  plugins_head = NULL;
1071  plugins_tail = NULL;
1072  /* Get port to bind to */
1073  if (GNUNET_OK !=
1074  GNUNET_CONFIGURATION_get_value_number (cfg, "rest", "HTTP_PORT", &port))
1075  {
1076  // No address specified
1077  GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Using default port...\n");
1079  }
1080 
1081  /* Get address to bind to */
1082  if (GNUNET_OK !=
1083  GNUNET_CONFIGURATION_get_value_string (cfg, "rest", "BIND_TO", &addr_str))
1084  {
1085  // No address specified
1086  GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Don't know what to bind to...\n");
1088  return;
1089  }
1090  if (1 != inet_pton (AF_INET, addr_str, &address))
1091  {
1093  "Unable to parse address %s\n",
1094  addr_str);
1095  GNUNET_free (addr_str);
1097  return;
1098  }
1099  GNUNET_free (addr_str);
1100  /* Get address to bind to */
1102  "rest",
1103  "BIND_TO6",
1104  &addr_str))
1105  {
1106  // No address specified
1107  GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Don't know what to bind6 to...\n");
1109  return;
1110  }
1111  if (1 != inet_pton (AF_INET6, addr_str, &address6))
1112  {
1114  "Unable to parse IPv6 address %s\n",
1115  addr_str);
1116  GNUNET_free (addr_str);
1118  return;
1119  }
1120  GNUNET_free (addr_str);
1121 
1122 
1123  /* Get CORS data from cfg */
1124  echo_origin =
1126  "rest",
1127  "REST_ECHO_ORIGIN_WEBEXT");
1128  allow_origins = NULL;
1130  "rest",
1131  "REST_ALLOW_ORIGIN",
1132  &allow_origins))
1133  {
1135  "No CORS Access-Control-Allow-Origin header will be sent...\n");
1136  }
1137  if (GNUNET_OK !=
1139  "rest",
1140  "REST_ALLOW_CREDENTIALS",
1142  {
1143  // No origin specified
1145  "No CORS Credential Header will be sent...\n");
1146  }
1147 
1149  "rest",
1150  "REST_ALLOW_HEADERS",
1151  &allow_headers))
1152  {
1153  // No origin specified
1155  "No CORS Access-Control-Allow-Headers Header will be sent...\n");
1156  }
1157 
1158  /* Open listen socket proxy */
1159  lsock6 = bind_v6 ();
1160  if (NULL == lsock6)
1161  {
1163  }
1164  else
1165  {
1166  if (GNUNET_OK != GNUNET_NETWORK_socket_listen (lsock6, 5))
1167  {
1169  GNUNET_NETWORK_socket_close (lsock6);
1170  lsock6 = NULL;
1171  }
1172  else
1173  {
1175  lsock6,
1176  &do_accept,
1177  lsock6);
1178  }
1179  }
1180  lsock4 = bind_v4 ();
1181  if (NULL == lsock4)
1182  {
1184  }
1185  else
1186  {
1187  if (GNUNET_OK != GNUNET_NETWORK_socket_listen (lsock4, 5))
1188  {
1190  GNUNET_NETWORK_socket_close (lsock4);
1191  lsock4 = NULL;
1192  }
1193  else
1194  {
1196  lsock4,
1197  &do_accept,
1198  lsock4);
1199  }
1200  }
1201  if ((NULL == lsock4) && (NULL == lsock6))
1202  {
1204  return;
1205  }
1206  GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Service listens on port %llu\n", port);
1207  httpd = MHD_start_daemon (MHD_USE_DEBUG | MHD_USE_NO_LISTEN_SOCKET
1208  | MHD_ALLOW_SUSPEND_RESUME,
1209  0,
1210  NULL,
1211  NULL,
1212  &create_response,
1213  NULL,
1214  MHD_OPTION_CONNECTION_TIMEOUT,
1215  (unsigned int) 16,
1216  MHD_OPTION_NOTIFY_CONNECTION,
1218  NULL,
1219  MHD_OPTION_URI_LOG_CALLBACK,
1221  NULL,
1222  MHD_OPTION_NOTIFY_COMPLETED,
1224  NULL,
1225  MHD_OPTION_END);
1226  if (NULL == httpd)
1227  {
1229  return;
1230  }
1231  /* Load plugins */
1232  GNUNET_PLUGIN_load_all ("libgnunet_plugin_rest",
1233  (void *) cfg,
1234  &load_plugin,
1235  NULL);
1237 }
1238 
1239 
1249 int
1250 main (int argc, char *const *argv)
1251 {
1252  struct GNUNET_GETOPT_CommandLineOption options[] =
1254  static const char *err_page = "{}";
1255  int ret;
1256 
1257  if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
1258  return 2;
1259  GNUNET_log_setup ("gnunet-rest-server", "WARNING", NULL);
1260  failure_response = MHD_create_response_from_buffer (strlen (err_page),
1261  (void *) err_page,
1262  MHD_RESPMEM_PERSISTENT);
1263  ret = (GNUNET_OK == GNUNET_PROGRAM_run (argc,
1264  argv,
1265  "gnunet-rest-server",
1266  _ ("GNUnet REST server"),
1267  options,
1268  &run,
1269  NULL))
1270  ? 0
1271  : 1;
1272  MHD_destroy_response (failure_response);
1273  GNUNET_free_nz ((char *) argv);
1274  return ret;
1275 }
1276 
1277 
1278 /* end of gnunet-rest-server.c */
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
int GNUNET_NETWORK_socket_listen(const struct GNUNET_NETWORK_Handle *desc, int backlog)
Listen on a socket.
Definition: network.c:708
static struct PluginListEntry * plugins_tail
Plugin list tail.
static char * allow_headers
Allowed Headers (CORS)
int GNUNET_NETWORK_get_fd(const struct GNUNET_NETWORK_Handle *desc)
Return file descriptor for this network handle.
Definition: network.c:1080
Accepted requests.
struct sockaddr * GNUNET_NETWORK_get_addr(const struct GNUNET_NETWORK_Handle *desc)
Return the sockaddr for this network handle.
Definition: network.c:1093
static struct MHD_Response * failure_response
Response we return on failures.
static unsigned long long port
The port the service is running on (default 7776)
int GNUNET_CONFIGURATION_get_value_number(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, unsigned long long *number)
Get a configuration value that should be a number.
uint64_t rel_value_us
The actual value.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
static void load_plugin(void *cls, const char *libname, void *lib_ret)
Callback for plugin load.
static struct GNUNET_SCHEDULER_Task * httpd_task
The task ID.
struct PluginListEntry * next
#define GNUNET_REST_SERVICE_PORT
Default Socks5 listen port.
socklen_t GNUNET_NETWORK_get_addrlen(const struct GNUNET_NETWORK_Handle *desc)
Return sockaddr length for this network handle.
Definition: network.c:1106
size_t data_size
The POST data size.
MHD Connection handle.
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_shutdown(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run on shutdown, that is when a CTRL-C signal is received, or when GNUNET_SCHEDULER_shutdown() is being invoked.
Definition: scheduler.c:1331
int GNUNET_STRINGS_get_utf8_args(int argc, char *const *argv, int *u8argc, char *const **u8argv)
Returns utf-8 encoded arguments.
Definition: strings.c:1459
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
static void do_accept(void *cls)
Accept new incoming connections.
static struct in6_addr address6
The IPv6 address to bind to.
static void kill_httpd()
Kill the MHD daemon.
struct GNUNET_REST_RequestHandle * data_handle
int GNUNET_NETWORK_socket_bind(struct GNUNET_NETWORK_Handle *desc, const struct sockaddr *address, socklen_t address_len)
Bind a socket to a particular address.
Definition: network.c:485
struct returned by the initialization function of the plugin
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
#define GNUNET_new(type)
Allocate a struct or union of the given type.
Definition of a command line option.
struct AcceptedRequest * prev
DLL.
void GNUNET_SCHEDULER_shutdown(void)
Request the shutdown of a scheduler.
Definition: scheduler.c:531
int socket_with_mhd
State.
static void cleanup_handle(struct MhdConnectionHandle *handle)
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
struct PluginListEntry * prev
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_OPTION_END
Definition: 002.c:13
void GNUNET_NETWORK_fdset_copy_native(struct GNUNET_NETWORK_FDSet *to, const fd_set *from, int nfds)
Copy a native fd set into the GNUnet representation.
Definition: network.c:1120
static int url_iterator(void *cls, enum MHD_ValueKind kind, const char *key, const char *value)
void * GNUNET_CONTAINER_multihashmap_get(const struct GNUNET_CONTAINER_MultiHashMap *map, const struct GNUNET_HashCode *key)
Given a key find a value in the map matching the key.
#define _(String)
GNU gettext support macro.
Definition: platform.h:184
void * GNUNET_PLUGIN_unload(const char *library_name, void *arg)
Unload plugin (runs the "done" callback and returns whatever "done" returned).
Definition: plugin.c:256
void GNUNET_NETWORK_socket_free_memory_only_(struct GNUNET_NETWORK_Handle *desc)
Only free memory of a socket, keep the file descriptor untouched.
Definition: network.c:622
struct GNUNET_NETWORK_Handle * GNUNET_NETWORK_socket_accept(const struct GNUNET_NETWORK_Handle *desc, struct sockaddr *address, socklen_t *address_len)
Accept a new connection on a socket.
Definition: network.c:430
static void mhd_completed_cb(void *cls, struct MHD_Connection *connection, void **con_cls, enum MHD_RequestTerminationCode toe)
Function called when MHD decides that we are done with a connection.
void GNUNET_NETWORK_fdset_destroy(struct GNUNET_NETWORK_FDSet *fds)
Releases the associated memory of an fd set.
Definition: network.c:1266
#define GNUNET_log_strerror(level, cmd)
Log an error message at log-level &#39;level&#39; that indicates a failure of the command &#39;cmd&#39; with the mess...
static MHD_RESULT create_response(void *cls, struct MHD_Connection *con, const char *url, const char *meth, const char *ver, const char *upload_data, size_t *upload_data_size, void **con_cls)
Main MHD callback for handling requests.
struct GNUNET_NETWORK_FDSet * GNUNET_NETWORK_fdset_create(void)
Creates an fd set.
Definition: network.c:1250
static int echo_origin
Echo request Origin in CORS.
static struct GNUNET_TIME_Relative timeout
Desired timeout for the lookup (default is no timeout).
Definition: gnunet-abd.c:61
static struct PluginListEntry * plugins_head
Plugin list head.
static char * value
Value of the record to add/remove.
#define GN_REST_STATE_INIT
struct GNUNET_CONTAINER_MultiHashMap * url_param_map
Map of url parameters.
static struct GNUNET_NETWORK_Handle * lsock4
The listen socket of the service for IPv4.
void GNUNET_CRYPTO_hash(const void *block, size_t size, struct GNUNET_HashCode *ret)
Compute hash of a given block.
Definition: crypto_hash.c:48
const char * url
The url as string.
void GNUNET_CONTAINER_multihashmap_destroy(struct GNUNET_CONTAINER_MultiHashMap *map)
Destroy a hash map.
static struct GNUNET_SCHEDULER_Task * ltask6
The listen task ID for IPv6.
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_now(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run as soon as possible.
Definition: scheduler.c:1296
char * name
Plugin name.
struct MhdConnectionHandle * con_handle
Connection.
static char * allow_origins
Allowed Origins (CORS)
char * libname
libname (to cleanup)
collection of IO descriptors
uint16_t status
See PRISM_STATUS_*-constants.
const char * method
The HTTP method as MHD value (see microhttpd.h)
static char * filename
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_select(enum GNUNET_SCHEDULER_Priority prio, struct GNUNET_TIME_Relative delay, const struct GNUNET_NETWORK_FDSet *rs, const struct GNUNET_NETWORK_FDSet *ws, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay or when any of the specified file descriptor set...
Definition: scheduler.c:1841
static int header_iterator(void *cls, enum MHD_ValueKind kind, const char *key, const char *value)
static struct GNUNET_DNS_Handle * handle
Handle to transport service.
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
static void do_shutdown(void *cls)
Task run on shutdown.
static in_addr_t address
The address to bind to.
A plugin list entry.
A 512-bit hashcode.
static struct GNUNET_NETWORK_Handle * lsock6
The listen socket of the service for IPv6.
int int GNUNET_asprintf(char **buf, const char *format,...) __attribute__((format(printf
Like asprintf, just portable.
int GNUNET_CONFIGURATION_get_value_string(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, char **value)
Get a configuration value that should be a string.
#define GN_REST_STATE_PROCESSING
const char * data
The POST data.
struct GNUNET_REST_Plugin * plugin
The plugin.
#define GNUNET_free_nz(ptr)
Wrapper around free.
static void cleanup_ar(struct AcceptedRequest *ar)
There must only be one value per key; storing a value should fail if a value under the same key alrea...
struct GNUNET_HashCode key
The key used in the DHT.
static unsigned int size
Size of the "table".
Definition: peer.c:67
static struct GNUNET_SCHEDULER_Task * ltask4
The listen task ID for IPv4.
void GNUNET_PLUGIN_load_all(const char *basename, void *arg, GNUNET_PLUGIN_LoaderCallback cb, void *cb_cls)
Load all compatible plugins with the given base name.
Definition: plugin.c:372
struct AcceptedRequest * next
DLL.
static char * allow_credentials
Allowed Credentials (CORS)
struct MHD_Connection * con
int GNUNET_CONTAINER_multihashmap_put(struct GNUNET_CONTAINER_MultiHashMap *map, const struct GNUNET_HashCode *key, void *value, enum GNUNET_CONTAINER_MultiHashMapOption opt)
Store a key-value pair in the map.
#define MHD_RESULT
Data type to use for functions return an "MHD result".
static struct GNUNET_NETWORK_Handle * ls
Listen socket for STUN processing.
Definition: gnunet-nat.c:85
struct MHD_PostProcessor * pp
static int cleanup_url_map(void *cls, const struct GNUNET_HashCode *key, void *value)
static struct GNUNET_NETWORK_Handle * bind_v6()
Create an IPv6 listen socket bound to our port.
configuration data
Definition: configuration.c:84
static void do_httpd(void *cls)
Task run whenever HTTP server operations are pending.
static void * mhd_log_callback(void *cls, const char *url, struct MHD_Connection *connection)
Function called when MHD first processes an incoming connection.
static void schedule_httpd()
Schedule MHD.
static struct AcceptedRequest * req_list_head
AcceptedRequest list head.
#define GNUNET_log(kind,...)
Entry in list of pending tasks.
Definition: scheduler.c:134
static struct MHD_Daemon * httpd
Daemon for HTTP.
struct GNUNET_NETWORK_Handle * sock
Socket.
handle to a socket
Definition: network.c:52
struct GNUNET_CONTAINER_MultiHashMap * GNUNET_CONTAINER_multihashmap_create(unsigned int len, int do_not_copy_keys)
Create a multi hash map.
int GNUNET_PROGRAM_run(int argc, char *const *argv, const char *binaryName, const char *binaryHelp, const struct GNUNET_GETOPT_CommandLineOption *options, GNUNET_PROGRAM_Main task, void *task_cls)
Run a standard GNUnet command startup sequence (initialize loggers and configuration, parse options).
Definition: program.c:372
struct GNUNET_CONTAINER_MultiHashMap * header_param_map
Map of headers.
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_read_net(struct GNUNET_TIME_Relative delay, struct GNUNET_NETWORK_Handle *rfd, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay or when the specified file descriptor is ready f...
Definition: scheduler.c:1517
static struct AcceptedRequest * req_list_tail
AcceptedRequest list tail.
Run with the default priority (normal P2P operations).
int GNUNET_log_setup(const char *comp, const char *loglevel, const char *logfile)
Setup logging.
int GNUNET_CONFIGURATION_get_value_yesno(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option)
Get a configuration value that should be in a set of "YES" or "NO".
enum GNUNET_GenericReturnValue(* process_request)(struct GNUNET_REST_RequestHandle *handle, GNUNET_REST_ResultProcessor proc, void *proc_cls)
Function to process a REST call.
int GNUNET_CONTAINER_multihashmap_iterate(struct GNUNET_CONTAINER_MultiHashMap *map, GNUNET_CONTAINER_MulitHashMapIteratorCallback it, void *it_cls)
Iterate over all entries in the map.
static void plugin_callback(void *cls, struct MHD_Response *resp, int status)
Plugin result callback.
uint32_t data
The data value.
struct MHD_Response * response
static const struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
static void run_mhd_now()
Run MHD now, we have extra data ready for the callback.
int GNUNET_NETWORK_socket_close(struct GNUNET_NETWORK_Handle *desc)
Close a socket.
Definition: network.c:560
static void mhd_connection_cb(void *cls, struct MHD_Connection *connection, void **con_cls, enum MHD_ConnectionNotificationCode cnc)
Function called when MHD connection is opened or closed.
#define GNUNET_malloc(size)
Wrapper around malloc.
static void run(void *cls, char *const *args, const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c)
Main function that will be run.
#define GNUNET_free(ptr)
Wrapper around free.
Time for relative time used by GNUnet, in microseconds.
int main(int argc, char *const *argv)
The main function for gnunet-rest-service.
uint16_t len
length of data (which is always a uint32_t, but presumably this can be used to specify that fewer byt...
void GNUNET_STRINGS_utf8_tolower(const char *input, char *output)
Convert the utf-8 input string to lower case.
Definition: strings.c:568
struct GNUNET_NETWORK_Handle * GNUNET_NETWORK_socket_create(int domain, int type, int protocol)
Create a new socket.
Definition: network.c:912
static struct GNUNET_NETWORK_Handle * bind_v4()
Create an IPv4 listen socket bound to our port.
static MHD_RESULT post_data_iter(void *cls, enum MHD_ValueKind kind, const char *key, const char *filename, const char *content_type, const char *transfer_encoding, const char *data, uint64_t off, size_t size)
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:972