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 {
66 
70  struct MHD_Connection *mhd_conn;
71 
75  struct MHD_Daemon *mhd_daemon;
76 
80  uint32_t options;
81 #define OPTION_LONG_POLL 1 /* GET request wants long-poll semantics */
82 
86  int direction;
87 
92  int connected;
93 
97  bool suspended;
98 };
99 
100 
109 
114 
119 
123  size_t addrlen;
124 };
125 
126 
130 struct HTTP_Message {
134  struct HTTP_Message *next;
135 
139  struct HTTP_Message *prev;
140 
144  char *buf;
145 
149  size_t pos;
150 
154  size_t size;
155 
159  size_t overhead;
160 
167 
171  void *transmit_cont_cls;
172 };
173 
174 
178 struct GNUNET_ATS_Session {
183  struct GNUNET_PeerIdentity target;
184 
189 
193  struct HTTP_Message *msg_head;
194 
198  struct HTTP_Message *msg_tail;
199 
203  struct GNUNET_MessageStreamTokenizer *msg_tk;
204 
208  struct ServerRequest *server_recv;
209 
213  struct ServerRequest *server_send;
214 
219 
224  struct GNUNET_TIME_Absolute next_receive;
225 
230 
235 
239  struct GNUNET_SCHEDULER_Task * recv_wakeup_task;
240 
244  unsigned long long bytes_in_queue;
245 
249  unsigned int msgs_in_queue;
250 
254  uint32_t tag;
255 
260 
265 };
266 
267 
276 
281 
286 
290  void *sic_cls;
291 
295  char *name;
296 
300  char *protocol;
301 
306 
312 
317 
322 
327 
331  struct sockaddr_in *server_addr_v4;
332 
336  struct sockaddr_in6 *server_addr_v6;
337 
341  struct MHD_Daemon *server_v4;
342 
346  struct MHD_Daemon *server_v6;
347 
348 #if BUILD_HTTPS
349 
358  char *crypto_init;
359 
363  char *key;
364 
368  char *cert;
369 #endif
370 
375 
380 
385 
389  unsigned int external_only;
390 
395 
400 
405 
410  unsigned int max_request;
411 
416  unsigned int cur_request;
417 
422 
427 
431  uint32_t options;
432 
436  uint16_t use_ipv6;
437 
441  uint16_t use_ipv4;
442 
446  uint16_t port;
447 
451  regex_t url_regex;
452 };
453 
454 
463 static void
465  struct GNUNET_ATS_Session *session,
467 {
468  struct GNUNET_TRANSPORT_SessionInfo info;
469 
470  if (NULL == plugin->sic)
471  return;
472  memset(&info, 0, sizeof(info));
473  info.state = state;
474  info.is_inbound = GNUNET_YES;
475  info.num_msg_pending = session->msgs_in_queue;
476  info.num_bytes_pending = session->bytes_in_queue;
477  info.receive_delay = session->next_receive;
478  info.session_timeout = session->timeout;
479  info.address = session->address;
480  plugin->sic(plugin->sic_cls,
481  session,
482  &info);
483 }
484 
485 
491 static void
492 server_wake_up(void *cls)
493 {
494  struct GNUNET_ATS_Session *s = cls;
495 
496  s->recv_wakeup_task = NULL;
498  "Session %p: Waking up PUT handle\n",
499  s);
501  MHD_resume_connection(s->server_recv->mhd_conn);
502  s->server_recv->suspended = false;
503 }
504 
505 
514 static void
516  struct MHD_Daemon *server,
517  int now);
518 
519 
525 static void
527 {
528  struct HTTP_Server_Plugin *plugin = s->plugin;
529  struct HTTP_Message *msg;
530 
531  if (NULL != s->timeout_task)
532  {
534  s->timeout_task = NULL;
536  }
537  if (NULL != s->recv_wakeup_task)
538  {
540  s->recv_wakeup_task = NULL;
541  if (NULL != s->server_recv)
542  {
544  s->server_recv->suspended = false;
545  MHD_resume_connection(s->server_recv->mhd_conn);
546  }
547  }
550  &s->target,
551  s));
552  while (NULL != (msg = s->msg_head))
553  {
555  s->msg_tail,
556  msg);
557  if (NULL != msg->transmit_cont)
559  &s->target,
561  msg->size,
562  msg->pos + msg->overhead);
564  s->msgs_in_queue--;
565  GNUNET_assert(s->bytes_in_queue >= msg->size);
566  s->bytes_in_queue -= msg->size;
567  GNUNET_free(msg);
568  }
569 
570  GNUNET_assert(0 == s->msgs_in_queue);
571  GNUNET_assert(0 == s->bytes_in_queue);
572 
573  if (NULL != s->server_send)
574  {
576  "Server: %p / %p Terminating inbound PUT session to peer `%s'\n",
577  s, s->server_send,
578  GNUNET_i2s(&s->target));
579  s->server_send->session = NULL;
580  MHD_set_connection_option(s->server_send->mhd_conn,
581  MHD_CONNECTION_OPTION_TIMEOUT,
582  1 /* 0 = no timeout, so this is MIN */);
583  if (s->server_send->suspended)
584  {
585  s->server_send->suspended = false;
586  MHD_resume_connection(s->server_send->mhd_conn);
587  }
588  server_reschedule(plugin,
590  GNUNET_YES);
591  }
592 
593  if (NULL != s->server_recv)
594  {
596  "Server: %p / %p Terminating inbound GET session to peer `%s'\n",
597  s, s->server_recv, GNUNET_i2s(&s->target));
598  s->server_recv->session = NULL;
599  MHD_set_connection_option(s->server_recv->mhd_conn,
600  MHD_CONNECTION_OPTION_TIMEOUT,
601  1 /* 0 = no timeout, so this is MIN */);
602  server_reschedule(plugin,
604  GNUNET_YES);
605  }
606  notify_session_monitor(plugin,
607  s,
609  if (GNUNET_YES == s->known_to_service)
610  {
611  plugin->env->session_end(plugin->env->cls,
612  s->address,
613  s);
615  }
616  if (NULL != s->msg_tk)
617  {
619  s->msg_tk = NULL;
620  }
623  "Session %p destroyed\n",
624  s);
625  GNUNET_free(s);
626 }
627 
628 
637 static int
639  struct GNUNET_ATS_Session *s)
640 {
642  return GNUNET_OK;
643 }
644 
645 
651 static void
653 {
654  struct GNUNET_ATS_Session *s = cls;
655  struct GNUNET_TIME_Relative left;
656 
657  s->timeout_task = NULL;
659  if (0 != left.rel_value_us)
660  {
661  /* not actually our turn yet, but let's at least update
662  the monitor, it may think we're about to die ... */
664  s,
668  s);
669  return;
670  }
672  "Session %p was idle for %s, disconnecting\n",
673  s,
675  GNUNET_YES));
677 }
678 
679 
685 static void
687 {
688  GNUNET_assert(NULL != s->timeout_task);
690 }
691 
692 
720 static ssize_t
722  struct GNUNET_ATS_Session *session,
723  const char *msgbuf,
724  size_t msgbuf_size,
725  unsigned int priority,
726  struct GNUNET_TIME_Relative to,
728  void *cont_cls)
729 {
730  struct HTTP_Server_Plugin *plugin = cls;
731  struct HTTP_Message *msg;
732  ssize_t bytes_sent = 0;
733  char *stat_txt;
734 
736  "Session %p/request %p: Sending message with %u to peer `%s'\n",
737  session,
738  session->server_send,
739  msgbuf_size,
740  GNUNET_i2s(&session->target));
741 
742  /* create new message and schedule */
743  bytes_sent = sizeof(struct HTTP_Message) + msgbuf_size;
744  msg = GNUNET_malloc(bytes_sent);
745  msg->next = NULL;
746  msg->size = msgbuf_size;
747  msg->pos = 0;
748  msg->buf = (char *)&msg[1];
749  msg->transmit_cont = cont;
750  msg->transmit_cont_cls = cont_cls;
751  GNUNET_memcpy(msg->buf,
752  msgbuf,
753  msgbuf_size);
755  session->msg_tail,
756  msg);
757  session->msgs_in_queue++;
758  session->bytes_in_queue += msg->size;
759  notify_session_monitor(plugin,
760  session,
762  GNUNET_asprintf(&stat_txt,
763  "# bytes currently in %s_server buffers",
764  plugin->protocol);
766  stat_txt, msgbuf_size, GNUNET_NO);
767  GNUNET_free(stat_txt);
768 
769  if (NULL != session->server_send)
770  {
771  if (session->server_send->suspended)
772  {
773  MHD_resume_connection(session->server_send->mhd_conn);
774  session->server_send->suspended = false;
775  }
776  server_reschedule(session->plugin,
777  session->server_send->mhd_daemon,
778  GNUNET_YES);
779  }
780  return bytes_sent;
781 }
782 
783 
792 static int
794  const struct GNUNET_PeerIdentity *peer,
795  void *value)
796 {
797  struct GNUNET_ATS_Session *s = value;
798  struct ServerRequest *sc_send;
799  struct ServerRequest *sc_recv;
800 
801  sc_send = s->server_send;
802  sc_recv = s->server_recv;
804  if (NULL != sc_send)
805  sc_send->session = NULL;
806  if (NULL != sc_recv)
807  sc_recv->session = NULL;
808 
809  return GNUNET_OK;
810 }
811 
812 
821 static int
823  const struct GNUNET_PeerIdentity *peer,
824  void *value)
825 {
826  struct GNUNET_ATS_Session *s = value;
827 
829  return GNUNET_OK;
830 }
831 
832 
841 static void
843  const struct GNUNET_PeerIdentity *target)
844 {
845  struct HTTP_Server_Plugin *plugin = cls;
846 
848  "Transport tells me to disconnect `%s'\n",
849  GNUNET_i2s(target));
851  target,
853  plugin);
854 }
855 
856 
869 static int
871  const void *addr,
872  size_t addrlen)
873 {
874  struct HTTP_Server_Plugin *plugin = cls;
875  struct HttpAddressWrapper *next;
876  struct HttpAddressWrapper *pos;
877  const struct HttpAddress *haddr = addr;
878 
879  if ((NULL != plugin->ext_addr) &&
880  GNUNET_YES == (http_common_cmp_addresses(addr, addrlen,
881  plugin->ext_addr->address,
882  plugin->ext_addr->address_length)))
883  {
884  /* Checking HTTP_OPTIONS_VERIFY_CERTIFICATE option for external hostname */
885  if ((ntohl(haddr->options) & HTTP_OPTIONS_VERIFY_CERTIFICATE) !=
887  return GNUNET_NO; /* VERIFY option not set as required! */
888  return GNUNET_OK;
889  }
890  next = plugin->addr_head;
891  while (NULL != (pos = next))
892  {
893  next = pos->next;
895  addrlen,
896  pos->address,
897  pos->addrlen)))
898  return GNUNET_OK;
899  }
900  return GNUNET_NO;
901 }
902 
903 
914 static struct GNUNET_ATS_Session *
916  const struct GNUNET_HELLO_Address *address)
917 {
918  return NULL;
919 }
920 
921 
928 static void
929 server_v4_run(void *cls)
930 {
931  struct HTTP_Server_Plugin *plugin = cls;
932 
933  plugin->server_v4_task = NULL;
935  GNUNET_assert(MHD_YES == MHD_run(plugin->server_v4));
936  server_reschedule(plugin, plugin->server_v4, GNUNET_NO);
937 }
938 
939 
946 static void
947 server_v6_run(void *cls)
948 {
949  struct HTTP_Server_Plugin *plugin = cls;
950 
951  plugin->server_v6_task = NULL;
953  GNUNET_assert(MHD_YES == MHD_run(plugin->server_v6));
954  server_reschedule(plugin, plugin->server_v6, GNUNET_NO);
955 }
956 
957 
967 static struct GNUNET_SCHEDULER_Task *
969  struct MHD_Daemon *daemon_handle,
970  int now)
971 {
972  struct GNUNET_SCHEDULER_Task * ret;
973  fd_set rs;
974  fd_set ws;
975  fd_set es;
976  struct GNUNET_NETWORK_FDSet *wrs;
977  struct GNUNET_NETWORK_FDSet *wws;
978  int max;
979  MHD_UNSIGNED_LONG_LONG timeout;
980  static unsigned long long last_timeout = 0;
981  int haveto;
982  struct GNUNET_TIME_Relative tv;
983 
984  if (GNUNET_YES == plugin->in_shutdown)
985  return NULL;
986 
987  ret = NULL;
988  FD_ZERO(&rs);
989  FD_ZERO(&ws);
990  FD_ZERO(&es);
993  max = -1;
994  GNUNET_assert(MHD_YES ==
995  MHD_get_fdset(daemon_handle,
996  &rs,
997  &ws,
998  &es,
999  &max));
1000  haveto = MHD_get_timeout(daemon_handle, &timeout);
1001  if (haveto == MHD_YES)
1002  {
1003  if (timeout != last_timeout)
1004  {
1006  "SELECT Timeout changed from %llu to %llu (ms)\n",
1007  last_timeout, timeout);
1008  last_timeout = timeout;
1009  }
1010  if (timeout <= GNUNET_TIME_UNIT_SECONDS.rel_value_us / 1000LL)
1011  tv.rel_value_us = (uint64_t)timeout * 1000LL;
1012  else
1014  }
1015  else
1017  /* Force immediate run, since we have outbound data to send */
1018  if (now == GNUNET_YES)
1020  GNUNET_NETWORK_fdset_copy_native(wrs, &rs, max + 1);
1021  GNUNET_NETWORK_fdset_copy_native(wws, &ws, max + 1);
1022 
1023  if (daemon_handle == plugin->server_v4)
1024  {
1025  if (plugin->server_v4_task != NULL)
1026  {
1028  plugin->server_v4_task = NULL;
1029  }
1030 #if 0
1032  "Scheduling IPv4 server task in %llu ms\n",
1033  tv);
1034 #endif
1035  ret =
1037  tv, wrs, wws,
1038  &server_v4_run, plugin);
1039  }
1040  if (daemon_handle == plugin->server_v6)
1041  {
1042  if (plugin->server_v6_task != NULL)
1043  {
1045  plugin->server_v6_task = NULL;
1046  }
1047 #if 0
1049  "Scheduling IPv6 server task in %llu ms\n", tv);
1050 #endif
1051  ret =
1053  tv, wrs, wws,
1054  &server_v6_run, plugin);
1055  }
1058  return ret;
1059 }
1060 
1061 
1070 static void
1072  struct MHD_Daemon *server,
1073  int now)
1074 {
1075  if ((server == plugin->server_v4) && (plugin->server_v4 != NULL))
1076  {
1077  if (GNUNET_YES == plugin->server_v4_immediately)
1078  return; /* No rescheduling, server will run asap */
1079 
1080  if (GNUNET_YES == now)
1082 
1083  if (plugin->server_v4_task != NULL)
1084  {
1086  plugin->server_v4_task = NULL;
1087  }
1088  plugin->server_v4_task = server_schedule(plugin, plugin->server_v4, now);
1089  }
1090 
1091  if ((server == plugin->server_v6) && (plugin->server_v6 != NULL))
1092  {
1093  if (GNUNET_YES == plugin->server_v6_immediately)
1094  return; /* No rescheduling, server will run asap */
1095 
1096  if (GNUNET_YES == now)
1098 
1099  if (plugin->server_v6_task != NULL)
1100  {
1102  plugin->server_v6_task = NULL;
1103  }
1104  plugin->server_v6_task = server_schedule(plugin, plugin->server_v6, now);
1105  }
1106 }
1107 
1108 
1117 static unsigned int
1119 {
1120  return 3;
1121 }
1122 
1123 
1133 static void
1135  const struct GNUNET_PeerIdentity *peer,
1136  struct GNUNET_ATS_Session *session)
1137 {
1139 }
1140 
1141 
1149 static void
1151  struct GNUNET_ATS_Session *s,
1152  unsigned int to)
1153 {
1154  /* Setting timeouts for other connections */
1155  if (NULL != s->server_recv)
1156  {
1158  "Setting timeout for %p to %u sec.\n",
1159  s->server_recv, to);
1160  MHD_set_connection_option(s->server_recv->mhd_conn,
1161  MHD_CONNECTION_OPTION_TIMEOUT,
1162  to);
1164  }
1165  if (NULL != s->server_send)
1166  {
1168  "Setting timeout for %p to %u sec.\n",
1169  s->server_send, to);
1170  MHD_set_connection_option(s->server_send->mhd_conn,
1171  MHD_CONNECTION_OPTION_TIMEOUT,
1172  to);
1174  }
1175 }
1176 
1177 
1188 static int
1190  const char *url,
1191  struct GNUNET_PeerIdentity *target,
1192  uint32_t *tag,
1193  uint32_t *options)
1194 {
1195  regmatch_t matches[4];
1196  const char *tag_start;
1197  const char *target_start;
1198  char *tag_end;
1199  char *options_end;
1200  size_t hash_length;
1201  unsigned long int rc;
1202 
1203  /* URL parsing */
1204 #define URL_REGEX \
1205  ("^.*/([0-9A-Z]+);([0-9]+)(,[0-9]+)?$")
1206 
1207  if (NULL == url)
1208  {
1209  GNUNET_break(0);
1210  return GNUNET_SYSERR;
1211  }
1212 
1213  if (regexec(&plugin->url_regex, url, 4, matches, 0))
1214  {
1216  "URL `%s' did not match regex\n", url);
1217  return GNUNET_SYSERR;
1218  }
1219 
1220  target_start = &url[matches[1].rm_so];
1221  tag_start = &url[matches[2].rm_so];
1222 
1223  /* convert tag */
1224  rc = strtoul(tag_start, &tag_end, 10);
1225  if (&url[matches[2].rm_eo] != tag_end)
1226  {
1228  "URL tag did not line up with submatch\n");
1229  return GNUNET_SYSERR;
1230  }
1231  if (rc == 0)
1232  {
1234  "URL tag is zero\n");
1235  return GNUNET_SYSERR;
1236  }
1237  if ((rc == ULONG_MAX) && (ERANGE == errno))
1238  {
1240  "URL tag > ULONG_MAX\n");
1241  return GNUNET_SYSERR;
1242  }
1243  if (rc > UINT32_MAX)
1244  {
1246  "URL tag > UINT32_MAX\n");
1247  return GNUNET_SYSERR;
1248  }
1249  (*tag) = (uint32_t)rc;
1251  "Found tag `%u' in url\n",
1252  *tag);
1253 
1254  /* convert peer id */
1255  hash_length = matches[1].rm_eo - matches[1].rm_so;
1256  if (hash_length != plugin->peer_id_length)
1257  {
1259  "URL target is %u bytes, expecting %u\n",
1260  hash_length, plugin->peer_id_length);
1261  return GNUNET_SYSERR;
1262  }
1263  if (GNUNET_OK !=
1265  hash_length,
1266  &target->public_key))
1267  {
1269  "URL target conversion failed\n");
1270  return GNUNET_SYSERR;
1271  }
1273  "Found target `%s' in URL\n",
1274  GNUNET_i2s_full(target));
1275 
1276  /* convert options */
1277  if (-1 == matches[3].rm_so)
1278  {
1279  *options = 0;
1280  }
1281  else
1282  {
1283  rc = strtoul(&url[matches[3].rm_so + 1], &options_end, 10);
1284  if (&url[matches[3].rm_eo] != options_end)
1285  {
1287  "URL options did not line up with submatch\n");
1288  return GNUNET_SYSERR;
1289  }
1290  if ((rc == ULONG_MAX) && (ERANGE == errno))
1291  {
1293  "URL options > ULONG_MAX\n");
1294  return GNUNET_SYSERR;
1295  }
1296  if (rc > UINT32_MAX)
1297  {
1299  "URL options > UINT32_MAX\n");
1300  return GNUNET_SYSERR;
1301  }
1302  (*options) = (uint32_t)rc;
1304  "Found options `%u' in url\n",
1305  *options);
1306  }
1307  return GNUNET_OK;
1308 }
1309 
1310 
1319 
1323  uint32_t tag;
1324 };
1325 
1326 
1335 static int
1336 session_tag_it(void *cls,
1337  const struct GNUNET_PeerIdentity *key,
1338  void *value)
1339 {
1340  struct GNUNET_ATS_SessionTagContext *stc = cls;
1341  struct GNUNET_ATS_Session *s = value;
1342 
1343  if (s->tag == stc->tag)
1344  {
1345  stc->res = s;
1346  return GNUNET_NO;
1347  }
1348  return GNUNET_YES;
1349 }
1350 
1351 
1361 static struct ServerRequest *
1363  struct MHD_Connection *mhd_connection,
1364  const char *url,
1365  const char *method)
1366 {
1367  struct GNUNET_ATS_Session *s = NULL;
1368  struct ServerRequest *sc = NULL;
1369  const union MHD_ConnectionInfo *conn_info;
1370  struct HttpAddress *addr;
1371  struct GNUNET_PeerIdentity target;
1372  size_t addr_len;
1373  struct GNUNET_ATS_SessionTagContext stc;
1374  uint32_t options;
1375  int direction = GNUNET_SYSERR;
1376  unsigned int to;
1378 
1379  conn_info = MHD_get_connection_info(mhd_connection,
1380  MHD_CONNECTION_INFO_CLIENT_ADDRESS);
1381  if ((conn_info->client_addr->sa_family != AF_INET) &&
1382  (conn_info->client_addr->sa_family != AF_INET6))
1383  return NULL;
1385  "New %s request from %s\n",
1386  method,
1387  url);
1388  stc.tag = 0;
1389  options = 0; /* make gcc happy */
1390  if (GNUNET_SYSERR ==
1391  server_parse_url(plugin, url, &target, &stc.tag, &options))
1392  {
1394  "Invalid url %s\n", url);
1395  return NULL;
1396  }
1397  if (0 == strcmp(MHD_HTTP_METHOD_PUT, method))
1398  direction = _RECEIVE;
1399  else if (0 == strcmp(MHD_HTTP_METHOD_GET, method))
1400  direction = _SEND;
1401  else
1402  {
1404  "Invalid method %s for request from %s\n",
1405  method, url);
1406  return NULL;
1407  }
1408 
1409  plugin->cur_request++;
1411  "New %s request from %s with tag %u (%u of %u)\n",
1412  method,
1413  GNUNET_i2s(&target),
1414  stc.tag,
1415  plugin->cur_request, plugin->max_request);
1416  /* find existing session */
1417  stc.res = NULL;
1419  &target,
1420  &session_tag_it,
1421  &stc);
1422  if (NULL == (s = stc.res))
1423  {
1424  /* create new session */
1425  addr = NULL;
1426  switch (conn_info->client_addr->sa_family)
1427  {
1428  case (AF_INET):
1430  conn_info->client_addr,
1431  sizeof(struct sockaddr_in));
1432  addr_len = http_common_address_get_size(addr);
1433  scope = plugin->env->get_address_type(plugin->env->cls,
1434  conn_info->client_addr,
1435  sizeof(struct sockaddr_in));
1436  break;
1437 
1438  case (AF_INET6):
1440  conn_info->client_addr,
1441  sizeof(struct sockaddr_in6));
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_in6));
1446  break;
1447 
1448  default:
1449  /* external host name */
1450  return NULL;
1451  }
1452  s = GNUNET_new(struct GNUNET_ATS_Session);
1453  s->target = target;
1454  s->plugin = plugin;
1455  s->scope = scope;
1457  PLUGIN_NAME,
1458  addr,
1459  addr_len,
1462  s->tag = stc.tag;
1466  s);
1468  &s->target,
1469  s,
1471  notify_session_monitor(plugin,
1472  s,
1474  notify_session_monitor(plugin,
1475  s,
1478  "Creating new session %p for peer `%s' connecting from `%s'\n",
1479  s, GNUNET_i2s(&target),
1481  addr,
1482  addr_len));
1483  GNUNET_free_non_null(addr);
1484  }
1485 
1486  if ((_RECEIVE == direction) &&
1487  (NULL != s->server_recv))
1488  {
1490  "Duplicate PUT request from `%s' tag %u, dismissing new request\n",
1491  GNUNET_i2s(&target),
1492  stc.tag);
1493  return NULL;
1494  }
1495  if ((_SEND == direction) && (NULL != s->server_send))
1496  {
1498  "Duplicate GET request from `%s' tag %u, dismissing new request\n",
1499  GNUNET_i2s(&target),
1500  stc.tag);
1501  return NULL;
1502  }
1503  sc = GNUNET_new(struct ServerRequest);
1504  if (conn_info->client_addr->sa_family == AF_INET)
1505  sc->mhd_daemon = plugin->server_v4;
1506  if (conn_info->client_addr->sa_family == AF_INET6)
1507  sc->mhd_daemon = plugin->server_v6;
1508  sc->mhd_conn = mhd_connection;
1509  sc->direction = direction;
1510  sc->connected = GNUNET_NO;
1511  sc->session = s;
1512  sc->options = options;
1513  if (direction == _SEND)
1514  {
1515  s->server_send = sc;
1516  }
1517  if (direction == _RECEIVE)
1518  {
1519  s->server_recv = sc;
1520  }
1521 
1522  if ((GNUNET_NO == s->known_to_service) &&
1523  (NULL != s->server_send) &&
1524  (NULL != s->server_recv))
1525  {
1527  notify_session_monitor(plugin,
1528  s,
1530  plugin->env->session_start(plugin->env->cls,
1531  s->address,
1532  s,
1533  s->scope);
1534  }
1535 
1536  to = (HTTP_SERVER_SESSION_TIMEOUT.rel_value_us / 1000LL / 1000LL);
1537  server_mhd_connection_timeout(plugin, s, to);
1538  return sc;
1539 }
1540 
1541 
1551 static ssize_t
1553  uint64_t pos,
1554  char *buf,
1555  size_t max)
1556 {
1557  struct ServerRequest *sc = cls;
1558  struct GNUNET_ATS_Session *s = sc->session;
1559  ssize_t bytes_read = 0;
1560  struct HTTP_Message *msg;
1561  char *stat_txt;
1562 
1563  if (NULL == s)
1564  {
1565  /* session is disconnecting */
1566  return 0;
1567  }
1568 
1569  sc = s->server_send;
1570  if (NULL == sc)
1571  return 0;
1572  msg = s->msg_head;
1573  if (NULL != msg)
1574  {
1575  /* sending */
1576  bytes_read = GNUNET_MIN(msg->size - msg->pos,
1577  max);
1578  GNUNET_memcpy(buf, &msg->buf[msg->pos], bytes_read);
1579  msg->pos += bytes_read;
1580 
1581  /* removing message */
1582  if (msg->pos == msg->size)
1583  {
1585  s->msg_tail,
1586  msg);
1587  if (NULL != msg->transmit_cont)
1589  msg->size, msg->size + msg->overhead);
1590  GNUNET_assert(s->msgs_in_queue > 0);
1591  s->msgs_in_queue--;
1592  GNUNET_assert(s->bytes_in_queue >= msg->size);
1593  s->bytes_in_queue -= msg->size;
1594  GNUNET_free(msg);
1596  s,
1598  }
1599  }
1600  if (0 < bytes_read)
1601  {
1602  sc->connected = GNUNET_YES;
1604  "Sent %u bytes to peer `%s' with session %p \n",
1605  bytes_read,
1606  GNUNET_i2s(&s->target),
1607  s);
1608  GNUNET_asprintf(&stat_txt,
1609  "# bytes currently in %s_server buffers",
1610  s->plugin->protocol);
1611  GNUNET_STATISTICS_update(s->plugin->env->stats,
1612  stat_txt,
1613  -bytes_read,
1614  GNUNET_NO);
1615  GNUNET_free(stat_txt);
1616  GNUNET_asprintf(&stat_txt,
1617  "# bytes transmitted via %s_server",
1618  s->plugin->protocol);
1619  GNUNET_STATISTICS_update(s->plugin->env->stats,
1620  stat_txt, bytes_read, GNUNET_NO);
1621  GNUNET_free(stat_txt);
1622  }
1623  else if ((sc->options & OPTION_LONG_POLL) && sc->connected)
1624  {
1626  "Completing GET response to peer `%s' with session %p\n",
1627  GNUNET_i2s(&s->target),
1628  s);
1629  return MHD_CONTENT_READER_END_OF_STREAM;
1630  }
1631  else
1632  {
1633  MHD_suspend_connection(s->server_send->mhd_conn);
1634  s->server_send->suspended = true;
1635  return 0;
1636  }
1637  return bytes_read;
1638 }
1639 
1640 
1648 static int
1650  const struct GNUNET_MessageHeader *message)
1651 {
1652  struct GNUNET_ATS_Session *s = cls;
1653  struct HTTP_Server_Plugin *plugin = s->plugin;
1654  struct GNUNET_TIME_Relative delay;
1655  char *stat_txt;
1656 
1657  if (GNUNET_NO == s->known_to_service)
1658  {
1660  plugin->env->session_start(plugin->env->cls,
1661  s->address,
1662  s,
1663  s->scope);
1664  notify_session_monitor(plugin,
1665  s,
1667  }
1668  delay = plugin->env->receive(plugin->env->cls,
1669  s->address,
1670  s,
1671  message);
1672  GNUNET_asprintf(&stat_txt,
1673  "# bytes received via %s_server",
1674  plugin->protocol);
1676  stat_txt,
1677  ntohs(message->size),
1678  GNUNET_NO);
1679  GNUNET_free(stat_txt);
1681  if (delay.rel_value_us > 0)
1682  {
1684  "Peer `%s' address `%s' next read delayed for %s\n",
1685  GNUNET_i2s(&s->target),
1687  s->address->address,
1688  s->address->address_length),
1690  GNUNET_YES));
1691  }
1693  return GNUNET_OK;
1694 }
1695 
1696 
1703 static void
1704 add_cors_headers(struct MHD_Response *response)
1705 {
1706  MHD_add_response_header(response,
1707  "Access-Control-Allow-Origin",
1708  "*");
1709  MHD_add_response_header(response,
1710  "Access-Control-Allow-Methods",
1711  "GET, PUT, OPTIONS");
1712  MHD_add_response_header(response,
1713  "Access-Control-Max-Age",
1714  "86400");
1715 }
1716 
1717 
1731 static int
1733  struct MHD_Connection *mhd_connection,
1734  const char *url,
1735  const char *method,
1736  const char *version,
1737  const char *upload_data,
1738  size_t *upload_data_size,
1739  void **httpSessionCache)
1740 {
1741  struct HTTP_Server_Plugin *plugin = cls;
1742  struct ServerRequest *sc = *httpSessionCache;
1743  struct GNUNET_ATS_Session *s;
1744  struct MHD_Response *response;
1745  int res = MHD_YES;
1746 
1748  _("Access from connection %p (%u of %u) for `%s' `%s' url `%s' with upload data size %u\n"),
1749  sc,
1750  plugin->cur_request,
1751  plugin->max_request,
1752  method,
1753  version,
1754  url,
1755  (*upload_data_size));
1756  if (NULL == sc)
1757  {
1758  /* CORS pre-flight request */
1759  if (0 == strcmp(MHD_HTTP_METHOD_OPTIONS, method))
1760  {
1761  response = MHD_create_response_from_buffer(0, NULL,
1762  MHD_RESPMEM_PERSISTENT);
1763  add_cors_headers(response);
1764  res = MHD_queue_response(mhd_connection, MHD_HTTP_OK, response);
1765  MHD_destroy_response(response);
1766  return res;
1767  }
1768  /* new connection */
1769  sc = server_lookup_connection(plugin, mhd_connection, url, method);
1770  if (NULL != sc)
1771  {
1772  /* attach to new / existing session */
1773  (*httpSessionCache) = sc;
1774  }
1775  else
1776  {
1777  /* existing session already has matching connection, refuse */
1778  response = MHD_create_response_from_buffer(strlen(HTTP_ERROR_RESPONSE),
1780  MHD_RESPMEM_PERSISTENT);
1781  MHD_add_response_header(response,
1782  MHD_HTTP_HEADER_CONTENT_TYPE,
1783  "text/html");
1784  add_cors_headers(response);
1785  res = MHD_queue_response(mhd_connection, MHD_HTTP_NOT_FOUND, response);
1786  MHD_destroy_response(response);
1787  return res;
1788  }
1789  }
1790  /* 'old' connection */
1791  if (NULL == (s = sc->session))
1792  {
1793  /* Session was already disconnected;
1794  sent HTTP/1.1: 200 OK as response */
1795  response = MHD_create_response_from_buffer(strlen("Thank you!"),
1796  "Thank you!",
1797  MHD_RESPMEM_PERSISTENT);
1798  add_cors_headers(response);
1799  MHD_queue_response(mhd_connection, MHD_HTTP_OK, response);
1800  MHD_destroy_response(response);
1801  return MHD_YES;
1802  }
1803 
1804  if (sc->direction == _SEND)
1805  {
1806  response = MHD_create_response_from_callback(MHD_SIZE_UNKNOWN, 32 * 1024,
1807  &server_send_callback, sc, NULL);
1808  add_cors_headers(response);
1809  MHD_queue_response(mhd_connection, MHD_HTTP_OK, response);
1810  MHD_destroy_response(response);
1811  return MHD_YES;
1812  }
1813  if (sc->direction == _RECEIVE)
1814  {
1815  if ((*upload_data_size == 0) && (sc->connected == GNUNET_NO))
1816  {
1817  /* (*upload_data_size == 0) first callback when header are passed */
1819  "Session %p / Connection %p: Peer `%s' PUT on address `%s' connected\n",
1820  s, sc,
1821  GNUNET_i2s(&s->target),
1823  s->address->address,
1824  s->address->address_length));
1825  sc->connected = GNUNET_YES;
1826  return MHD_YES;
1827  }
1828  else if ((*upload_data_size == 0) && (sc->connected == GNUNET_YES))
1829  {
1830  /* (*upload_data_size == 0) when upload is complete */
1832  "Session %p / Connection %p: Peer `%s' PUT on address `%s' finished upload\n",
1833  s, sc,
1834  GNUNET_i2s(&s->target),
1836  s->address->address,
1837  s->address->address_length));
1838  sc->connected = GNUNET_NO;
1839  /* Sent HTTP/1.1: 200 OK as PUT Response\ */
1840  response = MHD_create_response_from_buffer(strlen("Thank you!"),
1841  "Thank you!",
1842  MHD_RESPMEM_PERSISTENT);
1843  add_cors_headers(response);
1844  MHD_queue_response(mhd_connection, MHD_HTTP_OK, response);
1845  MHD_destroy_response(response);
1846  return MHD_YES;
1847  }
1848  else if ((*upload_data_size > 0) && (sc->connected == GNUNET_YES))
1849  {
1850  struct GNUNET_TIME_Relative delay;
1851 
1852  /* (*upload_data_size > 0) for every segment received */
1854  "Session %p / Connection %p: Peer `%s' PUT on address `%s' received %u bytes\n",
1855  s, sc,
1856  GNUNET_i2s(&s->target),
1858  s->address->address,
1859  s->address->address_length),
1860  *upload_data_size);
1862  if (0 == delay.rel_value_us)
1863  {
1865  "PUT with %u bytes forwarded to MST\n",
1866  *upload_data_size);
1867  if (s->msg_tk == NULL)
1868  {
1870  s);
1871  }
1873  upload_data,
1874  *upload_data_size,
1875  GNUNET_NO, GNUNET_NO);
1877  GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value_us / 1000LL
1878  / 1000LL);
1879  (*upload_data_size) = 0;
1880  }
1881  else
1882  {
1883  /* delay processing */
1885  "Session %p / Connection %p: no inbound bandwidth available! Next read was delayed by %s\n",
1886  s,
1887  sc,
1889  GNUNET_YES));
1890  GNUNET_assert(s->server_recv->mhd_conn == mhd_connection);
1891  MHD_suspend_connection(s->server_recv->mhd_conn);
1892  s->server_recv->suspended = true;
1893  if (NULL == s->recv_wakeup_task)
1894  s->recv_wakeup_task
1896  &server_wake_up,
1897  s);
1898  }
1899  return MHD_YES;
1900  }
1901  else
1902  {
1903  GNUNET_break(0);
1904  return MHD_NO;
1905  }
1906  }
1907  return res;
1908 }
1909 
1910 
1918 static void
1920  struct MHD_Connection *connection,
1921  void **httpSessionCache)
1922 {
1923  struct HTTP_Server_Plugin *plugin = cls;
1924  struct ServerRequest *sc = *httpSessionCache;
1925 
1927  "Disconnect for connection %p\n",
1928  sc);
1929  if (NULL == sc)
1930  {
1931  /* CORS pre-flight request finished */
1932  return;
1933  }
1934 
1935  if (NULL != sc->session)
1936  {
1937  if (sc->direction == _SEND)
1938  {
1940  "Peer `%s' connection %p, GET on address `%s' disconnected\n",
1941  GNUNET_i2s(&sc->session->target),
1942  sc->session->server_send,
1944  sc->session->address->address,
1945  sc->session->address->address_length));
1946 
1947  sc->session->server_send = NULL;
1948  }
1949  else if (sc->direction == _RECEIVE)
1950  {
1952  "Peer `%s' connection %p PUT on address `%s' disconnected\n",
1953  GNUNET_i2s(&sc->session->target),
1954  sc->session->server_recv,
1956  sc->session->address->address,
1957  sc->session->address->address_length));
1958  sc->session->server_recv = NULL;
1959  if (NULL != sc->session->msg_tk)
1960  {
1962  sc->session->msg_tk = NULL;
1963  }
1964  }
1965  }
1966  GNUNET_free(sc);
1967  plugin->cur_request--;
1968 }
1969 
1970 
1980 static void
1982  struct MHD_Connection *connection,
1983  void **socket_context,
1984  enum MHD_ConnectionNotificationCode toe)
1985 {
1986  struct HTTP_Server_Plugin *plugin = cls;
1987  const union MHD_ConnectionInfo *info;
1988 
1989  if (MHD_CONNECTION_NOTIFY_STARTED == toe)
1990  return;
1991 
1992  /* Reschedule to remove closed socket from our select set */
1993  info = MHD_get_connection_info(connection,
1994  MHD_CONNECTION_INFO_DAEMON);
1995  GNUNET_assert(NULL != info);
1996  server_reschedule(plugin,
1997  info->daemon,
1998  GNUNET_YES);
1999 }
2000 
2001 
2010 static int
2012  const struct sockaddr *addr,
2013  socklen_t addr_len)
2014 {
2015  struct HTTP_Server_Plugin *plugin = cls;
2016 
2017  if (plugin->cur_request <= plugin->max_request)
2018  {
2020  _("Accepting connection (%u of %u) from `%s'\n"),
2021  plugin->cur_request, plugin->max_request,
2022  GNUNET_a2s(addr, addr_len));
2023  return MHD_YES;
2024  }
2025  else
2026  {
2028  _("Server reached maximum number connections (%u), rejecting new connection\n"),
2029  plugin->max_request);
2030  return MHD_NO;
2031  }
2032 }
2033 
2034 
2043 static void
2045  const char *fmt,
2046  va_list ap)
2047 {
2048  char text[1024];
2049 
2050  vsnprintf(text,
2051  sizeof(text),
2052  fmt,
2053  ap);
2055  "Server: %s\n",
2056  text);
2057 }
2058 
2059 
2060 #if BUILD_HTTPS
2061 
2067 static char *
2068 server_load_file(const char *file)
2069 {
2070  struct GNUNET_DISK_FileHandle *gn_file;
2071  uint64_t fsize;
2072  char *text = NULL;
2073 
2074  if (GNUNET_OK != GNUNET_DISK_file_size(file,
2075  &fsize, GNUNET_NO, GNUNET_YES))
2076  return NULL;
2077  text = GNUNET_malloc(fsize + 1);
2078  gn_file =
2081  if (NULL == gn_file)
2082  {
2083  GNUNET_free(text);
2084  return NULL;
2085  }
2086  if (GNUNET_SYSERR == GNUNET_DISK_file_read(gn_file, text, fsize))
2087  {
2088  GNUNET_free(text);
2089  GNUNET_DISK_file_close(gn_file);
2090  return NULL;
2091  }
2092  text[fsize] = '\0';
2093  GNUNET_DISK_file_close(gn_file);
2094  return text;
2095 }
2096 #endif
2097 
2098 
2099 #if BUILD_HTTPS
2100 
2106 static int
2107 server_load_certificate(struct HTTP_Server_Plugin *plugin)
2108 {
2109  int res = GNUNET_OK;
2110  char *key_file;
2111  char *cert_file;
2112 
2113 
2114  if (GNUNET_OK !=
2116  plugin->name,
2117  "KEY_FILE", &key_file))
2118  {
2120  plugin->name, "CERT_FILE");
2121  return GNUNET_SYSERR;
2122  }
2123  if (GNUNET_OK !=
2125  plugin->name,
2126  "CERT_FILE", &cert_file))
2127  {
2129  plugin->name, "CERT_FILE");
2130  GNUNET_free(key_file);
2131  return GNUNET_SYSERR;
2132  }
2133  /* Get crypto init string from config. If not present, use
2134  * default values */
2135  if (GNUNET_OK ==
2137  plugin->name,
2138  "CRYPTO_INIT",
2139  &plugin->crypto_init))
2141  "Using crypto init string `%s'\n",
2142  plugin->crypto_init);
2143  else
2145  "Using default crypto init string \n");
2146 
2147  /* read key & certificates from file */
2149  "Trying to loading TLS certificate from key-file `%s' cert-file`%s'\n",
2150  key_file, cert_file);
2151 
2152  plugin->key = server_load_file(key_file);
2153  plugin->cert = server_load_file(cert_file);
2154 
2155  if ((plugin->key == NULL) || (plugin->cert == NULL))
2156  {
2157  struct GNUNET_OS_Process *cert_creation;
2158 
2159  GNUNET_free_non_null(plugin->key);
2160  plugin->key = NULL;
2161  GNUNET_free_non_null(plugin->cert);
2162  plugin->cert = NULL;
2163 
2165  "No usable TLS certificate found, creating certificate\n");
2166  errno = 0;
2167  cert_creation =
2169  NULL, NULL, NULL,
2170  "gnunet-transport-certificate-creation",
2171  "gnunet-transport-certificate-creation",
2172  key_file,
2173  cert_file,
2174  NULL);
2175  if (NULL == cert_creation)
2176  {
2178  _("Could not create a new TLS certificate, program `gnunet-transport-certificate-creation' could not be started!\n"));
2179  GNUNET_free(key_file);
2180  GNUNET_free(cert_file);
2181 
2182  GNUNET_free_non_null(plugin->key);
2183  plugin->key = NULL;
2184  GNUNET_free_non_null(plugin->cert);
2185  plugin->cert = NULL;
2186  GNUNET_free_non_null(plugin->crypto_init);
2187  plugin->crypto_init = NULL;
2188 
2189  return GNUNET_SYSERR;
2190  }
2191  GNUNET_assert(GNUNET_OK == GNUNET_OS_process_wait(cert_creation));
2192  GNUNET_OS_process_destroy(cert_creation);
2193 
2194  plugin->key = server_load_file(key_file);
2195  plugin->cert = server_load_file(cert_file);
2196  }
2197 
2198  if ((plugin->key == NULL) || (plugin->cert == NULL))
2199  {
2201  _("No usable TLS certificate found and creating one at `%s/%s' failed!\n"),
2202  key_file, cert_file);
2203  GNUNET_free(key_file);
2204  GNUNET_free(cert_file);
2205 
2206  GNUNET_free_non_null(plugin->key);
2207  plugin->key = NULL;
2208  GNUNET_free_non_null(plugin->cert);
2209  plugin->cert = NULL;
2210  GNUNET_free_non_null(plugin->crypto_init);
2211  plugin->crypto_init = NULL;
2212 
2213  return GNUNET_SYSERR;
2214  }
2215  GNUNET_free(key_file);
2216  GNUNET_free(cert_file);
2218  "TLS certificate loaded\n");
2219  return res;
2220 }
2221 #endif
2222 
2223 
2233 static struct MHD_Daemon *
2235  const struct sockaddr_in *addr,
2236  int v6)
2237 {
2238  struct MHD_Daemon *server;
2239  unsigned int timeout;
2240 
2241 #if MHD_VERSION >= 0x00090E00
2242  timeout = HTTP_SERVER_NOT_VALIDATED_TIMEOUT.rel_value_us / 1000LL / 1000LL;
2244  "MHD can set timeout per connection! Default time out %u sec.\n",
2245  timeout);
2246 #else
2247  timeout = HTTP_SERVER_SESSION_TIMEOUT.rel_value_us / 1000LL / 1000LL;
2249  "MHD cannot set timeout per connection! Default time out %u sec.\n",
2250  timeout);
2251 #endif
2252  server = MHD_start_daemon(
2253 #if VERBOSE_SERVER
2254  MHD_USE_DEBUG |
2255 #endif
2256 #if BUILD_HTTPS
2257  MHD_USE_SSL |
2258 #endif
2259  MHD_USE_SUSPEND_RESUME |
2260  v6,
2261  plugin->port,
2262  &server_accept_cb, plugin,
2263  &server_access_cb, plugin,
2264  MHD_OPTION_SOCK_ADDR,
2265  addr,
2266  MHD_OPTION_CONNECTION_LIMIT,
2267  (unsigned int)plugin->max_request,
2268 #if BUILD_HTTPS
2269  MHD_OPTION_HTTPS_PRIORITIES,
2270  plugin->crypto_init,
2271  MHD_OPTION_HTTPS_MEM_KEY,
2272  plugin->key,
2273  MHD_OPTION_HTTPS_MEM_CERT,
2274  plugin->cert,
2275 #endif
2276  MHD_OPTION_CONNECTION_TIMEOUT,
2277  timeout,
2278  MHD_OPTION_CONNECTION_MEMORY_LIMIT,
2279  (size_t)(2 *
2281  MHD_OPTION_NOTIFY_COMPLETED,
2282  &server_disconnect_cb, plugin,
2283  MHD_OPTION_NOTIFY_CONNECTION,
2284  &server_connection_cb, plugin,
2285  MHD_OPTION_EXTERNAL_LOGGER,
2286  &server_log, NULL,
2287  MHD_OPTION_END);
2288 #ifdef TCP_STEALTH
2289  if ((NULL != server) &&
2290  (0 != (plugin->options & HTTP_OPTIONS_TCP_STEALTH)))
2291  {
2292  const union MHD_DaemonInfo *di;
2293 
2294  di = MHD_get_daemon_info(server,
2295  MHD_DAEMON_INFO_LISTEN_FD,
2296  NULL);
2297  if ((0 != setsockopt((int)di->listen_fd,
2298  IPPROTO_TCP,
2299  TCP_STEALTH,
2300  plugin->env->my_identity,
2301  sizeof(struct GNUNET_PeerIdentity))))
2302  {
2304  _("TCP_STEALTH not supported on this platform.\n"));
2305  MHD_stop_daemon(server);
2306  server = NULL;
2307  }
2308  }
2309 #endif
2310  return server;
2311 }
2312 
2313 
2320 static int
2322 {
2323  const char *msg;
2324 
2325  GNUNET_assert(NULL != plugin);
2326 #if BUILD_HTTPS
2327  if (GNUNET_SYSERR == server_load_certificate(plugin))
2328  {
2330  _("Could not load or create server certificate! Loading plugin failed!\n"));
2331  return GNUNET_SYSERR;
2332  }
2333 #endif
2334 
2335 
2336 
2337  plugin->server_v4 = NULL;
2338  if (GNUNET_YES == plugin->use_ipv4)
2339  {
2340  plugin->server_v4
2341  = run_mhd_start_daemon(plugin,
2342  (const struct sockaddr_in *)plugin->server_addr_v4,
2343  MHD_NO_FLAG);
2344 
2345  if (NULL == plugin->server_v4)
2346  {
2348  "Failed to start %s IPv4 server component on port %u\n",
2349  plugin->name,
2350  plugin->port);
2351  }
2352  else
2353  server_reschedule(plugin,
2354  plugin->server_v4,
2355  GNUNET_NO);
2356  }
2357 
2358 
2359  plugin->server_v6 = NULL;
2360  if (GNUNET_YES == plugin->use_ipv6)
2361  {
2362  plugin->server_v6
2363  = run_mhd_start_daemon(plugin,
2364  (const struct sockaddr_in *)plugin->server_addr_v6,
2365  MHD_USE_IPv6);
2366  if (NULL == plugin->server_v6)
2367  {
2369  "Failed to start %s IPv6 server component on port %u\n",
2370  plugin->name,
2371  plugin->port);
2372  }
2373  else
2374  {
2375  server_reschedule(plugin,
2376  plugin->server_v6,
2377  GNUNET_NO);
2378  }
2379  }
2380  msg = "No";
2381  if ((NULL == plugin->server_v6) &&
2382  (NULL == plugin->server_v4))
2383  {
2385  "%s %s server component started on port %u\n",
2386  msg,
2387  plugin->name,
2388  plugin->port);
2389  return GNUNET_SYSERR;
2390  }
2391  if ((NULL != plugin->server_v6) &&
2392  (NULL != plugin->server_v4))
2393  msg = "IPv4 and IPv6";
2394  else if (NULL != plugin->server_v6)
2395  msg = "IPv6";
2396  else if (NULL != plugin->server_v4)
2397  msg = "IPv4";
2399  "%s %s server component started on port %u\n",
2400  msg,
2401  plugin->name,
2402  plugin->port);
2403  return GNUNET_OK;
2404 }
2405 
2406 
2415 static void
2417  int add_remove,
2418  const struct sockaddr *addr,
2419  socklen_t addrlen)
2420 {
2421  struct HTTP_Server_Plugin *plugin = cls;
2422  struct GNUNET_HELLO_Address *address;
2423  struct HttpAddressWrapper *w = NULL;
2424 
2425  w = GNUNET_new(struct HttpAddressWrapper);
2427  addr,
2428  addrlen);
2429  if (NULL == w->address)
2430  {
2431  GNUNET_free(w);
2432  return;
2433  }
2435 
2437  plugin->addr_tail,
2438  w);
2440  "Notifying transport to add address `%s'\n",
2442  w->address,
2443  w->addrlen));
2444  /* modify our published address list */
2445 #if BUILD_HTTPS
2446  address = GNUNET_HELLO_address_allocate(plugin->env->my_identity,
2447  "https_client", w->address, w->addrlen, GNUNET_HELLO_ADDRESS_INFO_NONE);
2448 #else
2449  address = GNUNET_HELLO_address_allocate(plugin->env->my_identity,
2450  "http_client", w->address, w->addrlen, GNUNET_HELLO_ADDRESS_INFO_NONE);
2451 #endif
2452 
2453  plugin->env->notify_address(plugin->env->cls,
2454  add_remove,
2455  address);
2456  GNUNET_HELLO_address_free(address);
2457 }
2458 
2459 
2468 static void
2470  int add_remove,
2471  const struct sockaddr *addr,
2472  socklen_t addrlen)
2473 {
2474  struct HTTP_Server_Plugin *plugin = cls;
2475  struct GNUNET_HELLO_Address *address;
2476  struct HttpAddressWrapper *w = plugin->addr_head;
2477  size_t saddr_len;
2478  void * saddr;
2479 
2480  saddr = http_common_address_from_socket(plugin->protocol,
2481  addr,
2482  addrlen);
2483  if (NULL == saddr)
2484  return;
2485  saddr_len = http_common_address_get_size(saddr);
2486 
2487  while (NULL != w)
2488  {
2489  if (GNUNET_YES ==
2491  w->addrlen,
2492  saddr,
2493  saddr_len))
2494  break;
2495  w = w->next;
2496  }
2497  GNUNET_free(saddr);
2498 
2499  if (NULL == w)
2500  return;
2501 
2503  "Notifying transport to remove address `%s'\n",
2505  w->address,
2506  w->addrlen));
2508  plugin->addr_tail,
2509  w);
2510  /* modify our published address list */
2511 #if BUILD_HTTPS
2512  address = GNUNET_HELLO_address_allocate(plugin->env->my_identity,
2513  "https_client", w->address, w->addrlen, GNUNET_HELLO_ADDRESS_INFO_NONE);
2514 #else
2515  address = GNUNET_HELLO_address_allocate(plugin->env->my_identity,
2516  "http_client", w->address, w->addrlen, GNUNET_HELLO_ADDRESS_INFO_NONE);
2517 #endif
2518  plugin->env->notify_address(plugin->env->cls, add_remove, address);
2519  GNUNET_HELLO_address_free(address);
2520  GNUNET_free(w->address);
2521  GNUNET_free(w);
2522 }
2523 
2524 
2525 
2538 static void
2540  void **app_ctx,
2541  int add_remove,
2543  const struct sockaddr *addr,
2544  socklen_t addrlen)
2545 {
2546  struct HTTP_Server_Plugin *plugin = cls;
2547 
2548  (void)app_ctx;
2550  "NAT called to %s address `%s'\n",
2551  (add_remove == GNUNET_NO) ? "remove" : "add",
2552  GNUNET_a2s(addr, addrlen));
2553 
2554  if (AF_INET == addr->sa_family)
2555  {
2556  struct sockaddr_in *s4 = (struct sockaddr_in *)addr;
2557 
2558  if (GNUNET_NO == plugin->use_ipv4)
2559  return;
2560 
2561  if ((NULL != plugin->server_addr_v4) &&
2562  (0 != memcmp(&plugin->server_addr_v4->sin_addr,
2563  &s4->sin_addr,
2564  sizeof(struct in_addr))))
2565  {
2567  "Skipping address `%s' (not bindto address)\n",
2568  GNUNET_a2s(addr, addrlen));
2569  return;
2570  }
2571  }
2572 
2573  if (AF_INET6 == addr->sa_family)
2574  {
2575  struct sockaddr_in6 *s6 = (struct sockaddr_in6 *)addr;
2576  if (GNUNET_NO == plugin->use_ipv6)
2577  return;
2578 
2579  if ((NULL != plugin->server_addr_v6) &&
2580  (0 != memcmp(&plugin->server_addr_v6->sin6_addr,
2581  &s6->sin6_addr, sizeof(struct in6_addr))))
2582  {
2584  "Skipping address `%s' (not bindto address)\n",
2585  GNUNET_a2s(addr, addrlen));
2586  return;
2587  }
2588  }
2589 
2590  switch (add_remove)
2591  {
2592  case GNUNET_YES:
2593  server_add_address(cls, add_remove, addr, addrlen);
2594  break;
2595 
2596  case GNUNET_NO:
2597  server_remove_address(cls, add_remove, addr, addrlen);
2598  break;
2599  }
2600 }
2601 
2602 
2613 static int
2615  const char *service_name,
2616  const struct GNUNET_CONFIGURATION_Handle *cfg,
2617  struct sockaddr ***addrs,
2618  socklen_t ** addr_lens)
2619 {
2620  int disablev6;
2621  unsigned long long port;
2622  struct addrinfo hints;
2623  struct addrinfo *res;
2624  struct addrinfo *pos;
2625  struct addrinfo *next;
2626  unsigned int i;
2627  int resi;
2628  int ret;
2629  struct sockaddr **saddrs;
2630  socklen_t *saddrlens;
2631  char *hostname;
2632 
2633  *addrs = NULL;
2634  *addr_lens = NULL;
2635 
2636  disablev6 = !plugin->use_ipv6;
2637 
2638  port = 0;
2639  if (GNUNET_CONFIGURATION_have_value(cfg, service_name, "PORT"))
2640  {
2642  GNUNET_CONFIGURATION_get_value_number(cfg, service_name,
2643  "PORT", &port));
2644  if (port > 65535)
2645  {
2647  _("Require valid port number for service in configuration!\n"));
2648  return GNUNET_SYSERR;
2649  }
2650  }
2651  if (0 == port)
2652  {
2654  "Starting in listen only mode\n");
2655  return -1; /* listen only */
2656  }
2657 
2658 
2659  if (GNUNET_CONFIGURATION_have_value(cfg, service_name,
2660  "BINDTO"))
2661  {
2663  GNUNET_CONFIGURATION_get_value_string(cfg, service_name,
2664  "BINDTO", &hostname));
2665  }
2666  else
2667  hostname = NULL;
2668 
2669  if (NULL != hostname)
2670  {
2672  "Resolving `%s' since that is where `%s' will bind to.\n",
2673  hostname, service_name);
2674  memset(&hints, 0, sizeof(struct addrinfo));
2675  if (disablev6)
2676  hints.ai_family = AF_INET;
2677  if ((0 != (ret = getaddrinfo(hostname, NULL, &hints, &res))) ||
2678  (NULL == res))
2679  {
2681  _("Failed to resolve `%s': %s\n"),
2682  hostname,
2683  gai_strerror(ret));
2684  GNUNET_free(hostname);
2685  return GNUNET_SYSERR;
2686  }
2687  next = res;
2688  i = 0;
2689  while (NULL != (pos = next))
2690  {
2691  next = pos->ai_next;
2692  if ((disablev6) && (pos->ai_family == AF_INET6))
2693  continue;
2694  i++;
2695  }
2696  if (0 == i)
2697  {
2699  _("Failed to find %saddress for `%s'.\n"),
2700  disablev6 ? "IPv4 " : "", hostname);
2701  freeaddrinfo(res);
2702  GNUNET_free(hostname);
2703  return GNUNET_SYSERR;
2704  }
2705  resi = i;
2706  saddrs = GNUNET_malloc((resi + 1) * sizeof(struct sockaddr *));
2707  saddrlens = GNUNET_malloc((resi + 1) * sizeof(socklen_t));
2708  i = 0;
2709  next = res;
2710  while (NULL != (pos = next))
2711  {
2712  next = pos->ai_next;
2713  if ((disablev6) && (pos->ai_family == AF_INET6))
2714  continue;
2715  if ((pos->ai_protocol != IPPROTO_TCP) && (0 != pos->ai_protocol))
2716  continue; /* not TCP */
2717  if ((pos->ai_socktype != SOCK_STREAM) && (0 != pos->ai_socktype))
2718  continue; /* huh? */
2720  "Service will bind to `%s'\n",
2721  GNUNET_a2s(pos->ai_addr,
2722  pos->ai_addrlen));
2723  if (pos->ai_family == AF_INET)
2724  {
2725  GNUNET_assert(pos->ai_addrlen == sizeof(struct sockaddr_in));
2726  saddrlens[i] = pos->ai_addrlen;
2727  saddrs[i] = GNUNET_malloc(saddrlens[i]);
2728  GNUNET_memcpy(saddrs[i], pos->ai_addr, saddrlens[i]);
2729  ((struct sockaddr_in *)saddrs[i])->sin_port = htons(port);
2730  }
2731  else
2732  {
2733  GNUNET_assert(pos->ai_family == AF_INET6);
2734  GNUNET_assert(pos->ai_addrlen == sizeof(struct sockaddr_in6));
2735  saddrlens[i] = pos->ai_addrlen;
2736  saddrs[i] = GNUNET_malloc(saddrlens[i]);
2737  GNUNET_memcpy(saddrs[i], pos->ai_addr, saddrlens[i]);
2738  ((struct sockaddr_in6 *)saddrs[i])->sin6_port = htons(port);
2739  }
2740  i++;
2741  }
2742  GNUNET_free(hostname);
2743  freeaddrinfo(res);
2744  resi = i;
2745  }
2746  else
2747  {
2748  /* will bind against everything, just set port */
2749  if (disablev6)
2750  {
2751  /* V4-only */
2752  resi = 1;
2753  i = 0;
2754  saddrs = GNUNET_malloc((resi + 1) * sizeof(struct sockaddr *));
2755  saddrlens = GNUNET_malloc((resi + 1) * sizeof(socklen_t));
2756 
2757  saddrlens[i] = sizeof(struct sockaddr_in);
2758  saddrs[i] = GNUNET_malloc(saddrlens[i]);
2759 #if HAVE_SOCKADDR_IN_SIN_LEN
2760  ((struct sockaddr_in *)saddrs[i])->sin_len = saddrlens[i];
2761 #endif
2762  ((struct sockaddr_in *)saddrs[i])->sin_family = AF_INET;
2763  ((struct sockaddr_in *)saddrs[i])->sin_port = htons(port);
2764  }
2765  else
2766  {
2767  /* dual stack */
2768  resi = 2;
2769  saddrs = GNUNET_malloc((resi + 1) * sizeof(struct sockaddr *));
2770  saddrlens = GNUNET_malloc((resi + 1) * sizeof(socklen_t));
2771  i = 0;
2772  saddrlens[i] = sizeof(struct sockaddr_in6);
2773  saddrs[i] = GNUNET_malloc(saddrlens[i]);
2774 #if HAVE_SOCKADDR_IN_SIN_LEN
2775  ((struct sockaddr_in6 *)saddrs[i])->sin6_len = saddrlens[0];
2776 #endif
2777  ((struct sockaddr_in6 *)saddrs[i])->sin6_family = AF_INET6;
2778  ((struct sockaddr_in6 *)saddrs[i])->sin6_port = htons(port);
2779  i++;
2780  saddrlens[i] = sizeof(struct sockaddr_in);
2781  saddrs[i] = GNUNET_malloc(saddrlens[i]);
2782 #if HAVE_SOCKADDR_IN_SIN_LEN
2783  ((struct sockaddr_in *)saddrs[i])->sin_len = saddrlens[1];
2784 #endif
2785  ((struct sockaddr_in *)saddrs[i])->sin_family = AF_INET;
2786  ((struct sockaddr_in *)saddrs[i])->sin_port = htons(port);
2787  }
2788  }
2789  *addrs = saddrs;
2790  *addr_lens = saddrlens;
2791  return resi;
2792 }
2793 
2794 
2800 static void
2802 {
2803  int res = GNUNET_OK;
2804  struct sockaddr **addrs;
2805  socklen_t *addrlens;
2806 
2807  res = server_get_addresses(plugin,
2808  plugin->name,
2809  plugin->env->cfg,
2810  &addrs, &addrlens);
2812  _("Found %u addresses to report to NAT service\n"),
2813  res);
2814 
2815  if (GNUNET_SYSERR == res)
2816  {
2817  plugin->nat = NULL;
2818  return;
2819  }
2820 
2821  plugin->nat
2822  = GNUNET_NAT_register(plugin->env->cfg,
2823  "transport-http_server",
2824  IPPROTO_TCP,
2825  (unsigned int)res,
2826  (const struct sockaddr **)addrs,
2827  addrlens,
2829  NULL,
2830  plugin);
2831  while (res > 0)
2832  {
2833  res--;
2834  GNUNET_assert(NULL != addrs[res]);
2835  GNUNET_free(addrs[res]);
2836  }
2837  GNUNET_free_non_null(addrs);
2838  GNUNET_free_non_null(addrlens);
2839 }
2840 
2841 
2847 static void
2849 {
2850  struct HttpAddressWrapper *w;
2851 
2852  /* Stop NAT handle */
2853  if (NULL != plugin->nat)
2854  {
2855  GNUNET_NAT_unregister(plugin->nat);
2856  plugin->nat = NULL;
2857  }
2858  /* Clean up addresses */
2859  while (NULL != plugin->addr_head)
2860  {
2861  w = plugin->addr_head;
2863  plugin->addr_tail,
2864  w);
2865  GNUNET_free(w->address);
2866  GNUNET_free(w);
2867  }
2868 }
2869 
2870 
2877 static int
2879 {
2880  struct GNUNET_NETWORK_Handle *desc = NULL;
2881  int res = GNUNET_NO;
2882 
2883  /* Probe IPv6 support */
2884  desc = GNUNET_NETWORK_socket_create(PF_INET6,
2885  SOCK_STREAM,
2886  0);
2887  if (NULL == desc)
2888  {
2889  if ((errno == ENOBUFS) ||
2890  (errno == ENOMEM) ||
2891  (errno == ENFILE) ||
2892  (errno == EACCES))
2893  {
2895  "socket");
2896  }
2898  _("Disabling IPv6 since it is not supported on this system!\n"));
2899  res = GNUNET_NO;
2900  }
2901  else
2902  {
2905  desc = NULL;
2906  res = GNUNET_YES;
2907  }
2909  "Testing IPv6 on this system: %s\n",
2910  (res == GNUNET_YES) ? "successful" : "failed");
2911  return res;
2912 }
2913 
2914 
2920 static void
2922 {
2923  struct HTTP_Server_Plugin *plugin = cls;
2924  struct HttpAddress *ext_addr;
2925  size_t ext_addr_len;
2926  unsigned int urlen;
2927  char *url;
2928 
2929  plugin->notify_ext_task = NULL;
2930  GNUNET_asprintf(&url,
2931  "%s://%s",
2932  plugin->protocol,
2933  plugin->external_hostname);
2934  urlen = strlen(url) + 1;
2935  ext_addr = GNUNET_malloc(sizeof(struct HttpAddress) + urlen);
2936  ext_addr->options = htonl(plugin->options);
2937  ext_addr->urlen = htonl(urlen);
2938  ext_addr_len = sizeof(struct HttpAddress) + urlen;
2939  GNUNET_memcpy(&ext_addr[1], url, urlen);
2940  GNUNET_free(url);
2941 
2943  "Notifying transport about external hostname address `%s'\n",
2944  plugin->external_hostname);
2945 
2946 #if BUILD_HTTPS
2947  if (GNUNET_YES == plugin->verify_external_hostname)
2949  "Enabling SSL verification for external hostname address `%s'\n",
2950  plugin->external_hostname);
2951  plugin->ext_addr
2953  "https_client",
2954  ext_addr,
2955  ext_addr_len,
2957  plugin->env->notify_address(plugin->env->cls,
2958  GNUNET_YES,
2959  plugin->ext_addr);
2960  GNUNET_free(ext_addr);
2961 #else
2962  plugin->ext_addr
2964  "http_client",
2965  ext_addr,
2966  ext_addr_len,
2968  plugin->env->notify_address(plugin->env->cls,
2969  GNUNET_YES,
2970  plugin->ext_addr);
2971  GNUNET_free(ext_addr);
2972 #endif
2973 }
2974 
2975 
2982 static int
2984 {
2985  unsigned long long port;
2986  unsigned long long max_connections;
2987  char *bind4_address = NULL;
2988  char *bind6_address = NULL;
2989  char *eh_tmp = NULL;
2990  int external_hostname_use_port;
2991 
2992  /* Use IPv4? */
2994  (plugin->env->cfg, plugin->name, "USE_IPv4"))
2995  {
2996  plugin->use_ipv4 =
2998  plugin->name,
2999  "USE_IPv4");
3000  }
3001  else
3002  plugin->use_ipv4 = GNUNET_YES;
3004  _("IPv4 support is %s\n"),
3005  (plugin->use_ipv4 == GNUNET_YES) ? "enabled" : "disabled");
3006 
3007  /* Use IPv6? */
3009  (plugin->env->cfg, plugin->name, "USE_IPv6"))
3010  {
3011  plugin->use_ipv6 =
3013  plugin->name,
3014  "USE_IPv6");
3015  }
3016  else
3017  plugin->use_ipv6 = GNUNET_YES;
3019  _("IPv6 support is %s\n"),
3020  (plugin->use_ipv6 == GNUNET_YES) ? "enabled" : "disabled");
3021 
3022  if ((plugin->use_ipv4 == GNUNET_NO) && (plugin->use_ipv6 == GNUNET_NO))
3023  {
3025  _("Neither IPv4 nor IPv6 are enabled! Fix in configuration\n"));
3026  return GNUNET_SYSERR;
3027  }
3028 
3029  /* Reading port number from config file */
3030  if ((GNUNET_OK !=
3032  plugin->name,
3033  "PORT", &port)) || (port > 65535))
3034  {
3036  _("Port is required! Fix in configuration\n"));
3037  return GNUNET_SYSERR;
3038  }
3039  plugin->port = port;
3040 
3042  _("Using port %u\n"), plugin->port);
3043 
3044  if ((plugin->use_ipv4 == GNUNET_YES) &&
3045  (GNUNET_YES ==
3047  plugin->name,
3048  "BINDTO",
3049  &bind4_address)))
3050  {
3052  "Binding %s plugin to specific IPv4 address: `%s'\n",
3053  plugin->protocol,
3054  bind4_address);
3055  plugin->server_addr_v4 = GNUNET_new(struct sockaddr_in);
3056  if (1 != inet_pton(AF_INET,
3057  bind4_address,
3058  &plugin->server_addr_v4->sin_addr))
3059  {
3061  _("Specific IPv4 address `%s' in configuration file is invalid!\n"),
3062  bind4_address);
3063  GNUNET_free(bind4_address);
3064  GNUNET_free(plugin->server_addr_v4);
3065  plugin->server_addr_v4 = NULL;
3066  return GNUNET_SYSERR;
3067  }
3068  else
3069  {
3071  "Binding to IPv4 address %s\n",
3072  bind4_address);
3073  plugin->server_addr_v4->sin_family = AF_INET;
3074  plugin->server_addr_v4->sin_port = htons(plugin->port);
3075  }
3076  GNUNET_free(bind4_address);
3077  }
3078 
3079  if ((plugin->use_ipv6 == GNUNET_YES) &&
3080  (GNUNET_YES ==
3082  plugin->name,
3083  "BINDTO6",
3084  &bind6_address)))
3085  {
3087  "Binding %s plugin to specific IPv6 address: `%s'\n",
3088  plugin->protocol, bind6_address);
3089  plugin->server_addr_v6 = GNUNET_new(struct sockaddr_in6);
3090  if (1 !=
3091  inet_pton(AF_INET6,
3092  bind6_address,
3093  &plugin->server_addr_v6->sin6_addr))
3094  {
3096  _("Specific IPv6 address `%s' in configuration file is invalid!\n"),
3097  bind6_address);
3098  GNUNET_free(bind6_address);
3099  GNUNET_free(plugin->server_addr_v6);
3100  plugin->server_addr_v6 = NULL;
3101  return GNUNET_SYSERR;
3102  }
3103  else
3104  {
3106  "Binding to IPv6 address %s\n",
3107  bind6_address);
3108  plugin->server_addr_v6->sin6_family = AF_INET6;
3109  plugin->server_addr_v6->sin6_port = htons(plugin->port);
3110  }
3111  GNUNET_free(bind6_address);
3112  }
3113 
3115 #if BUILD_HTTPS
3116  plugin->verify_external_hostname
3118  plugin->name,
3119  "VERIFY_EXTERNAL_HOSTNAME");
3120  if (GNUNET_SYSERR == plugin->verify_external_hostname)
3122  if (GNUNET_YES == plugin->verify_external_hostname)
3124 #endif
3125  external_hostname_use_port
3127  plugin->name,
3128  "EXTERNAL_HOSTNAME_USE_PORT");
3129  if (GNUNET_SYSERR == external_hostname_use_port)
3130  external_hostname_use_port = GNUNET_NO;
3131 
3132 
3133  if (GNUNET_YES ==
3135  plugin->name,
3136  "EXTERNAL_HOSTNAME",
3137  &eh_tmp))
3138  {
3139  char *tmp;
3140  char *pos = NULL;
3141  char *pos_url = NULL;
3142 
3143  if (NULL != strstr(eh_tmp, "://"))
3144  tmp = &strstr(eh_tmp, "://")[3];
3145  else
3146  tmp = eh_tmp;
3147 
3148  if (GNUNET_YES == external_hostname_use_port)
3149  {
3150  if ((strlen(tmp) > 1) && (NULL != (pos = strchr(tmp, '/'))))
3151  {
3152  pos_url = pos + 1;
3153  pos[0] = '\0';
3155  "%s:%u/%s",
3156  tmp,
3157  (uint16_t)port,
3158  pos_url);
3159  }
3160  else
3162  "%s:%u",
3163  tmp,
3164  (uint16_t)port);
3165  }
3166  else
3167  plugin->external_hostname = GNUNET_strdup(tmp);
3168  GNUNET_free(eh_tmp);
3169 
3171  _("Using external hostname `%s'\n"),
3172  plugin->external_hostname);
3174  plugin);
3175 
3176  /* Use only configured external hostname */
3178  (plugin->env->cfg,
3179  plugin->name,
3180  "EXTERNAL_HOSTNAME_ONLY"))
3181  {
3182  plugin->external_only =
3184  plugin->name,
3185  "EXTERNAL_HOSTNAME_ONLY");
3186  }
3187  else
3188  plugin->external_only = GNUNET_NO;
3189 
3190  if (GNUNET_YES == plugin->external_only)
3192  _("Notifying transport only about hostname `%s'\n"),
3193  plugin->external_hostname);
3194  }
3195  else
3197  "No external hostname configured\n");
3198 
3199  /* Optional parameters */
3200  if (GNUNET_OK !=
3202  plugin->name,
3203  "MAX_CONNECTIONS",
3204  &max_connections))
3205  max_connections = 128;
3206  plugin->max_request = max_connections;
3207 
3209  _("Maximum number of connections is %u\n"),
3210  plugin->max_request);
3211 
3212  plugin->peer_id_length = strlen(GNUNET_i2s_full(plugin->env->my_identity));
3213 
3214  return GNUNET_OK;
3215 }
3216 
3217 
3224 void *
3226 {
3227  struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
3228  struct HTTP_Server_Plugin *plugin = api->cls;
3229 
3230  if (NULL == api->cls)
3231  {
3232  /* Free for stub mode */
3233  GNUNET_free(api);
3234  return NULL;
3235  }
3236  plugin->in_shutdown = GNUNET_YES;
3238  _("Shutting down plugin `%s'\n"),
3239  plugin->name);
3240 
3241  if (NULL != plugin->notify_ext_task)
3242  {
3244  plugin->notify_ext_task = NULL;
3245  }
3246 
3247  if (NULL != plugin->ext_addr)
3248  {
3250  "Notifying transport to remove address `%s'\n",
3252  plugin->ext_addr->address,
3253  plugin->ext_addr->address_length));
3254 #if BUILD_HTTPS
3255  plugin->env->notify_address(plugin->env->cls,
3256  GNUNET_NO,
3257  plugin->ext_addr);
3258 #else
3259  plugin->env->notify_address(plugin->env->cls,
3260  GNUNET_NO,
3261  plugin->ext_addr);
3262 #endif
3264  plugin->ext_addr = NULL;
3265  }
3266 
3267  /* Stop to report addresses to transport service */
3269  if (NULL != plugin->server_v4_task)
3270  {
3272  plugin->server_v4_task = NULL;
3273  }
3274 
3275  if (NULL != plugin->server_v6_task)
3276  {
3278  plugin->server_v6_task = NULL;
3279  }
3280 #if BUILD_HTTPS
3281  GNUNET_free_non_null(plugin->crypto_init);
3282  GNUNET_free_non_null(plugin->cert);
3283  GNUNET_free_non_null(plugin->key);
3284 #endif
3287  plugin);
3289  plugin->sessions = NULL;
3290  if (NULL != plugin->server_v4)
3291  {
3292  MHD_stop_daemon(plugin->server_v4);
3293  plugin->server_v4 = NULL;
3294  }
3295  if (NULL != plugin->server_v6)
3296  {
3297  MHD_stop_daemon(plugin->server_v6);
3298  plugin->server_v6 = NULL;
3299  }
3300  /* Clean up */
3302  GNUNET_free_non_null(plugin->ext_addr);
3305  regfree(&plugin->url_regex);
3306 
3308  _("Shutdown for plugin `%s' complete\n"),
3309  plugin->name);
3310 
3311  GNUNET_free(plugin);
3312  GNUNET_free(api);
3313  return NULL;
3314 }
3315 
3316 
3328 static const char *
3330  const void *addr,
3331  size_t addrlen)
3332 {
3334  addr,
3335  addrlen);
3336 }
3337 
3338 
3346 static enum GNUNET_NetworkType
3348  struct GNUNET_ATS_Session *session)
3349 {
3350  return session->scope;
3351 }
3352 
3353 
3361 static enum GNUNET_NetworkType
3363  const struct GNUNET_HELLO_Address *address)
3364 {
3365  struct HTTP_Server_Plugin *plugin = cls;
3366 
3368  address);
3369 }
3370 
3371 
3382 static void
3384  const struct GNUNET_PeerIdentity *peer,
3385  struct GNUNET_ATS_Session *session,
3386  struct GNUNET_TIME_Relative delay)
3387 {
3390  "New inbound delay %s\n",
3392  GNUNET_NO));
3393  if (NULL != session->recv_wakeup_task)
3394  {
3396  session->recv_wakeup_task
3398  &server_wake_up,
3399  session);
3400  }
3401 }
3402 
3403 
3413 static int
3415  const struct GNUNET_PeerIdentity *peer,
3416  void *value)
3417 {
3418  struct HTTP_Server_Plugin *plugin = cls;
3419  struct GNUNET_ATS_Session *session = value;
3420 
3421  notify_session_monitor(plugin,
3422  session,
3424  return GNUNET_OK;
3425 }
3426 
3427 
3440 static void
3443  void *sic_cls)
3444 {
3445  struct HTTP_Server_Plugin *plugin = cls;
3446 
3447  plugin->sic = sic;
3448  plugin->sic_cls = sic_cls;
3449  if (NULL != sic)
3450  {
3453  plugin);
3454  /* signal end of first iteration */
3455  sic(sic_cls, NULL, NULL);
3456  }
3457 }
3458 
3459 
3466 void *
3468 {
3471  struct HTTP_Server_Plugin *plugin;
3472 
3473  if (NULL == env->receive)
3474  {
3475  /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully
3476  initialze the plugin or the API */
3478  api->cls = NULL;
3482  return api;
3483  }
3484  plugin = GNUNET_new(struct HTTP_Server_Plugin);
3485  plugin->env = env;
3487  GNUNET_YES);
3488 
3490  api->cls = plugin;
3491  api->send = &http_server_plugin_send;
3497 
3506 #if BUILD_HTTPS
3507  plugin->name = "transport-https_server";
3508  plugin->protocol = "https";
3509 #else
3510  plugin->name = "transport-http_server";
3511  plugin->protocol = "http";
3512 #endif
3513 
3514  if (GNUNET_YES ==
3516  plugin->name,
3517  "TCP_STEALTH"))
3518  {
3519 #ifdef TCP_STEALTH
3520  plugin->options |= HTTP_OPTIONS_TCP_STEALTH;
3521 #else
3523  _("TCP_STEALTH not supported on this platform.\n"));
3525  return NULL;
3526 #endif
3527  }
3528 
3529  /* Compile URL regex */
3530  if (regcomp(&plugin->url_regex,
3531  URL_REGEX,
3532  REG_EXTENDED))
3533  {
3535  _("Unable to compile URL regex\n"));
3537  return NULL;
3538  }
3539 
3540  /* Configure plugin */
3541  if (GNUNET_SYSERR == server_configure_plugin(plugin))
3542  {
3544  return NULL;
3545  }
3546 
3547  /* Check IPv6 support */
3548  if (GNUNET_YES == plugin->use_ipv6)
3549  plugin->use_ipv6 = server_check_ipv6_support(plugin);
3550 
3551  /* Report addresses to transport service */
3552  if (GNUNET_NO == plugin->external_only)
3554 
3555  if (GNUNET_SYSERR == server_start(plugin))
3556  {
3558  return NULL;
3559  }
3560  return api;
3561 }
3562 
3563 /* 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:46
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:70
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:1339
#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:286
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:729
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:246
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:687
#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.
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
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:78
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:75
#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:1108
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:181
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:1254
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:1237
struct GNUNET_NETWORK_FDSet * GNUNET_NETWORK_fdset_create(void)
Creates an fd set.
Definition: network.c:1238
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.
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:410
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:1264
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:80
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:686
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:1784
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:84
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:113
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:96
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:76
static unsigned int size
Size of the "table".
Definition: peer.c:66
#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:376
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:254
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:1000
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:81
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:83
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.
#define GNUNET_log(kind,...)
The session was created (first call for each session object).
Entry in list of pending tasks.
Definition: scheduler.c:131
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:77
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:1262
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:548
#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:900
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition: scheduler.c:956