GNUnet  0.19.4
plugin_transport_http_server.c
Go to the documentation of this file.
1 /*
2  This file is part of GNUnet
3  Copyright (C) 2002-2014, 2017 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  */
20 
28 #include "platform.h"
29 #include "gnunet_util_lib.h"
32 #include "gnunet_nat_service.h"
34 #include <microhttpd.h>
35 #include <regex.h>
36 #include "gnunet_mhd_compat.h"
37 
38 #if BUILD_HTTPS
39 #define PLUGIN_NAME "https_server"
40 #define LIBGNUNET_PLUGIN_TRANSPORT_INIT \
41  libgnunet_plugin_transport_https_server_init
42 #define LIBGNUNET_PLUGIN_TRANSPORT_DONE \
43  libgnunet_plugin_transport_https_server_done
44 #else
45 #define PLUGIN_NAME "http_server"
46 #define LIBGNUNET_PLUGIN_TRANSPORT_INIT \
47  libgnunet_plugin_transport_http_server_init
48 #define LIBGNUNET_PLUGIN_TRANSPORT_DONE \
49  libgnunet_plugin_transport_http_server_done
50 #endif
51 
52 #define HTTP_ERROR_RESPONSE \
53  "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\"><HTML><HEAD><TITLE>404 Not Found</TITLE></HEAD><BODY><H1>Not Found</H1>The requested URL was not found on this server.<P><HR><ADDRESS></ADDRESS></BODY></HTML>"
54 #define _RECEIVE 0
55 #define _SEND 1
56 
57 
58 #define LOG(kind, ...) GNUNET_log_from (kind, "transport-" PLUGIN_NAME, \
59  __VA_ARGS__)
60 
61 
65 struct ServerRequest
66 {
72 
76  struct MHD_Connection *mhd_conn;
77 
81  struct MHD_Daemon *mhd_daemon;
82 
86  uint32_t options;
87 #define OPTION_LONG_POLL 1 /* GET request wants long-poll semantics */
88 
92  int direction;
93 
98  int connected;
99 
103  bool suspended;
104 };
105 
106 
111 {
116 
121 
126 
130  size_t addrlen;
131 };
132 
133 
137 struct HTTP_Message
138 {
142  struct HTTP_Message *next;
143 
147  struct HTTP_Message *prev;
148 
152  char *buf;
153 
157  size_t pos;
158 
162  size_t size;
163 
167  size_t overhead;
168 
175 
179  void *transmit_cont_cls;
180 };
181 
182 
186 struct GNUNET_ATS_Session
187 {
193 
198 
202  struct HTTP_Message *msg_head;
203 
207  struct HTTP_Message *msg_tail;
208 
213 
217  struct ServerRequest *server_recv;
218 
222  struct ServerRequest *server_send;
223 
228 
234 
239 
244 
249 
253  unsigned long long bytes_in_queue;
254 
258  unsigned int msgs_in_queue;
259 
263  uint32_t tag;
264 
269 
274 };
275 
276 
281 {
286 
291 
296 
300  void *sic_cls;
301 
305  char *name;
306 
310  char *protocol;
311 
316 
322 
327 
332 
337 
341  struct sockaddr_in *server_addr_v4;
342 
346  struct sockaddr_in6 *server_addr_v6;
347 
351  struct MHD_Daemon *server_v4;
352 
356  struct MHD_Daemon *server_v6;
357 
358 #if BUILD_HTTPS
368  char *crypto_init;
369 
373  char *key;
374 
378  char *cert;
379 #endif
380 
385 
390 
395 
399  unsigned int external_only;
400 
405 
410 
415 
420  unsigned int max_request;
421 
426  unsigned int cur_request;
427 
432 
437 
441  uint32_t options;
442 
446  uint16_t use_ipv6;
447 
451  uint16_t use_ipv4;
452 
456  uint16_t port;
457 
461  regex_t url_regex;
462 };
463 
464 
473 static void
475  struct GNUNET_ATS_Session *session,
477 {
479 
480  if (NULL == plugin->sic)
481  return;
482  memset (&info, 0, sizeof(info));
483  info.state = state;
484  info.is_inbound = GNUNET_YES;
485  info.num_msg_pending = session->msgs_in_queue;
486  info.num_bytes_pending = session->bytes_in_queue;
487  info.receive_delay = session->next_receive;
488  info.session_timeout = session->timeout;
489  info.address = session->address;
490  plugin->sic (plugin->sic_cls,
491  session,
492  &info);
493 }
494 
495 
501 static void
502 server_wake_up (void *cls)
503 {
504  struct GNUNET_ATS_Session *s = cls;
505 
506  s->recv_wakeup_task = NULL;
508  "Session %p: Waking up PUT handle\n",
509  s);
511  MHD_resume_connection (s->server_recv->mhd_conn);
512  s->server_recv->suspended = false;
513 }
514 
515 
524 static void
526  struct MHD_Daemon *server,
527  int now);
528 
529 
535 static void
537 {
538  struct HTTP_Server_Plugin *plugin = s->plugin;
539  struct HTTP_Message *msg;
540 
541  if (NULL != s->timeout_task)
542  {
544  s->timeout_task = NULL;
546  }
547  if (NULL != s->recv_wakeup_task)
548  {
550  s->recv_wakeup_task = NULL;
551  if (NULL != s->server_recv)
552  {
554  s->server_recv->suspended = false;
555  MHD_resume_connection (s->server_recv->mhd_conn);
556  }
557  }
560  &s->target,
561  s));
562  while (NULL != (msg = s->msg_head))
563  {
565  s->msg_tail,
566  msg);
567  if (NULL != msg->transmit_cont)
568  msg->transmit_cont (msg->transmit_cont_cls,
569  &s->target,
571  msg->size,
572  msg->pos + msg->overhead);
573  GNUNET_assert (s->msgs_in_queue > 0);
574  s->msgs_in_queue--;
576  s->bytes_in_queue -= msg->size;
577  GNUNET_free (msg);
578  }
579 
580  GNUNET_assert (0 == s->msgs_in_queue);
581  GNUNET_assert (0 == s->bytes_in_queue);
582 
583  if (NULL != s->server_send)
584  {
586  "Server: %p / %p Terminating inbound PUT session to peer `%s'\n",
587  s, s->server_send,
588  GNUNET_i2s (&s->target));
589  s->server_send->session = NULL;
590  MHD_set_connection_option (s->server_send->mhd_conn,
591  MHD_CONNECTION_OPTION_TIMEOUT,
592  1 /* 0 = no timeout, so this is MIN */);
593  if (s->server_send->suspended)
594  {
595  s->server_send->suspended = false;
596  MHD_resume_connection (s->server_send->mhd_conn);
597  }
600  GNUNET_YES);
601  }
602 
603  if (NULL != s->server_recv)
604  {
606  "Server: %p / %p Terminating inbound GET session to peer `%s'\n",
607  s, s->server_recv, GNUNET_i2s (&s->target));
608  s->server_recv->session = NULL;
609  MHD_set_connection_option (s->server_recv->mhd_conn,
610  MHD_CONNECTION_OPTION_TIMEOUT,
611  1 /* 0 = no timeout, so this is MIN */);
614  GNUNET_YES);
615  }
617  s,
619  if (GNUNET_YES == s->known_to_service)
620  {
621  plugin->env->session_end (plugin->env->cls,
622  s->address,
623  s);
625  }
626  if (NULL != s->msg_tk)
627  {
629  s->msg_tk = NULL;
630  }
633  "Session %p destroyed\n",
634  s);
635  GNUNET_free (s);
636 }
637 
638 
647 static int
649  struct GNUNET_ATS_Session *s)
650 {
652  return GNUNET_OK;
653 }
654 
655 
661 static void
663 {
664  struct GNUNET_ATS_Session *s = cls;
665  struct GNUNET_TIME_Relative left;
666 
667  s->timeout_task = NULL;
669  if (0 != left.rel_value_us)
670  {
671  /* not actually our turn yet, but let's at least update
672  the monitor, it may think we're about to die ... */
674  s,
678  s);
679  return;
680  }
682  "Session %p was idle for %s, disconnecting\n",
683  s,
686  GNUNET_YES));
688 }
689 
690 
696 static void
698 {
699  GNUNET_assert (NULL != s->timeout_task);
702 }
703 
704 
732 static ssize_t
734  struct GNUNET_ATS_Session *session,
735  const char *msgbuf,
736  size_t msgbuf_size,
737  unsigned int priority,
738  struct GNUNET_TIME_Relative to,
740  void *cont_cls)
741 {
742  struct HTTP_Server_Plugin *plugin = cls;
743  struct HTTP_Message *msg;
744  ssize_t bytes_sent = 0;
745  char *stat_txt;
746 
748  "Session %p/request %p: Sending message with %lu to peer `%s'\n",
749  session,
750  session->server_send,
751  (unsigned long) msgbuf_size,
752  GNUNET_i2s (&session->target));
753 
754  /* create new message and schedule */
755  bytes_sent = sizeof(struct HTTP_Message) + msgbuf_size;
756  msg = GNUNET_malloc (bytes_sent);
757  msg->next = NULL;
758  msg->size = msgbuf_size;
759  msg->pos = 0;
760  msg->buf = (char *) &msg[1];
761  msg->transmit_cont = cont;
762  msg->transmit_cont_cls = cont_cls;
763  GNUNET_memcpy (msg->buf,
764  msgbuf,
765  msgbuf_size);
767  session->msg_tail,
768  msg);
769  session->msgs_in_queue++;
770  session->bytes_in_queue += msg->size;
772  session,
774  GNUNET_asprintf (&stat_txt,
775  "# bytes currently in %s_server buffers",
776  plugin->protocol);
777  GNUNET_STATISTICS_update (plugin->env->stats,
778  stat_txt, msgbuf_size, GNUNET_NO);
779  GNUNET_free (stat_txt);
780 
781  if (NULL != session->server_send)
782  {
783  if (session->server_send->suspended)
784  {
785  MHD_resume_connection (session->server_send->mhd_conn);
786  session->server_send->suspended = false;
787  }
788  server_reschedule (session->plugin,
789  session->server_send->mhd_daemon,
790  GNUNET_YES);
791  }
792  return bytes_sent;
793 }
794 
795 
804 static int
806  const struct GNUNET_PeerIdentity *peer,
807  void *value)
808 {
809  struct GNUNET_ATS_Session *s = value;
810  struct ServerRequest *sc_send;
811  struct ServerRequest *sc_recv;
812 
813  sc_send = s->server_send;
814  sc_recv = s->server_recv;
816  if (NULL != sc_send)
817  sc_send->session = NULL;
818  if (NULL != sc_recv)
819  sc_recv->session = NULL;
820 
821  return GNUNET_OK;
822 }
823 
824 
833 static int
835  const struct GNUNET_PeerIdentity *peer,
836  void *value)
837 {
838  struct GNUNET_ATS_Session *s = value;
839 
841  return GNUNET_OK;
842 }
843 
844 
853 static void
855  const struct GNUNET_PeerIdentity *target)
856 {
857  struct HTTP_Server_Plugin *plugin = cls;
858 
860  "Transport tells me to disconnect `%s'\n",
861  GNUNET_i2s (target));
863  target,
865  plugin);
866 }
867 
868 
881 static int
883  const void *addr,
884  size_t addrlen)
885 {
886  struct HTTP_Server_Plugin *plugin = cls;
887  struct HttpAddressWrapper *next;
888  struct HttpAddressWrapper *pos;
889  const struct HttpAddress *haddr = addr;
890 
891  if ((NULL != plugin->ext_addr) &&
893  plugin->ext_addr->address,
894  plugin->ext_addr->
895  address_length))) )
896  {
897  /* Checking HTTP_OPTIONS_VERIFY_CERTIFICATE option for external hostname */
898  if ((ntohl (haddr->options) & HTTP_OPTIONS_VERIFY_CERTIFICATE) !=
900  return GNUNET_NO; /* VERIFY option not set as required! */
901  return GNUNET_OK;
902  }
903  next = plugin->addr_head;
904  while (NULL != (pos = next))
905  {
906  next = pos->next;
908  addrlen,
909  pos->address,
910  pos->addrlen)))
911  return GNUNET_OK;
912  }
913  return GNUNET_NO;
914 }
915 
916 
927 static struct GNUNET_ATS_Session *
929  const struct GNUNET_HELLO_Address *address)
930 {
931  return NULL;
932 }
933 
934 
941 static void
942 server_v4_run (void *cls)
943 {
944  struct HTTP_Server_Plugin *plugin = cls;
945 
946  plugin->server_v4_task = NULL;
947  plugin->server_v4_immediately = GNUNET_NO;
948  GNUNET_assert (MHD_YES == MHD_run (plugin->server_v4));
949  server_reschedule (plugin, plugin->server_v4, GNUNET_NO);
950 }
951 
952 
959 static void
960 server_v6_run (void *cls)
961 {
962  struct HTTP_Server_Plugin *plugin = cls;
963 
964  plugin->server_v6_task = NULL;
965  plugin->server_v6_immediately = GNUNET_NO;
966  GNUNET_assert (MHD_YES == MHD_run (plugin->server_v6));
967  server_reschedule (plugin, plugin->server_v6, GNUNET_NO);
968 }
969 
970 
980 static struct GNUNET_SCHEDULER_Task *
982  struct MHD_Daemon *daemon_handle,
983  int now)
984 {
985  struct GNUNET_SCHEDULER_Task *ret;
986  fd_set rs;
987  fd_set ws;
988  fd_set es;
989  struct GNUNET_NETWORK_FDSet *wrs;
990  struct GNUNET_NETWORK_FDSet *wws;
991  int max;
992  MHD_UNSIGNED_LONG_LONG timeout;
993  static unsigned long long last_timeout = 0;
994  int haveto;
995  struct GNUNET_TIME_Relative tv;
996 
997  if (GNUNET_YES == plugin->in_shutdown)
998  return NULL;
999 
1000  ret = NULL;
1001  FD_ZERO (&rs);
1002  FD_ZERO (&ws);
1003  FD_ZERO (&es);
1004  wrs = GNUNET_NETWORK_fdset_create ();
1005  wws = GNUNET_NETWORK_fdset_create ();
1006  max = -1;
1007  GNUNET_assert (MHD_YES ==
1008  MHD_get_fdset (daemon_handle,
1009  &rs,
1010  &ws,
1011  &es,
1012  &max));
1013  haveto = MHD_get_timeout (daemon_handle, &timeout);
1014  if (haveto == MHD_YES)
1015  {
1016  if (timeout != last_timeout)
1017  {
1019  "SELECT Timeout changed from %llu to %llu (ms)\n",
1020  last_timeout, timeout);
1021  last_timeout = timeout;
1022  }
1023  if (timeout <= GNUNET_TIME_UNIT_SECONDS.rel_value_us / 1000LL)
1024  tv.rel_value_us = (uint64_t) timeout * 1000LL;
1025  else
1027  }
1028  else
1030  /* Force immediate run, since we have outbound data to send */
1031  if (now == GNUNET_YES)
1033  GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1);
1034  GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1);
1035 
1036  if (daemon_handle == plugin->server_v4)
1037  {
1038  if (plugin->server_v4_task != NULL)
1039  {
1040  GNUNET_SCHEDULER_cancel (plugin->server_v4_task);
1041  plugin->server_v4_task = NULL;
1042  }
1043 #if 0
1045  "Scheduling IPv4 server task in %llu ms\n",
1046  tv);
1047 #endif
1048  ret =
1050  tv, wrs, wws,
1051  &server_v4_run, plugin);
1052  }
1053  if (daemon_handle == plugin->server_v6)
1054  {
1055  if (plugin->server_v6_task != NULL)
1056  {
1057  GNUNET_SCHEDULER_cancel (plugin->server_v6_task);
1058  plugin->server_v6_task = NULL;
1059  }
1060 #if 0
1062  "Scheduling IPv6 server task in %llu ms\n", tv);
1063 #endif
1064  ret =
1066  tv, wrs, wws,
1067  &server_v6_run, plugin);
1068  }
1071  return ret;
1072 }
1073 
1074 
1083 static void
1085  struct MHD_Daemon *server,
1086  int now)
1087 {
1088  if ((server == plugin->server_v4) && (plugin->server_v4 != NULL))
1089  {
1090  if (GNUNET_YES == plugin->server_v4_immediately)
1091  return; /* No rescheduling, server will run asap */
1092 
1093  if (GNUNET_YES == now)
1094  plugin->server_v4_immediately = GNUNET_YES;
1095 
1096  if (plugin->server_v4_task != NULL)
1097  {
1098  GNUNET_SCHEDULER_cancel (plugin->server_v4_task);
1099  plugin->server_v4_task = NULL;
1100  }
1101  plugin->server_v4_task = server_schedule (plugin, plugin->server_v4, now);
1102  }
1103 
1104  if ((server == plugin->server_v6) && (plugin->server_v6 != NULL))
1105  {
1106  if (GNUNET_YES == plugin->server_v6_immediately)
1107  return; /* No rescheduling, server will run asap */
1108 
1109  if (GNUNET_YES == now)
1110  plugin->server_v6_immediately = GNUNET_YES;
1111 
1112  if (plugin->server_v6_task != NULL)
1113  {
1114  GNUNET_SCHEDULER_cancel (plugin->server_v6_task);
1115  plugin->server_v6_task = NULL;
1116  }
1117  plugin->server_v6_task = server_schedule (plugin, plugin->server_v6, now);
1118  }
1119 }
1120 
1121 
1130 static unsigned int
1132 {
1133  return 3;
1134 }
1135 
1136 
1146 static void
1148  const struct
1150  struct GNUNET_ATS_Session *session)
1151 {
1153 }
1154 
1155 
1163 static void
1165  struct GNUNET_ATS_Session *s,
1166  unsigned int to)
1167 {
1168  /* Setting timeouts for other connections */
1169  if (NULL != s->server_recv)
1170  {
1172  "Setting timeout for %p to %u sec.\n",
1173  s->server_recv, to);
1174  MHD_set_connection_option (s->server_recv->mhd_conn,
1175  MHD_CONNECTION_OPTION_TIMEOUT,
1176  to);
1178  }
1179  if (NULL != s->server_send)
1180  {
1182  "Setting timeout for %p to %u sec.\n",
1183  s->server_send, to);
1184  MHD_set_connection_option (s->server_send->mhd_conn,
1185  MHD_CONNECTION_OPTION_TIMEOUT,
1186  to);
1188  }
1189 }
1190 
1191 
1202 static int
1204  const char *url,
1205  struct GNUNET_PeerIdentity *target,
1206  uint32_t *tag,
1207  uint32_t *options)
1208 {
1209  regmatch_t matches[4];
1210  const char *tag_start;
1211  const char *target_start;
1212  char *tag_end;
1213  char *options_end;
1214  size_t hash_length;
1215  unsigned long int rc;
1216 
1217  /* URL parsing */
1218 #define URL_REGEX \
1219  ("^.*/([0-9A-Z]+);([0-9]+)(,[0-9]+)?$")
1220 
1221  if (NULL == url)
1222  {
1223  GNUNET_break (0);
1224  return GNUNET_SYSERR;
1225  }
1226 
1227  if (regexec (&plugin->url_regex, url, 4, matches, 0))
1228  {
1230  "URL `%s' did not match regex\n", url);
1231  return GNUNET_SYSERR;
1232  }
1233 
1234  target_start = &url[matches[1].rm_so];
1235  tag_start = &url[matches[2].rm_so];
1236 
1237  /* convert tag */
1238  rc = strtoul (tag_start, &tag_end, 10);
1239  if (&url[matches[2].rm_eo] != tag_end)
1240  {
1242  "URL tag did not line up with submatch\n");
1243  return GNUNET_SYSERR;
1244  }
1245  if (rc == 0)
1246  {
1248  "URL tag is zero\n");
1249  return GNUNET_SYSERR;
1250  }
1251  if ((rc == ULONG_MAX) && (ERANGE == errno))
1252  {
1254  "URL tag > ULONG_MAX\n");
1255  return GNUNET_SYSERR;
1256  }
1257  if (rc > UINT32_MAX)
1258  {
1260  "URL tag > UINT32_MAX\n");
1261  return GNUNET_SYSERR;
1262  }
1263  (*tag) = (uint32_t) rc;
1265  "Found tag `%u' in url\n",
1266  *tag);
1267 
1268  /* convert peer id */
1269  hash_length = matches[1].rm_eo - matches[1].rm_so;
1270  if (hash_length != plugin->peer_id_length)
1271  {
1273  "URL target is %lu bytes, expecting %u\n",
1274  (unsigned long) hash_length, plugin->peer_id_length);
1275  return GNUNET_SYSERR;
1276  }
1277  if (GNUNET_OK !=
1279  hash_length,
1280  &target->public_key))
1281  {
1283  "URL target conversion failed\n");
1284  return GNUNET_SYSERR;
1285  }
1287  "Found target `%s' in URL\n",
1288  GNUNET_i2s_full (target));
1289 
1290  /* convert options */
1291  if (-1 == matches[3].rm_so)
1292  {
1293  *options = 0;
1294  }
1295  else
1296  {
1297  rc = strtoul (&url[matches[3].rm_so + 1], &options_end, 10);
1298  if (&url[matches[3].rm_eo] != options_end)
1299  {
1301  "URL options did not line up with submatch\n");
1302  return GNUNET_SYSERR;
1303  }
1304  if ((rc == ULONG_MAX) && (ERANGE == errno))
1305  {
1307  "URL options > ULONG_MAX\n");
1308  return GNUNET_SYSERR;
1309  }
1310  if (rc > UINT32_MAX)
1311  {
1313  "URL options > UINT32_MAX\n");
1314  return GNUNET_SYSERR;
1315  }
1316  (*options) = (uint32_t) rc;
1318  "Found options `%u' in url\n",
1319  *options);
1320  }
1321  return GNUNET_OK;
1322 }
1323 
1324 
1329 {
1334 
1338  uint32_t tag;
1339 };
1340 
1341 
1350 static int
1351 session_tag_it (void *cls,
1352  const struct GNUNET_PeerIdentity *key,
1353  void *value)
1354 {
1355  struct GNUNET_ATS_SessionTagContext *stc = cls;
1356  struct GNUNET_ATS_Session *s = value;
1357 
1358  if (s->tag == stc->tag)
1359  {
1360  stc->res = s;
1361  return GNUNET_NO;
1362  }
1363  return GNUNET_YES;
1364 }
1365 
1366 
1376 static struct ServerRequest *
1378  struct MHD_Connection *mhd_connection,
1379  const char *url,
1380  const char *method)
1381 {
1382  struct GNUNET_ATS_Session *s = NULL;
1383  struct ServerRequest *sc = NULL;
1384  const union MHD_ConnectionInfo *conn_info;
1385  struct HttpAddress *addr;
1386  struct GNUNET_PeerIdentity target;
1387  size_t addr_len;
1388  struct GNUNET_ATS_SessionTagContext stc;
1389  uint32_t options;
1390  int direction = GNUNET_SYSERR;
1391  unsigned int to;
1393 
1394  conn_info = MHD_get_connection_info (mhd_connection,
1395  MHD_CONNECTION_INFO_CLIENT_ADDRESS);
1396  if ((conn_info->client_addr->sa_family != AF_INET) &&
1397  (conn_info->client_addr->sa_family != AF_INET6))
1398  return NULL;
1400  "New %s request from %s\n",
1401  method,
1402  url);
1403  stc.tag = 0;
1404  options = 0; /* make gcc happy */
1405  if (GNUNET_SYSERR ==
1406  server_parse_url (plugin, url, &target, &stc.tag, &options))
1407  {
1409  "Invalid url %s\n", url);
1410  return NULL;
1411  }
1412  if (0 == strcmp (MHD_HTTP_METHOD_PUT, method))
1413  direction = _RECEIVE;
1414  else if (0 == strcmp (MHD_HTTP_METHOD_GET, method))
1415  direction = _SEND;
1416  else
1417  {
1419  "Invalid method %s for request from %s\n",
1420  method, url);
1421  return NULL;
1422  }
1423 
1424  plugin->cur_request++;
1426  "New %s request from %s with tag %u (%u of %u)\n",
1427  method,
1428  GNUNET_i2s (&target),
1429  stc.tag,
1430  plugin->cur_request, plugin->max_request);
1431  /* find existing session */
1432  stc.res = NULL;
1434  &target,
1435  &session_tag_it,
1436  &stc);
1437  if (NULL == (s = stc.res))
1438  {
1439  /* create new session */
1440  addr = NULL;
1441  switch (conn_info->client_addr->sa_family)
1442  {
1443  case (AF_INET):
1444  addr = http_common_address_from_socket (plugin->protocol,
1445  conn_info->client_addr,
1446  sizeof(struct sockaddr_in));
1447  addr_len = http_common_address_get_size (addr);
1448  scope = plugin->env->get_address_type (plugin->env->cls,
1449  conn_info->client_addr,
1450  sizeof(struct sockaddr_in));
1451  break;
1452 
1453  case (AF_INET6):
1454  addr = http_common_address_from_socket (plugin->protocol,
1455  conn_info->client_addr,
1456  sizeof(struct sockaddr_in6));
1457  addr_len = http_common_address_get_size (addr);
1458  scope = plugin->env->get_address_type (plugin->env->cls,
1459  conn_info->client_addr,
1460  sizeof(struct sockaddr_in6));
1461  break;
1462 
1463  default:
1464  /* external host name */
1465  return NULL;
1466  }
1467  s = GNUNET_new (struct GNUNET_ATS_Session);
1468  s->target = target;
1469  s->plugin = plugin;
1470  s->scope = scope;
1472  PLUGIN_NAME,
1473  addr,
1474  addr_len,
1477  s->tag = stc.tag;
1481  s);
1482  (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessions,
1483  &s->target,
1484  s,
1487  s,
1490  s,
1493  "Creating new session %p for peer `%s' connecting from `%s'\n",
1494  s, GNUNET_i2s (&target),
1496  addr,
1497  addr_len));
1498  GNUNET_free (addr);
1499  }
1500 
1501  if ((_RECEIVE == direction) &&
1502  (NULL != s->server_recv))
1503  {
1505  "Duplicate PUT request from `%s' tag %u, dismissing new request\n",
1506  GNUNET_i2s (&target),
1507  stc.tag);
1508  return NULL;
1509  }
1510  if ((_SEND == direction) && (NULL != s->server_send))
1511  {
1513  "Duplicate GET request from `%s' tag %u, dismissing new request\n",
1514  GNUNET_i2s (&target),
1515  stc.tag);
1516  return NULL;
1517  }
1518  sc = GNUNET_new (struct ServerRequest);
1519  if (conn_info->client_addr->sa_family == AF_INET)
1520  sc->mhd_daemon = plugin->server_v4;
1521  if (conn_info->client_addr->sa_family == AF_INET6)
1522  sc->mhd_daemon = plugin->server_v6;
1523  sc->mhd_conn = mhd_connection;
1524  sc->direction = direction;
1525  sc->connected = GNUNET_NO;
1526  sc->session = s;
1527  sc->options = options;
1528  if (direction == _SEND)
1529  {
1530  s->server_send = sc;
1531  }
1532  if (direction == _RECEIVE)
1533  {
1534  s->server_recv = sc;
1535  }
1536 
1537  if ((GNUNET_NO == s->known_to_service) &&
1538  (NULL != s->server_send) &&
1539  (NULL != s->server_recv))
1540  {
1543  s,
1545  plugin->env->session_start (plugin->env->cls,
1546  s->address,
1547  s,
1548  s->scope);
1549  }
1550 
1551  to = (HTTP_SERVER_SESSION_TIMEOUT.rel_value_us / 1000LL / 1000LL);
1553  return sc;
1554 }
1555 
1556 
1566 static ssize_t
1568  uint64_t pos,
1569  char *buf,
1570  size_t max)
1571 {
1572  struct ServerRequest *sc = cls;
1573  struct GNUNET_ATS_Session *s = sc->session;
1574  ssize_t bytes_read = 0;
1575  struct HTTP_Message *msg;
1576  char *stat_txt;
1577 
1578  if (NULL == s)
1579  {
1580  /* session is disconnecting */
1581  return 0;
1582  }
1583 
1584  sc = s->server_send;
1585  if (NULL == sc)
1586  return 0;
1587  msg = s->msg_head;
1588  if (NULL != msg)
1589  {
1590  /* sending */
1591  bytes_read = GNUNET_MIN (msg->size - msg->pos,
1592  max);
1593  GNUNET_memcpy (buf, &msg->buf[msg->pos], bytes_read);
1594  msg->pos += bytes_read;
1595 
1596  /* removing message */
1597  if (msg->pos == msg->size)
1598  {
1600  s->msg_tail,
1601  msg);
1602  if (NULL != msg->transmit_cont)
1603  msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_OK,
1604  msg->size, msg->size + msg->overhead);
1605  GNUNET_assert (s->msgs_in_queue > 0);
1606  s->msgs_in_queue--;
1608  s->bytes_in_queue -= msg->size;
1609  GNUNET_free (msg);
1611  s,
1613  }
1614  }
1615  if (0 < bytes_read)
1616  {
1617  sc->connected = GNUNET_YES;
1619  "Sent %lu bytes to peer `%s' with session %p \n",
1620  (unsigned long) bytes_read,
1621  GNUNET_i2s (&s->target),
1622  s);
1623  GNUNET_asprintf (&stat_txt,
1624  "# bytes currently in %s_server buffers",
1625  s->plugin->protocol);
1626  GNUNET_STATISTICS_update (s->plugin->env->stats,
1627  stat_txt,
1628  -bytes_read,
1629  GNUNET_NO);
1630  GNUNET_free (stat_txt);
1631  GNUNET_asprintf (&stat_txt,
1632  "# bytes transmitted via %s_server",
1633  s->plugin->protocol);
1634  GNUNET_STATISTICS_update (s->plugin->env->stats,
1635  stat_txt, bytes_read, GNUNET_NO);
1636  GNUNET_free (stat_txt);
1637  }
1638  else if ((sc->options & OPTION_LONG_POLL) && sc->connected)
1639  {
1641  "Completing GET response to peer `%s' with session %p\n",
1642  GNUNET_i2s (&s->target),
1643  s);
1644  return MHD_CONTENT_READER_END_OF_STREAM;
1645  }
1646  else
1647  {
1648  MHD_suspend_connection (s->server_send->mhd_conn);
1649  s->server_send->suspended = true;
1650  return 0;
1651  }
1652  return bytes_read;
1653 }
1654 
1655 
1663 static int
1665  const struct GNUNET_MessageHeader *message)
1666 {
1667  struct GNUNET_ATS_Session *s = cls;
1668  struct HTTP_Server_Plugin *plugin = s->plugin;
1669  struct GNUNET_TIME_Relative delay;
1670  char *stat_txt;
1671 
1672  if (GNUNET_NO == s->known_to_service)
1673  {
1675  plugin->env->session_start (plugin->env->cls,
1676  s->address,
1677  s,
1678  s->scope);
1680  s,
1682  }
1683  delay = plugin->env->receive (plugin->env->cls,
1684  s->address,
1685  s,
1686  message);
1687  GNUNET_asprintf (&stat_txt,
1688  "# bytes received via %s_server",
1689  plugin->protocol);
1690  GNUNET_STATISTICS_update (plugin->env->stats,
1691  stat_txt,
1692  ntohs (message->size),
1693  GNUNET_NO);
1694  GNUNET_free (stat_txt);
1696  if (delay.rel_value_us > 0)
1697  {
1699  "Peer `%s' address `%s' next read delayed for %s\n",
1700  GNUNET_i2s (&s->target),
1702  s->address->address,
1703  s->address->address_length),
1705  GNUNET_YES));
1706  }
1708  return GNUNET_OK;
1709 }
1710 
1711 
1718 static void
1719 add_cors_headers (struct MHD_Response *response)
1720 {
1721  MHD_add_response_header (response,
1722  "Access-Control-Allow-Origin",
1723  "*");
1724  MHD_add_response_header (response,
1725  "Access-Control-Allow-Methods",
1726  "GET, PUT, OPTIONS");
1727  MHD_add_response_header (response,
1728  "Access-Control-Max-Age",
1729  "86400");
1730 }
1731 
1732 
1746 static MHD_RESULT
1747 server_access_cb (void *cls,
1748  struct MHD_Connection *mhd_connection,
1749  const char *url,
1750  const char *method,
1751  const char *version,
1752  const char *upload_data,
1753  size_t *upload_data_size,
1754  void **httpSessionCache)
1755 {
1756  struct HTTP_Server_Plugin *plugin = cls;
1757  struct ServerRequest *sc = *httpSessionCache;
1758  struct GNUNET_ATS_Session *s;
1759  struct MHD_Response *response;
1760  MHD_RESULT res = MHD_YES;
1761 
1763  _ (
1764  "Access from connection %p (%u of %u) for `%s' `%s' url `%s' with upload data size %lu\n"),
1765  sc,
1766  plugin->cur_request,
1767  plugin->max_request,
1768  method,
1769  version,
1770  url,
1771  (unsigned long) (*upload_data_size));
1772  if (NULL == sc)
1773  {
1774  /* CORS pre-flight request */
1775  if (0 == strcmp (MHD_HTTP_METHOD_OPTIONS, method))
1776  {
1777  response = MHD_create_response_from_buffer (0, NULL,
1778  MHD_RESPMEM_PERSISTENT);
1780  res = MHD_queue_response (mhd_connection, MHD_HTTP_OK, response);
1781  MHD_destroy_response (response);
1782  return res;
1783  }
1784  /* new connection */
1785  sc = server_lookup_connection (plugin, mhd_connection, url, method);
1786  if (NULL != sc)
1787  {
1788  /* attach to new / existing session */
1789  (*httpSessionCache) = sc;
1790  }
1791  else
1792  {
1793  /* existing session already has matching connection, refuse */
1794  response = MHD_create_response_from_buffer (strlen (HTTP_ERROR_RESPONSE),
1796  MHD_RESPMEM_PERSISTENT);
1797  MHD_add_response_header (response,
1798  MHD_HTTP_HEADER_CONTENT_TYPE,
1799  "text/html");
1801  res = MHD_queue_response (mhd_connection, MHD_HTTP_NOT_FOUND, response);
1802  MHD_destroy_response (response);
1803  return res;
1804  }
1805  }
1806  /* 'old' connection */
1807  if (NULL == (s = sc->session))
1808  {
1809  /* Session was already disconnected;
1810  sent HTTP/1.1: 200 OK as response */
1811  response = MHD_create_response_from_buffer (strlen ("Thank you!"),
1812  "Thank you!",
1813  MHD_RESPMEM_PERSISTENT);
1815  MHD_queue_response (mhd_connection, MHD_HTTP_OK, response);
1816  MHD_destroy_response (response);
1817  return MHD_YES;
1818  }
1819 
1820  if (sc->direction == _SEND)
1821  {
1822  response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN, 32 * 1024,
1824  NULL);
1826  MHD_queue_response (mhd_connection, MHD_HTTP_OK, response);
1827  MHD_destroy_response (response);
1828  return MHD_YES;
1829  }
1830  if (sc->direction == _RECEIVE)
1831  {
1832  if ((*upload_data_size == 0) && (sc->connected == GNUNET_NO))
1833  {
1834  /* (*upload_data_size == 0) first callback when header are passed */
1836  "Session %p / Connection %p: Peer `%s' PUT on address `%s' connected\n",
1837  s, sc,
1838  GNUNET_i2s (&s->target),
1840  s->address->address,
1841  s->address->address_length));
1842  sc->connected = GNUNET_YES;
1843  return MHD_YES;
1844  }
1845  else if ((*upload_data_size == 0) && (sc->connected == GNUNET_YES))
1846  {
1847  /* (*upload_data_size == 0) when upload is complete */
1849  "Session %p / Connection %p: Peer `%s' PUT on address `%s' finished upload\n",
1850  s, sc,
1851  GNUNET_i2s (&s->target),
1853  s->address->address,
1854  s->address->address_length));
1855  sc->connected = GNUNET_NO;
1856  /* Sent HTTP/1.1: 200 OK as PUT Response\ */
1857  response = MHD_create_response_from_buffer (strlen ("Thank you!"),
1858  "Thank you!",
1859  MHD_RESPMEM_PERSISTENT);
1861  MHD_queue_response (mhd_connection, MHD_HTTP_OK, response);
1862  MHD_destroy_response (response);
1863  return MHD_YES;
1864  }
1865  else if ((*upload_data_size > 0) && (sc->connected == GNUNET_YES))
1866  {
1867  struct GNUNET_TIME_Relative delay;
1868 
1869  /* (*upload_data_size > 0) for every segment received */
1871  "Session %p / Connection %p: Peer `%s' PUT on address `%s' received %lu bytes\n",
1872  s, sc,
1873  GNUNET_i2s (&s->target),
1875  s->address->address,
1876  s->address->address_length),
1877  (unsigned long) *upload_data_size);
1879  if (0 == delay.rel_value_us)
1880  {
1882  "PUT with %lu bytes forwarded to MST\n",
1883  (unsigned long) *upload_data_size);
1884  if (s->msg_tk == NULL)
1885  {
1887  s);
1888  }
1890  upload_data,
1891  *upload_data_size,
1892  GNUNET_NO, GNUNET_NO);
1895  rel_value_us / 1000LL
1896  / 1000LL);
1897  (*upload_data_size) = 0;
1898  }
1899  else
1900  {
1901  /* delay processing */
1903  "Session %p / Connection %p: no inbound bandwidth available! Next read was delayed by %s\n",
1904  s,
1905  sc,
1907  GNUNET_YES));
1908  GNUNET_assert (s->server_recv->mhd_conn == mhd_connection);
1909  MHD_suspend_connection (s->server_recv->mhd_conn);
1910  s->server_recv->suspended = true;
1911  if (NULL == s->recv_wakeup_task)
1912  s->recv_wakeup_task
1914  &server_wake_up,
1915  s);
1916  }
1917  return MHD_YES;
1918  }
1919  else
1920  {
1921  GNUNET_break (0);
1922  return MHD_NO;
1923  }
1924  }
1925  return res;
1926 }
1927 
1928 
1936 static void
1938  struct MHD_Connection *connection,
1939  void **httpSessionCache)
1940 {
1941  struct HTTP_Server_Plugin *plugin = cls;
1942  struct ServerRequest *sc = *httpSessionCache;
1943 
1945  "Disconnect for connection %p\n",
1946  sc);
1947  if (NULL == sc)
1948  {
1949  /* CORS pre-flight request finished */
1950  return;
1951  }
1952 
1953  if (NULL != sc->session)
1954  {
1955  if (sc->direction == _SEND)
1956  {
1958  "Peer `%s' connection %p, GET on address `%s' disconnected\n",
1959  GNUNET_i2s (&sc->session->target),
1960  sc->session->server_send,
1962  sc->session->address->address,
1963  sc->session->address->
1964  address_length));
1965 
1966  sc->session->server_send = NULL;
1967  }
1968  else if (sc->direction == _RECEIVE)
1969  {
1971  "Peer `%s' connection %p PUT on address `%s' disconnected\n",
1972  GNUNET_i2s (&sc->session->target),
1973  sc->session->server_recv,
1975  sc->session->address->address,
1976  sc->session->address->
1977  address_length));
1978  sc->session->server_recv = NULL;
1979  if (NULL != sc->session->msg_tk)
1980  {
1981  GNUNET_MST_destroy (sc->session->msg_tk);
1982  sc->session->msg_tk = NULL;
1983  }
1984  }
1985  }
1986  GNUNET_free (sc);
1987  plugin->cur_request--;
1988 }
1989 
1990 
2000 static void
2002  struct MHD_Connection *connection,
2003  void **socket_context,
2004  enum MHD_ConnectionNotificationCode toe)
2005 {
2006  struct HTTP_Server_Plugin *plugin = cls;
2007  const union MHD_ConnectionInfo *info;
2008 
2009  if (MHD_CONNECTION_NOTIFY_STARTED == toe)
2010  return;
2011 
2012  /* Reschedule to remove closed socket from our select set */
2013  info = MHD_get_connection_info (connection,
2014  MHD_CONNECTION_INFO_DAEMON);
2015  GNUNET_assert (NULL != info);
2017  info->daemon,
2018  GNUNET_YES);
2019 }
2020 
2021 
2030 static MHD_RESULT
2031 server_accept_cb (void *cls,
2032  const struct sockaddr *addr,
2033  socklen_t addr_len)
2034 {
2035  struct HTTP_Server_Plugin *plugin = cls;
2036 
2037  if (plugin->cur_request <= plugin->max_request)
2038  {
2040  _ ("Accepting connection (%u of %u) from `%s'\n"),
2041  plugin->cur_request, plugin->max_request,
2042  GNUNET_a2s (addr, addr_len));
2043  return MHD_YES;
2044  }
2045  else
2046  {
2048  _ (
2049  "Server reached maximum number connections (%u), rejecting new connection\n"),
2050  plugin->max_request);
2051  return MHD_NO;
2052  }
2053 }
2054 
2055 
2064 static void
2066  const char *fmt,
2067  va_list ap)
2068 {
2069  char text[1024];
2070 
2071  vsnprintf (text,
2072  sizeof(text),
2073  fmt,
2074  ap);
2076  "Server: %s\n",
2077  text);
2078 }
2079 
2080 
2081 #if BUILD_HTTPS
2088 static char *
2089 server_load_file (const char *file)
2090 {
2091  struct GNUNET_DISK_FileHandle *gn_file;
2092  uint64_t fsize;
2093  char *text = NULL;
2094 
2095  if (GNUNET_OK != GNUNET_DISK_file_size (file,
2096  &fsize, GNUNET_NO, GNUNET_YES))
2097  return NULL;
2098  text = GNUNET_malloc (fsize + 1);
2099  gn_file =
2102  if (NULL == gn_file)
2103  {
2104  GNUNET_free (text);
2105  return NULL;
2106  }
2107  if (GNUNET_SYSERR == GNUNET_DISK_file_read (gn_file, text, fsize))
2108  {
2109  GNUNET_free (text);
2110  GNUNET_DISK_file_close (gn_file);
2111  return NULL;
2112  }
2113  text[fsize] = '\0';
2114  GNUNET_DISK_file_close (gn_file);
2115  return text;
2116 }
2117 
2118 
2119 #endif
2120 
2121 
2122 #if BUILD_HTTPS
2129 static int
2130 server_load_certificate (struct HTTP_Server_Plugin *plugin)
2131 {
2132  int res = GNUNET_OK;
2133  char *key_file;
2134  char *cert_file;
2135 
2136 
2137  if (GNUNET_OK !=
2139  plugin->name,
2140  "KEY_FILE", &key_file))
2141  {
2143  plugin->name, "CERT_FILE");
2144  return GNUNET_SYSERR;
2145  }
2146  if (GNUNET_OK !=
2148  plugin->name,
2149  "CERT_FILE", &cert_file))
2150  {
2152  plugin->name, "CERT_FILE");
2153  GNUNET_free (key_file);
2154  return GNUNET_SYSERR;
2155  }
2156  /* Get crypto init string from config. If not present, use
2157  * default values */
2158  if (GNUNET_OK ==
2160  plugin->name,
2161  "CRYPTO_INIT",
2162  &plugin->crypto_init))
2164  "Using crypto init string `%s'\n",
2165  plugin->crypto_init);
2166  else
2168  "Using default crypto init string \n");
2169 
2170  /* read key & certificates from file */
2172  "Trying to loading TLS certificate from key-file `%s' cert-file`%s'\n",
2173  key_file, cert_file);
2174 
2175  plugin->key = server_load_file (key_file);
2176  plugin->cert = server_load_file (cert_file);
2177 
2178  if ((plugin->key == NULL) || (plugin->cert == NULL))
2179  {
2180  struct GNUNET_OS_Process *cert_creation;
2181 
2182  GNUNET_free (plugin->key);
2183  plugin->key = NULL;
2184  GNUNET_free (plugin->cert);
2185  plugin->cert = NULL;
2186 
2188  "No usable TLS certificate found, creating certificate\n");
2189  errno = 0;
2190  cert_creation =
2192  NULL, NULL, NULL,
2193  "gnunet-transport-certificate-creation",
2194  "gnunet-transport-certificate-creation",
2195  key_file,
2196  cert_file,
2197  NULL);
2198  if (NULL == cert_creation)
2199  {
2201  _ (
2202  "Could not create a new TLS certificate, program `gnunet-transport-certificate-creation' could not be started!\n"));
2203  GNUNET_free (key_file);
2204  GNUNET_free (cert_file);
2205 
2206  GNUNET_free (plugin->key);
2207  plugin->key = NULL;
2208  GNUNET_free (plugin->cert);
2209  plugin->cert = NULL;
2210  GNUNET_free (plugin->crypto_init);
2211  plugin->crypto_init = NULL;
2212 
2213  return GNUNET_SYSERR;
2214  }
2215  GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (cert_creation));
2216  GNUNET_OS_process_destroy (cert_creation);
2217 
2218  plugin->key = server_load_file (key_file);
2219  plugin->cert = server_load_file (cert_file);
2220  }
2221 
2222  if ((plugin->key == NULL) || (plugin->cert == NULL))
2223  {
2225  _ (
2226  "No usable TLS certificate found and creating one at `%s/%s' failed!\n"),
2227  key_file, cert_file);
2228  GNUNET_free (key_file);
2229  GNUNET_free (cert_file);
2230 
2231  GNUNET_free (plugin->key);
2232  plugin->key = NULL;
2233  GNUNET_free (plugin->cert);
2234  plugin->cert = NULL;
2235  GNUNET_free (plugin->crypto_init);
2236  plugin->crypto_init = NULL;
2237 
2238  return GNUNET_SYSERR;
2239  }
2240  GNUNET_free (key_file);
2241  GNUNET_free (cert_file);
2243  "TLS certificate loaded\n");
2244  return res;
2245 }
2246 
2247 
2248 #endif
2249 
2250 
2260 static struct MHD_Daemon *
2262  const struct sockaddr_in *addr,
2263  int v6)
2264 {
2265  struct MHD_Daemon *server;
2266  unsigned int timeout;
2267 
2268 #if MHD_VERSION >= 0x00090E00
2269  timeout = HTTP_SERVER_NOT_VALIDATED_TIMEOUT.rel_value_us / 1000LL / 1000LL;
2271  "MHD can set timeout per connection! Default time out %u sec.\n",
2272  timeout);
2273 #else
2274  timeout = HTTP_SERVER_SESSION_TIMEOUT.rel_value_us / 1000LL / 1000LL;
2276  "MHD cannot set timeout per connection! Default time out %u sec.\n",
2277  timeout);
2278 #endif
2279  server = MHD_start_daemon (
2280 #if VERBOSE_SERVER
2281  MHD_USE_DEBUG |
2282 #endif
2283 #if BUILD_HTTPS
2284  MHD_USE_SSL |
2285 #endif
2286  MHD_USE_SUSPEND_RESUME
2287  | v6,
2288  plugin->port,
2291  MHD_OPTION_SOCK_ADDR,
2292  addr,
2293  MHD_OPTION_CONNECTION_LIMIT,
2294  (unsigned int) plugin->max_request,
2295 #if BUILD_HTTPS
2296  MHD_OPTION_HTTPS_PRIORITIES,
2297  plugin->crypto_init,
2298  MHD_OPTION_HTTPS_MEM_KEY,
2299  plugin->key,
2300  MHD_OPTION_HTTPS_MEM_CERT,
2301  plugin->cert,
2302 #endif
2303  MHD_OPTION_CONNECTION_TIMEOUT,
2304  timeout,
2305  MHD_OPTION_CONNECTION_MEMORY_LIMIT,
2306  (size_t) (2
2308  MHD_OPTION_NOTIFY_COMPLETED,
2310  MHD_OPTION_NOTIFY_CONNECTION,
2312  MHD_OPTION_EXTERNAL_LOGGER,
2313  &server_log, NULL,
2314  MHD_OPTION_END);
2315 #ifdef TCP_STEALTH
2316  if ((NULL != server) &&
2317  (0 != (plugin->options & HTTP_OPTIONS_TCP_STEALTH)))
2318  {
2319  const union MHD_DaemonInfo *di;
2320 
2321  di = MHD_get_daemon_info (server,
2322  MHD_DAEMON_INFO_LISTEN_FD,
2323  NULL);
2324  if ((0 != setsockopt ((int) di->listen_fd,
2325  IPPROTO_TCP,
2326  TCP_STEALTH,
2327  plugin->env->my_identity,
2328  sizeof(struct GNUNET_PeerIdentity))))
2329  {
2331  _ ("TCP_STEALTH not supported on this platform.\n"));
2332  MHD_stop_daemon (server);
2333  server = NULL;
2334  }
2335  }
2336 #endif
2337  return server;
2338 }
2339 
2340 
2347 static int
2349 {
2350  const char *msg;
2351 
2352  GNUNET_assert (NULL != plugin);
2353 #if BUILD_HTTPS
2354  if (GNUNET_SYSERR == server_load_certificate (plugin))
2355  {
2357  _ (
2358  "Could not load or create server certificate! Loading plugin failed!\n"));
2359  return GNUNET_SYSERR;
2360  }
2361 #endif
2362 
2363 
2364  plugin->server_v4 = NULL;
2365  if (GNUNET_YES == plugin->use_ipv4)
2366  {
2367  plugin->server_v4
2369  (const struct
2370  sockaddr_in *) plugin->server_addr_v4,
2371  MHD_NO_FLAG);
2372 
2373  if (NULL == plugin->server_v4)
2374  {
2376  "Failed to start %s IPv4 server component on port %u\n",
2377  plugin->name,
2378  plugin->port);
2379  }
2380  else
2382  plugin->server_v4,
2383  GNUNET_NO);
2384  }
2385 
2386 
2387  plugin->server_v6 = NULL;
2388  if (GNUNET_YES == plugin->use_ipv6)
2389  {
2390  plugin->server_v6
2392  (const struct
2393  sockaddr_in *) plugin->server_addr_v6,
2394  MHD_USE_IPv6);
2395  if (NULL == plugin->server_v6)
2396  {
2398  "Failed to start %s IPv6 server component on port %u\n",
2399  plugin->name,
2400  plugin->port);
2401  }
2402  else
2403  {
2405  plugin->server_v6,
2406  GNUNET_NO);
2407  }
2408  }
2409  msg = "No";
2410  if ((NULL == plugin->server_v6) &&
2411  (NULL == plugin->server_v4))
2412  {
2414  "%s %s server component started on port %u\n",
2415  msg,
2416  plugin->name,
2417  plugin->port);
2418  return GNUNET_SYSERR;
2419  }
2420  if ((NULL != plugin->server_v6) &&
2421  (NULL != plugin->server_v4))
2422  msg = "IPv4 and IPv6";
2423  else if (NULL != plugin->server_v6)
2424  msg = "IPv6";
2425  else if (NULL != plugin->server_v4)
2426  msg = "IPv4";
2428  "%s %s server component started on port %u\n",
2429  msg,
2430  plugin->name,
2431  plugin->port);
2432  return GNUNET_OK;
2433 }
2434 
2435 
2444 static void
2446  int add_remove,
2447  const struct sockaddr *addr,
2448  socklen_t addrlen)
2449 {
2450  struct HTTP_Server_Plugin *plugin = cls;
2451  struct GNUNET_HELLO_Address *address;
2452  struct HttpAddressWrapper *w = NULL;
2453 
2454  w = GNUNET_new (struct HttpAddressWrapper);
2456  addr,
2457  addrlen);
2458  if (NULL == w->address)
2459  {
2460  GNUNET_free (w);
2461  return;
2462  }
2464 
2465  GNUNET_CONTAINER_DLL_insert (plugin->addr_head,
2466  plugin->addr_tail,
2467  w);
2469  "Notifying transport to add address `%s'\n",
2471  w->address,
2472  w->addrlen));
2473  /* modify our published address list */
2474 #if BUILD_HTTPS
2475  address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
2476  "https_client", w->address,
2477  w->addrlen,
2479 #else
2480  address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
2481  "http_client", w->address,
2482  w->addrlen,
2484 #endif
2485 
2486  plugin->env->notify_address (plugin->env->cls,
2487  add_remove,
2488  address);
2490 }
2491 
2492 
2501 static void
2503  int add_remove,
2504  const struct sockaddr *addr,
2505  socklen_t addrlen)
2506 {
2507  struct HTTP_Server_Plugin *plugin = cls;
2508  struct GNUNET_HELLO_Address *address;
2509  struct HttpAddressWrapper *w = plugin->addr_head;
2510  size_t saddr_len;
2511  void *saddr;
2512 
2513  saddr = http_common_address_from_socket (plugin->protocol,
2514  addr,
2515  addrlen);
2516  if (NULL == saddr)
2517  return;
2518  saddr_len = http_common_address_get_size (saddr);
2519 
2520  while (NULL != w)
2521  {
2522  if (GNUNET_YES ==
2524  w->addrlen,
2525  saddr,
2526  saddr_len))
2527  break;
2528  w = w->next;
2529  }
2530  GNUNET_free (saddr);
2531 
2532  if (NULL == w)
2533  return;
2534 
2536  "Notifying transport to remove address `%s'\n",
2538  w->address,
2539  w->addrlen));
2540  GNUNET_CONTAINER_DLL_remove (plugin->addr_head,
2541  plugin->addr_tail,
2542  w);
2543  /* modify our published address list */
2544 #if BUILD_HTTPS
2545  address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
2546  "https_client", w->address,
2547  w->addrlen,
2549 #else
2550  address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
2551  "http_client", w->address,
2552  w->addrlen,
2554 #endif
2555  plugin->env->notify_address (plugin->env->cls, add_remove, address);
2557  GNUNET_free (w->address);
2558  GNUNET_free (w);
2559 }
2560 
2561 
2574 static void
2576  void **app_ctx,
2577  int add_remove,
2579  const struct sockaddr *addr,
2580  socklen_t addrlen)
2581 {
2582  struct HTTP_Server_Plugin *plugin = cls;
2583 
2584  (void) app_ctx;
2586  "NAT called to %s address `%s'\n",
2587  (add_remove == GNUNET_NO) ? "remove" : "add",
2588  GNUNET_a2s (addr, addrlen));
2589 
2590  if (AF_INET == addr->sa_family)
2591  {
2592  struct sockaddr_in *s4 = (struct sockaddr_in *) addr;
2593 
2594  if (GNUNET_NO == plugin->use_ipv4)
2595  return;
2596 
2597  if ((NULL != plugin->server_addr_v4) &&
2598  (0 != memcmp (&plugin->server_addr_v4->sin_addr,
2599  &s4->sin_addr,
2600  sizeof(struct in_addr))))
2601  {
2603  "Skipping address `%s' (not bindto address)\n",
2604  GNUNET_a2s (addr, addrlen));
2605  return;
2606  }
2607  }
2608 
2609  if (AF_INET6 == addr->sa_family)
2610  {
2611  struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) addr;
2612  if (GNUNET_NO == plugin->use_ipv6)
2613  return;
2614 
2615  if ((NULL != plugin->server_addr_v6) &&
2616  (0 != memcmp (&plugin->server_addr_v6->sin6_addr,
2617  &s6->sin6_addr, sizeof(struct in6_addr))))
2618  {
2620  "Skipping address `%s' (not bindto address)\n",
2621  GNUNET_a2s (addr, addrlen));
2622  return;
2623  }
2624  }
2625 
2626  switch (add_remove)
2627  {
2628  case GNUNET_YES:
2629  server_add_address (cls, add_remove, addr, addrlen);
2630  break;
2631 
2632  case GNUNET_NO:
2633  server_remove_address (cls, add_remove, addr, addrlen);
2634  break;
2635  }
2636 }
2637 
2638 
2649 static int
2651  const char *service_name,
2652  const struct GNUNET_CONFIGURATION_Handle *cfg,
2653  struct sockaddr ***addrs,
2654  socklen_t **addr_lens)
2655 {
2656  int disablev6;
2657  unsigned long long port;
2658  struct addrinfo hints;
2659  struct addrinfo *res;
2660  struct addrinfo *pos;
2661  struct addrinfo *next;
2662  unsigned int i;
2663  int resi;
2664  int ret;
2665  struct sockaddr **saddrs;
2666  socklen_t *saddrlens;
2667  char *hostname;
2668 
2669  *addrs = NULL;
2670  *addr_lens = NULL;
2671 
2672  disablev6 = ! plugin->use_ipv6;
2673 
2674  port = 0;
2676  {
2679  "PORT", &port));
2680  if (port > 65535)
2681  {
2683  _ (
2684  "Require valid port number for service in configuration!\n"));
2685  return GNUNET_SYSERR;
2686  }
2687  }
2688  if (0 == port)
2689  {
2691  "Starting in listen only mode\n");
2692  return -1; /* listen only */
2693  }
2694 
2695 
2697  "BINDTO"))
2698  {
2701  "BINDTO", &hostname));
2702  }
2703  else
2704  hostname = NULL;
2705 
2706  if (NULL != hostname)
2707  {
2709  "Resolving `%s' since that is where `%s' will bind to.\n",
2711  memset (&hints, 0, sizeof(struct addrinfo));
2712  if (disablev6)
2713  hints.ai_family = AF_INET;
2714  if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
2715  (NULL == res))
2716  {
2718  _ ("Failed to resolve `%s': %s\n"),
2719  hostname,
2720  gai_strerror (ret));
2722  return GNUNET_SYSERR;
2723  }
2724  next = res;
2725  i = 0;
2726  while (NULL != (pos = next))
2727  {
2728  next = pos->ai_next;
2729  if ((disablev6) && (pos->ai_family == AF_INET6))
2730  continue;
2731  i++;
2732  }
2733  if (0 == i)
2734  {
2736  _ ("Failed to find %saddress for `%s'.\n"),
2737  disablev6 ? "IPv4 " : "", hostname);
2738  freeaddrinfo (res);
2740  return GNUNET_SYSERR;
2741  }
2742  resi = i;
2743  saddrs = GNUNET_malloc ((resi + 1) * sizeof(struct sockaddr *));
2744  saddrlens = GNUNET_malloc ((resi + 1) * sizeof(socklen_t));
2745  i = 0;
2746  next = res;
2747  while (NULL != (pos = next))
2748  {
2749  next = pos->ai_next;
2750  if ((disablev6) && (pos->ai_family == AF_INET6))
2751  continue;
2752  if ((pos->ai_protocol != IPPROTO_TCP) && (0 != pos->ai_protocol))
2753  continue; /* not TCP */
2754  if ((pos->ai_socktype != SOCK_STREAM) && (0 != pos->ai_socktype))
2755  continue; /* huh? */
2757  "Service will bind to `%s'\n",
2758  GNUNET_a2s (pos->ai_addr,
2759  pos->ai_addrlen));
2760  if (pos->ai_family == AF_INET)
2761  {
2762  GNUNET_assert (pos->ai_addrlen == sizeof(struct sockaddr_in));
2763  saddrlens[i] = pos->ai_addrlen;
2764  saddrs[i] = GNUNET_malloc (saddrlens[i]);
2765  GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
2766  ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
2767  }
2768  else
2769  {
2770  GNUNET_assert (pos->ai_family == AF_INET6);
2771  GNUNET_assert (pos->ai_addrlen == sizeof(struct sockaddr_in6));
2772  saddrlens[i] = pos->ai_addrlen;
2773  saddrs[i] = GNUNET_malloc (saddrlens[i]);
2774  GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
2775  ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
2776  }
2777  i++;
2778  }
2780  freeaddrinfo (res);
2781  resi = i;
2782  }
2783  else
2784  {
2785  /* will bind against everything, just set port */
2786  if (disablev6)
2787  {
2788  /* V4-only */
2789  resi = 1;
2790  i = 0;
2791  saddrs = GNUNET_malloc ((resi + 1) * sizeof(struct sockaddr *));
2792  saddrlens = GNUNET_malloc ((resi + 1) * sizeof(socklen_t));
2793 
2794  saddrlens[i] = sizeof(struct sockaddr_in);
2795  saddrs[i] = GNUNET_malloc (saddrlens[i]);
2796 #if HAVE_SOCKADDR_IN_SIN_LEN
2797  ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
2798 #endif
2799  ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
2800  ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
2801  }
2802  else
2803  {
2804  /* dual stack */
2805  resi = 2;
2806  saddrs = GNUNET_malloc ((resi + 1) * sizeof(struct sockaddr *));
2807  saddrlens = GNUNET_malloc ((resi + 1) * sizeof(socklen_t));
2808  i = 0;
2809  saddrlens[i] = sizeof(struct sockaddr_in6);
2810  saddrs[i] = GNUNET_malloc (saddrlens[i]);
2811 #if HAVE_SOCKADDR_IN_SIN_LEN
2812  ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
2813 #endif
2814  ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
2815  ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
2816  i++;
2817  saddrlens[i] = sizeof(struct sockaddr_in);
2818  saddrs[i] = GNUNET_malloc (saddrlens[i]);
2819 #if HAVE_SOCKADDR_IN_SIN_LEN
2820  ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
2821 #endif
2822  ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
2823  ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
2824  }
2825  }
2826  *addrs = saddrs;
2827  *addr_lens = saddrlens;
2828  return resi;
2829 }
2830 
2831 
2837 static void
2839 {
2840  int res = GNUNET_OK;
2841  struct sockaddr **addrs;
2842  socklen_t *addrlens;
2843 
2845  plugin->name,
2846  plugin->env->cfg,
2847  &addrs, &addrlens);
2849  _ ("Found %u addresses to report to NAT service\n"),
2850  res);
2851 
2852  if (GNUNET_SYSERR == res)
2853  {
2854  plugin->nat = NULL;
2855  return;
2856  }
2857 
2858  plugin->nat
2859  = GNUNET_NAT_register (plugin->env->cfg,
2860  plugin->name,
2861  IPPROTO_TCP,
2862  (unsigned int) res,
2863  (const struct sockaddr **) addrs,
2864  addrlens,
2866  NULL,
2867  plugin);
2868  while (res > 0)
2869  {
2870  res--;
2871  GNUNET_assert (NULL != addrs[res]);
2872  GNUNET_free (addrs[res]);
2873  }
2874  GNUNET_free (addrs);
2875  GNUNET_free (addrlens);
2876 }
2877 
2878 
2884 static void
2886 {
2887  struct HttpAddressWrapper *w;
2888 
2889  /* Stop NAT handle */
2890  if (NULL != plugin->nat)
2891  {
2893  plugin->nat = NULL;
2894  }
2895  /* Clean up addresses */
2896  while (NULL != plugin->addr_head)
2897  {
2898  w = plugin->addr_head;
2899  GNUNET_CONTAINER_DLL_remove (plugin->addr_head,
2900  plugin->addr_tail,
2901  w);
2902  GNUNET_free (w->address);
2903  GNUNET_free (w);
2904  }
2905 }
2906 
2907 
2914 static int
2916 {
2917  struct GNUNET_NETWORK_Handle *desc = NULL;
2918  int res = GNUNET_NO;
2919 
2920  /* Probe IPv6 support */
2921  desc = GNUNET_NETWORK_socket_create (PF_INET6,
2922  SOCK_STREAM,
2923  0);
2924  if (NULL == desc)
2925  {
2926  if ((errno == ENOBUFS) ||
2927  (errno == ENOMEM) ||
2928  (errno == ENFILE) ||
2929  (errno == EACCES))
2930  {
2932  "socket");
2933  }
2935  _ ("Disabling IPv6 since it is not supported on this system!\n"));
2936  res = GNUNET_NO;
2937  }
2938  else
2939  {
2942  desc = NULL;
2943  res = GNUNET_YES;
2944  }
2946  "Testing IPv6 on this system: %s\n",
2947  (res == GNUNET_YES) ? "successful" : "failed");
2948  return res;
2949 }
2950 
2951 
2957 static void
2959 {
2960  struct HTTP_Server_Plugin *plugin = cls;
2961  struct HttpAddress *ext_addr;
2962  size_t ext_addr_len;
2963  unsigned int urlen;
2964  char *url;
2965 
2966  plugin->notify_ext_task = NULL;
2967  GNUNET_asprintf (&url,
2968  "%s://%s",
2969  plugin->protocol,
2970  plugin->external_hostname);
2971  urlen = strlen (url) + 1;
2972  ext_addr = GNUNET_malloc (sizeof(struct HttpAddress) + urlen);
2973  ext_addr->options = htonl (plugin->options);
2974  ext_addr->urlen = htonl (urlen);
2975  ext_addr_len = sizeof(struct HttpAddress) + urlen;
2976  GNUNET_memcpy (&ext_addr[1], url, urlen);
2977  GNUNET_free (url);
2978 
2980  "Notifying transport about external hostname address `%s'\n",
2981  plugin->external_hostname);
2982 
2983 #if BUILD_HTTPS
2984  if (GNUNET_YES == plugin->verify_external_hostname)
2986  "Enabling SSL verification for external hostname address `%s'\n",
2987  plugin->external_hostname);
2988  plugin->ext_addr
2989  = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
2990  "https_client",
2991  ext_addr,
2992  ext_addr_len,
2994  plugin->env->notify_address (plugin->env->cls,
2995  GNUNET_YES,
2996  plugin->ext_addr);
2997  GNUNET_free (ext_addr);
2998 #else
2999  plugin->ext_addr
3000  = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
3001  "http_client",
3002  ext_addr,
3003  ext_addr_len,
3005  plugin->env->notify_address (plugin->env->cls,
3006  GNUNET_YES,
3007  plugin->ext_addr);
3008  GNUNET_free (ext_addr);
3009 #endif
3010 }
3011 
3012 
3019 static int
3021 {
3022  unsigned long long port;
3023  unsigned long long max_connections;
3024  char *bind4_address = NULL;
3025  char *bind6_address = NULL;
3026  char *eh_tmp = NULL;
3027  int external_hostname_use_port;
3028 
3029  /* Use IPv4? */
3031  (plugin->env->cfg, plugin->name, "USE_IPv4"))
3032  {
3033  plugin->use_ipv4 =
3035  plugin->name,
3036  "USE_IPv4");
3037  }
3038  else
3039  plugin->use_ipv4 = GNUNET_YES;
3041  _ ("IPv4 support is %s\n"),
3042  (plugin->use_ipv4 == GNUNET_YES) ? "enabled" : "disabled");
3043 
3044  /* Use IPv6? */
3046  (plugin->env->cfg, plugin->name, "USE_IPv6"))
3047  {
3048  plugin->use_ipv6 =
3050  plugin->name,
3051  "USE_IPv6");
3052  }
3053  else
3054  plugin->use_ipv6 = GNUNET_YES;
3056  _ ("IPv6 support is %s\n"),
3057  (plugin->use_ipv6 == GNUNET_YES) ? "enabled" : "disabled");
3058 
3059  if ((plugin->use_ipv4 == GNUNET_NO) && (plugin->use_ipv6 == GNUNET_NO))
3060  {
3062  _ ("Neither IPv4 nor IPv6 are enabled! Fix in configuration\n"));
3063  return GNUNET_SYSERR;
3064  }
3065 
3066  /* Reading port number from config file */
3067  if ((GNUNET_OK !=
3069  plugin->name,
3070  "PORT", &port)) || (port > 65535))
3071  {
3073  _ ("Port is required! Fix in configuration\n"));
3074  return GNUNET_SYSERR;
3075  }
3076  plugin->port = port;
3077 
3079  _ ("Using port %u\n"), plugin->port);
3080 
3081  if ((plugin->use_ipv4 == GNUNET_YES) &&
3082  (GNUNET_YES ==
3084  plugin->name,
3085  "BINDTO",
3086  &bind4_address)))
3087  {
3089  "Binding %s plugin to specific IPv4 address: `%s'\n",
3090  plugin->protocol,
3091  bind4_address);
3092  plugin->server_addr_v4 = GNUNET_new (struct sockaddr_in);
3093  if (1 != inet_pton (AF_INET,
3094  bind4_address,
3095  &plugin->server_addr_v4->sin_addr))
3096  {
3098  _ ("Specific IPv4 address `%s' in configuration file is invalid!\n"),
3099  bind4_address);
3100  GNUNET_free (bind4_address);
3101  GNUNET_free (plugin->server_addr_v4);
3102  plugin->server_addr_v4 = NULL;
3103  return GNUNET_SYSERR;
3104  }
3105  else
3106  {
3108  "Binding to IPv4 address %s\n",
3109  bind4_address);
3110  plugin->server_addr_v4->sin_family = AF_INET;
3111  plugin->server_addr_v4->sin_port = htons (plugin->port);
3112  }
3113  GNUNET_free (bind4_address);
3114  }
3115 
3116  if ((plugin->use_ipv6 == GNUNET_YES) &&
3117  (GNUNET_YES ==
3119  plugin->name,
3120  "BINDTO6",
3121  &bind6_address)))
3122  {
3124  "Binding %s plugin to specific IPv6 address: `%s'\n",
3125  plugin->protocol, bind6_address);
3126  plugin->server_addr_v6 = GNUNET_new (struct sockaddr_in6);
3127  if (1 !=
3128  inet_pton (AF_INET6,
3129  bind6_address,
3130  &plugin->server_addr_v6->sin6_addr))
3131  {
3133  _ ("Specific IPv6 address `%s' in configuration file is invalid!\n"),
3134  bind6_address);
3135  GNUNET_free (bind6_address);
3136  GNUNET_free (plugin->server_addr_v6);
3137  plugin->server_addr_v6 = NULL;
3138  return GNUNET_SYSERR;
3139  }
3140  else
3141  {
3143  "Binding to IPv6 address %s\n",
3144  bind6_address);
3145  plugin->server_addr_v6->sin6_family = AF_INET6;
3146  plugin->server_addr_v6->sin6_port = htons (plugin->port);
3147  }
3148  GNUNET_free (bind6_address);
3149  }
3150 
3151  plugin->verify_external_hostname = GNUNET_NO;
3152 #if BUILD_HTTPS
3153  plugin->verify_external_hostname
3155  plugin->name,
3156  "VERIFY_EXTERNAL_HOSTNAME");
3157  if (GNUNET_SYSERR == plugin->verify_external_hostname)
3158  plugin->verify_external_hostname = GNUNET_NO;
3159  if (GNUNET_YES == plugin->verify_external_hostname)
3161 #endif
3162  external_hostname_use_port
3164  plugin->name,
3165  "EXTERNAL_HOSTNAME_USE_PORT");
3166  if (GNUNET_SYSERR == external_hostname_use_port)
3167  external_hostname_use_port = GNUNET_NO;
3168 
3169 
3170  if (GNUNET_YES ==
3172  plugin->name,
3173  "EXTERNAL_HOSTNAME",
3174  &eh_tmp))
3175  {
3176  char *tmp;
3177  char *pos = NULL;
3178  char *pos_url = NULL;
3179 
3180  if (NULL != strstr (eh_tmp, "://"))
3181  tmp = &strstr (eh_tmp, "://")[3];
3182  else
3183  tmp = eh_tmp;
3184 
3185  if (GNUNET_YES == external_hostname_use_port)
3186  {
3187  if ((strlen (tmp) > 1) && (NULL != (pos = strchr (tmp, '/'))))
3188  {
3189  pos_url = pos + 1;
3190  pos[0] = '\0';
3191  GNUNET_asprintf (&plugin->external_hostname,
3192  "%s:%u/%s",
3193  tmp,
3194  (uint16_t) port,
3195  pos_url);
3196  }
3197  else
3198  GNUNET_asprintf (&plugin->external_hostname,
3199  "%s:%u",
3200  tmp,
3201  (uint16_t) port);
3202  }
3203  else
3204  plugin->external_hostname = GNUNET_strdup (tmp);
3205  GNUNET_free (eh_tmp);
3206 
3208  _ ("Using external hostname `%s'\n"),
3209  plugin->external_hostname);
3210  plugin->notify_ext_task = GNUNET_SCHEDULER_add_now (
3212  plugin);
3213 
3214  /* Use only configured external hostname */
3216  (plugin->env->cfg,
3217  plugin->name,
3218  "EXTERNAL_HOSTNAME_ONLY"))
3219  {
3220  plugin->external_only =
3222  plugin->name,
3223  "EXTERNAL_HOSTNAME_ONLY");
3224  }
3225  else
3226  plugin->external_only = GNUNET_NO;
3227 
3228  if (GNUNET_YES == plugin->external_only)
3230  _ ("Notifying transport only about hostname `%s'\n"),
3231  plugin->external_hostname);
3232  }
3233  else
3235  "No external hostname configured\n");
3236 
3237  /* Optional parameters */
3238  if (GNUNET_OK !=
3240  plugin->name,
3241  "MAX_CONNECTIONS",
3242  &max_connections))
3243  max_connections = 128;
3244  plugin->max_request = max_connections;
3245 
3247  _ ("Maximum number of connections is %u\n"),
3248  plugin->max_request);
3249 
3250  plugin->peer_id_length = strlen (GNUNET_i2s_full (plugin->env->my_identity));
3251 
3252  return GNUNET_OK;
3253 }
3254 
3255 
3262 void *
3264 {
3265  struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
3266  struct HTTP_Server_Plugin *plugin = api->cls;
3267 
3268  if (NULL == api->cls)
3269  {
3270  /* Free for stub mode */
3271  GNUNET_free (api);
3272  return NULL;
3273  }
3274  plugin->in_shutdown = GNUNET_YES;
3276  _ ("Shutting down plugin `%s'\n"),
3277  plugin->name);
3278 
3279  if (NULL != plugin->notify_ext_task)
3280  {
3281  GNUNET_SCHEDULER_cancel (plugin->notify_ext_task);
3282  plugin->notify_ext_task = NULL;
3283  }
3284 
3285  if (NULL != plugin->ext_addr)
3286  {
3288  "Notifying transport to remove address `%s'\n",
3290  plugin->ext_addr->address,
3291  plugin->ext_addr->address_length));
3292 #if BUILD_HTTPS
3293  plugin->env->notify_address (plugin->env->cls,
3294  GNUNET_NO,
3295  plugin->ext_addr);
3296 #else
3297  plugin->env->notify_address (plugin->env->cls,
3298  GNUNET_NO,
3299  plugin->ext_addr);
3300 #endif
3301  GNUNET_HELLO_address_free (plugin->ext_addr);
3302  plugin->ext_addr = NULL;
3303  }
3304 
3305  /* Stop to report addresses to transport service */
3307  if (NULL != plugin->server_v4_task)
3308  {
3309  GNUNET_SCHEDULER_cancel (plugin->server_v4_task);
3310  plugin->server_v4_task = NULL;
3311  }
3312 
3313  if (NULL != plugin->server_v6_task)
3314  {
3315  GNUNET_SCHEDULER_cancel (plugin->server_v6_task);
3316  plugin->server_v6_task = NULL;
3317  }
3318 #if BUILD_HTTPS
3319  GNUNET_free (plugin->crypto_init);
3320  GNUNET_free (plugin->cert);
3321  GNUNET_free (plugin->key);
3322 #endif
3325  plugin);
3327  plugin->sessions = NULL;
3328  if (NULL != plugin->server_v4)
3329  {
3330  MHD_stop_daemon (plugin->server_v4);
3331  plugin->server_v4 = NULL;
3332  }
3333  if (NULL != plugin->server_v6)
3334  {
3335  MHD_stop_daemon (plugin->server_v6);
3336  plugin->server_v6 = NULL;
3337  }
3338  /* Clean up */
3339  GNUNET_free (plugin->external_hostname);
3340  GNUNET_free (plugin->ext_addr);
3341  GNUNET_free (plugin->server_addr_v4);
3342  GNUNET_free (plugin->server_addr_v6);
3343  regfree (&plugin->url_regex);
3344 
3346  _ ("Shutdown for plugin `%s' complete\n"),
3347  plugin->name);
3348 
3349  GNUNET_free (plugin);
3350  GNUNET_free (api);
3351  return NULL;
3352 }
3353 
3354 
3366 static const char *
3368  const void *addr,
3369  size_t addrlen)
3370 {
3372  addr,
3373  addrlen);
3374 }
3375 
3376 
3384 static enum GNUNET_NetworkType
3386  struct GNUNET_ATS_Session *session)
3387 {
3388  return session->scope;
3389 }
3390 
3391 
3399 static enum GNUNET_NetworkType
3401  const struct
3403 {
3404  struct HTTP_Server_Plugin *plugin = cls;
3405 
3407  address);
3408 }
3409 
3410 
3421 static void
3423  const struct GNUNET_PeerIdentity *peer,
3424  struct GNUNET_ATS_Session *session,
3425  struct GNUNET_TIME_Relative delay)
3426 {
3429  "New inbound delay %s\n",
3431  GNUNET_NO));
3432  if (NULL != session->recv_wakeup_task)
3433  {
3435  session->recv_wakeup_task
3437  &server_wake_up,
3438  session);
3439  }
3440 }
3441 
3442 
3452 static int
3454  const struct GNUNET_PeerIdentity *peer,
3455  void *value)
3456 {
3457  struct HTTP_Server_Plugin *plugin = cls;
3458  struct GNUNET_ATS_Session *session = value;
3459 
3461  session,
3463  return GNUNET_OK;
3464 }
3465 
3466 
3479 static void
3482  void *sic_cls)
3483 {
3484  struct HTTP_Server_Plugin *plugin = cls;
3485 
3486  plugin->sic = sic;
3487  plugin->sic_cls = sic_cls;
3488  if (NULL != sic)
3489  {
3492  plugin);
3493  /* signal end of first iteration */
3494  sic (sic_cls, NULL, NULL);
3495  }
3496 }
3497 
3498 
3505 void *
3507 {
3510  struct HTTP_Server_Plugin *plugin;
3511 
3512  if (NULL == env->receive)
3513  {
3514  /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully
3515  initialize the plugin or the API */
3517  api->cls = NULL;
3521  return api;
3522  }
3524  plugin->env = env;
3526  GNUNET_YES);
3527 
3529  api->cls = plugin;
3530  api->send = &http_server_plugin_send;
3536 
3545 #if BUILD_HTTPS
3546  plugin->name = "transport-https_server";
3547  plugin->protocol = "https";
3548 #else
3549  plugin->name = "transport-http_server";
3550  plugin->protocol = "http";
3551 #endif
3552 
3553  if (GNUNET_YES ==
3555  plugin->name,
3556  "TCP_STEALTH"))
3557  {
3558 #ifdef TCP_STEALTH
3559  plugin->options |= HTTP_OPTIONS_TCP_STEALTH;
3560 #else
3562  _ ("TCP_STEALTH not supported on this platform.\n"));
3564  return NULL;
3565 #endif
3566  }
3567 
3568  /* Compile URL regex */
3569  if (regcomp (&plugin->url_regex,
3570  URL_REGEX,
3571  REG_EXTENDED))
3572  {
3574  _ ("Unable to compile URL regex\n"));
3576  return NULL;
3577  }
3578 
3579  /* Configure plugin */
3581  {
3583  return NULL;
3584  }
3585 
3586  /* Check IPv6 support */
3587  if (GNUNET_YES == plugin->use_ipv6)
3588  plugin->use_ipv6 = server_check_ipv6_support (plugin);
3589 
3590  /* Report addresses to transport service */
3591  if (GNUNET_NO == plugin->external_only)
3593 
3595  {
3597  return NULL;
3598  }
3599  return api;
3600 }
3601 
3602 
3603 /* end of plugin_transport_http_server.c */
struct GNUNET_GETOPT_CommandLineOption options[]
Definition: 002.c:5
struct GNUNET_MessageHeader * msg
Definition: 005.c:2
struct GNUNET_MQ_Envelope * env
Definition: 005.c:1
static const struct GNUNET_CONFIGURATION_Handle * cfg
Configuration we are using.
Definition: gnunet-abd.c:36
static int ret
Return value of the commandline.
Definition: gnunet-abd.c:81
static struct GNUNET_TIME_Relative timeout
Desired timeout for the lookup (default is no timeout).
Definition: gnunet-abd.c:61
enum GNUNET_ABD_AlgoDirectionFlags direction
API enum, filled and passed for collect/verify.
Definition: gnunet-abd.c:172
static int res
static uint16_t port
Port number.
Definition: gnunet-bcd.c:147
struct TestcasePlugin * plugin
The process handle to the testbed service.
static char * address
GNS address for this phone.
static unsigned long long max_connections
If there are at least this many connections, old ones will be removed.
static struct MHD_Response * response
Our canonical response.
struct GNUNET_HashCode key
The key used in the DHT.
static char * value
Value of the record to add/remove.
static struct GNUNET_MQ_Envelope * ac
Handle to current GNUNET_PEERINFO_add_peer() operation.
enum State state
current state of profiling
#define info
static struct GNUNET_FS_SearchContext * sc
Definition: gnunet-search.c:87
static struct GNUNET_TIME_Relative delay
When should dkg communication start?
static char * hostname
Our hostname; we give this to all the peers we start.
static char buf[2048]
static char * service_name
Option -s: service name (hash to get service descriptor)
Definition: gnunet-vpn.c:50
#define MHD_RESULT
API to create, modify and access statistics.
Transport service plugin API.
#define GNUNET_MAX_MESSAGE_SIZE
Largest supported message (to be precise, one byte more than the largest possible message,...
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_filename(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, char **value)
Get a configuration value that should be the name of a file or directory.
enum GNUNET_GenericReturnValue 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.
enum GNUNET_GenericReturnValue 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 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.
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_have_value(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option)
Test if we have a value for a particular option.
#define GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT
After how long do we consider a connection to a peer dead if we don't receive messages from the peer?
struct GNUNET_DISK_FileHandle * GNUNET_DISK_file_open(const char *fn, enum GNUNET_DISK_OpenFlags flags, enum GNUNET_DISK_AccessPermissions perm)
Open a file.
Definition: disk.c:1237
enum GNUNET_GenericReturnValue GNUNET_DISK_file_size(const char *filename, uint64_t *size, int include_symbolic_links, int single_file_mode)
Get the size of the file (or directory) of the given file (in bytes).
Definition: disk.c:221
enum GNUNET_GenericReturnValue GNUNET_DISK_file_close(struct GNUNET_DISK_FileHandle *h)
Close an open file.
Definition: disk.c:1308
ssize_t GNUNET_DISK_file_read(const struct GNUNET_DISK_FileHandle *h, void *result, size_t len)
Read the contents of a binary file into a buffer.
Definition: disk.c:622
@ GNUNET_DISK_OPEN_READ
Open the file for reading.
@ GNUNET_DISK_PERM_USER_READ
Owner can read.
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
#define GNUNET_CONTAINER_DLL_insert_tail(head, tail, element)
Insert an element at the tail of a DLL.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
void GNUNET_CONTAINER_multipeermap_destroy(struct GNUNET_CONTAINER_MultiPeerMap *map)
Destroy a hash map.
int GNUNET_CONTAINER_multipeermap_iterate(struct GNUNET_CONTAINER_MultiPeerMap *map, GNUNET_CONTAINER_PeerMapIterator it, void *it_cls)
Iterate over all entries in the map.
struct GNUNET_CONTAINER_MultiPeerMap * GNUNET_CONTAINER_multipeermap_create(unsigned int len, int do_not_copy_keys)
Create a multi peer map (hash map for public keys of peers).
int GNUNET_CONTAINER_multipeermap_get_multiple(struct GNUNET_CONTAINER_MultiPeerMap *map, const struct GNUNET_PeerIdentity *key, GNUNET_CONTAINER_PeerMapIterator it, void *it_cls)
Iterate over all entries in the map that match a particular key.
int GNUNET_CONTAINER_multipeermap_put(struct GNUNET_CONTAINER_MultiPeerMap *map, const struct GNUNET_PeerIdentity *key, void *value, enum GNUNET_CONTAINER_MultiHashMapOption opt)
Store a key-value pair in the map.
enum GNUNET_GenericReturnValue GNUNET_CONTAINER_multipeermap_remove(struct GNUNET_CONTAINER_MultiPeerMap *map, const struct GNUNET_PeerIdentity *key, const void *value)
Remove the given key-value pair from the map.
@ GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE
Allow multiple values with the same key.
struct GNUNET_HELLO_Address * GNUNET_HELLO_address_allocate(const struct GNUNET_PeerIdentity *peer, const char *transport_name, const void *address, size_t address_length, enum GNUNET_HELLO_AddressInfo local_info)
Allocate an address struct.
Definition: address.c:63
#define GNUNET_HELLO_address_free(addr)
Free an address.
@ GNUNET_HELLO_ADDRESS_INFO_INBOUND
This is an inbound address and cannot be used to initiate an outbound connection to another peer.
@ GNUNET_HELLO_ADDRESS_INFO_NONE
No additional information.
#define GNUNET_log(kind,...)
enum GNUNET_GenericReturnValue GNUNET_CRYPTO_eddsa_public_key_from_string(const char *enc, size_t enclen, struct GNUNET_CRYPTO_EddsaPublicKey *pub)
Convert a string representing a public key to a public key.
Definition: crypto_ecc.c:357
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
#define GNUNET_MIN(a, b)
@ GNUNET_SCHEDULER_PRIORITY_DEFAULT
Run with the default priority (normal P2P operations).
@ GNUNET_OK
@ GNUNET_YES
@ GNUNET_NO
@ GNUNET_SYSERR
const char * GNUNET_i2s(const struct GNUNET_PeerIdentity *pid)
Convert a peer identity to a string (for printing debug messages).
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
void GNUNET_log_config_missing(enum GNUNET_ErrorType kind, const char *section, const char *option)
Log error message about missing configuration option.
const char * GNUNET_i2s_full(const struct GNUNET_PeerIdentity *pid)
Convert a peer identity to a string (for printing debug messages).
#define GNUNET_log_strerror(level, cmd)
Log an error message at log-level 'level' that indicates a failure of the command 'cmd' with the mess...
const char * GNUNET_a2s(const struct sockaddr *addr, socklen_t addrlen)
Convert a "struct sockaddr*" (IPv4 or IPv6 address) to a string (for printing debug messages).
@ GNUNET_ERROR_TYPE_WARNING
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_DEBUG
@ GNUNET_ERROR_TYPE_INFO
int int GNUNET_asprintf(char **buf, const char *format,...) __attribute__((format(printf
Like asprintf, just portable.
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_malloc(size)
Wrapper around malloc.
#define GNUNET_free(ptr)
Wrapper around free.
void GNUNET_NAT_unregister(struct GNUNET_NAT_Handle *nh)
Stop port redirection and public IP address detection for the given handle.
Definition: nat_api.c:674
GNUNET_NAT_AddressClass
Some addresses contain sensitive information or are not suitable for global distribution.
struct GNUNET_NAT_Handle * GNUNET_NAT_register(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *config_section, uint8_t proto, unsigned int num_addrs, const struct sockaddr **addrs, const socklen_t *addrlens, GNUNET_NAT_AddressCallback address_callback, GNUNET_NAT_ReversalCallback reversal_callback, void *callback_cls)
Attempt to enable port redirection and detect public IP address contacting UPnP or NAT-PMP routers on...
Definition: nat_api.c:366
struct GNUNET_NETWORK_FDSet * GNUNET_NETWORK_fdset_create(void)
Creates an fd set.
Definition: network.c:1170
enum GNUNET_GenericReturnValue GNUNET_NETWORK_socket_close(struct GNUNET_NETWORK_Handle *desc)
Close a socket.
Definition: network.c:508
void GNUNET_NETWORK_fdset_destroy(struct GNUNET_NETWORK_FDSet *fds)
Releases the associated memory of an fd set.
Definition: network.c:1186
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:1040
struct GNUNET_NETWORK_Handle * GNUNET_NETWORK_socket_create(int domain, int type, int protocol)
Create a new socket.
Definition: network.c:832
GNUNET_NetworkType
Types of networks (with separate quotas) we support.
Definition: gnunet_nt_lib.h:39
struct GNUNET_OS_Process * GNUNET_OS_start_process(enum GNUNET_OS_InheritStdioFlags std_inheritance, struct GNUNET_DISK_PipeHandle *pipe_stdin, struct GNUNET_DISK_PipeHandle *pipe_stdout, struct GNUNET_DISK_PipeHandle *pipe_stderr, const char *filename,...)
Start a process.
Definition: os_priority.c:620
void GNUNET_OS_process_destroy(struct GNUNET_OS_Process *proc)
Cleans up process structure contents (OS-dependent) and deallocates it.
Definition: os_priority.c:260
enum GNUNET_GenericReturnValue GNUNET_OS_process_wait(struct GNUNET_OS_Process *proc)
Wait for a process to terminate.
Definition: os_priority.c:871
@ GNUNET_OS_INHERIT_STD_OUT_AND_ERR
When these flags are set, the child process will inherit stdout and stderr of the parent.
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:1299
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:1830
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:975
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_delayed(struct GNUNET_TIME_Relative delay, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay.
Definition: scheduler.c:1272
enum GNUNET_GenericReturnValue GNUNET_MST_from_buffer(struct GNUNET_MessageStreamTokenizer *mst, const char *buf, size_t size, int purge, int one_shot)
Add incoming data to the receive buffer and call the callback for all complete messages.
Definition: mst.c:101
void GNUNET_MST_destroy(struct GNUNET_MessageStreamTokenizer *mst)
Destroys a tokenizer.
Definition: mst.c:404
struct GNUNET_MessageStreamTokenizer * GNUNET_MST_create(GNUNET_MessageTokenizerCallback cb, void *cb_cls)
Create a message stream tokenizer.
Definition: mst.c:86
void GNUNET_STATISTICS_update(struct GNUNET_STATISTICS_Handle *handle, const char *name, int64_t delta, int make_persistent)
Set statistic value for the peer.
#define GNUNET_TIME_UNIT_SECONDS
One second.
struct GNUNET_TIME_Relative GNUNET_TIME_absolute_get_remaining(struct GNUNET_TIME_Absolute future)
Given a timestamp in the future, how much time remains until then?
Definition: time.c:405
#define GNUNET_TIME_UNIT_MILLISECONDS
One millisecond.
struct GNUNET_TIME_Absolute GNUNET_TIME_relative_to_absolute(struct GNUNET_TIME_Relative rel)
Convert relative time to an absolute time in the future.
Definition: time.c:316
#define GNUNET_TIME_UNIT_ZERO_ABS
Absolute time zero.
const char * GNUNET_STRINGS_relative_time_to_string(struct GNUNET_TIME_Relative delta, int do_round)
Give relative time in human-readable fancy format.
Definition: strings.c:569
void(* GNUNET_TRANSPORT_SessionInfoCallback)(void *cls, struct GNUNET_ATS_Session *session, const struct GNUNET_TRANSPORT_SessionInfo *info)
Function called by the plugin with information about the current sessions managed by the plugin (for ...
void(* GNUNET_TRANSPORT_TransmitContinuation)(void *cls, const struct GNUNET_PeerIdentity *target, int result, size_t size_payload, size_t size_on_wire)
Function called by the GNUNET_TRANSPORT_TransmitFunction upon "completion".
GNUNET_TRANSPORT_SessionState
Possible states of a session in a plugin.
@ GNUNET_TRANSPORT_SS_INIT
The session was created (first call for each session object).
@ GNUNET_TRANSPORT_SS_HANDSHAKE
Initial session handshake is in progress.
@ GNUNET_TRANSPORT_SS_DONE
Session is being torn down and about to disappear.
@ GNUNET_TRANSPORT_SS_UP
Session is fully UP.
@ GNUNET_TRANSPORT_SS_UPDATE
This is just an update about the session, the state did not change.
@ MHD_HTTP_OK
OK [RFC7231, Section 6.3.1].
@ MHD_HTTP_NOT_FOUND
Not Found [RFC7231, Section 6.5.4].
#define max(x, y)
dictionary matches
#define _(String)
GNU gettext support macro.
Definition: platform.h:177
#define VERBOSE_SERVER
const char * http_common_plugin_address_to_string(const char *plugin, const void *addr, size_t addrlen)
Function called for a quick conversion of the binary address to a numeric address.
size_t http_common_address_get_size(const struct HttpAddress *addr)
Get the length of an address.
size_t http_common_cmp_addresses(const void *addr1, size_t addrlen1, const void *addr2, size_t addrlen2)
Compare addr1 to addr2.
int http_common_plugin_string_to_address(void *cls, const char *addr, uint16_t addrlen, void **buf, size_t *added)
Function called to convert a string address to a binary address.
void http_common_plugin_address_pretty_printer(void *cls, const char *type, const void *addr, size_t addrlen, int numeric, struct GNUNET_TIME_Relative timeout, GNUNET_TRANSPORT_AddressStringCallback asc, void *asc_cls)
Convert the transports address to a nice, human-readable format.
struct HttpAddress * http_common_address_from_socket(const char *protocol, const struct sockaddr *addr, socklen_t addrlen)
Create a HTTP address from a socketaddr.
enum GNUNET_NetworkType http_common_get_network_for_address(struct GNUNET_TRANSPORT_PluginEnvironment *env, const struct GNUNET_HELLO_Address *address)
Function obtain the network type for an address.
#define HTTP_SERVER_SESSION_TIMEOUT
@ HTTP_OPTIONS_VERIFY_CERTIFICATE
Verify X509 server certificate, it should be valid.
@ HTTP_OPTIONS_TCP_STEALTH
Enable TCP Stealth-style port knocking.
#define HTTP_SERVER_NOT_VALIDATED_TIMEOUT
#define TIMEOUT_LOG
static void http_server_plugin_setup_monitor(void *cls, GNUNET_TRANSPORT_SessionInfoCallback sic, void *sic_cls)
Begin monitoring sessions of a plugin.
static void server_nat_port_map_callback(void *cls, void **app_ctx, int add_remove, enum GNUNET_NAT_AddressClass ac, const struct sockaddr *addr, socklen_t addrlen)
Our external IP address/port mapping has changed.
#define PLUGIN_NAME
static void server_mhd_connection_timeout(struct HTTP_Server_Plugin *plugin, struct GNUNET_ATS_Session *s, unsigned int to)
Tell MHD that the connection should timeout after to seconds.
#define LIBGNUNET_PLUGIN_TRANSPORT_DONE
static void server_connection_cb(void *cls, struct MHD_Connection *connection, void **socket_context, enum MHD_ConnectionNotificationCode toe)
Callback from MHD when a connection starts/stops.
static void server_start_report_addresses(struct HTTP_Server_Plugin *plugin)
Ask NAT for addresses.
static MHD_RESULT server_accept_cb(void *cls, const struct sockaddr *addr, socklen_t addr_len)
Check if incoming connection is accepted.
static void server_add_address(void *cls, int add_remove, const struct sockaddr *addr, socklen_t addrlen)
Add an address to the server's set of addresses and notify transport.
static void server_session_timeout(void *cls)
Session was idle, so disconnect it.
static struct GNUNET_ATS_Session * http_server_plugin_get_session(void *cls, const struct GNUNET_HELLO_Address *address)
Creates a new outbound session the transport service will use to send data to the peer.
#define OPTION_LONG_POLL
#define _RECEIVE
static void add_cors_headers(struct MHD_Response *response)
Add headers to a request indicating that we allow Cross-Origin Resource Sharing.
static unsigned int http_server_query_keepalive_factor(void *cls)
Function that is called to get the keepalive factor.
static void server_remove_address(void *cls, int add_remove, const struct sockaddr *addr, socklen_t addrlen)
Remove an address from the server's set of addresses and notify transport.
static void server_disconnect_cb(void *cls, struct MHD_Connection *connection, void **httpSessionCache)
Callback from MHD when a connection disconnects.
static int http_server_plugin_address_suggested(void *cls, const void *addr, size_t addrlen)
Another peer has suggested an address for this peer and transport plugin.
static void server_v4_run(void *cls)
Call MHD IPv4 to process pending requests and then go back and schedule the next run.
static int server_parse_url(struct HTTP_Server_Plugin *plugin, const char *url, struct GNUNET_PeerIdentity *target, uint32_t *tag, uint32_t *options)
Parse incoming URL for tag and target.
static void http_server_plugin_update_session_timeout(void *cls, const struct GNUNET_PeerIdentity *peer, struct GNUNET_ATS_Session *session)
Function that will be called whenever the transport service wants to notify the plugin that a session...
static struct ServerRequest * server_lookup_connection(struct HTTP_Server_Plugin *plugin, struct MHD_Connection *mhd_connection, const char *url, const char *method)
Lookup a mhd connection and create one if none is found.
static void server_v6_run(void *cls)
Call MHD IPv6 to process pending requests and then go back and schedule the next run.
static int destroy_session_cb(void *cls, const struct GNUNET_PeerIdentity *peer, void *value)
Terminate session.
#define URL_REGEX
static int server_start(struct HTTP_Server_Plugin *plugin)
Start the HTTP server.
static int session_tag_it(void *cls, const struct GNUNET_PeerIdentity *key, void *value)
Find a session with a matching tag.
static void server_log(void *arg, const char *fmt, va_list ap)
Log function called by MHD.
static void http_server_plugin_disconnect_peer(void *cls, const struct GNUNET_PeerIdentity *target)
Function that can be used to force the plugin to disconnect from the given peer and cancel all previo...
static void server_delete_session(struct GNUNET_ATS_Session *s)
Deletes the session.
static void server_stop_report_addresses(struct HTTP_Server_Plugin *plugin)
Stop NAT for addresses.
static int server_receive_mst_cb(void *cls, const struct GNUNET_MessageHeader *message)
Callback called by MessageStreamTokenizer when a message has arrived.
static ssize_t http_server_plugin_send(void *cls, struct GNUNET_ATS_Session *session, const char *msgbuf, size_t msgbuf_size, unsigned int priority, struct GNUNET_TIME_Relative to, GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls)
Function that can be used by the transport service to transmit a message using the plugin.
#define LIBGNUNET_PLUGIN_TRANSPORT_INIT
static int server_check_ipv6_support(struct HTTP_Server_Plugin *plugin)
Check if IPv6 supported on this system.
static struct GNUNET_SCHEDULER_Task * server_schedule(struct HTTP_Server_Plugin *plugin, struct MHD_Daemon *daemon_handle, int now)
Function that queries MHD's select sets and starts the task waiting for them.
static struct MHD_Daemon * run_mhd_start_daemon(struct HTTP_Server_Plugin *plugin, const struct sockaddr_in *addr, int v6)
Invoke MHD_start_daemon with the various options we need to setup the HTTP server with the given list...
static ssize_t server_send_callback(void *cls, uint64_t pos, char *buf, size_t max)
Callback called by MHD when it needs data to send.
static void notify_session_monitor(struct HTTP_Server_Plugin *plugin, struct GNUNET_ATS_Session *session, enum GNUNET_TRANSPORT_SessionState state)
If a session monitor is attached, notify it about the new session state.
static void server_wake_up(void *cls)
Wake up an MHD connection which was suspended.
static void server_notify_external_hostname(void *cls)
Notify server about our external hostname.
static enum GNUNET_NetworkType http_server_plugin_get_network(void *cls, struct GNUNET_ATS_Session *session)
Function obtain the network type for a session.
static int destroy_session_shutdown_cb(void *cls, const struct GNUNET_PeerIdentity *peer, void *value)
Terminate session during shutdown.
static int http_server_plugin_disconnect_session(void *cls, struct GNUNET_ATS_Session *s)
Disconnect session s by telling MHD to close the connections (reducing timeout, etc....
static void http_server_plugin_update_inbound_delay(void *cls, const struct GNUNET_PeerIdentity *peer, struct GNUNET_ATS_Session *session, struct GNUNET_TIME_Relative delay)
Function that will be called whenever the transport service wants to notify the plugin that the inbou...
static void server_reschedule(struct HTTP_Server_Plugin *plugin, struct MHD_Daemon *server, int now)
Reschedule the execution of both IPv4 and IPv6 server.
static int server_configure_plugin(struct HTTP_Server_Plugin *plugin)
Configure the plugin.
#define LOG(kind,...)
static int server_get_addresses(struct HTTP_Server_Plugin *plugin, const char *service_name, const struct GNUNET_CONFIGURATION_Handle *cfg, struct sockaddr ***addrs, socklen_t **addr_lens)
Get valid server addresses.
static const char * http_server_plugin_address_to_string(void *cls, const void *addr, size_t addrlen)
Function called for a quick conversion of the binary address to a numeric address.
static enum GNUNET_NetworkType http_server_plugin_get_network_for_address(void *cls, const struct GNUNET_HELLO_Address *address)
Function obtain the network type for an address.
static int send_session_info_iter(void *cls, const struct GNUNET_PeerIdentity *peer, void *value)
Return information about the given session to the monitor callback.
static void server_reschedule_session_timeout(struct GNUNET_ATS_Session *s)
Increment session timeout due to activity session s.
#define HTTP_ERROR_RESPONSE
static MHD_RESULT server_access_cb(void *cls, struct MHD_Connection *mhd_connection, const char *url, const char *method, const char *version, const char *upload_data, size_t *upload_data_size, void **httpSessionCache)
MHD callback for a new incoming connection.
static enum GNUNET_NetworkType scope
Which network scope do we belong to?
struct GNUNET_ATS_Session * res
Set to session matching the tag.
uint32_t tag
Tag we are looking for.
Session handle for connections.
struct GNUNET_PeerIdentity target
To whom are we talking to.
struct Plugin * plugin
Pointer to the global plugin struct.
struct ServerRequest * server_recv
Client send handle.
unsigned int msgs_in_queue
Number of messages waiting for transmission to this peer.
int known_to_service
GNUNET_YES if this session is known to the service.
struct GNUNET_TIME_Absolute timeout
When does this session time out.
struct ServerRequest * server_send
Client send handle.
struct HTTP_Message * msg_tail
previous pointer for double linked list
struct HTTP_Server_Plugin * plugin
Pointer to the global plugin struct.
uint32_t tag
Unique HTTP/S connection tag for this connection.
struct GNUNET_HELLO_Address * address
Address.
struct HTTP_Message * msg_head
next pointer for double linked list
enum GNUNET_NetworkType scope
ATS network type.
unsigned long long bytes_in_queue
Number of bytes waiting for transmission to this peer.
struct GNUNET_SCHEDULER_Task * recv_wakeup_task
Task to wake up client receive handle when receiving is allowed again.
struct GNUNET_TIME_Absolute next_receive
Absolute time when to receive data again Used for receive throttling.
struct GNUNET_SCHEDULER_Task * timeout_task
Session timeout task.
struct GNUNET_SERVER_MessageStreamTokenizer * msg_tk
Message stream tokenizer for incoming data.
Internal representation of the hash map.
Handle used to access files (and pipes).
enum GNUNET_FS_SearchOptions options
Options for the search.
Definition: fs_api.h:1598
An address for communicating with a peer.
size_t address_length
Number of bytes in address.
const void * address
Binary representation of the address (plugin-specific).
Header for all communications.
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format.
Handle to a message stream tokenizer.
Definition: mst.c:45
Handle for active NAT registrations.
Definition: nat_api.c:72
collection of IO descriptors
handle to a socket
Definition: network.c:53
The identity of the host (wraps the signing key of the peer).
struct GNUNET_CRYPTO_EddsaPublicKey public_key
Entry in list of pending tasks.
Definition: scheduler.c:136
Time for absolute times used by GNUnet, in microseconds.
Time for relative time used by GNUnet, in microseconds.
uint64_t rel_value_us
The actual value.
The transport service will pass a pointer to a struct of this type as the first and only argument to ...
void * cls
Closure for the various callbacks.
Each plugin is required to return a pointer to a struct of this type as the return value from its ent...
void * cls
Closure for all of the callbacks.
GNUNET_TRANSPORT_TransmitFunction send
Function that the transport service will use to transmit data to another peer.
GNUNET_TRANSPORT_UpdateInboundDelay update_inbound_delay
Function that will be called whenever the transport service wants to notify the plugin that the inbou...
GNUNET_TRANSPORT_SessionMonitorSetup setup_monitor
Function to monitor the sessions managed by the plugin.
GNUNET_TRANSPORT_DisconnectPeerFunction disconnect_peer
Function that can be used to force the plugin to disconnect from the given peer and cancel all previo...
GNUNET_TRANSPORT_GetNetworkTypeForAddress get_network_for_address
Function to obtain the network type for an address.
GNUNET_TRANSPORT_DisconnectSessionFunction disconnect_session
Function that can be used to force the plugin to disconnect from the given peer and cancel all previo...
GNUNET_TRANSPORT_QueryKeepaliveFactorFunction query_keepalive_factor
Function that is used to query keepalive factor.
GNUNET_TRANSPORT_AddressPrettyPrinter address_pretty_printer
Function to pretty-print addresses.
GNUNET_TRANSPORT_AddressToString address_to_string
Function that will be called to convert a binary address to a string (numeric conversion only).
GNUNET_TRANSPORT_GetNetworkType get_network
Function to obtain the network type for a session.
GNUNET_TRANSPORT_CreateSession get_session
Function that will be called tell the plugin to create a session object.
GNUNET_TRANSPORT_CheckAddress check_address
Function that will be called to check if a binary address for this plugin is well-formed and correspo...
GNUNET_TRANSPORT_StringToAddress string_to_address
Function that will be called to convert a string address to binary (numeric conversion only).
GNUNET_TRANSPORT_UpdateSessionTimeout update_session_timeout
Function that will be called whenever the transport service wants to notify the plugin that a session...
Information about a plugin's session.
Message to send using http.
size_t size
buffer length
struct HTTP_Message * next
next pointer for double linked list
size_t pos
amount of data already sent
GNUNET_TRANSPORT_TransmitContinuation transmit_cont
Continuation function to call once the transmission buffer has again space available.
void * transmit_cont_cls
Closure for transmit_cont.
char * buf
buffer containing data to send
struct HTTP_Message * prev
previous pointer for double linked list
size_t overhead
HTTP/S specific overhead.
Encapsulation of all of the state of the plugin.
struct MHD_Daemon * server_v4
MHD IPv4 daemon.
void * sic_cls
Closure for sic.
struct sockaddr_in * server_addr_v4
IPv4 server socket to bind to.
int server_v6_immediately
The IPv6 server is scheduled to run asap.
struct GNUNET_TRANSPORT_PluginEnvironment * env
Our environment.
struct sockaddr_in6 * server_addr_v6
IPv6 server socket to bind to.
GNUNET_TRANSPORT_SessionInfoCallback sic
Function to call about session status changes.
struct MHD_Daemon * server_v6
MHD IPv4 daemon.
struct HttpAddressWrapper * addr_tail
IPv4 addresses DLL tail.
char * external_hostname
External address.
struct GNUNET_SCHEDULER_Task * server_v4_task
MHD IPv4 task.
int server_v4_immediately
The IPv4 server is scheduled to run asap.
struct GNUNET_CONTAINER_MultiPeerMap * sessions
Hash map of open sessions.
struct GNUNET_SCHEDULER_Task * notify_ext_task
Task calling transport service about external address.
uint32_t options
My options to be included in the address.
struct GNUNET_HELLO_Address * ext_addr
External hostname the plugin can be connected to, can be different to the host's FQDN,...
unsigned int cur_request
Current number of sockets the plugin can use Each http connection are two requests.
int peer_id_length
Length of peer id.
struct GNUNET_SCHEDULER_Task * server_v6_task
MHD IPv6 task.
struct HttpAddressWrapper * addr_head
IPv4 addresses DLL head.
int verify_external_hostname
Verify external address.
unsigned int max_request
Maximum number of sockets the plugin can use Each http request /request connections are two connectio...
regex_t url_regex
Regex for parsing URLs.
int in_shutdown
Did we immediately end the session in disconnect_cb.
struct GNUNET_NAT_Handle * nat
NAT handle & address management.
unsigned int external_only
Notify transport only about external address.
Wrapper to manage addresses.
size_t addrlen
Length of the address.
struct HttpAddressWrapper * prev
Linked list previous.
struct HttpAddress * address
An address we are using.
struct HttpAddressWrapper * next
Linked list next.
HTTP addresses including a full URI.
void * addr
Address following.
uint32_t urlen
Length of URL located after struct.
uint32_t options
Address options see enum HttpAddressOptions
struct GNUNET_DATACACHE_PluginEnvironment * env
Our execution environment.
char * protocol
Plugin protocol http, https.
Information we keep with MHD for an HTTP request.
int connected
For PUT requests: Is this the first or last callback with size 0 For GET requests: Have we sent a mes...
struct GNUNET_ATS_Session * session
The session this server connection belongs to.
int direction
_RECV or _SEND
bool suspended
Currently suspended.
struct MHD_Daemon * mhd_daemon
The MHD daemon.
uint32_t options
Options requested by peer.
struct MHD_Connection * mhd_conn
The MHD connection.
struct GNUNET_TESTBED_Peer * peer
The peer associated with this model.