GNUnet  0.10.x
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 
37 
38 
39 #if BUILD_HTTPS
40 #define PLUGIN_NAME "https_server"
41 #define LIBGNUNET_PLUGIN_TRANSPORT_INIT libgnunet_plugin_transport_https_server_init
42 #define LIBGNUNET_PLUGIN_TRANSPORT_DONE libgnunet_plugin_transport_https_server_done
43 #else
44 #define PLUGIN_NAME "http_server"
45 #define LIBGNUNET_PLUGIN_TRANSPORT_INIT libgnunet_plugin_transport_http_server_init
46 #define LIBGNUNET_PLUGIN_TRANSPORT_DONE libgnunet_plugin_transport_http_server_done
47 #endif
48 
49 #define HTTP_ERROR_RESPONSE "<!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>"
50 #define _RECEIVE 0
51 #define _SEND 1
52 
53 
54 #define LOG(kind,...) GNUNET_log_from (kind, "transport-" PLUGIN_NAME,__VA_ARGS__)
55 
56 
60 struct ServerRequest
61 {
67 
71  struct MHD_Connection *mhd_conn;
72 
76  struct MHD_Daemon *mhd_daemon;
77 
81  uint32_t options;
82 #define OPTION_LONG_POLL 1 /* GET request wants long-poll semantics */
83 
87  int direction;
88 
93  int connected;
94 
98  bool suspended;
99 
100 };
101 
102 
107 {
112 
117 
122 
126  size_t addrlen;
127 };
128 
129 
133 struct HTTP_Message
134 {
138  struct HTTP_Message *next;
139 
143  struct HTTP_Message *prev;
144 
148  char *buf;
149 
153  size_t pos;
154 
158  size_t size;
159 
163  size_t overhead;
164 
171 
175  void *transmit_cont_cls;
176 };
177 
178 
182 struct GNUNET_ATS_Session
183 {
184 
189  struct GNUNET_PeerIdentity target;
190 
195 
199  struct HTTP_Message *msg_head;
200 
204  struct HTTP_Message *msg_tail;
205 
209  struct GNUNET_MessageStreamTokenizer *msg_tk;
210 
214  struct ServerRequest *server_recv;
215 
219  struct ServerRequest *server_send;
220 
225 
230  struct GNUNET_TIME_Absolute next_receive;
231 
236 
241 
245  struct GNUNET_SCHEDULER_Task * recv_wakeup_task;
246 
250  unsigned long long bytes_in_queue;
251 
255  unsigned int msgs_in_queue;
256 
260  uint32_t tag;
261 
266 
271 
272 };
273 
274 
279 {
284 
289 
294 
298  void *sic_cls;
299 
303  char *name;
304 
308  char *protocol;
309 
314 
320 
325 
330 
335 
339  struct sockaddr_in *server_addr_v4;
340 
344  struct sockaddr_in6 *server_addr_v6;
345 
349  struct MHD_Daemon *server_v4;
350 
354  struct MHD_Daemon *server_v6;
355 
356 #if BUILD_HTTPS
357 
366  char *crypto_init;
367 
371  char *key;
372 
376  char *cert;
377 #endif
378 
383 
388 
393 
397  unsigned int external_only;
398 
403 
408 
413 
418  unsigned int max_request;
419 
424  unsigned int cur_request;
425 
430 
435 
439  uint32_t options;
440 
444  uint16_t use_ipv6;
445 
449  uint16_t use_ipv4;
450 
454  uint16_t port;
455 
459  regex_t url_regex;
460 
461 };
462 
463 
472 static void
474  struct GNUNET_ATS_Session *session,
476 {
477  struct GNUNET_TRANSPORT_SessionInfo info;
478 
479  if (NULL == plugin->sic)
480  return;
481  memset (&info, 0, sizeof (info));
482  info.state = state;
483  info.is_inbound = GNUNET_YES;
484  info.num_msg_pending = session->msgs_in_queue;
485  info.num_bytes_pending = session->bytes_in_queue;
486  info.receive_delay = session->next_receive;
487  info.session_timeout = session->timeout;
488  info.address = session->address;
489  plugin->sic (plugin->sic_cls,
490  session,
491  &info);
492 }
493 
494 
500 static void
501 server_wake_up (void *cls)
502 {
503  struct GNUNET_ATS_Session *s = cls;
504 
505  s->recv_wakeup_task = NULL;
507  "Session %p: Waking up PUT handle\n",
508  s);
510  MHD_resume_connection (s->server_recv->mhd_conn);
511  s->server_recv->suspended = false;
512 }
513 
514 
523 static void
525  struct MHD_Daemon *server,
526  int now);
527 
528 
534 static void
536 {
537  struct HTTP_Server_Plugin *plugin = s->plugin;
538  struct HTTP_Message *msg;
539 
540  if (NULL != s->timeout_task)
541  {
543  s->timeout_task = NULL;
545  }
546  if (NULL != s->recv_wakeup_task)
547  {
549  s->recv_wakeup_task = NULL;
550  if (NULL != s->server_recv)
551  {
553  s->server_recv->suspended = false;
554  MHD_resume_connection (s->server_recv->mhd_conn);
555  }
556  }
559  &s->target,
560  s));
561  while (NULL != (msg = s->msg_head))
562  {
564  s->msg_tail,
565  msg);
566  if (NULL != msg->transmit_cont)
567  msg->transmit_cont (msg->transmit_cont_cls,
568  &s->target,
570  msg->size,
571  msg->pos + msg->overhead);
572  GNUNET_assert (s->msgs_in_queue > 0);
573  s->msgs_in_queue--;
574  GNUNET_assert (s->bytes_in_queue >= msg->size);
575  s->bytes_in_queue -= msg->size;
576  GNUNET_free (msg);
577  }
578 
579  GNUNET_assert (0 == s->msgs_in_queue);
580  GNUNET_assert (0 == s->bytes_in_queue);
581 
582  if (NULL != s->server_send)
583  {
585  "Server: %p / %p Terminating inbound PUT session to peer `%s'\n",
586  s, s->server_send,
587  GNUNET_i2s (&s->target));
588  s->server_send->session = NULL;
589  MHD_set_connection_option (s->server_send->mhd_conn,
590  MHD_CONNECTION_OPTION_TIMEOUT,
591  1 /* 0 = no timeout, so this is MIN */);
592  if (s->server_send->suspended)
593  {
594  s->server_send->suspended = false;
595  MHD_resume_connection (s->server_send->mhd_conn);
596  }
597  server_reschedule (plugin,
599  GNUNET_YES);
600  }
601 
602  if (NULL != s->server_recv)
603  {
605  "Server: %p / %p Terminating inbound GET session to peer `%s'\n",
606  s, s->server_recv, GNUNET_i2s (&s->target));
607  s->server_recv->session = NULL;
608  MHD_set_connection_option (s->server_recv->mhd_conn,
609  MHD_CONNECTION_OPTION_TIMEOUT,
610  1 /* 0 = no timeout, so this is MIN */);
611  server_reschedule (plugin,
613  GNUNET_YES);
614  }
615  notify_session_monitor (plugin,
616  s,
618  if (GNUNET_YES == s->known_to_service)
619  {
620  plugin->env->session_end (plugin->env->cls,
621  s->address,
622  s);
624  }
625  if (NULL != s->msg_tk)
626  {
628  s->msg_tk = NULL;
629  }
632  "Session %p destroyed\n",
633  s);
634  GNUNET_free (s);
635 }
636 
637 
646 static int
648  struct GNUNET_ATS_Session *s)
649 {
651  return GNUNET_OK;
652 }
653 
654 
660 static void
662 {
663  struct GNUNET_ATS_Session *s = cls;
664  struct GNUNET_TIME_Relative left;
665 
666  s->timeout_task = NULL;
668  if (0 != left.rel_value_us)
669  {
670  /* not actually our turn yet, but let's at least update
671  the monitor, it may think we're about to die ... */
673  s,
677  s);
678  return;
679  }
681  "Session %p was idle for %s, disconnecting\n",
682  s,
684  GNUNET_YES));
686 }
687 
688 
694 static void
696 {
697  GNUNET_assert (NULL != s->timeout_task);
699 }
700 
701 
729 static ssize_t
731  struct GNUNET_ATS_Session *session,
732  const char *msgbuf,
733  size_t msgbuf_size,
734  unsigned int priority,
735  struct GNUNET_TIME_Relative to,
737  void *cont_cls)
738 {
739  struct HTTP_Server_Plugin *plugin = cls;
740  struct HTTP_Message *msg;
741  ssize_t bytes_sent = 0;
742  char *stat_txt;
743 
745  "Session %p/request %p: Sending message with %u to peer `%s'\n",
746  session,
747  session->server_send,
748  msgbuf_size,
749  GNUNET_i2s (&session->target));
750 
751  /* create new message and schedule */
752  bytes_sent = sizeof (struct HTTP_Message) + msgbuf_size;
753  msg = GNUNET_malloc (bytes_sent);
754  msg->next = NULL;
755  msg->size = msgbuf_size;
756  msg->pos = 0;
757  msg->buf = (char *) &msg[1];
758  msg->transmit_cont = cont;
759  msg->transmit_cont_cls = cont_cls;
760  GNUNET_memcpy (msg->buf,
761  msgbuf,
762  msgbuf_size);
764  session->msg_tail,
765  msg);
766  session->msgs_in_queue++;
767  session->bytes_in_queue += msg->size;
768  notify_session_monitor (plugin,
769  session,
771  GNUNET_asprintf (&stat_txt,
772  "# bytes currently in %s_server buffers",
773  plugin->protocol);
775  stat_txt, msgbuf_size, GNUNET_NO);
776  GNUNET_free (stat_txt);
777 
778  if (NULL != session->server_send)
779  {
780  if (session->server_send->suspended)
781  {
782  MHD_resume_connection (session->server_send->mhd_conn);
783  session->server_send->suspended = false;
784  }
785  server_reschedule (session->plugin,
786  session->server_send->mhd_daemon,
787  GNUNET_YES);
788  }
789  return bytes_sent;
790 }
791 
792 
801 static int
803  const struct GNUNET_PeerIdentity *peer,
804  void *value)
805 {
806  struct GNUNET_ATS_Session *s = value;
807  struct ServerRequest *sc_send;
808  struct ServerRequest *sc_recv;
809 
810  sc_send = s->server_send;
811  sc_recv = s->server_recv;
813  if (NULL != sc_send)
814  sc_send->session = NULL;
815  if (NULL != sc_recv)
816  sc_recv->session = NULL;
817 
818  return GNUNET_OK;
819 }
820 
821 
830 static int
832  const struct GNUNET_PeerIdentity *peer,
833  void *value)
834 {
835  struct GNUNET_ATS_Session *s = value;
836 
838  return GNUNET_OK;
839 }
840 
841 
850 static void
852  const struct GNUNET_PeerIdentity *target)
853 {
854  struct HTTP_Server_Plugin *plugin = cls;
855 
857  "Transport tells me to disconnect `%s'\n",
858  GNUNET_i2s (target));
860  target,
862  plugin);
863 }
864 
865 
878 static int
880  const void *addr,
881  size_t addrlen)
882 {
883  struct HTTP_Server_Plugin *plugin = cls;
884  struct HttpAddressWrapper *next;
885  struct HttpAddressWrapper *pos;
886  const struct HttpAddress *haddr = addr;
887 
888  if ((NULL != plugin->ext_addr) &&
889  GNUNET_YES == (http_common_cmp_addresses (addr, addrlen,
890  plugin->ext_addr->address,
891  plugin->ext_addr->address_length)))
892  {
893  /* Checking HTTP_OPTIONS_VERIFY_CERTIFICATE option for external hostname */
894  if ((ntohl (haddr->options) & HTTP_OPTIONS_VERIFY_CERTIFICATE) !=
896  return GNUNET_NO; /* VERIFY option not set as required! */
897  return GNUNET_OK;
898  }
899  next = plugin->addr_head;
900  while (NULL != (pos = next))
901  {
902  next = pos->next;
904  addrlen,
905  pos->address,
906  pos->addrlen)))
907  return GNUNET_OK;
908  }
909  return GNUNET_NO;
910 }
911 
912 
923 static struct GNUNET_ATS_Session *
925  const struct GNUNET_HELLO_Address *address)
926 {
927  return NULL;
928 }
929 
930 
937 static void
938 server_v4_run (void *cls)
939 {
940  struct HTTP_Server_Plugin *plugin = cls;
941 
942  plugin->server_v4_task = NULL;
944  GNUNET_assert (MHD_YES == MHD_run (plugin->server_v4));
945  server_reschedule (plugin, plugin->server_v4, GNUNET_NO);
946 }
947 
948 
955 static void
956 server_v6_run (void *cls)
957 {
958  struct HTTP_Server_Plugin *plugin = cls;
959 
960  plugin->server_v6_task = NULL;
962  GNUNET_assert (MHD_YES == MHD_run (plugin->server_v6));
963  server_reschedule (plugin, plugin->server_v6, GNUNET_NO);
964 }
965 
966 
976 static struct GNUNET_SCHEDULER_Task *
978  struct MHD_Daemon *daemon_handle,
979  int now)
980 {
981  struct GNUNET_SCHEDULER_Task * ret;
982  fd_set rs;
983  fd_set ws;
984  fd_set es;
985  struct GNUNET_NETWORK_FDSet *wrs;
986  struct GNUNET_NETWORK_FDSet *wws;
987  int max;
988  MHD_UNSIGNED_LONG_LONG timeout;
989  static unsigned long long last_timeout = 0;
990  int haveto;
991  struct GNUNET_TIME_Relative tv;
992 
993  if (GNUNET_YES == plugin->in_shutdown)
994  return NULL;
995 
996  ret = NULL;
997  FD_ZERO (&rs);
998  FD_ZERO (&ws);
999  FD_ZERO (&es);
1000  wrs = GNUNET_NETWORK_fdset_create ();
1001  wws = GNUNET_NETWORK_fdset_create ();
1002  max = -1;
1003  GNUNET_assert (MHD_YES ==
1004  MHD_get_fdset (daemon_handle,
1005  &rs,
1006  &ws,
1007  &es,
1008  &max));
1009  haveto = MHD_get_timeout (daemon_handle, &timeout);
1010  if (haveto == MHD_YES)
1011  {
1012  if (timeout != last_timeout)
1013  {
1015  "SELECT Timeout changed from %llu to %llu (ms)\n",
1016  last_timeout, timeout);
1017  last_timeout = timeout;
1018  }
1019  if (timeout <= GNUNET_TIME_UNIT_SECONDS.rel_value_us / 1000LL)
1020  tv.rel_value_us = (uint64_t) timeout * 1000LL;
1021  else
1023  }
1024  else
1026  /* Force immediate run, since we have outbound data to send */
1027  if (now == GNUNET_YES)
1029  GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1);
1030  GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1);
1031 
1032  if (daemon_handle == plugin->server_v4)
1033  {
1034  if (plugin->server_v4_task != NULL)
1035  {
1037  plugin->server_v4_task = NULL;
1038  }
1039 #if 0
1041  "Scheduling IPv4 server task in %llu ms\n",
1042  tv);
1043 #endif
1044  ret =
1046  tv, wrs, wws,
1047  &server_v4_run, plugin);
1048  }
1049  if (daemon_handle == plugin->server_v6)
1050  {
1051  if (plugin->server_v6_task != NULL)
1052  {
1054  plugin->server_v6_task = NULL;
1055  }
1056 #if 0
1058  "Scheduling IPv6 server task in %llu ms\n", tv);
1059 #endif
1060  ret =
1062  tv, wrs, wws,
1063  &server_v6_run, plugin);
1064  }
1067  return ret;
1068 }
1069 
1070 
1079 static void
1081  struct MHD_Daemon *server,
1082  int now)
1083 {
1084  if ((server == plugin->server_v4) && (plugin->server_v4 != NULL))
1085  {
1086  if (GNUNET_YES == plugin->server_v4_immediately)
1087  return; /* No rescheduling, server will run asap */
1088 
1089  if (GNUNET_YES == now)
1091 
1092  if (plugin->server_v4_task != NULL)
1093  {
1095  plugin->server_v4_task = NULL;
1096  }
1097  plugin->server_v4_task = server_schedule (plugin, plugin->server_v4, now);
1098  }
1099 
1100  if ((server == plugin->server_v6) && (plugin->server_v6 != NULL))
1101  {
1102  if (GNUNET_YES == plugin->server_v6_immediately)
1103  return; /* No rescheduling, server will run asap */
1104 
1105  if (GNUNET_YES == now)
1107 
1108  if (plugin->server_v6_task != NULL)
1109  {
1111  plugin->server_v6_task = NULL;
1112  }
1113  plugin->server_v6_task = server_schedule (plugin, plugin->server_v6, now);
1114  }
1115 }
1116 
1117 
1126 static unsigned int
1128 {
1129  return 3;
1130 }
1131 
1132 
1142 static void
1144  const struct GNUNET_PeerIdentity *peer,
1145  struct GNUNET_ATS_Session *session)
1146 {
1148 }
1149 
1150 
1158 static void
1160  struct GNUNET_ATS_Session *s,
1161  unsigned int to)
1162 {
1163  /* Setting timeouts for other connections */
1164  if (NULL != s->server_recv)
1165  {
1167  "Setting timeout for %p to %u sec.\n",
1168  s->server_recv, to);
1169  MHD_set_connection_option (s->server_recv->mhd_conn,
1170  MHD_CONNECTION_OPTION_TIMEOUT,
1171  to);
1173  }
1174  if (NULL != s->server_send)
1175  {
1177  "Setting timeout for %p to %u sec.\n",
1178  s->server_send, to);
1179  MHD_set_connection_option (s->server_send->mhd_conn,
1180  MHD_CONNECTION_OPTION_TIMEOUT,
1181  to);
1183  }
1184 }
1185 
1186 
1197 static int
1199  const char *url,
1200  struct GNUNET_PeerIdentity *target,
1201  uint32_t *tag,
1202  uint32_t *options)
1203 {
1204  regmatch_t matches[4];
1205  const char *tag_start;
1206  const char *target_start;
1207  char *tag_end;
1208  char *options_end;
1209  size_t hash_length;
1210  unsigned long int rc;
1211 
1212  /* URL parsing */
1213 #define URL_REGEX \
1214  ("^.*/([0-9A-Z]+);([0-9]+)(,[0-9]+)?$")
1215 
1216  if (NULL == url)
1217  {
1218  GNUNET_break (0);
1219  return GNUNET_SYSERR;
1220  }
1221 
1222  if (regexec(&plugin->url_regex, url, 4, matches, 0))
1223  {
1225  "URL `%s' did not match regex\n", url);
1226  return GNUNET_SYSERR;
1227  }
1228 
1229  target_start = &url[matches[1].rm_so];
1230  tag_start = &url[matches[2].rm_so];
1231 
1232  /* convert tag */
1233  rc = strtoul (tag_start, &tag_end, 10);
1234  if (&url[matches[2].rm_eo] != tag_end)
1235  {
1237  "URL tag did not line up with submatch\n");
1238  return GNUNET_SYSERR;
1239  }
1240  if (rc == 0)
1241  {
1243  "URL tag is zero\n");
1244  return GNUNET_SYSERR;
1245  }
1246  if ((rc == ULONG_MAX) && (ERANGE == errno))
1247  {
1249  "URL tag > ULONG_MAX\n");
1250  return GNUNET_SYSERR;
1251  }
1252  if (rc > UINT32_MAX)
1253  {
1255  "URL tag > UINT32_MAX\n");
1256  return GNUNET_SYSERR;
1257  }
1258  (*tag) = (uint32_t)rc;
1260  "Found tag `%u' in url\n",
1261  *tag);
1262 
1263  /* convert peer id */
1264  hash_length = matches[1].rm_eo - matches[1].rm_so;
1265  if (hash_length != plugin->peer_id_length)
1266  {
1268  "URL target is %u bytes, expecting %u\n",
1269  hash_length, plugin->peer_id_length);
1270  return GNUNET_SYSERR;
1271  }
1272  if (GNUNET_OK !=
1274  hash_length,
1275  &target->public_key))
1276  {
1278  "URL target conversion failed\n");
1279  return GNUNET_SYSERR;
1280  }
1282  "Found target `%s' in URL\n",
1283  GNUNET_i2s_full (target));
1284 
1285  /* convert options */
1286  if (-1 == matches[3].rm_so)
1287  {
1288  *options = 0;
1289  }
1290  else
1291  {
1292  rc = strtoul (&url[matches[3].rm_so + 1], &options_end, 10);
1293  if (&url[matches[3].rm_eo] != options_end)
1294  {
1296  "URL options did not line up with submatch\n");
1297  return GNUNET_SYSERR;
1298  }
1299  if ((rc == ULONG_MAX) && (ERANGE == errno))
1300  {
1302  "URL options > ULONG_MAX\n");
1303  return GNUNET_SYSERR;
1304  }
1305  if (rc > UINT32_MAX)
1306  {
1308  "URL options > UINT32_MAX\n");
1309  return GNUNET_SYSERR;
1310  }
1311  (*options) = (uint32_t) rc;
1313  "Found options `%u' in url\n",
1314  *options);
1315  }
1316  return GNUNET_OK;
1317 }
1318 
1319 
1324 {
1329 
1333  uint32_t tag;
1334 };
1335 
1336 
1345 static int
1346 session_tag_it (void *cls,
1347  const struct GNUNET_PeerIdentity *key,
1348  void *value)
1349 {
1350  struct GNUNET_ATS_SessionTagContext *stc = cls;
1351  struct GNUNET_ATS_Session *s = value;
1352 
1353  if (s->tag == stc->tag)
1354  {
1355  stc->res = s;
1356  return GNUNET_NO;
1357  }
1358  return GNUNET_YES;
1359 }
1360 
1361 
1371 static struct ServerRequest *
1373  struct MHD_Connection *mhd_connection,
1374  const char *url,
1375  const char *method)
1376 {
1377  struct GNUNET_ATS_Session *s = NULL;
1378  struct ServerRequest *sc = NULL;
1379  const union MHD_ConnectionInfo *conn_info;
1380  struct HttpAddress *addr;
1381  struct GNUNET_PeerIdentity target;
1382  size_t addr_len;
1383  struct GNUNET_ATS_SessionTagContext stc;
1384  uint32_t options;
1385  int direction = GNUNET_SYSERR;
1386  unsigned int to;
1388 
1389  conn_info = MHD_get_connection_info (mhd_connection,
1390  MHD_CONNECTION_INFO_CLIENT_ADDRESS);
1391  if ((conn_info->client_addr->sa_family != AF_INET) &&
1392  (conn_info->client_addr->sa_family != AF_INET6))
1393  return NULL;
1395  "New %s request from %s\n",
1396  method,
1397  url);
1398  stc.tag = 0;
1399  options = 0; /* make gcc happy */
1400  if (GNUNET_SYSERR ==
1401  server_parse_url (plugin, url, &target, &stc.tag, &options))
1402  {
1404  "Invalid url %s\n", url);
1405  return NULL;
1406  }
1407  if (0 == strcmp (MHD_HTTP_METHOD_PUT, method))
1408  direction = _RECEIVE;
1409  else if (0 == strcmp (MHD_HTTP_METHOD_GET, method))
1410  direction = _SEND;
1411  else
1412  {
1414  "Invalid method %s for request from %s\n",
1415  method, url);
1416  return NULL;
1417  }
1418 
1419  plugin->cur_request++;
1421  "New %s request from %s with tag %u (%u of %u)\n",
1422  method,
1423  GNUNET_i2s (&target),
1424  stc.tag,
1425  plugin->cur_request, plugin->max_request);
1426  /* find existing session */
1427  stc.res = NULL;
1429  &target,
1430  &session_tag_it,
1431  &stc);
1432  if (NULL == (s = stc.res))
1433  {
1434  /* create new session */
1435  addr = NULL;
1436  switch (conn_info->client_addr->sa_family)
1437  {
1438  case (AF_INET):
1439  addr = http_common_address_from_socket (plugin->protocol,
1440  conn_info->client_addr,
1441  sizeof (struct sockaddr_in));
1442  addr_len = http_common_address_get_size (addr);
1443  scope = plugin->env->get_address_type (plugin->env->cls,
1444  conn_info->client_addr,
1445  sizeof (struct sockaddr_in));
1446  break;
1447  case (AF_INET6):
1448  addr = http_common_address_from_socket (plugin->protocol,
1449  conn_info->client_addr,
1450  sizeof (struct sockaddr_in6));
1451  addr_len = http_common_address_get_size (addr);
1452  scope = plugin->env->get_address_type (plugin->env->cls,
1453  conn_info->client_addr,
1454  sizeof (struct sockaddr_in6));
1455  break;
1456  default:
1457  /* external host name */
1458  return NULL;
1459  }
1460  s = GNUNET_new (struct GNUNET_ATS_Session);
1461  s->target = target;
1462  s->plugin = plugin;
1463  s->scope = scope;
1465  PLUGIN_NAME,
1466  addr,
1467  addr_len,
1470  s->tag = stc.tag;
1474  s);
1476  &s->target,
1477  s,
1479  notify_session_monitor (plugin,
1480  s,
1482  notify_session_monitor (plugin,
1483  s,
1486  "Creating new session %p for peer `%s' connecting from `%s'\n",
1487  s, GNUNET_i2s (&target),
1489  addr,
1490  addr_len));
1491  GNUNET_free_non_null (addr);
1492  }
1493 
1494  if ( (_RECEIVE == direction) &&
1495  (NULL != s->server_recv) )
1496  {
1498  "Duplicate PUT request from `%s' tag %u, dismissing new request\n",
1499  GNUNET_i2s (&target),
1500  stc.tag);
1501  return NULL;
1502  }
1503  if ((_SEND == direction) && (NULL != s->server_send))
1504  {
1506  "Duplicate GET request from `%s' tag %u, dismissing new request\n",
1507  GNUNET_i2s (&target),
1508  stc.tag);
1509  return NULL;
1510  }
1511  sc = GNUNET_new (struct ServerRequest);
1512  if (conn_info->client_addr->sa_family == AF_INET)
1513  sc->mhd_daemon = plugin->server_v4;
1514  if (conn_info->client_addr->sa_family == AF_INET6)
1515  sc->mhd_daemon = plugin->server_v6;
1516  sc->mhd_conn = mhd_connection;
1517  sc->direction = direction;
1518  sc->connected = GNUNET_NO;
1519  sc->session = s;
1520  sc->options = options;
1521  if (direction == _SEND)
1522  {
1523  s->server_send = sc;
1524  }
1525  if (direction == _RECEIVE)
1526  {
1527  s->server_recv = sc;
1528  }
1529 
1530  if ((GNUNET_NO == s->known_to_service) &&
1531  (NULL != s->server_send) &&
1532  (NULL != s->server_recv) )
1533  {
1535  notify_session_monitor (plugin,
1536  s,
1538  plugin->env->session_start (plugin->env->cls,
1539  s->address,
1540  s,
1541  s->scope);
1542  }
1543 
1544  to = (HTTP_SERVER_SESSION_TIMEOUT.rel_value_us / 1000LL / 1000LL);
1545  server_mhd_connection_timeout (plugin, s, to);
1546  return sc;
1547 }
1548 
1549 
1559 static ssize_t
1561  uint64_t pos,
1562  char *buf,
1563  size_t max)
1564 {
1565  struct ServerRequest *sc = cls;
1566  struct GNUNET_ATS_Session *s = sc->session;
1567  ssize_t bytes_read = 0;
1568  struct HTTP_Message *msg;
1569  char *stat_txt;
1570 
1571  if (NULL == s)
1572  {
1573  /* session is disconnecting */
1574  return 0;
1575  }
1576 
1577  sc = s->server_send;
1578  if (NULL == sc)
1579  return 0;
1580  msg = s->msg_head;
1581  if (NULL != msg)
1582  {
1583  /* sending */
1584  bytes_read = GNUNET_MIN (msg->size - msg->pos,
1585  max);
1586  GNUNET_memcpy (buf, &msg->buf[msg->pos], bytes_read);
1587  msg->pos += bytes_read;
1588 
1589  /* removing message */
1590  if (msg->pos == msg->size)
1591  {
1593  s->msg_tail,
1594  msg);
1595  if (NULL != msg->transmit_cont)
1597  msg->size, msg->size + msg->overhead);
1598  GNUNET_assert (s->msgs_in_queue > 0);
1599  s->msgs_in_queue--;
1600  GNUNET_assert (s->bytes_in_queue >= msg->size);
1601  s->bytes_in_queue -= msg->size;
1602  GNUNET_free (msg);
1604  s,
1606  }
1607  }
1608  if (0 < bytes_read)
1609  {
1610  sc->connected = GNUNET_YES;
1612  "Sent %u bytes to peer `%s' with session %p \n",
1613  bytes_read,
1614  GNUNET_i2s (&s->target),
1615  s);
1616  GNUNET_asprintf (&stat_txt,
1617  "# bytes currently in %s_server buffers",
1618  s->plugin->protocol);
1619  GNUNET_STATISTICS_update (s->plugin->env->stats,
1620  stat_txt,
1621  - bytes_read,
1622  GNUNET_NO);
1623  GNUNET_free (stat_txt);
1624  GNUNET_asprintf (&stat_txt,
1625  "# bytes transmitted via %s_server",
1626  s->plugin->protocol);
1627  GNUNET_STATISTICS_update (s->plugin->env->stats,
1628  stat_txt, bytes_read, GNUNET_NO);
1629  GNUNET_free (stat_txt);
1630  }
1631  else if ((sc->options & OPTION_LONG_POLL) && sc->connected)
1632  {
1634  "Completing GET response to peer `%s' with session %p\n",
1635  GNUNET_i2s (&s->target),
1636  s);
1637  return MHD_CONTENT_READER_END_OF_STREAM;
1638  }
1639  else
1640  {
1641  MHD_suspend_connection (s->server_send->mhd_conn);
1642  s->server_send->suspended = true;
1643  return 0;
1644  }
1645  return bytes_read;
1646 }
1647 
1648 
1656 static int
1658  const struct GNUNET_MessageHeader *message)
1659 {
1660  struct GNUNET_ATS_Session *s = cls;
1661  struct HTTP_Server_Plugin *plugin = s->plugin;
1662  struct GNUNET_TIME_Relative delay;
1663  char *stat_txt;
1664 
1665  if (GNUNET_NO == s->known_to_service)
1666  {
1668  plugin->env->session_start (plugin->env->cls,
1669  s->address,
1670  s,
1671  s->scope);
1672  notify_session_monitor (plugin,
1673  s,
1675  }
1676  delay = plugin->env->receive (plugin->env->cls,
1677  s->address,
1678  s,
1679  message);
1680  GNUNET_asprintf (&stat_txt,
1681  "# bytes received via %s_server",
1682  plugin->protocol);
1684  stat_txt,
1685  ntohs (message->size),
1686  GNUNET_NO);
1687  GNUNET_free (stat_txt);
1689  if (delay.rel_value_us > 0)
1690  {
1692  "Peer `%s' address `%s' next read delayed for %s\n",
1693  GNUNET_i2s (&s->target),
1695  s->address->address,
1696  s->address->address_length),
1698  GNUNET_YES));
1699  }
1701  return GNUNET_OK;
1702 }
1703 
1704 
1711 static void
1712 add_cors_headers(struct MHD_Response *response)
1713 {
1714  MHD_add_response_header (response,
1715  "Access-Control-Allow-Origin",
1716  "*");
1717  MHD_add_response_header (response,
1718  "Access-Control-Allow-Methods",
1719  "GET, PUT, OPTIONS");
1720  MHD_add_response_header (response,
1721  "Access-Control-Max-Age",
1722  "86400");
1723 }
1724 
1725 
1739 static int
1740 server_access_cb (void *cls,
1741  struct MHD_Connection *mhd_connection,
1742  const char *url,
1743  const char *method,
1744  const char *version,
1745  const char *upload_data,
1746  size_t *upload_data_size,
1747  void **httpSessionCache)
1748 {
1749  struct HTTP_Server_Plugin *plugin = cls;
1750  struct ServerRequest *sc = *httpSessionCache;
1751  struct GNUNET_ATS_Session *s;
1752  struct MHD_Response *response;
1753  int res = MHD_YES;
1754 
1756  _("Access from connection %p (%u of %u) for `%s' `%s' url `%s' with upload data size %u\n"),
1757  sc,
1758  plugin->cur_request,
1759  plugin->max_request,
1760  method,
1761  version,
1762  url,
1763  (*upload_data_size));
1764  if (NULL == sc)
1765  {
1766  /* CORS pre-flight request */
1767  if (0 == strcmp (MHD_HTTP_METHOD_OPTIONS, method))
1768  {
1769  response = MHD_create_response_from_buffer (0, NULL,
1770  MHD_RESPMEM_PERSISTENT);
1771  add_cors_headers(response);
1772  res = MHD_queue_response (mhd_connection, MHD_HTTP_OK, response);
1773  MHD_destroy_response (response);
1774  return res;
1775  }
1776  /* new connection */
1777  sc = server_lookup_connection (plugin, mhd_connection, url, method);
1778  if (NULL != sc)
1779  {
1780  /* attach to new / existing session */
1781  (*httpSessionCache) = sc;
1782  }
1783  else
1784  {
1785  /* existing session already has matching connection, refuse */
1786  response = MHD_create_response_from_buffer (strlen (HTTP_ERROR_RESPONSE),
1788  MHD_RESPMEM_PERSISTENT);
1789  MHD_add_response_header (response,
1790  MHD_HTTP_HEADER_CONTENT_TYPE,
1791  "text/html");
1792  add_cors_headers(response);
1793  res = MHD_queue_response (mhd_connection, MHD_HTTP_NOT_FOUND, response);
1794  MHD_destroy_response (response);
1795  return res;
1796  }
1797  }
1798  /* 'old' connection */
1799  if (NULL == (s = sc->session))
1800  {
1801  /* Session was already disconnected;
1802  sent HTTP/1.1: 200 OK as response */
1803  response = MHD_create_response_from_buffer (strlen ("Thank you!"),
1804  "Thank you!",
1805  MHD_RESPMEM_PERSISTENT);
1806  add_cors_headers(response);
1807  MHD_queue_response (mhd_connection, MHD_HTTP_OK, response);
1808  MHD_destroy_response (response);
1809  return MHD_YES;
1810  }
1811 
1812  if (sc->direction == _SEND)
1813  {
1814  response = MHD_create_response_from_callback (MHD_SIZE_UNKNOWN, 32 * 1024,
1815  &server_send_callback, sc, NULL);
1816  add_cors_headers(response);
1817  MHD_queue_response (mhd_connection, MHD_HTTP_OK, response);
1818  MHD_destroy_response (response);
1819  return MHD_YES;
1820  }
1821  if (sc->direction == _RECEIVE)
1822  {
1823  if ((*upload_data_size == 0) && (sc->connected == GNUNET_NO))
1824  {
1825  /* (*upload_data_size == 0) first callback when header are passed */
1827  "Session %p / Connection %p: Peer `%s' PUT on address `%s' connected\n",
1828  s, sc,
1829  GNUNET_i2s (&s->target),
1831  s->address->address,
1832  s->address->address_length));
1833  sc->connected = GNUNET_YES;
1834  return MHD_YES;
1835  }
1836  else if ((*upload_data_size == 0) && (sc->connected == GNUNET_YES))
1837  {
1838  /* (*upload_data_size == 0) when upload is complete */
1840  "Session %p / Connection %p: Peer `%s' PUT on address `%s' finished upload\n",
1841  s, sc,
1842  GNUNET_i2s (&s->target),
1844  s->address->address,
1845  s->address->address_length));
1846  sc->connected = GNUNET_NO;
1847  /* Sent HTTP/1.1: 200 OK as PUT Response\ */
1848  response = MHD_create_response_from_buffer (strlen ("Thank you!"),
1849  "Thank you!",
1850  MHD_RESPMEM_PERSISTENT);
1851  add_cors_headers(response);
1852  MHD_queue_response (mhd_connection, MHD_HTTP_OK, response);
1853  MHD_destroy_response (response);
1854  return MHD_YES;
1855  }
1856  else if ((*upload_data_size > 0) && (sc->connected == GNUNET_YES))
1857  {
1858  struct GNUNET_TIME_Relative delay;
1859 
1860  /* (*upload_data_size > 0) for every segment received */
1862  "Session %p / Connection %p: Peer `%s' PUT on address `%s' received %u bytes\n",
1863  s, sc,
1864  GNUNET_i2s (&s->target),
1866  s->address->address,
1867  s->address->address_length),
1868  *upload_data_size);
1870  if (0 == delay.rel_value_us)
1871  {
1873  "PUT with %u bytes forwarded to MST\n",
1874  *upload_data_size);
1875  if (s->msg_tk == NULL)
1876  {
1878  s);
1879  }
1881  upload_data,
1882  *upload_data_size,
1883  GNUNET_NO, GNUNET_NO);
1884  server_mhd_connection_timeout (plugin, s,
1885  GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value_us / 1000LL
1886  / 1000LL);
1887  (*upload_data_size) = 0;
1888  }
1889  else
1890  {
1891  /* delay processing */
1893  "Session %p / Connection %p: no inbound bandwidth available! Next read was delayed by %s\n",
1894  s,
1895  sc,
1897  GNUNET_YES));
1898  GNUNET_assert(s->server_recv->mhd_conn == mhd_connection);
1899  MHD_suspend_connection (s->server_recv->mhd_conn);
1900  s->server_recv->suspended = true;
1901  if (NULL == s->recv_wakeup_task)
1902  s->recv_wakeup_task
1904  &server_wake_up,
1905  s);
1906  }
1907  return MHD_YES;
1908  }
1909  else
1910  {
1911  GNUNET_break (0);
1912  return MHD_NO;
1913  }
1914  }
1915  return res;
1916 }
1917 
1918 
1926 static void
1928  struct MHD_Connection *connection,
1929  void **httpSessionCache)
1930 {
1931  struct HTTP_Server_Plugin *plugin = cls;
1932  struct ServerRequest *sc = *httpSessionCache;
1933 
1935  "Disconnect for connection %p\n",
1936  sc);
1937  if (NULL == sc)
1938  {
1939  /* CORS pre-flight request finished */
1940  return;
1941  }
1942 
1943  if (NULL != sc->session)
1944  {
1945  if (sc->direction == _SEND)
1946  {
1948  "Peer `%s' connection %p, GET on address `%s' disconnected\n",
1949  GNUNET_i2s (&sc->session->target),
1950  sc->session->server_send,
1952  sc->session->address->address,
1953  sc->session->address->address_length));
1954 
1955  sc->session->server_send = NULL;
1956  }
1957  else if (sc->direction == _RECEIVE)
1958  {
1960  "Peer `%s' connection %p PUT on address `%s' disconnected\n",
1961  GNUNET_i2s (&sc->session->target),
1962  sc->session->server_recv,
1964  sc->session->address->address,
1965  sc->session->address->address_length));
1966  sc->session->server_recv = NULL;
1967  if (NULL != sc->session->msg_tk)
1968  {
1970  sc->session->msg_tk = NULL;
1971  }
1972  }
1973  }
1974  GNUNET_free (sc);
1975  plugin->cur_request--;
1976 }
1977 
1978 
1988 static void
1990  struct MHD_Connection *connection,
1991  void **socket_context,
1992  enum MHD_ConnectionNotificationCode toe)
1993 {
1994  struct HTTP_Server_Plugin *plugin = cls;
1995  const union MHD_ConnectionInfo *info;
1996 
1997  if (MHD_CONNECTION_NOTIFY_STARTED == toe)
1998  return;
1999 
2000  /* Reschedule to remove closed socket from our select set */
2001  info = MHD_get_connection_info (connection,
2002  MHD_CONNECTION_INFO_DAEMON);
2003  GNUNET_assert (NULL != info);
2004  server_reschedule (plugin,
2005  info->daemon,
2006  GNUNET_YES);
2007 }
2008 
2009 
2018 static int
2019 server_accept_cb (void *cls,
2020  const struct sockaddr *addr,
2021  socklen_t addr_len)
2022 {
2023  struct HTTP_Server_Plugin *plugin = cls;
2024 
2025  if (plugin->cur_request <= plugin->max_request)
2026  {
2028  _("Accepting connection (%u of %u) from `%s'\n"),
2029  plugin->cur_request, plugin->max_request,
2030  GNUNET_a2s (addr, addr_len));
2031  return MHD_YES;
2032  }
2033  else
2034  {
2036  _("Server reached maximum number connections (%u), rejecting new connection\n"),
2037  plugin->max_request);
2038  return MHD_NO;
2039  }
2040 }
2041 
2042 
2051 static void
2053  const char *fmt,
2054  va_list ap)
2055 {
2056  char text[1024];
2057 
2058  vsnprintf (text,
2059  sizeof (text),
2060  fmt,
2061  ap);
2063  "Server: %s\n",
2064  text);
2065 }
2066 
2067 
2068 #if BUILD_HTTPS
2069 
2075 static char *
2076 server_load_file (const char *file)
2077 {
2078  struct GNUNET_DISK_FileHandle *gn_file;
2079  uint64_t fsize;
2080  char *text = NULL;
2081 
2082  if (GNUNET_OK != GNUNET_DISK_file_size (file,
2083  &fsize, GNUNET_NO, GNUNET_YES))
2084  return NULL;
2085  text = GNUNET_malloc (fsize + 1);
2086  gn_file =
2089  if (NULL == gn_file)
2090  {
2091  GNUNET_free (text);
2092  return NULL;
2093  }
2094  if (GNUNET_SYSERR == GNUNET_DISK_file_read (gn_file, text, fsize))
2095  {
2096  GNUNET_free (text);
2097  GNUNET_DISK_file_close (gn_file);
2098  return NULL;
2099  }
2100  text[fsize] = '\0';
2101  GNUNET_DISK_file_close (gn_file);
2102  return text;
2103 }
2104 #endif
2105 
2106 
2107 #if BUILD_HTTPS
2108 
2114 static int
2115 server_load_certificate (struct HTTP_Server_Plugin *plugin)
2116 {
2117  int res = GNUNET_OK;
2118  char *key_file;
2119  char *cert_file;
2120 
2121 
2122  if (GNUNET_OK !=
2124  plugin->name,
2125  "KEY_FILE", &key_file))
2126  {
2128  plugin->name, "CERT_FILE");
2129  return GNUNET_SYSERR;
2130  }
2131  if (GNUNET_OK !=
2133  plugin->name,
2134  "CERT_FILE", &cert_file))
2135  {
2137  plugin->name, "CERT_FILE");
2138  GNUNET_free (key_file);
2139  return GNUNET_SYSERR;
2140  }
2141  /* Get crypto init string from config. If not present, use
2142  * default values */
2143  if (GNUNET_OK ==
2145  plugin->name,
2146  "CRYPTO_INIT",
2147  &plugin->crypto_init))
2149  "Using crypto init string `%s'\n",
2150  plugin->crypto_init);
2151  else
2153  "Using default crypto init string \n");
2154 
2155  /* read key & certificates from file */
2157  "Trying to loading TLS certificate from key-file `%s' cert-file`%s'\n",
2158  key_file, cert_file);
2159 
2160  plugin->key = server_load_file (key_file);
2161  plugin->cert = server_load_file (cert_file);
2162 
2163  if ((plugin->key == NULL) || (plugin->cert == NULL))
2164  {
2165  struct GNUNET_OS_Process *cert_creation;
2166 
2167  GNUNET_free_non_null (plugin->key);
2168  plugin->key = NULL;
2169  GNUNET_free_non_null (plugin->cert);
2170  plugin->cert = NULL;
2171 
2173  "No usable TLS certificate found, creating certificate\n");
2174  errno = 0;
2175  cert_creation =
2177  NULL, NULL, NULL,
2178  "gnunet-transport-certificate-creation",
2179  "gnunet-transport-certificate-creation",
2180  key_file,
2181  cert_file,
2182  NULL);
2183  if (NULL == cert_creation)
2184  {
2186  _("Could not create a new TLS certificate, program `gnunet-transport-certificate-creation' could not be started!\n"));
2187  GNUNET_free (key_file);
2188  GNUNET_free (cert_file);
2189 
2190  GNUNET_free_non_null (plugin->key);
2191  plugin->key = NULL;
2192  GNUNET_free_non_null (plugin->cert);
2193  plugin->cert = NULL;
2194  GNUNET_free_non_null (plugin->crypto_init);
2195  plugin->crypto_init = NULL;
2196 
2197  return GNUNET_SYSERR;
2198  }
2199  GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (cert_creation));
2200  GNUNET_OS_process_destroy (cert_creation);
2201 
2202  plugin->key = server_load_file (key_file);
2203  plugin->cert = server_load_file (cert_file);
2204  }
2205 
2206  if ((plugin->key == NULL) || (plugin->cert == NULL))
2207  {
2209  _("No usable TLS certificate found and creating one at `%s/%s' failed!\n"),
2210  key_file, cert_file);
2211  GNUNET_free (key_file);
2212  GNUNET_free (cert_file);
2213 
2214  GNUNET_free_non_null (plugin->key);
2215  plugin->key = NULL;
2216  GNUNET_free_non_null (plugin->cert);
2217  plugin->cert = NULL;
2218  GNUNET_free_non_null (plugin->crypto_init);
2219  plugin->crypto_init = NULL;
2220 
2221  return GNUNET_SYSERR;
2222  }
2223  GNUNET_free (key_file);
2224  GNUNET_free (cert_file);
2226  "TLS certificate loaded\n");
2227  return res;
2228 }
2229 #endif
2230 
2231 
2241 static struct MHD_Daemon *
2243  const struct sockaddr_in *addr,
2244  int v6)
2245 {
2246  struct MHD_Daemon *server;
2247  unsigned int timeout;
2248 
2249 #if MHD_VERSION >= 0x00090E00
2250  timeout = HTTP_SERVER_NOT_VALIDATED_TIMEOUT.rel_value_us / 1000LL / 1000LL;
2252  "MHD can set timeout per connection! Default time out %u sec.\n",
2253  timeout);
2254 #else
2255  timeout = HTTP_SERVER_SESSION_TIMEOUT.rel_value_us / 1000LL / 1000LL;
2257  "MHD cannot set timeout per connection! Default time out %u sec.\n",
2258  timeout);
2259 #endif
2260  server = MHD_start_daemon (
2261 #if VERBOSE_SERVER
2262  MHD_USE_DEBUG |
2263 #endif
2264 #if BUILD_HTTPS
2265  MHD_USE_SSL |
2266 #endif
2267  MHD_USE_SUSPEND_RESUME |
2268  v6,
2269  plugin->port,
2270  &server_accept_cb, plugin,
2271  &server_access_cb, plugin,
2272  MHD_OPTION_SOCK_ADDR,
2273  addr,
2274  MHD_OPTION_CONNECTION_LIMIT,
2275  (unsigned int) plugin->max_request,
2276 #if BUILD_HTTPS
2277  MHD_OPTION_HTTPS_PRIORITIES,
2278  plugin->crypto_init,
2279  MHD_OPTION_HTTPS_MEM_KEY,
2280  plugin->key,
2281  MHD_OPTION_HTTPS_MEM_CERT,
2282  plugin->cert,
2283 #endif
2284  MHD_OPTION_CONNECTION_TIMEOUT,
2285  timeout,
2286  MHD_OPTION_CONNECTION_MEMORY_LIMIT,
2287  (size_t) (2 *
2289  MHD_OPTION_NOTIFY_COMPLETED,
2290  &server_disconnect_cb, plugin,
2291  MHD_OPTION_NOTIFY_CONNECTION,
2292  &server_connection_cb, plugin,
2293  MHD_OPTION_EXTERNAL_LOGGER,
2294  &server_log, NULL,
2295  MHD_OPTION_END);
2296 #ifdef TCP_STEALTH
2297  if ( (NULL != server) &&
2298  (0 != (plugin->options & HTTP_OPTIONS_TCP_STEALTH)) )
2299  {
2300  const union MHD_DaemonInfo *di;
2301 
2302  di = MHD_get_daemon_info (server,
2303  MHD_DAEMON_INFO_LISTEN_FD,
2304  NULL);
2305  if ( (0 != setsockopt ((int) di->listen_fd,
2306  IPPROTO_TCP,
2307  TCP_STEALTH,
2308  plugin->env->my_identity,
2309  sizeof (struct GNUNET_PeerIdentity))) )
2310  {
2312  _("TCP_STEALTH not supported on this platform.\n"));
2313  MHD_stop_daemon (server);
2314  server = NULL;
2315  }
2316  }
2317 #endif
2318  return server;
2319 }
2320 
2321 
2328 static int
2330 {
2331  const char *msg;
2332 
2333  GNUNET_assert (NULL != plugin);
2334 #if BUILD_HTTPS
2335  if (GNUNET_SYSERR == server_load_certificate (plugin))
2336  {
2338  _("Could not load or create server certificate! Loading plugin failed!\n"));
2339  return GNUNET_SYSERR;
2340  }
2341 #endif
2342 
2343 
2344 
2345  plugin->server_v4 = NULL;
2346  if (GNUNET_YES == plugin->use_ipv4)
2347  {
2348  plugin->server_v4
2349  = run_mhd_start_daemon (plugin,
2350  (const struct sockaddr_in *) plugin->server_addr_v4,
2351  MHD_NO_FLAG);
2352 
2353  if (NULL == plugin->server_v4)
2354  {
2356  "Failed to start %s IPv4 server component on port %u\n",
2357  plugin->name,
2358  plugin->port);
2359  }
2360  else
2361  server_reschedule (plugin,
2362  plugin->server_v4,
2363  GNUNET_NO);
2364  }
2365 
2366 
2367  plugin->server_v6 = NULL;
2368  if (GNUNET_YES == plugin->use_ipv6)
2369  {
2370  plugin->server_v6
2371  = run_mhd_start_daemon (plugin,
2372  (const struct sockaddr_in *) plugin->server_addr_v6,
2373  MHD_USE_IPv6);
2374  if (NULL == plugin->server_v6)
2375  {
2377  "Failed to start %s IPv6 server component on port %u\n",
2378  plugin->name,
2379  plugin->port);
2380  }
2381  else
2382  {
2383  server_reschedule (plugin,
2384  plugin->server_v6,
2385  GNUNET_NO);
2386  }
2387  }
2388  msg = "No";
2389  if ( (NULL == plugin->server_v6) &&
2390  (NULL == plugin->server_v4) )
2391  {
2393  "%s %s server component started on port %u\n",
2394  msg,
2395  plugin->name,
2396  plugin->port);
2397  return GNUNET_SYSERR;
2398  }
2399  if ((NULL != plugin->server_v6) &&
2400  (NULL != plugin->server_v4))
2401  msg = "IPv4 and IPv6";
2402  else if (NULL != plugin->server_v6)
2403  msg = "IPv6";
2404  else if (NULL != plugin->server_v4)
2405  msg = "IPv4";
2407  "%s %s server component started on port %u\n",
2408  msg,
2409  plugin->name,
2410  plugin->port);
2411  return GNUNET_OK;
2412 }
2413 
2414 
2423 static void
2425  int add_remove,
2426  const struct sockaddr *addr,
2427  socklen_t addrlen)
2428 {
2429  struct HTTP_Server_Plugin *plugin = cls;
2430  struct GNUNET_HELLO_Address *address;
2431  struct HttpAddressWrapper *w = NULL;
2432 
2433  w = GNUNET_new (struct HttpAddressWrapper);
2435  addr,
2436  addrlen);
2437  if (NULL == w->address)
2438  {
2439  GNUNET_free (w);
2440  return;
2441  }
2443 
2445  plugin->addr_tail,
2446  w);
2448  "Notifying transport to add address `%s'\n",
2450  w->address,
2451  w->addrlen));
2452  /* modify our published address list */
2453 #if BUILD_HTTPS
2454  address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
2455  "https_client", w->address, w->addrlen, GNUNET_HELLO_ADDRESS_INFO_NONE);
2456 #else
2457  address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
2458  "http_client", w->address, w->addrlen, GNUNET_HELLO_ADDRESS_INFO_NONE);
2459 #endif
2460 
2461  plugin->env->notify_address (plugin->env->cls,
2462  add_remove,
2463  address);
2464  GNUNET_HELLO_address_free (address);
2465 }
2466 
2467 
2476 static void
2478  int add_remove,
2479  const struct sockaddr *addr,
2480  socklen_t addrlen)
2481 {
2482  struct HTTP_Server_Plugin *plugin = cls;
2483  struct GNUNET_HELLO_Address *address;
2484  struct HttpAddressWrapper *w = plugin->addr_head;
2485  size_t saddr_len;
2486  void * saddr;
2487 
2488  saddr = http_common_address_from_socket (plugin->protocol,
2489  addr,
2490  addrlen);
2491  if (NULL == saddr)
2492  return;
2493  saddr_len = http_common_address_get_size (saddr);
2494 
2495  while (NULL != w)
2496  {
2497  if (GNUNET_YES ==
2499  w->addrlen,
2500  saddr,
2501  saddr_len))
2502  break;
2503  w = w->next;
2504  }
2505  GNUNET_free (saddr);
2506 
2507  if (NULL == w)
2508  return;
2509 
2511  "Notifying transport to remove address `%s'\n",
2513  w->address,
2514  w->addrlen));
2516  plugin->addr_tail,
2517  w);
2518  /* modify our published address list */
2519 #if BUILD_HTTPS
2520  address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
2521  "https_client", w->address, w->addrlen, GNUNET_HELLO_ADDRESS_INFO_NONE);
2522 #else
2523  address = GNUNET_HELLO_address_allocate (plugin->env->my_identity,
2524  "http_client", w->address, w->addrlen, GNUNET_HELLO_ADDRESS_INFO_NONE);
2525 #endif
2526  plugin->env->notify_address (plugin->env->cls, add_remove, address);
2527  GNUNET_HELLO_address_free (address);
2528  GNUNET_free (w->address);
2529  GNUNET_free (w);
2530 }
2531 
2532 
2533 
2546 static void
2548  void **app_ctx,
2549  int add_remove,
2551  const struct sockaddr *addr,
2552  socklen_t addrlen)
2553 {
2554  struct HTTP_Server_Plugin *plugin = cls;
2555 
2556  (void) app_ctx;
2558  "NAT called to %s address `%s'\n",
2559  (add_remove == GNUNET_NO) ? "remove" : "add",
2560  GNUNET_a2s (addr, addrlen));
2561 
2562  if (AF_INET == addr->sa_family)
2563  {
2564  struct sockaddr_in *s4 = (struct sockaddr_in *) addr;
2565 
2566  if (GNUNET_NO == plugin->use_ipv4)
2567  return;
2568 
2569  if ((NULL != plugin->server_addr_v4) &&
2570  (0 != memcmp (&plugin->server_addr_v4->sin_addr,
2571  &s4->sin_addr,
2572  sizeof (struct in_addr))))
2573  {
2575  "Skipping address `%s' (not bindto address)\n",
2576  GNUNET_a2s (addr, addrlen));
2577  return;
2578  }
2579  }
2580 
2581  if (AF_INET6 == addr->sa_family)
2582  {
2583  struct sockaddr_in6 *s6 = (struct sockaddr_in6 *) addr;
2584  if (GNUNET_NO == plugin->use_ipv6)
2585  return;
2586 
2587  if ((NULL != plugin->server_addr_v6) &&
2588  (0 != memcmp (&plugin->server_addr_v6->sin6_addr,
2589  &s6->sin6_addr, sizeof (struct in6_addr))))
2590  {
2592  "Skipping address `%s' (not bindto address)\n",
2593  GNUNET_a2s (addr, addrlen));
2594  return;
2595  }
2596  }
2597 
2598  switch (add_remove)
2599  {
2600  case GNUNET_YES:
2601  server_add_address (cls, add_remove, addr, addrlen);
2602  break;
2603  case GNUNET_NO:
2604  server_remove_address (cls, add_remove, addr, addrlen);
2605  break;
2606  }
2607 }
2608 
2609 
2620 static int
2622  const char *service_name,
2623  const struct GNUNET_CONFIGURATION_Handle *cfg,
2624  struct sockaddr ***addrs,
2625  socklen_t ** addr_lens)
2626 {
2627  int disablev6;
2628  unsigned long long port;
2629  struct addrinfo hints;
2630  struct addrinfo *res;
2631  struct addrinfo *pos;
2632  struct addrinfo *next;
2633  unsigned int i;
2634  int resi;
2635  int ret;
2636  struct sockaddr **saddrs;
2637  socklen_t *saddrlens;
2638  char *hostname;
2639 
2640  *addrs = NULL;
2641  *addr_lens = NULL;
2642 
2643  disablev6 = !plugin->use_ipv6;
2644 
2645  port = 0;
2646  if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT"))
2647  {
2649  GNUNET_CONFIGURATION_get_value_number (cfg, service_name,
2650  "PORT", &port));
2651  if (port > 65535)
2652  {
2654  _("Require valid port number for service in configuration!\n"));
2655  return GNUNET_SYSERR;
2656  }
2657  }
2658  if (0 == port)
2659  {
2661  "Starting in listen only mode\n");
2662  return -1; /* listen only */
2663  }
2664 
2665 
2666  if (GNUNET_CONFIGURATION_have_value (cfg, service_name,
2667  "BINDTO"))
2668  {
2670  GNUNET_CONFIGURATION_get_value_string (cfg, service_name,
2671  "BINDTO", &hostname));
2672  }
2673  else
2674  hostname = NULL;
2675 
2676  if (NULL != hostname)
2677  {
2679  "Resolving `%s' since that is where `%s' will bind to.\n",
2680  hostname, service_name);
2681  memset (&hints, 0, sizeof (struct addrinfo));
2682  if (disablev6)
2683  hints.ai_family = AF_INET;
2684  if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
2685  (NULL == res))
2686  {
2688  _("Failed to resolve `%s': %s\n"),
2689  hostname,
2690  gai_strerror (ret));
2691  GNUNET_free (hostname);
2692  return GNUNET_SYSERR;
2693  }
2694  next = res;
2695  i = 0;
2696  while (NULL != (pos = next))
2697  {
2698  next = pos->ai_next;
2699  if ((disablev6) && (pos->ai_family == AF_INET6))
2700  continue;
2701  i++;
2702  }
2703  if (0 == i)
2704  {
2706  _("Failed to find %saddress for `%s'.\n"),
2707  disablev6 ? "IPv4 " : "", hostname);
2708  freeaddrinfo (res);
2709  GNUNET_free (hostname);
2710  return GNUNET_SYSERR;
2711  }
2712  resi = i;
2713  saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
2714  saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
2715  i = 0;
2716  next = res;
2717  while (NULL != (pos = next))
2718  {
2719  next = pos->ai_next;
2720  if ((disablev6) && (pos->ai_family == AF_INET6))
2721  continue;
2722  if ((pos->ai_protocol != IPPROTO_TCP) && (0 != pos->ai_protocol))
2723  continue; /* not TCP */
2724  if ((pos->ai_socktype != SOCK_STREAM) && (0 != pos->ai_socktype))
2725  continue; /* huh? */
2727  "Service will bind to `%s'\n",
2728  GNUNET_a2s (pos->ai_addr,
2729  pos->ai_addrlen));
2730  if (pos->ai_family == AF_INET)
2731  {
2732  GNUNET_assert (pos->ai_addrlen == sizeof (struct sockaddr_in));
2733  saddrlens[i] = pos->ai_addrlen;
2734  saddrs[i] = GNUNET_malloc (saddrlens[i]);
2735  GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
2736  ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
2737  }
2738  else
2739  {
2740  GNUNET_assert (pos->ai_family == AF_INET6);
2741  GNUNET_assert (pos->ai_addrlen == sizeof (struct sockaddr_in6));
2742  saddrlens[i] = pos->ai_addrlen;
2743  saddrs[i] = GNUNET_malloc (saddrlens[i]);
2744  GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
2745  ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
2746  }
2747  i++;
2748  }
2749  GNUNET_free (hostname);
2750  freeaddrinfo (res);
2751  resi = i;
2752  }
2753  else
2754  {
2755  /* will bind against everything, just set port */
2756  if (disablev6)
2757  {
2758  /* V4-only */
2759  resi = 1;
2760  i = 0;
2761  saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
2762  saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
2763 
2764  saddrlens[i] = sizeof (struct sockaddr_in);
2765  saddrs[i] = GNUNET_malloc (saddrlens[i]);
2766 #if HAVE_SOCKADDR_IN_SIN_LEN
2767  ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
2768 #endif
2769  ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
2770  ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
2771  }
2772  else
2773  {
2774  /* dual stack */
2775  resi = 2;
2776  saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
2777  saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
2778  i = 0;
2779  saddrlens[i] = sizeof (struct sockaddr_in6);
2780  saddrs[i] = GNUNET_malloc (saddrlens[i]);
2781 #if HAVE_SOCKADDR_IN_SIN_LEN
2782  ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
2783 #endif
2784  ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
2785  ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
2786  i++;
2787  saddrlens[i] = sizeof (struct sockaddr_in);
2788  saddrs[i] = GNUNET_malloc (saddrlens[i]);
2789 #if HAVE_SOCKADDR_IN_SIN_LEN
2790  ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
2791 #endif
2792  ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
2793  ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
2794  }
2795  }
2796  *addrs = saddrs;
2797  *addr_lens = saddrlens;
2798  return resi;
2799 }
2800 
2801 
2807 static void
2809 {
2810  int res = GNUNET_OK;
2811  struct sockaddr **addrs;
2812  socklen_t *addrlens;
2813 
2814  res = server_get_addresses (plugin,
2815  plugin->name,
2816  plugin->env->cfg,
2817  &addrs, &addrlens);
2819  _("Found %u addresses to report to NAT service\n"),
2820  res);
2821 
2822  if (GNUNET_SYSERR == res)
2823  {
2824  plugin->nat = NULL;
2825  return;
2826  }
2827 
2828  plugin->nat
2829  = GNUNET_NAT_register (plugin->env->cfg,
2830  "transport-http_server",
2831  IPPROTO_TCP,
2832  (unsigned int) res,
2833  (const struct sockaddr **) addrs,
2834  addrlens,
2836  NULL,
2837  plugin);
2838  while (res > 0)
2839  {
2840  res--;
2841  GNUNET_assert (NULL != addrs[res]);
2842  GNUNET_free (addrs[res]);
2843  }
2844  GNUNET_free_non_null (addrs);
2845  GNUNET_free_non_null (addrlens);
2846 }
2847 
2848 
2854 static void
2856 {
2857  struct HttpAddressWrapper *w;
2858 
2859  /* Stop NAT handle */
2860  if (NULL != plugin->nat)
2861  {
2862  GNUNET_NAT_unregister (plugin->nat);
2863  plugin->nat = NULL;
2864  }
2865  /* Clean up addresses */
2866  while (NULL != plugin->addr_head)
2867  {
2868  w = plugin->addr_head;
2870  plugin->addr_tail,
2871  w);
2872  GNUNET_free (w->address);
2873  GNUNET_free (w);
2874  }
2875 }
2876 
2877 
2884 static int
2886 {
2887  struct GNUNET_NETWORK_Handle *desc = NULL;
2888  int res = GNUNET_NO;
2889 
2890  /* Probe IPv6 support */
2891  desc = GNUNET_NETWORK_socket_create (PF_INET6,
2892  SOCK_STREAM,
2893  0);
2894  if (NULL == desc)
2895  {
2896  if ( (errno == ENOBUFS) ||
2897  (errno == ENOMEM) ||
2898  (errno == ENFILE) ||
2899  (errno == EACCES) )
2900  {
2902  "socket");
2903  }
2905  _("Disabling IPv6 since it is not supported on this system!\n"));
2906  res = GNUNET_NO;
2907  }
2908  else
2909  {
2912  desc = NULL;
2913  res = GNUNET_YES;
2914  }
2916  "Testing IPv6 on this system: %s\n",
2917  (res == GNUNET_YES) ? "successful" : "failed");
2918  return res;
2919 }
2920 
2921 
2927 static void
2929 {
2930  struct HTTP_Server_Plugin *plugin = cls;
2931  struct HttpAddress *ext_addr;
2932  size_t ext_addr_len;
2933  unsigned int urlen;
2934  char *url;
2935 
2936  plugin->notify_ext_task = NULL;
2937  GNUNET_asprintf (&url,
2938  "%s://%s",
2939  plugin->protocol,
2940  plugin->external_hostname);
2941  urlen = strlen (url) + 1;
2942  ext_addr = GNUNET_malloc (sizeof (struct HttpAddress) + urlen);
2943  ext_addr->options = htonl (plugin->options);
2944  ext_addr->urlen = htonl (urlen);
2945  ext_addr_len = sizeof (struct HttpAddress) + urlen;
2946  GNUNET_memcpy (&ext_addr[1], url, urlen);
2947  GNUNET_free (url);
2948 
2950  "Notifying transport about external hostname address `%s'\n",
2951  plugin->external_hostname);
2952 
2953 #if BUILD_HTTPS
2954  if (GNUNET_YES == plugin->verify_external_hostname)
2956  "Enabling SSL verification for external hostname address `%s'\n",
2957  plugin->external_hostname);
2958  plugin->ext_addr
2960  "https_client",
2961  ext_addr,
2962  ext_addr_len,
2964  plugin->env->notify_address (plugin->env->cls,
2965  GNUNET_YES,
2966  plugin->ext_addr);
2967  GNUNET_free (ext_addr);
2968 #else
2969  plugin->ext_addr
2971  "http_client",
2972  ext_addr,
2973  ext_addr_len,
2975  plugin->env->notify_address (plugin->env->cls,
2976  GNUNET_YES,
2977  plugin->ext_addr);
2978  GNUNET_free (ext_addr);
2979 #endif
2980 }
2981 
2982 
2989 static int
2991 {
2992  unsigned long long port;
2993  unsigned long long max_connections;
2994  char *bind4_address = NULL;
2995  char *bind6_address = NULL;
2996  char *eh_tmp = NULL;
2997  int external_hostname_use_port;
2998 
2999  /* Use IPv4? */
3001  (plugin->env->cfg, plugin->name, "USE_IPv4"))
3002  {
3003  plugin->use_ipv4 =
3005  plugin->name,
3006  "USE_IPv4");
3007  }
3008  else
3009  plugin->use_ipv4 = GNUNET_YES;
3011  _("IPv4 support is %s\n"),
3012  (plugin->use_ipv4 == GNUNET_YES) ? "enabled" : "disabled");
3013 
3014  /* Use IPv6? */
3016  (plugin->env->cfg, plugin->name, "USE_IPv6"))
3017  {
3018  plugin->use_ipv6 =
3020  plugin->name,
3021  "USE_IPv6");
3022  }
3023  else
3024  plugin->use_ipv6 = GNUNET_YES;
3026  _("IPv6 support is %s\n"),
3027  (plugin->use_ipv6 == GNUNET_YES) ? "enabled" : "disabled");
3028 
3029  if ((plugin->use_ipv4 == GNUNET_NO) && (plugin->use_ipv6 == GNUNET_NO))
3030  {
3032  _("Neither IPv4 nor IPv6 are enabled! Fix in configuration\n"));
3033  return GNUNET_SYSERR;
3034  }
3035 
3036  /* Reading port number from config file */
3037  if ((GNUNET_OK !=
3039  plugin->name,
3040  "PORT", &port)) || (port > 65535))
3041  {
3043  _("Port is required! Fix in configuration\n"));
3044  return GNUNET_SYSERR;
3045  }
3046  plugin->port = port;
3047 
3049  _("Using port %u\n"), plugin->port);
3050 
3051  if ( (plugin->use_ipv4 == GNUNET_YES) &&
3052  (GNUNET_YES ==
3054  plugin->name,
3055  "BINDTO",
3056  &bind4_address)))
3057  {
3059  "Binding %s plugin to specific IPv4 address: `%s'\n",
3060  plugin->protocol,
3061  bind4_address);
3062  plugin->server_addr_v4 = GNUNET_new (struct sockaddr_in);
3063  if (1 != inet_pton (AF_INET,
3064  bind4_address,
3065  &plugin->server_addr_v4->sin_addr))
3066  {
3068  _("Specific IPv4 address `%s' in configuration file is invalid!\n"),
3069  bind4_address);
3070  GNUNET_free (bind4_address);
3071  GNUNET_free (plugin->server_addr_v4);
3072  plugin->server_addr_v4 = NULL;
3073  return GNUNET_SYSERR;
3074  }
3075  else
3076  {
3078  "Binding to IPv4 address %s\n",
3079  bind4_address);
3080  plugin->server_addr_v4->sin_family = AF_INET;
3081  plugin->server_addr_v4->sin_port = htons (plugin->port);
3082  }
3083  GNUNET_free (bind4_address);
3084  }
3085 
3086  if ((plugin->use_ipv6 == GNUNET_YES) &&
3087  (GNUNET_YES ==
3089  plugin->name,
3090  "BINDTO6",
3091  &bind6_address)))
3092  {
3094  "Binding %s plugin to specific IPv6 address: `%s'\n",
3095  plugin->protocol, bind6_address);
3096  plugin->server_addr_v6 = GNUNET_new (struct sockaddr_in6);
3097  if (1 !=
3098  inet_pton (AF_INET6,
3099  bind6_address,
3100  &plugin->server_addr_v6->sin6_addr))
3101  {
3103  _("Specific IPv6 address `%s' in configuration file is invalid!\n"),
3104  bind6_address);
3105  GNUNET_free (bind6_address);
3106  GNUNET_free (plugin->server_addr_v6);
3107  plugin->server_addr_v6 = NULL;
3108  return GNUNET_SYSERR;
3109  }
3110  else
3111  {
3113  "Binding to IPv6 address %s\n",
3114  bind6_address);
3115  plugin->server_addr_v6->sin6_family = AF_INET6;
3116  plugin->server_addr_v6->sin6_port = htons (plugin->port);
3117  }
3118  GNUNET_free (bind6_address);
3119  }
3120 
3122 #if BUILD_HTTPS
3123  plugin->verify_external_hostname
3125  plugin->name,
3126  "VERIFY_EXTERNAL_HOSTNAME");
3127  if (GNUNET_SYSERR == plugin->verify_external_hostname)
3129  if (GNUNET_YES == plugin->verify_external_hostname)
3131 #endif
3132  external_hostname_use_port
3134  plugin->name,
3135  "EXTERNAL_HOSTNAME_USE_PORT");
3136  if (GNUNET_SYSERR == external_hostname_use_port)
3137  external_hostname_use_port = GNUNET_NO;
3138 
3139 
3140  if (GNUNET_YES ==
3142  plugin->name,
3143  "EXTERNAL_HOSTNAME",
3144  &eh_tmp))
3145  {
3146  char *tmp;
3147  char *pos = NULL;
3148  char *pos_url = NULL;
3149 
3150  if (NULL != strstr(eh_tmp, "://"))
3151  tmp = &strstr(eh_tmp, "://")[3];
3152  else
3153  tmp = eh_tmp;
3154 
3155  if (GNUNET_YES == external_hostname_use_port)
3156  {
3157  if ( (strlen (tmp) > 1) && (NULL != (pos = strchr(tmp, '/'))) )
3158  {
3159  pos_url = pos + 1;
3160  pos[0] = '\0';
3162  "%s:%u/%s",
3163  tmp,
3164  (uint16_t) port,
3165  pos_url);
3166  }
3167  else
3169  "%s:%u",
3170  tmp,
3171  (uint16_t) port);
3172  }
3173  else
3174  plugin->external_hostname = GNUNET_strdup (tmp);
3175  GNUNET_free (eh_tmp);
3176 
3178  _("Using external hostname `%s'\n"),
3179  plugin->external_hostname);
3181  plugin);
3182 
3183  /* Use only configured external hostname */
3185  (plugin->env->cfg,
3186  plugin->name,
3187  "EXTERNAL_HOSTNAME_ONLY"))
3188  {
3189  plugin->external_only =
3191  plugin->name,
3192  "EXTERNAL_HOSTNAME_ONLY");
3193  }
3194  else
3195  plugin->external_only = GNUNET_NO;
3196 
3197  if (GNUNET_YES == plugin->external_only)
3199  _("Notifying transport only about hostname `%s'\n"),
3200  plugin->external_hostname);
3201  }
3202  else
3204  "No external hostname configured\n");
3205 
3206  /* Optional parameters */
3207  if (GNUNET_OK !=
3209  plugin->name,
3210  "MAX_CONNECTIONS",
3211  &max_connections))
3212  max_connections = 128;
3213  plugin->max_request = max_connections;
3214 
3216  _("Maximum number of connections is %u\n"),
3217  plugin->max_request);
3218 
3219  plugin->peer_id_length = strlen (GNUNET_i2s_full (plugin->env->my_identity));
3220 
3221  return GNUNET_OK;
3222 }
3223 
3224 
3231 void *
3233 {
3234  struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
3235  struct HTTP_Server_Plugin *plugin = api->cls;
3236 
3237  if (NULL == api->cls)
3238  {
3239  /* Free for stub mode */
3240  GNUNET_free (api);
3241  return NULL;
3242  }
3243  plugin->in_shutdown = GNUNET_YES;
3245  _("Shutting down plugin `%s'\n"),
3246  plugin->name);
3247 
3248  if (NULL != plugin->notify_ext_task)
3249  {
3251  plugin->notify_ext_task = NULL;
3252  }
3253 
3254  if (NULL != plugin->ext_addr)
3255  {
3257  "Notifying transport to remove address `%s'\n",
3259  plugin->ext_addr->address,
3260  plugin->ext_addr->address_length));
3261 #if BUILD_HTTPS
3262  plugin->env->notify_address (plugin->env->cls,
3263  GNUNET_NO,
3264  plugin->ext_addr);
3265 #else
3266  plugin->env->notify_address (plugin->env->cls,
3267  GNUNET_NO,
3268  plugin->ext_addr);
3269 #endif
3271  plugin->ext_addr = NULL;
3272  }
3273 
3274  /* Stop to report addresses to transport service */
3276  if (NULL != plugin->server_v4_task)
3277  {
3279  plugin->server_v4_task = NULL;
3280  }
3281 
3282  if (NULL != plugin->server_v6_task)
3283  {
3285  plugin->server_v6_task = NULL;
3286  }
3287 #if BUILD_HTTPS
3288  GNUNET_free_non_null (plugin->crypto_init);
3289  GNUNET_free_non_null (plugin->cert);
3290  GNUNET_free_non_null (plugin->key);
3291 #endif
3294  plugin);
3296  plugin->sessions = NULL;
3297  if (NULL != plugin->server_v4)
3298  {
3299  MHD_stop_daemon (plugin->server_v4);
3300  plugin->server_v4 = NULL;
3301  }
3302  if (NULL != plugin->server_v6)
3303  {
3304  MHD_stop_daemon (plugin->server_v6);
3305  plugin->server_v6 = NULL;
3306  }
3307  /* Clean up */
3309  GNUNET_free_non_null (plugin->ext_addr);
3312  regfree (&plugin->url_regex);
3313 
3315  _("Shutdown for plugin `%s' complete\n"),
3316  plugin->name);
3317 
3318  GNUNET_free (plugin);
3319  GNUNET_free (api);
3320  return NULL;
3321 }
3322 
3323 
3335 static const char *
3337  const void *addr,
3338  size_t addrlen)
3339 {
3341  addr,
3342  addrlen);
3343 }
3344 
3345 
3353 static enum GNUNET_NetworkType
3355  struct GNUNET_ATS_Session *session)
3356 {
3357  return session->scope;
3358 }
3359 
3360 
3368 static enum GNUNET_NetworkType
3370  const struct GNUNET_HELLO_Address *address)
3371 {
3372  struct HTTP_Server_Plugin *plugin = cls;
3373 
3374  return http_common_get_network_for_address (plugin->env,
3375  address);
3376 }
3377 
3378 
3389 static void
3391  const struct GNUNET_PeerIdentity *peer,
3392  struct GNUNET_ATS_Session *session,
3393  struct GNUNET_TIME_Relative delay)
3394 {
3397  "New inbound delay %s\n",
3399  GNUNET_NO));
3400  if (NULL != session->recv_wakeup_task)
3401  {
3403  session->recv_wakeup_task
3405  &server_wake_up,
3406  session);
3407  }
3408 }
3409 
3410 
3420 static int
3422  const struct GNUNET_PeerIdentity *peer,
3423  void *value)
3424 {
3425  struct HTTP_Server_Plugin *plugin = cls;
3426  struct GNUNET_ATS_Session *session = value;
3427 
3428  notify_session_monitor (plugin,
3429  session,
3431  return GNUNET_OK;
3432 }
3433 
3434 
3447 static void
3450  void *sic_cls)
3451 {
3452  struct HTTP_Server_Plugin *plugin = cls;
3453 
3454  plugin->sic = sic;
3455  plugin->sic_cls = sic_cls;
3456  if (NULL != sic)
3457  {
3460  plugin);
3461  /* signal end of first iteration */
3462  sic (sic_cls, NULL, NULL);
3463  }
3464 }
3465 
3466 
3473 void *
3475 {
3478  struct HTTP_Server_Plugin *plugin;
3479 
3480  if (NULL == env->receive)
3481  {
3482  /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully
3483  initialze the plugin or the API */
3485  api->cls = NULL;
3489  return api;
3490  }
3491  plugin = GNUNET_new (struct HTTP_Server_Plugin);
3492  plugin->env = env;
3494  GNUNET_YES);
3495 
3497  api->cls = plugin;
3498  api->send = &http_server_plugin_send;
3504 
3513 #if BUILD_HTTPS
3514  plugin->name = "transport-https_server";
3515  plugin->protocol = "https";
3516 #else
3517  plugin->name = "transport-http_server";
3518  plugin->protocol = "http";
3519 #endif
3520 
3521  if (GNUNET_YES ==
3523  plugin->name,
3524  "TCP_STEALTH"))
3525  {
3526 #ifdef TCP_STEALTH
3527  plugin->options |= HTTP_OPTIONS_TCP_STEALTH;
3528 #else
3530  _("TCP_STEALTH not supported on this platform.\n"));
3532  return NULL;
3533 #endif
3534  }
3535 
3536  /* Compile URL regex */
3537  if (regcomp (&plugin->url_regex,
3538  URL_REGEX,
3539  REG_EXTENDED))
3540  {
3542  _("Unable to compile URL regex\n"));
3544  return NULL;
3545  }
3546 
3547  /* Configure plugin */
3548  if (GNUNET_SYSERR == server_configure_plugin (plugin))
3549  {
3551  return NULL;
3552  }
3553 
3554  /* Check IPv6 support */
3555  if (GNUNET_YES == plugin->use_ipv6)
3556  plugin->use_ipv6 = server_check_ipv6_support (plugin);
3557 
3558  /* Report addresses to transport service */
3559  if (GNUNET_NO == plugin->external_only)
3561 
3562  if (GNUNET_SYSERR == server_start (plugin))
3563  {
3565  return NULL;
3566  }
3567  return api;
3568 }
3569 
3570 /* end of plugin_transport_http_server.c */
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
static int server_receive_mst_cb(void *cls, const struct GNUNET_MessageHeader *message)
Callback called by MessageStreamTokenizer when a message has arrived.
static struct MHD_Daemon * daemon_handle
Handle to the HTTP server as provided by libmicrohttpd.
Definition: gnunet-bcd.c:44
struct GNUNET_SCHEDULER_Task * server_v6_task
MHD IPv6 task.
size_t address_length
Number of bytes in address.
void * sic_cls
Closure for sic.
Wrapper to manage addresses.
Session is being torn down and about to disappear.
static void server_remove_address(void *cls, int add_remove, const struct sockaddr *addr, socklen_t addrlen)
Remove an address from the server&#39;s set of addresses and notify transport.
Open the file for reading.
struct GNUNET_TRANSPORT_PluginEnvironment * env
Our environment.
static void server_add_address(void *cls, int add_remove, const struct sockaddr *addr, socklen_t addrlen)
Add an address to the server&#39;s set of addresses and notify transport.
struct ServerRequest * server_recv
Client send handle.
struct sockaddr_in6 * server_addr_v6
IPv6 server socket to bind to.
int verify_external_hostname
Verify external address.
Handle for active NAT registrations.
Definition: nat_api.c:72
uint32_t num_bytes_pending
Number of bytes pending transmission for this session.
struct GNUNET_MessageHeader * msg
Definition: 005.c:2
GNUNET_TRANSPORT_CreateSession get_session
Function that will be called tell the plugin to create a session object.
uint32_t options
Address options see enum HttpAddressOptions
GNUNET_TRANSPORT_AddressToString address_to_string
Function that will be called to convert a binary address to a string (numeric conversion only)...
GNUNET_NAT_AddressClass
Some addresses contain sensitive information or are not suitable for global distribution.
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:73
int GNUNET_DISK_file_close(struct GNUNET_DISK_FileHandle *h)
Close an open file.
Definition: disk.c:1817
#define GNUNET_TIME_UNIT_ZERO_ABS
Absolute time zero.
int GNUNET_CONFIGURATION_get_value_number(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, unsigned long long *number)
Get a configuration value that should be a number.
struct GNUNET_SCHEDULER_Task * recv_wakeup_task
Task to wake up client receive handle when receiving is allowed again.
uint64_t rel_value_us
The actual value.
const void * address
Binary representation of the address (plugin-specific).
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
GNUNET_TRANSPORT_SessionStart session_start
Function called by the plugin when a new (incoming) session was created not explicitly created using ...
char * buf
buffer containing data to send
unsigned int msgs_in_queue
Number of messages waiting for transmission to this peer.
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...
void GNUNET_OS_process_destroy(struct GNUNET_OS_Process *proc)
Cleans up process structure contents (OS-dependent) and deallocates it.
Definition: os_priority.c:364
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.
struct GNUNET_SCHEDULER_Task * timeout_task
Session timeout task.
struct HTTP_Message * msg_tail
previous pointer for double linked list
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:881
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.
struct Plugin * plugin
Pointer to the global plugin struct.
static enum GNUNET_NetworkType http_server_plugin_get_network(void *cls, struct GNUNET_ATS_Session *session)
Function obtain the network type for a session.
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.
static void server_wake_up(void *cls)
Wake up an MHD connection which was suspended.
GNUNET_TRANSPORT_TransmitFunction send
Function that the transport service will use to transmit data to another peer.
GNUNET_TRANSPORT_DisconnectPeerFunction disconnect_peer
Function that can be used to force the plugin to disconnect from the given peer and cancel all previo...
static unsigned long long max_connections
If there are at least this many connections, old ones will be removed.
GNUNET_TRANSPORT_AddressToType get_address_type
Function that will be called to figure if an address is an loopback, LAN, WAN etc.
int is_inbound
GNUNET_YES if this is an inbound connection, GNUNET_NO if this is an outbound connection, GNUNET_SYSERR if connections of this plugin are so fundamentally bidirectional that they have no &#39;initiator&#39;
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:245
static void server_v6_run(void *cls)
Call MHD IPv6 to process pending requests and then go back and schedule the next run.
enum GNUNET_TRANSPORT_SessionState state
New state of the session.
unsigned int max_request
Maximum number of sockets the plugin can use Each http request /request connections are two connectio...
size_t pos
amount of data already sent
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
char * protocol
Plugin protocol http, https.
struct GNUNET_OS_Process * GNUNET_OS_start_process(int pipe_control, 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:1400
#define GNUNET_TIME_UNIT_SECONDS
One second.
uint32_t options
My options to be included in the 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...
Message to send using http.
Each plugin is required to return a pointer to a struct of this type as the return value from its ent...
struct GNUNET_SERVER_MessageStreamTokenizer * msg_tk
Message stream tokenizer for incoming data.
GNUNET_TRANSPORT_SessionMonitorSetup setup_monitor
Function to monitor the sessions managed by the plugin.
struct GNUNET_CONTAINER_MultiPeerMap * sessions
Hash map of open sessions.
Initial session handshake is in progress.
static void server_delete_session(struct GNUNET_ATS_Session *s)
Deletes the session.
struct HTTP_Message * next
next pointer for double linked list
bool suspended
Currently suspended.
GNUNET_TRANSPORT_SessionInfoCallback sic
Function to call about session status changes.
static void server_session_timeout(void *cls)
Session was idle, so disconnect it.
const struct GNUNET_PeerIdentity * my_identity
Identity of this peer.
static void server_start_report_addresses(struct HTTP_Server_Plugin *plugin)
Ask NAT for addresses.
struct GNUNET_TIME_Absolute timeout
When does this session time out.
struct GNUNET_SCHEDULER_Task * server_v4_task
MHD IPv4 task.
int 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.
#define GNUNET_NO
Definition: gnunet_common.h:81
const char * GNUNET_i2s_full(const struct GNUNET_PeerIdentity *pid)
Convert a peer identity to a string (for printing debug messages).
unsigned int cur_request
Current number of sockets the plugin can use Each http connection are two requests.
#define GNUNET_OK
Named constants for return values.
Definition: gnunet_common.h:78
#define HTTP_SERVER_NOT_VALIDATED_TIMEOUT
#define GNUNET_free_non_null(ptr)
Free the memory pointed to by ptr if ptr is not NULL.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
struct HTTP_Server_Plugin * plugin
Pointer to the global plugin struct.
struct GNUNET_HELLO_Address * address
Address.
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format...
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.
struct GNUNET_HELLO_Address * ext_addr
External hostname the plugin can be connected to, can be different to the host&#39;s FQDN, used e.g.
struct HTTP_Message * msg_head
next pointer for double linked list
void GNUNET_STATISTICS_update(struct GNUNET_STATISTICS_Handle *handle, const char *name, int64_t delta, int make_persistent)
Set statistic value for the peer.
const struct GNUNET_HELLO_Address * address
Address used by the session.
unsigned long long bytes_in_queue
Number of bytes waiting for transmission to this peer.
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).
static int ret
Final status code.
Definition: gnunet-arm.c:89
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
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...
GNUNET_NetworkType
Types of networks (with separate quotas) we support.
Definition: gnunet_nt_lib.h:35
uint32_t num_msg_pending
Number of messages pending transmission for this session.
int direction
_RECV or _SEND
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur...
void * transmit_cont_cls
Closure for transmit_cont.
void GNUNET_CONTAINER_multipeermap_destroy(struct GNUNET_CONTAINER_MultiPeerMap *map)
Destroy a hash map.
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:1308
struct GNUNET_TIME_Absolute receive_delay
Until when does this plugin refuse to receive to manage staying within the inbound quota...
int in_shutdown
Did we immediately end the session in disconnect_cb.
GNUNET_TRANSPORT_TransmitContinuation transmit_cont
Continuation function to call once the transmission buffer has again space available.
regex_t url_regex
Regex for parsing URLs.
#define _(String)
GNU gettext support macro.
Definition: platform.h:208
struct MHD_Daemon * mhd_daemon
The MHD daemon.
struct HttpAddressWrapper * next
Linked list next.
GNUNET_TRANSPORT_SessionEnd session_end
Function that must be called by the plugin when a non-NULL session handle stops being valid (is destr...
GNUNET_TRANSPORT_PluginReceiveCallback receive
Function that should be called by the transport plugin whenever a message is received.
struct GNUNET_SCHEDULER_Task * notify_ext_task
Task calling transport service about external address.
struct GNUNET_TIME_Absolute next_receive
Absolute time when to receive data again Used for receive throttling.
static int server_check_ipv6_support(struct HTTP_Server_Plugin *plugin)
Check if IPv6 supported on this system.
GNUNET_TRANSPORT_UpdateSessionTimeout update_session_timeout
Function that will be called whenever the transport service wants to notify the plugin that a session...
void GNUNET_NETWORK_fdset_destroy(struct GNUNET_NETWORK_FDSet *fds)
Releases the associated memory of an fd set.
Definition: network.c:1554
static int session_tag_it(void *cls, const struct GNUNET_PeerIdentity *key, void *value)
Find a session with a matching tag.
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 struct GNUNET_ATS_SolverFunctions * plugin
Our solver.
#define GNUNET_log_strerror(level, cmd)
Log an error message at log-level &#39;level&#39; that indicates a failure of the command &#39;cmd&#39; with the mess...
Information about a plugin&#39;s session.
size_t http_common_address_get_size(const struct HttpAddress *addr)
Get the length of an address.
int GNUNET_asprintf(char **buf, const char *format,...)
Like asprintf, just portable.
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:1246
struct GNUNET_NETWORK_FDSet * GNUNET_NETWORK_fdset_create(void)
Creates an fd set.
Definition: network.c:1538
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 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.
int server_v4_immediately
The IPv4 server is scheduled to run asap.
void * cls
Closure for the various callbacks.
enum State state
current state of profiling
static struct GNUNET_TIME_Relative timeout
User defined timestamp for completing operations.
Definition: gnunet-arm.c:114
void * cls
Closure for all of the callbacks.
#define GNUNET_memcpy(dst, src, n)
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.).
void GNUNET_log_config_missing(enum GNUNET_ErrorType kind, const char *section, const char *option)
Log error message about missing configuration option.
static char * value
Value of the record to add/remove.
GNUNET_TRANSPORT_StringToAddress string_to_address
Function that will be called to convert a string address to binary (numeric conversion only)...
void GNUNET_MST_destroy(struct GNUNET_MessageStreamTokenizer *mst)
Destroys a tokenizer.
Definition: mst.c:413
static int destroy_session_cb(void *cls, const struct GNUNET_PeerIdentity *peer, void *value)
Terminate session.
Information about ongoing sessions of the transport client.
This is an inbound address and cannot be used to initiate an outbound connection to another peer...
struct GNUNET_DATACACHE_PluginEnvironment * env
Our execution environment.
struct MHD_Daemon * server_v4
MHD IPv4 daemon.
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.
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:1273
The transport service will pass a pointer to a struct of this type as the first and only argument to ...
#define _RECEIVE
static enum GNUNET_NetworkType scope
Which network scope do we belong to?
int 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.
static struct GNUNET_SCHEDULER_Task * server_schedule(struct HTTP_Server_Plugin *plugin, struct MHD_Daemon *daemon_handle, int now)
Function that queries MHD&#39;s select sets and starts the task waiting for them.
GNUNET_TRANSPORT_GetNetworkType get_network
Function to obtain the network type for a session.
Handle to a message stream tokenizer.
Definition: mst.c:43
#define GNUNET_MIN(a, b)
Definition: gnunet_common.h:83
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:727
void * addr
Address following.
static char * service_name
Option -s: service name (hash to get service descriptor)
Definition: gnunet-vpn.c:51
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...
collection of IO descriptors
static char buf[2048]
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:1829
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 GNUNET_MessageStreamTokenizer * GNUNET_MST_create(GNUNET_MessageTokenizerCallback cb, void *cb_cls)
Create a message stream tokenizer.
Definition: mst.c:87
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 ...
static unsigned int http_server_query_keepalive_factor(void *cls)
Function that is called to get the keepalive factor.
static int server_configure_plugin(struct HTTP_Server_Plugin *plugin)
Configure the plugin.
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)...
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.
int 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:116
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.
struct GNUNET_TIME_Absolute session_timeout
At what time will this session timeout (unless activity happens)?
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.
int known_to_service
GNUNET_YES if this session is known to the service.
Internal representation of the hash map.
static void server_stop_report_addresses(struct HTTP_Server_Plugin *plugin)
Stop NAT for addresses.
GNUNET_TRANSPORT_UpdateInboundDelay update_inbound_delay
Function that will be called whenever the transport service wants to notify the plugin that the inbou...
struct GNUNET_NAT_Handle * nat
NAT handle & address management.
#define GNUNET_TIME_UNIT_MILLISECONDS
One millisecond.
static int res
size_t overhead
HTTP/S specific overhead.
struct GNUNET_ATS_Session * res
Set to session matching the tag.
When these flags are set, the child process will inherit stdout and stderr of the parent...
Definition: gnunet_os_lib.h:98
int GNUNET_CONFIGURATION_get_value_string(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, char **value)
Get a configuration value that should be a string.
static struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
Definition: gnunet-arm.c:104
Closure for session_tag_it().
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:690
static void server_log(void *arg, const char *fmt, va_list ap)
Log function called by MHD.
#define VERBOSE_SERVER
static int destroy_session_shutdown_cb(void *cls, const struct GNUNET_PeerIdentity *peer, void *value)
Terminate session during shutdown.
struct MHD_Connection * mhd_conn
The MHD connection.
size_t size
buffer length
static void add_cors_headers(struct MHD_Response *response)
Add headers to a request indicating that we allow Cross-Origin Resource Sharing.
struct GNUNET_TESTBED_Peer * peer
The peer associated with this model.
struct GNUNET_HashCode key
The key used in the DHT.
#define GNUNET_SYSERR
Definition: gnunet_common.h:79
static unsigned int size
Size of the "table".
Definition: peer.c:67
#define LIBGNUNET_PLUGIN_TRANSPORT_INIT
uint32_t urlen
Length of URL located after struct.
enum GNUNET_NetworkType scope
ATS network type.
uint32_t tag
Unique HTTP/S connection tag for this connection.
#define HTTP_ERROR_RESPONSE
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:378
static struct GNUNET_MQ_Envelope * ac
Handle to current GNUNET_PEERINFO_add_peer() operation.
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...
struct GNUNET_MQ_Envelope * env
Definition: 005.c:1
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".
#define GNUNET_CONTAINER_DLL_insert_tail(head, tail, element)
Insert an element at the tail of a DLL.
unsigned int external_only
Notify transport only about external address.
static struct GNUNET_FS_SearchContext * sc
Definition: gnunet-search.c:37
static void server_notify_external_hostname(void *cls)
Notify server about our external hostname.
static struct GNUNET_SCHEDULER_Task * timeout_task
Task to be run on timeout.
Definition: gnunet-arm.c:119
static struct GNUNET_TIME_Relative delay
When should dkg communication start?
struct sockaddr_in * server_addr_v4
IPv4 server socket to bind to.
static int 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.
Enable TCP Stealth-style port knocking.
#define GNUNET_MAX_MESSAGE_SIZE
Largest supported message (to be precise, one byte more than the largest possible message...
int 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:289
static int server_start(struct HTTP_Server_Plugin *plugin)
Start the HTTP server.
const struct GNUNET_CONFIGURATION_Handle * cfg
Configuration to use.
struct HttpAddress * address
An address we are using.
Allow multiple values with the same key.
#define GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT
After how long do we consider a connection to a peer dead if we don&#39;t receive messages from the peer...
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.
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.
This is just an update about the session, the state did not change.
int GNUNET_CONTAINER_multipeermap_iterate(struct GNUNET_CONTAINER_MultiPeerMap *map, GNUNET_CONTAINER_PeerMapIterator it, void *it_cls)
Iterate over all entries in the map.
int 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:501
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.
GNUNET_TRANSPORT_QueryKeepaliveFactorFunction query_keepalive_factor
Function that is used to query keepalive factor.
The identity of the host (wraps the signing key of the peer).
No additional information.
uint32_t tag
Tag we are looking for.
Information we keep with MHD for an HTTP request.
static char * hostname
Our hostname; we give this to all the peers we start.
#define HTTP_SERVER_SESSION_TIMEOUT
int GNUNET_OS_process_wait(struct GNUNET_OS_Process *proc)
Wait for a process to terminate.
Definition: os_priority.c:1762
static void http_server_plugin_setup_monitor(void *cls, GNUNET_TRANSPORT_SessionInfoCallback sic, void *sic_cls)
Begin monitoring sessions of a plugin.
size_t http_common_cmp_addresses(const void *addr1, size_t addrlen1, const void *addr2, size_t addrlen2)
Compare addr1 to addr2.
struct GNUNET_ATS_Session * session
The session this server connection belongs to.
static uint16_t port
Port number.
Definition: gnunet-bcd.c:79
int connected
For PUT requests: Is this the first or last callback with size 0 For GET requests: Have we sent a mes...
configuration data
Definition: configuration.c:85
Encapsulation of all of the state of the plugin.
struct GNUNET_PeerIdentity target
To whom are we talking to.
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.
An address for communicating with a peer.
static void server_disconnect_cb(void *cls, struct MHD_Connection *connection, void **httpSessionCache)
Callback from MHD when a connection disconnects.
struct HttpAddress * http_common_address_from_socket(const char *protocol, const struct sockaddr *addr, socklen_t addrlen)
Create a HTTP address from a socketaddr.
struct GNUNET_STATISTICS_Handle * stats
Handle for reporting statistics.
static int inet_pton(int af, const char *cp, struct in_addr *buf)
Convert IPv4 address from text to binary form.
#define GNUNET_log(kind,...)
The session was created (first call for each session object).
Entry in list of pending tasks.
Definition: scheduler.c:134
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...
struct HTTP_Message * prev
previous pointer for double linked list
uint32_t options
Options requested by peer.
int 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.
int server_send(struct GNUNET_ATS_Session *s, struct HTTP_Message *msg)
handle to a socket
Definition: network.c:46
struct HttpAddressWrapper * addr_tail
IPv4 addresses DLL tail.
static struct MHD_Response * response
Our canonical response.
GNUNET_TRANSPORT_AddressNotification notify_address
Function that must be called by each plugin to notify the transport service about the addresses under...
Verify X509 server certificate, it should be valid.
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:331
struct ServerRequest * server_send
Client send handle.
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.
int server_v6_immediately
The IPv6 server is scheduled to run asap.
#define URL_REGEX
GNUNET_TRANSPORT_AddressPrettyPrinter address_pretty_printer
Function to pretty-print addresses.
Header for all communications.
Time for absolute times used by GNUnet, in microseconds.
#define GNUNET_YES
Definition: gnunet_common.h:80
static void server_reschedule_session_timeout(struct GNUNET_ATS_Session *s)
Increment session timeout due to activity session s.
struct HttpAddressWrapper * prev
Linked list previous.
static void server_v4_run(void *cls)
Call MHD IPv4 to process pending requests and then go back and schedule the next run.
Run with the default priority (normal P2P operations).
struct HttpAddressWrapper * addr_head
IPv4 addresses DLL head.
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_SessionState
Possible states of a session in a plugin.
#define LIBGNUNET_PLUGIN_TRANSPORT_DONE
#define PLUGIN_NAME
static int server_accept_cb(void *cls, const struct sockaddr *addr, socklen_t addr_len)
Check if incoming connection is accepted.
#define LOG(kind,...)
int GNUNET_CONFIGURATION_get_value_yesno(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option)
Get a configuration value that should be in a set of "YES" or "NO".
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.
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:1673
static char * address
GNS address for this phone.
#define OPTION_LONG_POLL
Handle used to access files (and pipes).
const char * GNUNET_i2s(const struct GNUNET_PeerIdentity *pid)
Convert a peer identity to a string (for printing debug messages).
int GNUNET_NETWORK_socket_close(struct GNUNET_NETWORK_Handle *desc)
Close a socket.
Definition: network.c:604
#define GNUNET_HELLO_address_free(addr)
Free an address.
HTTP addresses including a full URI.
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.
static void server_reschedule(struct HTTP_Server_Plugin *plugin, struct MHD_Daemon *server, int now)
Reschedule the execution of both IPv4 and IPv6 server.
#define TIMEOUT_LOG
char * external_hostname
External address.
#define GNUNET_malloc(size)
Wrapper around malloc.
struct MHD_Daemon * server_v6
MHD IPv4 daemon.
size_t addrlen
Length of the address.
int peer_id_length
Length of peer id.
#define GNUNET_free(ptr)
Wrapper around free.
Time for relative time used by GNUnet, in microseconds.
struct GNUNET_CRYPTO_EddsaPublicKey public_key
GNUNET_TRANSPORT_GetNetworkTypeForAddress get_network_for_address
Function to obtain the network type for an address.
struct GNUNET_NETWORK_Handle * GNUNET_NETWORK_socket_create(int domain, int type, int protocol)
Create a new socket.
Definition: network.c:1037
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:965