diff options
-rw-r--r-- | src/transport/Makefile.am | 29 | ||||
-rw-r--r-- | src/transport/plugin_transport_http.c | 131 | ||||
-rw-r--r-- | src/transport/plugin_transport_https.c | 2585 | ||||
-rw-r--r-- | src/transport/test_plugin_transport_data_http.conf | 10 | ||||
-rw-r--r-- | src/transport/test_plugin_transport_https.c | 1354 | ||||
-rw-r--r-- | src/transport/test_transport_api_http_peer1.conf | 4 | ||||
-rw-r--r-- | src/transport/test_transport_api_http_peer2.conf | 4 |
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 | ||
15 | endif | 18 | endif |
16 | 19 | ||
17 | if USE_COVERAGE | 20 | if 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 = \ | |||
128 | libgnunet_plugin_transport_http_la_LDFLAGS = \ | 132 | libgnunet_plugin_transport_http_la_LDFLAGS = \ |
129 | $(GN_LIBMHD) \ | 133 | $(GN_LIBMHD) \ |
130 | $(GN_PLUGIN_LDFLAGS) | 134 | $(GN_PLUGIN_LDFLAGS) |
135 | |||
136 | libgnunet_plugin_transport_https_la_SOURCES = \ | ||
137 | plugin_transport_https.c | ||
138 | libgnunet_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 | ||
144 | libgnunet_plugin_transport_https_la_LDFLAGS = \ | ||
145 | $(GN_LIBMHD) \ | ||
146 | $(GN_PLUGIN_LDFLAGS) | ||
131 | endif | 147 | endif |
132 | 148 | ||
133 | check_PROGRAMS = \ | 149 | check_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 |
212 | test_transport_api_reliability_http_LDADD = \ | 230 | test_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 | |||
234 | test_plugin_transport_https_SOURCES = \ | ||
235 | test_plugin_transport_https.c | ||
236 | test_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 | |||
215 | endif | 242 | endif |
216 | 243 | ||
217 | EXTRA_DIST = \ | 244 | EXTRA_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 | ||
441 | int 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, | |||
1085 | static size_t curl_get_header_cb( void *ptr, size_t size, size_t nmemb, void *stream) | 1128 | static 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 */ | ||
76 | const 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 | |||
94 | const 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 | */ | ||
126 | struct 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 | */ | ||
144 | struct 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 | */ | ||
162 | struct 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 | |||
203 | struct 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 | |||
239 | struct 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 | */ | ||
354 | struct 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 | */ | ||
425 | static const char* | ||
426 | http_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 | */ | ||
435 | static 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 | */ | ||
440 | static 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 | */ | ||
449 | static 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 | */ | ||
457 | static int curl_schedule(void *cls ); | ||
458 | |||
459 | |||
460 | |||
461 | static 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 | */ | ||
481 | static 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 | |||
488 | int 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 | */ | ||
498 | static 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 | |||
554 | int 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 | */ | ||
613 | static int | ||
614 | process_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 | */ | ||
690 | static 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 | |||
728 | static 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 | */ | ||
755 | static int | ||
756 | mhd_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 | |||
766 | int 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 | */ | ||
817 | static int | ||
818 | mdh_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 | */ | ||
1055 | static GNUNET_SCHEDULER_TaskIdentifier | ||
1056 | http_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 | */ | ||
1138 | static 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 | */ | ||
1159 | static 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 | |||
1175 | static 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 | |||
1222 | static 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 | */ | ||
1282 | static 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 | |||
1341 | static 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 | */ | ||
1374 | static 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 | |||
1385 | static 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 | */ | ||
1543 | static 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 | */ | ||
1610 | static 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 | |||
1772 | static 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 | */ | ||
1916 | static ssize_t | ||
1917 | http_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 | */ | ||
2061 | static void | ||
2062 | http_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 | */ | ||
2130 | static void | ||
2131 | http_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 | */ | ||
2194 | static int | ||
2195 | http_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 | */ | ||
2252 | static const char* | ||
2253 | http_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 | */ | ||
2297 | void * | ||
2298 | libgnunet_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 | */ | ||
2369 | void * | ||
2370 | libgnunet_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] |
9 | PORT = 12389 | 9 | PORT = 12389 |
10 | DEBUG = NO | 10 | DEBUG = YES |
11 | #USE_IPv4 = NO | 11 | #USE_IPv4 = NO |
12 | #USE_IPv6 = NO | 12 | #USE_IPv6 = NO |
13 | USE_IPv6 = YES | 13 | USE_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] | ||
18 | PORT = 12389 | ||
19 | DEBUG = NO | ||
20 | #USE_IPv4 = NO | ||
21 | #USE_IPv6 = NO | ||
22 | USE_IPv6 = YES | ||
23 | #BINDTO4 = 127.0.0.1 | ||
24 | #BINDTO6 = ::1 | ||
17 | 25 | ||
18 | [transport] | 26 | [transport] |
19 | PREFIX = valgrind --leak-check=full | 27 | PREFIX = 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 | */ | ||
74 | struct 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 | */ | ||
95 | struct 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 | */ | ||
122 | struct 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 | */ | ||
164 | struct 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 | */ | ||
182 | struct 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 | */ | ||
204 | static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key; | ||
205 | |||
206 | /** | ||
207 | * Our identity. | ||
208 | */ | ||
209 | static struct GNUNET_PeerIdentity my_identity; | ||
210 | |||
211 | /** | ||
212 | * Our private key. | ||
213 | */ | ||
214 | static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key; | ||
215 | |||
216 | /** | ||
217 | * Peer's port | ||
218 | */ | ||
219 | static long long unsigned int port; | ||
220 | |||
221 | /** | ||
222 | * Peer's addr | ||
223 | */ | ||
224 | static char * test_addr; | ||
225 | |||
226 | /** | ||
227 | * Our scheduler. | ||
228 | */ | ||
229 | struct GNUNET_SCHEDULER_Handle *sched; | ||
230 | |||
231 | /** | ||
232 | * Our statistics handle. | ||
233 | */ | ||
234 | struct GNUNET_STATISTICS_Handle *stats; | ||
235 | |||
236 | |||
237 | /** | ||
238 | * Our configuration. | ||
239 | */ | ||
240 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
241 | |||
242 | /** | ||
243 | * Number of neighbours we'd like to have. | ||
244 | */ | ||
245 | static uint32_t max_connect_per_transport; | ||
246 | |||
247 | /** | ||
248 | * Environment for this plugin. | ||
249 | */ | ||
250 | static struct GNUNET_TRANSPORT_PluginEnvironment env; | ||
251 | |||
252 | /** | ||
253 | *handle for the api provided by this plugin | ||
254 | */ | ||
255 | static struct GNUNET_TRANSPORT_PluginFunctions *api; | ||
256 | |||
257 | /** | ||
258 | * ID of the task controlling the testcase timeout | ||
259 | */ | ||
260 | static GNUNET_SCHEDULER_TaskIdentifier ti_timeout; | ||
261 | |||
262 | static GNUNET_SCHEDULER_TaskIdentifier ti_send; | ||
263 | |||
264 | //const struct GNUNET_PeerIdentity * p; | ||
265 | |||
266 | /** | ||
267 | * buffer for data to send | ||
268 | */ | ||
269 | static struct HTTP_Message buffer_out; | ||
270 | |||
271 | /** | ||
272 | * buffer for data to recieve | ||
273 | */ | ||
274 | static struct HTTP_Message buffer_in; | ||
275 | |||
276 | |||
277 | struct Plugin_Address * addr_head; | ||
278 | |||
279 | /** | ||
280 | * Did the test pass or fail? | ||
281 | */ | ||
282 | static int fail_notify_address; | ||
283 | /** | ||
284 | * Did the test pass or fail? | ||
285 | */ | ||
286 | static int fail_notify_address_count; | ||
287 | |||
288 | /** | ||
289 | * Did the test pass or fail? | ||
290 | */ | ||
291 | static int fail_pretty_printer; | ||
292 | |||
293 | /** | ||
294 | * Did the test pass or fail? | ||
295 | */ | ||
296 | static int fail_pretty_printer_count; | ||
297 | |||
298 | /** | ||
299 | * Did the test pass or fail? | ||
300 | */ | ||
301 | static int fail_addr_to_str; | ||
302 | |||
303 | /** | ||
304 | * No. of msgs transmitted successfully to local addresses | ||
305 | */ | ||
306 | static int fail_msgs_transmited_to_local_addrs; | ||
307 | |||
308 | /** | ||
309 | * Test: transmit msg of max. size | ||
310 | */ | ||
311 | static int fail_msg_transmited_bigger_max_size; | ||
312 | |||
313 | /** | ||
314 | * Test: transmit msg of max. size | ||
315 | */ | ||
316 | static int fail_msg_transmited_max_size; | ||
317 | |||
318 | /** | ||
319 | * Test: transmit 2 msgs. in in send operation | ||
320 | */ | ||
321 | static int fail_multiple_msgs_in_transmission; | ||
322 | |||
323 | /** | ||
324 | * Test: connect to peer without peer identification | ||
325 | */ | ||
326 | static struct HTTP_Transfer test_no_ident; | ||
327 | |||
328 | /** | ||
329 | * Test: connect to peer without peer identification | ||
330 | */ | ||
331 | static struct HTTP_Transfer test_too_short_ident; | ||
332 | |||
333 | /** | ||
334 | * Test: connect to peer without peer identification | ||
335 | */ | ||
336 | static struct HTTP_Transfer test_too_long_ident; | ||
337 | |||
338 | /** | ||
339 | * Test: connect to peer with valid peer identification | ||
340 | */ | ||
341 | static struct HTTP_Transfer test_valid_ident; | ||
342 | |||
343 | /** | ||
344 | * Test: session selection, use any existing | ||
345 | */ | ||
346 | static int fail_session_selection_any; | ||
347 | |||
348 | /** | ||
349 | * Test: session selection, use existing inbound session | ||
350 | */ | ||
351 | static 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 | */ | ||
357 | static int fail_session_selection_session_big; | ||
358 | |||
359 | /** | ||
360 | * Test: session selection, use reliable existing | ||
361 | */ | ||
362 | static int fail_session_selection_reliable; | ||
363 | |||
364 | /** | ||
365 | * Did the test pass or fail? | ||
366 | */ | ||
367 | static int fail; | ||
368 | |||
369 | /** | ||
370 | * Number of local addresses | ||
371 | */ | ||
372 | static unsigned int count_str_addr; | ||
373 | |||
374 | CURL *curl_handle; | ||
375 | |||
376 | /** | ||
377 | * cURL Multihandle | ||
378 | */ | ||
379 | static CURLM *multi_handle; | ||
380 | |||
381 | /** | ||
382 | * The task sending data | ||
383 | */ | ||
384 | static GNUNET_SCHEDULER_TaskIdentifier http_task_send; | ||
385 | |||
386 | /** | ||
387 | * Shutdown testcase | ||
388 | */ | ||
389 | static void | ||
390 | shutdown_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 | |||
477 | static 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 | |||
499 | static void run_connection_tests( int phase , void * cls); | ||
500 | |||
501 | /** | ||
502 | * Recieves messages from plugin, in real world transport | ||
503 | */ | ||
504 | static struct GNUNET_TIME_Relative | ||
505 | receive (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 | |||
557 | static 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 | |||
570 | static 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 | |||
584 | static 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 | |||
622 | static size_t send_prepare( struct HTTP_Transfer * result); | ||
623 | |||
624 | |||
625 | |||
626 | static 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 | */ | ||
738 | static 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 | */ | ||
794 | static 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 | */ | ||
831 | void | ||
832 | notify_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 | |||
889 | static void | ||
890 | plugin_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 | */ | ||
901 | static void | ||
902 | setup_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 = ¬ify_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 | */ | ||
919 | static void | ||
920 | task_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 | |||
933 | static 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 | */ | ||
945 | static 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 | */ | ||
1124 | static void | ||
1125 | run (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 | */ | ||
1315 | int | ||
1316 | main (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] |
2 | PORT = 12389 | 2 | PORT = 12389 |
3 | DEBUG = NO | 3 | DEBUG = NO |
4 | USE_IPv6 = NO | 4 | USE_IPv6 = YES |
5 | USE_IPv4 = YES | 5 | USE_IPv4 = YES |
6 | BINDTO4 = 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] |
2 | PORT = 22368 | 2 | PORT = 22368 |
3 | DEBUG = NO | 3 | DEBUG = NO |
4 | USE_IPv6 = NO | 4 | USE_IPv6 = YES |
5 | USE_IPv4 = YES | 5 | USE_IPv4 = YES |
6 | BINDTO4 = 127.0.0.1 | 6 | #BINDTO4 = 127.0.0.1 |
7 | #BINDTO6 = ::1 | 7 | #BINDTO6 = ::1 |
8 | 8 | ||
9 | [fs] | 9 | [fs] |