diff options
author | Matthias Wachs <wachs@net.in.tum.de> | 2012-08-21 14:28:55 +0000 |
---|---|---|
committer | Matthias Wachs <wachs@net.in.tum.de> | 2012-08-21 14:28:55 +0000 |
commit | b109b888a1a99ce9c9396e606cea57204762c1d4 (patch) | |
tree | 500df275a7916d8fe61e4ba536b8cb03b26fe8e3 | |
parent | 77463bc3a995cf19a1bfb7512530c29aa1bc80cc (diff) | |
download | gnunet-b109b888a1a99ce9c9396e606cea57204762c1d4.tar.gz gnunet-b109b888a1a99ce9c9396e606cea57204762c1d4.zip |
- preprations for http plugin split
-rw-r--r-- | src/transport/Makefile.am | 186 | ||||
-rw-r--r-- | src/transport/plugin_transport_http.c | 496 | ||||
-rw-r--r-- | src/transport/plugin_transport_http.h | 13 | ||||
-rw-r--r-- | src/transport/plugin_transport_http_client.c | 784 | ||||
-rw-r--r-- | src/transport/plugin_transport_http_client_old.c | 645 | ||||
-rw-r--r-- | src/transport/plugin_transport_http_server.c | 1461 | ||||
-rw-r--r-- | src/transport/plugin_transport_http_server_old.c | 1336 | ||||
-rw-r--r-- | src/transport/test_transport_api_http_reverse_proxy.conf | 2 |
8 files changed, 2624 insertions, 2299 deletions
diff --git a/src/transport/Makefile.am b/src/transport/Makefile.am index c6fdafa6b..6447b1152 100644 --- a/src/transport/Makefile.am +++ b/src/transport/Makefile.am | |||
@@ -10,7 +10,15 @@ pkgcfg_DATA = \ | |||
10 | 10 | ||
11 | if HAVE_MHD | 11 | if HAVE_MHD |
12 | GN_LIBMHD = -lmicrohttpd | 12 | GN_LIBMHD = -lmicrohttpd |
13 | HTTP_PLUGIN_LA = libgnunet_plugin_transport_http.la | 13 | HTTP_SERVER_PLUGIN_LA = libgnunet_plugin_transport_http_server.la |
14 | HTTPS_SERVER_PLUGIN_LA = libgnunet_plugin_transport_https_server.la | ||
15 | endif | ||
16 | |||
17 | HTTP_CLIENT_PLUGIN_LA = libgnunet_plugin_transport_http_client.la | ||
18 | HTTPS_CLIENT_PLUGIN_LA = libgnunet_plugin_transport_https_client.la | ||
19 | |||
20 | |||
21 | if FALSE | ||
14 | HTTP_API_TEST = test_transport_api_http | 22 | HTTP_API_TEST = test_transport_api_http |
15 | HTTP_NAT_API_TEST = test_transport_api_http_nat | 23 | HTTP_NAT_API_TEST = test_transport_api_http_nat |
16 | HTTP_API_TIMEOUT_TEST = test_transport_api_timeout_http | 24 | HTTP_API_TIMEOUT_TEST = test_transport_api_timeout_http |
@@ -18,7 +26,7 @@ if HAVE_MHD | |||
18 | HTTP_NAT_REL_TEST = test_transport_api_reliability_http_nat | 26 | HTTP_NAT_REL_TEST = test_transport_api_reliability_http_nat |
19 | HTTP_QUOTA_TEST = test_quota_compliance_http \ | 27 | HTTP_QUOTA_TEST = test_quota_compliance_http \ |
20 | test_quota_compliance_http_asymmetric | 28 | test_quota_compliance_http_asymmetric |
21 | HTTPS_PLUGIN_LA = libgnunet_plugin_transport_https.la | 29 | |
22 | HTTPS_API_TEST = test_transport_api_https | 30 | HTTPS_API_TEST = test_transport_api_https |
23 | HTTPS_NAT_API_TEST = test_transport_api_https_nat | 31 | HTTPS_NAT_API_TEST = test_transport_api_https_nat |
24 | HTTPS_API_TIMEOUT_TEST = test_transport_api_timeout_https | 32 | HTTPS_API_TIMEOUT_TEST = test_transport_api_timeout_https |
@@ -28,6 +36,7 @@ if HAVE_MHD | |||
28 | test_quota_compliance_https_asymmetric | 36 | test_quota_compliance_https_asymmetric |
29 | endif | 37 | endif |
30 | 38 | ||
39 | |||
31 | if USE_COVERAGE | 40 | if USE_COVERAGE |
32 | AM_CFLAGS = --coverage -O0 | 41 | AM_CFLAGS = --coverage -O0 |
33 | endif | 42 | endif |
@@ -154,8 +163,10 @@ plugin_LTLIBRARIES = \ | |||
154 | libgnunet_plugin_transport_tcp.la \ | 163 | libgnunet_plugin_transport_tcp.la \ |
155 | libgnunet_plugin_transport_udp.la \ | 164 | libgnunet_plugin_transport_udp.la \ |
156 | $(UNIX_PLUGIN_LA) \ | 165 | $(UNIX_PLUGIN_LA) \ |
157 | $(HTTP_PLUGIN_LA) \ | 166 | $(HTTP_CLIENT_PLUGIN_LA) \ |
158 | $(HTTPS_PLUGIN_LA) \ | 167 | $(HTTPS_CLIENT_PLUGIN_LA) \ |
168 | $(HTTP_SERVER_PLUGIN_LA) \ | ||
169 | $(HTTPS_SERVER_PLUGIN_LA) \ | ||
159 | $(WLAN_PLUGIN_LA) \ | 170 | $(WLAN_PLUGIN_LA) \ |
160 | libgnunet_plugin_transport_template.la | 171 | libgnunet_plugin_transport_template.la |
161 | 172 | ||
@@ -214,43 +225,69 @@ libgnunet_plugin_transport_unix_la_LIBADD = \ | |||
214 | $(LTLIBINTL) | 225 | $(LTLIBINTL) |
215 | libgnunet_plugin_transport_unix_la_LDFLAGS = \ | 226 | libgnunet_plugin_transport_unix_la_LDFLAGS = \ |
216 | $(GN_PLUGIN_LDFLAGS) | 227 | $(GN_PLUGIN_LDFLAGS) |
217 | 228 | ||
218 | libgnunet_plugin_transport_http_la_SOURCES = \ | 229 | |
219 | plugin_transport_http.c plugin_transport_http.h \ | 230 | libgnunet_plugin_transport_http_client_la_SOURCES = \ |
220 | plugin_transport_http_client.c plugin_transport_http_server.c | 231 | plugin_transport_http_client.c |
221 | libgnunet_plugin_transport_http_la_LIBADD = \ | 232 | libgnunet_plugin_transport_http_client_la_LIBADD = \ |
222 | $(top_builddir)/src/hello/libgnunethello.la \ | 233 | $(top_builddir)/src/hello/libgnunethello.la \ |
223 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ | 234 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ |
224 | $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ | 235 | $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ |
225 | @LIBCURL@ \ | 236 | @LIBCURL@ \ |
226 | $(top_builddir)/src/nat/libgnunetnat.la \ | 237 | $(top_builddir)/src/nat/libgnunetnat.la \ |
227 | $(top_builddir)/src/util/libgnunetutil.la | 238 | $(top_builddir)/src/util/libgnunetutil.la |
228 | libgnunet_plugin_transport_http_la_LDFLAGS = \ | 239 | libgnunet_plugin_transport_http_client_laLDFLAGS = \ |
229 | $(GN_LIBMHD) \ | ||
230 | $(GN_PLUGIN_LDFLAGS) | 240 | $(GN_PLUGIN_LDFLAGS) |
231 | libgnunet_plugin_transport_http_la_CFLAGS = \ | 241 | libgnunet_plugin_transport_http_client_la_CFLAGS = \ |
232 | $(CFLAGS) | 242 | $(CFLAGS) |
233 | libgnunet_plugin_transport_http_la_CPPFLAGS = \ | 243 | libgnunet_plugin_transport_http_client_la_CPPFLAGS = \ |
234 | @LIBCURL_CPPFLAGS@ | 244 | @LIBCURL_CPPFLAGS@ |
245 | |||
246 | |||
247 | libgnunet_plugin_transport_http_server_la_SOURCES = \ | ||
248 | plugin_transport_http_server.c | ||
249 | libgnunet_plugin_transport_http_server_la_LIBADD = \ | ||
250 | $(top_builddir)/src/hello/libgnunethello.la \ | ||
251 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ | ||
252 | $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ | ||
253 | $(top_builddir)/src/nat/libgnunetnat.la \ | ||
254 | $(top_builddir)/src/util/libgnunetutil.la | ||
255 | libgnunet_plugin_transport_http_server_la_LDFLAGS = \ | ||
256 | $(GN_LIBMHD) \ | ||
257 | $(GN_PLUGIN_LDFLAGS) | ||
258 | libgnunet_plugin_transport_http_server_la_CFLAGS = \ | ||
259 | $(CFLAGS) | ||
235 | 260 | ||
236 | libgnunet_plugin_transport_https_la_SOURCES = \ | 261 | libgnunet_plugin_transport_https_client_la_SOURCES = \ |
237 | plugin_transport_http.c plugin_transport_http.h \ | 262 | plugin_transport_http_client.c |
238 | plugin_transport_http_client.c plugin_transport_http_server.c | 263 | libgnunet_plugin_transport_https_client_la_LIBADD = \ |
239 | libgnunet_plugin_transport_https_la_LIBADD = \ | ||
240 | $(top_builddir)/src/hello/libgnunethello.la \ | 264 | $(top_builddir)/src/hello/libgnunethello.la \ |
241 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ | 265 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ |
242 | $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ | 266 | $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ |
243 | @LIBCURL@ \ | 267 | @LIBCURL@ \ |
244 | $(top_builddir)/src/nat/libgnunetnat.la \ | 268 | $(top_builddir)/src/nat/libgnunetnat.la \ |
245 | $(top_builddir)/src/util/libgnunetutil.la | 269 | $(top_builddir)/src/util/libgnunetutil.la |
246 | libgnunet_plugin_transport_https_la_LDFLAGS = \ | 270 | libgnunet_plugin_transport_https_client_laLDFLAGS = \ |
247 | $(GN_LIBMHD) \ | ||
248 | $(GN_PLUGIN_LDFLAGS) | 271 | $(GN_PLUGIN_LDFLAGS) |
249 | libgnunet_plugin_transport_https_la_CFLAGS = \ | 272 | libgnunet_plugin_transport_https_client_la_CFLAGS = \ |
250 | $(CFLAGS) -DBUILD_HTTPS | 273 | $(CFLAGS) |
251 | libgnunet_plugin_transport_https_la_CPPFLAGS = \ | 274 | libgnunet_plugin_transport_https_client_la_CPPFLAGS = \ |
252 | @LIBCURL_CPPFLAGS@ | 275 | @LIBCURL_CPPFLAGS@ |
253 | 276 | ||
277 | |||
278 | libgnunet_plugin_transport_https_server_la_SOURCES = \ | ||
279 | plugin_transport_http_server.c | ||
280 | libgnunet_plugin_transport_https_server_la_LIBADD = \ | ||
281 | $(top_builddir)/src/hello/libgnunethello.la \ | ||
282 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ | ||
283 | $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \ | ||
284 | $(top_builddir)/src/nat/libgnunetnat.la \ | ||
285 | $(top_builddir)/src/util/libgnunetutil.la | ||
286 | libgnunet_plugin_transport_https_server_la_LDFLAGS = \ | ||
287 | $(GN_LIBMHD) \ | ||
288 | $(GN_PLUGIN_LDFLAGS) | ||
289 | libgnunet_plugin_transport_https_server_la_CFLAGS = \ | ||
290 | $(CFLAGS) | ||
254 | 291 | ||
255 | check_PROGRAMS = \ | 292 | check_PROGRAMS = \ |
256 | test_transport_testing_startstop \ | 293 | test_transport_testing_startstop \ |
@@ -471,22 +508,6 @@ test_transport_api_timeout_unix_LDADD = \ | |||
471 | $(top_builddir)/src/util/libgnunetutil.la \ | 508 | $(top_builddir)/src/util/libgnunetutil.la \ |
472 | $(top_builddir)/src/transport/libgnunettransporttesting.la | 509 | $(top_builddir)/src/transport/libgnunettransporttesting.la |
473 | 510 | ||
474 | test_transport_api_timeout_http_SOURCES = \ | ||
475 | test_transport_api_timeout.c | ||
476 | test_transport_api_timeout_http_LDADD = \ | ||
477 | $(top_builddir)/src/transport/libgnunettransport.la \ | ||
478 | $(top_builddir)/src/hello/libgnunethello.la \ | ||
479 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
480 | $(top_builddir)/src/transport/libgnunettransporttesting.la | ||
481 | |||
482 | test_transport_api_timeout_https_SOURCES = \ | ||
483 | test_transport_api_timeout.c | ||
484 | test_transport_api_timeout_https_LDADD = \ | ||
485 | $(top_builddir)/src/transport/libgnunettransport.la \ | ||
486 | $(top_builddir)/src/hello/libgnunethello.la \ | ||
487 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
488 | $(top_builddir)/src/transport/libgnunettransporttesting.la | ||
489 | |||
490 | test_transport_api_reliability_tcp_nat_SOURCES = \ | 511 | test_transport_api_reliability_tcp_nat_SOURCES = \ |
491 | test_transport_api_reliability.c | 512 | test_transport_api_reliability.c |
492 | test_transport_api_reliability_tcp_nat_LDADD = \ | 513 | test_transport_api_reliability_tcp_nat_LDADD = \ |
@@ -543,6 +564,26 @@ test_transport_api_unix_LDADD = \ | |||
543 | $(top_builddir)/src/util/libgnunetutil.la \ | 564 | $(top_builddir)/src/util/libgnunetutil.la \ |
544 | $(top_builddir)/src/transport/libgnunettransporttesting.la | 565 | $(top_builddir)/src/transport/libgnunettransporttesting.la |
545 | 566 | ||
567 | # HTTP/S tests | ||
568 | if FALSE | ||
569 | |||
570 | test_transport_api_timeout_http_SOURCES = \ | ||
571 | test_transport_api_timeout.c | ||
572 | test_transport_api_timeout_http_LDADD = \ | ||
573 | $(top_builddir)/src/transport/libgnunettransport.la \ | ||
574 | $(top_builddir)/src/hello/libgnunethello.la \ | ||
575 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
576 | $(top_builddir)/src/transport/libgnunettransporttesting.la | ||
577 | |||
578 | test_transport_api_timeout_https_SOURCES = \ | ||
579 | test_transport_api_timeout.c | ||
580 | test_transport_api_timeout_https_LDADD = \ | ||
581 | $(top_builddir)/src/transport/libgnunettransport.la \ | ||
582 | $(top_builddir)/src/hello/libgnunethello.la \ | ||
583 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
584 | $(top_builddir)/src/transport/libgnunettransporttesting.la | ||
585 | |||
586 | |||
546 | test_transport_api_http_SOURCES = \ | 587 | test_transport_api_http_SOURCES = \ |
547 | test_transport_api.c | 588 | test_transport_api.c |
548 | test_transport_api_http_LDADD = \ | 589 | test_transport_api_http_LDADD = \ |
@@ -607,6 +648,41 @@ test_transport_api_reliability_https_nat_LDADD = \ | |||
607 | $(top_builddir)/src/util/libgnunetutil.la \ | 648 | $(top_builddir)/src/util/libgnunetutil.la \ |
608 | $(top_builddir)/src/transport/libgnunettransporttesting.la | 649 | $(top_builddir)/src/transport/libgnunettransporttesting.la |
609 | 650 | ||
651 | test_quota_compliance_http_SOURCES = \ | ||
652 | test_quota_compliance.c | ||
653 | test_quota_compliance_http_LDADD = \ | ||
654 | $(top_builddir)/src/transport/libgnunettransport.la \ | ||
655 | $(top_builddir)/src/hello/libgnunethello.la \ | ||
656 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
657 | $(top_builddir)/src/transport/libgnunettransporttesting.la | ||
658 | |||
659 | test_quota_compliance_http_asymmetric_SOURCES = \ | ||
660 | test_quota_compliance.c | ||
661 | test_quota_compliance_http_asymmetric_LDADD = \ | ||
662 | $(top_builddir)/src/transport/libgnunettransport.la \ | ||
663 | $(top_builddir)/src/hello/libgnunethello.la \ | ||
664 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
665 | $(top_builddir)/src/transport/libgnunettransporttesting.la | ||
666 | |||
667 | test_quota_compliance_https_SOURCES = \ | ||
668 | test_quota_compliance.c | ||
669 | test_quota_compliance_https_LDADD = \ | ||
670 | $(top_builddir)/src/transport/libgnunettransport.la \ | ||
671 | $(top_builddir)/src/hello/libgnunethello.la \ | ||
672 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
673 | $(top_builddir)/src/transport/libgnunettransporttesting.la | ||
674 | |||
675 | test_quota_compliance_https_asymmetric_SOURCES = \ | ||
676 | test_quota_compliance.c | ||
677 | test_quota_compliance_https_asymmetric_LDADD = \ | ||
678 | $(top_builddir)/src/transport/libgnunettransport.la \ | ||
679 | $(top_builddir)/src/hello/libgnunethello.la \ | ||
680 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
681 | $(top_builddir)/src/transport/libgnunettransporttesting.la | ||
682 | |||
683 | |||
684 | endif | ||
685 | |||
610 | test_transport_api_unreliability_unix_SOURCES = \ | 686 | test_transport_api_unreliability_unix_SOURCES = \ |
611 | test_transport_api_unreliability.c | 687 | test_transport_api_unreliability.c |
612 | test_transport_api_unreliability_unix_LDADD = \ | 688 | test_transport_api_unreliability_unix_LDADD = \ |
@@ -657,38 +733,6 @@ test_quota_compliance_tcp_asymmetric_LDADD = \ | |||
657 | $(top_builddir)/src/util/libgnunetutil.la \ | 733 | $(top_builddir)/src/util/libgnunetutil.la \ |
658 | $(top_builddir)/src/transport/libgnunettransporttesting.la | 734 | $(top_builddir)/src/transport/libgnunettransporttesting.la |
659 | 735 | ||
660 | test_quota_compliance_http_SOURCES = \ | ||
661 | test_quota_compliance.c | ||
662 | test_quota_compliance_http_LDADD = \ | ||
663 | $(top_builddir)/src/transport/libgnunettransport.la \ | ||
664 | $(top_builddir)/src/hello/libgnunethello.la \ | ||
665 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
666 | $(top_builddir)/src/transport/libgnunettransporttesting.la | ||
667 | |||
668 | test_quota_compliance_http_asymmetric_SOURCES = \ | ||
669 | test_quota_compliance.c | ||
670 | test_quota_compliance_http_asymmetric_LDADD = \ | ||
671 | $(top_builddir)/src/transport/libgnunettransport.la \ | ||
672 | $(top_builddir)/src/hello/libgnunethello.la \ | ||
673 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
674 | $(top_builddir)/src/transport/libgnunettransporttesting.la | ||
675 | |||
676 | test_quota_compliance_https_SOURCES = \ | ||
677 | test_quota_compliance.c | ||
678 | test_quota_compliance_https_LDADD = \ | ||
679 | $(top_builddir)/src/transport/libgnunettransport.la \ | ||
680 | $(top_builddir)/src/hello/libgnunethello.la \ | ||
681 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
682 | $(top_builddir)/src/transport/libgnunettransporttesting.la | ||
683 | |||
684 | test_quota_compliance_https_asymmetric_SOURCES = \ | ||
685 | test_quota_compliance.c | ||
686 | test_quota_compliance_https_asymmetric_LDADD = \ | ||
687 | $(top_builddir)/src/transport/libgnunettransport.la \ | ||
688 | $(top_builddir)/src/hello/libgnunethello.la \ | ||
689 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
690 | $(top_builddir)/src/transport/libgnunettransporttesting.la | ||
691 | |||
692 | test_quota_compliance_udp_SOURCES = \ | 736 | test_quota_compliance_udp_SOURCES = \ |
693 | test_quota_compliance.c | 737 | test_quota_compliance.c |
694 | test_quota_compliance_udp_LDADD = \ | 738 | test_quota_compliance_udp_LDADD = \ |
diff --git a/src/transport/plugin_transport_http.c b/src/transport/plugin_transport_http.c index af0d9fcf8..7f78f0e4f 100644 --- a/src/transport/plugin_transport_http.c +++ b/src/transport/plugin_transport_http.c | |||
@@ -53,43 +53,6 @@ struct HttpAddressWrapper | |||
53 | }; | 53 | }; |
54 | 54 | ||
55 | /** | 55 | /** |
56 | * Wrapper to manage IPv4 addresses | ||
57 | */ | ||
58 | struct IPv4HttpAddressWrapper | ||
59 | { | ||
60 | /** | ||
61 | * Linked list next | ||
62 | */ | ||
63 | struct IPv4HttpAddressWrapper *next; | ||
64 | |||
65 | /** | ||
66 | * Linked list previous | ||
67 | */ | ||
68 | struct IPv4HttpAddressWrapper *prev; | ||
69 | |||
70 | struct IPv4HttpAddress addr; | ||
71 | }; | ||
72 | |||
73 | /** | ||
74 | * Wrapper for IPv4 addresses. | ||
75 | */ | ||
76 | struct IPv6HttpAddressWrapper | ||
77 | { | ||
78 | /** | ||
79 | * Linked list next | ||
80 | */ | ||
81 | struct IPv6HttpAddressWrapper *next; | ||
82 | |||
83 | /** | ||
84 | * Linked list previous | ||
85 | */ | ||
86 | struct IPv6HttpAddressWrapper *prev; | ||
87 | |||
88 | struct IPv6HttpAddress addr6; | ||
89 | }; | ||
90 | |||
91 | |||
92 | /** | ||
93 | * Context for address to string conversion. | 56 | * Context for address to string conversion. |
94 | */ | 57 | */ |
95 | struct PrettyPrinterContext | 58 | struct PrettyPrinterContext |
@@ -144,52 +107,6 @@ static void | |||
144 | stop_session_timeout (struct Session *s); | 107 | stop_session_timeout (struct Session *s); |
145 | 108 | ||
146 | /** | 109 | /** |
147 | * Append our port and forward the result. | ||
148 | * | ||
149 | * @param cls the 'struct PrettyPrinterContext*' | ||
150 | * @param hostname hostname part of the address | ||
151 | */ | ||
152 | static void | ||
153 | append_port (void *cls, const char *hostname) | ||
154 | { | ||
155 | struct PrettyPrinterContext *ppc = cls; | ||
156 | static char rbuf[INET6_ADDRSTRLEN + 13]; | ||
157 | |||
158 | if (hostname == NULL) | ||
159 | { | ||
160 | ppc->asc (ppc->asc_cls, NULL); | ||
161 | GNUNET_free (ppc); | ||
162 | return; | ||
163 | } | ||
164 | |||
165 | #if !BUILD_HTTPS | ||
166 | const char *protocol = "http"; | ||
167 | #else | ||
168 | const char *protocol = "https"; | ||
169 | #endif | ||
170 | GNUNET_assert ((strlen (hostname) + 7) < (INET6_ADDRSTRLEN + 13)); | ||
171 | if (ppc->addrlen == sizeof (struct IPv6HttpAddress)) | ||
172 | { | ||
173 | if (ppc->numeric == GNUNET_YES) | ||
174 | GNUNET_snprintf (rbuf, sizeof (rbuf), "%s://[%s]:%u/", protocol, hostname, ppc->port); | ||
175 | else | ||
176 | { | ||
177 | if (strchr(hostname, ':') != NULL) | ||
178 | GNUNET_snprintf (rbuf, sizeof (rbuf), "%s://[%s]:%u/", protocol, hostname, ppc->port); | ||
179 | else | ||
180 | GNUNET_snprintf (rbuf, sizeof (rbuf), "%s://%s:%u/", protocol, hostname, ppc->port); | ||
181 | } | ||
182 | } | ||
183 | else if (ppc->addrlen == sizeof (struct IPv4HttpAddress)) | ||
184 | GNUNET_snprintf (rbuf, sizeof (rbuf), "%s://%s:%u/", protocol, hostname, ppc->port); | ||
185 | ppc->asc (ppc->asc_cls, rbuf); | ||
186 | } | ||
187 | |||
188 | |||
189 | |||
190 | |||
191 | |||
192 | /** | ||
193 | * Convert the transports address to a nice, human-readable | 110 | * Convert the transports address to a nice, human-readable |
194 | * format. | 111 | * format. |
195 | * | 112 | * |
@@ -212,62 +129,16 @@ http_plugin_address_pretty_printer (void *cls, const char *type, | |||
212 | void *asc_cls) | 129 | void *asc_cls) |
213 | { | 130 | { |
214 | GNUNET_assert (cls != NULL); | 131 | GNUNET_assert (cls != NULL); |
215 | struct PrettyPrinterContext *ppc; | 132 | struct HttpAddress *haddr = (struct HttpAddress *) addr; |
216 | const void *sb; | ||
217 | struct sockaddr_in s4; | ||
218 | struct sockaddr_in6 s6; | ||
219 | size_t sbs; | ||
220 | uint16_t port = 0; | ||
221 | |||
222 | if ((addrlen == sizeof (struct IPv6HttpAddress)) && (addr != NULL)) | ||
223 | { | ||
224 | struct IPv6HttpAddress *a6 = (struct IPv6HttpAddress *) addr; | ||
225 | s6.sin6_family = AF_INET6; | ||
226 | s6.sin6_addr = a6->ipv6_addr; | ||
227 | s6.sin6_port = a6->u6_port; | ||
228 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
229 | s6.sin6_len = sizeof (struct sockaddr_in6); | ||
230 | #endif | ||
231 | sb = &s6; | ||
232 | sbs = sizeof (struct sockaddr_in6); | ||
233 | port = ntohs (a6->u6_port); | ||
234 | |||
235 | } | ||
236 | else if ((addrlen == sizeof (struct IPv4HttpAddress)) && (addr != NULL)) | ||
237 | { | ||
238 | struct IPv4HttpAddress *a4 = (struct IPv4HttpAddress *) addr; | ||
239 | 133 | ||
240 | s4.sin_family = AF_INET; | 134 | if (addrlen < (sizeof (struct HttpAddress))) |
241 | s4.sin_addr.s_addr = a4->ipv4_addr; | ||
242 | s4.sin_port = a4->u4_port; | ||
243 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
244 | s4.sin_len = sizeof (struct sockaddr_in); | ||
245 | #endif | ||
246 | sb = &s4; | ||
247 | sbs = sizeof (struct sockaddr_in); | ||
248 | port = ntohs (a4->u4_port); | ||
249 | } | ||
250 | else if (0 == addrlen) | ||
251 | { | ||
252 | asc (asc_cls, "<inbound connection>"); | ||
253 | asc (asc_cls, NULL); | ||
254 | return; | ||
255 | } | ||
256 | else | ||
257 | { | 135 | { |
258 | /* invalid address */ | 136 | /* invalid address */ |
259 | GNUNET_break_op (0); | 137 | GNUNET_break_op (0); |
260 | asc (asc_cls, NULL); | 138 | asc (asc_cls, NULL); |
261 | return; | 139 | return; |
262 | } | 140 | } |
263 | ppc = GNUNET_malloc (sizeof (struct PrettyPrinterContext)); | 141 | asc (asc_cls, haddr->addr); |
264 | ppc->asc = asc; | ||
265 | ppc->asc_cls = asc_cls; | ||
266 | ppc->port = port; | ||
267 | ppc->plugin = cls; | ||
268 | ppc->addrlen = addrlen; | ||
269 | ppc->numeric = numeric; | ||
270 | GNUNET_RESOLVER_hostname_get (sb, sbs, !numeric, timeout, &append_port, ppc); | ||
271 | } | 142 | } |
272 | 143 | ||
273 | 144 | ||
@@ -288,51 +159,24 @@ static int | |||
288 | http_plugin_address_suggested (void *cls, const void *addr, size_t addrlen) | 159 | http_plugin_address_suggested (void *cls, const void *addr, size_t addrlen) |
289 | { | 160 | { |
290 | struct Plugin *plugin = cls; | 161 | struct Plugin *plugin = cls; |
291 | struct IPv4HttpAddressWrapper *w_tv4 = plugin->ipv4_addr_head; | 162 | struct HttpAddressWrapper *w = plugin->addr_head; |
292 | struct IPv6HttpAddressWrapper *w_tv6 = plugin->ipv6_addr_head; | 163 | struct HttpAddress *haddr = (struct HttpAddress *) addr; |
293 | 164 | ||
294 | GNUNET_assert (cls != NULL); | 165 | GNUNET_assert (cls != NULL); |
295 | if ((addrlen != sizeof (struct sockaddr_in)) || | ||
296 | (addrlen != sizeof (struct sockaddr_in6))) | ||
297 | return GNUNET_SYSERR; | ||
298 | 166 | ||
299 | if (addrlen == sizeof (struct IPv4HttpAddress)) | 167 | if (addrlen <= sizeof (struct HttpAddress)) |
300 | { | 168 | return GNUNET_SYSERR; |
301 | struct IPv4HttpAddress *a4 = (struct IPv4HttpAddress *) addr; | ||
302 | 169 | ||
303 | while (w_tv4 != NULL) | 170 | if (0 == (strcmp (plugin->ext_addr->addr, haddr->addr))) |
304 | { | ||
305 | if ((0 == | ||
306 | memcmp (&w_tv4->addr.ipv4_addr, &a4->ipv4_addr, | ||
307 | sizeof (struct in_addr))) && | ||
308 | (w_tv4->addr.u4_port == a4->u4_port)) | ||
309 | break; | ||
310 | w_tv4 = w_tv4->next; | ||
311 | } | ||
312 | if (w_tv4 != NULL) | ||
313 | return GNUNET_OK; | 171 | return GNUNET_OK; |
314 | else | ||
315 | return GNUNET_SYSERR; | ||
316 | } | ||
317 | if (addrlen == sizeof (struct sockaddr_in6)) | ||
318 | { | ||
319 | struct IPv6HttpAddress *a6 = (struct IPv6HttpAddress *) addr; | ||
320 | 172 | ||
321 | while (w_tv6 != NULL) | 173 | while (NULL != w) |
322 | { | 174 | { |
323 | if ((0 == | 175 | if (0 == (strcmp (w->addr->addr, haddr->addr))) |
324 | memcmp (&w_tv6->addr6.ipv6_addr, &a6->ipv6_addr, | 176 | return GNUNET_OK; |
325 | sizeof (struct in6_addr))) && | 177 | w = w->next; |
326 | (w_tv6->addr6.u6_port == a6->u6_port)) | ||
327 | break; | ||
328 | w_tv6 = w_tv6->next; | ||
329 | } | ||
330 | if (w_tv6 != NULL) | ||
331 | return GNUNET_OK; | ||
332 | else | ||
333 | return GNUNET_SYSERR; | ||
334 | } | 178 | } |
335 | return GNUNET_OK; | 179 | return GNUNET_SYSERR; |
336 | } | 180 | } |
337 | 181 | ||
338 | struct GNUNET_TIME_Relative | 182 | struct GNUNET_TIME_Relative |
@@ -381,6 +225,7 @@ http_string_to_address (void *cls, | |||
381 | void **buf, | 225 | void **buf, |
382 | size_t *added) | 226 | size_t *added) |
383 | { | 227 | { |
228 | #if 0 | ||
384 | #if !BUILD_HTTPS | 229 | #if !BUILD_HTTPS |
385 | char *protocol = "http"; | 230 | char *protocol = "http"; |
386 | #else | 231 | #else |
@@ -455,7 +300,8 @@ http_string_to_address (void *cls, | |||
455 | "Invalid address string `%s' to convert to address\n", | 300 | "Invalid address string `%s' to convert to address\n", |
456 | addr_str); | 301 | addr_str); |
457 | GNUNET_break (0); | 302 | GNUNET_break (0); |
458 | return GNUNET_SYSERR; | 303 | return GNUNET_SYSERR; |
304 | #endif | ||
459 | } | 305 | } |
460 | 306 | ||
461 | 307 | ||
@@ -473,57 +319,19 @@ http_string_to_address (void *cls, | |||
473 | const char * | 319 | const char * |
474 | http_plugin_address_to_string (void *cls, const void *addr, size_t addrlen) | 320 | http_plugin_address_to_string (void *cls, const void *addr, size_t addrlen) |
475 | { | 321 | { |
476 | 322 | struct HttpAddress *haddr; | |
477 | struct IPv4HttpAddress *a4; | 323 | if (addrlen < sizeof (struct HttpAddress)) |
478 | struct IPv6HttpAddress *a6; | ||
479 | char *address; | ||
480 | static char rbuf[INET6_ADDRSTRLEN + 13]; | ||
481 | uint16_t port; | ||
482 | int res = 0; | ||
483 | |||
484 | if (addrlen == sizeof (struct IPv6HttpAddress)) | ||
485 | { | ||
486 | a6 = (struct IPv6HttpAddress *) addr; | ||
487 | address = GNUNET_malloc (INET6_ADDRSTRLEN); | ||
488 | GNUNET_assert (NULL != | ||
489 | inet_ntop (AF_INET6, &a6->ipv6_addr, address, | ||
490 | INET6_ADDRSTRLEN)); | ||
491 | port = ntohs (a6->u6_port); | ||
492 | } | ||
493 | else if (addrlen == sizeof (struct IPv4HttpAddress)) | ||
494 | { | 324 | { |
495 | a4 = (struct IPv4HttpAddress *) addr; | 325 | /* invalid address */ |
496 | address = GNUNET_malloc (INET_ADDRSTRLEN); | 326 | GNUNET_break (0); |
497 | GNUNET_assert (NULL != | 327 | return NULL; |
498 | inet_ntop (AF_INET, &(a4->ipv4_addr), address, | ||
499 | INET_ADDRSTRLEN)); | ||
500 | port = ntohs (a4->u4_port); | ||
501 | } | 328 | } |
502 | else | 329 | else |
503 | { | 330 | { |
504 | /* invalid address */ | 331 | haddr = (struct HttpAddress *) addr; |
505 | GNUNET_break (0); | 332 | GNUNET_assert (NULL != haddr->addr); |
506 | return NULL; | 333 | return (const char *) haddr->addr; |
507 | } | 334 | } |
508 | #if !BUILD_HTTPS | ||
509 | char *protocol = "http"; | ||
510 | #else | ||
511 | char *protocol = "https"; | ||
512 | #endif | ||
513 | |||
514 | GNUNET_assert (strlen (address) + 7 < (INET6_ADDRSTRLEN + 13)); | ||
515 | if (addrlen == sizeof (struct IPv6HttpAddress)) | ||
516 | res = | ||
517 | GNUNET_snprintf (rbuf, sizeof (rbuf), "%s://[%s]:%u/", protocol, | ||
518 | address, port); | ||
519 | else if (addrlen == sizeof (struct IPv4HttpAddress)) | ||
520 | res = | ||
521 | GNUNET_snprintf (rbuf, sizeof (rbuf), "%s://%s:%u/", protocol, address, | ||
522 | port); | ||
523 | |||
524 | GNUNET_free (address); | ||
525 | GNUNET_assert (res != 0); | ||
526 | return rbuf; | ||
527 | } | 335 | } |
528 | 336 | ||
529 | 337 | ||
@@ -651,44 +459,16 @@ create_session (struct Plugin *plugin, const struct GNUNET_PeerIdentity *target, | |||
651 | struct Session *s = NULL; | 459 | struct Session *s = NULL; |
652 | struct GNUNET_ATS_Information ats; | 460 | struct GNUNET_ATS_Information ats; |
653 | 461 | ||
654 | GNUNET_assert ((addrlen == sizeof (struct IPv6HttpAddress)) || | 462 | /* |
655 | (addrlen == sizeof (struct IPv4HttpAddress))); | 463 | * ats = plugin->env->get_address_type (plugin->env->cls, (const struct sockaddr *) &s6, sizeof (struct sockaddr_in6)); |
656 | 464 | */ | |
657 | 465 | if (addrlen < sizeof (struct HttpAddress)) | |
658 | |||
659 | |||
660 | if (addrlen == sizeof (struct IPv4HttpAddress)) | ||
661 | { | 466 | { |
662 | struct IPv4HttpAddress *a4 = (struct IPv4HttpAddress *) addr; | 467 | GNUNET_break (0); |
663 | struct sockaddr_in s4; | ||
664 | |||
665 | if (0 == ntohs(a4->u4_port)) | ||
666 | return NULL; | 468 | return NULL; |
667 | |||
668 | s4.sin_family = AF_INET; | ||
669 | s4.sin_addr.s_addr = a4->ipv4_addr; | ||
670 | s4.sin_port = a4->u4_port; | ||
671 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
672 | s4.sin_len = sizeof (struct sockaddr_in); | ||
673 | #endif | ||
674 | ats = plugin->env->get_address_type (plugin->env->cls, (const struct sockaddr *) &s4, sizeof (struct sockaddr_in)); | ||
675 | } | 469 | } |
676 | if (addrlen == sizeof (struct IPv6HttpAddress)) | ||
677 | { | ||
678 | struct IPv6HttpAddress *a6 = (struct IPv6HttpAddress *) addr; | ||
679 | struct sockaddr_in6 s6; | ||
680 | 470 | ||
681 | if (0 == ntohs(a6->u6_port)) | ||
682 | return NULL; | ||
683 | 471 | ||
684 | s6.sin6_family = AF_INET6; | ||
685 | s6.sin6_addr = a6->ipv6_addr; | ||
686 | s6.sin6_port = a6->u6_port; | ||
687 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
688 | s6.sin6_len = sizeof (struct sockaddr_in6); | ||
689 | #endif | ||
690 | ats = plugin->env->get_address_type (plugin->env->cls, (const struct sockaddr *) &s6, sizeof (struct sockaddr_in6)); | ||
691 | } | ||
692 | 472 | ||
693 | s = GNUNET_malloc (sizeof (struct Session)); | 473 | s = GNUNET_malloc (sizeof (struct Session)); |
694 | memcpy (&s->target, target, sizeof (struct GNUNET_PeerIdentity)); | 474 | memcpy (&s->target, target, sizeof (struct GNUNET_PeerIdentity)); |
@@ -756,8 +536,7 @@ http_get_session (void *cls, | |||
756 | /* create new session */ | 536 | /* create new session */ |
757 | addrlen = address->address_length; | 537 | addrlen = address->address_length; |
758 | 538 | ||
759 | GNUNET_assert ((addrlen == sizeof (struct IPv6HttpAddress)) || | 539 | GNUNET_assert (addrlen > sizeof (struct HttpAddress)); |
760 | (addrlen == sizeof (struct IPv4HttpAddress))); | ||
761 | 540 | ||
762 | s = create_session (plugin, &address->peer, address->address, address->address_length); | 541 | s = create_session (plugin, &address->peer, address->address, address->address_length); |
763 | 542 | ||
@@ -913,120 +692,49 @@ http_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *target) | |||
913 | static void * | 692 | static void * |
914 | find_address (struct Plugin *plugin, const struct sockaddr *addr, socklen_t addrlen) | 693 | find_address (struct Plugin *plugin, const struct sockaddr *addr, socklen_t addrlen) |
915 | { | 694 | { |
916 | int af; | 695 | struct HttpAddressWrapper *w = NULL; |
917 | struct IPv4HttpAddressWrapper *w_t4 = NULL; | 696 | char *saddr; |
918 | struct IPv6HttpAddressWrapper *w_t6 = NULL; | ||
919 | 697 | ||
920 | af = addr->sa_family; | 698 | GNUNET_asprintf(&saddr, "%s://%s", plugin->protocol, GNUNET_a2s (addr, addrlen)); |
921 | switch (af) | 699 | w = plugin->addr_head; |
700 | while (NULL != w) | ||
922 | { | 701 | { |
923 | case AF_INET: | 702 | if (0 == strcmp (saddr, w->addr->addr)) |
924 | w_t4 = plugin->ipv4_addr_head; | ||
925 | struct sockaddr_in *a4 = (struct sockaddr_in *) addr; | ||
926 | |||
927 | while (w_t4 != NULL) | ||
928 | { | ||
929 | int res = memcmp (&w_t4->addr.ipv4_addr, | ||
930 | &a4->sin_addr, | ||
931 | sizeof (struct in_addr)); | ||
932 | |||
933 | if (res == 0) | ||
934 | { | ||
935 | if (a4->sin_port != w_t4->addr.u4_port) | ||
936 | res = -1; | ||
937 | } | ||
938 | |||
939 | if (0 == res) | ||
940 | break; | 703 | break; |
941 | w_t4 = w_t4->next; | 704 | w = w->next; |
942 | } | ||
943 | return w_t4; | ||
944 | break; | ||
945 | case AF_INET6: | ||
946 | w_t6 = plugin->ipv6_addr_head; | ||
947 | struct sockaddr_in6 *a6 = (struct sockaddr_in6 *) addr; | ||
948 | |||
949 | while (w_t6) | ||
950 | { | ||
951 | int res = memcmp (&w_t6->addr6.ipv6_addr, &a6->sin6_addr, | ||
952 | sizeof (struct in6_addr)); | ||
953 | |||
954 | if (res == 0) | ||
955 | { | ||
956 | if (a6->sin6_port != w_t6->addr6.u6_port) | ||
957 | res = -1; | ||
958 | } | ||
959 | if (0 == res) | ||
960 | break; | ||
961 | w_t6 = w_t6->next; | ||
962 | } | ||
963 | return w_t6; | ||
964 | break; | ||
965 | default: | ||
966 | return NULL; | ||
967 | } | 705 | } |
968 | return NULL; | 706 | |
707 | GNUNET_free (saddr); | ||
708 | return w; | ||
969 | } | 709 | } |
970 | 710 | ||
971 | 711 | ||
712 | |||
713 | |||
972 | static void | 714 | static void |
973 | nat_add_address (void *cls, int add_remove, const struct sockaddr *addr, | 715 | nat_add_address (void *cls, int add_remove, const struct sockaddr *addr, |
974 | socklen_t addrlen) | 716 | socklen_t addrlen) |
975 | { | 717 | { |
976 | struct Plugin *plugin = cls; | 718 | struct Plugin *plugin = cls; |
977 | struct IPv4HttpAddressWrapper *w_t4 = NULL; | 719 | struct HttpAddressWrapper *w = NULL; |
978 | struct IPv6HttpAddressWrapper *w_t6 = NULL; | 720 | char *saddr; |
979 | int af; | 721 | size_t haddrlen; |
980 | |||
981 | af = addr->sa_family; | ||
982 | switch (af) | ||
983 | { | ||
984 | case AF_INET: | ||
985 | w_t4 = find_address (plugin, addr, addrlen); | ||
986 | if (w_t4 == NULL) | ||
987 | { | ||
988 | struct sockaddr_in *a4 = (struct sockaddr_in *) addr; | ||
989 | w_t4 = GNUNET_malloc (sizeof (struct IPv4HttpAddressWrapper)); | ||
990 | memcpy (&w_t4->addr.ipv4_addr, &a4->sin_addr, sizeof (struct in_addr)); | ||
991 | w_t4->addr.u4_port = a4->sin_port; | ||
992 | 722 | ||
993 | GNUNET_CONTAINER_DLL_insert (plugin->ipv4_addr_head, | 723 | GNUNET_asprintf(&saddr, "%s://%s", plugin->protocol, GNUNET_a2s (addr, addrlen)); |
994 | plugin->ipv4_addr_tail, w_t4); | ||
995 | |||
996 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
997 | "Notifying transport to add IPv4 address `%s'\n", | ||
998 | http_plugin_address_to_string (NULL, &w_t4->addr, | ||
999 | sizeof (struct | ||
1000 | IPv4HttpAddress))); | ||
1001 | plugin->env->notify_address (plugin->env->cls, add_remove, &w_t4->addr, | ||
1002 | sizeof (struct IPv4HttpAddress)); | ||
1003 | } | ||
1004 | break; | ||
1005 | case AF_INET6: | ||
1006 | w_t6 = find_address (plugin, addr, addrlen); | ||
1007 | if (w_t6 == NULL) | ||
1008 | { | ||
1009 | w_t6 = GNUNET_malloc (sizeof (struct IPv6HttpAddressWrapper)); | ||
1010 | struct sockaddr_in6 *a6 = (struct sockaddr_in6 *) addr; | ||
1011 | memcpy (&w_t6->addr6.ipv6_addr, &a6->sin6_addr, sizeof (struct in6_addr)); | ||
1012 | w_t6->addr6.u6_port = a6->sin6_port; | ||
1013 | 724 | ||
1014 | GNUNET_CONTAINER_DLL_insert (plugin->ipv6_addr_head, | 725 | haddrlen = sizeof (struct HttpAddress) + strlen(saddr) + 1; |
1015 | plugin->ipv6_addr_tail, w_t6); | 726 | w = GNUNET_malloc (sizeof (struct HttpAddressWrapper)); |
727 | w->addr = GNUNET_malloc (haddrlen); | ||
728 | w->addr->addr = &w->addr[1]; | ||
729 | w->addr->addr_len = htonl (strlen(saddr) + 1); | ||
730 | memcpy (w->addr->addr, saddr, strlen(saddr) + 1); | ||
731 | GNUNET_free (saddr); | ||
1016 | 732 | ||
1017 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | 733 | GNUNET_CONTAINER_DLL_insert(plugin->addr_head, plugin->addr_tail, w); |
1018 | "Notifying transport to add IPv6 address `%s'\n", | 734 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, |
1019 | http_plugin_address_to_string (NULL, &w_t6->addr6, | 735 | "Notifying transport to add address `%s'\n", w->addr->addr); |
1020 | sizeof (struct | ||
1021 | IPv6HttpAddress))); | ||
1022 | plugin->env->notify_address (plugin->env->cls, add_remove, &w_t6->addr6, | ||
1023 | sizeof (struct IPv6HttpAddress)); | ||
1024 | } | ||
1025 | break; | ||
1026 | default: | ||
1027 | return; | ||
1028 | } | ||
1029 | 736 | ||
737 | plugin->env->notify_address (plugin->env->cls, add_remove, w->addr, haddrlen); | ||
1030 | } | 738 | } |
1031 | 739 | ||
1032 | 740 | ||
@@ -1035,52 +743,23 @@ nat_remove_address (void *cls, int add_remove, const struct sockaddr *addr, | |||
1035 | socklen_t addrlen) | 743 | socklen_t addrlen) |
1036 | { | 744 | { |
1037 | struct Plugin *plugin = cls; | 745 | struct Plugin *plugin = cls; |
1038 | struct IPv4HttpAddressWrapper *w_t4 = NULL; | 746 | struct HttpAddressWrapper *w = NULL; |
1039 | struct IPv6HttpAddressWrapper *w_t6 = NULL; | 747 | size_t haddrlen; |
1040 | int af; | ||
1041 | 748 | ||
1042 | af = addr->sa_family; | 749 | w = find_address (plugin, addr, addrlen); |
1043 | switch (af) | 750 | if (NULL == w) |
1044 | { | 751 | return; |
1045 | case AF_INET: | ||
1046 | w_t4 = find_address (plugin, addr, addrlen); | ||
1047 | if (w_t4 == NULL) | ||
1048 | return; | ||
1049 | |||
1050 | |||
1051 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
1052 | "Notifying transport to remove IPv4 address `%s'\n", | ||
1053 | http_plugin_address_to_string (NULL, &w_t4->addr, | ||
1054 | sizeof (struct | ||
1055 | IPv4HttpAddress))); | ||
1056 | plugin->env->notify_address (plugin->env->cls, add_remove, &w_t4->addr, | ||
1057 | sizeof (struct IPv4HttpAddress)); | ||
1058 | |||
1059 | GNUNET_CONTAINER_DLL_remove (plugin->ipv4_addr_head, plugin->ipv4_addr_tail, | ||
1060 | w_t4); | ||
1061 | GNUNET_free (w_t4); | ||
1062 | break; | ||
1063 | case AF_INET6: | ||
1064 | w_t6 = find_address (plugin, addr, addrlen); | ||
1065 | if (w_t6 == NULL) | ||
1066 | return; | ||
1067 | 752 | ||
1068 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | 753 | haddrlen = sizeof (struct HttpAddress) + ntohl (w->addr->addr_len); |
1069 | "Notifying transport to remove IPv6 address `%s'\n", | 754 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, |
1070 | http_plugin_address_to_string (NULL, &w_t6->addr6, | 755 | "Notifying transport to remove address `%s'\n", http_plugin_address_to_string(NULL, w->addr, haddrlen)); |
1071 | sizeof (struct | ||
1072 | IPv6HttpAddress))); | ||
1073 | 756 | ||
1074 | plugin->env->notify_address (plugin->env->cls, add_remove, &w_t6->addr6, | ||
1075 | sizeof (struct IPv6HttpAddress)); | ||
1076 | 757 | ||
1077 | GNUNET_CONTAINER_DLL_remove (plugin->ipv6_addr_head, plugin->ipv6_addr_tail, | 758 | GNUNET_CONTAINER_DLL_remove (plugin->addr_head, plugin->addr_tail, w); |
1078 | w_t6); | 759 | plugin->env->notify_address (plugin->env->cls, add_remove, w->addr, |
1079 | GNUNET_free (w_t6); | 760 | sizeof (struct HttpAddress) + ntohl (w->addr->addr_len)); |
1080 | break; | 761 | GNUNET_free (w->addr); |
1081 | default: | 762 | GNUNET_free (w); |
1082 | return; | ||
1083 | } | ||
1084 | } | 763 | } |
1085 | 764 | ||
1086 | 765 | ||
@@ -1371,23 +1050,14 @@ stop_report_addresses (struct Plugin *plugin) | |||
1371 | GNUNET_NAT_unregister (plugin->nat); | 1050 | GNUNET_NAT_unregister (plugin->nat); |
1372 | 1051 | ||
1373 | /* Clean up addresses */ | 1052 | /* Clean up addresses */ |
1374 | struct IPv4HttpAddressWrapper *w_t4; | 1053 | struct HttpAddressWrapper *w; |
1375 | struct IPv6HttpAddressWrapper *w_t6; | ||
1376 | 1054 | ||
1377 | while (plugin->ipv4_addr_head != NULL) | 1055 | while (plugin->addr_head != NULL) |
1378 | { | 1056 | { |
1379 | w_t4 = plugin->ipv4_addr_head; | 1057 | w = plugin->addr_head; |
1380 | GNUNET_CONTAINER_DLL_remove (plugin->ipv4_addr_head, plugin->ipv4_addr_tail, | 1058 | GNUNET_CONTAINER_DLL_remove (plugin->addr_head, plugin->addr_tail, w); |
1381 | w_t4); | 1059 | GNUNET_free (w->addr); |
1382 | GNUNET_free (w_t4); | 1060 | GNUNET_free (w); |
1383 | } | ||
1384 | |||
1385 | while (plugin->ipv6_addr_head != NULL) | ||
1386 | { | ||
1387 | w_t6 = plugin->ipv6_addr_head; | ||
1388 | GNUNET_CONTAINER_DLL_remove (plugin->ipv6_addr_head, plugin->ipv6_addr_tail, | ||
1389 | w_t6); | ||
1390 | GNUNET_free (w_t6); | ||
1391 | } | 1061 | } |
1392 | } | 1062 | } |
1393 | 1063 | ||
@@ -1403,6 +1073,7 @@ notify_external_hostname (void *cls, const struct GNUNET_SCHEDULER_TaskContext * | |||
1403 | { | 1073 | { |
1404 | struct Plugin *plugin = cls; | 1074 | struct Plugin *plugin = cls; |
1405 | struct HttpAddress *eaddr; | 1075 | struct HttpAddress *eaddr; |
1076 | char *addr; | ||
1406 | size_t eaddr_len; | 1077 | size_t eaddr_len; |
1407 | size_t uri_len; | 1078 | size_t uri_len; |
1408 | 1079 | ||
@@ -1411,12 +1082,17 @@ notify_external_hostname (void *cls, const struct GNUNET_SCHEDULER_TaskContext * | |||
1411 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | 1082 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) |
1412 | return; | 1083 | return; |
1413 | 1084 | ||
1414 | uri_len = strlen (plugin->external_hostname) + 1; | 1085 | GNUNET_asprintf(&addr, "%s://%s", plugin->protocol, plugin->external_hostname); |
1086 | uri_len = strlen (addr) + 1; | ||
1415 | eaddr_len = sizeof (struct HttpAddress) + uri_len; | 1087 | eaddr_len = sizeof (struct HttpAddress) + uri_len; |
1416 | eaddr = GNUNET_malloc (eaddr_len); | 1088 | eaddr = GNUNET_malloc (eaddr_len); |
1417 | eaddr->addr_len = htonl (strlen (plugin->external_hostname) + 1); | 1089 | eaddr->addr_len = htonl (uri_len); |
1418 | eaddr->addr = (void *) &eaddr[1]; | 1090 | eaddr->addr = (void *) &eaddr[1]; |
1419 | memcpy (&eaddr->addr, plugin->external_hostname, uri_len); | 1091 | memcpy (&eaddr->addr, addr, uri_len); |
1092 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, | ||
1093 | "Notifying transport about external hostname address `%s'\n", addr); | ||
1094 | |||
1095 | GNUNET_free (addr); | ||
1420 | plugin->env->notify_address (plugin->env->cls, GNUNET_YES, eaddr, eaddr_len); | 1096 | plugin->env->notify_address (plugin->env->cls, GNUNET_YES, eaddr, eaddr_len); |
1421 | plugin->ext_addr = eaddr; | 1097 | plugin->ext_addr = eaddr; |
1422 | plugin->ext_addr_len = eaddr_len; | 1098 | plugin->ext_addr_len = eaddr_len; |
diff --git a/src/transport/plugin_transport_http.h b/src/transport/plugin_transport_http.h index 1469fd8a9..1ac2f9859 100644 --- a/src/transport/plugin_transport_http.h +++ b/src/transport/plugin_transport_http.h | |||
@@ -96,22 +96,13 @@ struct Plugin | |||
96 | /** | 96 | /** |
97 | * IPv4 addresses DLL head | 97 | * IPv4 addresses DLL head |
98 | */ | 98 | */ |
99 | struct IPv4HttpAddressWrapper *ipv4_addr_head; | 99 | struct HttpAddressWrapper *addr_head; |
100 | 100 | ||
101 | /** | 101 | /** |
102 | * IPv4 addresses DLL tail | 102 | * IPv4 addresses DLL tail |
103 | */ | 103 | */ |
104 | struct IPv4HttpAddressWrapper *ipv4_addr_tail; | 104 | struct HttpAddressWrapper *addr_tail; |
105 | 105 | ||
106 | /** | ||
107 | * IPv6 addresses DLL head | ||
108 | */ | ||
109 | struct IPv6HttpAddressWrapper *ipv6_addr_head; | ||
110 | |||
111 | /** | ||
112 | * IPv6 addresses DLL tail | ||
113 | */ | ||
114 | struct IPv6HttpAddressWrapper *ipv6_addr_tail; | ||
115 | 106 | ||
116 | /** | 107 | /** |
117 | * Plugin configuration | 108 | * Plugin configuration |
diff --git a/src/transport/plugin_transport_http_client.c b/src/transport/plugin_transport_http_client.c index ff23da974..f4790b0f6 100644 --- a/src/transport/plugin_transport_http_client.c +++ b/src/transport/plugin_transport_http_client.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet | 2 | This file is part of GNUnet |
3 | (C) 2002--2012 Christian Grothoff (and other contributing authors) | 3 | (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors) |
4 | 4 | ||
5 | GNUnet is free software; you can redistribute it and/or modify | 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 | 6 | it under the terms of the GNU General Public License as published |
@@ -20,626 +20,288 @@ | |||
20 | 20 | ||
21 | /** | 21 | /** |
22 | * @file transport/plugin_transport_http_client.c | 22 | * @file transport/plugin_transport_http_client.c |
23 | * @brief http transport service plugin | 23 | * @brief HTTP/S client transport plugin |
24 | * @author Matthias Wachs | 24 | * @author Matthias Wachs |
25 | */ | 25 | */ |
26 | 26 | ||
27 | #include "plugin_transport_http.h" | 27 | #if BUILD_HTTPS |
28 | #define LIBGNUNET_PLUGIN_TRANSPORT_INIT libgnunet_plugin_transport_https_client_init | ||
29 | #define LIBGNUNET_PLUGIN_TRANSPORT_DONE libgnunet_plugin_transport_https_client_done | ||
30 | #else | ||
31 | #define LIBGNUNET_PLUGIN_TRANSPORT_INIT libgnunet_plugin_transport_http_client_init | ||
32 | #define LIBGNUNET_PLUGIN_TRANSPORT_DONE libgnunet_plugin_transport_http_client_done | ||
33 | #endif | ||
34 | |||
28 | 35 | ||
29 | static struct Plugin * p; | 36 | #include "platform.h" |
37 | #include "gnunet_protocols.h" | ||
38 | #include "gnunet_connection_lib.h" | ||
39 | #include "gnunet_server_lib.h" | ||
40 | #include "gnunet_service_lib.h" | ||
41 | #include "gnunet_statistics_service.h" | ||
42 | #include "gnunet_transport_service.h" | ||
43 | #include "gnunet_transport_plugin.h" | ||
44 | |||
45 | #define DEBUG_TEMPLATE GNUNET_EXTRA_LOGGING | ||
30 | 46 | ||
31 | #if VERBOSE_CURL | ||
32 | /** | 47 | /** |
33 | * Function to log curl debug messages with GNUNET_log | 48 | * After how long do we expire an address that we |
34 | * @param curl handle | 49 | * learned from another peer if it is not reconfirmed |
35 | * @param type curl_infotype | 50 | * by anyone? |
36 | * @param data data | ||
37 | * @param size size | ||
38 | * @param cls closure | ||
39 | * @return 0 | ||
40 | */ | 51 | */ |
41 | static int | 52 | #define LEARNED_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 6) |
42 | client_log (CURL * curl, curl_infotype type, char *data, size_t size, void *cls) | 53 | |
43 | { | ||
44 | if (type == CURLINFO_TEXT) | ||
45 | { | ||
46 | char text[size + 2]; | ||
47 | |||
48 | memcpy (text, data, size); | ||
49 | if (text[size - 1] == '\n') | ||
50 | text[size] = '\0'; | ||
51 | else | ||
52 | { | ||
53 | text[size] = '\n'; | ||
54 | text[size + 1] = '\0'; | ||
55 | } | ||
56 | #if BUILD_HTTPS | ||
57 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-https", | ||
58 | "Client: %p - %s", cls, text); | ||
59 | #else | ||
60 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-http", | ||
61 | "Client: %p - %s", cls, text); | ||
62 | #endif | ||
63 | } | ||
64 | return 0; | ||
65 | } | ||
66 | #endif | ||
67 | 54 | ||
68 | /** | 55 | /** |
69 | * Task performing curl operations | 56 | * Encapsulation of all of the state of the plugin. |
70 | * @param cls plugin as closure | ||
71 | * @param tc gnunet scheduler task context | ||
72 | */ | 57 | */ |
73 | static void | 58 | struct Plugin; |
74 | client_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); | ||
75 | 59 | ||
76 | 60 | ||
77 | /** | 61 | /** |
78 | * Function setting up file descriptors and scheduling task to run | 62 | * Session handle for connections. |
79 | * | ||
80 | * @param plugin plugin as closure | ||
81 | * @param now schedule task in 1ms, regardless of what curl may say | ||
82 | * @return GNUNET_SYSERR for hard failure, GNUNET_OK for ok | ||
83 | */ | 63 | */ |
84 | static int | 64 | struct Session |
85 | client_schedule (struct Plugin *plugin, int now) | ||
86 | { | 65 | { |
87 | fd_set rs; | 66 | /** |
88 | fd_set ws; | 67 | * To whom are we talking to (set to our identity |
89 | fd_set es; | 68 | * if we are still waiting for the welcome message) |
90 | int max; | 69 | */ |
91 | struct GNUNET_NETWORK_FDSet *grs; | 70 | struct GNUNET_PeerIdentity sender; |
92 | struct GNUNET_NETWORK_FDSet *gws; | 71 | |
93 | long to; | 72 | /** |
94 | CURLMcode mret; | 73 | * Stored in a linked list. |
95 | struct GNUNET_TIME_Relative timeout; | 74 | */ |
96 | 75 | struct Session *next; | |
97 | /* Cancel previous scheduled task */ | 76 | |
98 | if (plugin->client_perform_task != GNUNET_SCHEDULER_NO_TASK) | 77 | /** |
99 | { | 78 | * Pointer to the global plugin struct. |
100 | GNUNET_SCHEDULER_cancel (plugin->client_perform_task); | 79 | */ |
101 | plugin->client_perform_task = GNUNET_SCHEDULER_NO_TASK; | 80 | struct Plugin *plugin; |
102 | } | 81 | |
103 | max = -1; | 82 | /** |
104 | FD_ZERO (&rs); | 83 | * The client (used to identify this connection) |
105 | FD_ZERO (&ws); | 84 | */ |
106 | FD_ZERO (&es); | 85 | /* void *client; */ |
107 | mret = curl_multi_fdset (plugin->client_mh, &rs, &ws, &es, &max); | 86 | |
108 | if (mret != CURLM_OK) | 87 | /** |
109 | { | 88 | * Continuation function to call once the transmission buffer |
110 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"), | 89 | * has again space available. NULL if there is no |
111 | "curl_multi_fdset", __FILE__, __LINE__, | 90 | * continuation to call. |
112 | curl_multi_strerror (mret)); | 91 | */ |
113 | return GNUNET_SYSERR; | 92 | GNUNET_TRANSPORT_TransmitContinuation transmit_cont; |
114 | } | 93 | |
115 | mret = curl_multi_timeout (plugin->client_mh, &to); | 94 | /** |
116 | if (to == -1) | 95 | * Closure for transmit_cont. |
117 | timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1); | 96 | */ |
118 | else | 97 | void *transmit_cont_cls; |
119 | timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, to); | 98 | |
120 | if (now == GNUNET_YES) | 99 | /** |
121 | timeout = GNUNET_TIME_UNIT_MILLISECONDS; | 100 | * At what time did we reset last_received last? |
122 | 101 | */ | |
123 | if (mret != CURLM_OK) | 102 | struct GNUNET_TIME_Absolute last_quota_update; |
124 | { | 103 | |
125 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"), | 104 | /** |
126 | "curl_multi_timeout", __FILE__, __LINE__, | 105 | * How many bytes have we received since the "last_quota_update" |
127 | curl_multi_strerror (mret)); | 106 | * timestamp? |
128 | return GNUNET_SYSERR; | 107 | */ |
129 | } | 108 | uint64_t last_received; |
130 | 109 | ||
131 | grs = GNUNET_NETWORK_fdset_create (); | 110 | /** |
132 | gws = GNUNET_NETWORK_fdset_create (); | 111 | * Number of bytes per ms that this peer is allowed |
133 | GNUNET_NETWORK_fdset_copy_native (grs, &rs, max + 1); | 112 | * to send to us. |
134 | GNUNET_NETWORK_fdset_copy_native (gws, &ws, max + 1); | 113 | */ |
135 | 114 | uint32_t quota; | |
136 | plugin->client_perform_task = | 115 | |
137 | GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, | 116 | }; |
138 | timeout, grs, gws, | ||
139 | &client_run, plugin); | ||
140 | GNUNET_NETWORK_fdset_destroy (gws); | ||
141 | GNUNET_NETWORK_fdset_destroy (grs); | ||
142 | return GNUNET_OK; | ||
143 | } | ||
144 | |||
145 | 117 | ||
146 | int | 118 | /** |
147 | client_send (struct Session *s, struct HTTP_Message *msg) | 119 | * Encapsulation of all of the state of the plugin. |
120 | */ | ||
121 | struct Plugin | ||
148 | { | 122 | { |
149 | GNUNET_assert (s != NULL); | 123 | /** |
150 | GNUNET_CONTAINER_DLL_insert_tail (s->msg_head, s->msg_tail, msg); | 124 | * Our environment. |
151 | 125 | */ | |
152 | if (GNUNET_YES != exist_session(p, s)) | 126 | struct GNUNET_TRANSPORT_PluginEnvironment *env; |
153 | { | ||
154 | GNUNET_break (0); | ||
155 | return GNUNET_SYSERR; | ||
156 | } | ||
157 | if (s->client_put_paused == GNUNET_YES) | ||
158 | { | ||
159 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, s->plugin->name, | ||
160 | "Client: %p was suspended, unpausing\n", s->client_put); | ||
161 | s->client_put_paused = GNUNET_NO; | ||
162 | curl_easy_pause (s->client_put, CURLPAUSE_CONT); | ||
163 | } | ||
164 | client_schedule (s->plugin, GNUNET_YES); | ||
165 | 127 | ||
166 | return GNUNET_OK; | 128 | /** |
167 | } | 129 | * List of open sessions. |
130 | */ | ||
131 | struct Session *sessions; | ||
132 | |||
133 | }; | ||
168 | 134 | ||
169 | 135 | ||
170 | /** | 136 | /** |
171 | * Task performing curl operations | 137 | * Function that can be used by the transport service to transmit |
138 | * a message using the plugin. Note that in the case of a | ||
139 | * peer disconnecting, the continuation MUST be called | ||
140 | * prior to the disconnect notification itself. This function | ||
141 | * will be called with this peer's HELLO message to initiate | ||
142 | * a fresh connection to another peer. | ||
172 | * | 143 | * |
173 | * @param cls plugin as closure | 144 | * @param cls closure |
174 | * @param tc gnunet scheduler task context | 145 | * @param session which session must be used |
146 | * @param msgbuf the message to transmit | ||
147 | * @param msgbuf_size number of bytes in 'msgbuf' | ||
148 | * @param priority how important is the message (most plugins will | ||
149 | * ignore message priority and just FIFO) | ||
150 | * @param to how long to wait at most for the transmission (does not | ||
151 | * require plugins to discard the message after the timeout, | ||
152 | * just advisory for the desired delay; most plugins will ignore | ||
153 | * this as well) | ||
154 | * @param cont continuation to call once the message has | ||
155 | * been transmitted (or if the transport is ready | ||
156 | * for the next transmission call; or if the | ||
157 | * peer disconnected...); can be NULL | ||
158 | * @param cont_cls closure for cont | ||
159 | * @return number of bytes used (on the physical network, with overheads); | ||
160 | * -1 on hard errors (i.e. address invalid); 0 is a legal value | ||
161 | * and does NOT mean that the message was not transmitted (DV) | ||
175 | */ | 162 | */ |
176 | static void | 163 | static ssize_t |
177 | client_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | 164 | http_client_plugin_send (void *cls, |
165 | struct Session *session, | ||
166 | const char *msgbuf, size_t msgbuf_size, | ||
167 | unsigned int priority, | ||
168 | struct GNUNET_TIME_Relative to, | ||
169 | GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls) | ||
178 | { | 170 | { |
179 | struct Plugin *plugin = cls; | 171 | struct Plugin *plugin = cls; |
180 | int running; | 172 | int bytes_sent = 0; |
181 | CURLMcode mret; | ||
182 | |||
183 | GNUNET_assert (cls != NULL); | ||
184 | |||
185 | plugin->client_perform_task = GNUNET_SCHEDULER_NO_TASK; | ||
186 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | ||
187 | return; | ||
188 | |||
189 | do | ||
190 | { | ||
191 | running = 0; | ||
192 | mret = curl_multi_perform (plugin->client_mh, &running); | ||
193 | |||
194 | CURLMsg *msg; | ||
195 | int msgs_left; | ||
196 | |||
197 | while ((msg = curl_multi_info_read (plugin->client_mh, &msgs_left))) | ||
198 | { | ||
199 | CURL *easy_h = msg->easy_handle; | ||
200 | struct Session *s = NULL; | ||
201 | char *d = (char *) s; | ||
202 | |||
203 | if (easy_h == NULL) | ||
204 | { | ||
205 | GNUNET_break (0); | ||
206 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
207 | "Client: connection to ended with reason %i: `%s', %i handles running\n", | ||
208 | msg->data.result, | ||
209 | curl_easy_strerror (msg->data.result), running); | ||
210 | continue; | ||
211 | } | ||
212 | |||
213 | GNUNET_assert (CURLE_OK == | ||
214 | curl_easy_getinfo (easy_h, CURLINFO_PRIVATE, &d)); | ||
215 | s = (struct Session *) d; | ||
216 | |||
217 | if (GNUNET_YES != exist_session(plugin, s)) | ||
218 | { | ||
219 | GNUNET_break (0); | ||
220 | return; | ||
221 | } | ||
222 | |||
223 | GNUNET_assert (s != NULL); | ||
224 | if (msg->msg == CURLMSG_DONE) | ||
225 | { | ||
226 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
227 | "Client: %p connection to '%s' %s ended with reason %i: `%s'\n", | ||
228 | msg->easy_handle, GNUNET_i2s (&s->target), | ||
229 | http_plugin_address_to_string (NULL, s->addr, | ||
230 | s->addrlen), | ||
231 | msg->data.result, | ||
232 | curl_easy_strerror (msg->data.result)); | ||
233 | |||
234 | /* Disconnect other transmission direction and tell transport */ | ||
235 | client_disconnect (s); | ||
236 | } | ||
237 | } | ||
238 | } | ||
239 | while (mret == CURLM_CALL_MULTI_PERFORM); | ||
240 | client_schedule (plugin, GNUNET_NO); | ||
241 | } | ||
242 | 173 | ||
174 | GNUNET_assert (plugin != NULL); | ||
175 | GNUNET_assert (session != NULL); | ||
243 | 176 | ||
244 | int | 177 | /* struct Plugin *plugin = cls; */ |
245 | client_disconnect (struct Session *s) | 178 | return bytes_sent; |
246 | { | ||
247 | int res = GNUNET_OK; | ||
248 | CURLMcode mret; | ||
249 | struct Plugin *plugin = s->plugin; | ||
250 | struct HTTP_Message *msg; | ||
251 | struct HTTP_Message *t; | ||
252 | |||
253 | if (GNUNET_YES != exist_session(plugin, s)) | ||
254 | { | ||
255 | GNUNET_break (0); | ||
256 | return GNUNET_SYSERR; | ||
257 | } | ||
258 | |||
259 | if (s->client_put != NULL) | ||
260 | { | ||
261 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
262 | "Client: %p / %p Deleting outbound PUT session to peer `%s'\n", | ||
263 | s, s->client_put, GNUNET_i2s (&s->target)); | ||
264 | |||
265 | /* remove curl handle from multi handle */ | ||
266 | mret = curl_multi_remove_handle (plugin->client_mh, s->client_put); | ||
267 | if (mret != CURLM_OK) | ||
268 | { | ||
269 | /* clean up easy handle, handle is now invalid and free'd */ | ||
270 | res = GNUNET_SYSERR; | ||
271 | GNUNET_break (0); | ||
272 | } | ||
273 | curl_easy_cleanup (s->client_put); | ||
274 | s->client_put = NULL; | ||
275 | } | ||
276 | |||
277 | |||
278 | if (s->recv_wakeup_task != GNUNET_SCHEDULER_NO_TASK) | ||
279 | { | ||
280 | GNUNET_SCHEDULER_cancel (s->recv_wakeup_task); | ||
281 | s->recv_wakeup_task = GNUNET_SCHEDULER_NO_TASK; | ||
282 | } | ||
283 | |||
284 | if (s->client_get != NULL) | ||
285 | { | ||
286 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
287 | "Client: %p / %p Deleting outbound GET session to peer `%s'\n", | ||
288 | s, | ||
289 | s->client_get, GNUNET_i2s (&s->target)); | ||
290 | |||
291 | /* remove curl handle from multi handle */ | ||
292 | mret = curl_multi_remove_handle (plugin->client_mh, s->client_get); | ||
293 | if (mret != CURLM_OK) | ||
294 | { | ||
295 | /* clean up easy handle, handle is now invalid and free'd */ | ||
296 | res = GNUNET_SYSERR; | ||
297 | GNUNET_break (0); | ||
298 | } | ||
299 | curl_easy_cleanup (s->client_get); | ||
300 | s->client_get = NULL; | ||
301 | } | ||
302 | |||
303 | msg = s->msg_head; | ||
304 | while (msg != NULL) | ||
305 | { | ||
306 | t = msg->next; | ||
307 | if (NULL != msg->transmit_cont) | ||
308 | msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_SYSERR); | ||
309 | GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg); | ||
310 | GNUNET_free (msg); | ||
311 | msg = t; | ||
312 | } | ||
313 | |||
314 | plugin->cur_connections -= 2; | ||
315 | |||
316 | notify_session_end (plugin, &s->target, s); | ||
317 | |||
318 | GNUNET_assert (plugin->outbound_sessions > 0); | ||
319 | plugin->outbound_sessions --; | ||
320 | GNUNET_STATISTICS_set (plugin->env->stats, | ||
321 | "# HTTP outbound sessions", | ||
322 | plugin->outbound_sessions, | ||
323 | GNUNET_NO); | ||
324 | |||
325 | /* Re-schedule since handles have changed */ | ||
326 | if (plugin->client_perform_task != GNUNET_SCHEDULER_NO_TASK) | ||
327 | { | ||
328 | GNUNET_SCHEDULER_cancel (plugin->client_perform_task); | ||
329 | plugin->client_perform_task = GNUNET_SCHEDULER_NO_TASK; | ||
330 | } | ||
331 | client_schedule (plugin, GNUNET_YES); | ||
332 | |||
333 | return res; | ||
334 | } | 179 | } |
335 | 180 | ||
336 | static int | ||
337 | client_receive_mst_cb (void *cls, void *client, | ||
338 | const struct GNUNET_MessageHeader *message) | ||
339 | { | ||
340 | struct Session *s = cls; | ||
341 | struct GNUNET_TIME_Relative delay; | ||
342 | |||
343 | if (GNUNET_YES != exist_session(p, s)) | ||
344 | { | ||
345 | GNUNET_break (0); | ||
346 | return GNUNET_OK; | ||
347 | } | ||
348 | |||
349 | delay = http_plugin_receive (s, &s->target, message, s, s->addr, s->addrlen); | ||
350 | s->next_receive = | ||
351 | GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), delay); | ||
352 | |||
353 | if (GNUNET_TIME_absolute_get ().abs_value < s->next_receive.abs_value) | ||
354 | { | ||
355 | struct Plugin *plugin = s->plugin; | ||
356 | |||
357 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
358 | "Client: peer `%s' address `%s' next read delayed for %llu ms\n", | ||
359 | GNUNET_i2s (&s->target), GNUNET_a2s (s->addr, s->addrlen), | ||
360 | delay); | ||
361 | } | ||
362 | return GNUNET_OK; | ||
363 | } | ||
364 | 181 | ||
365 | 182 | ||
183 | /** | ||
184 | * Function that can be used to force the plugin to disconnect | ||
185 | * from the given peer and cancel all previous transmissions | ||
186 | * (and their continuationc). | ||
187 | * | ||
188 | * @param cls closure | ||
189 | * @param target peer from which to disconnect | ||
190 | */ | ||
366 | static void | 191 | static void |
367 | client_wake_up (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | 192 | http_client_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *target) |
368 | { | 193 | { |
369 | struct Session *s = cls; | 194 | // struct Plugin *plugin = cls; |
370 | 195 | // FIXME | |
371 | if (GNUNET_YES != exist_session(p, s)) | ||
372 | { | ||
373 | GNUNET_break (0); | ||
374 | return; | ||
375 | } | ||
376 | s->recv_wakeup_task = GNUNET_SCHEDULER_NO_TASK; | ||
377 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | ||
378 | return; | ||
379 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, s->plugin->name, | ||
380 | "Client: %p Waking up receive handle\n", s->client_get); | ||
381 | if (s->client_get != NULL) | ||
382 | curl_easy_pause (s->client_get, CURLPAUSE_CONT); | ||
383 | } | 196 | } |
384 | 197 | ||
385 | 198 | ||
386 | /** | 199 | /** |
387 | * Callback method used with libcurl | 200 | * Convert the transports address to a nice, human-readable |
388 | * Method is called when libcurl needs to write data during sending | 201 | * format. |
389 | * | 202 | * |
390 | * @param stream pointer where to write data | 203 | * @param cls closure |
391 | * @param size size of an individual element | 204 | * @param type name of the transport that generated the address |
392 | * @param nmemb count of elements that can be written to the buffer | 205 | * @param addr one of the addresses of the host, NULL for the last address |
393 | * @param cls destination pointer, passed to the libcurl handle | 206 | * the specific address format depends on the transport |
394 | * @return bytes read from stream | 207 | * @param addrlen length of the address |
208 | * @param numeric should (IP) addresses be displayed in numeric form? | ||
209 | * @param timeout after how long should we give up? | ||
210 | * @param asc function to call on each string | ||
211 | * @param asc_cls closure for asc | ||
395 | */ | 212 | */ |
396 | static size_t | 213 | static void |
397 | client_receive (void *stream, size_t size, size_t nmemb, void *cls) | 214 | http_client_plugin_address_pretty_printer (void *cls, const char *type, |
215 | const void *addr, size_t addrlen, | ||
216 | int numeric, | ||
217 | struct GNUNET_TIME_Relative timeout, | ||
218 | GNUNET_TRANSPORT_AddressStringCallback | ||
219 | asc, void *asc_cls) | ||
398 | { | 220 | { |
399 | struct Session *s = cls; | 221 | asc (asc_cls, NULL); |
400 | struct GNUNET_TIME_Absolute now; | ||
401 | size_t len = size * nmemb; | ||
402 | struct Plugin *plugin = s->plugin; | ||
403 | |||
404 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
405 | "Client: Received %u bytes from peer `%s'\n", len, | ||
406 | GNUNET_i2s (&s->target)); | ||
407 | now = GNUNET_TIME_absolute_get (); | ||
408 | if (now.abs_value < s->next_receive.abs_value) | ||
409 | { | ||
410 | struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); | ||
411 | struct GNUNET_TIME_Relative delta = | ||
412 | GNUNET_TIME_absolute_get_difference (now, s->next_receive); | ||
413 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
414 | "Client: %p No inbound bandwidth available! Next read was delayed for %llu ms\n", | ||
415 | s->client_get, delta.rel_value); | ||
416 | if (s->recv_wakeup_task != GNUNET_SCHEDULER_NO_TASK) | ||
417 | { | ||
418 | GNUNET_SCHEDULER_cancel (s->recv_wakeup_task); | ||
419 | s->recv_wakeup_task = GNUNET_SCHEDULER_NO_TASK; | ||
420 | } | ||
421 | s->recv_wakeup_task = | ||
422 | GNUNET_SCHEDULER_add_delayed (delta, &client_wake_up, s); | ||
423 | return CURLPAUSE_ALL; | ||
424 | } | ||
425 | if (NULL == s->msg_tk) | ||
426 | s->msg_tk = GNUNET_SERVER_mst_create (&client_receive_mst_cb, s); | ||
427 | GNUNET_SERVER_mst_receive (s->msg_tk, s, stream, len, GNUNET_NO, GNUNET_NO); | ||
428 | return len; | ||
429 | } | 222 | } |
430 | 223 | ||
431 | 224 | ||
225 | |||
432 | /** | 226 | /** |
433 | * Callback method used with libcurl | 227 | * Another peer has suggested an address for this |
434 | * Method is called when libcurl needs to read data during sending | 228 | * peer and transport plugin. Check that this could be a valid |
229 | * address. If so, consider adding it to the list | ||
230 | * of addresses. | ||
435 | * | 231 | * |
436 | * @param stream pointer where to write data | 232 | * @param cls closure |
437 | * @param size size of an individual element | 233 | * @param addr pointer to the address |
438 | * @param nmemb count of elements that can be written to the buffer | 234 | * @param addrlen length of addr |
439 | * @param cls source pointer, passed to the libcurl handle | 235 | * @return GNUNET_OK if this is a plausible address for this peer |
440 | * @return bytes written to stream, returning 0 will terminate connection! | 236 | * and transport |
441 | */ | 237 | */ |
442 | static size_t | 238 | static int |
443 | client_send_cb (void *stream, size_t size, size_t nmemb, void *cls) | 239 | http_client_plugin_address_suggested (void *cls, const void *addr, size_t addrlen) |
444 | { | 240 | { |
445 | struct Session *s = cls; | 241 | /* struct Plugin *plugin = cls; */ |
446 | struct Plugin *plugin = s->plugin; | 242 | |
447 | struct HTTP_Message *msg = s->msg_head; | 243 | /* check if the address is plausible; if so, |
448 | size_t len; | 244 | * add it to our list! */ |
449 | 245 | return GNUNET_OK; | |
450 | if (GNUNET_YES != exist_session(plugin, s)) | ||
451 | { | ||
452 | GNUNET_break (0); | ||
453 | return 0; | ||
454 | } | ||
455 | if (NULL == msg) | ||
456 | { | ||
457 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
458 | "Client: %p Nothing to send! Suspending PUT handle!\n", | ||
459 | s->client_put); | ||
460 | s->client_put_paused = GNUNET_YES; | ||
461 | return CURL_READFUNC_PAUSE; | ||
462 | } | ||
463 | /* data to send */ | ||
464 | GNUNET_assert (msg->pos < msg->size); | ||
465 | /* calculate how much fits in buffer */ | ||
466 | len = GNUNET_MIN (msg->size - msg->pos, | ||
467 | size * nmemb); | ||
468 | memcpy (stream, &msg->buf[msg->pos], len); | ||
469 | msg->pos += len; | ||
470 | if (msg->pos == msg->size) | ||
471 | { | ||
472 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
473 | "Client: %p Message with %u bytes sent, removing message from queue\n", | ||
474 | s->client_put, msg->size, msg->pos); | ||
475 | /* Calling transmit continuation */ | ||
476 | GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg); | ||
477 | if (NULL != msg->transmit_cont) | ||
478 | msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_OK); | ||
479 | GNUNET_free (msg); | ||
480 | } | ||
481 | return len; | ||
482 | } | 246 | } |
483 | 247 | ||
484 | 248 | ||
485 | int | 249 | /** |
486 | client_connect (struct Session *s) | 250 | * Function called for a quick conversion of the binary address to |
251 | * a numeric address. Note that the caller must not free the | ||
252 | * address and that the next call to this function is allowed | ||
253 | * to override the address again. | ||
254 | * | ||
255 | * @param cls closure | ||
256 | * @param addr binary address | ||
257 | * @param addrlen length of the address | ||
258 | * @return string representing the same address | ||
259 | */ | ||
260 | static const char * | ||
261 | http_client_plugin_address_to_string (void *cls, const void *addr, size_t addrlen) | ||
487 | { | 262 | { |
488 | struct Plugin *plugin = s->plugin; | 263 | GNUNET_break (0); |
489 | int res = GNUNET_OK; | 264 | return NULL; |
490 | char *url; | 265 | } |
491 | CURLMcode mret; | ||
492 | |||
493 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
494 | "Initiating outbound session peer `%s'\n", | ||
495 | GNUNET_i2s (&s->target)); | ||
496 | s->inbound = GNUNET_NO; | ||
497 | plugin->last_tag++; | ||
498 | /* create url */ | ||
499 | GNUNET_asprintf (&url, "%s%s;%u", | ||
500 | http_plugin_address_to_string (plugin, s->addr, s->addrlen), | ||
501 | GNUNET_h2s_full (&plugin->env->my_identity->hashPubKey), | ||
502 | plugin->last_tag); | ||
503 | #if 0 | ||
504 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, "URL `%s'\n", url); | ||
505 | #endif | ||
506 | /* create get connection */ | ||
507 | s->client_get = curl_easy_init (); | ||
508 | #if VERBOSE_CURL | ||
509 | curl_easy_setopt (s->client_get, CURLOPT_VERBOSE, 1L); | ||
510 | curl_easy_setopt (s->client_get, CURLOPT_DEBUGFUNCTION, &client_log); | ||
511 | curl_easy_setopt (s->client_get, CURLOPT_DEBUGDATA, s->client_get); | ||
512 | #endif | ||
513 | #if BUILD_HTTPS | ||
514 | curl_easy_setopt (s->client_get, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1); | ||
515 | curl_easy_setopt (s->client_get, CURLOPT_SSL_VERIFYPEER, 0); | ||
516 | curl_easy_setopt (s->client_get, CURLOPT_SSL_VERIFYHOST, 0); | ||
517 | #endif | ||
518 | curl_easy_setopt (s->client_get, CURLOPT_URL, url); | ||
519 | //curl_easy_setopt (s->client_get, CURLOPT_HEADERFUNCTION, &curl_get_header_cb); | ||
520 | //curl_easy_setopt (s->client_get, CURLOPT_WRITEHEADER, ps); | ||
521 | curl_easy_setopt (s->client_get, CURLOPT_READFUNCTION, client_send_cb); | ||
522 | curl_easy_setopt (s->client_get, CURLOPT_READDATA, s); | ||
523 | curl_easy_setopt (s->client_get, CURLOPT_WRITEFUNCTION, client_receive); | ||
524 | curl_easy_setopt (s->client_get, CURLOPT_WRITEDATA, s); | ||
525 | curl_easy_setopt (s->client_get, CURLOPT_TIMEOUT_MS, | ||
526 | (long) GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value); | ||
527 | curl_easy_setopt (s->client_get, CURLOPT_PRIVATE, s); | ||
528 | curl_easy_setopt (s->client_get, CURLOPT_CONNECTTIMEOUT_MS, | ||
529 | (long) HTTP_NOT_VALIDATED_TIMEOUT.rel_value); | ||
530 | curl_easy_setopt (s->client_get, CURLOPT_BUFFERSIZE, | ||
531 | 2 * GNUNET_SERVER_MAX_MESSAGE_SIZE); | ||
532 | #if CURL_TCP_NODELAY | ||
533 | curl_easy_setopt (ps->recv_endpoint, CURLOPT_TCP_NODELAY, 1); | ||
534 | #endif | ||
535 | 266 | ||
536 | /* create put connection */ | ||
537 | s->client_put = curl_easy_init (); | ||
538 | #if VERBOSE_CURL | ||
539 | curl_easy_setopt (s->client_put, CURLOPT_VERBOSE, 1L); | ||
540 | curl_easy_setopt (s->client_put, CURLOPT_DEBUGFUNCTION, &client_log); | ||
541 | curl_easy_setopt (s->client_put, CURLOPT_DEBUGDATA, s->client_put); | ||
542 | #endif | ||
543 | #if BUILD_HTTPS | ||
544 | curl_easy_setopt (s->client_put, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1); | ||
545 | curl_easy_setopt (s->client_put, CURLOPT_SSL_VERIFYPEER, 0); | ||
546 | curl_easy_setopt (s->client_put, CURLOPT_SSL_VERIFYHOST, 0); | ||
547 | #endif | ||
548 | curl_easy_setopt (s->client_put, CURLOPT_URL, url); | ||
549 | curl_easy_setopt (s->client_put, CURLOPT_PUT, 1L); | ||
550 | //curl_easy_setopt (s->client_put, CURLOPT_HEADERFUNCTION, &curl_put_header_cb); | ||
551 | //curl_easy_setopt (s->client_put, CURLOPT_WRITEHEADER, ps); | ||
552 | curl_easy_setopt (s->client_put, CURLOPT_READFUNCTION, client_send_cb); | ||
553 | curl_easy_setopt (s->client_put, CURLOPT_READDATA, s); | ||
554 | curl_easy_setopt (s->client_put, CURLOPT_WRITEFUNCTION, client_receive); | ||
555 | curl_easy_setopt (s->client_put, CURLOPT_WRITEDATA, s); | ||
556 | curl_easy_setopt (s->client_put, CURLOPT_TIMEOUT_MS, | ||
557 | (long) GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value); | ||
558 | curl_easy_setopt (s->client_put, CURLOPT_PRIVATE, s); | ||
559 | curl_easy_setopt (s->client_put, CURLOPT_CONNECTTIMEOUT_MS, | ||
560 | (long) HTTP_NOT_VALIDATED_TIMEOUT.rel_value); | ||
561 | curl_easy_setopt (s->client_put, CURLOPT_BUFFERSIZE, | ||
562 | 2 * GNUNET_SERVER_MAX_MESSAGE_SIZE); | ||
563 | #if CURL_TCP_NODELAY | ||
564 | curl_easy_setopt (s->client_put, CURLOPT_TCP_NODELAY, 1); | ||
565 | #endif | ||
566 | 267 | ||
567 | GNUNET_free (url); | ||
568 | |||
569 | mret = curl_multi_add_handle (plugin->client_mh, s->client_get); | ||
570 | if (mret != CURLM_OK) | ||
571 | { | ||
572 | curl_easy_cleanup (s->client_get); | ||
573 | res = GNUNET_SYSERR; | ||
574 | GNUNET_break (0); | ||
575 | } | ||
576 | |||
577 | mret = curl_multi_add_handle (plugin->client_mh, s->client_put); | ||
578 | if (mret != CURLM_OK) | ||
579 | { | ||
580 | curl_multi_remove_handle (plugin->client_mh, s->client_get); | ||
581 | curl_easy_cleanup (s->client_get); | ||
582 | curl_easy_cleanup (s->client_put); | ||
583 | res = GNUNET_SYSERR; | ||
584 | GNUNET_break (0); | ||
585 | } | ||
586 | |||
587 | /* Perform connect */ | ||
588 | plugin->cur_connections += 2; | ||
589 | |||
590 | plugin->outbound_sessions ++; | ||
591 | GNUNET_STATISTICS_set (plugin->env->stats, | ||
592 | "# HTTP outbound sessions", | ||
593 | plugin->outbound_sessions, | ||
594 | GNUNET_NO); | ||
595 | |||
596 | /* Re-schedule since handles have changed */ | ||
597 | if (plugin->client_perform_task != GNUNET_SCHEDULER_NO_TASK) | ||
598 | { | ||
599 | GNUNET_SCHEDULER_cancel (plugin->client_perform_task); | ||
600 | plugin->client_perform_task = GNUNET_SCHEDULER_NO_TASK; | ||
601 | } | ||
602 | plugin->client_perform_task = GNUNET_SCHEDULER_add_now (client_run, plugin); | ||
603 | |||
604 | return res; | ||
605 | } | ||
606 | 268 | ||
607 | 269 | ||
608 | int | 270 | /** |
609 | client_start (struct Plugin *plugin) | 271 | * Entry point for the plugin. |
272 | */ | ||
273 | void * | ||
274 | LIBGNUNET_PLUGIN_TRANSPORT_INIT (void *cls) | ||
610 | { | 275 | { |
611 | int res = GNUNET_OK; | 276 | struct GNUNET_TRANSPORT_PluginEnvironment *env = cls; |
612 | p = plugin; | 277 | struct GNUNET_TRANSPORT_PluginFunctions *api; |
613 | 278 | struct Plugin *plugin; | |
614 | curl_global_init (CURL_GLOBAL_ALL); | 279 | |
615 | plugin->client_mh = curl_multi_init (); | 280 | plugin = GNUNET_malloc (sizeof (struct Plugin)); |
616 | 281 | plugin->env = env; | |
617 | if (NULL == plugin->client_mh) | 282 | api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); |
618 | { | 283 | api->cls = plugin; |
619 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, | 284 | api->send = &http_client_plugin_send; |
620 | _ | 285 | api->disconnect = &http_client_plugin_disconnect; |
621 | ("Could not initialize curl multi handle, failed to start %s plugin!\n"), | 286 | api->address_pretty_printer = &http_client_plugin_address_pretty_printer; |
622 | plugin->name); | 287 | api->check_address = &http_client_plugin_address_suggested; |
623 | res = GNUNET_SYSERR; | 288 | api->address_to_string = &http_client_plugin_address_to_string; |
624 | } | 289 | return api; |
625 | return res; | ||
626 | } | 290 | } |
627 | 291 | ||
628 | 292 | ||
629 | void | 293 | /** |
630 | client_stop (struct Plugin *plugin) | 294 | * Exit point from the plugin. |
295 | */ | ||
296 | void * | ||
297 | LIBGNUNET_PLUGIN_TRANSPORT_DONE (void *cls) | ||
631 | { | 298 | { |
632 | p = NULL; | 299 | struct GNUNET_TRANSPORT_PluginFunctions *api = cls; |
633 | if (plugin->client_perform_task != GNUNET_SCHEDULER_NO_TASK) | 300 | struct Plugin *plugin = api->cls; |
634 | { | ||
635 | GNUNET_SCHEDULER_cancel (plugin->client_perform_task); | ||
636 | plugin->client_perform_task = GNUNET_SCHEDULER_NO_TASK; | ||
637 | } | ||
638 | |||
639 | curl_multi_cleanup (plugin->client_mh); | ||
640 | curl_global_cleanup (); | ||
641 | } | ||
642 | |||
643 | 301 | ||
302 | GNUNET_free (plugin); | ||
303 | GNUNET_free (api); | ||
304 | return NULL; | ||
305 | } | ||
644 | 306 | ||
645 | /* end of plugin_transport_http_client.c */ | 307 | /* end of plugin_transport_http_client.c */ |
diff --git a/src/transport/plugin_transport_http_client_old.c b/src/transport/plugin_transport_http_client_old.c new file mode 100644 index 000000000..ff23da974 --- /dev/null +++ b/src/transport/plugin_transport_http_client_old.c | |||
@@ -0,0 +1,645 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet | ||
3 | (C) 2002--2012 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_http_client.c | ||
23 | * @brief http transport service plugin | ||
24 | * @author Matthias Wachs | ||
25 | */ | ||
26 | |||
27 | #include "plugin_transport_http.h" | ||
28 | |||
29 | static struct Plugin * p; | ||
30 | |||
31 | #if VERBOSE_CURL | ||
32 | /** | ||
33 | * Function to log curl debug messages with GNUNET_log | ||
34 | * @param curl handle | ||
35 | * @param type curl_infotype | ||
36 | * @param data data | ||
37 | * @param size size | ||
38 | * @param cls closure | ||
39 | * @return 0 | ||
40 | */ | ||
41 | static int | ||
42 | client_log (CURL * curl, curl_infotype type, char *data, size_t size, void *cls) | ||
43 | { | ||
44 | if (type == CURLINFO_TEXT) | ||
45 | { | ||
46 | char text[size + 2]; | ||
47 | |||
48 | memcpy (text, data, size); | ||
49 | if (text[size - 1] == '\n') | ||
50 | text[size] = '\0'; | ||
51 | else | ||
52 | { | ||
53 | text[size] = '\n'; | ||
54 | text[size + 1] = '\0'; | ||
55 | } | ||
56 | #if BUILD_HTTPS | ||
57 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-https", | ||
58 | "Client: %p - %s", cls, text); | ||
59 | #else | ||
60 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-http", | ||
61 | "Client: %p - %s", cls, text); | ||
62 | #endif | ||
63 | } | ||
64 | return 0; | ||
65 | } | ||
66 | #endif | ||
67 | |||
68 | /** | ||
69 | * Task performing curl operations | ||
70 | * @param cls plugin as closure | ||
71 | * @param tc gnunet scheduler task context | ||
72 | */ | ||
73 | static void | ||
74 | client_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc); | ||
75 | |||
76 | |||
77 | /** | ||
78 | * Function setting up file descriptors and scheduling task to run | ||
79 | * | ||
80 | * @param plugin plugin as closure | ||
81 | * @param now schedule task in 1ms, regardless of what curl may say | ||
82 | * @return GNUNET_SYSERR for hard failure, GNUNET_OK for ok | ||
83 | */ | ||
84 | static int | ||
85 | client_schedule (struct Plugin *plugin, int now) | ||
86 | { | ||
87 | fd_set rs; | ||
88 | fd_set ws; | ||
89 | fd_set es; | ||
90 | int max; | ||
91 | struct GNUNET_NETWORK_FDSet *grs; | ||
92 | struct GNUNET_NETWORK_FDSet *gws; | ||
93 | long to; | ||
94 | CURLMcode mret; | ||
95 | struct GNUNET_TIME_Relative timeout; | ||
96 | |||
97 | /* Cancel previous scheduled task */ | ||
98 | if (plugin->client_perform_task != GNUNET_SCHEDULER_NO_TASK) | ||
99 | { | ||
100 | GNUNET_SCHEDULER_cancel (plugin->client_perform_task); | ||
101 | plugin->client_perform_task = GNUNET_SCHEDULER_NO_TASK; | ||
102 | } | ||
103 | max = -1; | ||
104 | FD_ZERO (&rs); | ||
105 | FD_ZERO (&ws); | ||
106 | FD_ZERO (&es); | ||
107 | mret = curl_multi_fdset (plugin->client_mh, &rs, &ws, &es, &max); | ||
108 | if (mret != CURLM_OK) | ||
109 | { | ||
110 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"), | ||
111 | "curl_multi_fdset", __FILE__, __LINE__, | ||
112 | curl_multi_strerror (mret)); | ||
113 | return GNUNET_SYSERR; | ||
114 | } | ||
115 | mret = curl_multi_timeout (plugin->client_mh, &to); | ||
116 | if (to == -1) | ||
117 | timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1); | ||
118 | else | ||
119 | timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, to); | ||
120 | if (now == GNUNET_YES) | ||
121 | timeout = GNUNET_TIME_UNIT_MILLISECONDS; | ||
122 | |||
123 | if (mret != CURLM_OK) | ||
124 | { | ||
125 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"), | ||
126 | "curl_multi_timeout", __FILE__, __LINE__, | ||
127 | curl_multi_strerror (mret)); | ||
128 | return GNUNET_SYSERR; | ||
129 | } | ||
130 | |||
131 | grs = GNUNET_NETWORK_fdset_create (); | ||
132 | gws = GNUNET_NETWORK_fdset_create (); | ||
133 | GNUNET_NETWORK_fdset_copy_native (grs, &rs, max + 1); | ||
134 | GNUNET_NETWORK_fdset_copy_native (gws, &ws, max + 1); | ||
135 | |||
136 | plugin->client_perform_task = | ||
137 | GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, | ||
138 | timeout, grs, gws, | ||
139 | &client_run, plugin); | ||
140 | GNUNET_NETWORK_fdset_destroy (gws); | ||
141 | GNUNET_NETWORK_fdset_destroy (grs); | ||
142 | return GNUNET_OK; | ||
143 | } | ||
144 | |||
145 | |||
146 | int | ||
147 | client_send (struct Session *s, struct HTTP_Message *msg) | ||
148 | { | ||
149 | GNUNET_assert (s != NULL); | ||
150 | GNUNET_CONTAINER_DLL_insert_tail (s->msg_head, s->msg_tail, msg); | ||
151 | |||
152 | if (GNUNET_YES != exist_session(p, s)) | ||
153 | { | ||
154 | GNUNET_break (0); | ||
155 | return GNUNET_SYSERR; | ||
156 | } | ||
157 | if (s->client_put_paused == GNUNET_YES) | ||
158 | { | ||
159 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, s->plugin->name, | ||
160 | "Client: %p was suspended, unpausing\n", s->client_put); | ||
161 | s->client_put_paused = GNUNET_NO; | ||
162 | curl_easy_pause (s->client_put, CURLPAUSE_CONT); | ||
163 | } | ||
164 | client_schedule (s->plugin, GNUNET_YES); | ||
165 | |||
166 | return GNUNET_OK; | ||
167 | } | ||
168 | |||
169 | |||
170 | /** | ||
171 | * Task performing curl operations | ||
172 | * | ||
173 | * @param cls plugin as closure | ||
174 | * @param tc gnunet scheduler task context | ||
175 | */ | ||
176 | static void | ||
177 | client_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
178 | { | ||
179 | struct Plugin *plugin = cls; | ||
180 | int running; | ||
181 | CURLMcode mret; | ||
182 | |||
183 | GNUNET_assert (cls != NULL); | ||
184 | |||
185 | plugin->client_perform_task = GNUNET_SCHEDULER_NO_TASK; | ||
186 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | ||
187 | return; | ||
188 | |||
189 | do | ||
190 | { | ||
191 | running = 0; | ||
192 | mret = curl_multi_perform (plugin->client_mh, &running); | ||
193 | |||
194 | CURLMsg *msg; | ||
195 | int msgs_left; | ||
196 | |||
197 | while ((msg = curl_multi_info_read (plugin->client_mh, &msgs_left))) | ||
198 | { | ||
199 | CURL *easy_h = msg->easy_handle; | ||
200 | struct Session *s = NULL; | ||
201 | char *d = (char *) s; | ||
202 | |||
203 | if (easy_h == NULL) | ||
204 | { | ||
205 | GNUNET_break (0); | ||
206 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
207 | "Client: connection to ended with reason %i: `%s', %i handles running\n", | ||
208 | msg->data.result, | ||
209 | curl_easy_strerror (msg->data.result), running); | ||
210 | continue; | ||
211 | } | ||
212 | |||
213 | GNUNET_assert (CURLE_OK == | ||
214 | curl_easy_getinfo (easy_h, CURLINFO_PRIVATE, &d)); | ||
215 | s = (struct Session *) d; | ||
216 | |||
217 | if (GNUNET_YES != exist_session(plugin, s)) | ||
218 | { | ||
219 | GNUNET_break (0); | ||
220 | return; | ||
221 | } | ||
222 | |||
223 | GNUNET_assert (s != NULL); | ||
224 | if (msg->msg == CURLMSG_DONE) | ||
225 | { | ||
226 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
227 | "Client: %p connection to '%s' %s ended with reason %i: `%s'\n", | ||
228 | msg->easy_handle, GNUNET_i2s (&s->target), | ||
229 | http_plugin_address_to_string (NULL, s->addr, | ||
230 | s->addrlen), | ||
231 | msg->data.result, | ||
232 | curl_easy_strerror (msg->data.result)); | ||
233 | |||
234 | /* Disconnect other transmission direction and tell transport */ | ||
235 | client_disconnect (s); | ||
236 | } | ||
237 | } | ||
238 | } | ||
239 | while (mret == CURLM_CALL_MULTI_PERFORM); | ||
240 | client_schedule (plugin, GNUNET_NO); | ||
241 | } | ||
242 | |||
243 | |||
244 | int | ||
245 | client_disconnect (struct Session *s) | ||
246 | { | ||
247 | int res = GNUNET_OK; | ||
248 | CURLMcode mret; | ||
249 | struct Plugin *plugin = s->plugin; | ||
250 | struct HTTP_Message *msg; | ||
251 | struct HTTP_Message *t; | ||
252 | |||
253 | if (GNUNET_YES != exist_session(plugin, s)) | ||
254 | { | ||
255 | GNUNET_break (0); | ||
256 | return GNUNET_SYSERR; | ||
257 | } | ||
258 | |||
259 | if (s->client_put != NULL) | ||
260 | { | ||
261 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
262 | "Client: %p / %p Deleting outbound PUT session to peer `%s'\n", | ||
263 | s, s->client_put, GNUNET_i2s (&s->target)); | ||
264 | |||
265 | /* remove curl handle from multi handle */ | ||
266 | mret = curl_multi_remove_handle (plugin->client_mh, s->client_put); | ||
267 | if (mret != CURLM_OK) | ||
268 | { | ||
269 | /* clean up easy handle, handle is now invalid and free'd */ | ||
270 | res = GNUNET_SYSERR; | ||
271 | GNUNET_break (0); | ||
272 | } | ||
273 | curl_easy_cleanup (s->client_put); | ||
274 | s->client_put = NULL; | ||
275 | } | ||
276 | |||
277 | |||
278 | if (s->recv_wakeup_task != GNUNET_SCHEDULER_NO_TASK) | ||
279 | { | ||
280 | GNUNET_SCHEDULER_cancel (s->recv_wakeup_task); | ||
281 | s->recv_wakeup_task = GNUNET_SCHEDULER_NO_TASK; | ||
282 | } | ||
283 | |||
284 | if (s->client_get != NULL) | ||
285 | { | ||
286 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
287 | "Client: %p / %p Deleting outbound GET session to peer `%s'\n", | ||
288 | s, | ||
289 | s->client_get, GNUNET_i2s (&s->target)); | ||
290 | |||
291 | /* remove curl handle from multi handle */ | ||
292 | mret = curl_multi_remove_handle (plugin->client_mh, s->client_get); | ||
293 | if (mret != CURLM_OK) | ||
294 | { | ||
295 | /* clean up easy handle, handle is now invalid and free'd */ | ||
296 | res = GNUNET_SYSERR; | ||
297 | GNUNET_break (0); | ||
298 | } | ||
299 | curl_easy_cleanup (s->client_get); | ||
300 | s->client_get = NULL; | ||
301 | } | ||
302 | |||
303 | msg = s->msg_head; | ||
304 | while (msg != NULL) | ||
305 | { | ||
306 | t = msg->next; | ||
307 | if (NULL != msg->transmit_cont) | ||
308 | msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_SYSERR); | ||
309 | GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg); | ||
310 | GNUNET_free (msg); | ||
311 | msg = t; | ||
312 | } | ||
313 | |||
314 | plugin->cur_connections -= 2; | ||
315 | |||
316 | notify_session_end (plugin, &s->target, s); | ||
317 | |||
318 | GNUNET_assert (plugin->outbound_sessions > 0); | ||
319 | plugin->outbound_sessions --; | ||
320 | GNUNET_STATISTICS_set (plugin->env->stats, | ||
321 | "# HTTP outbound sessions", | ||
322 | plugin->outbound_sessions, | ||
323 | GNUNET_NO); | ||
324 | |||
325 | /* Re-schedule since handles have changed */ | ||
326 | if (plugin->client_perform_task != GNUNET_SCHEDULER_NO_TASK) | ||
327 | { | ||
328 | GNUNET_SCHEDULER_cancel (plugin->client_perform_task); | ||
329 | plugin->client_perform_task = GNUNET_SCHEDULER_NO_TASK; | ||
330 | } | ||
331 | client_schedule (plugin, GNUNET_YES); | ||
332 | |||
333 | return res; | ||
334 | } | ||
335 | |||
336 | static int | ||
337 | client_receive_mst_cb (void *cls, void *client, | ||
338 | const struct GNUNET_MessageHeader *message) | ||
339 | { | ||
340 | struct Session *s = cls; | ||
341 | struct GNUNET_TIME_Relative delay; | ||
342 | |||
343 | if (GNUNET_YES != exist_session(p, s)) | ||
344 | { | ||
345 | GNUNET_break (0); | ||
346 | return GNUNET_OK; | ||
347 | } | ||
348 | |||
349 | delay = http_plugin_receive (s, &s->target, message, s, s->addr, s->addrlen); | ||
350 | s->next_receive = | ||
351 | GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), delay); | ||
352 | |||
353 | if (GNUNET_TIME_absolute_get ().abs_value < s->next_receive.abs_value) | ||
354 | { | ||
355 | struct Plugin *plugin = s->plugin; | ||
356 | |||
357 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
358 | "Client: peer `%s' address `%s' next read delayed for %llu ms\n", | ||
359 | GNUNET_i2s (&s->target), GNUNET_a2s (s->addr, s->addrlen), | ||
360 | delay); | ||
361 | } | ||
362 | return GNUNET_OK; | ||
363 | } | ||
364 | |||
365 | |||
366 | static void | ||
367 | client_wake_up (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
368 | { | ||
369 | struct Session *s = cls; | ||
370 | |||
371 | if (GNUNET_YES != exist_session(p, s)) | ||
372 | { | ||
373 | GNUNET_break (0); | ||
374 | return; | ||
375 | } | ||
376 | s->recv_wakeup_task = GNUNET_SCHEDULER_NO_TASK; | ||
377 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | ||
378 | return; | ||
379 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, s->plugin->name, | ||
380 | "Client: %p Waking up receive handle\n", s->client_get); | ||
381 | if (s->client_get != NULL) | ||
382 | curl_easy_pause (s->client_get, CURLPAUSE_CONT); | ||
383 | } | ||
384 | |||
385 | |||
386 | /** | ||
387 | * Callback method used with libcurl | ||
388 | * Method is called when libcurl needs to write data during sending | ||
389 | * | ||
390 | * @param stream pointer where to write data | ||
391 | * @param size size of an individual element | ||
392 | * @param nmemb count of elements that can be written to the buffer | ||
393 | * @param cls destination pointer, passed to the libcurl handle | ||
394 | * @return bytes read from stream | ||
395 | */ | ||
396 | static size_t | ||
397 | client_receive (void *stream, size_t size, size_t nmemb, void *cls) | ||
398 | { | ||
399 | struct Session *s = cls; | ||
400 | struct GNUNET_TIME_Absolute now; | ||
401 | size_t len = size * nmemb; | ||
402 | struct Plugin *plugin = s->plugin; | ||
403 | |||
404 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
405 | "Client: Received %u bytes from peer `%s'\n", len, | ||
406 | GNUNET_i2s (&s->target)); | ||
407 | now = GNUNET_TIME_absolute_get (); | ||
408 | if (now.abs_value < s->next_receive.abs_value) | ||
409 | { | ||
410 | struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); | ||
411 | struct GNUNET_TIME_Relative delta = | ||
412 | GNUNET_TIME_absolute_get_difference (now, s->next_receive); | ||
413 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
414 | "Client: %p No inbound bandwidth available! Next read was delayed for %llu ms\n", | ||
415 | s->client_get, delta.rel_value); | ||
416 | if (s->recv_wakeup_task != GNUNET_SCHEDULER_NO_TASK) | ||
417 | { | ||
418 | GNUNET_SCHEDULER_cancel (s->recv_wakeup_task); | ||
419 | s->recv_wakeup_task = GNUNET_SCHEDULER_NO_TASK; | ||
420 | } | ||
421 | s->recv_wakeup_task = | ||
422 | GNUNET_SCHEDULER_add_delayed (delta, &client_wake_up, s); | ||
423 | return CURLPAUSE_ALL; | ||
424 | } | ||
425 | if (NULL == s->msg_tk) | ||
426 | s->msg_tk = GNUNET_SERVER_mst_create (&client_receive_mst_cb, s); | ||
427 | GNUNET_SERVER_mst_receive (s->msg_tk, s, stream, len, GNUNET_NO, GNUNET_NO); | ||
428 | return len; | ||
429 | } | ||
430 | |||
431 | |||
432 | /** | ||
433 | * Callback method used with libcurl | ||
434 | * Method is called when libcurl needs to read data during sending | ||
435 | * | ||
436 | * @param stream pointer where to write data | ||
437 | * @param size size of an individual element | ||
438 | * @param nmemb count of elements that can be written to the buffer | ||
439 | * @param cls source pointer, passed to the libcurl handle | ||
440 | * @return bytes written to stream, returning 0 will terminate connection! | ||
441 | */ | ||
442 | static size_t | ||
443 | client_send_cb (void *stream, size_t size, size_t nmemb, void *cls) | ||
444 | { | ||
445 | struct Session *s = cls; | ||
446 | struct Plugin *plugin = s->plugin; | ||
447 | struct HTTP_Message *msg = s->msg_head; | ||
448 | size_t len; | ||
449 | |||
450 | if (GNUNET_YES != exist_session(plugin, s)) | ||
451 | { | ||
452 | GNUNET_break (0); | ||
453 | return 0; | ||
454 | } | ||
455 | if (NULL == msg) | ||
456 | { | ||
457 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
458 | "Client: %p Nothing to send! Suspending PUT handle!\n", | ||
459 | s->client_put); | ||
460 | s->client_put_paused = GNUNET_YES; | ||
461 | return CURL_READFUNC_PAUSE; | ||
462 | } | ||
463 | /* data to send */ | ||
464 | GNUNET_assert (msg->pos < msg->size); | ||
465 | /* calculate how much fits in buffer */ | ||
466 | len = GNUNET_MIN (msg->size - msg->pos, | ||
467 | size * nmemb); | ||
468 | memcpy (stream, &msg->buf[msg->pos], len); | ||
469 | msg->pos += len; | ||
470 | if (msg->pos == msg->size) | ||
471 | { | ||
472 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
473 | "Client: %p Message with %u bytes sent, removing message from queue\n", | ||
474 | s->client_put, msg->size, msg->pos); | ||
475 | /* Calling transmit continuation */ | ||
476 | GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg); | ||
477 | if (NULL != msg->transmit_cont) | ||
478 | msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_OK); | ||
479 | GNUNET_free (msg); | ||
480 | } | ||
481 | return len; | ||
482 | } | ||
483 | |||
484 | |||
485 | int | ||
486 | client_connect (struct Session *s) | ||
487 | { | ||
488 | struct Plugin *plugin = s->plugin; | ||
489 | int res = GNUNET_OK; | ||
490 | char *url; | ||
491 | CURLMcode mret; | ||
492 | |||
493 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
494 | "Initiating outbound session peer `%s'\n", | ||
495 | GNUNET_i2s (&s->target)); | ||
496 | s->inbound = GNUNET_NO; | ||
497 | plugin->last_tag++; | ||
498 | /* create url */ | ||
499 | GNUNET_asprintf (&url, "%s%s;%u", | ||
500 | http_plugin_address_to_string (plugin, s->addr, s->addrlen), | ||
501 | GNUNET_h2s_full (&plugin->env->my_identity->hashPubKey), | ||
502 | plugin->last_tag); | ||
503 | #if 0 | ||
504 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, "URL `%s'\n", url); | ||
505 | #endif | ||
506 | /* create get connection */ | ||
507 | s->client_get = curl_easy_init (); | ||
508 | #if VERBOSE_CURL | ||
509 | curl_easy_setopt (s->client_get, CURLOPT_VERBOSE, 1L); | ||
510 | curl_easy_setopt (s->client_get, CURLOPT_DEBUGFUNCTION, &client_log); | ||
511 | curl_easy_setopt (s->client_get, CURLOPT_DEBUGDATA, s->client_get); | ||
512 | #endif | ||
513 | #if BUILD_HTTPS | ||
514 | curl_easy_setopt (s->client_get, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1); | ||
515 | curl_easy_setopt (s->client_get, CURLOPT_SSL_VERIFYPEER, 0); | ||
516 | curl_easy_setopt (s->client_get, CURLOPT_SSL_VERIFYHOST, 0); | ||
517 | #endif | ||
518 | curl_easy_setopt (s->client_get, CURLOPT_URL, url); | ||
519 | //curl_easy_setopt (s->client_get, CURLOPT_HEADERFUNCTION, &curl_get_header_cb); | ||
520 | //curl_easy_setopt (s->client_get, CURLOPT_WRITEHEADER, ps); | ||
521 | curl_easy_setopt (s->client_get, CURLOPT_READFUNCTION, client_send_cb); | ||
522 | curl_easy_setopt (s->client_get, CURLOPT_READDATA, s); | ||
523 | curl_easy_setopt (s->client_get, CURLOPT_WRITEFUNCTION, client_receive); | ||
524 | curl_easy_setopt (s->client_get, CURLOPT_WRITEDATA, s); | ||
525 | curl_easy_setopt (s->client_get, CURLOPT_TIMEOUT_MS, | ||
526 | (long) GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value); | ||
527 | curl_easy_setopt (s->client_get, CURLOPT_PRIVATE, s); | ||
528 | curl_easy_setopt (s->client_get, CURLOPT_CONNECTTIMEOUT_MS, | ||
529 | (long) HTTP_NOT_VALIDATED_TIMEOUT.rel_value); | ||
530 | curl_easy_setopt (s->client_get, CURLOPT_BUFFERSIZE, | ||
531 | 2 * GNUNET_SERVER_MAX_MESSAGE_SIZE); | ||
532 | #if CURL_TCP_NODELAY | ||
533 | curl_easy_setopt (ps->recv_endpoint, CURLOPT_TCP_NODELAY, 1); | ||
534 | #endif | ||
535 | |||
536 | /* create put connection */ | ||
537 | s->client_put = curl_easy_init (); | ||
538 | #if VERBOSE_CURL | ||
539 | curl_easy_setopt (s->client_put, CURLOPT_VERBOSE, 1L); | ||
540 | curl_easy_setopt (s->client_put, CURLOPT_DEBUGFUNCTION, &client_log); | ||
541 | curl_easy_setopt (s->client_put, CURLOPT_DEBUGDATA, s->client_put); | ||
542 | #endif | ||
543 | #if BUILD_HTTPS | ||
544 | curl_easy_setopt (s->client_put, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1); | ||
545 | curl_easy_setopt (s->client_put, CURLOPT_SSL_VERIFYPEER, 0); | ||
546 | curl_easy_setopt (s->client_put, CURLOPT_SSL_VERIFYHOST, 0); | ||
547 | #endif | ||
548 | curl_easy_setopt (s->client_put, CURLOPT_URL, url); | ||
549 | curl_easy_setopt (s->client_put, CURLOPT_PUT, 1L); | ||
550 | //curl_easy_setopt (s->client_put, CURLOPT_HEADERFUNCTION, &curl_put_header_cb); | ||
551 | //curl_easy_setopt (s->client_put, CURLOPT_WRITEHEADER, ps); | ||
552 | curl_easy_setopt (s->client_put, CURLOPT_READFUNCTION, client_send_cb); | ||
553 | curl_easy_setopt (s->client_put, CURLOPT_READDATA, s); | ||
554 | curl_easy_setopt (s->client_put, CURLOPT_WRITEFUNCTION, client_receive); | ||
555 | curl_easy_setopt (s->client_put, CURLOPT_WRITEDATA, s); | ||
556 | curl_easy_setopt (s->client_put, CURLOPT_TIMEOUT_MS, | ||
557 | (long) GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value); | ||
558 | curl_easy_setopt (s->client_put, CURLOPT_PRIVATE, s); | ||
559 | curl_easy_setopt (s->client_put, CURLOPT_CONNECTTIMEOUT_MS, | ||
560 | (long) HTTP_NOT_VALIDATED_TIMEOUT.rel_value); | ||
561 | curl_easy_setopt (s->client_put, CURLOPT_BUFFERSIZE, | ||
562 | 2 * GNUNET_SERVER_MAX_MESSAGE_SIZE); | ||
563 | #if CURL_TCP_NODELAY | ||
564 | curl_easy_setopt (s->client_put, CURLOPT_TCP_NODELAY, 1); | ||
565 | #endif | ||
566 | |||
567 | GNUNET_free (url); | ||
568 | |||
569 | mret = curl_multi_add_handle (plugin->client_mh, s->client_get); | ||
570 | if (mret != CURLM_OK) | ||
571 | { | ||
572 | curl_easy_cleanup (s->client_get); | ||
573 | res = GNUNET_SYSERR; | ||
574 | GNUNET_break (0); | ||
575 | } | ||
576 | |||
577 | mret = curl_multi_add_handle (plugin->client_mh, s->client_put); | ||
578 | if (mret != CURLM_OK) | ||
579 | { | ||
580 | curl_multi_remove_handle (plugin->client_mh, s->client_get); | ||
581 | curl_easy_cleanup (s->client_get); | ||
582 | curl_easy_cleanup (s->client_put); | ||
583 | res = GNUNET_SYSERR; | ||
584 | GNUNET_break (0); | ||
585 | } | ||
586 | |||
587 | /* Perform connect */ | ||
588 | plugin->cur_connections += 2; | ||
589 | |||
590 | plugin->outbound_sessions ++; | ||
591 | GNUNET_STATISTICS_set (plugin->env->stats, | ||
592 | "# HTTP outbound sessions", | ||
593 | plugin->outbound_sessions, | ||
594 | GNUNET_NO); | ||
595 | |||
596 | /* Re-schedule since handles have changed */ | ||
597 | if (plugin->client_perform_task != GNUNET_SCHEDULER_NO_TASK) | ||
598 | { | ||
599 | GNUNET_SCHEDULER_cancel (plugin->client_perform_task); | ||
600 | plugin->client_perform_task = GNUNET_SCHEDULER_NO_TASK; | ||
601 | } | ||
602 | plugin->client_perform_task = GNUNET_SCHEDULER_add_now (client_run, plugin); | ||
603 | |||
604 | return res; | ||
605 | } | ||
606 | |||
607 | |||
608 | int | ||
609 | client_start (struct Plugin *plugin) | ||
610 | { | ||
611 | int res = GNUNET_OK; | ||
612 | p = plugin; | ||
613 | |||
614 | curl_global_init (CURL_GLOBAL_ALL); | ||
615 | plugin->client_mh = curl_multi_init (); | ||
616 | |||
617 | if (NULL == plugin->client_mh) | ||
618 | { | ||
619 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, | ||
620 | _ | ||
621 | ("Could not initialize curl multi handle, failed to start %s plugin!\n"), | ||
622 | plugin->name); | ||
623 | res = GNUNET_SYSERR; | ||
624 | } | ||
625 | return res; | ||
626 | } | ||
627 | |||
628 | |||
629 | void | ||
630 | client_stop (struct Plugin *plugin) | ||
631 | { | ||
632 | p = NULL; | ||
633 | if (plugin->client_perform_task != GNUNET_SCHEDULER_NO_TASK) | ||
634 | { | ||
635 | GNUNET_SCHEDULER_cancel (plugin->client_perform_task); | ||
636 | plugin->client_perform_task = GNUNET_SCHEDULER_NO_TASK; | ||
637 | } | ||
638 | |||
639 | curl_multi_cleanup (plugin->client_mh); | ||
640 | curl_global_cleanup (); | ||
641 | } | ||
642 | |||
643 | |||
644 | |||
645 | /* end of plugin_transport_http_client.c */ | ||
diff --git a/src/transport/plugin_transport_http_server.c b/src/transport/plugin_transport_http_server.c index f81f5cf6e..da0c11e24 100644 --- a/src/transport/plugin_transport_http_server.c +++ b/src/transport/plugin_transport_http_server.c | |||
@@ -19,1318 +19,289 @@ | |||
19 | */ | 19 | */ |
20 | 20 | ||
21 | /** | 21 | /** |
22 | * @file transport/plugin_transport_http.c | 22 | * @file transport/plugin_transport_http_server.c |
23 | * @brief http transport service plugin | 23 | * @brief HTTP/S server transport plugin |
24 | * @author Matthias Wachs | 24 | * @author Matthias Wachs |
25 | */ | 25 | */ |
26 | 26 | ||
27 | #include "plugin_transport_http.h" | 27 | #include "platform.h" |
28 | #include "gnunet_protocols.h" | ||
29 | #include "gnunet_connection_lib.h" | ||
30 | #include "gnunet_server_lib.h" | ||
31 | #include "gnunet_service_lib.h" | ||
32 | #include "gnunet_statistics_service.h" | ||
33 | #include "gnunet_transport_service.h" | ||
34 | #include "gnunet_transport_plugin.h" | ||
35 | |||
36 | #if BUILD_HTTPS | ||
37 | #define LIBGNUNET_PLUGIN_TRANSPORT_INIT libgnunet_plugin_transport_https_server_init | ||
38 | #define LIBGNUNET_PLUGIN_TRANSPORT_DONE libgnunet_plugin_transport_https_server_done | ||
39 | #else | ||
40 | #define LIBGNUNET_PLUGIN_TRANSPORT_INIT libgnunet_plugin_transport_http_server_init | ||
41 | #define LIBGNUNET_PLUGIN_TRANSPORT_DONE libgnunet_plugin_transport_http_server_done | ||
42 | #endif | ||
28 | 43 | ||
29 | #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>" | ||
30 | #define _RECEIVE 0 | ||
31 | #define _SEND 1 | ||
32 | 44 | ||
33 | static struct Plugin * p; | 45 | #define DEBUG_TEMPLATE GNUNET_EXTRA_LOGGING |
34 | 46 | ||
35 | /** | 47 | /** |
36 | * Function that queries MHD's select sets and | 48 | * After how long do we expire an address that we |
37 | * starts the task waiting for them. | 49 | * learned from another peer if it is not reconfirmed |
38 | * @param plugin plugin | 50 | * by anyone? |
39 | * @param daemon_handle the MHD daemon handle | ||
40 | * @param now schedule now or with MHD delay | ||
41 | * @return gnunet task identifier | ||
42 | */ | 51 | */ |
43 | static GNUNET_SCHEDULER_TaskIdentifier | 52 | #define LEARNED_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 6) |
44 | server_schedule (struct Plugin *plugin, | ||
45 | struct MHD_Daemon *daemon_handle, | ||
46 | int now); | ||
47 | 53 | ||
48 | static void | ||
49 | server_log (void *arg, const char *fmt, va_list ap) | ||
50 | { | ||
51 | char text[1024]; | ||
52 | |||
53 | vsnprintf (text, sizeof (text), fmt, ap); | ||
54 | va_end (ap); | ||
55 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Server: %s\n", text); | ||
56 | } | ||
57 | 54 | ||
58 | /** | 55 | /** |
59 | * Check if incoming connection is accepted. | 56 | * Encapsulation of all of the state of the plugin. |
60 | * NOTE: Here every connection is accepted | ||
61 | * @param cls plugin as closure | ||
62 | * @param addr address of incoming connection | ||
63 | * @param addr_len address length of incoming connection | ||
64 | * @return MHD_YES if connection is accepted, MHD_NO if connection is rejected | ||
65 | * | ||
66 | */ | 57 | */ |
67 | static int | 58 | struct Plugin; |
68 | server_accept_cb (void *cls, const struct sockaddr *addr, socklen_t addr_len) | ||
69 | { | ||
70 | struct Plugin *plugin = cls; | ||
71 | |||
72 | if (plugin->cur_connections <= plugin->max_connections) | ||
73 | return MHD_YES; | ||
74 | else | ||
75 | { | ||
76 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
77 | "Server: Cannot accept new connections\n"); | ||
78 | return MHD_NO; | ||
79 | } | ||
80 | } | ||
81 | |||
82 | |||
83 | #if BUILD_HTTPS | ||
84 | static char * | ||
85 | server_load_file (const char *file) | ||
86 | { | ||
87 | struct GNUNET_DISK_FileHandle *gn_file; | ||
88 | uint64_t fsize; | ||
89 | char *text = NULL; | ||
90 | |||
91 | if (GNUNET_OK != GNUNET_DISK_file_size (file, | ||
92 | &fsize, GNUNET_NO, GNUNET_YES)) | ||
93 | return NULL; | ||
94 | text = GNUNET_malloc (fsize + 1); | ||
95 | gn_file = | ||
96 | GNUNET_DISK_file_open (file, GNUNET_DISK_OPEN_READ, | ||
97 | GNUNET_DISK_PERM_USER_READ); | ||
98 | if (gn_file == NULL) | ||
99 | { | ||
100 | GNUNET_free (text); | ||
101 | return NULL; | ||
102 | } | ||
103 | if (GNUNET_SYSERR == GNUNET_DISK_file_read (gn_file, text, fsize)) | ||
104 | { | ||
105 | GNUNET_free (text); | ||
106 | GNUNET_DISK_file_close (gn_file); | ||
107 | return NULL; | ||
108 | } | ||
109 | text[fsize] = '\0'; | ||
110 | GNUNET_DISK_file_close (gn_file); | ||
111 | return text; | ||
112 | } | ||
113 | #endif | ||
114 | |||
115 | |||
116 | #if BUILD_HTTPS | ||
117 | |||
118 | static int | ||
119 | server_load_certificate (struct Plugin *plugin) | ||
120 | { | ||
121 | int res = GNUNET_OK; | ||
122 | |||
123 | char *key_file; | ||
124 | char *cert_file; | ||
125 | |||
126 | /* Get crypto init string from config | ||
127 | * If not present just use default values */ | ||
128 | |||
129 | GNUNET_assert (GNUNET_OK == | ||
130 | GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, | ||
131 | plugin->name, | ||
132 | "CRYPTO_INIT", | ||
133 | &plugin->crypto_init)); | ||
134 | |||
135 | if (GNUNET_OK != | ||
136 | GNUNET_CONFIGURATION_get_value_filename (plugin->env->cfg, plugin->name, | ||
137 | "KEY_FILE", &key_file)) | ||
138 | { | ||
139 | key_file = GNUNET_strdup ("https_key.key"); | ||
140 | } | ||
141 | |||
142 | if (GNUNET_OK != | ||
143 | GNUNET_CONFIGURATION_get_value_filename (plugin->env->cfg, plugin->name, | ||
144 | "CERT_FILE", &cert_file)) | ||
145 | { | ||
146 | GNUNET_asprintf (&cert_file, "%s", "https_cert.crt"); | ||
147 | } | ||
148 | |||
149 | /* read key & certificates from file */ | ||
150 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
151 | "Loading TLS certificate from key-file `%s' cert-file`%s'\n", | ||
152 | key_file, cert_file); | ||
153 | |||
154 | plugin->key = server_load_file (key_file); | ||
155 | plugin->cert = server_load_file (cert_file); | ||
156 | |||
157 | if ((plugin->key == NULL) || (plugin->cert == NULL)) | ||
158 | { | ||
159 | struct GNUNET_OS_Process *cert_creation; | ||
160 | |||
161 | GNUNET_free_non_null (plugin->key); | ||
162 | plugin->key = NULL; | ||
163 | GNUNET_free_non_null (plugin->cert); | ||
164 | plugin->cert = NULL; | ||
165 | |||
166 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
167 | "No usable TLS certificate found, creating certificate\n"); | ||
168 | errno = 0; | ||
169 | cert_creation = | ||
170 | GNUNET_OS_start_process (GNUNET_NO, GNUNET_OS_INHERIT_STD_OUT_AND_ERR, NULL, NULL, | ||
171 | "gnunet-transport-certificate-creation", | ||
172 | "gnunet-transport-certificate-creation", | ||
173 | key_file, cert_file, NULL); | ||
174 | if (cert_creation == NULL) | ||
175 | { | ||
176 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, | ||
177 | _ | ||
178 | ("Could not create a new TLS certificate, program `gnunet-transport-certificate-creation' could not be started!\n")); | ||
179 | GNUNET_free (key_file); | ||
180 | GNUNET_free (cert_file); | ||
181 | |||
182 | GNUNET_free_non_null (plugin->key); | ||
183 | plugin->key = NULL; | ||
184 | GNUNET_free_non_null (plugin->cert); | ||
185 | plugin->cert = NULL; | ||
186 | GNUNET_free_non_null (plugin->crypto_init); | ||
187 | plugin->crypto_init = NULL; | ||
188 | |||
189 | return GNUNET_SYSERR; | ||
190 | } | ||
191 | GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (cert_creation)); | ||
192 | GNUNET_OS_process_destroy (cert_creation); | ||
193 | |||
194 | plugin->key = server_load_file (key_file); | ||
195 | plugin->cert = server_load_file (cert_file); | ||
196 | } | ||
197 | |||
198 | if ((plugin->key == NULL) || (plugin->cert == NULL)) | ||
199 | { | ||
200 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, | ||
201 | _ | ||
202 | ("No usable TLS certificate found and creating one failed!\n"), | ||
203 | "transport-https"); | ||
204 | GNUNET_free (key_file); | ||
205 | GNUNET_free (cert_file); | ||
206 | |||
207 | GNUNET_free_non_null (plugin->key); | ||
208 | plugin->key = NULL; | ||
209 | GNUNET_free_non_null (plugin->cert); | ||
210 | plugin->cert = NULL; | ||
211 | GNUNET_free_non_null (plugin->crypto_init); | ||
212 | plugin->crypto_init = NULL; | ||
213 | |||
214 | return GNUNET_SYSERR; | ||
215 | } | ||
216 | GNUNET_free (key_file); | ||
217 | GNUNET_free (cert_file); | ||
218 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TLS certificate loaded\n"); | ||
219 | return res; | ||
220 | } | ||
221 | #endif | ||
222 | 59 | ||
223 | 60 | ||
224 | /** | 61 | /** |
225 | * Reschedule the execution of both IPv4 and IPv6 server | 62 | * Session handle for connections. |
226 | * @param plugin the plugin | ||
227 | * @param server which server to schedule v4 or v6? | ||
228 | * @param now GNUNET_YES to schedule execution immediately, GNUNET_NO to wait | ||
229 | * until timeout | ||
230 | */ | 63 | */ |
231 | static void | 64 | struct Session |
232 | server_reschedule (struct Plugin *plugin, struct MHD_Daemon *server, int now) | ||
233 | { | 65 | { |
234 | if ((server == plugin->server_v4) && (plugin->server_v4 != NULL)) | 66 | /** |
235 | { | 67 | * To whom are we talking to (set to our identity |
236 | if (GNUNET_YES == plugin->server_v4_immediately) | 68 | * if we are still waiting for the welcome message) |
237 | return; /* No rescheduling, server will run asap */ | 69 | */ |
238 | 70 | struct GNUNET_PeerIdentity sender; | |
239 | if (GNUNET_YES == now) | 71 | |
240 | plugin->server_v4_immediately = GNUNET_YES; | 72 | /** |
241 | 73 | * Stored in a linked list. | |
242 | if (plugin->server_v4_task != GNUNET_SCHEDULER_NO_TASK) | 74 | */ |
243 | { | 75 | struct Session *next; |
244 | GNUNET_SCHEDULER_cancel (plugin->server_v4_task); | 76 | |
245 | plugin->server_v4_task = GNUNET_SCHEDULER_NO_TASK; | 77 | /** |
246 | } | 78 | * Pointer to the global plugin struct. |
247 | plugin->server_v4_task = server_schedule (plugin, plugin->server_v4, now); | 79 | */ |
248 | } | 80 | struct Plugin *plugin; |
249 | 81 | ||
250 | if ((server == plugin->server_v6) && (plugin->server_v6 != NULL)) | 82 | /** |
251 | { | 83 | * The client (used to identify this connection) |
252 | if (GNUNET_YES == plugin->server_v6_immediately) | 84 | */ |
253 | return; /* No rescheduling, server will run asap */ | 85 | /* void *client; */ |
254 | 86 | ||
255 | if (GNUNET_YES == now) | 87 | /** |
256 | plugin->server_v6_immediately = GNUNET_YES; | 88 | * Continuation function to call once the transmission buffer |
257 | 89 | * has again space available. NULL if there is no | |
258 | if (plugin->server_v6_task != GNUNET_SCHEDULER_NO_TASK) | 90 | * continuation to call. |
259 | { | 91 | */ |
260 | GNUNET_SCHEDULER_cancel (plugin->server_v6_task); | 92 | GNUNET_TRANSPORT_TransmitContinuation transmit_cont; |
261 | plugin->server_v6_task = GNUNET_SCHEDULER_NO_TASK; | 93 | |
262 | } | 94 | /** |
263 | plugin->server_v6_task = server_schedule (plugin, plugin->server_v6, now); | 95 | * Closure for transmit_cont. |
264 | } | 96 | */ |
265 | } | 97 | void *transmit_cont_cls; |
98 | |||
99 | /** | ||
100 | * At what time did we reset last_received last? | ||
101 | */ | ||
102 | struct GNUNET_TIME_Absolute last_quota_update; | ||
103 | |||
104 | /** | ||
105 | * How many bytes have we received since the "last_quota_update" | ||
106 | * timestamp? | ||
107 | */ | ||
108 | uint64_t last_received; | ||
109 | |||
110 | /** | ||
111 | * Number of bytes per ms that this peer is allowed | ||
112 | * to send to us. | ||
113 | */ | ||
114 | uint32_t quota; | ||
115 | |||
116 | }; | ||
266 | 117 | ||
267 | /** | 118 | /** |
268 | * Callback called by MessageStreamTokenizer when a message has arrived | 119 | * Encapsulation of all of the state of the plugin. |
269 | * @param cls current session as closure | ||
270 | * @param client clien | ||
271 | * @param message the message to be forwarded to transport service | ||
272 | */ | 120 | */ |
273 | static int | 121 | struct Plugin |
274 | server_receive_mst_cb (void *cls, void *client, | ||
275 | const struct GNUNET_MessageHeader *message) | ||
276 | { | 122 | { |
277 | struct Session *s = cls; | 123 | /** |
278 | 124 | * Our environment. | |
279 | GNUNET_assert (NULL != p); | 125 | */ |
280 | if (GNUNET_NO == exist_session(p, s)) | 126 | struct GNUNET_TRANSPORT_PluginEnvironment *env; |
281 | return GNUNET_OK; | ||
282 | 127 | ||
283 | struct Plugin *plugin = s->plugin; | 128 | /** |
284 | struct GNUNET_TIME_Relative delay; | 129 | * List of open sessions. |
130 | */ | ||
131 | struct Session *sessions; | ||
285 | 132 | ||
286 | delay = http_plugin_receive (s, &s->target, message, s, s->addr, s->addrlen); | 133 | }; |
287 | |||
288 | s->next_receive = | ||
289 | GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), delay); | ||
290 | |||
291 | if (delay.rel_value > 0) | ||
292 | { | ||
293 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
294 | "Server: peer `%s' address `%s' next read delayed for %llu ms\n", | ||
295 | GNUNET_i2s (&s->target), | ||
296 | http_plugin_address_to_string (NULL, s->addr, s->addrlen), | ||
297 | delay); | ||
298 | } | ||
299 | return GNUNET_OK; | ||
300 | } | ||
301 | 134 | ||
302 | 135 | ||
303 | /** | 136 | /** |
304 | * Callback called by MHD when it needs data to send | 137 | * Function that can be used by the transport service to transmit |
305 | * @param cls current session | 138 | * a message using the plugin. Note that in the case of a |
306 | * @param pos position in buffer | 139 | * peer disconnecting, the continuation MUST be called |
307 | * @param buf the buffer to write data to | 140 | * prior to the disconnect notification itself. This function |
308 | * @param max max number of bytes available in buffer | 141 | * will be called with this peer's HELLO message to initiate |
309 | * @return bytes written to buffer | 142 | * a fresh connection to another peer. |
143 | * | ||
144 | * @param cls closure | ||
145 | * @param session which session must be used | ||
146 | * @param msgbuf the message to transmit | ||
147 | * @param msgbuf_size number of bytes in 'msgbuf' | ||
148 | * @param priority how important is the message (most plugins will | ||
149 | * ignore message priority and just FIFO) | ||
150 | * @param to how long to wait at most for the transmission (does not | ||
151 | * require plugins to discard the message after the timeout, | ||
152 | * just advisory for the desired delay; most plugins will ignore | ||
153 | * this as well) | ||
154 | * @param cont continuation to call once the message has | ||
155 | * been transmitted (or if the transport is ready | ||
156 | * for the next transmission call; or if the | ||
157 | * peer disconnected...); can be NULL | ||
158 | * @param cont_cls closure for cont | ||
159 | * @return number of bytes used (on the physical network, with overheads); | ||
160 | * -1 on hard errors (i.e. address invalid); 0 is a legal value | ||
161 | * and does NOT mean that the message was not transmitted (DV) | ||
310 | */ | 162 | */ |
311 | static ssize_t | 163 | static ssize_t |
312 | server_send_callback (void *cls, uint64_t pos, char *buf, size_t max) | 164 | http_server_plugin_send (void *cls, |
165 | struct Session *session, | ||
166 | const char *msgbuf, size_t msgbuf_size, | ||
167 | unsigned int priority, | ||
168 | struct GNUNET_TIME_Relative to, | ||
169 | GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls) | ||
313 | { | 170 | { |
314 | struct Session *s = cls; | 171 | struct Plugin *plugin = cls; |
315 | ssize_t bytes_read = 0; | 172 | int bytes_sent = 0; |
316 | struct HTTP_Message *msg; | ||
317 | |||
318 | GNUNET_assert (NULL != p); | ||
319 | if (GNUNET_NO == exist_session(p, s)) | ||
320 | return 0; | ||
321 | msg = s->msg_head; | ||
322 | if (NULL != msg) | ||
323 | { | ||
324 | /* sending */ | ||
325 | bytes_read = GNUNET_MIN (msg->size - msg->pos, | ||
326 | max); | ||
327 | memcpy (buf, &msg->buf[msg->pos], bytes_read); | ||
328 | msg->pos += bytes_read; | ||
329 | |||
330 | /* removing message */ | ||
331 | if (msg->pos == msg->size) | ||
332 | { | ||
333 | GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg); | ||
334 | if (NULL != msg->transmit_cont) | ||
335 | msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_OK); | ||
336 | GNUNET_free (msg); | ||
337 | } | ||
338 | } | ||
339 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, s->plugin->name, | ||
340 | "Server: %p: sent %u bytes\n", s, bytes_read); | ||
341 | return bytes_read; | ||
342 | } | ||
343 | |||
344 | 173 | ||
345 | static struct Session * | 174 | GNUNET_assert (plugin != NULL); |
346 | server_lookup_session (struct Plugin *plugin, | 175 | GNUNET_assert (session != NULL); |
347 | struct ServerConnection * sc) | ||
348 | { | ||
349 | struct Session *s; | ||
350 | 176 | ||
351 | for (s = plugin->head; NULL != s; s = s->next) | 177 | /* struct Plugin *plugin = cls; */ |
352 | if ((s->server_recv == sc) || (s->server_send == sc)) | 178 | return bytes_sent; |
353 | return s; | ||
354 | for (s = plugin->server_semi_head; NULL != s; s = s->next) | ||
355 | if ((s->server_recv == sc) || (s->server_send == sc)) | ||
356 | return s; | ||
357 | return NULL; | ||
358 | } | 179 | } |
359 | 180 | ||
360 | 181 | ||
361 | static struct ServerConnection * | ||
362 | server_lookup_serverconnection (struct Plugin *plugin, | ||
363 | struct MHD_Connection *mhd_connection, const char *url, | ||
364 | const char *method) | ||
365 | { | ||
366 | struct Session *s = NULL; | ||
367 | struct Session *t; | ||
368 | struct ServerConnection *sc = NULL; | ||
369 | const union MHD_ConnectionInfo *conn_info; | ||
370 | struct GNUNET_ATS_Information ats; | ||
371 | struct IPv4HttpAddress a4; | ||
372 | struct IPv6HttpAddress a6; | ||
373 | struct sockaddr_in *s4; | ||
374 | struct sockaddr_in6 *s6; | ||
375 | void *a; | ||
376 | size_t a_len; | ||
377 | struct GNUNET_PeerIdentity target; | ||
378 | uint32_t tag = 0; | ||
379 | int direction = GNUNET_SYSERR; | ||
380 | |||
381 | /* url parsing variables */ | ||
382 | size_t url_len; | ||
383 | char *url_end; | ||
384 | char *hash_start; | ||
385 | char *hash_end; | ||
386 | char *tag_start; | ||
387 | char *tag_end; | ||
388 | |||
389 | conn_info = MHD_get_connection_info (mhd_connection, | ||
390 | MHD_CONNECTION_INFO_CLIENT_ADDRESS); | ||
391 | if ((conn_info->client_addr->sa_family != AF_INET) && | ||
392 | (conn_info->client_addr->sa_family != AF_INET6)) | ||
393 | return NULL; | ||
394 | |||
395 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
396 | "New %s connection from %s\n", | ||
397 | method, url); | ||
398 | /* URL parsing | ||
399 | * URL is valid if it is in the form [peerid[103];tag]*/ | ||
400 | url_len = strlen (url); | ||
401 | url_end = (char *) &url[url_len]; | ||
402 | |||
403 | if (url_len < 105) | ||
404 | { | ||
405 | goto error; /* too short */ | ||
406 | } | ||
407 | hash_start = strrchr (url, '/'); | ||
408 | if (NULL == hash_start) | ||
409 | { | ||
410 | goto error; /* '/' delimiter not found */ | ||
411 | } | ||
412 | if (hash_start >= url_end) | ||
413 | { | ||
414 | goto error; /* mal formed */ | ||
415 | } | ||
416 | hash_start++; | ||
417 | |||
418 | hash_end = strrchr (hash_start, ';'); | ||
419 | if (NULL == hash_end) | ||
420 | goto error; /* ';' delimiter not found */ | ||
421 | if (hash_end >= url_end) | ||
422 | { | ||
423 | goto error; /* mal formed */ | ||
424 | } | ||
425 | |||
426 | if (hash_start >= hash_end) | ||
427 | { | ||
428 | goto error; /* mal formed */ | ||
429 | } | ||
430 | |||
431 | if ((strlen(hash_start) - strlen(hash_end)) != 103) | ||
432 | { | ||
433 | goto error; /* invalid hash length */ | ||
434 | } | ||
435 | |||
436 | char hash[104]; | ||
437 | memcpy (hash, hash_start, 103); | ||
438 | hash[103] = '\0'; | ||
439 | if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((const char *) hash, &(target.hashPubKey))) | ||
440 | { | ||
441 | goto error; /* mal formed */ | ||
442 | } | ||
443 | |||
444 | if (hash_end >= url_end) | ||
445 | { | ||
446 | goto error; /* mal formed */ | ||
447 | } | ||
448 | |||
449 | tag_start = &hash_end[1]; | ||
450 | /* Converting tag */ | ||
451 | tag_end = NULL; | ||
452 | tag = strtoul (tag_start, &tag_end, 10); | ||
453 | if (tag == 0) | ||
454 | { | ||
455 | goto error; /* mal formed */ | ||
456 | } | ||
457 | if (tag_end == NULL) | ||
458 | { | ||
459 | goto error; /* mal formed */ | ||
460 | } | ||
461 | if (tag_end != url_end) | ||
462 | { | ||
463 | goto error; /* mal formed */ | ||
464 | } | ||
465 | |||
466 | if (0 == strcmp (MHD_HTTP_METHOD_PUT, method)) | ||
467 | direction = _RECEIVE; | ||
468 | else if (0 == strcmp (MHD_HTTP_METHOD_GET, method)) | ||
469 | direction = _SEND; | ||
470 | else | ||
471 | { | ||
472 | goto error; | ||
473 | } | ||
474 | |||
475 | plugin->cur_connections++; | ||
476 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
477 | "Server: New %s connection from %s with tag %u\n", | ||
478 | method, | ||
479 | GNUNET_i2s (&target), tag); | ||
480 | |||
481 | /* find duplicate session */ | ||
482 | t = plugin->head; | ||
483 | while (t != NULL) | ||
484 | { | ||
485 | if ((t->inbound) && | ||
486 | (0 == memcmp (&t->target, &target, sizeof (struct GNUNET_PeerIdentity))) | ||
487 | && | ||
488 | /* FIXME add source address comparison */ | ||
489 | (t->tag == tag)) | ||
490 | break; | ||
491 | t = t->next; | ||
492 | } | ||
493 | if (t != NULL) | ||
494 | { | ||
495 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
496 | "Server: Duplicate session, dismissing new connection from peer `%s'\n", | ||
497 | GNUNET_i2s (&target)); | ||
498 | goto error; | ||
499 | } | ||
500 | |||
501 | /* find semi-session */ | ||
502 | t = plugin->server_semi_head; | ||
503 | |||
504 | while (t != NULL) | ||
505 | { | ||
506 | /* FIXME add source address comparison */ | ||
507 | if ((0 == memcmp (&t->target, &target, sizeof (struct GNUNET_PeerIdentity))) | ||
508 | && (t->tag == tag)) | ||
509 | { | ||
510 | break; | ||
511 | } | ||
512 | t = t->next; | ||
513 | } | ||
514 | |||
515 | if (t == NULL) | ||
516 | goto create; | ||
517 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
518 | "Server: Found existing semi-session for `%s'\n", | ||
519 | GNUNET_i2s (&target)); | ||
520 | |||
521 | if ((direction == _SEND) && (t->server_send != NULL)) | ||
522 | { | ||
523 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
524 | "Server: Duplicate GET session, dismissing new connection from peer `%s'\n", | ||
525 | GNUNET_i2s (&target)); | ||
526 | goto error; | ||
527 | } | ||
528 | else | ||
529 | { | ||
530 | s = t; | ||
531 | GNUNET_CONTAINER_DLL_remove (plugin->server_semi_head, | ||
532 | plugin->server_semi_tail, s); | ||
533 | GNUNET_CONTAINER_DLL_insert (plugin->head, plugin->tail, s); | ||
534 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
535 | "Server: Found matching semi-session, merging session for peer `%s'\n", | ||
536 | GNUNET_i2s (&target)); | ||
537 | |||
538 | plugin->inbound_sessions ++; | ||
539 | GNUNET_STATISTICS_set (plugin->env->stats, | ||
540 | "# HTTP inbound sessions", | ||
541 | plugin->inbound_sessions, | ||
542 | GNUNET_NO); | ||
543 | GNUNET_assert (NULL != s); | ||
544 | goto found; | ||
545 | } | ||
546 | if ((direction == _RECEIVE) && (t->server_recv != NULL)) | ||
547 | { | ||
548 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
549 | "Server: Duplicate PUT session, dismissing new connection from peer `%s'\n", | ||
550 | GNUNET_i2s (&target)); | ||
551 | goto error; | ||
552 | } | ||
553 | else | ||
554 | { | ||
555 | s = t; | ||
556 | GNUNET_CONTAINER_DLL_remove (plugin->server_semi_head, | ||
557 | plugin->server_semi_tail, s); | ||
558 | GNUNET_CONTAINER_DLL_insert (plugin->head, plugin->tail, s); | ||
559 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
560 | "Server: Found matching semi-session, merging session for peer `%s'\n", | ||
561 | GNUNET_i2s (&target)); | ||
562 | plugin->inbound_sessions ++; | ||
563 | GNUNET_STATISTICS_set (plugin->env->stats, | ||
564 | "# HTTP inbound sessions", | ||
565 | plugin->inbound_sessions, | ||
566 | GNUNET_NO); | ||
567 | GNUNET_assert (NULL != s); | ||
568 | goto found; | ||
569 | } | ||
570 | |||
571 | create: | ||
572 | /* create new session */ | ||
573 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
574 | "Server: Creating new session for peer `%s' \n", | ||
575 | GNUNET_i2s (&target)); | ||
576 | switch (conn_info->client_addr->sa_family) | ||
577 | { | ||
578 | case (AF_INET): | ||
579 | s4 = ((struct sockaddr_in *) conn_info->client_addr); | ||
580 | a4.u4_port = s4->sin_port; | ||
581 | memcpy (&a4.ipv4_addr, &s4->sin_addr, sizeof (struct in_addr)); | ||
582 | a = &a4; | ||
583 | a_len = sizeof (struct IPv4HttpAddress); | ||
584 | ats = plugin->env->get_address_type (plugin->env->cls, (const struct sockaddr *) s4, sizeof (struct sockaddr_in)); | ||
585 | break; | ||
586 | case (AF_INET6): | ||
587 | s6 = ((struct sockaddr_in6 *) conn_info->client_addr); | ||
588 | a6.u6_port = s6->sin6_port; | ||
589 | memcpy (&a6.ipv6_addr, &s6->sin6_addr, sizeof (struct in6_addr)); | ||
590 | a = &a6; | ||
591 | a_len = sizeof (struct IPv6HttpAddress); | ||
592 | ats = plugin->env->get_address_type (plugin->env->cls, (const struct sockaddr *) s6, sizeof (struct sockaddr_in6)); | ||
593 | break; | ||
594 | default: | ||
595 | GNUNET_break (0); | ||
596 | goto error; | ||
597 | } | ||
598 | s = create_session (plugin, &target, a, a_len); | ||
599 | GNUNET_assert (NULL != s); | ||
600 | s->ats_address_network_type = ats.value; | ||
601 | s->inbound = GNUNET_YES; | ||
602 | s->next_receive = GNUNET_TIME_UNIT_ZERO_ABS; | ||
603 | s->tag = tag; | ||
604 | s->server_recv = NULL; | ||
605 | s->server_send = NULL; | ||
606 | |||
607 | GNUNET_CONTAINER_DLL_insert (plugin->server_semi_head, | ||
608 | plugin->server_semi_tail, s); | ||
609 | goto found; | ||
610 | |||
611 | error: | ||
612 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
613 | "Server: Invalid connection request\n"); | ||
614 | return NULL; | ||
615 | |||
616 | found: | ||
617 | sc = GNUNET_malloc (sizeof (struct ServerConnection)); | ||
618 | sc->mhd_conn = mhd_connection; | ||
619 | sc->direction = direction; | ||
620 | sc->session = s; | ||
621 | if (direction == _SEND) | ||
622 | s->server_send = sc; | ||
623 | if (direction == _RECEIVE) | ||
624 | s->server_recv = sc; | ||
625 | |||
626 | #if MHD_VERSION >= 0x00090E00 | ||
627 | int to = (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value / 1000); | ||
628 | |||
629 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
630 | "Server: Setting timeout for %p to %u sec.\n", sc, to); | ||
631 | MHD_set_connection_option (mhd_connection, MHD_CONNECTION_OPTION_TIMEOUT, to); | ||
632 | |||
633 | struct MHD_Daemon *d = NULL; | ||
634 | |||
635 | if (s->addrlen == sizeof (struct IPv6HttpAddress)) | ||
636 | d = plugin->server_v6; | ||
637 | if (s->addrlen == sizeof (struct IPv4HttpAddress)) | ||
638 | d = plugin->server_v4; | ||
639 | |||
640 | server_reschedule (plugin, d, GNUNET_NO); | ||
641 | #endif | ||
642 | return sc; | ||
643 | } | ||
644 | 182 | ||
645 | /** | 183 | /** |
646 | * Process GET or PUT request received via MHD. For | 184 | * Function that can be used to force the plugin to disconnect |
647 | * GET, queue response that will send back our pending | 185 | * from the given peer and cancel all previous transmissions |
648 | * messages. For PUT, process incoming data and send | 186 | * (and their continuationc). |
649 | * to GNUnet core. In either case, check if a session | 187 | * |
650 | * already exists and create a new one if not. | 188 | * @param cls closure |
189 | * @param target peer from which to disconnect | ||
651 | */ | 190 | */ |
652 | static int | 191 | static void |
653 | server_access_cb (void *cls, struct MHD_Connection *mhd_connection, | 192 | http_server_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *target) |
654 | const char *url, const char *method, const char *version, | ||
655 | const char *upload_data, size_t * upload_data_size, | ||
656 | void **httpSessionCache) | ||
657 | { | 193 | { |
658 | struct Plugin *plugin = cls; | 194 | // struct Plugin *plugin = cls; |
659 | struct ServerConnection *sc = *httpSessionCache; | 195 | // FIXME |
660 | struct Session *s; | ||
661 | struct MHD_Response *response; | ||
662 | int res = MHD_YES; | ||
663 | |||
664 | GNUNET_assert (cls != NULL); | ||
665 | if (sc == NULL) | ||
666 | { | ||
667 | /* new connection */ | ||
668 | sc = server_lookup_serverconnection (plugin, mhd_connection, url, method); | ||
669 | if (sc != NULL) | ||
670 | (*httpSessionCache) = sc; | ||
671 | else | ||
672 | { | ||
673 | response = | ||
674 | MHD_create_response_from_data (strlen (HTTP_ERROR_RESPONSE), | ||
675 | HTTP_ERROR_RESPONSE, MHD_NO, MHD_NO); | ||
676 | res = MHD_queue_response (mhd_connection, MHD_HTTP_NOT_FOUND, response); | ||
677 | MHD_destroy_response (response); | ||
678 | return res; | ||
679 | } | ||
680 | } | ||
681 | else | ||
682 | { | ||
683 | /* 'old' connection */ | ||
684 | if (NULL == server_lookup_session (plugin, sc)) | ||
685 | { | ||
686 | /* Session was already disconnected */ | ||
687 | return MHD_NO; | ||
688 | } | ||
689 | } | ||
690 | |||
691 | /* existing connection */ | ||
692 | sc = (*httpSessionCache); | ||
693 | s = sc->session; | ||
694 | |||
695 | GNUNET_assert (NULL != s); | ||
696 | |||
697 | /* connection is to be disconnected */ | ||
698 | if (sc->disconnect == GNUNET_YES) | ||
699 | { | ||
700 | /* Sent HTTP/1.1: 200 OK as PUT Response\ */ | ||
701 | response = | ||
702 | MHD_create_response_from_data (strlen ("Thank you!"), "Thank you!", | ||
703 | MHD_NO, MHD_NO); | ||
704 | res = MHD_queue_response (mhd_connection, MHD_HTTP_OK, response); | ||
705 | MHD_destroy_response (response); | ||
706 | return MHD_YES; | ||
707 | } | ||
708 | |||
709 | GNUNET_assert (s != NULL); | ||
710 | /* Check if both directions are connected */ | ||
711 | if ((sc->session->server_recv == NULL) || (sc->session->server_send == NULL)) | ||
712 | { | ||
713 | /* Delayed read from since not both semi-connections are connected */ | ||
714 | return MHD_YES; | ||
715 | } | ||
716 | |||
717 | if (sc->direction == _SEND) | ||
718 | { | ||
719 | response = | ||
720 | MHD_create_response_from_callback (MHD_SIZE_UNKNOWN, | ||
721 | 32 * 1024, | ||
722 | &server_send_callback, s, | ||
723 | NULL); | ||
724 | MHD_queue_response (mhd_connection, MHD_HTTP_OK, response); | ||
725 | MHD_destroy_response (response); | ||
726 | return MHD_YES; | ||
727 | } | ||
728 | if (sc->direction == _RECEIVE) | ||
729 | { | ||
730 | if (*upload_data_size == 0) | ||
731 | { | ||
732 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
733 | "Server: Peer `%s' PUT on address `%s' connected\n", | ||
734 | GNUNET_i2s (&s->target), | ||
735 | http_plugin_address_to_string (NULL, s->addr, | ||
736 | s->addrlen)); | ||
737 | return MHD_YES; | ||
738 | } | ||
739 | |||
740 | /* Receiving data */ | ||
741 | if ((*upload_data_size > 0)) | ||
742 | { | ||
743 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
744 | "Server: peer `%s' PUT on address `%s' received %u bytes\n", | ||
745 | GNUNET_i2s (&s->target), | ||
746 | http_plugin_address_to_string (NULL, s->addr, | ||
747 | s->addrlen), | ||
748 | *upload_data_size); | ||
749 | struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); | ||
750 | |||
751 | if ((s->next_receive.abs_value <= now.abs_value)) | ||
752 | { | ||
753 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
754 | "Server: %p: PUT with %u bytes forwarded to MST\n", s, | ||
755 | *upload_data_size); | ||
756 | if (s->msg_tk == NULL) | ||
757 | { | ||
758 | s->msg_tk = GNUNET_SERVER_mst_create (&server_receive_mst_cb, s); | ||
759 | } | ||
760 | GNUNET_SERVER_mst_receive (s->msg_tk, s, upload_data, | ||
761 | *upload_data_size, GNUNET_NO, GNUNET_NO); | ||
762 | |||
763 | #if MHD_VERSION >= 0x00090E00 | ||
764 | int to = (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value / 1000); | ||
765 | struct ServerConnection *t = NULL; | ||
766 | |||
767 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
768 | "Server: Received %u bytes\n", *upload_data_size); | ||
769 | /* Setting timeouts for other connections */ | ||
770 | if (s->server_recv != NULL) | ||
771 | { | ||
772 | t = s->server_recv; | ||
773 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
774 | "Server: Setting timeout for %p to %u sec.\n", t, | ||
775 | to); | ||
776 | MHD_set_connection_option (t->mhd_conn, MHD_CONNECTION_OPTION_TIMEOUT, | ||
777 | to); | ||
778 | } | ||
779 | if (s->server_send != NULL) | ||
780 | { | ||
781 | t = s->server_send; | ||
782 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
783 | "Server: Setting timeout for %p to %u sec.\n", t, | ||
784 | to); | ||
785 | MHD_set_connection_option (t->mhd_conn, MHD_CONNECTION_OPTION_TIMEOUT, | ||
786 | to); | ||
787 | } | ||
788 | struct MHD_Daemon *d = NULL; | ||
789 | |||
790 | if (s->addrlen == sizeof (struct IPv6HttpAddress)) | ||
791 | d = plugin->server_v6; | ||
792 | if (s->addrlen == sizeof (struct IPv4HttpAddress)) | ||
793 | d = plugin->server_v4; | ||
794 | server_reschedule (plugin, d, GNUNET_NO); | ||
795 | #endif | ||
796 | (*upload_data_size) = 0; | ||
797 | } | ||
798 | else | ||
799 | { | ||
800 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
801 | "Server: %p no inbound bandwidth available! Next read was delayed by %llu ms\n", | ||
802 | s, now.abs_value - s->next_receive.abs_value); | ||
803 | } | ||
804 | return MHD_YES; | ||
805 | } | ||
806 | else | ||
807 | return MHD_NO; | ||
808 | } | ||
809 | return res; | ||
810 | } | 196 | } |
811 | 197 | ||
198 | |||
199 | /** | ||
200 | * Convert the transports address to a nice, human-readable | ||
201 | * format. | ||
202 | * | ||
203 | * @param cls closure | ||
204 | * @param type name of the transport that generated the address | ||
205 | * @param addr one of the addresses of the host, NULL for the last address | ||
206 | * the specific address format depends on the transport | ||
207 | * @param addrlen length of the address | ||
208 | * @param numeric should (IP) addresses be displayed in numeric form? | ||
209 | * @param timeout after how long should we give up? | ||
210 | * @param asc function to call on each string | ||
211 | * @param asc_cls closure for asc | ||
212 | */ | ||
812 | static void | 213 | static void |
813 | server_disconnect_cb (void *cls, struct MHD_Connection *connection, | 214 | http_server_plugin_address_pretty_printer (void *cls, const char *type, |
814 | void **httpSessionCache) | 215 | const void *addr, size_t addrlen, |
216 | int numeric, | ||
217 | struct GNUNET_TIME_Relative timeout, | ||
218 | GNUNET_TRANSPORT_AddressStringCallback | ||
219 | asc, void *asc_cls) | ||
815 | { | 220 | { |
816 | struct ServerConnection *sc = *httpSessionCache; | 221 | asc (asc_cls, NULL); |
817 | struct ServerConnection *tc = NULL; | ||
818 | struct Session *s = NULL; | ||
819 | struct Session *t = NULL; | ||
820 | struct Plugin *plugin = NULL; | ||
821 | |||
822 | if (sc == NULL) | ||
823 | return; | ||
824 | |||
825 | if (NULL == (s = server_lookup_session (p, sc))) | ||
826 | return; | ||
827 | |||
828 | GNUNET_assert (NULL != p); | ||
829 | if (GNUNET_NO == exist_session(p, s)) | ||
830 | return; | ||
831 | |||
832 | plugin = s->plugin; | ||
833 | if (sc->direction == _SEND) | ||
834 | { | ||
835 | |||
836 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
837 | "Server: %p peer `%s' GET on address `%s' disconnected\n", | ||
838 | s->server_send, GNUNET_i2s (&s->target), | ||
839 | http_plugin_address_to_string (NULL, s->addr, s->addrlen)); | ||
840 | s->server_send = NULL; | ||
841 | if (NULL != (tc = s->server_recv)) | ||
842 | { | ||
843 | tc->disconnect = GNUNET_YES; | ||
844 | GNUNET_assert (NULL != tc->mhd_conn); | ||
845 | #if MHD_VERSION >= 0x00090E00 | ||
846 | MHD_set_connection_option (tc->mhd_conn, MHD_CONNECTION_OPTION_TIMEOUT, | ||
847 | 1); | ||
848 | #endif | ||
849 | } | ||
850 | } | ||
851 | if (sc->direction == _RECEIVE) | ||
852 | { | ||
853 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
854 | "Server: %p peer `%s' PUT on address `%s' disconnected\n", | ||
855 | s->server_recv, GNUNET_i2s (&s->target), | ||
856 | http_plugin_address_to_string (NULL, s->addr, s->addrlen)); | ||
857 | s->server_recv = NULL; | ||
858 | if (NULL != (tc = s->server_send)) | ||
859 | { | ||
860 | tc->disconnect = GNUNET_YES; | ||
861 | GNUNET_assert (NULL != tc->mhd_conn); | ||
862 | #if MHD_VERSION >= 0x00090E00 | ||
863 | MHD_set_connection_option (tc->mhd_conn, MHD_CONNECTION_OPTION_TIMEOUT, | ||
864 | 1); | ||
865 | #endif | ||
866 | } | ||
867 | if (s->msg_tk != NULL) | ||
868 | { | ||
869 | GNUNET_SERVER_mst_destroy (s->msg_tk); | ||
870 | s->msg_tk = NULL; | ||
871 | } | ||
872 | } | ||
873 | |||
874 | GNUNET_free (sc); | ||
875 | |||
876 | t = plugin->server_semi_head; | ||
877 | while (t != NULL) | ||
878 | { | ||
879 | if (t == s) | ||
880 | { | ||
881 | GNUNET_CONTAINER_DLL_remove (plugin->server_semi_head, | ||
882 | plugin->server_semi_tail, s); | ||
883 | GNUNET_CONTAINER_DLL_insert (plugin->head, plugin->tail, s); | ||
884 | break; | ||
885 | } | ||
886 | t = t->next; | ||
887 | } | ||
888 | plugin->cur_connections--; | ||
889 | |||
890 | struct MHD_Daemon *d = NULL; | ||
891 | |||
892 | if (s->addrlen == sizeof (struct IPv6HttpAddress)) | ||
893 | d = plugin->server_v6; | ||
894 | if (s->addrlen == sizeof (struct IPv4HttpAddress)) | ||
895 | d = plugin->server_v4; | ||
896 | server_reschedule (plugin, d, GNUNET_NO); | ||
897 | |||
898 | if ((s->server_send == NULL) && (s->server_recv == NULL)) | ||
899 | { | ||
900 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
901 | "Server: peer `%s' on address `%s' disconnected\n", | ||
902 | GNUNET_i2s (&s->target), | ||
903 | http_plugin_address_to_string (NULL, s->addr, s->addrlen)); | ||
904 | if (s->msg_tk != NULL) | ||
905 | { | ||
906 | GNUNET_SERVER_mst_destroy (s->msg_tk); | ||
907 | s->msg_tk = NULL; | ||
908 | } | ||
909 | |||
910 | GNUNET_assert (plugin->inbound_sessions > 0); | ||
911 | plugin->inbound_sessions --; | ||
912 | GNUNET_STATISTICS_set (plugin->env->stats, | ||
913 | "# HTTP inbound sessions", | ||
914 | plugin->inbound_sessions, GNUNET_NO); | ||
915 | |||
916 | notify_session_end (s->plugin, &s->target, s); | ||
917 | } | ||
918 | } | 222 | } |
919 | 223 | ||
920 | int | ||
921 | server_disconnect (struct Session *s) | ||
922 | { | ||
923 | struct ServerConnection * send; | ||
924 | struct ServerConnection * recv; | ||
925 | 224 | ||
926 | send = (struct ServerConnection *) s->server_send; | ||
927 | if (s->server_send != NULL) | ||
928 | { | ||
929 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, s->plugin->name, | ||
930 | "Server: %p / %p Terminating inbound PUT session to peer `%s'\n", | ||
931 | s, s->server_send, GNUNET_i2s (&s->target)); | ||
932 | 225 | ||
933 | send->disconnect = GNUNET_YES; | 226 | /** |
934 | #if MHD_VERSION >= 0x00090E00 | 227 | * Another peer has suggested an address for this |
935 | MHD_set_connection_option (send->mhd_conn, MHD_CONNECTION_OPTION_TIMEOUT, | 228 | * peer and transport plugin. Check that this could be a valid |
936 | 1); | 229 | * address. If so, consider adding it to the list |
937 | #endif | 230 | * of addresses. |
938 | } | 231 | * |
939 | 232 | * @param cls closure | |
940 | recv = (struct ServerConnection *) s->server_recv; | 233 | * @param addr pointer to the address |
941 | if (recv != NULL) | 234 | * @param addrlen length of addr |
942 | { | 235 | * @return GNUNET_OK if this is a plausible address for this peer |
943 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, s->plugin->name, | 236 | * and transport |
944 | "Server: %p / %p Terminating inbound GET session to peer `%s'\n", | 237 | */ |
945 | s, s->server_recv, GNUNET_i2s (&s->target)); | 238 | static int |
946 | 239 | http_server_plugin_address_suggested (void *cls, const void *addr, size_t addrlen) | |
947 | recv->disconnect = GNUNET_YES; | ||
948 | #if MHD_VERSION >= 0x00090E00 | ||
949 | MHD_set_connection_option (recv->mhd_conn, MHD_CONNECTION_OPTION_TIMEOUT, | ||
950 | 1); | ||
951 | #endif | ||
952 | } | ||
953 | |||
954 | /* Schedule connection immediately */ | ||
955 | if (s->addrlen == sizeof (struct IPv4HttpAddress)) | ||
956 | { | ||
957 | server_reschedule (s->plugin, s->plugin->server_v4, GNUNET_YES); | ||
958 | } | ||
959 | else if (s->addrlen == sizeof (struct IPv6HttpAddress)) | ||
960 | { | ||
961 | server_reschedule (s->plugin, s->plugin->server_v6, GNUNET_YES); | ||
962 | } | ||
963 | return GNUNET_OK; | ||
964 | } | ||
965 | |||
966 | int | ||
967 | server_send (struct Session *s, struct HTTP_Message *msg) | ||
968 | { | 240 | { |
969 | GNUNET_CONTAINER_DLL_insert_tail (s->msg_head, s->msg_tail, msg); | 241 | /* struct Plugin *plugin = cls; */ |
970 | 242 | ||
971 | if (s->addrlen == sizeof (struct IPv4HttpAddress)) | 243 | /* check if the address is plausible; if so, |
972 | { | 244 | * add it to our list! */ |
973 | server_reschedule (s->plugin, s->plugin->server_v4, GNUNET_YES); | ||
974 | } | ||
975 | else if (s->addrlen == sizeof (struct IPv6HttpAddress)) | ||
976 | { | ||
977 | server_reschedule (s->plugin, s->plugin->server_v6, GNUNET_YES); | ||
978 | } | ||
979 | else | ||
980 | return GNUNET_SYSERR; | ||
981 | return GNUNET_OK; | 245 | return GNUNET_OK; |
982 | } | 246 | } |
983 | 247 | ||
984 | 248 | ||
985 | |||
986 | /** | 249 | /** |
987 | * Call MHD IPv4 to process pending requests and then go back | 250 | * Function called for a quick conversion of the binary address to |
988 | * and schedule the next run. | 251 | * a numeric address. Note that the caller must not free the |
989 | * @param cls plugin as closure | 252 | * address and that the next call to this function is allowed |
990 | * @param tc task context | 253 | * to override the address again. |
254 | * | ||
255 | * @param cls closure | ||
256 | * @param addr binary address | ||
257 | * @param addrlen length of the address | ||
258 | * @return string representing the same address | ||
991 | */ | 259 | */ |
992 | static void | 260 | static const char * |
993 | server_v4_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | 261 | http_server_plugin_address_to_string (void *cls, const void *addr, size_t addrlen) |
994 | { | 262 | { |
995 | struct Plugin *plugin = cls; | 263 | GNUNET_break (0); |
996 | 264 | return NULL; | |
997 | GNUNET_assert (cls != NULL); | ||
998 | |||
999 | plugin->server_v4_task = GNUNET_SCHEDULER_NO_TASK; | ||
1000 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | ||
1001 | return; | ||
1002 | #if 0 | ||
1003 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
1004 | "Running IPv4 server\n"); | ||
1005 | #endif | ||
1006 | plugin->server_v4_immediately = GNUNET_NO; | ||
1007 | GNUNET_assert (MHD_YES == MHD_run (plugin->server_v4)); | ||
1008 | server_reschedule (plugin, plugin->server_v4, GNUNET_NO); | ||
1009 | } | 265 | } |
1010 | 266 | ||
1011 | 267 | ||
1012 | /** | ||
1013 | * Call MHD IPv6 to process pending requests and then go back | ||
1014 | * and schedule the next run. | ||
1015 | * @param cls plugin as closure | ||
1016 | * @param tc task context | ||
1017 | */ | ||
1018 | static void | ||
1019 | server_v6_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
1020 | { | ||
1021 | struct Plugin *plugin = cls; | ||
1022 | 268 | ||
1023 | GNUNET_assert (cls != NULL); | ||
1024 | plugin->server_v6_task = GNUNET_SCHEDULER_NO_TASK; | ||
1025 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | ||
1026 | return; | ||
1027 | #if 0 | ||
1028 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
1029 | "Running IPv6 server\n"); | ||
1030 | #endif | ||
1031 | plugin->server_v6_immediately = GNUNET_NO; | ||
1032 | GNUNET_assert (MHD_YES == MHD_run (plugin->server_v6)); | ||
1033 | server_reschedule (plugin, plugin->server_v6, GNUNET_NO); | ||
1034 | } | ||
1035 | 269 | ||
1036 | /** | 270 | /** |
1037 | * Function that queries MHD's select sets and | 271 | * Entry point for the plugin. |
1038 | * starts the task waiting for them. | ||
1039 | * @param plugin plugin | ||
1040 | * @param daemon_handle the MHD daemon handle | ||
1041 | * @return gnunet task identifier | ||
1042 | */ | 272 | */ |
1043 | static GNUNET_SCHEDULER_TaskIdentifier | 273 | void * |
1044 | server_schedule (struct Plugin *plugin, struct MHD_Daemon *daemon_handle, | 274 | LIBGNUNET_PLUGIN_TRANSPORT_INIT (void *cls) |
1045 | int now) | ||
1046 | { | 275 | { |
1047 | GNUNET_SCHEDULER_TaskIdentifier ret; | 276 | struct GNUNET_TRANSPORT_PluginEnvironment *env = cls; |
1048 | fd_set rs; | 277 | struct GNUNET_TRANSPORT_PluginFunctions *api; |
1049 | fd_set ws; | 278 | struct Plugin *plugin; |
1050 | fd_set es; | 279 | |
1051 | struct GNUNET_NETWORK_FDSet *wrs; | 280 | plugin = GNUNET_malloc (sizeof (struct Plugin)); |
1052 | struct GNUNET_NETWORK_FDSet *wws; | 281 | plugin->env = env; |
1053 | struct GNUNET_NETWORK_FDSet *wes; | 282 | api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions)); |
1054 | int max; | 283 | api->cls = plugin; |
1055 | unsigned MHD_LONG_LONG timeout; | 284 | api->send = &http_server_plugin_send; |
1056 | static unsigned long long last_timeout = 0; | 285 | api->disconnect = &http_server_plugin_disconnect; |
1057 | int haveto; | 286 | api->address_pretty_printer = &http_server_plugin_address_pretty_printer; |
1058 | 287 | api->check_address = &http_server_plugin_address_suggested; | |
1059 | struct GNUNET_TIME_Relative tv; | 288 | api->address_to_string = &http_server_plugin_address_to_string; |
1060 | 289 | return api; | |
1061 | ret = GNUNET_SCHEDULER_NO_TASK; | ||
1062 | FD_ZERO (&rs); | ||
1063 | FD_ZERO (&ws); | ||
1064 | FD_ZERO (&es); | ||
1065 | wrs = GNUNET_NETWORK_fdset_create (); | ||
1066 | wes = GNUNET_NETWORK_fdset_create (); | ||
1067 | wws = GNUNET_NETWORK_fdset_create (); | ||
1068 | max = -1; | ||
1069 | GNUNET_assert (MHD_YES == MHD_get_fdset (daemon_handle, &rs, &ws, &es, &max)); | ||
1070 | haveto = MHD_get_timeout (daemon_handle, &timeout); | ||
1071 | if (haveto == MHD_YES) | ||
1072 | { | ||
1073 | if (timeout != last_timeout) | ||
1074 | { | ||
1075 | #if VERBOSE_SERVER | ||
1076 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
1077 | "SELECT Timeout changed from %llu to %llu\n", | ||
1078 | last_timeout, timeout); | ||
1079 | #endif | ||
1080 | last_timeout = timeout; | ||
1081 | } | ||
1082 | tv.rel_value = (uint64_t) timeout; | ||
1083 | } | ||
1084 | else | ||
1085 | tv = GNUNET_TIME_UNIT_SECONDS; | ||
1086 | /* Force immediate run, since we have outbound data to send */ | ||
1087 | if (now == GNUNET_YES) | ||
1088 | tv = GNUNET_TIME_UNIT_MILLISECONDS; | ||
1089 | GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1); | ||
1090 | GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1); | ||
1091 | GNUNET_NETWORK_fdset_copy_native (wes, &es, max + 1); | ||
1092 | |||
1093 | if (daemon_handle == plugin->server_v4) | ||
1094 | { | ||
1095 | if (plugin->server_v4_task != GNUNET_SCHEDULER_NO_TASK) | ||
1096 | { | ||
1097 | GNUNET_SCHEDULER_cancel (plugin->server_v4_task); | ||
1098 | plugin->server_v4_task = GNUNET_SCHEDULER_NO_TASK; | ||
1099 | } | ||
1100 | #if 0 | ||
1101 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
1102 | "Scheduling IPv4 server task in %llu ms\n", tv); | ||
1103 | #endif | ||
1104 | ret = | ||
1105 | GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, | ||
1106 | tv, wrs, wws, | ||
1107 | &server_v4_run, plugin); | ||
1108 | } | ||
1109 | if (daemon_handle == plugin->server_v6) | ||
1110 | { | ||
1111 | if (plugin->server_v6_task != GNUNET_SCHEDULER_NO_TASK) | ||
1112 | { | ||
1113 | GNUNET_SCHEDULER_cancel (plugin->server_v6_task); | ||
1114 | plugin->server_v6_task = GNUNET_SCHEDULER_NO_TASK; | ||
1115 | } | ||
1116 | #if 0 | ||
1117 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
1118 | "Scheduling IPv6 server task in %llu ms\n", tv); | ||
1119 | #endif | ||
1120 | ret = | ||
1121 | GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, | ||
1122 | tv, wrs, wws, | ||
1123 | &server_v6_run, plugin); | ||
1124 | } | ||
1125 | GNUNET_NETWORK_fdset_destroy (wrs); | ||
1126 | GNUNET_NETWORK_fdset_destroy (wws); | ||
1127 | GNUNET_NETWORK_fdset_destroy (wes); | ||
1128 | return ret; | ||
1129 | } | 290 | } |
1130 | 291 | ||
1131 | int | ||
1132 | server_start (struct Plugin *plugin) | ||
1133 | { | ||
1134 | int res = GNUNET_OK; | ||
1135 | unsigned int timeout; | ||
1136 | p = plugin; | ||
1137 | GNUNET_assert (NULL != plugin); | ||
1138 | |||
1139 | #if BUILD_HTTPS | ||
1140 | res = server_load_certificate (plugin); | ||
1141 | if (res == GNUNET_SYSERR) | ||
1142 | { | ||
1143 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, | ||
1144 | "Could not load or create server certificate! Loading plugin failed!\n"); | ||
1145 | return res; | ||
1146 | } | ||
1147 | #endif | ||
1148 | |||
1149 | 292 | ||
1150 | #if MHD_VERSION >= 0x00090E00 | 293 | /** |
1151 | timeout = HTTP_NOT_VALIDATED_TIMEOUT.rel_value / 1000; | 294 | * Exit point from the plugin. |
1152 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | 295 | */ |
1153 | "MHD can set timeout per connection! Default time out %u sec.\n", | 296 | void * |
1154 | timeout); | 297 | LIBGNUNET_PLUGIN_TRANSPORT_DONE (void *cls) |
1155 | #else | ||
1156 | timeout = GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value / 1000; | ||
1157 | GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, plugin->name, | ||
1158 | "MHD cannot set timeout per connection! Default time out %u sec.\n", | ||
1159 | timeout); | ||
1160 | #endif | ||
1161 | plugin->server_v4 = NULL; | ||
1162 | if (plugin->ipv4 == GNUNET_YES) | ||
1163 | { | ||
1164 | plugin->server_v4 = MHD_start_daemon ( | ||
1165 | #if VERBOSE_SERVER | ||
1166 | MHD_USE_DEBUG | | ||
1167 | #endif | ||
1168 | #if BUILD_HTTPS | ||
1169 | MHD_USE_SSL | | ||
1170 | #endif | ||
1171 | MHD_NO_FLAG, plugin->port, | ||
1172 | &server_accept_cb, plugin, | ||
1173 | &server_access_cb, plugin, | ||
1174 | MHD_OPTION_SOCK_ADDR, | ||
1175 | (struct sockaddr_in *) | ||
1176 | plugin->server_addr_v4, | ||
1177 | MHD_OPTION_CONNECTION_LIMIT, | ||
1178 | (unsigned int) | ||
1179 | plugin->max_connections, | ||
1180 | #if BUILD_HTTPS | ||
1181 | MHD_OPTION_HTTPS_PRIORITIES, | ||
1182 | plugin->crypto_init, | ||
1183 | MHD_OPTION_HTTPS_MEM_KEY, | ||
1184 | plugin->key, | ||
1185 | MHD_OPTION_HTTPS_MEM_CERT, | ||
1186 | plugin->cert, | ||
1187 | #endif | ||
1188 | MHD_OPTION_CONNECTION_TIMEOUT, | ||
1189 | timeout, | ||
1190 | MHD_OPTION_CONNECTION_MEMORY_LIMIT, | ||
1191 | (size_t) (2 * | ||
1192 | GNUNET_SERVER_MAX_MESSAGE_SIZE), | ||
1193 | MHD_OPTION_NOTIFY_COMPLETED, | ||
1194 | &server_disconnect_cb, plugin, | ||
1195 | MHD_OPTION_EXTERNAL_LOGGER, | ||
1196 | server_log, NULL, MHD_OPTION_END); | ||
1197 | } | ||
1198 | plugin->server_v6 = NULL; | ||
1199 | if (plugin->ipv6 == GNUNET_YES) | ||
1200 | { | ||
1201 | plugin->server_v6 = MHD_start_daemon ( | ||
1202 | #if VERBOSE_SERVER | ||
1203 | MHD_USE_DEBUG | | ||
1204 | #endif | ||
1205 | #if BUILD_HTTPS | ||
1206 | MHD_USE_SSL | | ||
1207 | #endif | ||
1208 | MHD_USE_IPv6, plugin->port, | ||
1209 | &server_accept_cb, plugin, | ||
1210 | &server_access_cb, plugin, | ||
1211 | MHD_OPTION_SOCK_ADDR, | ||
1212 | (struct sockaddr_in6 *) | ||
1213 | plugin->server_addr_v6, | ||
1214 | MHD_OPTION_CONNECTION_LIMIT, | ||
1215 | (unsigned int) | ||
1216 | plugin->max_connections, | ||
1217 | #if BUILD_HTTPS | ||
1218 | MHD_OPTION_HTTPS_PRIORITIES, | ||
1219 | plugin->crypto_init, | ||
1220 | MHD_OPTION_HTTPS_MEM_KEY, | ||
1221 | plugin->key, | ||
1222 | MHD_OPTION_HTTPS_MEM_CERT, | ||
1223 | plugin->cert, | ||
1224 | #endif | ||
1225 | MHD_OPTION_CONNECTION_TIMEOUT, | ||
1226 | timeout, | ||
1227 | MHD_OPTION_CONNECTION_MEMORY_LIMIT, | ||
1228 | (size_t) (2 * | ||
1229 | GNUNET_SERVER_MAX_MESSAGE_SIZE), | ||
1230 | MHD_OPTION_NOTIFY_COMPLETED, | ||
1231 | &server_disconnect_cb, plugin, | ||
1232 | MHD_OPTION_EXTERNAL_LOGGER, | ||
1233 | server_log, NULL, MHD_OPTION_END); | ||
1234 | |||
1235 | } | ||
1236 | |||
1237 | if ((plugin->ipv4 == GNUNET_YES) && (plugin->server_v4 == NULL)) | ||
1238 | { | ||
1239 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, | ||
1240 | "Failed to start %s IPv4 server component on port %u\n", | ||
1241 | plugin->name, plugin->port); | ||
1242 | return GNUNET_SYSERR; | ||
1243 | } | ||
1244 | server_reschedule (plugin, plugin->server_v4, GNUNET_NO); | ||
1245 | |||
1246 | if ((plugin->ipv6 == GNUNET_YES) && (plugin->server_v6 == NULL)) | ||
1247 | { | ||
1248 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, | ||
1249 | "Failed to start %s IPv6 server component on port %u\n", | ||
1250 | plugin->name, plugin->port); | ||
1251 | return GNUNET_SYSERR; | ||
1252 | } | ||
1253 | server_reschedule (plugin, plugin->server_v6, GNUNET_NO); | ||
1254 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
1255 | "%s server component started on port %u\n", plugin->name, | ||
1256 | plugin->port); | ||
1257 | return res; | ||
1258 | } | ||
1259 | |||
1260 | void | ||
1261 | server_stop (struct Plugin *plugin) | ||
1262 | { | 298 | { |
1263 | struct Session *s = NULL; | 299 | struct GNUNET_TRANSPORT_PluginFunctions *api = cls; |
1264 | struct Session *t = NULL; | 300 | struct Plugin *plugin = api->cls; |
1265 | |||
1266 | struct MHD_Daemon *server_v4_tmp = plugin->server_v4; | ||
1267 | plugin->server_v4 = NULL; | ||
1268 | |||
1269 | struct MHD_Daemon *server_v6_tmp = plugin->server_v6; | ||
1270 | plugin->server_v6 = NULL; | ||
1271 | |||
1272 | if (plugin->server_v4_task != GNUNET_SCHEDULER_NO_TASK) | ||
1273 | { | ||
1274 | GNUNET_SCHEDULER_cancel (plugin->server_v4_task); | ||
1275 | plugin->server_v4_task = GNUNET_SCHEDULER_NO_TASK; | ||
1276 | } | ||
1277 | |||
1278 | if (plugin->server_v6_task != GNUNET_SCHEDULER_NO_TASK) | ||
1279 | { | ||
1280 | GNUNET_SCHEDULER_cancel (plugin->server_v6_task); | ||
1281 | plugin->server_v6_task = GNUNET_SCHEDULER_NO_TASK; | ||
1282 | } | ||
1283 | |||
1284 | if (server_v6_tmp != NULL) | ||
1285 | { | ||
1286 | MHD_stop_daemon (server_v4_tmp); | ||
1287 | } | ||
1288 | if (server_v6_tmp != NULL) | ||
1289 | { | ||
1290 | MHD_stop_daemon (server_v6_tmp); | ||
1291 | } | ||
1292 | 301 | ||
1293 | /* cleaning up semi-sessions never propagated */ | 302 | GNUNET_free (plugin); |
1294 | s = plugin->server_semi_head; | 303 | GNUNET_free (api); |
1295 | while (s != NULL) | 304 | return NULL; |
1296 | { | ||
1297 | #if VERBOSE_SERVER | ||
1298 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
1299 | "Deleting semi-sessions %p\n", s); | ||
1300 | #endif | ||
1301 | t = s->next; | ||
1302 | struct HTTP_Message *msg = s->msg_head; | ||
1303 | struct HTTP_Message *tmp = NULL; | ||
1304 | |||
1305 | while (msg != NULL) | ||
1306 | { | ||
1307 | tmp = msg->next; | ||
1308 | |||
1309 | GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg); | ||
1310 | if (msg->transmit_cont != NULL) | ||
1311 | { | ||
1312 | msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_SYSERR); | ||
1313 | } | ||
1314 | GNUNET_free (msg); | ||
1315 | msg = tmp; | ||
1316 | } | ||
1317 | |||
1318 | delete_session (s); | ||
1319 | s = t; | ||
1320 | } | ||
1321 | |||
1322 | p = NULL; | ||
1323 | |||
1324 | #if BUILD_HTTPS | ||
1325 | GNUNET_free_non_null (plugin->crypto_init); | ||
1326 | GNUNET_free_non_null (plugin->cert); | ||
1327 | GNUNET_free_non_null (plugin->key); | ||
1328 | #endif | ||
1329 | |||
1330 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
1331 | "%s server component stopped\n", plugin->name); | ||
1332 | } | 305 | } |
1333 | 306 | ||
1334 | 307 | /* end of plugin_transport_http_server.c */ | |
1335 | |||
1336 | /* end of plugin_transport_http.c */ | ||
diff --git a/src/transport/plugin_transport_http_server_old.c b/src/transport/plugin_transport_http_server_old.c new file mode 100644 index 000000000..f81f5cf6e --- /dev/null +++ b/src/transport/plugin_transport_http_server_old.c | |||
@@ -0,0 +1,1336 @@ | |||
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_http.c | ||
23 | * @brief http transport service plugin | ||
24 | * @author Matthias Wachs | ||
25 | */ | ||
26 | |||
27 | #include "plugin_transport_http.h" | ||
28 | |||
29 | #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>" | ||
30 | #define _RECEIVE 0 | ||
31 | #define _SEND 1 | ||
32 | |||
33 | static struct Plugin * p; | ||
34 | |||
35 | /** | ||
36 | * Function that queries MHD's select sets and | ||
37 | * starts the task waiting for them. | ||
38 | * @param plugin plugin | ||
39 | * @param daemon_handle the MHD daemon handle | ||
40 | * @param now schedule now or with MHD delay | ||
41 | * @return gnunet task identifier | ||
42 | */ | ||
43 | static GNUNET_SCHEDULER_TaskIdentifier | ||
44 | server_schedule (struct Plugin *plugin, | ||
45 | struct MHD_Daemon *daemon_handle, | ||
46 | int now); | ||
47 | |||
48 | static void | ||
49 | server_log (void *arg, const char *fmt, va_list ap) | ||
50 | { | ||
51 | char text[1024]; | ||
52 | |||
53 | vsnprintf (text, sizeof (text), fmt, ap); | ||
54 | va_end (ap); | ||
55 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Server: %s\n", text); | ||
56 | } | ||
57 | |||
58 | /** | ||
59 | * Check if incoming connection is accepted. | ||
60 | * NOTE: Here every connection is accepted | ||
61 | * @param cls plugin as closure | ||
62 | * @param addr address of incoming connection | ||
63 | * @param addr_len address length of incoming connection | ||
64 | * @return MHD_YES if connection is accepted, MHD_NO if connection is rejected | ||
65 | * | ||
66 | */ | ||
67 | static int | ||
68 | server_accept_cb (void *cls, const struct sockaddr *addr, socklen_t addr_len) | ||
69 | { | ||
70 | struct Plugin *plugin = cls; | ||
71 | |||
72 | if (plugin->cur_connections <= plugin->max_connections) | ||
73 | return MHD_YES; | ||
74 | else | ||
75 | { | ||
76 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
77 | "Server: Cannot accept new connections\n"); | ||
78 | return MHD_NO; | ||
79 | } | ||
80 | } | ||
81 | |||
82 | |||
83 | #if BUILD_HTTPS | ||
84 | static char * | ||
85 | server_load_file (const char *file) | ||
86 | { | ||
87 | struct GNUNET_DISK_FileHandle *gn_file; | ||
88 | uint64_t fsize; | ||
89 | char *text = NULL; | ||
90 | |||
91 | if (GNUNET_OK != GNUNET_DISK_file_size (file, | ||
92 | &fsize, GNUNET_NO, GNUNET_YES)) | ||
93 | return NULL; | ||
94 | text = GNUNET_malloc (fsize + 1); | ||
95 | gn_file = | ||
96 | GNUNET_DISK_file_open (file, GNUNET_DISK_OPEN_READ, | ||
97 | GNUNET_DISK_PERM_USER_READ); | ||
98 | if (gn_file == NULL) | ||
99 | { | ||
100 | GNUNET_free (text); | ||
101 | return NULL; | ||
102 | } | ||
103 | if (GNUNET_SYSERR == GNUNET_DISK_file_read (gn_file, text, fsize)) | ||
104 | { | ||
105 | GNUNET_free (text); | ||
106 | GNUNET_DISK_file_close (gn_file); | ||
107 | return NULL; | ||
108 | } | ||
109 | text[fsize] = '\0'; | ||
110 | GNUNET_DISK_file_close (gn_file); | ||
111 | return text; | ||
112 | } | ||
113 | #endif | ||
114 | |||
115 | |||
116 | #if BUILD_HTTPS | ||
117 | |||
118 | static int | ||
119 | server_load_certificate (struct Plugin *plugin) | ||
120 | { | ||
121 | int res = GNUNET_OK; | ||
122 | |||
123 | char *key_file; | ||
124 | char *cert_file; | ||
125 | |||
126 | /* Get crypto init string from config | ||
127 | * If not present just use default values */ | ||
128 | |||
129 | GNUNET_assert (GNUNET_OK == | ||
130 | GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, | ||
131 | plugin->name, | ||
132 | "CRYPTO_INIT", | ||
133 | &plugin->crypto_init)); | ||
134 | |||
135 | if (GNUNET_OK != | ||
136 | GNUNET_CONFIGURATION_get_value_filename (plugin->env->cfg, plugin->name, | ||
137 | "KEY_FILE", &key_file)) | ||
138 | { | ||
139 | key_file = GNUNET_strdup ("https_key.key"); | ||
140 | } | ||
141 | |||
142 | if (GNUNET_OK != | ||
143 | GNUNET_CONFIGURATION_get_value_filename (plugin->env->cfg, plugin->name, | ||
144 | "CERT_FILE", &cert_file)) | ||
145 | { | ||
146 | GNUNET_asprintf (&cert_file, "%s", "https_cert.crt"); | ||
147 | } | ||
148 | |||
149 | /* read key & certificates from file */ | ||
150 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
151 | "Loading TLS certificate from key-file `%s' cert-file`%s'\n", | ||
152 | key_file, cert_file); | ||
153 | |||
154 | plugin->key = server_load_file (key_file); | ||
155 | plugin->cert = server_load_file (cert_file); | ||
156 | |||
157 | if ((plugin->key == NULL) || (plugin->cert == NULL)) | ||
158 | { | ||
159 | struct GNUNET_OS_Process *cert_creation; | ||
160 | |||
161 | GNUNET_free_non_null (plugin->key); | ||
162 | plugin->key = NULL; | ||
163 | GNUNET_free_non_null (plugin->cert); | ||
164 | plugin->cert = NULL; | ||
165 | |||
166 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
167 | "No usable TLS certificate found, creating certificate\n"); | ||
168 | errno = 0; | ||
169 | cert_creation = | ||
170 | GNUNET_OS_start_process (GNUNET_NO, GNUNET_OS_INHERIT_STD_OUT_AND_ERR, NULL, NULL, | ||
171 | "gnunet-transport-certificate-creation", | ||
172 | "gnunet-transport-certificate-creation", | ||
173 | key_file, cert_file, NULL); | ||
174 | if (cert_creation == NULL) | ||
175 | { | ||
176 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, | ||
177 | _ | ||
178 | ("Could not create a new TLS certificate, program `gnunet-transport-certificate-creation' could not be started!\n")); | ||
179 | GNUNET_free (key_file); | ||
180 | GNUNET_free (cert_file); | ||
181 | |||
182 | GNUNET_free_non_null (plugin->key); | ||
183 | plugin->key = NULL; | ||
184 | GNUNET_free_non_null (plugin->cert); | ||
185 | plugin->cert = NULL; | ||
186 | GNUNET_free_non_null (plugin->crypto_init); | ||
187 | plugin->crypto_init = NULL; | ||
188 | |||
189 | return GNUNET_SYSERR; | ||
190 | } | ||
191 | GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (cert_creation)); | ||
192 | GNUNET_OS_process_destroy (cert_creation); | ||
193 | |||
194 | plugin->key = server_load_file (key_file); | ||
195 | plugin->cert = server_load_file (cert_file); | ||
196 | } | ||
197 | |||
198 | if ((plugin->key == NULL) || (plugin->cert == NULL)) | ||
199 | { | ||
200 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, | ||
201 | _ | ||
202 | ("No usable TLS certificate found and creating one failed!\n"), | ||
203 | "transport-https"); | ||
204 | GNUNET_free (key_file); | ||
205 | GNUNET_free (cert_file); | ||
206 | |||
207 | GNUNET_free_non_null (plugin->key); | ||
208 | plugin->key = NULL; | ||
209 | GNUNET_free_non_null (plugin->cert); | ||
210 | plugin->cert = NULL; | ||
211 | GNUNET_free_non_null (plugin->crypto_init); | ||
212 | plugin->crypto_init = NULL; | ||
213 | |||
214 | return GNUNET_SYSERR; | ||
215 | } | ||
216 | GNUNET_free (key_file); | ||
217 | GNUNET_free (cert_file); | ||
218 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TLS certificate loaded\n"); | ||
219 | return res; | ||
220 | } | ||
221 | #endif | ||
222 | |||
223 | |||
224 | /** | ||
225 | * Reschedule the execution of both IPv4 and IPv6 server | ||
226 | * @param plugin the plugin | ||
227 | * @param server which server to schedule v4 or v6? | ||
228 | * @param now GNUNET_YES to schedule execution immediately, GNUNET_NO to wait | ||
229 | * until timeout | ||
230 | */ | ||
231 | static void | ||
232 | server_reschedule (struct Plugin *plugin, struct MHD_Daemon *server, int now) | ||
233 | { | ||
234 | if ((server == plugin->server_v4) && (plugin->server_v4 != NULL)) | ||
235 | { | ||
236 | if (GNUNET_YES == plugin->server_v4_immediately) | ||
237 | return; /* No rescheduling, server will run asap */ | ||
238 | |||
239 | if (GNUNET_YES == now) | ||
240 | plugin->server_v4_immediately = GNUNET_YES; | ||
241 | |||
242 | if (plugin->server_v4_task != GNUNET_SCHEDULER_NO_TASK) | ||
243 | { | ||
244 | GNUNET_SCHEDULER_cancel (plugin->server_v4_task); | ||
245 | plugin->server_v4_task = GNUNET_SCHEDULER_NO_TASK; | ||
246 | } | ||
247 | plugin->server_v4_task = server_schedule (plugin, plugin->server_v4, now); | ||
248 | } | ||
249 | |||
250 | if ((server == plugin->server_v6) && (plugin->server_v6 != NULL)) | ||
251 | { | ||
252 | if (GNUNET_YES == plugin->server_v6_immediately) | ||
253 | return; /* No rescheduling, server will run asap */ | ||
254 | |||
255 | if (GNUNET_YES == now) | ||
256 | plugin->server_v6_immediately = GNUNET_YES; | ||
257 | |||
258 | if (plugin->server_v6_task != GNUNET_SCHEDULER_NO_TASK) | ||
259 | { | ||
260 | GNUNET_SCHEDULER_cancel (plugin->server_v6_task); | ||
261 | plugin->server_v6_task = GNUNET_SCHEDULER_NO_TASK; | ||
262 | } | ||
263 | plugin->server_v6_task = server_schedule (plugin, plugin->server_v6, now); | ||
264 | } | ||
265 | } | ||
266 | |||
267 | /** | ||
268 | * Callback called by MessageStreamTokenizer when a message has arrived | ||
269 | * @param cls current session as closure | ||
270 | * @param client clien | ||
271 | * @param message the message to be forwarded to transport service | ||
272 | */ | ||
273 | static int | ||
274 | server_receive_mst_cb (void *cls, void *client, | ||
275 | const struct GNUNET_MessageHeader *message) | ||
276 | { | ||
277 | struct Session *s = cls; | ||
278 | |||
279 | GNUNET_assert (NULL != p); | ||
280 | if (GNUNET_NO == exist_session(p, s)) | ||
281 | return GNUNET_OK; | ||
282 | |||
283 | struct Plugin *plugin = s->plugin; | ||
284 | struct GNUNET_TIME_Relative delay; | ||
285 | |||
286 | delay = http_plugin_receive (s, &s->target, message, s, s->addr, s->addrlen); | ||
287 | |||
288 | s->next_receive = | ||
289 | GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), delay); | ||
290 | |||
291 | if (delay.rel_value > 0) | ||
292 | { | ||
293 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
294 | "Server: peer `%s' address `%s' next read delayed for %llu ms\n", | ||
295 | GNUNET_i2s (&s->target), | ||
296 | http_plugin_address_to_string (NULL, s->addr, s->addrlen), | ||
297 | delay); | ||
298 | } | ||
299 | return GNUNET_OK; | ||
300 | } | ||
301 | |||
302 | |||
303 | /** | ||
304 | * Callback called by MHD when it needs data to send | ||
305 | * @param cls current session | ||
306 | * @param pos position in buffer | ||
307 | * @param buf the buffer to write data to | ||
308 | * @param max max number of bytes available in buffer | ||
309 | * @return bytes written to buffer | ||
310 | */ | ||
311 | static ssize_t | ||
312 | server_send_callback (void *cls, uint64_t pos, char *buf, size_t max) | ||
313 | { | ||
314 | struct Session *s = cls; | ||
315 | ssize_t bytes_read = 0; | ||
316 | struct HTTP_Message *msg; | ||
317 | |||
318 | GNUNET_assert (NULL != p); | ||
319 | if (GNUNET_NO == exist_session(p, s)) | ||
320 | return 0; | ||
321 | msg = s->msg_head; | ||
322 | if (NULL != msg) | ||
323 | { | ||
324 | /* sending */ | ||
325 | bytes_read = GNUNET_MIN (msg->size - msg->pos, | ||
326 | max); | ||
327 | memcpy (buf, &msg->buf[msg->pos], bytes_read); | ||
328 | msg->pos += bytes_read; | ||
329 | |||
330 | /* removing message */ | ||
331 | if (msg->pos == msg->size) | ||
332 | { | ||
333 | GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg); | ||
334 | if (NULL != msg->transmit_cont) | ||
335 | msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_OK); | ||
336 | GNUNET_free (msg); | ||
337 | } | ||
338 | } | ||
339 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, s->plugin->name, | ||
340 | "Server: %p: sent %u bytes\n", s, bytes_read); | ||
341 | return bytes_read; | ||
342 | } | ||
343 | |||
344 | |||
345 | static struct Session * | ||
346 | server_lookup_session (struct Plugin *plugin, | ||
347 | struct ServerConnection * sc) | ||
348 | { | ||
349 | struct Session *s; | ||
350 | |||
351 | for (s = plugin->head; NULL != s; s = s->next) | ||
352 | if ((s->server_recv == sc) || (s->server_send == sc)) | ||
353 | return s; | ||
354 | for (s = plugin->server_semi_head; NULL != s; s = s->next) | ||
355 | if ((s->server_recv == sc) || (s->server_send == sc)) | ||
356 | return s; | ||
357 | return NULL; | ||
358 | } | ||
359 | |||
360 | |||
361 | static struct ServerConnection * | ||
362 | server_lookup_serverconnection (struct Plugin *plugin, | ||
363 | struct MHD_Connection *mhd_connection, const char *url, | ||
364 | const char *method) | ||
365 | { | ||
366 | struct Session *s = NULL; | ||
367 | struct Session *t; | ||
368 | struct ServerConnection *sc = NULL; | ||
369 | const union MHD_ConnectionInfo *conn_info; | ||
370 | struct GNUNET_ATS_Information ats; | ||
371 | struct IPv4HttpAddress a4; | ||
372 | struct IPv6HttpAddress a6; | ||
373 | struct sockaddr_in *s4; | ||
374 | struct sockaddr_in6 *s6; | ||
375 | void *a; | ||
376 | size_t a_len; | ||
377 | struct GNUNET_PeerIdentity target; | ||
378 | uint32_t tag = 0; | ||
379 | int direction = GNUNET_SYSERR; | ||
380 | |||
381 | /* url parsing variables */ | ||
382 | size_t url_len; | ||
383 | char *url_end; | ||
384 | char *hash_start; | ||
385 | char *hash_end; | ||
386 | char *tag_start; | ||
387 | char *tag_end; | ||
388 | |||
389 | conn_info = MHD_get_connection_info (mhd_connection, | ||
390 | MHD_CONNECTION_INFO_CLIENT_ADDRESS); | ||
391 | if ((conn_info->client_addr->sa_family != AF_INET) && | ||
392 | (conn_info->client_addr->sa_family != AF_INET6)) | ||
393 | return NULL; | ||
394 | |||
395 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
396 | "New %s connection from %s\n", | ||
397 | method, url); | ||
398 | /* URL parsing | ||
399 | * URL is valid if it is in the form [peerid[103];tag]*/ | ||
400 | url_len = strlen (url); | ||
401 | url_end = (char *) &url[url_len]; | ||
402 | |||
403 | if (url_len < 105) | ||
404 | { | ||
405 | goto error; /* too short */ | ||
406 | } | ||
407 | hash_start = strrchr (url, '/'); | ||
408 | if (NULL == hash_start) | ||
409 | { | ||
410 | goto error; /* '/' delimiter not found */ | ||
411 | } | ||
412 | if (hash_start >= url_end) | ||
413 | { | ||
414 | goto error; /* mal formed */ | ||
415 | } | ||
416 | hash_start++; | ||
417 | |||
418 | hash_end = strrchr (hash_start, ';'); | ||
419 | if (NULL == hash_end) | ||
420 | goto error; /* ';' delimiter not found */ | ||
421 | if (hash_end >= url_end) | ||
422 | { | ||
423 | goto error; /* mal formed */ | ||
424 | } | ||
425 | |||
426 | if (hash_start >= hash_end) | ||
427 | { | ||
428 | goto error; /* mal formed */ | ||
429 | } | ||
430 | |||
431 | if ((strlen(hash_start) - strlen(hash_end)) != 103) | ||
432 | { | ||
433 | goto error; /* invalid hash length */ | ||
434 | } | ||
435 | |||
436 | char hash[104]; | ||
437 | memcpy (hash, hash_start, 103); | ||
438 | hash[103] = '\0'; | ||
439 | if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((const char *) hash, &(target.hashPubKey))) | ||
440 | { | ||
441 | goto error; /* mal formed */ | ||
442 | } | ||
443 | |||
444 | if (hash_end >= url_end) | ||
445 | { | ||
446 | goto error; /* mal formed */ | ||
447 | } | ||
448 | |||
449 | tag_start = &hash_end[1]; | ||
450 | /* Converting tag */ | ||
451 | tag_end = NULL; | ||
452 | tag = strtoul (tag_start, &tag_end, 10); | ||
453 | if (tag == 0) | ||
454 | { | ||
455 | goto error; /* mal formed */ | ||
456 | } | ||
457 | if (tag_end == NULL) | ||
458 | { | ||
459 | goto error; /* mal formed */ | ||
460 | } | ||
461 | if (tag_end != url_end) | ||
462 | { | ||
463 | goto error; /* mal formed */ | ||
464 | } | ||
465 | |||
466 | if (0 == strcmp (MHD_HTTP_METHOD_PUT, method)) | ||
467 | direction = _RECEIVE; | ||
468 | else if (0 == strcmp (MHD_HTTP_METHOD_GET, method)) | ||
469 | direction = _SEND; | ||
470 | else | ||
471 | { | ||
472 | goto error; | ||
473 | } | ||
474 | |||
475 | plugin->cur_connections++; | ||
476 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
477 | "Server: New %s connection from %s with tag %u\n", | ||
478 | method, | ||
479 | GNUNET_i2s (&target), tag); | ||
480 | |||
481 | /* find duplicate session */ | ||
482 | t = plugin->head; | ||
483 | while (t != NULL) | ||
484 | { | ||
485 | if ((t->inbound) && | ||
486 | (0 == memcmp (&t->target, &target, sizeof (struct GNUNET_PeerIdentity))) | ||
487 | && | ||
488 | /* FIXME add source address comparison */ | ||
489 | (t->tag == tag)) | ||
490 | break; | ||
491 | t = t->next; | ||
492 | } | ||
493 | if (t != NULL) | ||
494 | { | ||
495 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
496 | "Server: Duplicate session, dismissing new connection from peer `%s'\n", | ||
497 | GNUNET_i2s (&target)); | ||
498 | goto error; | ||
499 | } | ||
500 | |||
501 | /* find semi-session */ | ||
502 | t = plugin->server_semi_head; | ||
503 | |||
504 | while (t != NULL) | ||
505 | { | ||
506 | /* FIXME add source address comparison */ | ||
507 | if ((0 == memcmp (&t->target, &target, sizeof (struct GNUNET_PeerIdentity))) | ||
508 | && (t->tag == tag)) | ||
509 | { | ||
510 | break; | ||
511 | } | ||
512 | t = t->next; | ||
513 | } | ||
514 | |||
515 | if (t == NULL) | ||
516 | goto create; | ||
517 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
518 | "Server: Found existing semi-session for `%s'\n", | ||
519 | GNUNET_i2s (&target)); | ||
520 | |||
521 | if ((direction == _SEND) && (t->server_send != NULL)) | ||
522 | { | ||
523 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
524 | "Server: Duplicate GET session, dismissing new connection from peer `%s'\n", | ||
525 | GNUNET_i2s (&target)); | ||
526 | goto error; | ||
527 | } | ||
528 | else | ||
529 | { | ||
530 | s = t; | ||
531 | GNUNET_CONTAINER_DLL_remove (plugin->server_semi_head, | ||
532 | plugin->server_semi_tail, s); | ||
533 | GNUNET_CONTAINER_DLL_insert (plugin->head, plugin->tail, s); | ||
534 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
535 | "Server: Found matching semi-session, merging session for peer `%s'\n", | ||
536 | GNUNET_i2s (&target)); | ||
537 | |||
538 | plugin->inbound_sessions ++; | ||
539 | GNUNET_STATISTICS_set (plugin->env->stats, | ||
540 | "# HTTP inbound sessions", | ||
541 | plugin->inbound_sessions, | ||
542 | GNUNET_NO); | ||
543 | GNUNET_assert (NULL != s); | ||
544 | goto found; | ||
545 | } | ||
546 | if ((direction == _RECEIVE) && (t->server_recv != NULL)) | ||
547 | { | ||
548 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
549 | "Server: Duplicate PUT session, dismissing new connection from peer `%s'\n", | ||
550 | GNUNET_i2s (&target)); | ||
551 | goto error; | ||
552 | } | ||
553 | else | ||
554 | { | ||
555 | s = t; | ||
556 | GNUNET_CONTAINER_DLL_remove (plugin->server_semi_head, | ||
557 | plugin->server_semi_tail, s); | ||
558 | GNUNET_CONTAINER_DLL_insert (plugin->head, plugin->tail, s); | ||
559 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
560 | "Server: Found matching semi-session, merging session for peer `%s'\n", | ||
561 | GNUNET_i2s (&target)); | ||
562 | plugin->inbound_sessions ++; | ||
563 | GNUNET_STATISTICS_set (plugin->env->stats, | ||
564 | "# HTTP inbound sessions", | ||
565 | plugin->inbound_sessions, | ||
566 | GNUNET_NO); | ||
567 | GNUNET_assert (NULL != s); | ||
568 | goto found; | ||
569 | } | ||
570 | |||
571 | create: | ||
572 | /* create new session */ | ||
573 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
574 | "Server: Creating new session for peer `%s' \n", | ||
575 | GNUNET_i2s (&target)); | ||
576 | switch (conn_info->client_addr->sa_family) | ||
577 | { | ||
578 | case (AF_INET): | ||
579 | s4 = ((struct sockaddr_in *) conn_info->client_addr); | ||
580 | a4.u4_port = s4->sin_port; | ||
581 | memcpy (&a4.ipv4_addr, &s4->sin_addr, sizeof (struct in_addr)); | ||
582 | a = &a4; | ||
583 | a_len = sizeof (struct IPv4HttpAddress); | ||
584 | ats = plugin->env->get_address_type (plugin->env->cls, (const struct sockaddr *) s4, sizeof (struct sockaddr_in)); | ||
585 | break; | ||
586 | case (AF_INET6): | ||
587 | s6 = ((struct sockaddr_in6 *) conn_info->client_addr); | ||
588 | a6.u6_port = s6->sin6_port; | ||
589 | memcpy (&a6.ipv6_addr, &s6->sin6_addr, sizeof (struct in6_addr)); | ||
590 | a = &a6; | ||
591 | a_len = sizeof (struct IPv6HttpAddress); | ||
592 | ats = plugin->env->get_address_type (plugin->env->cls, (const struct sockaddr *) s6, sizeof (struct sockaddr_in6)); | ||
593 | break; | ||
594 | default: | ||
595 | GNUNET_break (0); | ||
596 | goto error; | ||
597 | } | ||
598 | s = create_session (plugin, &target, a, a_len); | ||
599 | GNUNET_assert (NULL != s); | ||
600 | s->ats_address_network_type = ats.value; | ||
601 | s->inbound = GNUNET_YES; | ||
602 | s->next_receive = GNUNET_TIME_UNIT_ZERO_ABS; | ||
603 | s->tag = tag; | ||
604 | s->server_recv = NULL; | ||
605 | s->server_send = NULL; | ||
606 | |||
607 | GNUNET_CONTAINER_DLL_insert (plugin->server_semi_head, | ||
608 | plugin->server_semi_tail, s); | ||
609 | goto found; | ||
610 | |||
611 | error: | ||
612 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
613 | "Server: Invalid connection request\n"); | ||
614 | return NULL; | ||
615 | |||
616 | found: | ||
617 | sc = GNUNET_malloc (sizeof (struct ServerConnection)); | ||
618 | sc->mhd_conn = mhd_connection; | ||
619 | sc->direction = direction; | ||
620 | sc->session = s; | ||
621 | if (direction == _SEND) | ||
622 | s->server_send = sc; | ||
623 | if (direction == _RECEIVE) | ||
624 | s->server_recv = sc; | ||
625 | |||
626 | #if MHD_VERSION >= 0x00090E00 | ||
627 | int to = (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value / 1000); | ||
628 | |||
629 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
630 | "Server: Setting timeout for %p to %u sec.\n", sc, to); | ||
631 | MHD_set_connection_option (mhd_connection, MHD_CONNECTION_OPTION_TIMEOUT, to); | ||
632 | |||
633 | struct MHD_Daemon *d = NULL; | ||
634 | |||
635 | if (s->addrlen == sizeof (struct IPv6HttpAddress)) | ||
636 | d = plugin->server_v6; | ||
637 | if (s->addrlen == sizeof (struct IPv4HttpAddress)) | ||
638 | d = plugin->server_v4; | ||
639 | |||
640 | server_reschedule (plugin, d, GNUNET_NO); | ||
641 | #endif | ||
642 | return sc; | ||
643 | } | ||
644 | |||
645 | /** | ||
646 | * Process GET or PUT request received via MHD. For | ||
647 | * GET, queue response that will send back our pending | ||
648 | * messages. For PUT, process incoming data and send | ||
649 | * to GNUnet core. In either case, check if a session | ||
650 | * already exists and create a new one if not. | ||
651 | */ | ||
652 | static int | ||
653 | server_access_cb (void *cls, struct MHD_Connection *mhd_connection, | ||
654 | const char *url, const char *method, const char *version, | ||
655 | const char *upload_data, size_t * upload_data_size, | ||
656 | void **httpSessionCache) | ||
657 | { | ||
658 | struct Plugin *plugin = cls; | ||
659 | struct ServerConnection *sc = *httpSessionCache; | ||
660 | struct Session *s; | ||
661 | struct MHD_Response *response; | ||
662 | int res = MHD_YES; | ||
663 | |||
664 | GNUNET_assert (cls != NULL); | ||
665 | if (sc == NULL) | ||
666 | { | ||
667 | /* new connection */ | ||
668 | sc = server_lookup_serverconnection (plugin, mhd_connection, url, method); | ||
669 | if (sc != NULL) | ||
670 | (*httpSessionCache) = sc; | ||
671 | else | ||
672 | { | ||
673 | response = | ||
674 | MHD_create_response_from_data (strlen (HTTP_ERROR_RESPONSE), | ||
675 | HTTP_ERROR_RESPONSE, MHD_NO, MHD_NO); | ||
676 | res = MHD_queue_response (mhd_connection, MHD_HTTP_NOT_FOUND, response); | ||
677 | MHD_destroy_response (response); | ||
678 | return res; | ||
679 | } | ||
680 | } | ||
681 | else | ||
682 | { | ||
683 | /* 'old' connection */ | ||
684 | if (NULL == server_lookup_session (plugin, sc)) | ||
685 | { | ||
686 | /* Session was already disconnected */ | ||
687 | return MHD_NO; | ||
688 | } | ||
689 | } | ||
690 | |||
691 | /* existing connection */ | ||
692 | sc = (*httpSessionCache); | ||
693 | s = sc->session; | ||
694 | |||
695 | GNUNET_assert (NULL != s); | ||
696 | |||
697 | /* connection is to be disconnected */ | ||
698 | if (sc->disconnect == GNUNET_YES) | ||
699 | { | ||
700 | /* Sent HTTP/1.1: 200 OK as PUT Response\ */ | ||
701 | response = | ||
702 | MHD_create_response_from_data (strlen ("Thank you!"), "Thank you!", | ||
703 | MHD_NO, MHD_NO); | ||
704 | res = MHD_queue_response (mhd_connection, MHD_HTTP_OK, response); | ||
705 | MHD_destroy_response (response); | ||
706 | return MHD_YES; | ||
707 | } | ||
708 | |||
709 | GNUNET_assert (s != NULL); | ||
710 | /* Check if both directions are connected */ | ||
711 | if ((sc->session->server_recv == NULL) || (sc->session->server_send == NULL)) | ||
712 | { | ||
713 | /* Delayed read from since not both semi-connections are connected */ | ||
714 | return MHD_YES; | ||
715 | } | ||
716 | |||
717 | if (sc->direction == _SEND) | ||
718 | { | ||
719 | response = | ||
720 | MHD_create_response_from_callback (MHD_SIZE_UNKNOWN, | ||
721 | 32 * 1024, | ||
722 | &server_send_callback, s, | ||
723 | NULL); | ||
724 | MHD_queue_response (mhd_connection, MHD_HTTP_OK, response); | ||
725 | MHD_destroy_response (response); | ||
726 | return MHD_YES; | ||
727 | } | ||
728 | if (sc->direction == _RECEIVE) | ||
729 | { | ||
730 | if (*upload_data_size == 0) | ||
731 | { | ||
732 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
733 | "Server: Peer `%s' PUT on address `%s' connected\n", | ||
734 | GNUNET_i2s (&s->target), | ||
735 | http_plugin_address_to_string (NULL, s->addr, | ||
736 | s->addrlen)); | ||
737 | return MHD_YES; | ||
738 | } | ||
739 | |||
740 | /* Receiving data */ | ||
741 | if ((*upload_data_size > 0)) | ||
742 | { | ||
743 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
744 | "Server: peer `%s' PUT on address `%s' received %u bytes\n", | ||
745 | GNUNET_i2s (&s->target), | ||
746 | http_plugin_address_to_string (NULL, s->addr, | ||
747 | s->addrlen), | ||
748 | *upload_data_size); | ||
749 | struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); | ||
750 | |||
751 | if ((s->next_receive.abs_value <= now.abs_value)) | ||
752 | { | ||
753 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
754 | "Server: %p: PUT with %u bytes forwarded to MST\n", s, | ||
755 | *upload_data_size); | ||
756 | if (s->msg_tk == NULL) | ||
757 | { | ||
758 | s->msg_tk = GNUNET_SERVER_mst_create (&server_receive_mst_cb, s); | ||
759 | } | ||
760 | GNUNET_SERVER_mst_receive (s->msg_tk, s, upload_data, | ||
761 | *upload_data_size, GNUNET_NO, GNUNET_NO); | ||
762 | |||
763 | #if MHD_VERSION >= 0x00090E00 | ||
764 | int to = (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value / 1000); | ||
765 | struct ServerConnection *t = NULL; | ||
766 | |||
767 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
768 | "Server: Received %u bytes\n", *upload_data_size); | ||
769 | /* Setting timeouts for other connections */ | ||
770 | if (s->server_recv != NULL) | ||
771 | { | ||
772 | t = s->server_recv; | ||
773 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
774 | "Server: Setting timeout for %p to %u sec.\n", t, | ||
775 | to); | ||
776 | MHD_set_connection_option (t->mhd_conn, MHD_CONNECTION_OPTION_TIMEOUT, | ||
777 | to); | ||
778 | } | ||
779 | if (s->server_send != NULL) | ||
780 | { | ||
781 | t = s->server_send; | ||
782 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
783 | "Server: Setting timeout for %p to %u sec.\n", t, | ||
784 | to); | ||
785 | MHD_set_connection_option (t->mhd_conn, MHD_CONNECTION_OPTION_TIMEOUT, | ||
786 | to); | ||
787 | } | ||
788 | struct MHD_Daemon *d = NULL; | ||
789 | |||
790 | if (s->addrlen == sizeof (struct IPv6HttpAddress)) | ||
791 | d = plugin->server_v6; | ||
792 | if (s->addrlen == sizeof (struct IPv4HttpAddress)) | ||
793 | d = plugin->server_v4; | ||
794 | server_reschedule (plugin, d, GNUNET_NO); | ||
795 | #endif | ||
796 | (*upload_data_size) = 0; | ||
797 | } | ||
798 | else | ||
799 | { | ||
800 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
801 | "Server: %p no inbound bandwidth available! Next read was delayed by %llu ms\n", | ||
802 | s, now.abs_value - s->next_receive.abs_value); | ||
803 | } | ||
804 | return MHD_YES; | ||
805 | } | ||
806 | else | ||
807 | return MHD_NO; | ||
808 | } | ||
809 | return res; | ||
810 | } | ||
811 | |||
812 | static void | ||
813 | server_disconnect_cb (void *cls, struct MHD_Connection *connection, | ||
814 | void **httpSessionCache) | ||
815 | { | ||
816 | struct ServerConnection *sc = *httpSessionCache; | ||
817 | struct ServerConnection *tc = NULL; | ||
818 | struct Session *s = NULL; | ||
819 | struct Session *t = NULL; | ||
820 | struct Plugin *plugin = NULL; | ||
821 | |||
822 | if (sc == NULL) | ||
823 | return; | ||
824 | |||
825 | if (NULL == (s = server_lookup_session (p, sc))) | ||
826 | return; | ||
827 | |||
828 | GNUNET_assert (NULL != p); | ||
829 | if (GNUNET_NO == exist_session(p, s)) | ||
830 | return; | ||
831 | |||
832 | plugin = s->plugin; | ||
833 | if (sc->direction == _SEND) | ||
834 | { | ||
835 | |||
836 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
837 | "Server: %p peer `%s' GET on address `%s' disconnected\n", | ||
838 | s->server_send, GNUNET_i2s (&s->target), | ||
839 | http_plugin_address_to_string (NULL, s->addr, s->addrlen)); | ||
840 | s->server_send = NULL; | ||
841 | if (NULL != (tc = s->server_recv)) | ||
842 | { | ||
843 | tc->disconnect = GNUNET_YES; | ||
844 | GNUNET_assert (NULL != tc->mhd_conn); | ||
845 | #if MHD_VERSION >= 0x00090E00 | ||
846 | MHD_set_connection_option (tc->mhd_conn, MHD_CONNECTION_OPTION_TIMEOUT, | ||
847 | 1); | ||
848 | #endif | ||
849 | } | ||
850 | } | ||
851 | if (sc->direction == _RECEIVE) | ||
852 | { | ||
853 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
854 | "Server: %p peer `%s' PUT on address `%s' disconnected\n", | ||
855 | s->server_recv, GNUNET_i2s (&s->target), | ||
856 | http_plugin_address_to_string (NULL, s->addr, s->addrlen)); | ||
857 | s->server_recv = NULL; | ||
858 | if (NULL != (tc = s->server_send)) | ||
859 | { | ||
860 | tc->disconnect = GNUNET_YES; | ||
861 | GNUNET_assert (NULL != tc->mhd_conn); | ||
862 | #if MHD_VERSION >= 0x00090E00 | ||
863 | MHD_set_connection_option (tc->mhd_conn, MHD_CONNECTION_OPTION_TIMEOUT, | ||
864 | 1); | ||
865 | #endif | ||
866 | } | ||
867 | if (s->msg_tk != NULL) | ||
868 | { | ||
869 | GNUNET_SERVER_mst_destroy (s->msg_tk); | ||
870 | s->msg_tk = NULL; | ||
871 | } | ||
872 | } | ||
873 | |||
874 | GNUNET_free (sc); | ||
875 | |||
876 | t = plugin->server_semi_head; | ||
877 | while (t != NULL) | ||
878 | { | ||
879 | if (t == s) | ||
880 | { | ||
881 | GNUNET_CONTAINER_DLL_remove (plugin->server_semi_head, | ||
882 | plugin->server_semi_tail, s); | ||
883 | GNUNET_CONTAINER_DLL_insert (plugin->head, plugin->tail, s); | ||
884 | break; | ||
885 | } | ||
886 | t = t->next; | ||
887 | } | ||
888 | plugin->cur_connections--; | ||
889 | |||
890 | struct MHD_Daemon *d = NULL; | ||
891 | |||
892 | if (s->addrlen == sizeof (struct IPv6HttpAddress)) | ||
893 | d = plugin->server_v6; | ||
894 | if (s->addrlen == sizeof (struct IPv4HttpAddress)) | ||
895 | d = plugin->server_v4; | ||
896 | server_reschedule (plugin, d, GNUNET_NO); | ||
897 | |||
898 | if ((s->server_send == NULL) && (s->server_recv == NULL)) | ||
899 | { | ||
900 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
901 | "Server: peer `%s' on address `%s' disconnected\n", | ||
902 | GNUNET_i2s (&s->target), | ||
903 | http_plugin_address_to_string (NULL, s->addr, s->addrlen)); | ||
904 | if (s->msg_tk != NULL) | ||
905 | { | ||
906 | GNUNET_SERVER_mst_destroy (s->msg_tk); | ||
907 | s->msg_tk = NULL; | ||
908 | } | ||
909 | |||
910 | GNUNET_assert (plugin->inbound_sessions > 0); | ||
911 | plugin->inbound_sessions --; | ||
912 | GNUNET_STATISTICS_set (plugin->env->stats, | ||
913 | "# HTTP inbound sessions", | ||
914 | plugin->inbound_sessions, GNUNET_NO); | ||
915 | |||
916 | notify_session_end (s->plugin, &s->target, s); | ||
917 | } | ||
918 | } | ||
919 | |||
920 | int | ||
921 | server_disconnect (struct Session *s) | ||
922 | { | ||
923 | struct ServerConnection * send; | ||
924 | struct ServerConnection * recv; | ||
925 | |||
926 | send = (struct ServerConnection *) s->server_send; | ||
927 | if (s->server_send != NULL) | ||
928 | { | ||
929 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, s->plugin->name, | ||
930 | "Server: %p / %p Terminating inbound PUT session to peer `%s'\n", | ||
931 | s, s->server_send, GNUNET_i2s (&s->target)); | ||
932 | |||
933 | send->disconnect = GNUNET_YES; | ||
934 | #if MHD_VERSION >= 0x00090E00 | ||
935 | MHD_set_connection_option (send->mhd_conn, MHD_CONNECTION_OPTION_TIMEOUT, | ||
936 | 1); | ||
937 | #endif | ||
938 | } | ||
939 | |||
940 | recv = (struct ServerConnection *) s->server_recv; | ||
941 | if (recv != NULL) | ||
942 | { | ||
943 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, s->plugin->name, | ||
944 | "Server: %p / %p Terminating inbound GET session to peer `%s'\n", | ||
945 | s, s->server_recv, GNUNET_i2s (&s->target)); | ||
946 | |||
947 | recv->disconnect = GNUNET_YES; | ||
948 | #if MHD_VERSION >= 0x00090E00 | ||
949 | MHD_set_connection_option (recv->mhd_conn, MHD_CONNECTION_OPTION_TIMEOUT, | ||
950 | 1); | ||
951 | #endif | ||
952 | } | ||
953 | |||
954 | /* Schedule connection immediately */ | ||
955 | if (s->addrlen == sizeof (struct IPv4HttpAddress)) | ||
956 | { | ||
957 | server_reschedule (s->plugin, s->plugin->server_v4, GNUNET_YES); | ||
958 | } | ||
959 | else if (s->addrlen == sizeof (struct IPv6HttpAddress)) | ||
960 | { | ||
961 | server_reschedule (s->plugin, s->plugin->server_v6, GNUNET_YES); | ||
962 | } | ||
963 | return GNUNET_OK; | ||
964 | } | ||
965 | |||
966 | int | ||
967 | server_send (struct Session *s, struct HTTP_Message *msg) | ||
968 | { | ||
969 | GNUNET_CONTAINER_DLL_insert_tail (s->msg_head, s->msg_tail, msg); | ||
970 | |||
971 | if (s->addrlen == sizeof (struct IPv4HttpAddress)) | ||
972 | { | ||
973 | server_reschedule (s->plugin, s->plugin->server_v4, GNUNET_YES); | ||
974 | } | ||
975 | else if (s->addrlen == sizeof (struct IPv6HttpAddress)) | ||
976 | { | ||
977 | server_reschedule (s->plugin, s->plugin->server_v6, GNUNET_YES); | ||
978 | } | ||
979 | else | ||
980 | return GNUNET_SYSERR; | ||
981 | return GNUNET_OK; | ||
982 | } | ||
983 | |||
984 | |||
985 | |||
986 | /** | ||
987 | * Call MHD IPv4 to process pending requests and then go back | ||
988 | * and schedule the next run. | ||
989 | * @param cls plugin as closure | ||
990 | * @param tc task context | ||
991 | */ | ||
992 | static void | ||
993 | server_v4_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
994 | { | ||
995 | struct Plugin *plugin = cls; | ||
996 | |||
997 | GNUNET_assert (cls != NULL); | ||
998 | |||
999 | plugin->server_v4_task = GNUNET_SCHEDULER_NO_TASK; | ||
1000 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | ||
1001 | return; | ||
1002 | #if 0 | ||
1003 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
1004 | "Running IPv4 server\n"); | ||
1005 | #endif | ||
1006 | plugin->server_v4_immediately = GNUNET_NO; | ||
1007 | GNUNET_assert (MHD_YES == MHD_run (plugin->server_v4)); | ||
1008 | server_reschedule (plugin, plugin->server_v4, GNUNET_NO); | ||
1009 | } | ||
1010 | |||
1011 | |||
1012 | /** | ||
1013 | * Call MHD IPv6 to process pending requests and then go back | ||
1014 | * and schedule the next run. | ||
1015 | * @param cls plugin as closure | ||
1016 | * @param tc task context | ||
1017 | */ | ||
1018 | static void | ||
1019 | server_v6_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | ||
1020 | { | ||
1021 | struct Plugin *plugin = cls; | ||
1022 | |||
1023 | GNUNET_assert (cls != NULL); | ||
1024 | plugin->server_v6_task = GNUNET_SCHEDULER_NO_TASK; | ||
1025 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN)) | ||
1026 | return; | ||
1027 | #if 0 | ||
1028 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
1029 | "Running IPv6 server\n"); | ||
1030 | #endif | ||
1031 | plugin->server_v6_immediately = GNUNET_NO; | ||
1032 | GNUNET_assert (MHD_YES == MHD_run (plugin->server_v6)); | ||
1033 | server_reschedule (plugin, plugin->server_v6, GNUNET_NO); | ||
1034 | } | ||
1035 | |||
1036 | /** | ||
1037 | * Function that queries MHD's select sets and | ||
1038 | * starts the task waiting for them. | ||
1039 | * @param plugin plugin | ||
1040 | * @param daemon_handle the MHD daemon handle | ||
1041 | * @return gnunet task identifier | ||
1042 | */ | ||
1043 | static GNUNET_SCHEDULER_TaskIdentifier | ||
1044 | server_schedule (struct Plugin *plugin, struct MHD_Daemon *daemon_handle, | ||
1045 | int now) | ||
1046 | { | ||
1047 | GNUNET_SCHEDULER_TaskIdentifier ret; | ||
1048 | fd_set rs; | ||
1049 | fd_set ws; | ||
1050 | fd_set es; | ||
1051 | struct GNUNET_NETWORK_FDSet *wrs; | ||
1052 | struct GNUNET_NETWORK_FDSet *wws; | ||
1053 | struct GNUNET_NETWORK_FDSet *wes; | ||
1054 | int max; | ||
1055 | unsigned MHD_LONG_LONG timeout; | ||
1056 | static unsigned long long last_timeout = 0; | ||
1057 | int haveto; | ||
1058 | |||
1059 | struct GNUNET_TIME_Relative tv; | ||
1060 | |||
1061 | ret = GNUNET_SCHEDULER_NO_TASK; | ||
1062 | FD_ZERO (&rs); | ||
1063 | FD_ZERO (&ws); | ||
1064 | FD_ZERO (&es); | ||
1065 | wrs = GNUNET_NETWORK_fdset_create (); | ||
1066 | wes = GNUNET_NETWORK_fdset_create (); | ||
1067 | wws = GNUNET_NETWORK_fdset_create (); | ||
1068 | max = -1; | ||
1069 | GNUNET_assert (MHD_YES == MHD_get_fdset (daemon_handle, &rs, &ws, &es, &max)); | ||
1070 | haveto = MHD_get_timeout (daemon_handle, &timeout); | ||
1071 | if (haveto == MHD_YES) | ||
1072 | { | ||
1073 | if (timeout != last_timeout) | ||
1074 | { | ||
1075 | #if VERBOSE_SERVER | ||
1076 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
1077 | "SELECT Timeout changed from %llu to %llu\n", | ||
1078 | last_timeout, timeout); | ||
1079 | #endif | ||
1080 | last_timeout = timeout; | ||
1081 | } | ||
1082 | tv.rel_value = (uint64_t) timeout; | ||
1083 | } | ||
1084 | else | ||
1085 | tv = GNUNET_TIME_UNIT_SECONDS; | ||
1086 | /* Force immediate run, since we have outbound data to send */ | ||
1087 | if (now == GNUNET_YES) | ||
1088 | tv = GNUNET_TIME_UNIT_MILLISECONDS; | ||
1089 | GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1); | ||
1090 | GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1); | ||
1091 | GNUNET_NETWORK_fdset_copy_native (wes, &es, max + 1); | ||
1092 | |||
1093 | if (daemon_handle == plugin->server_v4) | ||
1094 | { | ||
1095 | if (plugin->server_v4_task != GNUNET_SCHEDULER_NO_TASK) | ||
1096 | { | ||
1097 | GNUNET_SCHEDULER_cancel (plugin->server_v4_task); | ||
1098 | plugin->server_v4_task = GNUNET_SCHEDULER_NO_TASK; | ||
1099 | } | ||
1100 | #if 0 | ||
1101 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
1102 | "Scheduling IPv4 server task in %llu ms\n", tv); | ||
1103 | #endif | ||
1104 | ret = | ||
1105 | GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, | ||
1106 | tv, wrs, wws, | ||
1107 | &server_v4_run, plugin); | ||
1108 | } | ||
1109 | if (daemon_handle == plugin->server_v6) | ||
1110 | { | ||
1111 | if (plugin->server_v6_task != GNUNET_SCHEDULER_NO_TASK) | ||
1112 | { | ||
1113 | GNUNET_SCHEDULER_cancel (plugin->server_v6_task); | ||
1114 | plugin->server_v6_task = GNUNET_SCHEDULER_NO_TASK; | ||
1115 | } | ||
1116 | #if 0 | ||
1117 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
1118 | "Scheduling IPv6 server task in %llu ms\n", tv); | ||
1119 | #endif | ||
1120 | ret = | ||
1121 | GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT, | ||
1122 | tv, wrs, wws, | ||
1123 | &server_v6_run, plugin); | ||
1124 | } | ||
1125 | GNUNET_NETWORK_fdset_destroy (wrs); | ||
1126 | GNUNET_NETWORK_fdset_destroy (wws); | ||
1127 | GNUNET_NETWORK_fdset_destroy (wes); | ||
1128 | return ret; | ||
1129 | } | ||
1130 | |||
1131 | int | ||
1132 | server_start (struct Plugin *plugin) | ||
1133 | { | ||
1134 | int res = GNUNET_OK; | ||
1135 | unsigned int timeout; | ||
1136 | p = plugin; | ||
1137 | GNUNET_assert (NULL != plugin); | ||
1138 | |||
1139 | #if BUILD_HTTPS | ||
1140 | res = server_load_certificate (plugin); | ||
1141 | if (res == GNUNET_SYSERR) | ||
1142 | { | ||
1143 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, | ||
1144 | "Could not load or create server certificate! Loading plugin failed!\n"); | ||
1145 | return res; | ||
1146 | } | ||
1147 | #endif | ||
1148 | |||
1149 | |||
1150 | #if MHD_VERSION >= 0x00090E00 | ||
1151 | timeout = HTTP_NOT_VALIDATED_TIMEOUT.rel_value / 1000; | ||
1152 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
1153 | "MHD can set timeout per connection! Default time out %u sec.\n", | ||
1154 | timeout); | ||
1155 | #else | ||
1156 | timeout = GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value / 1000; | ||
1157 | GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, plugin->name, | ||
1158 | "MHD cannot set timeout per connection! Default time out %u sec.\n", | ||
1159 | timeout); | ||
1160 | #endif | ||
1161 | plugin->server_v4 = NULL; | ||
1162 | if (plugin->ipv4 == GNUNET_YES) | ||
1163 | { | ||
1164 | plugin->server_v4 = MHD_start_daemon ( | ||
1165 | #if VERBOSE_SERVER | ||
1166 | MHD_USE_DEBUG | | ||
1167 | #endif | ||
1168 | #if BUILD_HTTPS | ||
1169 | MHD_USE_SSL | | ||
1170 | #endif | ||
1171 | MHD_NO_FLAG, plugin->port, | ||
1172 | &server_accept_cb, plugin, | ||
1173 | &server_access_cb, plugin, | ||
1174 | MHD_OPTION_SOCK_ADDR, | ||
1175 | (struct sockaddr_in *) | ||
1176 | plugin->server_addr_v4, | ||
1177 | MHD_OPTION_CONNECTION_LIMIT, | ||
1178 | (unsigned int) | ||
1179 | plugin->max_connections, | ||
1180 | #if BUILD_HTTPS | ||
1181 | MHD_OPTION_HTTPS_PRIORITIES, | ||
1182 | plugin->crypto_init, | ||
1183 | MHD_OPTION_HTTPS_MEM_KEY, | ||
1184 | plugin->key, | ||
1185 | MHD_OPTION_HTTPS_MEM_CERT, | ||
1186 | plugin->cert, | ||
1187 | #endif | ||
1188 | MHD_OPTION_CONNECTION_TIMEOUT, | ||
1189 | timeout, | ||
1190 | MHD_OPTION_CONNECTION_MEMORY_LIMIT, | ||
1191 | (size_t) (2 * | ||
1192 | GNUNET_SERVER_MAX_MESSAGE_SIZE), | ||
1193 | MHD_OPTION_NOTIFY_COMPLETED, | ||
1194 | &server_disconnect_cb, plugin, | ||
1195 | MHD_OPTION_EXTERNAL_LOGGER, | ||
1196 | server_log, NULL, MHD_OPTION_END); | ||
1197 | } | ||
1198 | plugin->server_v6 = NULL; | ||
1199 | if (plugin->ipv6 == GNUNET_YES) | ||
1200 | { | ||
1201 | plugin->server_v6 = MHD_start_daemon ( | ||
1202 | #if VERBOSE_SERVER | ||
1203 | MHD_USE_DEBUG | | ||
1204 | #endif | ||
1205 | #if BUILD_HTTPS | ||
1206 | MHD_USE_SSL | | ||
1207 | #endif | ||
1208 | MHD_USE_IPv6, plugin->port, | ||
1209 | &server_accept_cb, plugin, | ||
1210 | &server_access_cb, plugin, | ||
1211 | MHD_OPTION_SOCK_ADDR, | ||
1212 | (struct sockaddr_in6 *) | ||
1213 | plugin->server_addr_v6, | ||
1214 | MHD_OPTION_CONNECTION_LIMIT, | ||
1215 | (unsigned int) | ||
1216 | plugin->max_connections, | ||
1217 | #if BUILD_HTTPS | ||
1218 | MHD_OPTION_HTTPS_PRIORITIES, | ||
1219 | plugin->crypto_init, | ||
1220 | MHD_OPTION_HTTPS_MEM_KEY, | ||
1221 | plugin->key, | ||
1222 | MHD_OPTION_HTTPS_MEM_CERT, | ||
1223 | plugin->cert, | ||
1224 | #endif | ||
1225 | MHD_OPTION_CONNECTION_TIMEOUT, | ||
1226 | timeout, | ||
1227 | MHD_OPTION_CONNECTION_MEMORY_LIMIT, | ||
1228 | (size_t) (2 * | ||
1229 | GNUNET_SERVER_MAX_MESSAGE_SIZE), | ||
1230 | MHD_OPTION_NOTIFY_COMPLETED, | ||
1231 | &server_disconnect_cb, plugin, | ||
1232 | MHD_OPTION_EXTERNAL_LOGGER, | ||
1233 | server_log, NULL, MHD_OPTION_END); | ||
1234 | |||
1235 | } | ||
1236 | |||
1237 | if ((plugin->ipv4 == GNUNET_YES) && (plugin->server_v4 == NULL)) | ||
1238 | { | ||
1239 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, | ||
1240 | "Failed to start %s IPv4 server component on port %u\n", | ||
1241 | plugin->name, plugin->port); | ||
1242 | return GNUNET_SYSERR; | ||
1243 | } | ||
1244 | server_reschedule (plugin, plugin->server_v4, GNUNET_NO); | ||
1245 | |||
1246 | if ((plugin->ipv6 == GNUNET_YES) && (plugin->server_v6 == NULL)) | ||
1247 | { | ||
1248 | GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, | ||
1249 | "Failed to start %s IPv6 server component on port %u\n", | ||
1250 | plugin->name, plugin->port); | ||
1251 | return GNUNET_SYSERR; | ||
1252 | } | ||
1253 | server_reschedule (plugin, plugin->server_v6, GNUNET_NO); | ||
1254 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
1255 | "%s server component started on port %u\n", plugin->name, | ||
1256 | plugin->port); | ||
1257 | return res; | ||
1258 | } | ||
1259 | |||
1260 | void | ||
1261 | server_stop (struct Plugin *plugin) | ||
1262 | { | ||
1263 | struct Session *s = NULL; | ||
1264 | struct Session *t = NULL; | ||
1265 | |||
1266 | struct MHD_Daemon *server_v4_tmp = plugin->server_v4; | ||
1267 | plugin->server_v4 = NULL; | ||
1268 | |||
1269 | struct MHD_Daemon *server_v6_tmp = plugin->server_v6; | ||
1270 | plugin->server_v6 = NULL; | ||
1271 | |||
1272 | if (plugin->server_v4_task != GNUNET_SCHEDULER_NO_TASK) | ||
1273 | { | ||
1274 | GNUNET_SCHEDULER_cancel (plugin->server_v4_task); | ||
1275 | plugin->server_v4_task = GNUNET_SCHEDULER_NO_TASK; | ||
1276 | } | ||
1277 | |||
1278 | if (plugin->server_v6_task != GNUNET_SCHEDULER_NO_TASK) | ||
1279 | { | ||
1280 | GNUNET_SCHEDULER_cancel (plugin->server_v6_task); | ||
1281 | plugin->server_v6_task = GNUNET_SCHEDULER_NO_TASK; | ||
1282 | } | ||
1283 | |||
1284 | if (server_v6_tmp != NULL) | ||
1285 | { | ||
1286 | MHD_stop_daemon (server_v4_tmp); | ||
1287 | } | ||
1288 | if (server_v6_tmp != NULL) | ||
1289 | { | ||
1290 | MHD_stop_daemon (server_v6_tmp); | ||
1291 | } | ||
1292 | |||
1293 | /* cleaning up semi-sessions never propagated */ | ||
1294 | s = plugin->server_semi_head; | ||
1295 | while (s != NULL) | ||
1296 | { | ||
1297 | #if VERBOSE_SERVER | ||
1298 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
1299 | "Deleting semi-sessions %p\n", s); | ||
1300 | #endif | ||
1301 | t = s->next; | ||
1302 | struct HTTP_Message *msg = s->msg_head; | ||
1303 | struct HTTP_Message *tmp = NULL; | ||
1304 | |||
1305 | while (msg != NULL) | ||
1306 | { | ||
1307 | tmp = msg->next; | ||
1308 | |||
1309 | GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg); | ||
1310 | if (msg->transmit_cont != NULL) | ||
1311 | { | ||
1312 | msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_SYSERR); | ||
1313 | } | ||
1314 | GNUNET_free (msg); | ||
1315 | msg = tmp; | ||
1316 | } | ||
1317 | |||
1318 | delete_session (s); | ||
1319 | s = t; | ||
1320 | } | ||
1321 | |||
1322 | p = NULL; | ||
1323 | |||
1324 | #if BUILD_HTTPS | ||
1325 | GNUNET_free_non_null (plugin->crypto_init); | ||
1326 | GNUNET_free_non_null (plugin->cert); | ||
1327 | GNUNET_free_non_null (plugin->key); | ||
1328 | #endif | ||
1329 | |||
1330 | GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, | ||
1331 | "%s server component stopped\n", plugin->name); | ||
1332 | } | ||
1333 | |||
1334 | |||
1335 | |||
1336 | /* end of plugin_transport_http.c */ | ||
diff --git a/src/transport/test_transport_api_http_reverse_proxy.conf b/src/transport/test_transport_api_http_reverse_proxy.conf index 49fd9612e..8310ef3dd 100644 --- a/src/transport/test_transport_api_http_reverse_proxy.conf +++ b/src/transport/test_transport_api_http_reverse_proxy.conf | |||
@@ -5,7 +5,7 @@ DEFAULTCONFIG = test_transport_api_http_reverse_proxy.conf | |||
5 | 5 | ||
6 | [transport-http] | 6 | [transport-http] |
7 | PORT = 12080 | 7 | PORT = 12080 |
8 | EXTERNAL_HOSTNAME = fulcrum.net.in.tum.de/peer | 8 | EXTERNAL_HOSTNAME = fulcrum.net.in.tum.de:12080/peer |
9 | 9 | ||
10 | [arm] | 10 | [arm] |
11 | PORT = 12085 | 11 | PORT = 12085 |