aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/transport/Makefile.am29
-rw-r--r--src/transport/plugin_transport_http.c131
-rw-r--r--src/transport/plugin_transport_https.c2585
-rw-r--r--src/transport/test_plugin_transport_data_http.conf10
-rw-r--r--src/transport/test_plugin_transport_https.c1354
-rw-r--r--src/transport/test_transport_api_http_peer1.conf4
-rw-r--r--src/transport/test_transport_api_http_peer2.conf4
7 files changed, 4078 insertions, 39 deletions
diff --git a/src/transport/Makefile.am b/src/transport/Makefile.am
index 2a62d0fb6..f4824ab70 100644
--- a/src/transport/Makefile.am
+++ b/src/transport/Makefile.am
@@ -12,6 +12,9 @@ if HAVE_MHD
12 HTTP_PLUGIN_CHECK = test_plugin_transport_http \ 12 HTTP_PLUGIN_CHECK = test_plugin_transport_http \
13 test_transport_api_http \ 13 test_transport_api_http \
14 test_transport_api_reliability_http 14 test_transport_api_reliability_http
15
16 HTTPS_PLUGIN_LA = libgnunet_plugin_transport_https.la
17 HTTPS_PLUGIN_CHECK = test_plugin_transport_https
15endif 18endif
16 19
17if USE_COVERAGE 20if USE_COVERAGE
@@ -76,6 +79,7 @@ plugin_LTLIBRARIES = \
76 libgnunet_plugin_transport_tcp.la \ 79 libgnunet_plugin_transport_tcp.la \
77 libgnunet_plugin_transport_udp.la \ 80 libgnunet_plugin_transport_udp.la \
78 $(HTTP_PLUGIN_LA) \ 81 $(HTTP_PLUGIN_LA) \
82 $(HTTPS_PLUGIN_LA) \
79 libgnunet_plugin_transport_template.la 83 libgnunet_plugin_transport_template.la
80# TODO: add nat, etc. 84# TODO: add nat, etc.
81 85
@@ -128,6 +132,18 @@ libgnunet_plugin_transport_http_la_LIBADD = \
128libgnunet_plugin_transport_http_la_LDFLAGS = \ 132libgnunet_plugin_transport_http_la_LDFLAGS = \
129 $(GN_LIBMHD) \ 133 $(GN_LIBMHD) \
130 $(GN_PLUGIN_LDFLAGS) 134 $(GN_PLUGIN_LDFLAGS)
135
136libgnunet_plugin_transport_https_la_SOURCES = \
137 plugin_transport_https.c
138libgnunet_plugin_transport_https_la_LIBADD = \
139 $(top_builddir)/src/hello/libgnunethello.la \
140 $(top_builddir)/src/statistics/libgnunetstatistics.la \
141 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
142 @LIBCURL@ \
143 $(top_builddir)/src/util/libgnunetutil.la
144libgnunet_plugin_transport_https_la_LDFLAGS = \
145 $(GN_LIBMHD) \
146 $(GN_PLUGIN_LDFLAGS)
131endif 147endif
132 148
133check_PROGRAMS = \ 149check_PROGRAMS = \
@@ -135,6 +151,7 @@ check_PROGRAMS = \
135 test_transport_api_tcp_nat \ 151 test_transport_api_tcp_nat \
136 test_transport_api_udp \ 152 test_transport_api_udp \
137 $(HTTP_PLUGIN_CHECK) \ 153 $(HTTP_PLUGIN_CHECK) \
154 $(HTTPS_PLUGIN_CHECK) \
138 test_transport_api_udp_nat \ 155 test_transport_api_udp_nat \
139 test_transport_api_reliability_tcp \ 156 test_transport_api_reliability_tcp \
140 test_transport_api_reliability_tcp_nat \ 157 test_transport_api_reliability_tcp_nat \
@@ -147,6 +164,7 @@ TESTS = \
147 test_transport_api_udp \ 164 test_transport_api_udp \
148 test_transport_api_udp_nat \ 165 test_transport_api_udp_nat \
149 $(HTTP_PLUGIN_CHECK) \ 166 $(HTTP_PLUGIN_CHECK) \
167 $(HTTPS_PLUGIN_CHECK) \
150 test_transport_api_reliability_tcp \ 168 test_transport_api_reliability_tcp \
151 test_transport_api_reliability_tcp_nat 169 test_transport_api_reliability_tcp_nat
152 170
@@ -211,7 +229,16 @@ test_transport_api_reliability_http_SOURCES = \
211 test_transport_api_reliability.c 229 test_transport_api_reliability.c
212test_transport_api_reliability_http_LDADD = \ 230test_transport_api_reliability_http_LDADD = \
213 $(top_builddir)/src/transport/libgnunettransport.la \ 231 $(top_builddir)/src/transport/libgnunettransport.la \
214 $(top_builddir)/src/util/libgnunetutil.la 232 $(top_builddir)/src/util/libgnunetutil.la
233
234test_plugin_transport_https_SOURCES = \
235 test_plugin_transport_https.c
236test_plugin_transport_https_LDADD = \
237 $(top_builddir)/src/transport/libgnunettransport.la \
238 $(top_builddir)/src/statistics/libgnunetstatistics.la \
239 @LIBCURL@ \
240 $(top_builddir)/src/util/libgnunetutil.la
241
215endif 242endif
216 243
217EXTRA_DIST = \ 244EXTRA_DIST = \
diff --git a/src/transport/plugin_transport_http.c b/src/transport/plugin_transport_http.c
index 7137947c5..909156046 100644
--- a/src/transport/plugin_transport_http.c
+++ b/src/transport/plugin_transport_http.c
@@ -42,8 +42,8 @@
42 42
43#define DEBUG_HTTP GNUNET_YES 43#define DEBUG_HTTP GNUNET_YES
44#define DEBUG_CURL GNUNET_YES 44#define DEBUG_CURL GNUNET_YES
45#define DEBUG_CONNECTIONS GNUNET_YES 45#define DEBUG_CONNECTIONS GNUNET_NO
46#define DEBUG_SESSION_SELECTION GNUNET_YES 46#define DEBUG_SESSION_SELECTION GNUNET_NO
47 47
48#define INBOUND GNUNET_NO 48#define INBOUND GNUNET_NO
49#define OUTBOUND GNUNET_YES 49#define OUTBOUND GNUNET_YES
@@ -438,6 +438,8 @@ static int remove_http_message (struct Session * ps, struct HTTP_Message * msg)
438 return GNUNET_OK; 438 return GNUNET_OK;
439} 439}
440 440
441int remove_peer_context_Iterator (void *cls, const GNUNET_HashCode *key, void *value);
442
441/** 443/**
442 * Removes a session from the linked list of sessions 444 * Removes a session from the linked list of sessions
443 * @param pc peer context 445 * @param pc peer context
@@ -460,6 +462,20 @@ static int remove_session (struct HTTP_PeerContext * pc, struct Session * ps, i
460 GNUNET_SERVER_mst_destroy (ps->msgtok); 462 GNUNET_SERVER_mst_destroy (ps->msgtok);
461 GNUNET_free(ps->url); 463 GNUNET_free(ps->url);
462 464
465 if (ps->direction==INBOUND)
466 {
467 if (ps->recv_endpoint != NULL)
468 {
469 curl_easy_cleanup(ps->recv_endpoint);
470 ps->recv_endpoint = NULL;
471 }
472 if (ps->send_endpoint != NULL)
473 {
474 curl_easy_cleanup(ps->send_endpoint);
475 ps->send_endpoint = NULL;
476 }
477 }
478
463 msg = ps->pending_msgs_head; 479 msg = ps->pending_msgs_head;
464 while (msg!=NULL) 480 while (msg!=NULL)
465 { 481 {
@@ -475,6 +491,16 @@ static int remove_session (struct HTTP_PeerContext * pc, struct Session * ps, i
475 GNUNET_CONTAINER_DLL_remove(pc->head,pc->tail,ps); 491 GNUNET_CONTAINER_DLL_remove(pc->head,pc->tail,ps);
476 GNUNET_free(ps); 492 GNUNET_free(ps);
477 ps = NULL; 493 ps = NULL;
494
495 /* no sessions left remove peer */
496 if (pc->head==NULL)
497 {
498#if DEBUG_HTTP
499 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"No sessions left for peer `%s', removing context\n",GNUNET_i2s(&pc->identity));
500#endif
501 remove_peer_context_Iterator(plugin, &pc->identity.hashPubKey, pc);
502 }
503
478 return GNUNET_OK; 504 return GNUNET_OK;
479} 505}
480 506
@@ -489,6 +515,7 @@ int remove_peer_context_Iterator (void *cls, const GNUNET_HashCode *key, void *v
489#if DEBUG_HTTP 515#if DEBUG_HTTP
490 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Freeing context for peer `%s'\n",GNUNET_i2s(&pc->identity)); 516 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Freeing context for peer `%s'\n",GNUNET_i2s(&pc->identity));
491#endif 517#endif
518 GNUNET_CONTAINER_multihashmap_remove (plugin->peers, &pc->identity.hashPubKey, pc);
492 while (ps!=NULL) 519 while (ps!=NULL)
493 { 520 {
494 plugin->env->session_end(plugin, &pc->identity, ps); 521 plugin->env->session_end(plugin, &pc->identity, ps);
@@ -518,6 +545,10 @@ int remove_peer_context_Iterator (void *cls, const GNUNET_HashCode *key, void *v
518 ps=tmp; 545 ps=tmp;
519 } 546 }
520 GNUNET_free(pc); 547 GNUNET_free(pc);
548 GNUNET_STATISTICS_update (plugin->env->stats,
549 gettext_noop ("# HTTP peers active"),
550 -1,
551 GNUNET_NO);
521 return GNUNET_YES; 552 return GNUNET_YES;
522} 553}
523 554
@@ -639,6 +670,10 @@ static void mhd_termination_cb (void *cls, struct MHD_Connection * connection, v
639 /* if both connections disconnected, remove session */ 670 /* if both connections disconnected, remove session */
640 if ((ps->send_connected == GNUNET_NO) && (ps->recv_connected == GNUNET_NO)) 671 if ((ps->send_connected == GNUNET_NO) && (ps->recv_connected == GNUNET_NO))
641 { 672 {
673 GNUNET_STATISTICS_update (pc->plugin->env->stats,
674 gettext_noop ("# HTTP inbound sessions for peers active"),
675 -1,
676 GNUNET_NO);
642 remove_session(pc,ps,GNUNET_YES,GNUNET_SYSERR); 677 remove_session(pc,ps,GNUNET_YES,GNUNET_SYSERR);
643 } 678 }
644} 679}
@@ -817,6 +852,10 @@ mdh_access_cb (void *cls,
817 pc->last_session = NULL; 852 pc->last_session = NULL;
818 memcpy(&pc->identity, &pi_in, sizeof(struct GNUNET_PeerIdentity)); 853 memcpy(&pc->identity, &pi_in, sizeof(struct GNUNET_PeerIdentity));
819 GNUNET_CONTAINER_multihashmap_put(plugin->peers, &pc->identity.hashPubKey, pc, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); 854 GNUNET_CONTAINER_multihashmap_put(plugin->peers, &pc->identity.hashPubKey, pc, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
855 GNUNET_STATISTICS_update (plugin->env->stats,
856 gettext_noop ("# HTTP peers active"),
857 1,
858 GNUNET_NO);
820 } 859 }
821 860
822 conn_info = MHD_get_connection_info(mhd_connection, MHD_CONNECTION_INFO_CLIENT_ADDRESS ); 861 conn_info = MHD_get_connection_info(mhd_connection, MHD_CONNECTION_INFO_CLIENT_ADDRESS );
@@ -873,6 +912,10 @@ mdh_access_cb (void *cls,
873 ps->session_id =id_num; 912 ps->session_id =id_num;
874 ps->url = create_url (plugin, ps->addr, ps->addrlen, ps->session_id); 913 ps->url = create_url (plugin, ps->addr, ps->addrlen, ps->session_id);
875 GNUNET_CONTAINER_DLL_insert(pc->head,pc->tail,ps); 914 GNUNET_CONTAINER_DLL_insert(pc->head,pc->tail,ps);
915 GNUNET_STATISTICS_update (plugin->env->stats,
916 gettext_noop ("# HTTP inbound sessions for peers active"),
917 1,
918 GNUNET_NO);
876 } 919 }
877 920
878 *httpSessionCache = ps; 921 *httpSessionCache = ps;
@@ -1085,9 +1128,6 @@ static void http_server_daemon_v6_run (void *cls,
1085static size_t curl_get_header_cb( void *ptr, size_t size, size_t nmemb, void *stream) 1128static size_t curl_get_header_cb( void *ptr, size_t size, size_t nmemb, void *stream)
1086{ 1129{
1087 struct Session * ps = stream; 1130 struct Session * ps = stream;
1088
1089 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: curl_get_header_cb\n",ps);
1090
1091 char * tmp; 1131 char * tmp;
1092 size_t len = size * nmemb; 1132 size_t len = size * nmemb;
1093 long http_result = 0; 1133 long http_result = 0;
@@ -1356,8 +1396,8 @@ static void curl_perform (void *cls,
1356 ps->send_connected = GNUNET_NO; 1396 ps->send_connected = GNUNET_NO;
1357 ps->send_active = GNUNET_NO; 1397 ps->send_active = GNUNET_NO;
1358 curl_multi_remove_handle(plugin->multi_handle,ps->send_endpoint); 1398 curl_multi_remove_handle(plugin->multi_handle,ps->send_endpoint);
1359 curl_easy_cleanup(ps->send_endpoint); 1399 //curl_easy_cleanup(ps->send_endpoint);
1360 ps->send_endpoint=NULL; 1400 //ps->send_endpoint=NULL;
1361 cur_msg = ps->pending_msgs_tail; 1401 cur_msg = ps->pending_msgs_tail;
1362 if (( NULL != cur_msg) && ( NULL != cur_msg->transmit_cont)) 1402 if (( NULL != cur_msg) && ( NULL != cur_msg->transmit_cont))
1363 cur_msg->transmit_cont (cur_msg->transmit_cont_cls,&pc->identity,GNUNET_SYSERR); 1403 cur_msg->transmit_cont (cur_msg->transmit_cont_cls,&pc->identity,GNUNET_SYSERR);
@@ -1377,8 +1417,8 @@ static void curl_perform (void *cls,
1377 ps->recv_connected = GNUNET_NO; 1417 ps->recv_connected = GNUNET_NO;
1378 ps->recv_active = GNUNET_NO; 1418 ps->recv_active = GNUNET_NO;
1379 curl_multi_remove_handle(plugin->multi_handle,ps->recv_endpoint); 1419 curl_multi_remove_handle(plugin->multi_handle,ps->recv_endpoint);
1380 curl_easy_cleanup(ps->recv_endpoint); 1420 //curl_easy_cleanup(ps->recv_endpoint);
1381 ps->recv_endpoint=NULL; 1421 //ps->recv_endpoint=NULL;
1382 } 1422 }
1383 } 1423 }
1384 else 1424 else
@@ -1411,8 +1451,8 @@ static void curl_perform (void *cls,
1411 ps->send_connected = GNUNET_NO; 1451 ps->send_connected = GNUNET_NO;
1412 ps->send_active = GNUNET_NO; 1452 ps->send_active = GNUNET_NO;
1413 curl_multi_remove_handle(plugin->multi_handle,ps->send_endpoint); 1453 curl_multi_remove_handle(plugin->multi_handle,ps->send_endpoint);
1414 curl_easy_cleanup(ps->send_endpoint); 1454 //curl_easy_cleanup(ps->send_endpoint);
1415 ps->send_endpoint =NULL; 1455 //ps->send_endpoint =NULL;
1416 } 1456 }
1417 if (msg->easy_handle == ps->recv_endpoint) 1457 if (msg->easy_handle == ps->recv_endpoint)
1418 { 1458 {
@@ -1427,8 +1467,8 @@ static void curl_perform (void *cls,
1427 ps->recv_connected = GNUNET_NO; 1467 ps->recv_connected = GNUNET_NO;
1428 ps->recv_active = GNUNET_NO; 1468 ps->recv_active = GNUNET_NO;
1429 curl_multi_remove_handle(plugin->multi_handle,ps->recv_endpoint); 1469 curl_multi_remove_handle(plugin->multi_handle,ps->recv_endpoint);
1430 curl_easy_cleanup(ps->recv_endpoint); 1470 //curl_easy_cleanup(ps->recv_endpoint);
1431 ps->recv_endpoint=NULL; 1471 //ps->recv_endpoint=NULL;
1432 } 1472 }
1433 } 1473 }
1434 if ((ps->recv_connected == GNUNET_NO) && (ps->send_connected == GNUNET_NO)) 1474 if ((ps->recv_connected == GNUNET_NO) && (ps->send_connected == GNUNET_NO))
@@ -1536,9 +1576,14 @@ static ssize_t send_check_connections (void *cls, struct Session *ps)
1536 /* Check if session is connected to receive data, otherwise connect to peer */ 1576 /* Check if session is connected to receive data, otherwise connect to peer */
1537 if (ps->recv_connected == GNUNET_NO) 1577 if (ps->recv_connected == GNUNET_NO)
1538 { 1578 {
1579 int fresh = GNUNET_NO;
1539 if (ps->recv_endpoint == NULL) 1580 if (ps->recv_endpoint == NULL)
1540 { 1581 {
1541 ps->recv_endpoint = curl_easy_init(); 1582 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1583 "created handle\n");
1584 fresh = GNUNET_YES;
1585 ps->recv_endpoint = curl_easy_init();
1586 }
1542#if DEBUG_CURL 1587#if DEBUG_CURL
1543 curl_easy_setopt(ps->recv_endpoint, CURLOPT_VERBOSE, 1L); 1588 curl_easy_setopt(ps->recv_endpoint, CURLOPT_VERBOSE, 1L);
1544#endif 1589#endif
@@ -1554,15 +1599,18 @@ static ssize_t send_check_connections (void *cls, struct Session *ps)
1554 curl_easy_setopt(ps->recv_endpoint, CURLOPT_CONNECTTIMEOUT, HTTP_CONNECT_TIMEOUT); 1599 curl_easy_setopt(ps->recv_endpoint, CURLOPT_CONNECTTIMEOUT, HTTP_CONNECT_TIMEOUT);
1555 curl_easy_setopt(ps->recv_endpoint, CURLOPT_BUFFERSIZE, GNUNET_SERVER_MAX_MESSAGE_SIZE); 1600 curl_easy_setopt(ps->recv_endpoint, CURLOPT_BUFFERSIZE, GNUNET_SERVER_MAX_MESSAGE_SIZE);
1556 1601
1557 mret = curl_multi_add_handle(plugin->multi_handle, ps->recv_endpoint); 1602 if (fresh==GNUNET_YES)
1558 if (mret != CURLM_OK)
1559 { 1603 {
1560 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1604 mret = curl_multi_add_handle(plugin->multi_handle, ps->recv_endpoint);
1561 _("Connection: %X: %s failed at %s:%d: `%s'\n"), 1605 if (mret != CURLM_OK)
1562 ps, 1606 {
1563 "curl_multi_add_handle", __FILE__, __LINE__, 1607 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1564 curl_multi_strerror (mret)); 1608 _("Connection: %X: %s failed at %s:%d: `%s'\n"),
1565 return GNUNET_SYSERR; 1609 ps,
1610 "curl_multi_add_handle", __FILE__, __LINE__,
1611 curl_multi_strerror (mret));
1612 return GNUNET_SYSERR;
1613 }
1566 } 1614 }
1567 if (curl_schedule (plugin) == GNUNET_SYSERR) 1615 if (curl_schedule (plugin) == GNUNET_SYSERR)
1568 { 1616 {
@@ -1574,7 +1622,6 @@ static ssize_t send_check_connections (void *cls, struct Session *ps)
1574#if DEBUG_CONNECTIONS 1622#if DEBUG_CONNECTIONS
1575 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: inbound not connected, initiating connection\n",ps); 1623 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: inbound not connected, initiating connection\n",ps);
1576#endif 1624#endif
1577 }
1578 } 1625 }
1579 1626
1580 /* waiting for receive direction */ 1627 /* waiting for receive direction */
@@ -1607,9 +1654,14 @@ static ssize_t send_check_connections (void *cls, struct Session *ps)
1607 } 1654 }
1608 } 1655 }
1609 /* not connected, initiate connection */ 1656 /* not connected, initiate connection */
1610 if ((ps->send_connected==GNUNET_NO) && (NULL == ps->send_endpoint)) 1657 if (ps->send_connected==GNUNET_NO)
1611 { 1658 {
1612 ps->send_endpoint = curl_easy_init(); 1659 int fresh = GNUNET_NO;
1660 if (NULL == ps->send_endpoint)
1661 {
1662 ps->send_endpoint = curl_easy_init();
1663 fresh = GNUNET_YES;
1664 }
1613 GNUNET_assert (ps->send_endpoint != NULL); 1665 GNUNET_assert (ps->send_endpoint != NULL);
1614 GNUNET_assert (NULL != ps->pending_msgs_tail); 1666 GNUNET_assert (NULL != ps->pending_msgs_tail);
1615#if DEBUG_CONNECTIONS 1667#if DEBUG_CONNECTIONS
@@ -1634,15 +1686,18 @@ static ssize_t send_check_connections (void *cls, struct Session *ps)
1634 curl_easy_setopt(ps->send_endpoint, CURLOPT_CONNECTTIMEOUT, HTTP_CONNECT_TIMEOUT); 1686 curl_easy_setopt(ps->send_endpoint, CURLOPT_CONNECTTIMEOUT, HTTP_CONNECT_TIMEOUT);
1635 curl_easy_setopt(ps->send_endpoint, CURLOPT_BUFFERSIZE, GNUNET_SERVER_MAX_MESSAGE_SIZE); 1687 curl_easy_setopt(ps->send_endpoint, CURLOPT_BUFFERSIZE, GNUNET_SERVER_MAX_MESSAGE_SIZE);
1636 1688
1637 mret = curl_multi_add_handle(plugin->multi_handle, ps->send_endpoint); 1689 if (fresh==GNUNET_YES)
1638 if (mret != CURLM_OK)
1639 { 1690 {
1640 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 1691 mret = curl_multi_add_handle(plugin->multi_handle, ps->send_endpoint);
1641 _("Connection: %X: %s failed at %s:%d: `%s'\n"), 1692 if (mret != CURLM_OK)
1642 ps, 1693 {
1643 "curl_multi_add_handle", __FILE__, __LINE__, 1694 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1644 curl_multi_strerror (mret)); 1695 _("Connection: %X: %s failed at %s:%d: `%s'\n"),
1645 return GNUNET_SYSERR; 1696 ps,
1697 "curl_multi_add_handle", __FILE__, __LINE__,
1698 curl_multi_strerror (mret));
1699 return GNUNET_SYSERR;
1700 }
1646 } 1701 }
1647 } 1702 }
1648 if (curl_schedule (plugin) == GNUNET_SYSERR) 1703 if (curl_schedule (plugin) == GNUNET_SYSERR)
@@ -1853,6 +1908,10 @@ http_plugin_send (void *cls,
1853 pc->last_session = NULL; 1908 pc->last_session = NULL;
1854 memcpy(&pc->identity, target, sizeof(struct GNUNET_PeerIdentity)); 1909 memcpy(&pc->identity, target, sizeof(struct GNUNET_PeerIdentity));
1855 GNUNET_CONTAINER_multihashmap_put(plugin->peers, &pc->identity.hashPubKey, pc, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); 1910 GNUNET_CONTAINER_multihashmap_put(plugin->peers, &pc->identity.hashPubKey, pc, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
1911 GNUNET_STATISTICS_update (plugin->env->stats,
1912 gettext_noop ("# HTTP peers active"),
1913 1,
1914 GNUNET_NO);
1856 } 1915 }
1857 1916
1858 ps = send_select_session (plugin, pc, addr, addrlen, force_address, session); 1917 ps = send_select_session (plugin, pc, addr, addrlen, force_address, session);
@@ -1894,6 +1953,12 @@ http_plugin_send (void *cls,
1894 if (ps->msgtok == NULL) 1953 if (ps->msgtok == NULL)
1895 ps->msgtok = GNUNET_SERVER_mst_create (&curl_receive_mst_cb, ps); 1954 ps->msgtok = GNUNET_SERVER_mst_create (&curl_receive_mst_cb, ps);
1896 GNUNET_CONTAINER_DLL_insert(pc->head,pc->tail,ps); 1955 GNUNET_CONTAINER_DLL_insert(pc->head,pc->tail,ps);
1956/* FIXME */
1957
1958 GNUNET_STATISTICS_update (plugin->env->stats,
1959 gettext_noop ("# HTTP outbound sessions for peers active"),
1960 1,
1961 GNUNET_NO);
1897 } 1962 }
1898 else 1963 else
1899 { 1964 {
diff --git a/src/transport/plugin_transport_https.c b/src/transport/plugin_transport_https.c
new file mode 100644
index 000000000..22e121963
--- /dev/null
+++ b/src/transport/plugin_transport_https.c
@@ -0,0 +1,2585 @@
1/*
2 This file is part of GNUnet
3 (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 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 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file transport/plugin_transport_https.c
23 * @brief https transport service plugin
24 * @author Matthias Wachs
25 */
26
27#include "platform.h"
28#include "gnunet_common.h"
29#include "gnunet_constants.h"
30#include "gnunet_protocols.h"
31#include "gnunet_connection_lib.h"
32#include "gnunet_service_lib.h"
33#include "gnunet_statistics_service.h"
34#include "gnunet_transport_service.h"
35#include "gnunet_resolver_service.h"
36#include "gnunet_server_lib.h"
37#include "gnunet_container_lib.h"
38#include "plugin_transport.h"
39#include "gnunet_os_lib.h"
40#include "microhttpd.h"
41#include <curl/curl.h>
42
43#define DEBUG_HTTPS GNUNET_YES
44#define DEBUG_CURL GNUNET_YES
45#define DEBUG_CONNECTIONS GNUNET_YES
46#define DEBUG_SESSION_SELECTION GNUNET_NO
47
48#define INBOUND GNUNET_NO
49#define OUTBOUND GNUNET_YES
50
51/**
52 * Text of the response sent back after the last bytes of a PUT
53 * request have been received (just to formally obey the HTTP
54 * protocol).
55 */
56#define HTTP_PUT_RESPONSE "Thank you!"
57
58/**
59 * After how long do we expire an address that we
60 * learned from another peer if it is not reconfirmed
61 * by anyone?
62 */
63#define LEARNED_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 6)
64
65/**
66 * Page returned if request invalid
67 */
68#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>"
69
70/**
71 * Timeout for a http connect
72 */
73#define HTTP_CONNECT_TIMEOUT 30
74
75/* Test Certificate */
76const char cert_pem[] =
77 "-----BEGIN CERTIFICATE-----\n"
78 "MIICpjCCAZCgAwIBAgIESEPtjjALBgkqhkiG9w0BAQUwADAeFw0wODA2MDIxMjU0\n"
79 "MzhaFw0wOTA2MDIxMjU0NDZaMAAwggEfMAsGCSqGSIb3DQEBAQOCAQ4AMIIBCQKC\n"
80 "AQC03TyUvK5HmUAirRp067taIEO4bibh5nqolUoUdo/LeblMQV+qnrv/RNAMTx5X\n"
81 "fNLZ45/kbM9geF8qY0vsPyQvP4jumzK0LOJYuIwmHaUm9vbXnYieILiwCuTgjaud\n"
82 "3VkZDoQ9fteIo+6we9UTpVqZpxpbLulBMh/VsvX0cPJ1VFC7rT59o9hAUlFf9jX/\n"
83 "GmKdYI79MtgVx0OPBjmmSD6kicBBfmfgkO7bIGwlRtsIyMznxbHu6VuoX/eVxrTv\n"
84 "rmCwgEXLWRZ6ru8MQl5YfqeGXXRVwMeXU961KefbuvmEPccgCxm8FZ1C1cnDHFXh\n"
85 "siSgAzMBjC/b6KVhNQ4KnUdZAgMBAAGjLzAtMAwGA1UdEwEB/wQCMAAwHQYDVR0O\n"
86 "BBYEFJcUvpjvE5fF/yzUshkWDpdYiQh/MAsGCSqGSIb3DQEBBQOCAQEARP7eKSB2\n"
87 "RNd6XjEjK0SrxtoTnxS3nw9sfcS7/qD1+XHdObtDFqGNSjGYFB3Gpx8fpQhCXdoN\n"
88 "8QUs3/5ZVa5yjZMQewWBgz8kNbnbH40F2y81MHITxxCe1Y+qqHWwVaYLsiOTqj2/\n"
89 "0S3QjEJ9tvklmg7JX09HC4m5QRYfWBeQLD1u8ZjA1Sf1xJriomFVyRLI2VPO2bNe\n"
90 "JDMXWuP+8kMC7gEvUnJ7A92Y2yrhu3QI3bjPk8uSpHea19Q77tul1UVBJ5g+zpH3\n"
91 "OsF5p0MyaVf09GTzcLds5nE/osTdXGUyHJapWReVmPm3Zn6gqYlnzD99z+DPIgIV\n"
92 "RhZvQx74NQnS6g==\n" "-----END CERTIFICATE-----\n";
93
94const char key_pem[] =
95 "-----BEGIN RSA PRIVATE KEY-----\n"
96 "MIIEowIBAAKCAQEAtN08lLyuR5lAIq0adOu7WiBDuG4m4eZ6qJVKFHaPy3m5TEFf\n"
97 "qp67/0TQDE8eV3zS2eOf5GzPYHhfKmNL7D8kLz+I7psytCziWLiMJh2lJvb2152I\n"
98 "niC4sArk4I2rnd1ZGQ6EPX7XiKPusHvVE6VamacaWy7pQTIf1bL19HDydVRQu60+\n"
99 "faPYQFJRX/Y1/xpinWCO/TLYFcdDjwY5pkg+pInAQX5n4JDu2yBsJUbbCMjM58Wx\n"
100 "7ulbqF/3lca0765gsIBFy1kWeq7vDEJeWH6nhl10VcDHl1PetSnn27r5hD3HIAsZ\n"
101 "vBWdQtXJwxxV4bIkoAMzAYwv2+ilYTUOCp1HWQIDAQABAoIBAArOQv3R7gmqDspj\n"
102 "lDaTFOz0C4e70QfjGMX0sWnakYnDGn6DU19iv3GnX1S072ejtgc9kcJ4e8VUO79R\n"
103 "EmqpdRR7k8dJr3RTUCyjzf/C+qiCzcmhCFYGN3KRHA6MeEnkvRuBogX4i5EG1k5l\n"
104 "/5t+YBTZBnqXKWlzQLKoUAiMLPg0eRWh+6q7H4N7kdWWBmTpako7TEqpIwuEnPGx\n"
105 "u3EPuTR+LN6lF55WBePbCHccUHUQaXuav18NuDkcJmCiMArK9SKb+h0RqLD6oMI/\n"
106 "dKD6n8cZXeMBkK+C8U/K0sN2hFHACsu30b9XfdnljgP9v+BP8GhnB0nCB6tNBCPo\n"
107 "32srOwECgYEAxWh3iBT4lWqL6bZavVbnhmvtif4nHv2t2/hOs/CAq8iLAw0oWGZc\n"
108 "+JEZTUDMvFRlulr0kcaWra+4fN3OmJnjeuFXZq52lfMgXBIKBmoSaZpIh2aDY1Rd\n"
109 "RbEse7nQl9hTEPmYspiXLGtnAXW7HuWqVfFFP3ya8rUS3t4d07Hig8ECgYEA6ou6\n"
110 "OHiBRTbtDqLIv8NghARc/AqwNWgEc9PelCPe5bdCOLBEyFjqKiT2MttnSSUc2Zob\n"
111 "XhYkHC6zN1Mlq30N0e3Q61YK9LxMdU1vsluXxNq2rfK1Scb1oOlOOtlbV3zA3VRF\n"
112 "hV3t1nOA9tFmUrwZi0CUMWJE/zbPAyhwWotKyZkCgYEAh0kFicPdbABdrCglXVae\n"
113 "SnfSjVwYkVuGd5Ze0WADvjYsVkYBHTvhgRNnRJMg+/vWz3Sf4Ps4rgUbqK8Vc20b\n"
114 "AU5G6H6tlCvPRGm0ZxrwTWDHTcuKRVs+pJE8C/qWoklE/AAhjluWVoGwUMbPGuiH\n"
115 "6Gf1bgHF6oj/Sq7rv/VLZ8ECgYBeq7ml05YyLuJutuwa4yzQ/MXfghzv4aVyb0F3\n"
116 "QCdXR6o2IYgR6jnSewrZKlA9aPqFJrwHNR6sNXlnSmt5Fcf/RWO/qgJQGLUv3+rG\n"
117 "7kuLTNDR05azSdiZc7J89ID3Bkb+z2YkV+6JUiPq/Ei1+nDBEXb/m+/HqALU/nyj\n"
118 "P3gXeQKBgBusb8Rbd+KgxSA0hwY6aoRTPRt8LNvXdsB9vRcKKHUFQvxUWiUSS+L9\n"
119 "/Qu1sJbrUquKOHqksV5wCnWnAKyJNJlhHuBToqQTgKXjuNmVdYSe631saiI7PHyC\n"
120 "eRJ6DxULPxABytJrYCRrNqmXi5TCiqR2mtfalEMOPxz8rUU8dYyx\n"
121 "-----END RSA PRIVATE KEY-----\n";
122
123/**
124 * Network format for IPv4 addresses.
125 */
126struct IPv4HttpAddress
127{
128 /**
129 * IPv4 address, in network byte order.
130 */
131 uint32_t ipv4_addr GNUNET_PACKED;
132
133 /**
134 * Port number, in network byte order.
135 */
136 uint16_t u_port GNUNET_PACKED;
137
138};
139
140
141/**
142 * Network format for IPv6 addresses.
143 */
144struct IPv6HttpAddress
145{
146 /**
147 * IPv6 address.
148 */
149 struct in6_addr ipv6_addr GNUNET_PACKED;
150
151 /**
152 * Port number, in network byte order.
153 */
154 uint16_t u6_port GNUNET_PACKED;
155
156};
157
158
159/**
160 * Message to send using http
161 */
162struct HTTP_Message
163{
164 /**
165 * next pointer for double linked list
166 */
167 struct HTTP_Message * next;
168
169 /**
170 * previous pointer for double linked list
171 */
172 struct HTTP_Message * prev;
173
174 /**
175 * buffer containing data to send
176 */
177 char *buf;
178
179 /**
180 * amount of data already sent
181 */
182 size_t pos;
183
184 /**
185 * buffer length
186 */
187 size_t size;
188
189 /**
190 * Continuation function to call once the transmission buffer
191 * has again space available. NULL if there is no
192 * continuation to call.
193 */
194 GNUNET_TRANSPORT_TransmitContinuation transmit_cont;
195
196 /**
197 * Closure for transmit_cont.
198 */
199 void *transmit_cont_cls;
200};
201
202
203struct HTTP_PeerContext
204{
205 /**
206 * peer's identity
207 */
208 struct GNUNET_PeerIdentity identity;
209
210 /**
211 * Pointer to the global plugin struct.
212 */
213 struct Plugin *plugin;
214
215 /**
216 * Linked list of connections with this peer
217 * head
218 */
219 struct Session * head;
220
221 /**
222 * Linked list of connections with this peer
223 * tail
224 */
225 struct Session * tail;
226
227 /**
228 * id for next session
229 */
230 size_t session_id_counter;
231
232 /**
233 * Last session used to send data
234 */
235 struct Session * last_session;
236};
237
238
239struct Session
240{
241 /**
242 * API requirement.
243 */
244 struct SessionHeader header;
245
246 /**
247 * next session in linked list
248 */
249 struct Session * next;
250
251 /**
252 * previous session in linked list
253 */
254 struct Session * prev;
255
256 /**
257 * address of this session
258 */
259 void * addr;
260
261 /**
262 * address length
263 */
264 size_t addrlen;
265
266 /**
267 * target url
268 */
269 char * url;
270
271 /**
272 * Message queue for outbound messages
273 * head of queue
274 */
275 struct HTTP_Message * pending_msgs_head;
276
277 /**
278 * Message queue for outbound messages
279 * tail of queue
280 */
281 struct HTTP_Message * pending_msgs_tail;
282
283 /**
284 * partner peer this connection belongs to
285 */
286 struct HTTP_PeerContext * peercontext;
287
288 /**
289 * message stream tokenizer for incoming data
290 */
291 struct GNUNET_SERVER_MessageStreamTokenizer *msgtok;
292
293 /**
294 * session direction
295 * outbound: OUTBOUND (GNUNET_YES)
296 * inbound : INBOUND (GNUNET_NO)
297 */
298 unsigned int direction;
299
300 /**
301 * is session connected to send data?
302 */
303 unsigned int send_connected;
304
305 /**
306 * is send connection active?
307 */
308 unsigned int send_active;
309
310 /**
311 * connection disconnect forced (e.g. from transport)
312 */
313 unsigned int send_force_disconnect;
314
315 /**
316 * is session connected to receive data?
317 */
318 unsigned int recv_connected;
319
320 /**
321 * is receive connection active?
322 */
323 unsigned int recv_active;
324
325 /**
326 * connection disconnect forced (e.g. from transport)
327 */
328 unsigned int recv_force_disconnect;
329
330 /**
331 * id for next session
332 * NOTE: 0 is not an ID, zero is not defined. A correct ID is always > 0
333 */
334 size_t session_id;
335
336 /**
337 * entity managing sending data
338 * outbound session: CURL *
339 * inbound session: mhd_connection *
340 */
341 void * send_endpoint;
342
343 /**
344 * entity managing recieving data
345 * outbound session: CURL *
346 * inbound session: mhd_connection *
347 */
348 void * recv_endpoint;
349};
350
351/**
352 * Encapsulation of all of the state of the plugin.
353 */
354struct Plugin
355{
356 /**
357 * Our environment.
358 */
359 struct GNUNET_TRANSPORT_PluginEnvironment *env;
360
361 /**
362 * Handle for reporting statistics.
363 */
364 struct GNUNET_STATISTICS_Handle *stats;
365
366 unsigned int port_inbound;
367
368 struct GNUNET_CONTAINER_MultiHashMap *peers;
369
370 /**
371 * Daemon for listening for new IPv4 connections.
372 */
373 struct MHD_Daemon *http_server_daemon_v4;
374
375 /**
376 * Daemon for listening for new IPv6connections.
377 */
378 struct MHD_Daemon *http_server_daemon_v6;
379
380 /**
381 * Our primary task for http daemon handling IPv4 connections
382 */
383 GNUNET_SCHEDULER_TaskIdentifier http_server_task_v4;
384
385 /**
386 * Our primary task for http daemon handling IPv6 connections
387 */
388 GNUNET_SCHEDULER_TaskIdentifier http_server_task_v6;
389
390 /**
391 * The task sending data
392 */
393 GNUNET_SCHEDULER_TaskIdentifier http_curl_task;
394
395 /**
396 * cURL Multihandle
397 */
398 CURLM * multi_handle;
399
400 /**
401 * Our ASCII encoded, hashed peer identity
402 * This string is used to distinguish between connections and is added to the urls
403 */
404 struct GNUNET_CRYPTO_HashAsciiEncoded my_ascii_hash_ident;
405
406 struct sockaddr_in * bind4_address;
407 struct sockaddr_in6 * bind6_address;
408 char * bind_hostname;
409 int use_ipv6;
410 int use_ipv4;
411};
412
413
414/**
415 * Function called for a quick conversion of the binary address to
416 * a numeric address. Note that the caller must not free the
417 * address and that the next call to this function is allowed
418 * to override the address again.
419 *
420 * @param cls closure
421 * @param addr binary address
422 * @param addrlen length of the address
423 * @return string representing the same address
424 */
425static const char*
426http_plugin_address_to_string (void *cls,
427 const void *addr,
428 size_t addrlen);
429
430
431/**
432 * Call MHD to process pending ipv4 requests and then go back
433 * and schedule the next run.
434 */
435static void http_server_daemon_v4_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
436/**
437 * Call MHD to process pending ipv6 requests and then go back
438 * and schedule the next run.
439 */
440static void http_server_daemon_v6_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
441
442/**
443 * Function setting up curl handle and selecting message to send
444 * @param cls plugin
445 * @param ses session to send data to
446 * @param con connection
447 * @return bytes sent to peer
448 */
449static ssize_t send_check_connections (void *cls, struct Session *ps);
450
451/**
452 * Function setting up file descriptors and scheduling task to run
453 * @param cls closure
454 * @param ses session to send data to
455 * @param
456 */
457static int curl_schedule(void *cls );
458
459
460
461static char * create_url(void * cls, const void * addr, size_t addrlen, size_t id)
462{
463 struct Plugin *plugin = cls;
464 char *url = NULL;
465
466 GNUNET_assert ((addr!=NULL) && (addrlen != 0));
467 GNUNET_asprintf(&url,
468 "https://%s/%s;%u",
469 http_plugin_address_to_string(NULL, addr, addrlen),
470 (char *) (&plugin->my_ascii_hash_ident),id);
471
472 return url;
473}
474
475/**
476 * Removes a message from the linked list of messages
477 * @param con connection to remove message from
478 * @param msg message to remove
479 * @return GNUNET_SYSERR if msg not found, GNUNET_OK on success
480 */
481static int remove_http_message (struct Session * ps, struct HTTP_Message * msg)
482{
483 GNUNET_CONTAINER_DLL_remove(ps->pending_msgs_head,ps->pending_msgs_tail,msg);
484 GNUNET_free(msg);
485 return GNUNET_OK;
486}
487
488int remove_peer_context_Iterator (void *cls, const GNUNET_HashCode *key, void *value);
489
490/**
491 * Removes a session from the linked list of sessions
492 * @param pc peer context
493 * @param ps session
494 * @param call_msg_cont GNUNET_YES to call pending message continuations, otherwise no
495 * @param call_msg_cont_result, result to call message continuations with
496 * @return GNUNET_SYSERR if msg not found, GNUNET_OK on success
497 */
498static int remove_session (struct HTTP_PeerContext * pc, struct Session * ps, int call_msg_cont, int call_msg_cont_result)
499{
500 struct HTTP_Message * msg;
501 struct Plugin * plugin = ps->peercontext->plugin;
502
503#if DEBUG_CONNECTIONS
504 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: removing %s session %X with id %u\n", ps, (ps->direction == INBOUND) ? "inbound" : "outbound", ps, ps->session_id);
505#endif
506 plugin->env->session_end(plugin, &pc->identity, ps);
507
508 GNUNET_free_non_null (ps->addr);
509 GNUNET_SERVER_mst_destroy (ps->msgtok);
510 GNUNET_free(ps->url);
511
512 if (ps->direction==INBOUND)
513 {
514 if (ps->recv_endpoint != NULL)
515 {
516 curl_easy_cleanup(ps->recv_endpoint);
517 ps->recv_endpoint = NULL;
518 }
519 if (ps->send_endpoint != NULL)
520 {
521 curl_easy_cleanup(ps->send_endpoint);
522 ps->send_endpoint = NULL;
523 }
524 }
525
526 msg = ps->pending_msgs_head;
527 while (msg!=NULL)
528 {
529 if ((call_msg_cont == GNUNET_YES) && (msg->transmit_cont!=NULL))
530 {
531 msg->transmit_cont (msg->transmit_cont_cls,&pc->identity,call_msg_cont_result);
532 }
533 GNUNET_free(msg);
534 GNUNET_CONTAINER_DLL_remove(ps->pending_msgs_head,ps->pending_msgs_head,msg);
535 msg = ps->pending_msgs_head;
536 }
537
538 GNUNET_CONTAINER_DLL_remove(pc->head,pc->tail,ps);
539 GNUNET_free(ps);
540 ps = NULL;
541
542 /* no sessions left remove peer */
543 if (pc->head==NULL)
544 {
545#if DEBUG_HTTP
546 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"No sessions left for peer `%s', removing context\n",GNUNET_i2s(&pc->identity));
547#endif
548 remove_peer_context_Iterator(plugin, &pc->identity.hashPubKey, pc);
549 }
550
551 return GNUNET_OK;
552}
553
554int remove_peer_context_Iterator (void *cls, const GNUNET_HashCode *key, void *value)
555{
556 struct Plugin *plugin = cls;
557 struct HTTP_PeerContext * pc = value;
558 struct Session * ps = pc->head;
559 struct Session * tmp = NULL;
560 struct HTTP_Message * msg = NULL;
561 struct HTTP_Message * msg_tmp = NULL;
562#if DEBUG_HTTP
563 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Freeing context for peer `%s'\n",GNUNET_i2s(&pc->identity));
564#endif
565 GNUNET_CONTAINER_multihashmap_remove (plugin->peers, &pc->identity.hashPubKey, pc);
566 while (ps!=NULL)
567 {
568 plugin->env->session_end(plugin, &pc->identity, ps);
569 tmp = ps->next;
570
571 GNUNET_free_non_null (ps->addr);
572 GNUNET_free(ps->url);
573 if (ps->msgtok != NULL)
574 GNUNET_SERVER_mst_destroy (ps->msgtok);
575
576 msg = ps->pending_msgs_head;
577 while (msg!=NULL)
578 {
579 msg_tmp = msg->next;
580 GNUNET_free(msg);
581 msg = msg_tmp;
582 }
583 if (ps->direction==OUTBOUND)
584 {
585 if (ps->send_endpoint!=NULL)
586 curl_easy_cleanup(ps->send_endpoint);
587 if (ps->recv_endpoint!=NULL)
588 curl_easy_cleanup(ps->recv_endpoint);
589 }
590
591 GNUNET_free(ps);
592 ps=tmp;
593 }
594 GNUNET_free(pc);
595 GNUNET_STATISTICS_update (plugin->env->stats,
596 gettext_noop ("# HTTP peers active"),
597 -1,
598 GNUNET_NO);
599 return GNUNET_YES;
600}
601
602/**
603 * Add the IP of our network interface to the list of
604 * our external IP addresses.
605 *
606 * @param cls the 'struct Plugin*'
607 * @param name name of the interface
608 * @param isDefault do we think this may be our default interface
609 * @param addr address of the interface
610 * @param addrlen number of bytes in addr
611 * @return GNUNET_OK to continue iterating
612 */
613static int
614process_interfaces (void *cls,
615 const char *name,
616 int isDefault,
617 const struct sockaddr *addr, socklen_t addrlen)
618{
619 struct Plugin *plugin = cls;
620 struct IPv4HttpAddress * t4;
621 struct IPv6HttpAddress * t6;
622 int af;
623
624
625 GNUNET_assert(cls !=NULL);
626 af = addr->sa_family;
627 if ((af == AF_INET) && (plugin->use_ipv4 == GNUNET_YES) && (plugin->bind6_address == NULL))
628 {
629 struct in_addr bnd_cmp = ((struct sockaddr_in *) addr)->sin_addr;
630 t4 = GNUNET_malloc(sizeof(struct IPv4HttpAddress));
631 /* Not skipping loopback addresses
632 if (INADDR_LOOPBACK == ntohl(((struct sockaddr_in *) addr)->sin_addr.s_addr))
633 {
634
635 return GNUNET_OK;
636 }
637 */
638 t4->ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
639 t4->u_port = htons (plugin->port_inbound);
640 if (plugin->bind4_address != NULL)
641 {
642 if (0 == memcmp(&plugin->bind4_address->sin_addr, &bnd_cmp, sizeof (struct in_addr)))
643 {
644 plugin->env->notify_address(plugin->env->cls,"https",t4, sizeof (struct IPv4HttpAddress), GNUNET_TIME_UNIT_FOREVER_REL);
645 }
646 }
647 else
648 {
649 plugin->env->notify_address(plugin->env->cls,"https",t4, sizeof (struct IPv4HttpAddress), GNUNET_TIME_UNIT_FOREVER_REL);
650 }
651 GNUNET_free (t4);
652 }
653 else if ((af == AF_INET6) && (plugin->use_ipv6 == GNUNET_YES) && (plugin->bind4_address == NULL))
654 {
655 struct in6_addr bnd_cmp6 = ((struct sockaddr_in6 *) addr)->sin6_addr;
656 t6 = GNUNET_malloc(sizeof(struct IPv6HttpAddress));
657 if (IN6_IS_ADDR_LINKLOCAL (&((struct sockaddr_in6 *) addr)->sin6_addr))
658 {
659 return GNUNET_OK;
660 }
661
662 if (plugin->bind6_address != NULL)
663 {
664 if (0 == memcmp(&plugin->bind6_address->sin6_addr, &bnd_cmp6, sizeof (struct in6_addr)))
665 {
666 memcpy (&t6->ipv6_addr,
667 &((struct sockaddr_in6 *) addr)->sin6_addr,
668 sizeof (struct in6_addr));
669 t6->u6_port = htons (plugin->port_inbound);
670 plugin->env->notify_address(plugin->env->cls,"https",t6,sizeof (struct IPv6HttpAddress) , GNUNET_TIME_UNIT_FOREVER_REL);
671 }
672 }
673 else
674 {
675 memcpy (&t6->ipv6_addr,
676 &((struct sockaddr_in6 *) addr)->sin6_addr,
677 sizeof (struct in6_addr));
678 t6->u6_port = htons (plugin->port_inbound);
679 plugin->env->notify_address(plugin->env->cls,"https",t6,sizeof (struct IPv6HttpAddress) , GNUNET_TIME_UNIT_FOREVER_REL);
680 }
681 GNUNET_free (t6);
682 }
683 return GNUNET_OK;
684}
685
686
687/**
688 * Callback called by MHD when a connection is terminated
689 */
690static void mhd_termination_cb (void *cls, struct MHD_Connection * connection, void **httpSessionCache)
691{
692 struct Session * ps = *httpSessionCache;
693 if (ps == NULL)
694 return;
695 struct HTTP_PeerContext * pc = ps->peercontext;
696
697 if (connection==ps->recv_endpoint)
698 {
699#if DEBUG_CONNECTIONS
700 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: inbound connection from peer `%s' was terminated\n", ps, GNUNET_i2s(&pc->identity));
701#endif
702 ps->recv_active = GNUNET_NO;
703 ps->recv_connected = GNUNET_NO;
704 ps->recv_endpoint = NULL;
705 }
706 if (connection==ps->send_endpoint)
707 {
708
709 ps->send_active = GNUNET_NO;
710 ps->send_connected = GNUNET_NO;
711 ps->send_endpoint = NULL;
712#if DEBUG_CONNECTIONS
713 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: outbound connection from peer `%s' was terminated\n", ps, GNUNET_i2s(&pc->identity));
714#endif
715 }
716
717 /* if both connections disconnected, remove session */
718 if ((ps->send_connected == GNUNET_NO) && (ps->recv_connected == GNUNET_NO))
719 {
720 GNUNET_STATISTICS_update (pc->plugin->env->stats,
721 gettext_noop ("# HTTPS inbound sessions for peers active"),
722 -1,
723 GNUNET_NO);
724 remove_session(pc,ps,GNUNET_YES,GNUNET_SYSERR);
725 }
726}
727
728static void mhd_write_mst_cb (void *cls,
729 void *client,
730 const struct GNUNET_MessageHeader *message)
731{
732
733 struct Session *ps = cls;
734 struct HTTP_PeerContext *pc = ps->peercontext;
735 GNUNET_assert(ps != NULL);
736 GNUNET_assert(pc != NULL);
737#if DEBUG_HTTP
738 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
739 "Connection %X: Forwarding message to transport service, type %u and size %u from `%s' (`%s')\n",
740 ps,
741 ntohs(message->type),
742 ntohs(message->size),
743 GNUNET_i2s(&(ps->peercontext)->identity),http_plugin_address_to_string(NULL,ps->addr,ps->addrlen));
744#endif
745 pc->plugin->env->receive (ps->peercontext->plugin->env->cls,
746 &pc->identity,
747 message, 1, ps,
748 NULL,
749 0);
750}
751
752/**
753 * Check if ip is allowed to connect.
754 */
755static int
756mhd_accept_cb (void *cls,
757 const struct sockaddr *addr, socklen_t addr_len)
758{
759#if 0
760 struct Plugin *plugin = cls;
761#endif
762 /* Every connection is accepted, nothing more to do here */
763 return MHD_YES;
764}
765
766int mhd_send_callback (void *cls, uint64_t pos, char *buf, int max)
767{
768 int bytes_read = 0;
769
770 struct Session * ps = cls;
771 struct HTTP_PeerContext * pc;
772 struct HTTP_Message * msg;
773
774 GNUNET_assert (ps!=NULL);
775 pc = ps->peercontext;
776 msg = ps->pending_msgs_tail;
777 if (ps->send_force_disconnect==GNUNET_YES)
778 {
779#if DEBUG_CONNECTIONS
780 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: outbound forced to disconnect\n",ps);
781#endif
782 return -1;
783 }
784
785 if (msg!=NULL)
786 {
787 if ((msg->size-msg->pos) <= max)
788 {
789 memcpy(buf,&msg->buf[msg->pos],(msg->size-msg->pos));
790 bytes_read = msg->size-msg->pos;
791 msg->pos+=(msg->size-msg->pos);
792 }
793 else
794 {
795 memcpy(buf,&msg->buf[msg->pos],max);
796 msg->pos+=max;
797 bytes_read = max;
798 }
799
800 if (msg->pos==msg->size)
801 {
802 if (NULL!=msg->transmit_cont)
803 msg->transmit_cont (msg->transmit_cont_cls,&pc->identity,GNUNET_OK);
804 remove_http_message(ps,msg);
805 }
806 }
807 return bytes_read;
808}
809
810/**
811 * Process GET or PUT request received via MHD. For
812 * GET, queue response that will send back our pending
813 * messages. For PUT, process incoming data and send
814 * to GNUnet core. In either case, check if a session
815 * already exists and create a new one if not.
816 */
817static int
818mdh_access_cb (void *cls,
819 struct MHD_Connection *mhd_connection,
820 const char *url,
821 const char *method,
822 const char *version,
823 const char *upload_data,
824 size_t * upload_data_size, void **httpSessionCache)
825{
826 struct Plugin *plugin = cls;
827 struct MHD_Response *response;
828 const union MHD_ConnectionInfo * conn_info;
829
830 struct sockaddr_in *addrin;
831 struct sockaddr_in6 *addrin6;
832
833 char address[INET6_ADDRSTRLEN+14];
834 struct GNUNET_PeerIdentity pi_in;
835 size_t id_num = 0;
836
837 struct IPv4HttpAddress ipv4addr;
838 struct IPv6HttpAddress ipv6addr;
839
840 struct HTTP_PeerContext *pc;
841 struct Session *ps = NULL;
842 struct Session *ps_tmp = NULL;
843
844 int res = GNUNET_NO;
845 int send_error_to_client;
846 void * addr;
847 size_t addr_len;
848
849 GNUNET_assert(cls !=NULL);
850 send_error_to_client = GNUNET_NO;
851
852 if (NULL == *httpSessionCache)
853 {
854 /* check url for peer identity , if invalid send HTTP 404*/
855 size_t len = strlen(&url[1]);
856 char * peer = GNUNET_malloc(104+1);
857
858 if ((len>104) && (url[104]==';'))
859 {
860 char * id = GNUNET_malloc((len-104)+1);
861 strcpy(id,&url[105]);
862 memcpy(peer,&url[1],103);
863 peer[103] = '\0';
864 id_num = strtoul ( id, NULL , 10);
865 GNUNET_free(id);
866 }
867 res = GNUNET_CRYPTO_hash_from_string (peer, &(pi_in.hashPubKey));
868 GNUNET_free(peer);
869 if ( GNUNET_SYSERR == res )
870 {
871 response = MHD_create_response_from_data (strlen (HTTP_ERROR_RESPONSE),HTTP_ERROR_RESPONSE, MHD_NO, MHD_NO);
872 res = MHD_queue_response (mhd_connection, MHD_HTTP_NOT_FOUND, response);
873 MHD_destroy_response (response);
874#if DEBUG_CONNECTIONS
875 if (res == MHD_YES)
876 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Peer has no valid ident, sent HTTP 1.1/404\n");
877 else
878 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Peer has no valid ident, could not send error\n");
879#endif
880 return res;
881 }
882 }
883 else
884 {
885 ps = *httpSessionCache;
886 pc = ps->peercontext;
887 }
888
889 if (NULL == *httpSessionCache)
890 {
891 /* get peer context */
892 pc = GNUNET_CONTAINER_multihashmap_get (plugin->peers, &pi_in.hashPubKey);
893 /* Peer unknown */
894 if (pc==NULL)
895 {
896 pc = GNUNET_malloc(sizeof (struct HTTP_PeerContext));
897 pc->plugin = plugin;
898 pc->session_id_counter=1;
899 pc->last_session = NULL;
900 memcpy(&pc->identity, &pi_in, sizeof(struct GNUNET_PeerIdentity));
901 GNUNET_CONTAINER_multihashmap_put(plugin->peers, &pc->identity.hashPubKey, pc, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
902 GNUNET_STATISTICS_update (plugin->env->stats,
903 gettext_noop ("# HTTP peers active"),
904 1,
905 GNUNET_NO);
906 }
907
908 conn_info = MHD_get_connection_info(mhd_connection, MHD_CONNECTION_INFO_CLIENT_ADDRESS );
909 /* Incoming IPv4 connection */
910 if ( AF_INET == conn_info->client_addr->sin_family)
911 {
912 addrin = conn_info->client_addr;
913 inet_ntop(addrin->sin_family, &(addrin->sin_addr),address,INET_ADDRSTRLEN);
914 memcpy(&ipv4addr.ipv4_addr,&(addrin->sin_addr),sizeof(struct in_addr));
915 ipv4addr.u_port = addrin->sin_port;
916 addr = &ipv4addr;
917 addr_len = sizeof(struct IPv4HttpAddress);
918 }
919 /* Incoming IPv6 connection */
920 if ( AF_INET6 == conn_info->client_addr->sin_family)
921 {
922 addrin6 = (struct sockaddr_in6 *) conn_info->client_addr;
923 inet_ntop(addrin6->sin6_family, &(addrin6->sin6_addr),address,INET6_ADDRSTRLEN);
924 memcpy(&ipv6addr.ipv6_addr,&(addrin6->sin6_addr),sizeof(struct in6_addr));
925 ipv6addr.u6_port = addrin6->sin6_port;
926 addr = &ipv6addr;
927 addr_len = sizeof(struct IPv6HttpAddress);
928 }
929
930 ps = NULL;
931 /* only inbound sessions here */
932
933 ps_tmp = pc->head;
934 while (ps_tmp!=NULL)
935 {
936 if ((ps_tmp->direction==INBOUND) && (ps_tmp->session_id == id_num) && (id_num!=0))
937 {
938 if ((ps_tmp->recv_force_disconnect!=GNUNET_YES) && (ps_tmp->send_force_disconnect!=GNUNET_YES))
939 ps=ps_tmp;
940 break;
941 }
942 ps_tmp=ps_tmp->next;
943 }
944
945 if (ps==NULL)
946 {
947 ps = GNUNET_malloc(sizeof (struct Session));
948 ps->addr = GNUNET_malloc(addr_len);
949 memcpy(ps->addr,addr,addr_len);
950 ps->addrlen = addr_len;
951 ps->direction=INBOUND;
952 ps->pending_msgs_head = NULL;
953 ps->pending_msgs_tail = NULL;
954 ps->send_connected=GNUNET_NO;
955 ps->send_active=GNUNET_NO;
956 ps->recv_connected=GNUNET_NO;
957 ps->recv_active=GNUNET_NO;
958 ps->peercontext=pc;
959 ps->session_id =id_num;
960 ps->url = create_url (plugin, ps->addr, ps->addrlen, ps->session_id);
961 GNUNET_CONTAINER_DLL_insert(pc->head,pc->tail,ps);
962 GNUNET_STATISTICS_update (plugin->env->stats,
963 gettext_noop ("# HTTPS inbound sessions for peers active"),
964 1,
965 GNUNET_NO);
966 }
967
968 *httpSessionCache = ps;
969 if (ps->msgtok==NULL)
970 ps->msgtok = GNUNET_SERVER_mst_create (&mhd_write_mst_cb, ps);
971#if DEBUG_HTTP
972 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: HTTPS Daemon has new an incoming `%s' request from peer `%s' (`%s')\n",
973 ps,
974 method,
975 GNUNET_i2s(&pc->identity),
976 http_plugin_address_to_string(NULL, ps->addr, ps->addrlen));
977#endif
978 }
979
980 /* Is it a PUT or a GET request */
981 if (0 == strcmp (MHD_HTTP_METHOD_PUT, method))
982 {
983 if (ps->recv_force_disconnect == GNUNET_YES)
984 {
985#if DEBUG_CONNECTIONS
986 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: inbound connection was forced to disconnect\n",ps);
987#endif
988 ps->recv_active = GNUNET_NO;
989 return MHD_NO;
990 }
991 if ((*upload_data_size == 0) && (ps->recv_active==GNUNET_NO))
992 {
993 ps->recv_endpoint = mhd_connection;
994 ps->recv_connected = GNUNET_YES;
995 ps->recv_active = GNUNET_YES;
996 ps->recv_force_disconnect = GNUNET_NO;
997#if DEBUG_CONNECTIONS
998 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: inbound PUT connection connected\n",ps);
999#endif
1000 return MHD_YES;
1001 }
1002
1003 /* Transmission of all data complete */
1004 if ((*upload_data_size == 0) && (ps->recv_active == GNUNET_YES))
1005 {
1006 response = MHD_create_response_from_data (strlen (HTTP_PUT_RESPONSE),HTTP_PUT_RESPONSE, MHD_NO, MHD_NO);
1007 res = MHD_queue_response (mhd_connection, MHD_HTTP_OK, response);
1008#if DEBUG_CONNECTIONS
1009 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: Sent HTTP/1.1: 200 OK as PUT Response\n",ps);
1010#endif
1011 MHD_destroy_response (response);
1012 ps->recv_active=GNUNET_NO;
1013 return MHD_YES;
1014 }
1015
1016 /* Recieving data */
1017 if ((*upload_data_size > 0) && (ps->recv_active == GNUNET_YES))
1018 {
1019 res = GNUNET_SERVER_mst_receive(ps->msgtok, ps, upload_data,*upload_data_size, GNUNET_NO, GNUNET_NO);
1020 (*upload_data_size) = 0;
1021 return MHD_YES;
1022 }
1023 else
1024 return MHD_NO;
1025 }
1026 if ( 0 == strcmp (MHD_HTTP_METHOD_GET, method) )
1027 {
1028 if (ps->send_force_disconnect == GNUNET_YES)
1029 {
1030#if DEBUG_CONNECTIONS
1031 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: outbound connection was forced to disconnect\n",ps);
1032#endif
1033 ps->send_active = GNUNET_NO;
1034 return MHD_NO;
1035 }
1036 ps->send_connected = GNUNET_YES;
1037 ps->send_active = GNUNET_YES;
1038 ps->send_endpoint = mhd_connection;
1039 ps->send_force_disconnect = GNUNET_NO;
1040#if DEBUG_CONNECTIONS
1041 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: inbound GET connection connected\n",ps);
1042#endif
1043 response = MHD_create_response_from_callback(-1,32 * 1024, &mhd_send_callback, ps, NULL);
1044 res = MHD_queue_response (mhd_connection, MHD_HTTP_OK, response);
1045 MHD_destroy_response (response);
1046 return MHD_YES;
1047 }
1048 return MHD_NO;
1049}
1050
1051/**
1052 * Function that queries MHD's select sets and
1053 * starts the task waiting for them.
1054 */
1055static GNUNET_SCHEDULER_TaskIdentifier
1056http_server_daemon_prepare (void * cls, struct MHD_Daemon *daemon_handle)
1057{
1058 struct Plugin *plugin = cls;
1059 GNUNET_SCHEDULER_TaskIdentifier ret;
1060 fd_set rs;
1061 fd_set ws;
1062 fd_set es;
1063 struct GNUNET_NETWORK_FDSet *wrs;
1064 struct GNUNET_NETWORK_FDSet *wws;
1065 struct GNUNET_NETWORK_FDSet *wes;
1066 int max;
1067 unsigned long long timeout;
1068 int haveto;
1069 struct GNUNET_TIME_Relative tv;
1070
1071 GNUNET_assert(cls !=NULL);
1072 ret = GNUNET_SCHEDULER_NO_TASK;
1073 FD_ZERO(&rs);
1074 FD_ZERO(&ws);
1075 FD_ZERO(&es);
1076 wrs = GNUNET_NETWORK_fdset_create ();
1077 wes = GNUNET_NETWORK_fdset_create ();
1078 wws = GNUNET_NETWORK_fdset_create ();
1079 max = -1;
1080 GNUNET_assert (MHD_YES ==
1081 MHD_get_fdset (daemon_handle,
1082 &rs,
1083 &ws,
1084 &es,
1085 &max));
1086 haveto = MHD_get_timeout (daemon_handle, &timeout);
1087 if (haveto == MHD_YES)
1088 tv.value = (uint64_t) timeout;
1089 else
1090 tv = GNUNET_TIME_UNIT_FOREVER_REL;
1091 GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max);
1092 GNUNET_NETWORK_fdset_copy_native (wws, &ws, max);
1093 GNUNET_NETWORK_fdset_copy_native (wes, &es, max);
1094 if (daemon_handle == plugin->http_server_daemon_v4)
1095 {
1096 if (plugin->http_server_task_v4 != GNUNET_SCHEDULER_NO_TASK)
1097 {
1098 GNUNET_SCHEDULER_cancel(plugin->env->sched, plugin->http_server_task_v4);
1099 plugin->http_server_daemon_v4 = GNUNET_SCHEDULER_NO_TASK;
1100 }
1101
1102 ret = GNUNET_SCHEDULER_add_select (plugin->env->sched,
1103 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1104 GNUNET_SCHEDULER_NO_TASK,
1105 tv,
1106 wrs,
1107 wws,
1108 &http_server_daemon_v4_run,
1109 plugin);
1110 }
1111 if (daemon_handle == plugin->http_server_daemon_v6)
1112 {
1113 if (plugin->http_server_task_v6 != GNUNET_SCHEDULER_NO_TASK)
1114 {
1115 GNUNET_SCHEDULER_cancel(plugin->env->sched, plugin->http_server_task_v6);
1116 plugin->http_server_task_v6 = GNUNET_SCHEDULER_NO_TASK;
1117 }
1118
1119 ret = GNUNET_SCHEDULER_add_select (plugin->env->sched,
1120 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1121 GNUNET_SCHEDULER_NO_TASK,
1122 tv,
1123 wrs,
1124 wws,
1125 &http_server_daemon_v6_run,
1126 plugin);
1127 }
1128 GNUNET_NETWORK_fdset_destroy (wrs);
1129 GNUNET_NETWORK_fdset_destroy (wws);
1130 GNUNET_NETWORK_fdset_destroy (wes);
1131 return ret;
1132}
1133
1134/**
1135 * Call MHD to process pending requests and then go back
1136 * and schedule the next run.
1137 */
1138static void http_server_daemon_v4_run (void *cls,
1139 const struct GNUNET_SCHEDULER_TaskContext *tc)
1140{
1141 struct Plugin *plugin = cls;
1142
1143 GNUNET_assert(cls !=NULL);
1144 plugin->http_server_task_v4 = GNUNET_SCHEDULER_NO_TASK;
1145
1146 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
1147 return;
1148
1149 GNUNET_assert (MHD_YES == MHD_run (plugin->http_server_daemon_v4));
1150 plugin->http_server_task_v4 = http_server_daemon_prepare (plugin, plugin->http_server_daemon_v4);
1151 return;
1152}
1153
1154
1155/**
1156 * Call MHD to process pending requests and then go back
1157 * and schedule the next run.
1158 */
1159static void http_server_daemon_v6_run (void *cls,
1160 const struct GNUNET_SCHEDULER_TaskContext *tc)
1161{
1162 struct Plugin *plugin = cls;
1163
1164 GNUNET_assert(cls !=NULL);
1165 plugin->http_server_task_v6 = GNUNET_SCHEDULER_NO_TASK;
1166
1167 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
1168 return;
1169
1170 GNUNET_assert (MHD_YES == MHD_run (plugin->http_server_daemon_v6));
1171 plugin->http_server_task_v6 = http_server_daemon_prepare (plugin, plugin->http_server_daemon_v6);
1172 return;
1173}
1174
1175static size_t curl_get_header_cb( void *ptr, size_t size, size_t nmemb, void *stream)
1176{
1177 struct Session * ps = stream;
1178 char * tmp;
1179 size_t len = size * nmemb;
1180 long http_result = 0;
1181 int res;
1182 /* Getting last http result code */
1183 if (ps->recv_connected==GNUNET_NO)
1184 {
1185 GNUNET_assert(NULL!=ps);
1186 res = curl_easy_getinfo(ps->recv_endpoint, CURLINFO_RESPONSE_CODE, &http_result);
1187 if (CURLE_OK == res)
1188 {
1189 if (http_result == 200)
1190 {
1191 ps->recv_connected = GNUNET_YES;
1192 ps->recv_active = GNUNET_YES;
1193#if DEBUG_CONNECTIONS
1194 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: connected to recieve data\n",ps);
1195#endif
1196 // Calling send_check_connections again since receive is established
1197 send_check_connections (ps->peercontext->plugin, ps);
1198 }
1199 }
1200 }
1201
1202 tmp = NULL;
1203 if ((size * nmemb) < SIZE_MAX)
1204 tmp = GNUNET_malloc (len+1);
1205
1206 if ((tmp != NULL) && (len > 0))
1207 {
1208 memcpy(tmp,ptr,len);
1209 if (len>=2)
1210 {
1211 if (tmp[len-2] == 13)
1212 tmp[len-2]= '\0';
1213 }
1214 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: Header: %s\n",ps,tmp);
1215 }
1216 if (NULL != tmp)
1217 GNUNET_free (tmp);
1218
1219 return size * nmemb;
1220}
1221
1222static size_t curl_put_header_cb( void *ptr, size_t size, size_t nmemb, void *stream)
1223{
1224 struct Session * ps = stream;
1225
1226 char * tmp;
1227 size_t len = size * nmemb;
1228 long http_result = 0;
1229 int res;
1230
1231 /* Getting last http result code */
1232 GNUNET_assert(NULL!=ps);
1233 res = curl_easy_getinfo(ps->send_endpoint, CURLINFO_RESPONSE_CODE, &http_result);
1234 if (CURLE_OK == res)
1235 {
1236 if ((http_result == 100) && (ps->send_connected==GNUNET_NO))
1237 {
1238 ps->send_connected = GNUNET_YES;
1239 ps->send_active = GNUNET_YES;
1240#if DEBUG_CONNECTIONS
1241 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: connected to send data\n",ps);
1242#endif
1243 }
1244 if ((http_result == 200) && (ps->send_connected==GNUNET_YES))
1245 {
1246 ps->send_connected = GNUNET_NO;
1247 ps->send_active = GNUNET_NO;
1248#if DEBUG_CONNECTIONS
1249 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: sending disconnected\n",ps);
1250#endif
1251 }
1252 }
1253
1254 tmp = NULL;
1255 if ((size * nmemb) < SIZE_MAX)
1256 tmp = GNUNET_malloc (len+1);
1257
1258 if ((tmp != NULL) && (len > 0))
1259 {
1260 memcpy(tmp,ptr,len);
1261 if (len>=2)
1262 {
1263 if (tmp[len-2] == 13)
1264 tmp[len-2]= '\0';
1265 }
1266 }
1267 if (NULL != tmp)
1268 GNUNET_free (tmp);
1269
1270 return size * nmemb;
1271}
1272
1273/**
1274 * Callback method used with libcurl
1275 * Method is called when libcurl needs to read data during sending
1276 * @param stream pointer where to write data
1277 * @param size size of an individual element
1278 * @param nmemb count of elements that can be written to the buffer
1279 * @param ptr source pointer, passed to the libcurl handle
1280 * @return bytes written to stream
1281 */
1282static size_t curl_send_cb(void *stream, size_t size, size_t nmemb, void *ptr)
1283{
1284 struct Session * ps = ptr;
1285 struct HTTP_Message * msg = ps->pending_msgs_tail;
1286 size_t bytes_sent;
1287 size_t len;
1288
1289 if (ps->send_active == GNUNET_NO)
1290 return CURL_READFUNC_PAUSE;
1291
1292
1293 if ((ps->pending_msgs_tail == NULL) && (ps->send_active == GNUNET_YES))
1294 {
1295#if DEBUG_CONNECTIONS
1296 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: No Message to send, pausing connection\n",ps);
1297#endif
1298 ps->send_active = GNUNET_NO;
1299 return CURL_READFUNC_PAUSE;
1300 }
1301
1302 msg = ps->pending_msgs_tail;
1303 /* data to send */
1304 if (msg->pos < msg->size)
1305 {
1306 /* data fit in buffer */
1307 if ((msg->size - msg->pos) <= (size * nmemb))
1308 {
1309 len = (msg->size - msg->pos);
1310 memcpy(stream, &msg->buf[msg->pos], len);
1311 msg->pos += len;
1312 bytes_sent = len;
1313 }
1314 else
1315 {
1316 len = size*nmemb;
1317 memcpy(stream, &msg->buf[msg->pos], len);
1318 msg->pos += len;
1319 bytes_sent = len;
1320 }
1321 }
1322 /* no data to send */
1323 else
1324 {
1325 bytes_sent = 0;
1326 }
1327
1328 if ( msg->pos == msg->size)
1329 {
1330#if DEBUG_CONNECTIONS
1331 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: Message with %u bytes sent, removing message from queue \n",ps, msg->pos);
1332#endif
1333 /* Calling transmit continuation */
1334 if (( NULL != ps->pending_msgs_tail) && (NULL != ps->pending_msgs_tail->transmit_cont))
1335 msg->transmit_cont (ps->pending_msgs_tail->transmit_cont_cls,&(ps->peercontext)->identity,GNUNET_OK);
1336 remove_http_message(ps, msg);
1337 }
1338 return bytes_sent;
1339}
1340
1341static void curl_receive_mst_cb (void *cls,
1342 void *client,
1343 const struct GNUNET_MessageHeader *message)
1344{
1345 struct Session *ps = cls;
1346 struct HTTP_PeerContext *pc = ps->peercontext;
1347 GNUNET_assert(ps != NULL);
1348 GNUNET_assert(pc != NULL);
1349#if DEBUG_HTTP
1350 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1351 "Connection %X: Forwarding message to transport service, type %u and size %u from `%s' (`%s')\n",
1352 ps,
1353 ntohs(message->type),
1354 ntohs(message->size),
1355 GNUNET_i2s(&(pc->identity)),http_plugin_address_to_string(NULL,ps->addr,ps->addrlen));
1356#endif
1357 pc->plugin->env->receive (pc->plugin->env->cls,
1358 &pc->identity,
1359 message, 1, ps,
1360 ps->addr,
1361 ps->addrlen);
1362}
1363
1364
1365/**
1366* Callback method used with libcurl
1367* Method is called when libcurl needs to write data during sending
1368* @param stream pointer where to write data
1369* @param size size of an individual element
1370* @param nmemb count of elements that can be written to the buffer
1371* @param ptr destination pointer, passed to the libcurl handle
1372* @return bytes read from stream
1373*/
1374static size_t curl_receive_cb( void *stream, size_t size, size_t nmemb, void *ptr)
1375{
1376 struct Session * ps = ptr;
1377#if DEBUG_CONNECTIONS
1378 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: %u bytes received\n",ps, size*nmemb);
1379#endif
1380 GNUNET_SERVER_mst_receive(ps->msgtok, ps, stream, size*nmemb, GNUNET_NO, GNUNET_NO);
1381 return (size * nmemb);
1382
1383}
1384
1385static void curl_perform (void *cls,
1386 const struct GNUNET_SCHEDULER_TaskContext *tc)
1387{
1388 struct Plugin *plugin = cls;
1389 static unsigned int handles_last_run;
1390 int running;
1391 struct CURLMsg *msg;
1392 CURLMcode mret;
1393 struct Session *ps = NULL;
1394 struct HTTP_PeerContext *pc = NULL;
1395 struct HTTP_Message * cur_msg = NULL;
1396 long http_result;
1397 char * tmp;
1398
1399 GNUNET_assert(cls !=NULL);
1400
1401 plugin->http_curl_task = GNUNET_SCHEDULER_NO_TASK;
1402 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
1403 return;
1404
1405 do
1406 {
1407 running = 0;
1408 mret = curl_multi_perform (plugin->multi_handle, &running);
1409 if ((running < handles_last_run) && (running>0))
1410 {
1411 do
1412 {
1413
1414 msg = curl_multi_info_read (plugin->multi_handle, &running);
1415 if (running == 0)
1416 break;
1417 /* get session for affected curl handle */
1418 GNUNET_assert ( msg->easy_handle != NULL );
1419 curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, &tmp);
1420 ps = (struct Session *) tmp;
1421 GNUNET_assert ( ps != NULL );
1422 pc = ps->peercontext;
1423 GNUNET_assert ( pc != NULL );
1424 switch (msg->msg)
1425 {
1426
1427 case CURLMSG_DONE:
1428 if ( (msg->data.result != CURLE_OK) &&
1429 (msg->data.result != CURLE_GOT_NOTHING) )
1430 {
1431 /* sending msg failed*/
1432 if (msg->easy_handle == ps->send_endpoint)
1433 {
1434#if DEBUG_CONNECTIONS
1435 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1436 _("Connection %X: HTTPS PUT to peer `%s' (`%s') failed: `%s' `%s'\n"),
1437 ps,
1438 GNUNET_i2s(&pc->identity),
1439 http_plugin_address_to_string(NULL, ps->addr, ps->addrlen),
1440 "curl_multi_perform",
1441 curl_easy_strerror (msg->data.result));
1442#endif
1443 ps->send_connected = GNUNET_NO;
1444 ps->send_active = GNUNET_NO;
1445 curl_multi_remove_handle(plugin->multi_handle,ps->send_endpoint);
1446 //curl_easy_cleanup(ps->send_endpoint);
1447 //ps->send_endpoint=NULL;
1448 cur_msg = ps->pending_msgs_tail;
1449 if (( NULL != cur_msg) && ( NULL != cur_msg->transmit_cont))
1450 cur_msg->transmit_cont (cur_msg->transmit_cont_cls,&pc->identity,GNUNET_SYSERR);
1451 }
1452 /* GET connection failed */
1453 if (msg->easy_handle == ps->recv_endpoint)
1454 {
1455#if DEBUG_CONNECTIONS
1456 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
1457 _("Connection %X: HTTPS GET to peer `%s' (`%s') failed: `%s' `%s'\n"),
1458 ps,
1459 GNUNET_i2s(&pc->identity),
1460 http_plugin_address_to_string(NULL, ps->addr, ps->addrlen),
1461 "curl_multi_perform",
1462 curl_easy_strerror (msg->data.result));
1463#endif
1464 ps->recv_connected = GNUNET_NO;
1465 ps->recv_active = GNUNET_NO;
1466 curl_multi_remove_handle(plugin->multi_handle,ps->recv_endpoint);
1467 //curl_easy_cleanup(ps->recv_endpoint);
1468 //ps->recv_endpoint=NULL;
1469 }
1470 }
1471 else
1472 {
1473 if (msg->easy_handle == ps->send_endpoint)
1474 {
1475 GNUNET_assert (CURLE_OK == curl_easy_getinfo(msg->easy_handle, CURLINFO_RESPONSE_CODE, &http_result));
1476#if DEBUG_CONNECTIONS
1477 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1478 "Connection %X: HTTPS PUT connection to peer `%s' (`%s') was closed with HTTP code %u\n",
1479 ps,
1480 GNUNET_i2s(&pc->identity),
1481 http_plugin_address_to_string(NULL, ps->addr, ps->addrlen),
1482 http_result);
1483#endif
1484 /* Calling transmit continuation */
1485 cur_msg = ps->pending_msgs_tail;
1486 if (( NULL != cur_msg) && (NULL != cur_msg->transmit_cont))
1487 {
1488 /* HTTP 1xx : Last message before here was informational */
1489 if ((http_result >=100) && (http_result < 200))
1490 cur_msg->transmit_cont (cur_msg->transmit_cont_cls,&pc->identity,GNUNET_OK);
1491 /* HTTP 2xx: successful operations */
1492 if ((http_result >=200) && (http_result < 300))
1493 cur_msg->transmit_cont (cur_msg->transmit_cont_cls,&pc->identity,GNUNET_OK);
1494 /* HTTP 3xx..5xx: error */
1495 if ((http_result >=300) && (http_result < 600))
1496 cur_msg->transmit_cont (cur_msg->transmit_cont_cls,&pc->identity,GNUNET_SYSERR);
1497 }
1498 ps->send_connected = GNUNET_NO;
1499 ps->send_active = GNUNET_NO;
1500 curl_multi_remove_handle(plugin->multi_handle,ps->send_endpoint);
1501 //curl_easy_cleanup(ps->send_endpoint);
1502 //ps->send_endpoint =NULL;
1503 }
1504 if (msg->easy_handle == ps->recv_endpoint)
1505 {
1506#if DEBUG_CONNECTIONS
1507 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1508 "Connection %X: HTTP GET connection to peer `%s' (`%s') was closed with HTTP code %u\n",
1509 ps,
1510 GNUNET_i2s(&pc->identity),
1511 http_plugin_address_to_string(NULL, ps->addr, ps->addrlen),
1512 http_result);
1513#endif
1514 ps->recv_connected = GNUNET_NO;
1515 ps->recv_active = GNUNET_NO;
1516 curl_multi_remove_handle(plugin->multi_handle,ps->recv_endpoint);
1517 //curl_easy_cleanup(ps->recv_endpoint);
1518 //ps->recv_endpoint=NULL;
1519 }
1520 }
1521 if ((ps->recv_connected == GNUNET_NO) && (ps->send_connected == GNUNET_NO))
1522 remove_session (pc, ps, GNUNET_YES, GNUNET_SYSERR);
1523 break;
1524 default:
1525 break;
1526 }
1527
1528 }
1529 while ( (running > 0) );
1530 }
1531 handles_last_run = running;
1532 }
1533 while (mret == CURLM_CALL_MULTI_PERFORM);
1534 curl_schedule(plugin);
1535}
1536
1537
1538/**
1539 * Function setting up file descriptors and scheduling task to run
1540 * @param ses session to send data to
1541 * @return GNUNET_SYSERR for hard failure, GNUNET_OK for ok
1542 */
1543static int curl_schedule(void *cls)
1544{
1545 struct Plugin *plugin = cls;
1546 fd_set rs;
1547 fd_set ws;
1548 fd_set es;
1549 int max;
1550 struct GNUNET_NETWORK_FDSet *grs;
1551 struct GNUNET_NETWORK_FDSet *gws;
1552 long to;
1553 CURLMcode mret;
1554
1555 GNUNET_assert(cls !=NULL);
1556
1557 /* Cancel previous scheduled task */
1558 if (plugin->http_curl_task != GNUNET_SCHEDULER_NO_TASK)
1559 {
1560 GNUNET_SCHEDULER_cancel(plugin->env->sched, plugin->http_curl_task);
1561 plugin->http_curl_task = GNUNET_SCHEDULER_NO_TASK;
1562 }
1563 max = -1;
1564 FD_ZERO (&rs);
1565 FD_ZERO (&ws);
1566 FD_ZERO (&es);
1567 mret = curl_multi_fdset (plugin->multi_handle, &rs, &ws, &es, &max);
1568 if (mret != CURLM_OK)
1569 {
1570 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1571 _("%s failed at %s:%d: `%s'\n"),
1572 "curl_multi_fdset", __FILE__, __LINE__,
1573 curl_multi_strerror (mret));
1574 return GNUNET_SYSERR;
1575 }
1576 mret = curl_multi_timeout (plugin->multi_handle, &to);
1577 if (mret != CURLM_OK)
1578 {
1579 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1580 _("%s failed at %s:%d: `%s'\n"),
1581 "curl_multi_timeout", __FILE__, __LINE__,
1582 curl_multi_strerror (mret));
1583 return GNUNET_SYSERR;
1584 }
1585
1586 grs = GNUNET_NETWORK_fdset_create ();
1587 gws = GNUNET_NETWORK_fdset_create ();
1588 GNUNET_NETWORK_fdset_copy_native (grs, &rs, max + 1);
1589 GNUNET_NETWORK_fdset_copy_native (gws, &ws, max + 1);
1590 plugin->http_curl_task = GNUNET_SCHEDULER_add_select (plugin->env->sched,
1591 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1592 GNUNET_SCHEDULER_NO_TASK,
1593 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 0),
1594 grs,
1595 gws,
1596 &curl_perform,
1597 plugin);
1598 GNUNET_NETWORK_fdset_destroy (gws);
1599 GNUNET_NETWORK_fdset_destroy (grs);
1600 return GNUNET_OK;
1601}
1602
1603/**
1604 * Function setting up curl handle and selecting message to send
1605 * @param cls plugin
1606 * @param ses session to send data to
1607 * @param con connection
1608 * @return GNUNET_SYSERR on failure, GNUNET_NO if connecting, GNUNET_YES if ok
1609 */
1610static ssize_t send_check_connections (void *cls, struct Session *ps)
1611{
1612 struct Plugin *plugin = cls;
1613 CURLMcode mret;
1614 struct HTTP_Message * msg;
1615
1616 struct GNUNET_TIME_Relative timeout = GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT;
1617
1618 GNUNET_assert(cls !=NULL);
1619
1620 if (ps->direction == OUTBOUND)
1621 {
1622 /* RECV DIRECTION */
1623 /* Check if session is connected to receive data, otherwise connect to peer */
1624 if (ps->recv_connected == GNUNET_NO)
1625 {
1626 int fresh = GNUNET_NO;
1627 if (ps->recv_endpoint == NULL)
1628 {
1629 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1630 "created handle\n");
1631 fresh = GNUNET_YES;
1632 ps->recv_endpoint = curl_easy_init();
1633 }
1634#if DEBUG_CURL
1635 curl_easy_setopt(ps->recv_endpoint, CURLOPT_VERBOSE, 1L);
1636#endif
1637 curl_easy_setopt(ps->recv_endpoint, CURLOPT_URL, ps->url);
1638 curl_easy_setopt (ps->recv_endpoint, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
1639 //curl_easy_setopt (ps->recv_endpoint, CURLOPT_SSL_CIPHER_LIST, cipher_suite);
1640 curl_easy_setopt(ps->recv_endpoint, CURLOPT_SSL_VERIFYPEER, 0);
1641 curl_easy_setopt(ps->recv_endpoint, CURLOPT_SSL_VERIFYHOST, 0);
1642 curl_easy_setopt(ps->recv_endpoint, CURLOPT_HEADERFUNCTION, &curl_get_header_cb);
1643 curl_easy_setopt(ps->recv_endpoint, CURLOPT_WRITEHEADER, ps);
1644 curl_easy_setopt(ps->recv_endpoint, CURLOPT_READFUNCTION, curl_send_cb);
1645 curl_easy_setopt(ps->recv_endpoint, CURLOPT_READDATA, ps);
1646 curl_easy_setopt(ps->recv_endpoint, CURLOPT_WRITEFUNCTION, curl_receive_cb);
1647 curl_easy_setopt(ps->recv_endpoint, CURLOPT_WRITEDATA, ps);
1648 curl_easy_setopt(ps->recv_endpoint, CURLOPT_TIMEOUT, (long) timeout.value);
1649 curl_easy_setopt(ps->recv_endpoint, CURLOPT_PRIVATE, ps);
1650 curl_easy_setopt(ps->recv_endpoint, CURLOPT_CONNECTTIMEOUT, HTTP_CONNECT_TIMEOUT);
1651 curl_easy_setopt(ps->recv_endpoint, CURLOPT_BUFFERSIZE, GNUNET_SERVER_MAX_MESSAGE_SIZE);
1652
1653 if (fresh==GNUNET_YES)
1654 {
1655 mret = curl_multi_add_handle(plugin->multi_handle, ps->recv_endpoint);
1656 if (mret != CURLM_OK)
1657 {
1658 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1659 _("Connection: %X: %s failed at %s:%d: `%s'\n"),
1660 ps,
1661 "curl_multi_add_handle", __FILE__, __LINE__,
1662 curl_multi_strerror (mret));
1663 return GNUNET_SYSERR;
1664 }
1665 }
1666 if (curl_schedule (plugin) == GNUNET_SYSERR)
1667 {
1668#if DEBUG_CONNECTIONS
1669 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: could not schedule curl task\n",ps);
1670#endif
1671 return GNUNET_SYSERR;
1672 }
1673#if DEBUG_CONNECTIONS
1674 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: inbound not connected, initiating connection\n",ps);
1675#endif
1676 }
1677
1678 /* waiting for receive direction */
1679 if (ps->recv_connected==GNUNET_NO)
1680 return GNUNET_NO;
1681
1682 /* SEND DIRECTION */
1683 /* Check if session is connected to send data, otherwise connect to peer */
1684 if ((ps->send_connected == GNUNET_YES) && (ps->send_endpoint!= NULL))
1685 {
1686 if (ps->send_active == GNUNET_YES)
1687 {
1688#if DEBUG_CONNECTIONS
1689 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: outbound active, enqueueing message\n",ps);
1690#endif
1691 return GNUNET_YES;
1692 }
1693 if (ps->send_active == GNUNET_NO)
1694 {
1695#if DEBUG_CONNECTIONS
1696 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: outbound paused, unpausing existing connection and enqueueing message\n",ps);
1697#endif
1698 if (CURLE_OK == curl_easy_pause(ps->send_endpoint,CURLPAUSE_CONT))
1699 {
1700 ps->send_active=GNUNET_YES;
1701 return GNUNET_YES;
1702 }
1703 else
1704 return GNUNET_SYSERR;
1705 }
1706 }
1707 /* not connected, initiate connection */
1708 if (ps->send_connected==GNUNET_NO)
1709 {
1710 int fresh = GNUNET_NO;
1711 if (NULL == ps->send_endpoint)
1712 {
1713 ps->send_endpoint = curl_easy_init();
1714 fresh = GNUNET_YES;
1715 }
1716 GNUNET_assert (ps->send_endpoint != NULL);
1717 GNUNET_assert (NULL != ps->pending_msgs_tail);
1718#if DEBUG_CONNECTIONS
1719 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Connection %X: outbound not connected, initiating connection\n",ps);
1720#endif
1721 ps->send_active = GNUNET_NO;
1722 msg = ps->pending_msgs_tail;
1723
1724#if DEBUG_CURL
1725 curl_easy_setopt(ps->send_endpoint, CURLOPT_VERBOSE, 1L);
1726#endif
1727 curl_easy_setopt(ps->send_endpoint, CURLOPT_URL, ps->url);
1728 curl_easy_setopt(ps->send_endpoint, CURLOPT_PUT, 1L);
1729 curl_easy_setopt(ps->send_endpoint, CURLOPT_HEADERFUNCTION, &curl_put_header_cb);
1730 curl_easy_setopt(ps->send_endpoint, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
1731 curl_easy_setopt(ps->send_endpoint, CURLOPT_SSL_VERIFYPEER, 0);
1732 curl_easy_setopt(ps->send_endpoint, CURLOPT_SSL_VERIFYHOST, 0);
1733
1734 curl_easy_setopt(ps->send_endpoint, CURLOPT_WRITEHEADER, ps);
1735 curl_easy_setopt(ps->send_endpoint, CURLOPT_READFUNCTION, curl_send_cb);
1736 curl_easy_setopt(ps->send_endpoint, CURLOPT_READDATA, ps);
1737 curl_easy_setopt(ps->send_endpoint, CURLOPT_WRITEFUNCTION, curl_receive_cb);
1738 curl_easy_setopt(ps->send_endpoint, CURLOPT_READDATA, ps);
1739 curl_easy_setopt(ps->send_endpoint, CURLOPT_TIMEOUT, (long) timeout.value);
1740 curl_easy_setopt(ps->send_endpoint, CURLOPT_PRIVATE, ps);
1741 curl_easy_setopt(ps->send_endpoint, CURLOPT_CONNECTTIMEOUT, HTTP_CONNECT_TIMEOUT);
1742 curl_easy_setopt(ps->send_endpoint, CURLOPT_BUFFERSIZE, GNUNET_SERVER_MAX_MESSAGE_SIZE);
1743
1744 if (fresh==GNUNET_YES)
1745 {
1746 mret = curl_multi_add_handle(plugin->multi_handle, ps->send_endpoint);
1747 if (mret != CURLM_OK)
1748 {
1749 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1750 _("Connection: %X: %s failed at %s:%d: `%s'\n"),
1751 ps,
1752 "curl_multi_add_handle", __FILE__, __LINE__,
1753 curl_multi_strerror (mret));
1754 return GNUNET_SYSERR;
1755 }
1756 }
1757 }
1758 if (curl_schedule (plugin) == GNUNET_SYSERR)
1759 return GNUNET_SYSERR;
1760 return GNUNET_YES;
1761 }
1762 if (ps->direction == INBOUND)
1763 {
1764 GNUNET_assert (NULL != ps->pending_msgs_tail);
1765 if ((ps->recv_connected==GNUNET_YES) && (ps->send_connected==GNUNET_YES) &&
1766 (ps->recv_force_disconnect==GNUNET_NO) && (ps->recv_force_disconnect==GNUNET_NO))
1767 return GNUNET_YES;
1768 }
1769 return GNUNET_SYSERR;
1770}
1771
1772static struct Session * send_select_session (void * cls, struct HTTP_PeerContext *pc, const void * addr, size_t addrlen, int force_address, struct Session * session)
1773{
1774 struct Session * tmp = NULL;
1775 int addr_given = GNUNET_NO;
1776
1777 if ((addr!=NULL) && (addrlen>0))
1778 addr_given = GNUNET_YES;
1779
1780 if (force_address == GNUNET_YES)
1781 {
1782 /* check session given as argument */
1783 if ((session != NULL) && (addr_given == GNUNET_YES))
1784 {
1785 if (0 == memcmp(session->addr, addr, addrlen))
1786 {
1787 /* connection can not be used, since it is disconnected */
1788 if ((session->recv_force_disconnect==GNUNET_NO) && (session->send_force_disconnect==GNUNET_NO))
1789 {
1790#if DEBUG_SESSION_SELECTION
1791 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Session %X selected: Using session passed by transport to send to forced address \n", session);
1792#endif
1793 return session;
1794 }
1795 }
1796 }
1797 /* check last session used */
1798 if ((pc->last_session != NULL)&& (addr_given == GNUNET_YES))
1799 {
1800 if (0 == memcmp(pc->last_session->addr, addr, addrlen))
1801 {
1802 /* connection can not be used, since it is disconnected */
1803 if ((pc->last_session->recv_force_disconnect==GNUNET_NO) && (pc->last_session->send_force_disconnect==GNUNET_NO))
1804 {
1805#if DEBUG_SESSION_SELECTION
1806 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Session %X selected: Using last session used to send to forced address \n", pc->last_session);
1807#endif
1808 return pc->last_session;
1809 }
1810 }
1811 }
1812 /* find session in existing sessions */
1813 tmp = pc->head;
1814 while ((tmp!=NULL) && (addr_given == GNUNET_YES))
1815 {
1816
1817 if (0 == memcmp(tmp->addr, addr, addrlen))
1818 {
1819 /* connection can not be used, since it is disconnected */
1820 if ((tmp->recv_force_disconnect==GNUNET_NO) && (tmp->send_force_disconnect==GNUNET_NO))
1821 {
1822#if DEBUG_SESSION_SELECTION
1823 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Session %X selected: Using existing session to send to forced address \n", session);
1824#endif
1825 return session;
1826 }
1827
1828 }
1829 tmp=tmp->next;
1830 }
1831 /* no session to use */
1832 return NULL;
1833 }
1834 if ((force_address == GNUNET_NO) || (force_address == GNUNET_SYSERR))
1835 {
1836 /* check session given as argument */
1837 if (session != NULL)
1838 {
1839 /* connection can not be used, since it is disconnected */
1840 if ((session->recv_force_disconnect==GNUNET_NO) && (session->send_force_disconnect==GNUNET_NO))
1841 {
1842#if DEBUG_SESSION_SELECTION
1843 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Session %X selected: Using session passed by transport to send not-forced address \n", session);
1844#endif
1845 return session;
1846 }
1847
1848 }
1849 /* check last session used */
1850 if (pc->last_session != NULL)
1851 {
1852 /* connection can not be used, since it is disconnected */
1853 if ((pc->last_session->recv_force_disconnect==GNUNET_NO) && (pc->last_session->send_force_disconnect==GNUNET_NO))
1854 {
1855#if DEBUG_SESSION_SELECTION
1856 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Session %X selected: Using last session to send to not-forced address \n", pc->last_session);
1857#endif
1858 return pc->last_session;
1859 }
1860 }
1861 /* find session in existing sessions */
1862 tmp = pc->head;
1863 while (tmp!=NULL)
1864 {
1865 /* connection can not be used, since it is disconnected */
1866 if ((tmp->recv_force_disconnect==GNUNET_NO) && (tmp->send_force_disconnect==GNUNET_NO))
1867 {
1868#if DEBUG_SESSION_SELECTION
1869 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Session %X selected: Using existing session to send to not-forced address \n", tmp);
1870#endif
1871 return tmp;
1872 }
1873 tmp=tmp->next;
1874 }
1875 return NULL;
1876 }
1877 return NULL;
1878}
1879
1880/**
1881 * Function that can be used by the transport service to transmit
1882 * a message using the plugin. Note that in the case of a
1883 * peer disconnecting, the continuation MUST be called
1884 * prior to the disconnect notification itself. This function
1885 * will be called with this peer's HELLO message to initiate
1886 * a fresh connection to another peer.
1887 *
1888 * @param cls closure
1889 * @param target who should receive this message
1890 * @param msgbuf the message to transmit
1891 * @param msgbuf_size number of bytes in 'msgbuf'
1892 * @param priority how important is the message (most plugins will
1893 * ignore message priority and just FIFO)
1894 * @param timeout how long to wait at most for the transmission (does not
1895 * require plugins to discard the message after the timeout,
1896 * just advisory for the desired delay; most plugins will ignore
1897 * this as well)
1898 * @param session which session must be used (or NULL for "any")
1899 * @param addr the address to use (can be NULL if the plugin
1900 * is "on its own" (i.e. re-use existing TCP connection))
1901 * @param addrlen length of the address in bytes
1902 * @param force_address GNUNET_YES if the plugin MUST use the given address,
1903 * GNUNET_NO means the plugin may use any other address and
1904 * GNUNET_SYSERR means that only reliable existing
1905 * bi-directional connections should be used (regardless
1906 * of address)
1907 * @param cont continuation to call once the message has
1908 * been transmitted (or if the transport is ready
1909 * for the next transmission call; or if the
1910 * peer disconnected...); can be NULL
1911 * @param cont_cls closure for cont
1912 * @return number of bytes used (on the physical network, with overheads);
1913 * -1 on hard errors (i.e. address invalid); 0 is a legal value
1914 * and does NOT mean that the message was not transmitted (DV)
1915 */
1916static ssize_t
1917http_plugin_send (void *cls,
1918 const struct GNUNET_PeerIdentity *target,
1919 const char *msgbuf,
1920 size_t msgbuf_size,
1921 unsigned int priority,
1922 struct GNUNET_TIME_Relative to,
1923 struct Session *session,
1924 const void *addr,
1925 size_t addrlen,
1926 int force_address,
1927 GNUNET_TRANSPORT_TransmitContinuation cont,
1928 void *cont_cls)
1929{
1930 struct Plugin *plugin = cls;
1931 struct HTTP_Message *msg;
1932 struct HTTP_PeerContext * pc;
1933 struct Session * ps = NULL;
1934
1935 GNUNET_assert(cls !=NULL);
1936
1937#if DEBUG_HTTP
1938 char * force = GNUNET_malloc(40);
1939 if (force_address == GNUNET_YES)
1940 strcpy(force,"forced addr.");
1941 if (force_address == GNUNET_NO)
1942 strcpy(force,"any addr.");
1943 if (force_address == GNUNET_SYSERR)
1944 strcpy(force,"reliable bi-direc. address addr.");
1945
1946 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Transport tells me to send %u bytes to `%s' using %s (%s) and session: %X\n",
1947 msgbuf_size,
1948 GNUNET_i2s(target),
1949 force,
1950 http_plugin_address_to_string(NULL, addr, addrlen),
1951 session);
1952
1953 GNUNET_free(force);
1954#endif
1955
1956 pc = GNUNET_CONTAINER_multihashmap_get (plugin->peers, &target->hashPubKey);
1957 /* Peer unknown */
1958 if (pc==NULL)
1959 {
1960 pc = GNUNET_malloc(sizeof (struct HTTP_PeerContext));
1961 pc->plugin = plugin;
1962 pc->session_id_counter=1;
1963 pc->last_session = NULL;
1964 memcpy(&pc->identity, target, sizeof(struct GNUNET_PeerIdentity));
1965 GNUNET_CONTAINER_multihashmap_put(plugin->peers, &pc->identity.hashPubKey, pc, GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
1966 GNUNET_STATISTICS_update (plugin->env->stats,
1967 gettext_noop ("# HTTP peers active"),
1968 1,
1969 GNUNET_NO);
1970 }
1971
1972 ps = send_select_session (plugin, pc, addr, addrlen, force_address, session);
1973
1974 /* session not existing, but address forced -> creating new session */
1975 if (ps==NULL)
1976 {
1977 if ((addr!=NULL) && (addrlen!=0))
1978 {
1979 ps = GNUNET_malloc(sizeof (struct Session));
1980#if DEBUG_SESSION_SELECTION
1981 if (force_address == GNUNET_YES)
1982 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"No existing connection & forced address: creating new session %X to peer %s\n", ps, GNUNET_i2s(target));
1983 if (force_address != GNUNET_YES)
1984 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"No existing connection: creating new session %X to peer %s\n", ps, GNUNET_i2s(target));
1985#endif
1986 if ((addrlen!=0) && (addr!=NULL))
1987 {
1988 ps->addr = GNUNET_malloc(addrlen);
1989 memcpy(ps->addr,addr,addrlen);
1990 ps->addrlen = addrlen;
1991 }
1992 else
1993 {
1994 ps->addr = NULL;
1995 ps->addrlen = 0;
1996 }
1997 ps->direction=OUTBOUND;
1998 ps->recv_connected = GNUNET_NO;
1999 ps->recv_force_disconnect = GNUNET_NO;
2000 ps->send_connected = GNUNET_NO;
2001 ps->send_force_disconnect = GNUNET_NO;
2002 ps->pending_msgs_head = NULL;
2003 ps->pending_msgs_tail = NULL;
2004 ps->peercontext=pc;
2005 ps->session_id = pc->session_id_counter;
2006 pc->session_id_counter++;
2007 ps->url = create_url (plugin, ps->addr, ps->addrlen, ps->session_id);
2008 if (ps->msgtok == NULL)
2009 ps->msgtok = GNUNET_SERVER_mst_create (&curl_receive_mst_cb, ps);
2010 GNUNET_CONTAINER_DLL_insert(pc->head,pc->tail,ps);
2011/* FIXME */
2012
2013 GNUNET_STATISTICS_update (plugin->env->stats,
2014 gettext_noop ("# HTTP outbound sessions for peers active"),
2015 1,
2016 GNUNET_NO);
2017 }
2018 else
2019 {
2020#if DEBUG_HTTP
2021 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"No existing session found & and no address given: no way to send this message to peer `%s'!\n", GNUNET_i2s(target));
2022#endif
2023 return GNUNET_SYSERR;
2024 }
2025 }
2026
2027 /* create msg */
2028 msg = GNUNET_malloc (sizeof (struct HTTP_Message) + msgbuf_size);
2029 msg->next = NULL;
2030 msg->size = msgbuf_size;
2031 msg->pos = 0;
2032 msg->buf = (char *) &msg[1];
2033 msg->transmit_cont = cont;
2034 msg->transmit_cont_cls = cont_cls;
2035 memcpy (msg->buf,msgbuf, msgbuf_size);
2036 GNUNET_CONTAINER_DLL_insert(ps->pending_msgs_head,ps->pending_msgs_tail,msg);
2037
2038 if (send_check_connections (plugin, ps) != GNUNET_SYSERR)
2039 {
2040 if (force_address != GNUNET_YES)
2041 pc->last_session = ps;
2042
2043 if (pc->last_session==NULL)
2044 pc->last_session = ps;
2045 return msg->size;
2046 }
2047 else
2048 return GNUNET_SYSERR;
2049}
2050
2051
2052
2053/**
2054 * Function that can be used to force the plugin to disconnect
2055 * from the given peer and cancel all previous transmissions
2056 * (and their continuationc).
2057 *
2058 * @param cls closure
2059 * @param target peer from which to disconnect
2060 */
2061static void
2062http_plugin_disconnect (void *cls,
2063 const struct GNUNET_PeerIdentity *target)
2064{
2065
2066
2067 struct Plugin *plugin = cls;
2068 struct HTTP_PeerContext *pc = NULL;
2069 struct Session *ps = NULL;
2070 //struct Session *tmp = NULL;
2071
2072 pc = GNUNET_CONTAINER_multihashmap_get (plugin->peers, &target->hashPubKey);
2073 if (pc==NULL)
2074 return;
2075 ps = pc->head;
2076
2077 while (ps!=NULL)
2078 {
2079 /* Telling transport that session is getting disconnected */
2080 plugin->env->session_end(plugin, target, ps);
2081 if (ps->direction==OUTBOUND)
2082 {
2083 if (ps->send_endpoint!=NULL)
2084 {
2085 //GNUNET_assert(CURLM_OK == curl_multi_remove_handle(plugin->multi_handle,ps->send_endpoint));
2086 //curl_easy_cleanup(ps->send_endpoint);
2087 //ps->send_endpoint=NULL;
2088 ps->send_force_disconnect = GNUNET_YES;
2089 }
2090 if (ps->recv_endpoint!=NULL)
2091 {
2092 //GNUNET_assert(CURLM_OK == curl_multi_remove_handle(plugin->multi_handle,ps->recv_endpoint));
2093 //curl_easy_cleanup(ps->recv_endpoint);
2094 //ps->recv_endpoint=NULL;
2095 ps->recv_force_disconnect = GNUNET_YES;
2096 }
2097 }
2098
2099 if (ps->direction==INBOUND)
2100 {
2101 ps->recv_force_disconnect = GNUNET_YES;
2102 ps->send_force_disconnect = GNUNET_YES;
2103 }
2104
2105 while (ps->pending_msgs_head!=NULL)
2106 {
2107 remove_http_message(ps, ps->pending_msgs_head);
2108 }
2109 ps->recv_active = GNUNET_NO;
2110 ps->send_active = GNUNET_NO;
2111 ps=ps->next;
2112 }
2113}
2114
2115
2116/**
2117 * Convert the transports address to a nice, human-readable
2118 * format.
2119 *
2120 * @param cls closure
2121 * @param type name of the transport that generated the address
2122 * @param addr one of the addresses of the host, NULL for the last address
2123 * the specific address format depends on the transport
2124 * @param addrlen length of the address
2125 * @param numeric should (IP) addresses be displayed in numeric form?
2126 * @param timeout after how long should we give up?
2127 * @param asc function to call on each string
2128 * @param asc_cls closure for asc
2129 */
2130static void
2131http_plugin_address_pretty_printer (void *cls,
2132 const char *type,
2133 const void *addr,
2134 size_t addrlen,
2135 int numeric,
2136 struct GNUNET_TIME_Relative timeout,
2137 GNUNET_TRANSPORT_AddressStringCallback
2138 asc, void *asc_cls)
2139{
2140 const struct IPv4HttpAddress *t4;
2141 const struct IPv6HttpAddress *t6;
2142 struct sockaddr_in a4;
2143 struct sockaddr_in6 a6;
2144 char * address;
2145 char * ret;
2146 unsigned int port;
2147 unsigned int res;
2148
2149 GNUNET_assert(cls !=NULL);
2150 if (addrlen == sizeof (struct IPv6HttpAddress))
2151 {
2152 address = GNUNET_malloc (INET6_ADDRSTRLEN);
2153 t6 = addr;
2154 a6.sin6_addr = t6->ipv6_addr;
2155 inet_ntop(AF_INET6, &(a6.sin6_addr),address,INET6_ADDRSTRLEN);
2156 port = ntohs(t6->u6_port);
2157 }
2158 else if (addrlen == sizeof (struct IPv4HttpAddress))
2159 {
2160 address = GNUNET_malloc (INET_ADDRSTRLEN);
2161 t4 = addr;
2162 a4.sin_addr.s_addr = t4->ipv4_addr;
2163 inet_ntop(AF_INET, &(a4.sin_addr),address,INET_ADDRSTRLEN);
2164 port = ntohs(t4->u_port);
2165 }
2166 else
2167 {
2168 /* invalid address */
2169 GNUNET_break_op (0);
2170 asc (asc_cls, NULL);
2171 return;
2172 }
2173 res = GNUNET_asprintf(&ret,"http://%s:%u/",address,port);
2174 GNUNET_free (address);
2175 GNUNET_assert(res != 0);
2176 asc (asc_cls, ret);
2177 GNUNET_free_non_null (ret);
2178}
2179
2180
2181
2182/**
2183 * Another peer has suggested an address for this
2184 * peer and transport plugin. Check that this could be a valid
2185 * address. If so, consider adding it to the list
2186 * of addresses.
2187 *
2188 * @param cls closure
2189 * @param addr pointer to the address
2190 * @param addrlen length of addr
2191 * @return GNUNET_OK if this is a plausible address for this peer
2192 * and transport
2193 */
2194static int
2195http_plugin_address_suggested (void *cls,
2196 const void *addr, size_t addrlen)
2197{
2198 struct Plugin *plugin = cls;
2199 struct IPv4HttpAddress *v4;
2200 struct IPv6HttpAddress *v6;
2201 unsigned int port;
2202
2203 GNUNET_assert(cls !=NULL);
2204 if ((addrlen != sizeof (struct IPv4HttpAddress)) &&
2205 (addrlen != sizeof (struct IPv6HttpAddress)))
2206 {
2207 return GNUNET_SYSERR;
2208 }
2209 if (addrlen == sizeof (struct IPv4HttpAddress))
2210 {
2211 v4 = (struct IPv4HttpAddress *) addr;
2212 /* Not skipping loopback
2213 if (INADDR_LOOPBACK == ntohl(v4->ipv4_addr))
2214 {
2215 return GNUNET_SYSERR;
2216 } */
2217 port = ntohs (v4->u_port);
2218 if (port != plugin->port_inbound)
2219 {
2220 return GNUNET_SYSERR;
2221 }
2222 }
2223 if (addrlen == sizeof (struct IPv6HttpAddress))
2224 {
2225 v6 = (struct IPv6HttpAddress *) addr;
2226 if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr))
2227 {
2228 return GNUNET_SYSERR;
2229 }
2230 port = ntohs (v6->u6_port);
2231 if (port != plugin->port_inbound)
2232 {
2233 return GNUNET_SYSERR;
2234 }
2235 }
2236
2237 return GNUNET_OK;
2238}
2239
2240
2241/**
2242 * Function called for a quick conversion of the binary address to
2243 * a numeric address. Note that the caller must not free the
2244 * address and that the next call to this function is allowed
2245 * to override the address again.
2246 *
2247 * @param cls closure
2248 * @param addr binary address
2249 * @param addrlen length of the address
2250 * @return string representing the same address
2251 */
2252static const char*
2253http_plugin_address_to_string (void *cls,
2254 const void *addr,
2255 size_t addrlen)
2256{
2257 const struct IPv4HttpAddress *t4;
2258 const struct IPv6HttpAddress *t6;
2259 struct sockaddr_in a4;
2260 struct sockaddr_in6 a6;
2261 char * address;
2262 char * ret;
2263 uint16_t port;
2264 unsigned int res;
2265
2266 if (addrlen == sizeof (struct IPv6HttpAddress))
2267 {
2268 address = GNUNET_malloc (INET6_ADDRSTRLEN);
2269 t6 = addr;
2270 a6.sin6_addr = t6->ipv6_addr;
2271 inet_ntop(AF_INET6, &(a6.sin6_addr),address,INET6_ADDRSTRLEN);
2272 port = ntohs(t6->u6_port);
2273 }
2274 else if (addrlen == sizeof (struct IPv4HttpAddress))
2275 {
2276 address = GNUNET_malloc (INET_ADDRSTRLEN);
2277 t4 = addr;
2278 a4.sin_addr.s_addr = t4->ipv4_addr;
2279 inet_ntop(AF_INET, &(a4.sin_addr),address,INET_ADDRSTRLEN);
2280 port = ntohs(t4->u_port);
2281 }
2282 else
2283 {
2284 /* invalid address */
2285 return NULL;
2286 }
2287 res = GNUNET_asprintf(&ret,"%s:%u",address,port);
2288 GNUNET_free (address);
2289 GNUNET_assert(res != 0);
2290 return ret;
2291}
2292
2293
2294/**
2295 * Exit point from the plugin.
2296 */
2297void *
2298libgnunet_plugin_transport_https_done (void *cls)
2299{
2300 struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
2301 struct Plugin *plugin = api->cls;
2302 CURLMcode mret;
2303 GNUNET_assert(cls !=NULL);
2304
2305 if (plugin->http_server_daemon_v4 != NULL)
2306 {
2307 MHD_stop_daemon (plugin->http_server_daemon_v4);
2308 plugin->http_server_daemon_v4 = NULL;
2309 }
2310 if (plugin->http_server_daemon_v6 != NULL)
2311 {
2312 MHD_stop_daemon (plugin->http_server_daemon_v6);
2313 plugin->http_server_daemon_v6 = NULL;
2314 }
2315
2316 if ( plugin->http_server_task_v4 != GNUNET_SCHEDULER_NO_TASK)
2317 {
2318 GNUNET_SCHEDULER_cancel(plugin->env->sched, plugin->http_server_task_v4);
2319 plugin->http_server_task_v4 = GNUNET_SCHEDULER_NO_TASK;
2320 }
2321
2322 if ( plugin->http_server_task_v6 != GNUNET_SCHEDULER_NO_TASK)
2323 {
2324 GNUNET_SCHEDULER_cancel(plugin->env->sched, plugin->http_server_task_v6);
2325 plugin->http_server_task_v6 = GNUNET_SCHEDULER_NO_TASK;
2326 }
2327
2328
2329 /* free all peer information */
2330 if (plugin->peers!=NULL)
2331 {
2332 GNUNET_CONTAINER_multihashmap_iterate (plugin->peers,
2333 &remove_peer_context_Iterator,
2334 plugin);
2335 GNUNET_CONTAINER_multihashmap_destroy (plugin->peers);
2336 }
2337 if (plugin->multi_handle!=NULL)
2338 {
2339 mret = curl_multi_cleanup(plugin->multi_handle);
2340#if DEBUG_HTTP
2341 if ( CURLM_OK != mret)
2342 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"curl multihandle clean up failed\n");
2343#endif
2344 plugin->multi_handle = NULL;
2345 }
2346 curl_global_cleanup();
2347
2348 if ( plugin->http_curl_task != GNUNET_SCHEDULER_NO_TASK)
2349 {
2350 GNUNET_SCHEDULER_cancel(plugin->env->sched, plugin->http_curl_task);
2351 plugin->http_curl_task = GNUNET_SCHEDULER_NO_TASK;
2352 }
2353
2354 GNUNET_free_non_null (plugin->bind4_address);
2355 GNUNET_free_non_null (plugin->bind6_address);
2356 GNUNET_free_non_null(plugin->bind_hostname);
2357 GNUNET_free (plugin);
2358 GNUNET_free (api);
2359#if DEBUG_HTTP
2360 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Unload http plugin complete...\n");
2361#endif
2362 return NULL;
2363}
2364
2365
2366/**
2367 * Entry point for the plugin.
2368 */
2369void *
2370libgnunet_plugin_transport_https_init (void *cls)
2371{
2372 struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
2373 struct Plugin *plugin;
2374 struct GNUNET_TRANSPORT_PluginFunctions *api;
2375 struct GNUNET_TIME_Relative gn_timeout;
2376 long long unsigned int port;
2377
2378 GNUNET_assert(cls !=NULL);
2379#if DEBUG_HTTP
2380 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Starting https plugin...\n");
2381#endif
2382
2383 plugin = GNUNET_malloc (sizeof (struct Plugin));
2384 plugin->stats = env->stats;
2385 plugin->env = env;
2386 plugin->peers = NULL;
2387 plugin->bind4_address = NULL;
2388 plugin->use_ipv6 = GNUNET_YES;
2389 plugin->use_ipv4 = GNUNET_YES;
2390
2391 api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
2392 api->cls = plugin;
2393 api->send = &http_plugin_send;
2394 api->disconnect = &http_plugin_disconnect;
2395 api->address_pretty_printer = &http_plugin_address_pretty_printer;
2396 api->check_address = &http_plugin_address_suggested;
2397 api->address_to_string = &http_plugin_address_to_string;
2398
2399 /* Hashing our identity to use it in URLs */
2400 GNUNET_CRYPTO_hash_to_enc ( &(plugin->env->my_identity->hashPubKey), &plugin->my_ascii_hash_ident);
2401
2402 /* Reading port number from config file */
2403 if (GNUNET_CONFIGURATION_have_value (env->cfg,
2404 "transport-https", "USE_IPv6"))
2405 {
2406 plugin->use_ipv6 = GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
2407 "transport-https",
2408 "USE_IPv6");
2409 }
2410 /* Reading port number from config file */
2411 if (GNUNET_CONFIGURATION_have_value (env->cfg,
2412 "transport-https", "USE_IPv4"))
2413 {
2414 plugin->use_ipv4 = GNUNET_CONFIGURATION_get_value_yesno (env->cfg,
2415 "transport-https",
2416 "USE_IPv4");
2417 }
2418 /* Reading port number from config file */
2419 if ((GNUNET_OK !=
2420 GNUNET_CONFIGURATION_get_value_number (env->cfg,
2421 "transport-https",
2422 "PORT",
2423 &port)) ||
2424 (port > 65535) )
2425 {
2426 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
2427 "http",
2428 _("Require valid port number for transport plugin `%s' in configuration!\n"),
2429 "transport-https");
2430 libgnunet_plugin_transport_https_done (api);
2431 return NULL;
2432 }
2433
2434 /* Reading ipv4 addresse to bind to from config file */
2435 if ((plugin->use_ipv4==GNUNET_YES) && (GNUNET_CONFIGURATION_have_value (env->cfg,
2436 "transport-https", "BINDTO4")))
2437 {
2438 GNUNET_break (GNUNET_OK ==
2439 GNUNET_CONFIGURATION_get_value_string (env->cfg,
2440 "transport-https",
2441 "BINDTO4",
2442 &plugin->bind_hostname));
2443 plugin->bind4_address = GNUNET_malloc(sizeof(struct sockaddr_in));
2444 plugin->bind4_address->sin_family = AF_INET;
2445 plugin->bind4_address->sin_port = htons (port);
2446
2447 if (inet_pton(AF_INET,plugin->bind_hostname, &plugin->bind4_address->sin_addr)<=0)
2448 {
2449 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
2450 "http",
2451 _("Misconfigured address to bind to in configuration!\n"),
2452 "transport-https");
2453 GNUNET_free(plugin->bind4_address);
2454 GNUNET_free(plugin->bind_hostname);
2455 plugin->bind_hostname = NULL;
2456 plugin->bind4_address = NULL;
2457 }
2458 }
2459
2460 /* Reading ipv4 addresse to bind to from config file */
2461 if ((plugin->use_ipv6==GNUNET_YES) && (GNUNET_CONFIGURATION_have_value (env->cfg,
2462 "transport-https", "BINDTO6")))
2463 {
2464 GNUNET_break (GNUNET_OK ==
2465 GNUNET_CONFIGURATION_get_value_string (env->cfg,
2466 "transport-https",
2467 "BINDTO6",
2468 &plugin->bind_hostname));
2469
2470 plugin->bind6_address = GNUNET_malloc(sizeof(struct sockaddr_in6));
2471 plugin->bind6_address->sin6_family = AF_INET6;
2472 plugin->bind6_address->sin6_port = htons (port);
2473
2474 if (inet_pton(AF_INET6,plugin->bind_hostname, &plugin->bind6_address->sin6_addr)<=0)
2475 {
2476 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
2477 "http",
2478 _("Misconfigured address to bind to in configuration!\n"),
2479 "transport-https");
2480 GNUNET_free(plugin->bind6_address);
2481 GNUNET_free(plugin->bind_hostname);
2482 plugin->bind_hostname = NULL;
2483 plugin->bind6_address = NULL;
2484 }
2485 }
2486
2487 GNUNET_assert ((port > 0) && (port <= 65535));
2488 plugin->port_inbound = port;
2489 gn_timeout = GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT;
2490 unsigned int timeout = (gn_timeout.value) / 1000;
2491 if ((plugin->http_server_daemon_v6 == NULL) && (plugin->use_ipv6 == GNUNET_YES) && (port != 0))
2492 {
2493 struct sockaddr * tmp = (struct sockaddr *) plugin->bind6_address;
2494 plugin->http_server_daemon_v6 = MHD_start_daemon (
2495#if DEBUG_CONNECTIONS
2496 MHD_USE_DEBUG |
2497#endif
2498 MHD_USE_IPv6 | MHD_USE_SSL,
2499 port,
2500 &mhd_accept_cb,
2501 plugin , &mdh_access_cb, plugin,
2502 MHD_OPTION_HTTPS_MEM_KEY, key_pem,
2503 MHD_OPTION_HTTPS_MEM_CERT, cert_pem,
2504 MHD_OPTION_SOCK_ADDR, tmp,
2505 MHD_OPTION_CONNECTION_LIMIT, (unsigned int) 32,
2506 //MHD_OPTION_PER_IP_CONNECTION_LIMIT, (unsigned int) 6,
2507 MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) timeout,
2508 MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (16 * 1024),
2509 MHD_OPTION_NOTIFY_COMPLETED, &mhd_termination_cb, NULL,
2510 MHD_OPTION_END);
2511 }
2512 if ((plugin->http_server_daemon_v4 == NULL) && (plugin->use_ipv4 == GNUNET_YES) && (port != 0))
2513 {
2514 plugin->http_server_daemon_v4 = MHD_start_daemon (
2515#if DEBUG_CONNECTIONS
2516 MHD_USE_DEBUG |
2517#endif
2518 MHD_NO_FLAG | MHD_USE_SSL,
2519 port,
2520 &mhd_accept_cb,
2521 plugin , &mdh_access_cb, plugin,
2522 MHD_OPTION_HTTPS_MEM_KEY, key_pem,
2523 MHD_OPTION_HTTPS_MEM_CERT, cert_pem,
2524 MHD_OPTION_SOCK_ADDR, (struct sockaddr_in *)plugin->bind4_address,
2525 MHD_OPTION_CONNECTION_LIMIT, (unsigned int) 32,
2526 //MHD_OPTION_PER_IP_CONNECTION_LIMIT, (unsigned int) 6,
2527 MHD_OPTION_CONNECTION_TIMEOUT, (unsigned int) timeout,
2528 MHD_OPTION_CONNECTION_MEMORY_LIMIT, (size_t) (16 * 1024),
2529 MHD_OPTION_NOTIFY_COMPLETED, &mhd_termination_cb, NULL,
2530 MHD_OPTION_END);
2531 }
2532 if (plugin->http_server_daemon_v4 != NULL)
2533 plugin->http_server_task_v4 = http_server_daemon_prepare (plugin, plugin->http_server_daemon_v4);
2534 if (plugin->http_server_daemon_v6 != NULL)
2535 plugin->http_server_task_v6 = http_server_daemon_prepare (plugin, plugin->http_server_daemon_v6);
2536
2537
2538 if (plugin->http_server_task_v4 != GNUNET_SCHEDULER_NO_TASK)
2539 {
2540#if DEBUG_HTTP
2541 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Starting MHD with IPv4 bound to %s with port %u\n",(plugin->bind_hostname!=NULL) ? plugin->bind_hostname : "every address",port);
2542#endif
2543 }
2544 else if ((plugin->http_server_task_v6 != GNUNET_SCHEDULER_NO_TASK) && (plugin->http_server_task_v4 != GNUNET_SCHEDULER_NO_TASK))
2545 {
2546#if DEBUG_HTTP
2547 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Starting MHD with IPv6 bound to %s with port %u\n",(plugin->bind_hostname!=NULL) ? plugin->bind_hostname : "every address", port);
2548#endif
2549 }
2550 else if ((plugin->http_server_task_v6 != GNUNET_SCHEDULER_NO_TASK) && (plugin->http_server_task_v4 == GNUNET_SCHEDULER_NO_TASK))
2551 {
2552#if DEBUG_HTTP
2553 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Starting MHD with IPv4 and IPv6 bound to %s with port %u\n",(plugin->bind_hostname!=NULL) ? plugin->bind_hostname : "every address", port);
2554#endif
2555 }
2556 else
2557 {
2558#if DEBUG_HTTP
2559 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"No MHD was started, transport plugin not functional!\n");
2560#endif
2561 libgnunet_plugin_transport_https_done (api);
2562 return NULL;
2563 }
2564
2565 /* Initializing cURL */
2566 curl_global_init(CURL_GLOBAL_ALL);
2567 plugin->multi_handle = curl_multi_init();
2568
2569 if ( NULL == plugin->multi_handle )
2570 {
2571 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
2572 "http",
2573 _("Could not initialize curl multi handle, failed to start http plugin!\n"),
2574 "transport-https");
2575 libgnunet_plugin_transport_https_done (api);
2576 return NULL;
2577 }
2578
2579 plugin->peers = GNUNET_CONTAINER_multihashmap_create (10);
2580 GNUNET_OS_network_interfaces_list (&process_interfaces, plugin);
2581
2582 return api;
2583}
2584
2585/* end of plugin_transport_http.c */
diff --git a/src/transport/test_plugin_transport_data_http.conf b/src/transport/test_plugin_transport_data_http.conf
index 9418ac751..476229622 100644
--- a/src/transport/test_plugin_transport_data_http.conf
+++ b/src/transport/test_plugin_transport_data_http.conf
@@ -7,13 +7,21 @@ WEAKRANDOM = YES
7 7
8[transport-http] 8[transport-http]
9PORT = 12389 9PORT = 12389
10DEBUG = NO 10DEBUG = YES
11#USE_IPv4 = NO 11#USE_IPv4 = NO
12#USE_IPv6 = NO 12#USE_IPv6 = NO
13USE_IPv6 = YES 13USE_IPv6 = YES
14#BINDTO4 = 127.0.0.1 14#BINDTO4 = 127.0.0.1
15#BINDTO6 = ::1 15#BINDTO6 = ::1
16 16
17[transport-https]
18PORT = 12389
19DEBUG = NO
20#USE_IPv4 = NO
21#USE_IPv6 = NO
22USE_IPv6 = YES
23#BINDTO4 = 127.0.0.1
24#BINDTO6 = ::1
17 25
18[transport] 26[transport]
19PREFIX = valgrind --leak-check=full 27PREFIX = valgrind --leak-check=full
diff --git a/src/transport/test_plugin_transport_https.c b/src/transport/test_plugin_transport_https.c
new file mode 100644
index 000000000..7c9229111
--- /dev/null
+++ b/src/transport/test_plugin_transport_https.c
@@ -0,0 +1,1354 @@
1/*
2 This file is part of GNUnet.
3 (C) 2010 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 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 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20/**
21 * @file transport/test_plugin_transport_https.c
22 * @brief testcase for plugin_transport_https.c
23 * @author Matthias Wachs
24 */
25
26#include "platform.h"
27#include "gnunet_constants.h"
28#include "gnunet_common.h"
29#include "gnunet_getopt_lib.h"
30#include "gnunet_hello_lib.h"
31#include "gnunet_os_lib.h"
32#include "gnunet_peerinfo_service.h"
33#include "gnunet_plugin_lib.h"
34#include "gnunet_protocols.h"
35#include "gnunet_program_lib.h"
36#include "gnunet_signatures.h"
37#include "gnunet_service_lib.h"
38#include "gnunet_crypto_lib.h"
39
40#include "plugin_transport.h"
41#include "gnunet_statistics_service.h"
42#include "transport.h"
43#include <curl/curl.h>
44#include <netinet/in.h>
45#include <arpa/inet.h>
46
47#define VERBOSE GNUNET_YES
48#define DEBUG GNUNET_YES
49#define DEBUG_CURL GNUNET_YES
50#define HTTP_BUFFER_SIZE 2048
51
52#define PLUGIN libgnunet_plugin_transport_template
53
54/**
55 * How long until we give up on transmitting the message?
56 */
57#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 90)
58
59/**
60 * Testcase timeout
61 */
62#define TEST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20)
63
64/**
65 * How long between recieve and send?
66 */
67#define WAIT_INTERVALL GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
68
69
70
71/**
72 * Struct for plugin addresses
73 */
74struct Plugin_Address
75{
76 /**
77 * Next field for linked list
78 */
79 struct Plugin_Address * next;
80
81 /**
82 * buffer containing data to send
83 */
84 void * addr;
85
86 /**
87 * amount of data to sent
88 */
89 size_t addrlen;
90};
91
92/**
93 * Message to send using http
94 */
95struct HTTP_Message
96{
97 /**
98 * buffer
99 */
100 unsigned char buf[HTTP_BUFFER_SIZE];
101
102 /**
103 * current position in buffer
104 */
105 size_t pos;
106
107 /**
108 * buffer size
109 */
110 size_t size;
111
112 /**
113 * data size
114 */
115 size_t len;
116};
117
118
119/**
120 * Struct for plugin addresses
121 */
122struct HTTP_Transfer
123{
124 /**
125 * amount of bytes we recieved
126 */
127 size_t data_size;
128
129 /**
130 * buffer for http transfers
131 */
132 unsigned char buf[HTTP_BUFFER_SIZE];
133
134 /**
135 * buffer size this transfer
136 */
137 size_t size;
138
139 /**
140 * amount of bytes we recieved
141 */
142 size_t pos;
143
144 /**
145 * HTTP Header result for transfer
146 */
147 unsigned int http_result_code;
148
149 /**
150 * did the test fail?
151 */
152 unsigned int test_failed;
153
154 /**
155 * was this test already executed?
156 */
157 unsigned int test_executed;
158};
159
160
161/**
162 * Network format for IPv4 addresses.
163 */
164struct IPv4HttpAddress
165{
166 /**
167 * IPv4 address, in network byte order.
168 */
169 uint32_t ipv4_addr GNUNET_PACKED;
170
171 /**
172 * Port number, in network byte order.
173 */
174 uint16_t u_port GNUNET_PACKED;
175
176};
177
178
179/**
180 * Network format for IPv6 addresses.
181 */
182struct IPv6HttpAddress
183{
184 /**
185 * IPv6 address.
186 */
187 struct in6_addr ipv6_addr GNUNET_PACKED;
188
189 /**
190 * Port number, in network byte order.
191 */
192 uint16_t u6_port GNUNET_PACKED;
193
194};
195
196/**
197 * Our public key.
198 */
199/* static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key; */
200
201/**
202 * Our public key.
203 */
204static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
205
206/**
207 * Our identity.
208 */
209static struct GNUNET_PeerIdentity my_identity;
210
211/**
212 * Our private key.
213 */
214static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
215
216/**
217 * Peer's port
218 */
219static long long unsigned int port;
220
221/**
222 * Peer's addr
223 */
224static char * test_addr;
225
226/**
227 * Our scheduler.
228 */
229struct GNUNET_SCHEDULER_Handle *sched;
230
231/**
232 * Our statistics handle.
233 */
234struct GNUNET_STATISTICS_Handle *stats;
235
236
237/**
238 * Our configuration.
239 */
240const struct GNUNET_CONFIGURATION_Handle *cfg;
241
242/**
243 * Number of neighbours we'd like to have.
244 */
245static uint32_t max_connect_per_transport;
246
247/**
248 * Environment for this plugin.
249 */
250static struct GNUNET_TRANSPORT_PluginEnvironment env;
251
252/**
253 *handle for the api provided by this plugin
254 */
255static struct GNUNET_TRANSPORT_PluginFunctions *api;
256
257/**
258 * ID of the task controlling the testcase timeout
259 */
260static GNUNET_SCHEDULER_TaskIdentifier ti_timeout;
261
262static GNUNET_SCHEDULER_TaskIdentifier ti_send;
263
264//const struct GNUNET_PeerIdentity * p;
265
266/**
267 * buffer for data to send
268 */
269static struct HTTP_Message buffer_out;
270
271/**
272 * buffer for data to recieve
273 */
274static struct HTTP_Message buffer_in;
275
276
277struct Plugin_Address * addr_head;
278
279/**
280 * Did the test pass or fail?
281 */
282static int fail_notify_address;
283/**
284 * Did the test pass or fail?
285 */
286static int fail_notify_address_count;
287
288/**
289 * Did the test pass or fail?
290 */
291static int fail_pretty_printer;
292
293/**
294 * Did the test pass or fail?
295 */
296static int fail_pretty_printer_count;
297
298/**
299 * Did the test pass or fail?
300 */
301static int fail_addr_to_str;
302
303/**
304 * No. of msgs transmitted successfully to local addresses
305 */
306static int fail_msgs_transmited_to_local_addrs;
307
308/**
309 * Test: transmit msg of max. size
310 */
311static int fail_msg_transmited_bigger_max_size;
312
313/**
314 * Test: transmit msg of max. size
315 */
316static int fail_msg_transmited_max_size;
317
318/**
319 * Test: transmit 2 msgs. in in send operation
320 */
321static int fail_multiple_msgs_in_transmission;
322
323/**
324 * Test: connect to peer without peer identification
325 */
326static struct HTTP_Transfer test_no_ident;
327
328/**
329 * Test: connect to peer without peer identification
330 */
331static struct HTTP_Transfer test_too_short_ident;
332
333/**
334 * Test: connect to peer without peer identification
335 */
336static struct HTTP_Transfer test_too_long_ident;
337
338/**
339 * Test: connect to peer with valid peer identification
340 */
341static struct HTTP_Transfer test_valid_ident;
342
343/**
344 * Test: session selection, use any existing
345 */
346static int fail_session_selection_any;
347
348/**
349 * Test: session selection, use existing inbound session
350 */
351static int fail_session_selection_session;
352
353/**
354 * Test: session selection, use existing inbound session
355 * max message, not fitting in send & recv buffers at one time
356 */
357static int fail_session_selection_session_big;
358
359/**
360* Test: session selection, use reliable existing
361 */
362static int fail_session_selection_reliable;
363
364/**
365 * Did the test pass or fail?
366 */
367static int fail;
368
369/**
370 * Number of local addresses
371 */
372static unsigned int count_str_addr;
373
374CURL *curl_handle;
375
376/**
377 * cURL Multihandle
378 */
379static CURLM *multi_handle;
380
381/**
382 * The task sending data
383 */
384static GNUNET_SCHEDULER_TaskIdentifier http_task_send;
385
386/**
387 * Shutdown testcase
388 */
389static void
390shutdown_clean ()
391{
392 struct Plugin_Address * cur;
393 struct Plugin_Address * tmp;
394
395 /* Evaluate results */
396 fail = 0;
397 if ((fail_notify_address == GNUNET_YES) || (fail_pretty_printer == GNUNET_YES) || (fail_addr_to_str == GNUNET_YES))
398 {
399 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Phase 0: Test plugin functions failed\n");
400 fail = 1;
401 }
402 if ((test_no_ident.test_failed == GNUNET_YES) || (test_too_short_ident.test_failed == GNUNET_YES) || (test_too_long_ident.test_failed == GNUNET_YES) || (test_valid_ident.test_failed == GNUNET_YES))
403 {
404 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Phase 1: Test connect with wrong data failed\n");
405 fail = 1;
406 }
407 if ((fail_session_selection_any != GNUNET_NO) || (fail_session_selection_reliable != GNUNET_NO) || (fail_session_selection_session != GNUNET_NO) || (fail_session_selection_session_big != GNUNET_NO))
408 {
409 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Phase 2: Test session selection failed\n");
410 fail = 1;
411 }
412 if ((fail_msgs_transmited_to_local_addrs != count_str_addr) || (fail_multiple_msgs_in_transmission != 2) || (fail_msg_transmited_max_size == GNUNET_YES))
413 {
414 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Phase 3: Test sending with plugin failed\n");
415 fail = 1;
416 }
417 if (fail != 1)
418 {
419 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All tests successful\n");
420 }
421
422 api->disconnect(api->cls,&my_identity);
423
424 curl_multi_cleanup(multi_handle);
425
426 if (NULL != curl_handle)
427 curl_easy_cleanup (curl_handle);
428
429 /* cleaning addresses */
430 while (addr_head != NULL)
431 {
432 cur = addr_head;
433 tmp = addr_head->next;
434 GNUNET_free (addr_head->addr);
435 GNUNET_free (addr_head);
436 addr_head=tmp;
437 }
438
439 if (ti_send != GNUNET_SCHEDULER_NO_TASK)
440 {
441 GNUNET_SCHEDULER_cancel(sched,ti_send);
442 ti_send = GNUNET_SCHEDULER_NO_TASK;
443 }
444
445 if (http_task_send != GNUNET_SCHEDULER_NO_TASK)
446 {
447 GNUNET_SCHEDULER_cancel(sched,http_task_send);
448 http_task_send = GNUNET_SCHEDULER_NO_TASK;
449 }
450
451 if (ti_timeout != GNUNET_SCHEDULER_NO_TASK)
452 {
453 GNUNET_SCHEDULER_cancel(sched,ti_timeout);
454 ti_timeout = GNUNET_SCHEDULER_NO_TASK;
455 }
456
457 GNUNET_free(test_addr);
458 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Unloading http plugin\n");
459 GNUNET_assert (NULL == GNUNET_PLUGIN_unload ("libgnunet_plugin_transport_http", api));
460
461 GNUNET_SCHEDULER_shutdown(sched);
462 GNUNET_DISK_directory_remove ("/tmp/test_plugin_transport_http");
463
464 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Exiting testcase\n");
465 exit(fail);
466 return;
467}
468
469
470/**
471 * Continuation called after plugin send message
472 * @cls closure
473 * @target target
474 * @result GNUNET_OK or GNUNET_SYSERR
475 */
476
477static void task_send_cont (void *cls,
478 const struct GNUNET_PeerIdentity * target,
479 int result)
480{
481 struct Plugin_Address * tmp_addr;
482 tmp_addr = addr_head;
483
484 if ((cls == &fail_msg_transmited_bigger_max_size) && (result == GNUNET_SYSERR))
485 {
486 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Message bigger max msg size was not sent!\n");
487 fail_msg_transmited_bigger_max_size = GNUNET_NO;
488 return;
489 }
490
491 if ((cls == &fail_msg_transmited_max_size) && (result == GNUNET_OK))
492 {
493 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Message with max msg size succesfully sent!\n",fail_msgs_transmited_to_local_addrs);
494 fail_msg_transmited_max_size = GNUNET_NO;
495 }
496}
497
498
499static void run_connection_tests( int phase , void * cls);
500
501/**
502 * Recieves messages from plugin, in real world transport
503 */
504static struct GNUNET_TIME_Relative
505receive (void *cls,
506 const struct GNUNET_PeerIdentity * peer,
507 const struct GNUNET_MessageHeader * message,
508 uint32_t distance,
509 struct Session *session,
510 const char *sender_address,
511 uint16_t sender_address_len)
512{
513 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Testcase recieved new message from peer `%s' with type %u and length %u, session %X\n", GNUNET_i2s(peer), ntohs(message->type), ntohs(message->size),session);
514
515 if ((ntohs(message->type)>=10) && (ntohs(message->type)<20))
516 {
517 fail_msgs_transmited_to_local_addrs++;
518 if (fail_msgs_transmited_to_local_addrs == count_str_addr)
519 run_connection_tests(2, session);
520 }
521
522
523 if ((ntohs(message->type)==20))
524 {
525 fail_session_selection_reliable = GNUNET_NO;
526 }
527
528 if ((ntohs(message->type)==21))
529 {
530 fail_session_selection_any = GNUNET_NO;
531 }
532 if ((ntohs(message->type)==22))
533 {
534 fail_session_selection_session = GNUNET_NO;
535 }
536
537 if ((ntohs(message->type)==23))
538 {
539 fail_session_selection_session_big = GNUNET_NO;
540 run_connection_tests(3, NULL);
541 }
542
543 if ((ntohs(message->type)==30) || (ntohs(message->type)==31))
544 {
545 fail_multiple_msgs_in_transmission ++;
546 }
547
548 if ((ntohs(message->type)==32) && (ntohs(message->size) == GNUNET_SERVER_MAX_MESSAGE_SIZE-1))
549 {
550 fail_msg_transmited_max_size = GNUNET_NO;
551 //shutdown_clean();
552 }
553
554 return GNUNET_TIME_UNIT_ZERO;
555}
556
557static size_t send_function (void *stream, size_t size, size_t nmemb, void *ptr)
558{
559 unsigned int len;
560
561 len = buffer_out.len;
562
563 if (( buffer_out.pos == len) || (len > (size * nmemb)))
564 return 0;
565 memcpy(stream, buffer_out.buf, len);
566 buffer_out.pos = len;
567 return len;
568}
569
570static size_t recv_function (void *ptr, size_t size, size_t nmemb, void *ctx)
571{
572
573 if (buffer_in.pos + size * nmemb > buffer_in.size)
574 return 0; /* overflow */
575
576 buffer_in.len = size * nmemb;
577 memcpy (&buffer_in.buf[buffer_in.pos], ptr, size * nmemb);
578 buffer_in.pos += size * nmemb;
579 buffer_in.len = buffer_in.pos;
580 buffer_in.buf[buffer_in.pos] = '\0';
581 return buffer_in.pos;
582}
583
584static size_t header_function( void *ptr, size_t size, size_t nmemb, void *stream)
585{
586 struct HTTP_Transfer * res = (struct HTTP_Transfer *) stream;
587 char * tmp;
588 unsigned int len = size * nmemb;
589
590 tmp = GNUNET_malloc ( len+1 );
591 memcpy(tmp,ptr,len);
592 if (tmp[len-2] == 13)
593 tmp[len-2]= '\0';
594#if DEBUG_CURL
595 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Header: `%s'\n",tmp);
596#endif
597 if (0==strcmp (tmp,"HTTP/1.1 100 Continue"))
598 {
599 res->http_result_code=100;
600 }
601 if (0==strcmp (tmp,"HTTP/1.1 200 OK"))
602 {
603 res->http_result_code=200;
604 }
605 if (0==strcmp (tmp,"HTTP/1.1 400 Bad Request"))
606 {
607 res->http_result_code=400;
608 }
609 if (0==strcmp (tmp,"HTTP/1.1 404 Not Found"))
610 {
611 res->http_result_code=404;
612 }
613 if (0==strcmp (tmp,"HTTP/1.1 413 Request entity too large"))
614 {
615 res->http_result_code=413;
616 }
617
618 GNUNET_free (tmp);
619 return size * nmemb;
620}
621
622static size_t send_prepare( struct HTTP_Transfer * result);
623
624
625
626static void send_execute (void *cls,
627 const struct GNUNET_SCHEDULER_TaskContext *tc)
628{
629 struct HTTP_Transfer *res;
630
631 int running;
632 struct CURLMsg *msg;
633 CURLMcode mret;
634
635 res = (struct HTTP_Transfer *) cls;
636 http_task_send = GNUNET_SCHEDULER_NO_TASK;
637 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
638 return;
639
640 do
641 {
642 running = 0;
643 mret = curl_multi_perform (multi_handle, &running);
644 if (running == 0)
645 {
646 do
647 {
648
649 msg = curl_multi_info_read (multi_handle, &running);
650 if (msg == NULL)
651 break;
652 /* get session for affected curl handle */
653 //cs = find_session_by_curlhandle (msg->easy_handle);
654 //GNUNET_assert ( cs != NULL );
655 switch (msg->msg)
656 {
657
658 case CURLMSG_DONE:
659 if ( (msg->data.result != CURLE_OK) &&
660 (msg->data.result != CURLE_GOT_NOTHING) )
661 {
662
663 GNUNET_log(GNUNET_ERROR_TYPE_INFO,
664 _("curl failed for `%s' at %s:%d: `%s'\n"),
665 "curl_multi_perform",
666 __FILE__,
667 __LINE__,
668 curl_easy_strerror (msg->data.result));
669 /* sending msg failed*/
670 curl_easy_cleanup(curl_handle);
671 curl_handle=NULL;
672
673 run_connection_tests(0, NULL);
674 }
675 if (res == &test_no_ident)
676 {
677 if ((res->http_result_code==404) && (buffer_in.len==208))
678 {
679 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Connecting to peer without any peer identification: test passed\n"));
680 res->test_failed = GNUNET_NO;
681 }
682 else
683 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Connecting to peer without any peer identification: test failed\n"));
684 }
685 if (res == &test_too_short_ident)
686 {
687 if ((res->http_result_code==404) && (buffer_in.len==208))
688 {
689 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Connecting to peer with too short peer identification: test passed\n"));
690 res->test_failed = GNUNET_NO;
691 }
692 else
693 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Connecting to peer with too short peer identification: test failed\n"));
694 }
695 if (res == &test_too_long_ident)
696 {
697 if ((res->http_result_code==404) && (buffer_in.len==208))
698 {
699 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Connecting to peer with too long peer identification: test passed\n"));
700 res->test_failed = GNUNET_NO;
701 }
702 else
703 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Connecting to peer with too long peer identification: test failed\n"));
704 }
705 if (res == &test_valid_ident)
706 {
707 if ((res->http_result_code==200))
708 {
709 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Connecting to peer with valid peer identification: test passed\n"));
710 res->test_failed = GNUNET_NO;
711 }
712 else
713 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Connecting to peer with valid peer identification: test failed\n"));
714 }
715 curl_easy_cleanup(curl_handle);
716 curl_handle=NULL;
717 if ((res == &test_valid_ident) && (res->test_failed == GNUNET_NO))
718 run_connection_tests(1, NULL);
719 run_connection_tests(0, NULL);
720 return;
721 default:
722 break;
723 }
724
725 }
726 while ( (running > 0) );
727 }
728 }
729 while (mret == CURLM_CALL_MULTI_PERFORM);
730 send_prepare(cls);
731}
732
733/**
734 * Function setting up file descriptors and scheduling task to run
735 * @param ses session to send data to
736 * @return bytes sent to peer
737 */
738static size_t send_prepare( struct HTTP_Transfer * result)
739{
740 fd_set rs;
741 fd_set ws;
742 fd_set es;
743 int max;
744 struct GNUNET_NETWORK_FDSet *grs;
745 struct GNUNET_NETWORK_FDSet *gws;
746 long to;
747 CURLMcode mret;
748
749 max = -1;
750 FD_ZERO (&rs);
751 FD_ZERO (&ws);
752 FD_ZERO (&es);
753 mret = curl_multi_fdset (multi_handle, &rs, &ws, &es, &max);
754 if (mret != CURLM_OK)
755 {
756 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
757 _("%s failed at %s:%d: `%s'\n"),
758 "curl_multi_fdset", __FILE__, __LINE__,
759 curl_multi_strerror (mret));
760 return -1;
761 }
762 mret = curl_multi_timeout (multi_handle, &to);
763 if (mret != CURLM_OK)
764 {
765 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
766 _("%s failed at %s:%d: `%s'\n"),
767 "curl_multi_timeout", __FILE__, __LINE__,
768 curl_multi_strerror (mret));
769 return -1;
770 }
771
772 grs = GNUNET_NETWORK_fdset_create ();
773 gws = GNUNET_NETWORK_fdset_create ();
774 GNUNET_NETWORK_fdset_copy_native (grs, &rs, max + 1);
775 GNUNET_NETWORK_fdset_copy_native (gws, &ws, max + 1);
776 http_task_send = GNUNET_SCHEDULER_add_select (sched,
777 GNUNET_SCHEDULER_PRIORITY_DEFAULT,
778 GNUNET_SCHEDULER_NO_TASK,
779 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 0),
780 grs,
781 gws,
782 &send_execute,
783 result);
784 GNUNET_NETWORK_fdset_destroy (gws);
785 GNUNET_NETWORK_fdset_destroy (grs);
786
787 /* FIXME: return bytes REALLY sent */
788 return 0;
789}
790
791/**
792 * function to send data to server
793 */
794static int send_data( struct HTTP_Transfer * result, char * url)
795{
796
797 curl_handle = curl_easy_init();
798 if( NULL == curl_handle)
799 {
800 printf("easy_init failed \n");
801 return GNUNET_SYSERR;
802 }
803#if DEBUG_CURL
804 curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 1L);
805#endif
806 curl_easy_setopt(curl_handle, CURLOPT_URL, url);
807 curl_easy_setopt(curl_handle, CURLOPT_PUT, 1L);
808 //curl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
809 curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0);
810 curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0);
811 curl_easy_setopt (curl_handle, CURLOPT_HEADERFUNCTION, &header_function);
812 curl_easy_setopt (curl_handle, CURLOPT_WRITEHEADER, result);
813 curl_easy_setopt (curl_handle, CURLOPT_WRITEFUNCTION, &recv_function);
814 curl_easy_setopt (curl_handle, CURLOPT_WRITEDATA, result);
815 curl_easy_setopt (curl_handle, CURLOPT_READFUNCTION, &send_function);
816 curl_easy_setopt (curl_handle, CURLOPT_READDATA, result);
817 curl_easy_setopt(curl_handle, CURLOPT_INFILESIZE_LARGE, (curl_off_t) buffer_out.len);
818 curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, 30);
819 curl_easy_setopt(curl_handle, CURLOPT_CONNECTTIMEOUT, 20);
820
821 curl_multi_add_handle(multi_handle, curl_handle);
822
823 send_prepare(result);
824
825 return GNUNET_OK;
826}
827
828/**
829 * Plugin notifies transport (aka testcase) about its addresses
830 */
831void
832notify_address (void *cls,
833 const char *name,
834 const void *addr,
835 uint16_t addrlen,
836 struct GNUNET_TIME_Relative expires)
837{
838 char address[INET6_ADDRSTRLEN];
839 unsigned int port;
840 struct Plugin_Address * pl_addr;
841 struct Plugin_Address * cur;
842
843 if (addrlen == (sizeof (struct IPv4HttpAddress)))
844 {
845 inet_ntop(AF_INET, (struct in_addr *) addr,address,INET_ADDRSTRLEN);
846 port = ntohs(((struct IPv4HttpAddress *) addr)->u_port);
847 }
848 else if (addrlen == (sizeof (struct IPv6HttpAddress)))
849 {
850 inet_ntop(AF_INET6, (struct in6_addr *) addr,address,INET6_ADDRSTRLEN);
851 port = ntohs(((struct IPv6HttpAddress *) addr)->u6_port);
852 }
853 else
854 {
855 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
856 _("Unknown address size: ipv6 has %u ipv4 has %u but this has %u\n"),
857 sizeof (struct IPv6HttpAddress),
858 sizeof (struct IPv4HttpAddress),
859 addrlen);
860 return;
861 }
862 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
863 _("Transport plugin notification for address: `%s':%u\n"),
864 address,
865 port);
866 pl_addr = GNUNET_malloc (sizeof (struct Plugin_Address) );
867 pl_addr->addrlen = addrlen;
868 pl_addr->addr = GNUNET_malloc(addrlen);
869 memcpy(pl_addr->addr,addr,addrlen);
870 pl_addr->next = NULL;
871
872 if ( NULL == addr_head)
873 {
874 addr_head = pl_addr;
875 }
876 else
877 {
878 cur = addr_head;
879 while (NULL != cur->next)
880 {
881 cur = cur->next;
882 }
883 cur->next = pl_addr;
884 }
885 fail_notify_address_count++;
886 fail_notify_address = GNUNET_NO;
887}
888
889static void
890plugin_env_session_end (void *cls,
891 const struct GNUNET_PeerIdentity *peer,
892 struct Session *session)
893{
894 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Pluging tells me: session %X to peer `%s' ended\n", session, GNUNET_i2s(peer));
895}
896
897
898/**
899 * Setup plugin environment
900 */
901static void
902setup_plugin_environment ()
903{
904 env.cfg = cfg;
905 env.sched = sched;
906 env.stats = stats;
907 env.my_identity = &my_identity;
908 env.cls = &env;
909 env.receive = &receive;
910 env.notify_address = &notify_address;
911 env.max_connections = max_connect_per_transport;
912 env.session_end = &plugin_env_session_end;
913}
914
915
916/**
917 * Task shutting down testcase if it a timeout occurs
918 */
919static void
920task_timeout (void *cls,
921 const struct GNUNET_SCHEDULER_TaskContext *tc)
922{
923 ti_timeout = GNUNET_SCHEDULER_NO_TASK;
924 if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
925 return;
926
927 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Testcase timeout\n");
928 fail = GNUNET_YES;
929 shutdown_clean();
930 return;
931}
932
933static void pretty_printer_cb (void *cls,
934 const char *address)
935{
936 if (NULL==address)
937 return;
938 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Plugin returned pretty address: `%s'\n",address);
939 fail_pretty_printer_count++;
940}
941
942/**
943 * Runs every single test to test the plugin
944 */
945static void run_connection_tests( int phase , void * cls)
946{
947 struct GNUNET_MessageHeader * msg;
948 unsigned int size;
949
950 if (phase==0)
951 {
952 char * host_str = NULL;
953 /* resetting buffers */
954 buffer_in.size = HTTP_BUFFER_SIZE;
955 buffer_in.pos = 0;
956 buffer_in.len = 0;
957
958 buffer_out.size = HTTP_BUFFER_SIZE;
959 buffer_out.pos = 0;
960 buffer_out.len = 0;
961
962 if (test_no_ident.test_executed == GNUNET_NO)
963 {
964 /* Connecting to peer without identification */
965 char * ident = "";
966 GNUNET_asprintf (&host_str, "http://%s/%s",test_addr,ident);
967 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Connecting to peer without any peer identification.\n"));
968 test_no_ident.test_executed = GNUNET_YES;
969 send_data ( &test_no_ident, host_str);
970 GNUNET_free (host_str);
971 return;
972 }
973 if (test_too_short_ident.test_executed == GNUNET_NO)
974 {
975 char * ident = "AAAAAAAAAA";
976 /* Connecting to peer with too short identification */
977 GNUNET_asprintf (&host_str, "http://%s/%s",test_addr,ident);
978 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Connecting to peer with too short peer identification.\n"));
979 test_too_short_ident.test_executed = GNUNET_YES;
980 send_data ( &test_too_short_ident, host_str);
981 GNUNET_free (host_str);
982 return;
983 }
984
985 if (test_too_long_ident.test_executed == GNUNET_NO)
986 {
987 char * ident = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
988
989 /* Connecting to peer with too long identification */
990 GNUNET_asprintf (&host_str, "http://%s/%s",test_addr,ident);
991 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Connecting to peer with too long peer identification.\n"));
992 test_too_long_ident.test_executed = GNUNET_YES;
993 send_data ( &test_too_long_ident, host_str);
994 GNUNET_free (host_str);
995 return;
996 }
997 if (test_valid_ident.test_executed == GNUNET_NO)
998 {
999 struct GNUNET_CRYPTO_HashAsciiEncoded ident;
1000 GNUNET_CRYPTO_hash_to_enc(&my_identity.hashPubKey,&ident);
1001 GNUNET_asprintf (&host_str, "http://%s/%s%s",test_addr,(char *) &ident,";0");
1002 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Connecting to peer with valid peer identification.\n"));
1003 test_valid_ident.test_executed = GNUNET_YES;
1004 send_data ( &test_valid_ident, host_str);
1005 GNUNET_free (host_str);
1006 return;
1007 }
1008 }
1009 if (phase==1)
1010 {
1011 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("\nPhase 1: transmit data to all suggested addresses\n\n"));
1012 /* Using one of the addresses the plugin proposed */
1013 GNUNET_assert (addr_head->addr != NULL);
1014
1015 struct Plugin_Address * tmp_addr;
1016 struct GNUNET_MessageHeader msg;
1017 char * tmp = GNUNET_malloc(sizeof(struct GNUNET_MessageHeader));
1018 char address[INET6_ADDRSTRLEN];
1019 unsigned int port;
1020 unsigned int type = 10;
1021
1022 msg.size=htons(sizeof(struct GNUNET_MessageHeader));
1023 tmp_addr = addr_head;
1024 /* send a message to all addresses advertised by plugin */
1025
1026 int count = 0;
1027 while (tmp_addr != NULL)
1028 {
1029 if (tmp_addr->addrlen == (sizeof (struct IPv4HttpAddress)))
1030 {
1031 inet_ntop(AF_INET, (struct in_addr *) tmp_addr->addr,address,INET_ADDRSTRLEN);
1032 port = ntohs(((struct IPv4HttpAddress *) tmp_addr->addr)->u_port);
1033 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Sending message to addres no. %u: `%s':%u\n", count,address, port);
1034 }
1035 if (tmp_addr->addrlen == (sizeof (struct IPv6HttpAddress)))
1036 {
1037 inet_ntop(AF_INET6, (struct in6_addr *) tmp_addr->addr,address,INET6_ADDRSTRLEN);
1038 port = ntohs(((struct IPv6HttpAddress *) tmp_addr->addr)->u6_port);
1039 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Sending message to addres no. %u: `%s':%u\n", count,address,port);
1040 }
1041 msg.type=htons(type);
1042 memcpy(tmp,&msg,sizeof(struct GNUNET_MessageHeader));
1043 api->send(api->cls, &my_identity, tmp, sizeof(struct GNUNET_MessageHeader), 0, TIMEOUT, NULL,tmp_addr->addr, tmp_addr->addrlen, GNUNET_YES, &task_send_cont, &fail_msgs_transmited_to_local_addrs);
1044 tmp_addr = tmp_addr->next;
1045
1046 count ++;
1047 type ++;
1048 }
1049 GNUNET_free(tmp);
1050 return;
1051 }
1052
1053 if (phase==2)
1054 {
1055 struct Session * session = cls;
1056 msg = GNUNET_malloc (sizeof(struct GNUNET_MessageHeader));
1057
1058 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("\nPhase 2: session selection\n\n"));
1059 size = sizeof(struct GNUNET_MessageHeader);
1060 msg->size=htons(size);
1061 msg->type = htons(20);
1062 api->send(api->cls, &my_identity, (const char *) msg, size, 0, TIMEOUT, NULL, NULL, 0, GNUNET_NO, &task_send_cont, NULL);
1063
1064 msg->type = htons(21);
1065 api->send(api->cls, &my_identity, (const char *) msg, size, 0, TIMEOUT, NULL, NULL, 0, GNUNET_SYSERR, &task_send_cont, NULL);
1066
1067 /* answer on session*/
1068 size = sizeof( struct GNUNET_MessageHeader);
1069 msg->size = htons(size);
1070 msg->type = htons(22);
1071 api->send(api->cls, &my_identity, (const char *) msg, size, 0, TIMEOUT, session, NULL, 0, GNUNET_SYSERR, &task_send_cont, NULL);
1072
1073 GNUNET_free(msg);
1074
1075 /* answer on session with big message not fitting in mhd send buffer*/
1076 size = GNUNET_SERVER_MAX_MESSAGE_SIZE-1;
1077 msg = GNUNET_malloc (size);
1078 msg->size=htons(size);
1079 msg->type = htons(23);
1080 api->send(api->cls, &my_identity, (const char *) msg, size, 0, TIMEOUT, session, NULL, 0, GNUNET_NO, &task_send_cont, NULL);
1081 GNUNET_free(msg);
1082 return;
1083 }
1084
1085 if (phase==3)
1086 {
1087
1088 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("\nPhase 3: send multiple or big messages after disconnect\n\n"));
1089 /* disconnect from peer, so new connections are created */
1090 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Disconnect from peer: `%s'\n", GNUNET_i2s(&my_identity));
1091 api->disconnect(api->cls, &my_identity);
1092
1093 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Phase 3: sending messages\n"));
1094 /* send a multiple GNUNET_messages at a time*/
1095 size = 2 * sizeof(struct GNUNET_MessageHeader);
1096 msg = GNUNET_malloc( 2* size);
1097 msg->size = htons(size);
1098 msg->type = htons(30);
1099 struct GNUNET_MessageHeader * msg2 = &msg[2];
1100 msg2->size = htons(2 * sizeof(struct GNUNET_MessageHeader));
1101 msg2->type = htons(31);
1102 api->send(api->cls, &my_identity, (const char *) msg, 4 * sizeof(struct GNUNET_MessageHeader), 0, TIMEOUT, NULL,addr_head->addr, addr_head->addrlen, GNUNET_NO, &task_send_cont, &fail_multiple_msgs_in_transmission);
1103 GNUNET_free(msg);
1104 /* send a message with size GNUNET_SERVER_MAX_MESSAGE_SIZE-1 */
1105
1106 size = GNUNET_SERVER_MAX_MESSAGE_SIZE-1;
1107 msg = GNUNET_malloc(size);
1108 msg->size = htons(size);
1109 msg->type = htons(32);
1110 api->send(api->cls, &my_identity, (const char *) msg, size, 0, TIMEOUT, NULL,addr_head->addr, addr_head->addrlen, GNUNET_NO, &task_send_cont, &fail_msg_transmited_max_size);
1111 GNUNET_free(msg);
1112 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"No more tests to run\n");
1113 }
1114}
1115
1116
1117/**
1118 * Runs the test.
1119 *
1120 * @param cls closure
1121 * @param s scheduler to use
1122 * @param c configuration to use
1123 */
1124static void
1125run (void *cls,
1126 struct GNUNET_SCHEDULER_Handle *s,
1127 char *const *args,
1128 const char *cfgfile, const struct GNUNET_CONFIGURATION_Handle *c)
1129{
1130 char * libname;
1131 sched = s;
1132 cfg = c;
1133 char *keyfile;
1134 unsigned long long tneigh;
1135 struct Plugin_Address * cur;
1136 const char * addr_str;
1137
1138
1139 unsigned int suggest_res;
1140
1141 fail_pretty_printer = GNUNET_YES;
1142 fail_notify_address = GNUNET_YES;
1143 fail_addr_to_str = GNUNET_YES;
1144 fail_msgs_transmited_to_local_addrs = 0;
1145 fail_msg_transmited_max_size = GNUNET_YES;
1146 fail_multiple_msgs_in_transmission = 0;
1147 fail_session_selection_reliable = GNUNET_YES;
1148 fail_session_selection_reliable = GNUNET_YES;
1149 fail_session_selection_session = GNUNET_YES;
1150 fail_session_selection_session_big = GNUNET_YES;
1151
1152 addr_head = NULL;
1153 count_str_addr = 0;
1154 /* parse configuration */
1155 if ((GNUNET_OK !=
1156 GNUNET_CONFIGURATION_get_value_number (c,
1157 "TRANSPORT",
1158 "NEIGHBOUR_LIMIT",
1159 &tneigh)) ||
1160 (GNUNET_OK !=
1161 GNUNET_CONFIGURATION_get_value_filename (c,
1162 "GNUNETD",
1163 "HOSTKEY", &keyfile)))
1164 {
1165 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1166 _
1167 ("Transport service is lacking key configuration settings. Exiting.\n"));
1168 GNUNET_SCHEDULER_shutdown (s);
1169 fail = 1;
1170 return;
1171 }
1172
1173 if ((GNUNET_OK !=
1174 GNUNET_CONFIGURATION_get_value_number (cfg,
1175 "transport-https",
1176 "PORT",
1177 &port)) ||
1178 (port > 65535) || (port == 0))
1179 {
1180 GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
1181 "https",
1182 _
1183 ("Require valid port number for transport plugin `%s' in configuration!\n"),
1184 "transport-http");
1185 }
1186
1187 max_connect_per_transport = (uint32_t) tneigh;
1188 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
1189 GNUNET_free (keyfile);
1190 if (my_private_key == NULL)
1191 {
1192 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1193 _("Transport service could not access hostkey. Exiting.\n"));
1194 GNUNET_SCHEDULER_shutdown (s);
1195 fail = 1;
1196 return;
1197 }
1198
1199 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
1200 GNUNET_CRYPTO_hash (&my_public_key, sizeof (my_public_key), &my_identity.hashPubKey);
1201
1202 /* assertions before start */
1203 GNUNET_assert ((port > 0) && (port <= 65535));
1204 GNUNET_assert(&my_public_key != NULL);
1205 GNUNET_assert(&my_identity.hashPubKey != NULL);
1206
1207 /* load plugins... */
1208 setup_plugin_environment ();
1209 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Loading HTTPS transport plugin `%s'\n"),"libgnunet_plugin_transport_http");
1210 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_https");
1211 api = GNUNET_PLUGIN_load (libname, &env);
1212 GNUNET_free (libname);
1213 if (api == NULL)
1214 {
1215 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1216 _("Failed to load transport plugin for https\n"));
1217 fail = 1;
1218 return;
1219 }
1220
1221 ti_timeout = GNUNET_SCHEDULER_add_delayed (sched, TEST_TIMEOUT, &task_timeout, NULL);
1222
1223 /* testing plugin functionality */
1224 GNUNET_assert (0!=fail_notify_address_count);
1225 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport plugin returned %u addresses to connect to\n"), fail_notify_address_count);
1226
1227 /* testing pretty printer with all addresses obtained from the plugin*/
1228 cur = addr_head;
1229 while (cur != NULL)
1230 {
1231
1232 api->address_pretty_printer (api->cls, "http",cur->addr,cur->addrlen, GNUNET_NO,TEST_TIMEOUT, &pretty_printer_cb,NULL);
1233 addr_str = api->address_to_string (api->cls, cur->addr, cur->addrlen);
1234 suggest_res = api->check_address (api->cls, cur->addr, cur->addrlen);
1235
1236 GNUNET_assert (GNUNET_OK == suggest_res);
1237 GNUNET_assert (NULL != addr_str);
1238 count_str_addr++;
1239 GNUNET_free ( (char *) addr_str);
1240 cur = cur->next;
1241 }
1242 GNUNET_assert (fail_pretty_printer_count > 0);
1243 GNUNET_assert (fail_pretty_printer_count==fail_notify_address_count);
1244 GNUNET_assert (fail_pretty_printer_count==count_str_addr);
1245 fail_pretty_printer=GNUNET_NO;
1246 fail_addr_to_str=GNUNET_NO;
1247
1248 /* Suggesting addresses with wrong port*/
1249 struct IPv4HttpAddress failing_addr;
1250 failing_addr.ipv4_addr = htonl(INADDR_LOOPBACK);
1251 failing_addr.u_port = htons(0);
1252 suggest_res = api->check_address (api->cls,&failing_addr,sizeof (struct IPv4HttpAddress));
1253 GNUNET_assert (GNUNET_SYSERR == suggest_res);
1254
1255 /* Suggesting addresses with wrong size*/
1256 failing_addr.ipv4_addr = htonl(INADDR_LOOPBACK);
1257 failing_addr.u_port = htons(0);
1258 suggest_res = api->check_address (api->cls,&failing_addr,sizeof (struct IPv6HttpAddress));
1259 GNUNET_assert (GNUNET_SYSERR == suggest_res);
1260
1261 /* Suggesting addresses with wrong address*/
1262 failing_addr.ipv4_addr = htonl(0xffc00000);
1263 failing_addr.u_port = htons(12389);
1264 suggest_res = api->check_address (api->cls,&failing_addr,100);
1265 GNUNET_assert (GNUNET_SYSERR == suggest_res);
1266
1267 /* test sending to client */
1268 multi_handle = curl_multi_init();
1269
1270 /* Setting up buffers */
1271 buffer_in.size = HTTP_BUFFER_SIZE;
1272 buffer_in.pos = 0;
1273 buffer_in.len = 0;
1274
1275 buffer_out.size = HTTP_BUFFER_SIZE;
1276 buffer_out.pos = 0;
1277 buffer_out.len = 0;
1278
1279 /* Setting up connection tests */
1280
1281 /* Test: connecting without a peer identification */
1282 test_no_ident.test_executed = GNUNET_NO;
1283 test_no_ident.test_failed = GNUNET_YES;
1284
1285 /* Test: connecting with too short peer identification */
1286 test_too_short_ident.test_executed = GNUNET_NO;
1287 test_too_short_ident.test_failed = GNUNET_YES;
1288
1289 /* Test: connecting with too long peer identification */
1290 test_too_long_ident.test_executed = GNUNET_NO;
1291 test_too_long_ident.test_failed = GNUNET_YES;
1292
1293 /* Test: connecting with valid identification */
1294 test_valid_ident.test_executed = GNUNET_NO;
1295 test_valid_ident.test_failed = GNUNET_YES;
1296
1297 test_addr = (char *) api->address_to_string (api->cls,addr_head->addr,addr_head->addrlen);
1298
1299 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("\nPhase 0\n\n"));
1300 run_connection_tests(0, NULL);
1301
1302 /* testing finished */
1303
1304 return;
1305}
1306
1307
1308/**
1309 * The main function for the transport service.
1310 *
1311 * @param argc number of arguments from the command line
1312 * @param argv command line arguments
1313 * @return 0 ok, 1 on error
1314 */
1315int
1316main (int argc, char *const *argv)
1317{
1318
1319 static struct GNUNET_GETOPT_CommandLineOption options[] = {
1320 GNUNET_GETOPT_OPTION_END
1321 };
1322 int ret;
1323 char *const argv_prog[] = {
1324 "test_plugin_transport_https",
1325 "-c",
1326 "test_plugin_transport_data_http.conf",
1327 "-L",
1328#if VERBOSE
1329 "DEBUG",
1330#else
1331 "WARNING",
1332#endif
1333 NULL
1334 };
1335 GNUNET_log_setup ("test_plugin_transport_https",
1336#if VERBOSE
1337 "DEBUG",
1338#else
1339 "WARNING",
1340#endif
1341 NULL);
1342
1343 ret = (GNUNET_OK ==
1344 GNUNET_PROGRAM_run (5,
1345 argv_prog,
1346 "test_plugin_transport_https",
1347 "testcase", options, &run, NULL)) ? GNUNET_NO : GNUNET_YES;
1348
1349 GNUNET_DISK_directory_remove ("/tmp/test_plugin_transport_https");
1350
1351 return fail;
1352}
1353
1354/* end of test_plugin_transport_http.c */
diff --git a/src/transport/test_transport_api_http_peer1.conf b/src/transport/test_transport_api_http_peer1.conf
index f27e570b9..bb7027c0d 100644
--- a/src/transport/test_transport_api_http_peer1.conf
+++ b/src/transport/test_transport_api_http_peer1.conf
@@ -1,9 +1,9 @@
1[transport-http] 1[transport-http]
2PORT = 12389 2PORT = 12389
3DEBUG = NO 3DEBUG = NO
4USE_IPv6 = NO 4USE_IPv6 = YES
5USE_IPv4 = YES 5USE_IPv4 = YES
6BINDTO4 = 127.0.0.1 6#BINDTO4 = 127.0.0.1
7#BINDTO6 = ::1 7#BINDTO6 = ::1
8 8
9 9
diff --git a/src/transport/test_transport_api_http_peer2.conf b/src/transport/test_transport_api_http_peer2.conf
index d60d98baa..910a63c9c 100644
--- a/src/transport/test_transport_api_http_peer2.conf
+++ b/src/transport/test_transport_api_http_peer2.conf
@@ -1,9 +1,9 @@
1[transport-http] 1[transport-http]
2PORT = 22368 2PORT = 22368
3DEBUG = NO 3DEBUG = NO
4USE_IPv6 = NO 4USE_IPv6 = YES
5USE_IPv4 = YES 5USE_IPv4 = YES
6BINDTO4 = 127.0.0.1 6#BINDTO4 = 127.0.0.1
7#BINDTO6 = ::1 7#BINDTO6 = ::1
8 8
9[fs] 9[fs]