diff options
Diffstat (limited to 'src/util')
39 files changed, 2695 insertions, 9969 deletions
diff --git a/src/util/Makefile.am b/src/util/Makefile.am index df319fe77..9be572bb6 100644 --- a/src/util/Makefile.am +++ b/src/util/Makefile.am | |||
@@ -30,10 +30,9 @@ W32CONSOLEHELPER = gnunet-helper-w32-console | |||
30 | endif | 30 | endif |
31 | 31 | ||
32 | if !MINGW | 32 | if !MINGW |
33 | SERVER_CLIENT_UNIX = test_server_with_client_unix | 33 | TEST_CLIENT_UNIX_NC = test_client_unix.nc |
34 | TEST_CLIENT_UNIC_NC = test_client_unix.nc | ||
35 | else | 34 | else |
36 | TEST_CLIENT_UNIC_NC = | 35 | TEST_CLIENT_UNIX_NC = |
37 | endif | 36 | endif |
38 | 37 | ||
39 | if USE_COVERAGE | 38 | if USE_COVERAGE |
@@ -68,7 +67,6 @@ libgnunetutil_la_SOURCES = \ | |||
68 | common_logging.c \ | 67 | common_logging.c \ |
69 | configuration.c \ | 68 | configuration.c \ |
70 | configuration_loader.c \ | 69 | configuration_loader.c \ |
71 | connection.c \ | ||
72 | container_bloomfilter.c \ | 70 | container_bloomfilter.c \ |
73 | container_heap.c \ | 71 | container_heap.c \ |
74 | container_meta_data.c \ | 72 | container_meta_data.c \ |
@@ -108,16 +106,10 @@ libgnunetutil_la_SOURCES = \ | |||
108 | program.c \ | 106 | program.c \ |
109 | resolver_api.c resolver.h \ | 107 | resolver_api.c resolver.h \ |
110 | scheduler.c \ | 108 | scheduler.c \ |
111 | server.c \ | ||
112 | server_mst.c \ | ||
113 | server_nc.c \ | ||
114 | server_tc.c \ | ||
115 | service.c \ | 109 | service.c \ |
116 | service_new.c \ | ||
117 | signal.c \ | 110 | signal.c \ |
118 | strings.c \ | 111 | strings.c \ |
119 | time.c \ | 112 | time.c \ |
120 | socks.c \ | ||
121 | speedup.c speedup.h | 113 | speedup.c speedup.h |
122 | 114 | ||
123 | libgnunetutil_la_LIBADD = \ | 115 | libgnunetutil_la_LIBADD = \ |
@@ -263,14 +255,13 @@ if HAVE_BENCHMARKS | |||
263 | endif | 255 | endif |
264 | 256 | ||
265 | if HAVE_SSH_KEY | 257 | if HAVE_SSH_KEY |
266 | SSH_USING_TESTS = test_socks.nc | 258 | # SSH_USING_TESTS = test_socks.nc |
267 | endif | 259 | endif |
268 | 260 | ||
269 | check_PROGRAMS = \ | 261 | check_PROGRAMS = \ |
270 | test_bio \ | 262 | test_bio \ |
271 | test_client.nc \ | 263 | test_client.nc \ |
272 | $(TEST_CLIENT_UNIX_NC) \ | 264 | $(TEST_CLIENT_UNIX_NC) \ |
273 | $(SSH_USING_TESTS) \ | ||
274 | test_common_allocation \ | 265 | test_common_allocation \ |
275 | test_common_endian \ | 266 | test_common_endian \ |
276 | test_common_logging \ | 267 | test_common_logging \ |
@@ -298,12 +289,6 @@ check_PROGRAMS = \ | |||
298 | test_crypto_rsa \ | 289 | test_crypto_rsa \ |
299 | test_disk \ | 290 | test_disk \ |
300 | test_getopt \ | 291 | test_getopt \ |
301 | test_connection.nc \ | ||
302 | test_connection_addressing.nc \ | ||
303 | test_connection_receive_cancel.nc \ | ||
304 | test_connection_timeout.nc \ | ||
305 | test_connection_timeout_no_connect.nc \ | ||
306 | test_connection_transmit_cancel.nc \ | ||
307 | test_mq \ | 292 | test_mq \ |
308 | test_os_network \ | 293 | test_os_network \ |
309 | test_peer \ | 294 | test_peer \ |
@@ -312,11 +297,6 @@ check_PROGRAMS = \ | |||
312 | test_resolver_api.nc \ | 297 | test_resolver_api.nc \ |
313 | test_scheduler \ | 298 | test_scheduler \ |
314 | test_scheduler_delay \ | 299 | test_scheduler_delay \ |
315 | test_server.nc \ | ||
316 | test_server_disconnect.nc \ | ||
317 | test_server_with_client.nc \ | ||
318 | test_server_mst_interrupt.nc \ | ||
319 | $(SERVER_CLIENT_UNIX) \ | ||
320 | test_service \ | 300 | test_service \ |
321 | test_strings \ | 301 | test_strings \ |
322 | test_strings_to_data \ | 302 | test_strings_to_data \ |
@@ -330,18 +310,7 @@ check_PROGRAMS = \ | |||
330 | # Declare .nc (NO-CONCURRENCY) as a test extension so that we can impart | 310 | # Declare .nc (NO-CONCURRENCY) as a test extension so that we can impart |
331 | # sequential execution order for them | 311 | # sequential execution order for them |
332 | TEST_EXTENSIONS = .nc | 312 | TEST_EXTENSIONS = .nc |
333 | test_connection.log: test_client.log | 313 | test_test_client_unix.log: test_client.log |
334 | test_connection_addressing.log: test_connection.log | ||
335 | test_connection_timeout_no_connect.log: test_connection_addressing.log | ||
336 | test_connection_transmit_cancel.log: test_connection_timeout_no_connect.log | ||
337 | test_connection_receive_cancel.log: test_connection_transmit_cancel.log | ||
338 | test_connection_timeout.log: test_connection_receive_cancel.log | ||
339 | test_resolver_api.log: test_connection_timeout.log | ||
340 | test_server.log: test_resolver_api.log | ||
341 | test_server_disconnect.log: test_server.log | ||
342 | test_server_with_client.log: test_server_disconnect.log | ||
343 | test_server_mst_interrupt.log: test_server_with_client.log | ||
344 | test_client_unix.log: test_server_mst_interrupt.log | ||
345 | 314 | ||
346 | test_bio_SOURCES = \ | 315 | test_bio_SOURCES = \ |
347 | test_bio.c | 316 | test_bio.c |
@@ -518,36 +487,6 @@ test_getopt_SOURCES = \ | |||
518 | test_getopt_LDADD = \ | 487 | test_getopt_LDADD = \ |
519 | libgnunetutil.la | 488 | libgnunetutil.la |
520 | 489 | ||
521 | test_connection_nc_SOURCES = \ | ||
522 | test_connection.c | ||
523 | test_connection_nc_LDADD = \ | ||
524 | libgnunetutil.la | ||
525 | |||
526 | test_connection_addressing_nc_SOURCES = \ | ||
527 | test_connection_addressing.c | ||
528 | test_connection_addressing_nc_LDADD = \ | ||
529 | libgnunetutil.la | ||
530 | |||
531 | test_connection_receive_cancel_nc_SOURCES = \ | ||
532 | test_connection_receive_cancel.c | ||
533 | test_connection_receive_cancel_nc_LDADD = \ | ||
534 | libgnunetutil.la | ||
535 | |||
536 | test_connection_timeout_nc_SOURCES = \ | ||
537 | test_connection_timeout.c | ||
538 | test_connection_timeout_nc_LDADD = \ | ||
539 | libgnunetutil.la | ||
540 | |||
541 | test_connection_timeout_no_connect_nc_SOURCES = \ | ||
542 | test_connection_timeout_no_connect.c | ||
543 | test_connection_timeout_no_connect_nc_LDADD = \ | ||
544 | libgnunetutil.la | ||
545 | |||
546 | test_connection_transmit_cancel_nc_SOURCES = \ | ||
547 | test_connection_transmit_cancel.c | ||
548 | test_connection_transmit_cancel_nc_LDADD = \ | ||
549 | libgnunetutil.la | ||
550 | |||
551 | test_mq_SOURCES = \ | 490 | test_mq_SOURCES = \ |
552 | test_mq.c | 491 | test_mq.c |
553 | test_mq_LDADD = \ | 492 | test_mq_LDADD = \ |
@@ -588,32 +527,6 @@ test_scheduler_delay_SOURCES = \ | |||
588 | test_scheduler_delay_LDADD = \ | 527 | test_scheduler_delay_LDADD = \ |
589 | libgnunetutil.la | 528 | libgnunetutil.la |
590 | 529 | ||
591 | test_server_mst_interrupt_nc_SOURCES = \ | ||
592 | test_server_mst_interrupt.c | ||
593 | test_server_mst_interrupt_nc_LDADD = \ | ||
594 | libgnunetutil.la | ||
595 | |||
596 | test_server_nc_SOURCES = \ | ||
597 | test_server.c | ||
598 | test_server_nc_LDADD = \ | ||
599 | libgnunetutil.la | ||
600 | |||
601 | test_server_disconnect_nc_SOURCES = \ | ||
602 | test_server_disconnect.c | ||
603 | test_server_disconnect_nc_LDADD = \ | ||
604 | libgnunetutil.la | ||
605 | |||
606 | test_server_with_client_nc_SOURCES = \ | ||
607 | test_server_with_client.c | ||
608 | test_server_with_client_nc_LDADD = \ | ||
609 | libgnunetutil.la | ||
610 | |||
611 | test_server_with_client_unix_SOURCES = \ | ||
612 | test_server_with_client_unix.c | ||
613 | test_server_with_client_unix_LDADD = \ | ||
614 | libgnunetutil.la | ||
615 | |||
616 | |||
617 | test_service_SOURCES = \ | 530 | test_service_SOURCES = \ |
618 | test_service.c | 531 | test_service.c |
619 | test_service_LDADD = \ | 532 | test_service_LDADD = \ |
@@ -624,7 +537,6 @@ test_strings_SOURCES = \ | |||
624 | test_strings_LDADD = \ | 537 | test_strings_LDADD = \ |
625 | libgnunetutil.la | 538 | libgnunetutil.la |
626 | 539 | ||
627 | |||
628 | test_strings_to_data_SOURCES = \ | 540 | test_strings_to_data_SOURCES = \ |
629 | test_strings_to_data.c | 541 | test_strings_to_data.c |
630 | test_strings_to_data_LDADD = \ | 542 | test_strings_to_data_LDADD = \ |
diff --git a/src/util/bandwidth.c b/src/util/bandwidth.c index a059fc738..bc0c3b9b4 100644 --- a/src/util/bandwidth.c +++ b/src/util/bandwidth.c | |||
@@ -184,8 +184,8 @@ update_excess (struct GNUNET_BANDWIDTH_Tracker *av) | |||
184 | } | 184 | } |
185 | /* negative current_consumption means that we have savings */ | 185 | /* negative current_consumption means that we have savings */ |
186 | max_carry = ((uint64_t) av->available_bytes_per_s__) * av->max_carry_s__; | 186 | max_carry = ((uint64_t) av->available_bytes_per_s__) * av->max_carry_s__; |
187 | if (max_carry < GNUNET_SERVER_MAX_MESSAGE_SIZE) | 187 | if (max_carry < GNUNET_MAX_MESSAGE_SIZE) |
188 | max_carry = GNUNET_SERVER_MAX_MESSAGE_SIZE; | 188 | max_carry = GNUNET_MAX_MESSAGE_SIZE; |
189 | if (max_carry > INT64_MAX) | 189 | if (max_carry > INT64_MAX) |
190 | max_carry = INT64_MAX; | 190 | max_carry = INT64_MAX; |
191 | left_bytes = current_consumption + max_carry; | 191 | left_bytes = current_consumption + max_carry; |
@@ -224,10 +224,10 @@ update_excess (struct GNUNET_BANDWIDTH_Tracker *av) | |||
224 | /** | 224 | /** |
225 | * Initialize bandwidth tracker. Note that in addition to the | 225 | * Initialize bandwidth tracker. Note that in addition to the |
226 | * 'max_carry_s' limit, we also always allow at least | 226 | * 'max_carry_s' limit, we also always allow at least |
227 | * #GNUNET_SERVER_MAX_MESSAGE_SIZE to accumulate. So if the | 227 | * #GNUNET_MAX_MESSAGE_SIZE to accumulate. So if the |
228 | * bytes-per-second limit is so small that within 'max_carry_s' not | 228 | * bytes-per-second limit is so small that within 'max_carry_s' not |
229 | * even #GNUNET_SERVER_MAX_MESSAGE_SIZE is allowed to accumulate, it is | 229 | * even #GNUNET_MAX_MESSAGE_SIZE is allowed to accumulate, it is |
230 | * ignored and replaced by #GNUNET_SERVER_MAX_MESSAGE_SIZE (which is in | 230 | * ignored and replaced by #GNUNET_MAX_MESSAGE_SIZE (which is in |
231 | * bytes). | 231 | * bytes). |
232 | * | 232 | * |
233 | * To stop notifications about updates and excess callbacks use | 233 | * To stop notifications about updates and excess callbacks use |
@@ -271,10 +271,10 @@ GNUNET_BANDWIDTH_tracker_init2 (struct GNUNET_BANDWIDTH_Tracker *av, | |||
271 | /** | 271 | /** |
272 | * Initialize bandwidth tracker. Note that in addition to the | 272 | * Initialize bandwidth tracker. Note that in addition to the |
273 | * 'max_carry_s' limit, we also always allow at least | 273 | * 'max_carry_s' limit, we also always allow at least |
274 | * #GNUNET_SERVER_MAX_MESSAGE_SIZE to accumulate. So if the | 274 | * #GNUNET_MAX_MESSAGE_SIZE to accumulate. So if the |
275 | * bytes-per-second limit is so small that within 'max_carry_s' not | 275 | * bytes-per-second limit is so small that within 'max_carry_s' not |
276 | * even #GNUNET_SERVER_MAX_MESSAGE_SIZE is allowed to accumulate, it is | 276 | * even #GNUNET_MAX_MESSAGE_SIZE is allowed to accumulate, it is |
277 | * ignored and replaced by #GNUNET_SERVER_MAX_MESSAGE_SIZE (which is in | 277 | * ignored and replaced by #GNUNET_MAX_MESSAGE_SIZE (which is in |
278 | * bytes). | 278 | * bytes). |
279 | * | 279 | * |
280 | * @param av tracker to initialize | 280 | * @param av tracker to initialize |
@@ -345,8 +345,8 @@ update_tracker (struct GNUNET_BANDWIDTH_Tracker *av) | |||
345 | left_bytes = - av->consumption_since_last_update__; | 345 | left_bytes = - av->consumption_since_last_update__; |
346 | max_carry = ((unsigned long long) av->available_bytes_per_s__) * | 346 | max_carry = ((unsigned long long) av->available_bytes_per_s__) * |
347 | av->max_carry_s__; | 347 | av->max_carry_s__; |
348 | if (max_carry < GNUNET_SERVER_MAX_MESSAGE_SIZE) | 348 | if (max_carry < GNUNET_MAX_MESSAGE_SIZE) |
349 | max_carry = GNUNET_SERVER_MAX_MESSAGE_SIZE; | 349 | max_carry = GNUNET_MAX_MESSAGE_SIZE; |
350 | if (max_carry > INT64_MAX) | 350 | if (max_carry > INT64_MAX) |
351 | max_carry = INT64_MAX; | 351 | max_carry = INT64_MAX; |
352 | if (max_carry > left_bytes) | 352 | if (max_carry > left_bytes) |
diff --git a/src/util/client.c b/src/util/client.c index 0f7d0d359..3d74bff33 100644 --- a/src/util/client.c +++ b/src/util/client.c | |||
@@ -35,6 +35,15 @@ | |||
35 | 35 | ||
36 | #define LOG(kind,...) GNUNET_log_from (kind, "util-client",__VA_ARGS__) | 36 | #define LOG(kind,...) GNUNET_log_from (kind, "util-client",__VA_ARGS__) |
37 | 37 | ||
38 | /** | ||
39 | * Timeout we use on TCP connect before trying another | ||
40 | * result from the DNS resolver. Actual value used | ||
41 | * is this value divided by the number of address families. | ||
42 | * Default is 5s. | ||
43 | */ | ||
44 | #define CONNECT_RETRY_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) | ||
45 | |||
46 | |||
38 | 47 | ||
39 | /** | 48 | /** |
40 | * Internal state for a client connected to a GNUnet service. | 49 | * Internal state for a client connected to a GNUnet service. |
@@ -298,11 +307,11 @@ recv_message (void *cls, | |||
298 | 307 | ||
299 | if (GNUNET_YES == cstate->in_destroy) | 308 | if (GNUNET_YES == cstate->in_destroy) |
300 | return GNUNET_SYSERR; | 309 | return GNUNET_SYSERR; |
301 | 310 | LOG (GNUNET_ERROR_TYPE_DEBUG, | |
302 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
303 | "Received message of type %u and size %u from %s\n", | 311 | "Received message of type %u and size %u from %s\n", |
304 | ntohs (msg->type), ntohs (msg->size), cstate->service_name); | 312 | ntohs (msg->type), |
305 | 313 | ntohs (msg->size), | |
314 | cstate->service_name); | ||
306 | GNUNET_MQ_inject_message (cstate->mq, | 315 | GNUNET_MQ_inject_message (cstate->mq, |
307 | msg); | 316 | msg); |
308 | if (GNUNET_YES == cstate->in_destroy) | 317 | if (GNUNET_YES == cstate->in_destroy) |
@@ -656,7 +665,7 @@ try_connect_using_address (void *cls, | |||
656 | GNUNET_CONTAINER_DLL_insert (cstate->ap_head, | 665 | GNUNET_CONTAINER_DLL_insert (cstate->ap_head, |
657 | cstate->ap_tail, | 666 | cstate->ap_tail, |
658 | ap); | 667 | ap); |
659 | ap->task = GNUNET_SCHEDULER_add_write_net (GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT, | 668 | ap->task = GNUNET_SCHEDULER_add_write_net (CONNECT_RETRY_TIMEOUT, |
660 | ap->sock, | 669 | ap->sock, |
661 | &connect_probe_continuation, | 670 | &connect_probe_continuation, |
662 | ap); | 671 | ap); |
@@ -760,7 +769,7 @@ start_connect (void *cls) | |||
760 | cstate->dns_active | 769 | cstate->dns_active |
761 | = GNUNET_RESOLVER_ip_get (cstate->hostname, | 770 | = GNUNET_RESOLVER_ip_get (cstate->hostname, |
762 | AF_UNSPEC, | 771 | AF_UNSPEC, |
763 | GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT, | 772 | CONNECT_RETRY_TIMEOUT, |
764 | &try_connect_using_address, | 773 | &try_connect_using_address, |
765 | cstate); | 774 | cstate); |
766 | } | 775 | } |
diff --git a/src/util/connection.c b/src/util/connection.c deleted file mode 100644 index e822b264f..000000000 --- a/src/util/connection.c +++ /dev/null | |||
@@ -1,1648 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009-2013 GNUnet e.V. | ||
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., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file util/connection.c | ||
23 | * @brief TCP connection management | ||
24 | * @author Christian Grothoff | ||
25 | * | ||
26 | * This code is rather complex. Only modify it if you | ||
27 | * 1) Have a NEW testcase showing that the new code | ||
28 | * is needed and correct | ||
29 | * 2) All EXISTING testcases pass with the new code | ||
30 | * These rules should apply in general, but for this | ||
31 | * module they are VERY, VERY important. | ||
32 | */ | ||
33 | #include "platform.h" | ||
34 | #include "gnunet_util_lib.h" | ||
35 | #include "gnunet_resolver_service.h" | ||
36 | |||
37 | |||
38 | #define LOG(kind,...) GNUNET_log_from (kind, "util-connection", __VA_ARGS__) | ||
39 | |||
40 | #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-connection", syscall) | ||
41 | |||
42 | |||
43 | /** | ||
44 | * Transmission handle. There can only be one for each connection. | ||
45 | */ | ||
46 | struct GNUNET_CONNECTION_TransmitHandle | ||
47 | { | ||
48 | |||
49 | /** | ||
50 | * Function to call if the send buffer has notify_size | ||
51 | * bytes available. | ||
52 | */ | ||
53 | GNUNET_CONNECTION_TransmitReadyNotify notify_ready; | ||
54 | |||
55 | /** | ||
56 | * Closure for notify_ready. | ||
57 | */ | ||
58 | void *notify_ready_cls; | ||
59 | |||
60 | /** | ||
61 | * Our connection handle. | ||
62 | */ | ||
63 | struct GNUNET_CONNECTION_Handle *connection; | ||
64 | |||
65 | /** | ||
66 | * Timeout for receiving (in absolute time). | ||
67 | */ | ||
68 | struct GNUNET_TIME_Absolute transmit_timeout; | ||
69 | |||
70 | /** | ||
71 | * Task called on timeout. | ||
72 | */ | ||
73 | struct GNUNET_SCHEDULER_Task * timeout_task; | ||
74 | |||
75 | /** | ||
76 | * At what number of bytes available in the | ||
77 | * write buffer should the notify method be called? | ||
78 | */ | ||
79 | size_t notify_size; | ||
80 | |||
81 | }; | ||
82 | |||
83 | |||
84 | /** | ||
85 | * During connect, we try multiple possible IP addresses | ||
86 | * to find out which one might work. | ||
87 | */ | ||
88 | struct AddressProbe | ||
89 | { | ||
90 | |||
91 | /** | ||
92 | * This is a linked list. | ||
93 | */ | ||
94 | struct AddressProbe *next; | ||
95 | |||
96 | /** | ||
97 | * This is a doubly-linked list. | ||
98 | */ | ||
99 | struct AddressProbe *prev; | ||
100 | |||
101 | /** | ||
102 | * The address; do not free (allocated at the end of this struct). | ||
103 | */ | ||
104 | const struct sockaddr *addr; | ||
105 | |||
106 | /** | ||
107 | * Underlying OS's socket. | ||
108 | */ | ||
109 | struct GNUNET_NETWORK_Handle *sock; | ||
110 | |||
111 | /** | ||
112 | * Connection for which we are probing. | ||
113 | */ | ||
114 | struct GNUNET_CONNECTION_Handle *connection; | ||
115 | |||
116 | /** | ||
117 | * Lenth of addr. | ||
118 | */ | ||
119 | socklen_t addrlen; | ||
120 | |||
121 | /** | ||
122 | * Task waiting for the connection to finish connecting. | ||
123 | */ | ||
124 | struct GNUNET_SCHEDULER_Task * task; | ||
125 | }; | ||
126 | |||
127 | |||
128 | /** | ||
129 | * @brief handle for a network connection | ||
130 | */ | ||
131 | struct GNUNET_CONNECTION_Handle | ||
132 | { | ||
133 | |||
134 | /** | ||
135 | * Configuration to use. | ||
136 | */ | ||
137 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
138 | |||
139 | /** | ||
140 | * Linked list of sockets we are currently trying out | ||
141 | * (during connect). | ||
142 | */ | ||
143 | struct AddressProbe *ap_head; | ||
144 | |||
145 | /** | ||
146 | * Linked list of sockets we are currently trying out | ||
147 | * (during connect). | ||
148 | */ | ||
149 | struct AddressProbe *ap_tail; | ||
150 | |||
151 | /** | ||
152 | * Network address of the other end-point, may be NULL. | ||
153 | */ | ||
154 | struct sockaddr *addr; | ||
155 | |||
156 | /** | ||
157 | * Pointer to the hostname if connection was | ||
158 | * created using DNS lookup, otherwise NULL. | ||
159 | */ | ||
160 | char *hostname; | ||
161 | |||
162 | /** | ||
163 | * Underlying OS's socket, set to NULL after fatal errors. | ||
164 | */ | ||
165 | struct GNUNET_NETWORK_Handle *sock; | ||
166 | |||
167 | /** | ||
168 | * Function to call on data received, NULL if no receive is pending. | ||
169 | */ | ||
170 | GNUNET_CONNECTION_Receiver receiver; | ||
171 | |||
172 | /** | ||
173 | * Closure for @e receiver. | ||
174 | */ | ||
175 | void *receiver_cls; | ||
176 | |||
177 | /** | ||
178 | * Pointer to our write buffer. | ||
179 | */ | ||
180 | char *write_buffer; | ||
181 | |||
182 | /** | ||
183 | * Current size of our @e write_buffer. | ||
184 | */ | ||
185 | size_t write_buffer_size; | ||
186 | |||
187 | /** | ||
188 | * Current write-offset in @e write_buffer (where | ||
189 | * would we write next). | ||
190 | */ | ||
191 | size_t write_buffer_off; | ||
192 | |||
193 | /** | ||
194 | * Current read-offset in @e write_buffer (how many | ||
195 | * bytes have already been sent). | ||
196 | */ | ||
197 | size_t write_buffer_pos; | ||
198 | |||
199 | /** | ||
200 | * Length of @e addr. | ||
201 | */ | ||
202 | socklen_t addrlen; | ||
203 | |||
204 | /** | ||
205 | * Read task that we may need to wait for. | ||
206 | */ | ||
207 | struct GNUNET_SCHEDULER_Task *read_task; | ||
208 | |||
209 | /** | ||
210 | * Write task that we may need to wait for. | ||
211 | */ | ||
212 | struct GNUNET_SCHEDULER_Task *write_task; | ||
213 | |||
214 | /** | ||
215 | * Handle to a pending DNS lookup request. | ||
216 | */ | ||
217 | struct GNUNET_RESOLVER_RequestHandle *dns_active; | ||
218 | |||
219 | /** | ||
220 | * The handle we return for #GNUNET_CONNECTION_notify_transmit_ready(). | ||
221 | */ | ||
222 | struct GNUNET_CONNECTION_TransmitHandle nth; | ||
223 | |||
224 | /** | ||
225 | * Timeout for receiving (in absolute time). | ||
226 | */ | ||
227 | struct GNUNET_TIME_Absolute receive_timeout; | ||
228 | |||
229 | /** | ||
230 | * Maximum number of bytes to read (for receiving). | ||
231 | */ | ||
232 | size_t max; | ||
233 | |||
234 | /** | ||
235 | * Port to connect to. | ||
236 | */ | ||
237 | uint16_t port; | ||
238 | |||
239 | /** | ||
240 | * When shutdown, do not ever actually close the socket, but | ||
241 | * free resources. Only should ever be set if using program | ||
242 | * termination as a signal (because only then will the leaked | ||
243 | * socket be freed!) | ||
244 | */ | ||
245 | int8_t persist; | ||
246 | |||
247 | /** | ||
248 | * Usually 0. Set to 1 if this handle is in use, and should | ||
249 | * #GNUNET_CONNECTION_destroy() be called right now, the action needs | ||
250 | * to be deferred by setting it to -1. | ||
251 | */ | ||
252 | int8_t destroy_later; | ||
253 | |||
254 | /** | ||
255 | * Handle to subsequent connection after proxy handshake completes, | ||
256 | */ | ||
257 | struct GNUNET_CONNECTION_Handle *proxy_handshake; | ||
258 | |||
259 | }; | ||
260 | |||
261 | |||
262 | /** | ||
263 | * Set the persist option on this connection handle. Indicates | ||
264 | * that the underlying socket or fd should never really be closed. | ||
265 | * Used for indicating process death. | ||
266 | * | ||
267 | * @param connection the connection to set persistent | ||
268 | */ | ||
269 | void | ||
270 | GNUNET_CONNECTION_persist_ (struct GNUNET_CONNECTION_Handle *connection) | ||
271 | { | ||
272 | connection->persist = GNUNET_YES; | ||
273 | } | ||
274 | |||
275 | |||
276 | /** | ||
277 | * Disable the "CORK" feature for communication with the given connection, | ||
278 | * forcing the OS to immediately flush the buffer on transmission | ||
279 | * instead of potentially buffering multiple messages. Essentially | ||
280 | * reduces the OS send buffers to zero. | ||
281 | * Used to make sure that the last messages sent through the connection | ||
282 | * reach the other side before the process is terminated. | ||
283 | * | ||
284 | * @param connection the connection to make flushing and blocking | ||
285 | * @return #GNUNET_OK on success | ||
286 | */ | ||
287 | int | ||
288 | GNUNET_CONNECTION_disable_corking (struct GNUNET_CONNECTION_Handle *connection) | ||
289 | { | ||
290 | return GNUNET_NETWORK_socket_disable_corking (connection->sock); | ||
291 | } | ||
292 | |||
293 | |||
294 | /** | ||
295 | * Create a connection handle by boxing an existing OS socket. The OS | ||
296 | * socket should henceforth be no longer used directly. | ||
297 | * #GNUNET_connection_destroy() will close it. | ||
298 | * | ||
299 | * @param osSocket existing socket to box | ||
300 | * @return the boxed connection handle | ||
301 | */ | ||
302 | struct GNUNET_CONNECTION_Handle * | ||
303 | GNUNET_CONNECTION_create_from_existing (struct GNUNET_NETWORK_Handle *osSocket) | ||
304 | { | ||
305 | struct GNUNET_CONNECTION_Handle *connection; | ||
306 | |||
307 | connection = GNUNET_new (struct GNUNET_CONNECTION_Handle); | ||
308 | connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE; | ||
309 | connection->write_buffer = GNUNET_malloc (connection->write_buffer_size); | ||
310 | connection->sock = osSocket; | ||
311 | return connection; | ||
312 | } | ||
313 | |||
314 | |||
315 | /** | ||
316 | * Create a connection handle by accepting on a listen socket. This | ||
317 | * function may block if the listen socket has no connection ready. | ||
318 | * | ||
319 | * @param access_cb function to use to check if access is allowed | ||
320 | * @param access_cb_cls closure for @a access_cb | ||
321 | * @param lsock listen socket | ||
322 | * @return the connection handle, NULL on error | ||
323 | */ | ||
324 | struct GNUNET_CONNECTION_Handle * | ||
325 | GNUNET_CONNECTION_create_from_accept (GNUNET_CONNECTION_AccessCheck access_cb, | ||
326 | void *access_cb_cls, | ||
327 | struct GNUNET_NETWORK_Handle *lsock) | ||
328 | { | ||
329 | struct GNUNET_CONNECTION_Handle *connection; | ||
330 | char addr[128]; | ||
331 | socklen_t addrlen; | ||
332 | struct GNUNET_NETWORK_Handle *sock; | ||
333 | int aret; | ||
334 | struct sockaddr_in *v4; | ||
335 | struct sockaddr_in6 *v6; | ||
336 | struct sockaddr *sa; | ||
337 | void *uaddr; | ||
338 | #ifdef SO_PEERCRED | ||
339 | struct ucred uc; | ||
340 | socklen_t olen; | ||
341 | #endif | ||
342 | struct GNUNET_CONNECTION_Credentials *gcp; | ||
343 | #if HAVE_GETPEEREID || defined(SO_PEERCRED) || HAVE_GETPEERUCRED | ||
344 | struct GNUNET_CONNECTION_Credentials gc; | ||
345 | |||
346 | gc.uid = 0; | ||
347 | gc.gid = 0; | ||
348 | #endif | ||
349 | |||
350 | addrlen = sizeof (addr); | ||
351 | sock = | ||
352 | GNUNET_NETWORK_socket_accept (lsock, | ||
353 | (struct sockaddr *) &addr, | ||
354 | &addrlen); | ||
355 | if (NULL == sock) | ||
356 | { | ||
357 | if (EAGAIN != errno) | ||
358 | LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "accept"); | ||
359 | return NULL; | ||
360 | } | ||
361 | if ((addrlen > sizeof (addr)) || (addrlen < sizeof (sa_family_t))) | ||
362 | { | ||
363 | GNUNET_break (0); | ||
364 | GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock)); | ||
365 | return NULL; | ||
366 | } | ||
367 | |||
368 | sa = (struct sockaddr *) addr; | ||
369 | v6 = (struct sockaddr_in6 *) addr; | ||
370 | if ( (AF_INET6 == sa->sa_family) && | ||
371 | (IN6_IS_ADDR_V4MAPPED (&v6->sin6_addr)) ) | ||
372 | { | ||
373 | /* convert to V4 address */ | ||
374 | v4 = GNUNET_new (struct sockaddr_in); | ||
375 | memset (v4, 0, sizeof (struct sockaddr_in)); | ||
376 | v4->sin_family = AF_INET; | ||
377 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
378 | v4->sin_len = (u_char) sizeof (struct sockaddr_in); | ||
379 | #endif | ||
380 | GNUNET_memcpy (&v4->sin_addr, | ||
381 | &((char *) &v6->sin6_addr)[sizeof (struct in6_addr) - | ||
382 | sizeof (struct in_addr)], | ||
383 | sizeof (struct in_addr)); | ||
384 | v4->sin_port = v6->sin6_port; | ||
385 | uaddr = v4; | ||
386 | addrlen = sizeof (struct sockaddr_in); | ||
387 | } | ||
388 | else | ||
389 | { | ||
390 | uaddr = GNUNET_malloc (addrlen); | ||
391 | GNUNET_memcpy (uaddr, addr, addrlen); | ||
392 | } | ||
393 | gcp = NULL; | ||
394 | if (AF_UNIX == sa->sa_family) | ||
395 | { | ||
396 | #if HAVE_GETPEEREID | ||
397 | /* most BSDs */ | ||
398 | if (0 == getpeereid (GNUNET_NETWORK_get_fd (sock), | ||
399 | &gc.uid, | ||
400 | &gc.gid)) | ||
401 | gcp = &gc; | ||
402 | #else | ||
403 | #ifdef SO_PEERCRED | ||
404 | /* largely traditional GNU/Linux */ | ||
405 | olen = sizeof (uc); | ||
406 | if ( (0 == | ||
407 | getsockopt (GNUNET_NETWORK_get_fd (sock), | ||
408 | SOL_SOCKET, | ||
409 | SO_PEERCRED, | ||
410 | &uc, | ||
411 | &olen)) && | ||
412 | (olen == sizeof (uc)) ) | ||
413 | { | ||
414 | gc.uid = uc.uid; | ||
415 | gc.gid = uc.gid; | ||
416 | gcp = &gc; | ||
417 | } | ||
418 | #else | ||
419 | #if HAVE_GETPEERUCRED | ||
420 | /* this is for Solaris 10 */ | ||
421 | ucred_t *uc; | ||
422 | |||
423 | uc = NULL; | ||
424 | if (0 == getpeerucred (GNUNET_NETWORK_get_fd (sock), &uc)) | ||
425 | { | ||
426 | gc.uid = ucred_geteuid (uc); | ||
427 | gc.gid = ucred_getegid (uc); | ||
428 | gcp = &gc; | ||
429 | } | ||
430 | ucred_free (uc); | ||
431 | #endif | ||
432 | #endif | ||
433 | #endif | ||
434 | } | ||
435 | |||
436 | if ( (NULL != access_cb) && | ||
437 | (GNUNET_YES != (aret = access_cb (access_cb_cls, | ||
438 | gcp, | ||
439 | uaddr, | ||
440 | addrlen))) ) | ||
441 | { | ||
442 | if (GNUNET_NO == aret) | ||
443 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
444 | _("Access denied to `%s'\n"), | ||
445 | GNUNET_a2s (uaddr, | ||
446 | addrlen)); | ||
447 | GNUNET_break (GNUNET_OK == | ||
448 | GNUNET_NETWORK_socket_shutdown (sock, | ||
449 | SHUT_RDWR)); | ||
450 | GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock)); | ||
451 | GNUNET_free (uaddr); | ||
452 | return NULL; | ||
453 | } | ||
454 | connection = GNUNET_new (struct GNUNET_CONNECTION_Handle); | ||
455 | connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE; | ||
456 | connection->write_buffer = GNUNET_malloc (connection->write_buffer_size); | ||
457 | connection->addr = uaddr; | ||
458 | connection->addrlen = addrlen; | ||
459 | connection->sock = sock; | ||
460 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
461 | _("Accepting connection from `%s': %p\n"), | ||
462 | GNUNET_a2s (uaddr, | ||
463 | addrlen), | ||
464 | connection); | ||
465 | return connection; | ||
466 | } | ||
467 | |||
468 | |||
469 | /** | ||
470 | * Obtain the network address of the other party. | ||
471 | * | ||
472 | * @param connection the client to get the address for | ||
473 | * @param addr where to store the address | ||
474 | * @param addrlen where to store the length of the @a addr | ||
475 | * @return #GNUNET_OK on success | ||
476 | */ | ||
477 | int | ||
478 | GNUNET_CONNECTION_get_address (struct GNUNET_CONNECTION_Handle *connection, | ||
479 | void **addr, | ||
480 | size_t *addrlen) | ||
481 | { | ||
482 | if ((NULL == connection->addr) || (0 == connection->addrlen)) | ||
483 | return GNUNET_NO; | ||
484 | *addr = GNUNET_malloc (connection->addrlen); | ||
485 | GNUNET_memcpy (*addr, connection->addr, connection->addrlen); | ||
486 | *addrlen = connection->addrlen; | ||
487 | return GNUNET_OK; | ||
488 | } | ||
489 | |||
490 | |||
491 | /** | ||
492 | * Tell the receiver callback that we had an IO error. | ||
493 | * | ||
494 | * @param connection connection to signal error | ||
495 | * @param errcode error code to send | ||
496 | */ | ||
497 | static void | ||
498 | signal_receive_error (struct GNUNET_CONNECTION_Handle *connection, | ||
499 | int errcode) | ||
500 | { | ||
501 | GNUNET_CONNECTION_Receiver receiver; | ||
502 | |||
503 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
504 | "Receive encounters error (%s), connection closed (%p)\n", | ||
505 | STRERROR (errcode), | ||
506 | connection); | ||
507 | GNUNET_assert (NULL != (receiver = connection->receiver)); | ||
508 | connection->receiver = NULL; | ||
509 | receiver (connection->receiver_cls, | ||
510 | NULL, | ||
511 | 0, | ||
512 | connection->addr, | ||
513 | connection->addrlen, | ||
514 | errcode); | ||
515 | } | ||
516 | |||
517 | |||
518 | /** | ||
519 | * Tell the receiver callback that a timeout was reached. | ||
520 | * | ||
521 | * @param connection connection to signal for | ||
522 | */ | ||
523 | static void | ||
524 | signal_receive_timeout (struct GNUNET_CONNECTION_Handle *connection) | ||
525 | { | ||
526 | GNUNET_CONNECTION_Receiver receiver; | ||
527 | |||
528 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
529 | "Connection signals timeout to receiver (%p)!\n", | ||
530 | connection); | ||
531 | GNUNET_assert (NULL != (receiver = connection->receiver)); | ||
532 | connection->receiver = NULL; | ||
533 | receiver (connection->receiver_cls, NULL, 0, NULL, 0, 0); | ||
534 | } | ||
535 | |||
536 | |||
537 | /** | ||
538 | * We failed to transmit data to the service, signal the error. | ||
539 | * | ||
540 | * @param connection handle that had trouble | ||
541 | * @param ecode error code (errno) | ||
542 | */ | ||
543 | static void | ||
544 | signal_transmit_error (struct GNUNET_CONNECTION_Handle *connection, | ||
545 | int ecode) | ||
546 | { | ||
547 | GNUNET_CONNECTION_TransmitReadyNotify notify; | ||
548 | |||
549 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
550 | "Transmission encounterd error (%s), connection closed (%p)\n", | ||
551 | STRERROR (ecode), | ||
552 | connection); | ||
553 | if (NULL != connection->sock) | ||
554 | { | ||
555 | (void) GNUNET_NETWORK_socket_shutdown (connection->sock, | ||
556 | SHUT_RDWR); | ||
557 | GNUNET_break (GNUNET_OK == | ||
558 | GNUNET_NETWORK_socket_close (connection->sock)); | ||
559 | connection->sock = NULL; | ||
560 | GNUNET_assert (NULL == connection->write_task); | ||
561 | } | ||
562 | if (NULL != connection->read_task) | ||
563 | { | ||
564 | /* send errors trigger read errors... */ | ||
565 | GNUNET_SCHEDULER_cancel (connection->read_task); | ||
566 | connection->read_task = NULL; | ||
567 | signal_receive_timeout (connection); | ||
568 | return; | ||
569 | } | ||
570 | if (NULL == connection->nth.notify_ready) | ||
571 | return; /* nobody to tell about it */ | ||
572 | notify = connection->nth.notify_ready; | ||
573 | connection->nth.notify_ready = NULL; | ||
574 | notify (connection->nth.notify_ready_cls, | ||
575 | 0, | ||
576 | NULL); | ||
577 | } | ||
578 | |||
579 | |||
580 | /** | ||
581 | * We've failed for good to establish a connection (timeout or | ||
582 | * no more addresses to try). | ||
583 | * | ||
584 | * @param connection the connection we tried to establish | ||
585 | */ | ||
586 | static void | ||
587 | connect_fail_continuation (struct GNUNET_CONNECTION_Handle *connection) | ||
588 | { | ||
589 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
590 | "Failed to establish TCP connection to `%s:%u', no further addresses to try.\n", | ||
591 | connection->hostname, | ||
592 | connection->port); | ||
593 | GNUNET_break (NULL == connection->ap_head); | ||
594 | GNUNET_break (NULL == connection->ap_tail); | ||
595 | GNUNET_break (GNUNET_NO == connection->dns_active); | ||
596 | GNUNET_break (NULL == connection->sock); | ||
597 | GNUNET_assert (NULL == connection->write_task); | ||
598 | GNUNET_assert (NULL == connection->proxy_handshake); | ||
599 | |||
600 | /* signal errors for jobs that used to wait on the connection */ | ||
601 | connection->destroy_later = 1; | ||
602 | if (NULL != connection->receiver) | ||
603 | signal_receive_error (connection, | ||
604 | ECONNREFUSED); | ||
605 | if (NULL != connection->nth.notify_ready) | ||
606 | { | ||
607 | GNUNET_assert (NULL != connection->nth.timeout_task); | ||
608 | GNUNET_SCHEDULER_cancel (connection->nth.timeout_task); | ||
609 | connection->nth.timeout_task = NULL; | ||
610 | signal_transmit_error (connection, | ||
611 | ECONNREFUSED); | ||
612 | } | ||
613 | if (-1 == connection->destroy_later) | ||
614 | { | ||
615 | /* do it now */ | ||
616 | connection->destroy_later = 0; | ||
617 | GNUNET_CONNECTION_destroy (connection); | ||
618 | return; | ||
619 | } | ||
620 | connection->destroy_later = 0; | ||
621 | } | ||
622 | |||
623 | |||
624 | /** | ||
625 | * We are ready to transmit (or got a timeout). | ||
626 | * | ||
627 | * @param cls our connection handle | ||
628 | */ | ||
629 | static void | ||
630 | transmit_ready (void *cls); | ||
631 | |||
632 | |||
633 | /** | ||
634 | * This function is called once we either timeout or have data ready | ||
635 | * to read. | ||
636 | * | ||
637 | * @param cls connection to read from | ||
638 | */ | ||
639 | static void | ||
640 | receive_ready (void *cls); | ||
641 | |||
642 | |||
643 | /** | ||
644 | * We've succeeded in establishing a connection. | ||
645 | * | ||
646 | * @param connection the connection we tried to establish | ||
647 | */ | ||
648 | static void | ||
649 | connect_success_continuation (struct GNUNET_CONNECTION_Handle *connection) | ||
650 | { | ||
651 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
652 | "Connection to `%s' succeeded! (%p)\n", | ||
653 | GNUNET_a2s (connection->addr, | ||
654 | connection->addrlen), | ||
655 | connection); | ||
656 | /* trigger jobs that waited for the connection */ | ||
657 | if (NULL != connection->receiver) | ||
658 | { | ||
659 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
660 | "Connection succeeded, starting with receiving data (%p)\n", | ||
661 | connection); | ||
662 | GNUNET_assert (NULL == connection->read_task); | ||
663 | connection->read_task = | ||
664 | GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_absolute_get_remaining | ||
665 | (connection->receive_timeout), | ||
666 | connection->sock, | ||
667 | &receive_ready, connection); | ||
668 | } | ||
669 | if (NULL != connection->nth.notify_ready) | ||
670 | { | ||
671 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
672 | "Connection succeeded, starting with sending data (%p)\n", | ||
673 | connection); | ||
674 | GNUNET_assert (connection->nth.timeout_task != NULL); | ||
675 | GNUNET_SCHEDULER_cancel (connection->nth.timeout_task); | ||
676 | connection->nth.timeout_task = NULL; | ||
677 | GNUNET_assert (connection->write_task == NULL); | ||
678 | connection->write_task = | ||
679 | GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_absolute_get_remaining | ||
680 | (connection->nth.transmit_timeout), connection->sock, | ||
681 | &transmit_ready, connection); | ||
682 | } | ||
683 | } | ||
684 | |||
685 | |||
686 | /** | ||
687 | * Scheduler let us know that we're either ready to write on the | ||
688 | * socket OR connect timed out. Do the right thing. | ||
689 | * | ||
690 | * @param cls the `struct AddressProbe *` with the address that we are probing | ||
691 | */ | ||
692 | static void | ||
693 | connect_probe_continuation (void *cls) | ||
694 | { | ||
695 | struct AddressProbe *ap = cls; | ||
696 | struct GNUNET_CONNECTION_Handle *connection = ap->connection; | ||
697 | const struct GNUNET_SCHEDULER_TaskContext *tc; | ||
698 | struct AddressProbe *pos; | ||
699 | int error; | ||
700 | socklen_t len; | ||
701 | |||
702 | GNUNET_assert (NULL != ap->sock); | ||
703 | GNUNET_CONTAINER_DLL_remove (connection->ap_head, | ||
704 | connection->ap_tail, | ||
705 | ap); | ||
706 | len = sizeof (error); | ||
707 | errno = 0; | ||
708 | error = 0; | ||
709 | tc = GNUNET_SCHEDULER_get_task_context (); | ||
710 | if ( (0 == (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) || | ||
711 | (GNUNET_OK != | ||
712 | GNUNET_NETWORK_socket_getsockopt (ap->sock, | ||
713 | SOL_SOCKET, | ||
714 | SO_ERROR, | ||
715 | &error, | ||
716 | &len)) || | ||
717 | (0 != error) ) | ||
718 | { | ||
719 | GNUNET_break (GNUNET_OK == | ||
720 | GNUNET_NETWORK_socket_close (ap->sock)); | ||
721 | GNUNET_free (ap); | ||
722 | if ( (NULL == connection->ap_head) && | ||
723 | (GNUNET_NO == connection->dns_active) && | ||
724 | (NULL == connection->proxy_handshake) ) | ||
725 | connect_fail_continuation (connection); | ||
726 | return; | ||
727 | } | ||
728 | GNUNET_assert (NULL == connection->sock); | ||
729 | connection->sock = ap->sock; | ||
730 | GNUNET_assert (NULL == connection->addr); | ||
731 | connection->addr = GNUNET_malloc (ap->addrlen); | ||
732 | GNUNET_memcpy (connection->addr, ap->addr, ap->addrlen); | ||
733 | connection->addrlen = ap->addrlen; | ||
734 | GNUNET_free (ap); | ||
735 | /* cancel all other attempts */ | ||
736 | while (NULL != (pos = connection->ap_head)) | ||
737 | { | ||
738 | GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (pos->sock)); | ||
739 | GNUNET_SCHEDULER_cancel (pos->task); | ||
740 | GNUNET_CONTAINER_DLL_remove (connection->ap_head, | ||
741 | connection->ap_tail, | ||
742 | pos); | ||
743 | GNUNET_free (pos); | ||
744 | } | ||
745 | connect_success_continuation (connection); | ||
746 | } | ||
747 | |||
748 | |||
749 | /** | ||
750 | * Try to establish a connection given the specified address. | ||
751 | * This function is called by the resolver once we have a DNS reply. | ||
752 | * | ||
753 | * @param cls our `struct GNUNET_CONNECTION_Handle *` | ||
754 | * @param addr address to try, NULL for "last call" | ||
755 | * @param addrlen length of @a addr | ||
756 | */ | ||
757 | static void | ||
758 | try_connect_using_address (void *cls, | ||
759 | const struct sockaddr *addr, | ||
760 | socklen_t addrlen) | ||
761 | { | ||
762 | struct GNUNET_CONNECTION_Handle *connection = cls; | ||
763 | struct AddressProbe *ap; | ||
764 | struct GNUNET_TIME_Relative delay; | ||
765 | |||
766 | if (NULL == addr) | ||
767 | { | ||
768 | connection->dns_active = NULL; | ||
769 | if ((NULL == connection->ap_head) && | ||
770 | (NULL == connection->sock) && | ||
771 | (NULL == connection->proxy_handshake)) | ||
772 | connect_fail_continuation (connection); | ||
773 | return; | ||
774 | } | ||
775 | if (NULL != connection->sock) | ||
776 | return; /* already connected */ | ||
777 | GNUNET_assert (NULL == connection->addr); | ||
778 | /* try to connect */ | ||
779 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
780 | "Trying to connect using address `%s:%u/%s:%u'\n", | ||
781 | connection->hostname, | ||
782 | connection->port, | ||
783 | GNUNET_a2s (addr, addrlen), | ||
784 | connection->port); | ||
785 | ap = GNUNET_malloc (sizeof (struct AddressProbe) + addrlen); | ||
786 | ap->addr = (const struct sockaddr *) &ap[1]; | ||
787 | GNUNET_memcpy (&ap[1], addr, addrlen); | ||
788 | ap->addrlen = addrlen; | ||
789 | ap->connection = connection; | ||
790 | |||
791 | switch (ap->addr->sa_family) | ||
792 | { | ||
793 | case AF_INET: | ||
794 | ((struct sockaddr_in *) ap->addr)->sin_port = htons (connection->port); | ||
795 | break; | ||
796 | case AF_INET6: | ||
797 | ((struct sockaddr_in6 *) ap->addr)->sin6_port = htons (connection->port); | ||
798 | break; | ||
799 | default: | ||
800 | GNUNET_break (0); | ||
801 | GNUNET_free (ap); | ||
802 | return; /* not supported by us */ | ||
803 | } | ||
804 | ap->sock = GNUNET_NETWORK_socket_create (ap->addr->sa_family, | ||
805 | SOCK_STREAM, 0); | ||
806 | if (NULL == ap->sock) | ||
807 | { | ||
808 | GNUNET_free (ap); | ||
809 | return; /* not supported by OS */ | ||
810 | } | ||
811 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
812 | "Trying to connect to `%s' (%p)\n", | ||
813 | GNUNET_a2s (ap->addr, ap->addrlen), | ||
814 | connection); | ||
815 | if ((GNUNET_OK != | ||
816 | GNUNET_NETWORK_socket_connect (ap->sock, | ||
817 | ap->addr, | ||
818 | ap->addrlen)) && | ||
819 | (EINPROGRESS != errno)) | ||
820 | { | ||
821 | /* maybe refused / unsupported address, try next */ | ||
822 | LOG_STRERROR (GNUNET_ERROR_TYPE_INFO, "connect"); | ||
823 | GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (ap->sock)); | ||
824 | GNUNET_free (ap); | ||
825 | return; | ||
826 | } | ||
827 | GNUNET_CONTAINER_DLL_insert (connection->ap_head, connection->ap_tail, ap); | ||
828 | delay = GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT; | ||
829 | if (NULL != connection->nth.notify_ready) | ||
830 | delay = GNUNET_TIME_relative_min (delay, | ||
831 | GNUNET_TIME_absolute_get_remaining (connection->nth.transmit_timeout)); | ||
832 | if (NULL != connection->receiver) | ||
833 | delay = GNUNET_TIME_relative_min (delay, | ||
834 | GNUNET_TIME_absolute_get_remaining (connection->receive_timeout)); | ||
835 | ap->task = GNUNET_SCHEDULER_add_write_net (delay, | ||
836 | ap->sock, | ||
837 | &connect_probe_continuation, | ||
838 | ap); | ||
839 | } | ||
840 | |||
841 | |||
842 | /** | ||
843 | * Create a connection handle by (asynchronously) connecting to a host. | ||
844 | * This function returns immediately, even if the connection has not | ||
845 | * yet been established. This function only creates TCP connections. | ||
846 | * | ||
847 | * @param cfg configuration to use | ||
848 | * @param hostname name of the host to connect to | ||
849 | * @param port port to connect to | ||
850 | * @return the connection handle | ||
851 | */ | ||
852 | struct GNUNET_CONNECTION_Handle * | ||
853 | GNUNET_CONNECTION_create_from_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
854 | const char *hostname, | ||
855 | uint16_t port) | ||
856 | { | ||
857 | struct GNUNET_CONNECTION_Handle *connection; | ||
858 | |||
859 | GNUNET_assert (0 < strlen (hostname)); /* sanity check */ | ||
860 | connection = GNUNET_new (struct GNUNET_CONNECTION_Handle); | ||
861 | connection->cfg = cfg; | ||
862 | connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE; | ||
863 | connection->write_buffer = GNUNET_malloc (connection->write_buffer_size); | ||
864 | connection->port = port; | ||
865 | connection->hostname = GNUNET_strdup (hostname); | ||
866 | connection->dns_active = | ||
867 | GNUNET_RESOLVER_ip_get (connection->hostname, | ||
868 | AF_UNSPEC, | ||
869 | GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT, | ||
870 | &try_connect_using_address, | ||
871 | connection); | ||
872 | return connection; | ||
873 | } | ||
874 | |||
875 | |||
876 | /** | ||
877 | * Create a connection handle by connecting to a UNIX domain service. | ||
878 | * This function returns immediately, even if the connection has not | ||
879 | * yet been established. This function only creates UNIX connections. | ||
880 | * | ||
881 | * @param cfg configuration to use | ||
882 | * @param unixpath path to connect to | ||
883 | * @return the connection handle, NULL on systems without UNIX support | ||
884 | */ | ||
885 | struct GNUNET_CONNECTION_Handle * | ||
886 | GNUNET_CONNECTION_create_from_connect_to_unixpath (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
887 | const char *unixpath) | ||
888 | { | ||
889 | #ifdef AF_UNIX | ||
890 | struct GNUNET_CONNECTION_Handle *connection; | ||
891 | struct sockaddr_un *un; | ||
892 | |||
893 | GNUNET_assert (0 < strlen (unixpath)); /* sanity check */ | ||
894 | un = GNUNET_new (struct sockaddr_un); | ||
895 | un->sun_family = AF_UNIX; | ||
896 | strncpy (un->sun_path, unixpath, sizeof (un->sun_path) - 1); | ||
897 | #ifdef LINUX | ||
898 | { | ||
899 | int abstract; | ||
900 | |||
901 | abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg, | ||
902 | "TESTING", | ||
903 | "USE_ABSTRACT_SOCKETS"); | ||
904 | if (GNUNET_YES == abstract) | ||
905 | un->sun_path[0] = '\0'; | ||
906 | } | ||
907 | #endif | ||
908 | #if HAVE_SOCKADDR_UN_SUN_LEN | ||
909 | un->sun_len = (u_char) sizeof (struct sockaddr_un); | ||
910 | #endif | ||
911 | connection = GNUNET_new (struct GNUNET_CONNECTION_Handle); | ||
912 | connection->cfg = cfg; | ||
913 | connection->write_buffer_size = GNUNET_SERVER_MIN_BUFFER_SIZE; | ||
914 | connection->write_buffer = GNUNET_malloc (connection->write_buffer_size); | ||
915 | connection->port = 0; | ||
916 | connection->hostname = NULL; | ||
917 | connection->addr = (struct sockaddr *) un; | ||
918 | connection->addrlen = sizeof (struct sockaddr_un); | ||
919 | connection->sock = GNUNET_NETWORK_socket_create (AF_UNIX, | ||
920 | SOCK_STREAM, | ||
921 | 0); | ||
922 | if (NULL == connection->sock) | ||
923 | { | ||
924 | GNUNET_free (connection->addr); | ||
925 | GNUNET_free (connection->write_buffer); | ||
926 | GNUNET_free (connection); | ||
927 | return NULL; | ||
928 | } | ||
929 | if ( (GNUNET_OK != | ||
930 | GNUNET_NETWORK_socket_connect (connection->sock, | ||
931 | connection->addr, | ||
932 | connection->addrlen)) && | ||
933 | (EINPROGRESS != errno) ) | ||
934 | { | ||
935 | /* Just return; we expect everything to work eventually so don't fail HARD */ | ||
936 | GNUNET_break (GNUNET_OK == | ||
937 | GNUNET_NETWORK_socket_close (connection->sock)); | ||
938 | connection->sock = NULL; | ||
939 | return connection; | ||
940 | } | ||
941 | connect_success_continuation (connection); | ||
942 | return connection; | ||
943 | #else | ||
944 | return NULL; | ||
945 | #endif | ||
946 | } | ||
947 | |||
948 | |||
949 | /** | ||
950 | * Create a connection handle by (asynchronously) connecting to a host. | ||
951 | * This function returns immediately, even if the connection has not | ||
952 | * yet been established. This function only creates TCP connections. | ||
953 | * | ||
954 | * @param s socket to connect | ||
955 | * @param serv_addr server address | ||
956 | * @param addrlen length of @a serv_addr | ||
957 | * @return the connection handle | ||
958 | */ | ||
959 | struct GNUNET_CONNECTION_Handle * | ||
960 | GNUNET_CONNECTION_connect_socket (struct GNUNET_NETWORK_Handle *s, | ||
961 | const struct sockaddr *serv_addr, | ||
962 | socklen_t addrlen) | ||
963 | { | ||
964 | struct GNUNET_CONNECTION_Handle *connection; | ||
965 | |||
966 | if ( (GNUNET_OK != | ||
967 | GNUNET_NETWORK_socket_connect (s, serv_addr, addrlen)) && | ||
968 | (EINPROGRESS != errno) ) | ||
969 | { | ||
970 | /* maybe refused / unsupported address, try next */ | ||
971 | LOG_STRERROR (GNUNET_ERROR_TYPE_DEBUG, | ||
972 | "connect"); | ||
973 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
974 | "Attempt to connect to `%s' failed\n", | ||
975 | GNUNET_a2s (serv_addr, | ||
976 | addrlen)); | ||
977 | GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (s)); | ||
978 | return NULL; | ||
979 | } | ||
980 | connection = GNUNET_CONNECTION_create_from_existing (s); | ||
981 | connection->addr = GNUNET_malloc (addrlen); | ||
982 | GNUNET_memcpy (connection->addr, serv_addr, addrlen); | ||
983 | connection->addrlen = addrlen; | ||
984 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
985 | "Trying to connect to `%s' (%p)\n", | ||
986 | GNUNET_a2s (serv_addr, addrlen), | ||
987 | connection); | ||
988 | return connection; | ||
989 | } | ||
990 | |||
991 | |||
992 | /** | ||
993 | * Create a connection handle by creating a socket and | ||
994 | * (asynchronously) connecting to a host. This function returns | ||
995 | * immediately, even if the connection has not yet been established. | ||
996 | * This function only creates TCP connections. | ||
997 | * | ||
998 | * @param af_family address family to use | ||
999 | * @param serv_addr server address | ||
1000 | * @param addrlen length of @a serv_addr | ||
1001 | * @return the connection handle | ||
1002 | */ | ||
1003 | struct GNUNET_CONNECTION_Handle * | ||
1004 | GNUNET_CONNECTION_create_from_sockaddr (int af_family, | ||
1005 | const struct sockaddr *serv_addr, | ||
1006 | socklen_t addrlen) | ||
1007 | { | ||
1008 | struct GNUNET_NETWORK_Handle *s; | ||
1009 | |||
1010 | s = GNUNET_NETWORK_socket_create (af_family, SOCK_STREAM, 0); | ||
1011 | if (NULL == s) | ||
1012 | { | ||
1013 | LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING | GNUNET_ERROR_TYPE_BULK, | ||
1014 | "socket"); | ||
1015 | return NULL; | ||
1016 | } | ||
1017 | return GNUNET_CONNECTION_connect_socket (s, | ||
1018 | serv_addr, | ||
1019 | addrlen); | ||
1020 | } | ||
1021 | |||
1022 | |||
1023 | /** | ||
1024 | * Check if connection is valid (no fatal errors have happened so far). | ||
1025 | * Note that a connection that is still trying to connect is considered | ||
1026 | * valid. | ||
1027 | * | ||
1028 | * @param connection connection to check | ||
1029 | * @return #GNUNET_YES if valid, #GNUNET_NO otherwise | ||
1030 | */ | ||
1031 | int | ||
1032 | GNUNET_CONNECTION_check (struct GNUNET_CONNECTION_Handle *connection) | ||
1033 | { | ||
1034 | if ((NULL != connection->ap_head) || | ||
1035 | (NULL != connection->dns_active) || | ||
1036 | (NULL != connection->proxy_handshake)) | ||
1037 | return GNUNET_YES; /* still trying to connect */ | ||
1038 | if ( (0 != connection->destroy_later) || | ||
1039 | (NULL == connection->sock) ) | ||
1040 | return GNUNET_NO; | ||
1041 | return GNUNET_YES; | ||
1042 | } | ||
1043 | |||
1044 | |||
1045 | /** | ||
1046 | * Close the connection and free associated resources. There must | ||
1047 | * not be any pending requests for reading or writing to the | ||
1048 | * connection at this time. | ||
1049 | * | ||
1050 | * @param connection connection to destroy | ||
1051 | */ | ||
1052 | void | ||
1053 | GNUNET_CONNECTION_destroy (struct GNUNET_CONNECTION_Handle *connection) | ||
1054 | { | ||
1055 | struct AddressProbe *pos; | ||
1056 | |||
1057 | if (0 != connection->destroy_later) | ||
1058 | { | ||
1059 | connection->destroy_later = -1; | ||
1060 | return; | ||
1061 | } | ||
1062 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1063 | "Shutting down connection (%p)\n", | ||
1064 | connection); | ||
1065 | GNUNET_assert (NULL == connection->nth.notify_ready); | ||
1066 | GNUNET_assert (NULL == connection->receiver); | ||
1067 | if (NULL != connection->write_task) | ||
1068 | { | ||
1069 | GNUNET_SCHEDULER_cancel (connection->write_task); | ||
1070 | connection->write_task = NULL; | ||
1071 | connection->write_buffer_off = 0; | ||
1072 | } | ||
1073 | if (NULL != connection->read_task) | ||
1074 | { | ||
1075 | GNUNET_SCHEDULER_cancel (connection->read_task); | ||
1076 | connection->read_task = NULL; | ||
1077 | } | ||
1078 | if (NULL != connection->nth.timeout_task) | ||
1079 | { | ||
1080 | GNUNET_SCHEDULER_cancel (connection->nth.timeout_task); | ||
1081 | connection->nth.timeout_task = NULL; | ||
1082 | } | ||
1083 | connection->nth.notify_ready = NULL; | ||
1084 | if (NULL != connection->dns_active) | ||
1085 | { | ||
1086 | GNUNET_RESOLVER_request_cancel (connection->dns_active); | ||
1087 | connection->dns_active = NULL; | ||
1088 | } | ||
1089 | if (NULL != connection->proxy_handshake) | ||
1090 | { | ||
1091 | /* GNUNET_CONNECTION_destroy (connection->proxy_handshake); */ | ||
1092 | connection->proxy_handshake->destroy_later = -1; | ||
1093 | connection->proxy_handshake = NULL; /* Not leaked ??? */ | ||
1094 | } | ||
1095 | while (NULL != (pos = connection->ap_head)) | ||
1096 | { | ||
1097 | GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (pos->sock)); | ||
1098 | GNUNET_SCHEDULER_cancel (pos->task); | ||
1099 | GNUNET_CONTAINER_DLL_remove (connection->ap_head, | ||
1100 | connection->ap_tail, | ||
1101 | pos); | ||
1102 | GNUNET_free (pos); | ||
1103 | } | ||
1104 | if ( (NULL != connection->sock) && | ||
1105 | (GNUNET_YES != connection->persist) ) | ||
1106 | { | ||
1107 | if ((GNUNET_OK != | ||
1108 | GNUNET_NETWORK_socket_shutdown (connection->sock, | ||
1109 | SHUT_RDWR)) && | ||
1110 | (ENOTCONN != errno) && | ||
1111 | (ECONNRESET != errno) ) | ||
1112 | LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, | ||
1113 | "shutdown"); | ||
1114 | } | ||
1115 | if (NULL != connection->sock) | ||
1116 | { | ||
1117 | if (GNUNET_YES != connection->persist) | ||
1118 | { | ||
1119 | GNUNET_break (GNUNET_OK == | ||
1120 | GNUNET_NETWORK_socket_close (connection->sock)); | ||
1121 | } | ||
1122 | else | ||
1123 | { | ||
1124 | GNUNET_NETWORK_socket_free_memory_only_ (connection->sock); /* at least no memory leak (we deliberately | ||
1125 | * leak the socket in this special case) ... */ | ||
1126 | } | ||
1127 | } | ||
1128 | GNUNET_free_non_null (connection->addr); | ||
1129 | GNUNET_free_non_null (connection->hostname); | ||
1130 | GNUNET_free (connection->write_buffer); | ||
1131 | GNUNET_free (connection); | ||
1132 | } | ||
1133 | |||
1134 | |||
1135 | /** | ||
1136 | * This function is called once we either timeout | ||
1137 | * or have data ready to read. | ||
1138 | * | ||
1139 | * @param cls connection to read from | ||
1140 | */ | ||
1141 | static void | ||
1142 | receive_ready (void *cls) | ||
1143 | { | ||
1144 | struct GNUNET_CONNECTION_Handle *connection = cls; | ||
1145 | const struct GNUNET_SCHEDULER_TaskContext *tc; | ||
1146 | char buffer[connection->max]; | ||
1147 | ssize_t ret; | ||
1148 | GNUNET_CONNECTION_Receiver receiver; | ||
1149 | |||
1150 | connection->read_task = NULL; | ||
1151 | tc = GNUNET_SCHEDULER_get_task_context (); | ||
1152 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT)) | ||
1153 | { | ||
1154 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1155 | "Receive from `%s' encounters error: timeout (%s, %p)\n", | ||
1156 | GNUNET_a2s (connection->addr, | ||
1157 | connection->addrlen), | ||
1158 | GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (connection->receive_timeout), | ||
1159 | GNUNET_YES), | ||
1160 | connection); | ||
1161 | signal_receive_timeout (connection); | ||
1162 | return; | ||
1163 | } | ||
1164 | if (NULL == connection->sock) | ||
1165 | { | ||
1166 | /* connect failed for good */ | ||
1167 | signal_receive_error (connection, ECONNREFUSED); | ||
1168 | return; | ||
1169 | } | ||
1170 | GNUNET_assert (GNUNET_NETWORK_fdset_isset (tc->read_ready, | ||
1171 | connection->sock)); | ||
1172 | RETRY: | ||
1173 | ret = GNUNET_NETWORK_socket_recv (connection->sock, | ||
1174 | buffer, | ||
1175 | connection->max); | ||
1176 | if (-1 == ret) | ||
1177 | { | ||
1178 | if (EINTR == errno) | ||
1179 | goto RETRY; | ||
1180 | signal_receive_error (connection, errno); | ||
1181 | return; | ||
1182 | } | ||
1183 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1184 | "receive_ready read %u/%u bytes from `%s' (%p)!\n", | ||
1185 | (unsigned int) ret, | ||
1186 | connection->max, | ||
1187 | GNUNET_a2s (connection->addr, | ||
1188 | connection->addrlen), | ||
1189 | connection); | ||
1190 | GNUNET_assert (NULL != (receiver = connection->receiver)); | ||
1191 | connection->receiver = NULL; | ||
1192 | receiver (connection->receiver_cls, | ||
1193 | buffer, | ||
1194 | ret, | ||
1195 | connection->addr, | ||
1196 | connection->addrlen, | ||
1197 | 0); | ||
1198 | } | ||
1199 | |||
1200 | |||
1201 | /** | ||
1202 | * Receive data from the given connection. Note that this function | ||
1203 | * will call @a receiver asynchronously using the scheduler. It will | ||
1204 | * "immediately" return. Note that there MUST only be one active | ||
1205 | * receive call per connection at any given point in time (so do not | ||
1206 | * call receive again until the receiver callback has been invoked). | ||
1207 | * | ||
1208 | * @param connection connection handle | ||
1209 | * @param max maximum number of bytes to read | ||
1210 | * @param timeout maximum amount of time to wait | ||
1211 | * @param receiver function to call with received data | ||
1212 | * @param receiver_cls closure for @a receiver | ||
1213 | */ | ||
1214 | void | ||
1215 | GNUNET_CONNECTION_receive (struct GNUNET_CONNECTION_Handle *connection, | ||
1216 | size_t max, | ||
1217 | struct GNUNET_TIME_Relative timeout, | ||
1218 | GNUNET_CONNECTION_Receiver receiver, | ||
1219 | void *receiver_cls) | ||
1220 | { | ||
1221 | GNUNET_assert ((NULL == connection->read_task) && | ||
1222 | (NULL == connection->receiver)); | ||
1223 | GNUNET_assert (NULL != receiver); | ||
1224 | connection->receiver = receiver; | ||
1225 | connection->receiver_cls = receiver_cls; | ||
1226 | connection->receive_timeout = GNUNET_TIME_relative_to_absolute (timeout); | ||
1227 | connection->max = max; | ||
1228 | if (NULL != connection->sock) | ||
1229 | { | ||
1230 | connection->read_task = | ||
1231 | GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_absolute_get_remaining | ||
1232 | (connection->receive_timeout), | ||
1233 | connection->sock, | ||
1234 | &receive_ready, | ||
1235 | connection); | ||
1236 | return; | ||
1237 | } | ||
1238 | if ((NULL == connection->dns_active) && | ||
1239 | (NULL == connection->ap_head) && | ||
1240 | (NULL == connection->proxy_handshake)) | ||
1241 | { | ||
1242 | connection->receiver = NULL; | ||
1243 | receiver (receiver_cls, | ||
1244 | NULL, 0, | ||
1245 | NULL, 0, | ||
1246 | ETIMEDOUT); | ||
1247 | return; | ||
1248 | } | ||
1249 | } | ||
1250 | |||
1251 | |||
1252 | /** | ||
1253 | * Cancel receive job on the given connection. Note that the | ||
1254 | * receiver callback must not have been called yet in order | ||
1255 | * for the cancellation to be valid. | ||
1256 | * | ||
1257 | * @param connection connection handle | ||
1258 | * @return closure of the original receiver callback closure | ||
1259 | */ | ||
1260 | void * | ||
1261 | GNUNET_CONNECTION_receive_cancel (struct GNUNET_CONNECTION_Handle *connection) | ||
1262 | { | ||
1263 | if (NULL != connection->read_task) | ||
1264 | { | ||
1265 | GNUNET_assert (connection == | ||
1266 | GNUNET_SCHEDULER_cancel (connection->read_task)); | ||
1267 | connection->read_task = NULL; | ||
1268 | } | ||
1269 | connection->receiver = NULL; | ||
1270 | return connection->receiver_cls; | ||
1271 | } | ||
1272 | |||
1273 | |||
1274 | /** | ||
1275 | * Try to call the transmit notify method (check if we do | ||
1276 | * have enough space available first)! | ||
1277 | * | ||
1278 | * @param connection connection for which we should do this processing | ||
1279 | * @return #GNUNET_YES if we were able to call notify | ||
1280 | */ | ||
1281 | static int | ||
1282 | process_notify (struct GNUNET_CONNECTION_Handle *connection) | ||
1283 | { | ||
1284 | size_t used; | ||
1285 | size_t avail; | ||
1286 | size_t size; | ||
1287 | GNUNET_CONNECTION_TransmitReadyNotify notify; | ||
1288 | |||
1289 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1290 | "process_notify is running\n"); | ||
1291 | GNUNET_assert (NULL == connection->write_task); | ||
1292 | if (NULL == (notify = connection->nth.notify_ready)) | ||
1293 | { | ||
1294 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1295 | "No one to notify\n"); | ||
1296 | return GNUNET_NO; | ||
1297 | } | ||
1298 | used = connection->write_buffer_off - connection->write_buffer_pos; | ||
1299 | avail = connection->write_buffer_size - used; | ||
1300 | size = connection->nth.notify_size; | ||
1301 | if (size > avail) | ||
1302 | { | ||
1303 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1304 | "Not enough buffer\n"); | ||
1305 | return GNUNET_NO; | ||
1306 | } | ||
1307 | connection->nth.notify_ready = NULL; | ||
1308 | if (connection->write_buffer_size - connection->write_buffer_off < size) | ||
1309 | { | ||
1310 | /* need to compact */ | ||
1311 | memmove (connection->write_buffer, | ||
1312 | &connection->write_buffer[connection->write_buffer_pos], | ||
1313 | used); | ||
1314 | connection->write_buffer_off -= connection->write_buffer_pos; | ||
1315 | connection->write_buffer_pos = 0; | ||
1316 | } | ||
1317 | avail = connection->write_buffer_size - connection->write_buffer_off; | ||
1318 | GNUNET_assert (avail >= size); | ||
1319 | size = | ||
1320 | notify (connection->nth.notify_ready_cls, avail, | ||
1321 | &connection->write_buffer[connection->write_buffer_off]); | ||
1322 | GNUNET_assert (size <= avail); | ||
1323 | if (0 != size) | ||
1324 | connection->write_buffer_off += size; | ||
1325 | return GNUNET_YES; | ||
1326 | } | ||
1327 | |||
1328 | |||
1329 | /** | ||
1330 | * Task invoked by the scheduler when a call to transmit | ||
1331 | * is timing out (we never got enough buffer space to call | ||
1332 | * the callback function before the specified timeout | ||
1333 | * expired). | ||
1334 | * | ||
1335 | * This task notifies the client about the timeout. | ||
1336 | * | ||
1337 | * @param cls the `struct GNUNET_CONNECTION_Handle` | ||
1338 | */ | ||
1339 | static void | ||
1340 | transmit_timeout (void *cls) | ||
1341 | { | ||
1342 | struct GNUNET_CONNECTION_Handle *connection = cls; | ||
1343 | GNUNET_CONNECTION_TransmitReadyNotify notify; | ||
1344 | |||
1345 | connection->nth.timeout_task = NULL; | ||
1346 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1347 | "Transmit to `%s:%u/%s' fails, time out reached (%p).\n", | ||
1348 | connection->hostname, | ||
1349 | connection->port, | ||
1350 | GNUNET_a2s (connection->addr, | ||
1351 | connection->addrlen), | ||
1352 | connection); | ||
1353 | notify = connection->nth.notify_ready; | ||
1354 | GNUNET_assert (NULL != notify); | ||
1355 | connection->nth.notify_ready = NULL; | ||
1356 | notify (connection->nth.notify_ready_cls, | ||
1357 | 0, | ||
1358 | NULL); | ||
1359 | } | ||
1360 | |||
1361 | |||
1362 | /** | ||
1363 | * Task invoked by the scheduler when we failed to connect | ||
1364 | * at the time of being asked to transmit. | ||
1365 | * | ||
1366 | * This task notifies the client about the error. | ||
1367 | * | ||
1368 | * @param cls the `struct GNUNET_CONNECTION_Handle` | ||
1369 | */ | ||
1370 | static void | ||
1371 | connect_error (void *cls) | ||
1372 | { | ||
1373 | struct GNUNET_CONNECTION_Handle *connection = cls; | ||
1374 | GNUNET_CONNECTION_TransmitReadyNotify notify; | ||
1375 | |||
1376 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1377 | "Transmission request of size %u fails (%s/%u), connection failed (%p).\n", | ||
1378 | connection->nth.notify_size, | ||
1379 | connection->hostname, | ||
1380 | connection->port, | ||
1381 | connection); | ||
1382 | connection->write_task = NULL; | ||
1383 | notify = connection->nth.notify_ready; | ||
1384 | connection->nth.notify_ready = NULL; | ||
1385 | notify (connection->nth.notify_ready_cls, | ||
1386 | 0, | ||
1387 | NULL); | ||
1388 | } | ||
1389 | |||
1390 | |||
1391 | /** | ||
1392 | * We are ready to transmit (or got a timeout). | ||
1393 | * | ||
1394 | * @param cls our connection handle | ||
1395 | */ | ||
1396 | static void | ||
1397 | transmit_ready (void *cls) | ||
1398 | { | ||
1399 | struct GNUNET_CONNECTION_Handle *connection = cls; | ||
1400 | GNUNET_CONNECTION_TransmitReadyNotify notify; | ||
1401 | const struct GNUNET_SCHEDULER_TaskContext *tc; | ||
1402 | ssize_t ret; | ||
1403 | size_t have; | ||
1404 | |||
1405 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1406 | "transmit_ready running (%p).\n", | ||
1407 | connection); | ||
1408 | GNUNET_assert (NULL != connection->write_task); | ||
1409 | connection->write_task = NULL; | ||
1410 | GNUNET_assert (NULL == connection->nth.timeout_task); | ||
1411 | tc = GNUNET_SCHEDULER_get_task_context (); | ||
1412 | if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_TIMEOUT)) | ||
1413 | { | ||
1414 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1415 | "Transmit to `%s' fails, time out reached (%p).\n", | ||
1416 | GNUNET_a2s (connection->addr, | ||
1417 | connection->addrlen), | ||
1418 | connection); | ||
1419 | notify = connection->nth.notify_ready; | ||
1420 | GNUNET_assert (NULL != notify); | ||
1421 | connection->nth.notify_ready = NULL; | ||
1422 | notify (connection->nth.notify_ready_cls, 0, NULL); | ||
1423 | return; | ||
1424 | } | ||
1425 | GNUNET_assert (NULL != connection->sock); | ||
1426 | if (NULL == tc->write_ready) | ||
1427 | { | ||
1428 | /* special circumstances (in particular, PREREQ_DONE after | ||
1429 | * connect): not yet ready to write, but no "fatal" error either. | ||
1430 | * Hence retry. */ | ||
1431 | goto SCHEDULE_WRITE; | ||
1432 | } | ||
1433 | if (! GNUNET_NETWORK_fdset_isset (tc->write_ready, | ||
1434 | connection->sock)) | ||
1435 | { | ||
1436 | GNUNET_assert (NULL == connection->write_task); | ||
1437 | /* special circumstances (in particular, shutdown): not yet ready | ||
1438 | * to write, but no "fatal" error either. Hence retry. */ | ||
1439 | goto SCHEDULE_WRITE; | ||
1440 | } | ||
1441 | GNUNET_assert (connection->write_buffer_off >= connection->write_buffer_pos); | ||
1442 | if ((NULL != connection->nth.notify_ready) && | ||
1443 | (connection->write_buffer_size < connection->nth.notify_size)) | ||
1444 | { | ||
1445 | connection->write_buffer = | ||
1446 | GNUNET_realloc (connection->write_buffer, connection->nth.notify_size); | ||
1447 | connection->write_buffer_size = connection->nth.notify_size; | ||
1448 | } | ||
1449 | process_notify (connection); | ||
1450 | have = connection->write_buffer_off - connection->write_buffer_pos; | ||
1451 | if (0 == have) | ||
1452 | { | ||
1453 | /* no data ready for writing, terminate write loop */ | ||
1454 | return; | ||
1455 | } | ||
1456 | GNUNET_assert (have <= connection->write_buffer_size); | ||
1457 | GNUNET_assert (have + connection->write_buffer_pos <= connection->write_buffer_size); | ||
1458 | GNUNET_assert (connection->write_buffer_pos <= connection->write_buffer_size); | ||
1459 | RETRY: | ||
1460 | ret = | ||
1461 | GNUNET_NETWORK_socket_send (connection->sock, | ||
1462 | &connection->write_buffer[connection->write_buffer_pos], | ||
1463 | have); | ||
1464 | if (-1 == ret) | ||
1465 | { | ||
1466 | if (EINTR == errno) | ||
1467 | goto RETRY; | ||
1468 | if (NULL != connection->write_task) | ||
1469 | { | ||
1470 | GNUNET_SCHEDULER_cancel (connection->write_task); | ||
1471 | connection->write_task = NULL; | ||
1472 | } | ||
1473 | signal_transmit_error (connection, errno); | ||
1474 | return; | ||
1475 | } | ||
1476 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1477 | "Connection transmitted %u/%u bytes to `%s' (%p)\n", | ||
1478 | (unsigned int) ret, | ||
1479 | have, | ||
1480 | GNUNET_a2s (connection->addr, | ||
1481 | connection->addrlen), | ||
1482 | connection); | ||
1483 | connection->write_buffer_pos += ret; | ||
1484 | if (connection->write_buffer_pos == connection->write_buffer_off) | ||
1485 | { | ||
1486 | /* transmitted all pending data */ | ||
1487 | connection->write_buffer_pos = 0; | ||
1488 | connection->write_buffer_off = 0; | ||
1489 | } | ||
1490 | if ( (0 == connection->write_buffer_off) && | ||
1491 | (NULL == connection->nth.notify_ready) ) | ||
1492 | return; /* all data sent! */ | ||
1493 | /* not done writing, schedule more */ | ||
1494 | SCHEDULE_WRITE: | ||
1495 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1496 | "Re-scheduling transmit_ready (more to do) (%p).\n", | ||
1497 | connection); | ||
1498 | have = connection->write_buffer_off - connection->write_buffer_pos; | ||
1499 | GNUNET_assert ( (NULL != connection->nth.notify_ready) || | ||
1500 | (have > 0) ); | ||
1501 | if (NULL == connection->write_task) | ||
1502 | connection->write_task = | ||
1503 | GNUNET_SCHEDULER_add_write_net ((connection->nth.notify_ready == | ||
1504 | NULL) ? GNUNET_TIME_UNIT_FOREVER_REL : | ||
1505 | GNUNET_TIME_absolute_get_remaining | ||
1506 | (connection->nth.transmit_timeout), | ||
1507 | connection->sock, | ||
1508 | &transmit_ready, connection); | ||
1509 | } | ||
1510 | |||
1511 | |||
1512 | /** | ||
1513 | * Ask the connection to call us once the specified number of bytes | ||
1514 | * are free in the transmission buffer. Will never call the @a notify | ||
1515 | * callback in this task, but always first go into the scheduler. | ||
1516 | * | ||
1517 | * @param connection connection | ||
1518 | * @param size number of bytes to send | ||
1519 | * @param timeout after how long should we give up (and call | ||
1520 | * @a notify with buf NULL and size 0)? | ||
1521 | * @param notify function to call | ||
1522 | * @param notify_cls closure for @a notify | ||
1523 | * @return non-NULL if the notify callback was queued, | ||
1524 | * NULL if we are already going to notify someone else (busy) | ||
1525 | */ | ||
1526 | struct GNUNET_CONNECTION_TransmitHandle * | ||
1527 | GNUNET_CONNECTION_notify_transmit_ready (struct GNUNET_CONNECTION_Handle *connection, | ||
1528 | size_t size, | ||
1529 | struct GNUNET_TIME_Relative timeout, | ||
1530 | GNUNET_CONNECTION_TransmitReadyNotify notify, | ||
1531 | void *notify_cls) | ||
1532 | { | ||
1533 | if (NULL != connection->nth.notify_ready) | ||
1534 | { | ||
1535 | GNUNET_assert (0); | ||
1536 | return NULL; | ||
1537 | } | ||
1538 | GNUNET_assert (NULL != notify); | ||
1539 | GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE); | ||
1540 | GNUNET_assert (connection->write_buffer_off <= connection->write_buffer_size); | ||
1541 | GNUNET_assert (connection->write_buffer_pos <= connection->write_buffer_size); | ||
1542 | GNUNET_assert (connection->write_buffer_pos <= connection->write_buffer_off); | ||
1543 | connection->nth.notify_ready = notify; | ||
1544 | connection->nth.notify_ready_cls = notify_cls; | ||
1545 | connection->nth.connection = connection; | ||
1546 | connection->nth.notify_size = size; | ||
1547 | connection->nth.transmit_timeout = GNUNET_TIME_relative_to_absolute (timeout); | ||
1548 | GNUNET_assert (NULL == connection->nth.timeout_task); | ||
1549 | if ((NULL == connection->sock) && | ||
1550 | (NULL == connection->ap_head) && | ||
1551 | (NULL == connection->dns_active) && | ||
1552 | (NULL == connection->proxy_handshake)) | ||
1553 | { | ||
1554 | if (NULL != connection->write_task) | ||
1555 | GNUNET_SCHEDULER_cancel (connection->write_task); | ||
1556 | connection->write_task = GNUNET_SCHEDULER_add_now (&connect_error, | ||
1557 | connection); | ||
1558 | return &connection->nth; | ||
1559 | } | ||
1560 | if (NULL != connection->write_task) | ||
1561 | return &connection->nth; /* previous transmission still in progress */ | ||
1562 | if (NULL != connection->sock) | ||
1563 | { | ||
1564 | /* connected, try to transmit now */ | ||
1565 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1566 | "Scheduling transmission (%p).\n", | ||
1567 | connection); | ||
1568 | connection->write_task = | ||
1569 | GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_absolute_get_remaining | ||
1570 | (connection->nth.transmit_timeout), | ||
1571 | connection->sock, | ||
1572 | &transmit_ready, connection); | ||
1573 | return &connection->nth; | ||
1574 | } | ||
1575 | /* not yet connected, wait for connection */ | ||
1576 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1577 | "Need to wait to schedule transmission for connection, adding timeout task (%p).\n", | ||
1578 | connection); | ||
1579 | connection->nth.timeout_task = | ||
1580 | GNUNET_SCHEDULER_add_delayed (timeout, | ||
1581 | &transmit_timeout, | ||
1582 | connection); | ||
1583 | return &connection->nth; | ||
1584 | } | ||
1585 | |||
1586 | |||
1587 | /** | ||
1588 | * Cancel the specified transmission-ready notification. | ||
1589 | * | ||
1590 | * @param th notification to cancel | ||
1591 | */ | ||
1592 | void | ||
1593 | GNUNET_CONNECTION_notify_transmit_ready_cancel (struct GNUNET_CONNECTION_TransmitHandle *th) | ||
1594 | { | ||
1595 | GNUNET_assert (NULL != th->notify_ready); | ||
1596 | th->notify_ready = NULL; | ||
1597 | if (NULL != th->timeout_task) | ||
1598 | { | ||
1599 | GNUNET_SCHEDULER_cancel (th->timeout_task); | ||
1600 | th->timeout_task = NULL; | ||
1601 | } | ||
1602 | if (NULL != th->connection->write_task) | ||
1603 | { | ||
1604 | GNUNET_SCHEDULER_cancel (th->connection->write_task); | ||
1605 | th->connection->write_task = NULL; | ||
1606 | } | ||
1607 | } | ||
1608 | |||
1609 | |||
1610 | /** | ||
1611 | * Create a connection to be proxied using a given connection. | ||
1612 | * | ||
1613 | * @param cph connection to proxy server | ||
1614 | * @return connection to be proxied | ||
1615 | */ | ||
1616 | struct GNUNET_CONNECTION_Handle * | ||
1617 | GNUNET_CONNECTION_create_proxied_from_handshake (struct GNUNET_CONNECTION_Handle *cph) | ||
1618 | { | ||
1619 | struct GNUNET_CONNECTION_Handle *proxied = GNUNET_CONNECTION_create_from_existing (NULL); | ||
1620 | |||
1621 | proxied->proxy_handshake = cph; | ||
1622 | return proxied; | ||
1623 | } | ||
1624 | |||
1625 | |||
1626 | /** | ||
1627 | * Activate proxied connection and destroy initial proxy handshake connection. | ||
1628 | * There must not be any pending requests for reading or writing to the | ||
1629 | * proxy hadshake connection at this time. | ||
1630 | * | ||
1631 | * @param proxied connection connection to proxy server | ||
1632 | */ | ||
1633 | void | ||
1634 | GNUNET_CONNECTION_acivate_proxied (struct GNUNET_CONNECTION_Handle *proxied) | ||
1635 | { | ||
1636 | struct GNUNET_CONNECTION_Handle *cph = proxied->proxy_handshake; | ||
1637 | |||
1638 | GNUNET_assert (NULL != cph); | ||
1639 | GNUNET_assert (NULL == proxied->sock); | ||
1640 | GNUNET_assert (NULL != cph->sock); | ||
1641 | proxied->sock = cph->sock; | ||
1642 | cph->sock = NULL; | ||
1643 | GNUNET_CONNECTION_destroy (cph); | ||
1644 | connect_success_continuation (proxied); | ||
1645 | } | ||
1646 | |||
1647 | |||
1648 | /* end of connection.c */ | ||
diff --git a/src/util/disk.c b/src/util/disk.c index d3d5d87dc..d536ec897 100644 --- a/src/util/disk.c +++ b/src/util/disk.c | |||
@@ -329,8 +329,10 @@ GNUNET_DISK_file_get_identifiers (const char *filename, uint64_t * dev, | |||
329 | BY_HANDLE_FILE_INFORMATION info; | 329 | BY_HANDLE_FILE_INFORMATION info; |
330 | int succ; | 330 | int succ; |
331 | 331 | ||
332 | fh = GNUNET_DISK_file_open (filename, GNUNET_DISK_OPEN_READ, 0); | 332 | fh = GNUNET_DISK_file_open (filename, |
333 | if (fh == NULL) | 333 | GNUNET_DISK_OPEN_READ, |
334 | GNUNET_DISK_PERM_NONE); | ||
335 | if (NULL == fh) | ||
334 | return GNUNET_SYSERR; | 336 | return GNUNET_SYSERR; |
335 | succ = GetFileInformationByHandle (fh->h, &info); | 337 | succ = GetFileInformationByHandle (fh->h, &info); |
336 | GNUNET_DISK_file_close (fh); | 338 | GNUNET_DISK_file_close (fh); |
@@ -1191,7 +1193,7 @@ GNUNET_DISK_fn_write (const char *fn, | |||
1191 | fh = GNUNET_DISK_file_open (fn, | 1193 | fh = GNUNET_DISK_file_open (fn, |
1192 | GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_TRUNCATE | 1194 | GNUNET_DISK_OPEN_WRITE | GNUNET_DISK_OPEN_TRUNCATE |
1193 | | GNUNET_DISK_OPEN_CREATE, mode); | 1195 | | GNUNET_DISK_OPEN_CREATE, mode); |
1194 | if (!fh) | 1196 | if (! fh) |
1195 | return GNUNET_SYSERR; | 1197 | return GNUNET_SYSERR; |
1196 | ret = GNUNET_DISK_file_write (fh, buffer, n); | 1198 | ret = GNUNET_DISK_file_write (fh, buffer, n); |
1197 | GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh)); | 1199 | GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fh)); |
@@ -1756,9 +1758,10 @@ GNUNET_DISK_file_open (const char *fn, | |||
1756 | 1758 | ||
1757 | 1759 | ||
1758 | /** | 1760 | /** |
1759 | * Close an open file | 1761 | * Close an open file. |
1762 | * | ||
1760 | * @param h file handle | 1763 | * @param h file handle |
1761 | * @return GNUNET_OK on success, GNUNET_SYSERR otherwise | 1764 | * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise |
1762 | */ | 1765 | */ |
1763 | int | 1766 | int |
1764 | GNUNET_DISK_file_close (struct GNUNET_DISK_FileHandle *h) | 1767 | GNUNET_DISK_file_close (struct GNUNET_DISK_FileHandle *h) |
@@ -1773,7 +1776,7 @@ GNUNET_DISK_file_close (struct GNUNET_DISK_FileHandle *h) | |||
1773 | ret = GNUNET_OK; | 1776 | ret = GNUNET_OK; |
1774 | 1777 | ||
1775 | #if MINGW | 1778 | #if MINGW |
1776 | if (!CloseHandle (h->h)) | 1779 | if (! CloseHandle (h->h)) |
1777 | { | 1780 | { |
1778 | SetErrnoFromWinError (GetLastError ()); | 1781 | SetErrnoFromWinError (GetLastError ()); |
1779 | LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close"); | 1782 | LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close"); |
@@ -1781,7 +1784,7 @@ GNUNET_DISK_file_close (struct GNUNET_DISK_FileHandle *h) | |||
1781 | } | 1784 | } |
1782 | if (h->oOverlapRead) | 1785 | if (h->oOverlapRead) |
1783 | { | 1786 | { |
1784 | if (!CloseHandle (h->oOverlapRead->hEvent)) | 1787 | if (! CloseHandle (h->oOverlapRead->hEvent)) |
1785 | { | 1788 | { |
1786 | SetErrnoFromWinError (GetLastError ()); | 1789 | SetErrnoFromWinError (GetLastError ()); |
1787 | LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close"); | 1790 | LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "close"); |
@@ -1822,7 +1825,6 @@ struct GNUNET_DISK_FileHandle * | |||
1822 | GNUNET_DISK_get_handle_from_w32_handle (HANDLE osfh) | 1825 | GNUNET_DISK_get_handle_from_w32_handle (HANDLE osfh) |
1823 | { | 1826 | { |
1824 | struct GNUNET_DISK_FileHandle *fh; | 1827 | struct GNUNET_DISK_FileHandle *fh; |
1825 | |||
1826 | DWORD dwret; | 1828 | DWORD dwret; |
1827 | enum GNUNET_FILE_Type ftype; | 1829 | enum GNUNET_FILE_Type ftype; |
1828 | 1830 | ||
@@ -1836,7 +1838,8 @@ GNUNET_DISK_get_handle_from_w32_handle (HANDLE osfh) | |||
1836 | ftype = GNUNET_DISK_HANLDE_TYPE_PIPE; | 1838 | ftype = GNUNET_DISK_HANLDE_TYPE_PIPE; |
1837 | break; | 1839 | break; |
1838 | case FILE_TYPE_UNKNOWN: | 1840 | case FILE_TYPE_UNKNOWN: |
1839 | if (GetLastError () == NO_ERROR || GetLastError () == ERROR_INVALID_HANDLE) | 1841 | if ( (GetLastError () == NO_ERROR) || |
1842 | (GetLastError () == ERROR_INVALID_HANDLE) ) | ||
1840 | { | 1843 | { |
1841 | if (0 != ResetEvent (osfh)) | 1844 | if (0 != ResetEvent (osfh)) |
1842 | ftype = GNUNET_DISK_HANLDE_TYPE_EVENT; | 1845 | ftype = GNUNET_DISK_HANLDE_TYPE_EVENT; |
diff --git a/src/util/getopt.c b/src/util/getopt.c index ff62dba9b..036e0f4be 100644 --- a/src/util/getopt.c +++ b/src/util/getopt.c | |||
@@ -26,7 +26,7 @@ USA. | |||
26 | 26 | ||
27 | 27 | ||
28 | This code was heavily modified for GNUnet. | 28 | This code was heavily modified for GNUnet. |
29 | Copyright Copyright (C) 2006 Christian Grothoff | 29 | Copyright Copyright (C) 2006, 2017 Christian Grothoff |
30 | */ | 30 | */ |
31 | 31 | ||
32 | /** | 32 | /** |
@@ -845,9 +845,13 @@ GN_getopt_internal (int argc, char *const *argv, const char *optstring, | |||
845 | } | 845 | } |
846 | } | 846 | } |
847 | 847 | ||
848 | |||
848 | static int | 849 | static int |
849 | GNgetopt_long (int argc, char *const *argv, const char *options, | 850 | GNgetopt_long (int argc, |
850 | const struct GNoption *long_options, int *opt_index) | 851 | char *const *argv, |
852 | const char *options, | ||
853 | const struct GNoption *long_options, | ||
854 | int *opt_index) | ||
851 | { | 855 | { |
852 | return GN_getopt_internal (argc, argv, options, long_options, opt_index, 0); | 856 | return GN_getopt_internal (argc, argv, options, long_options, opt_index, 0); |
853 | } | 857 | } |
@@ -867,16 +871,17 @@ GNgetopt_long (int argc, char *const *argv, const char *options, | |||
867 | int | 871 | int |
868 | GNUNET_GETOPT_run (const char *binaryOptions, | 872 | GNUNET_GETOPT_run (const char *binaryOptions, |
869 | const struct GNUNET_GETOPT_CommandLineOption *allOptions, | 873 | const struct GNUNET_GETOPT_CommandLineOption *allOptions, |
870 | unsigned int argc, char *const *argv) | 874 | unsigned int argc, |
875 | char *const *argv) | ||
871 | { | 876 | { |
872 | struct GNoption *long_options; | 877 | struct GNoption *long_options; |
873 | struct GNUNET_GETOPT_CommandLineProcessorContext clpc; | 878 | struct GNUNET_GETOPT_CommandLineProcessorContext clpc; |
874 | int count; | 879 | int count; |
875 | int i; | ||
876 | char *shorts; | 880 | char *shorts; |
877 | int spos; | 881 | int spos; |
878 | int cont; | 882 | int cont; |
879 | int c; | 883 | int c; |
884 | uint8_t *seen; | ||
880 | 885 | ||
881 | GNUNET_assert (argc > 0); | 886 | GNUNET_assert (argc > 0); |
882 | GNoptind = 0; | 887 | GNoptind = 0; |
@@ -885,13 +890,15 @@ GNUNET_GETOPT_run (const char *binaryOptions, | |||
885 | clpc.allOptions = allOptions; | 890 | clpc.allOptions = allOptions; |
886 | clpc.argv = argv; | 891 | clpc.argv = argv; |
887 | clpc.argc = argc; | 892 | clpc.argc = argc; |
888 | count = 0; | 893 | for (count = 0; NULL != allOptions[count].name; count++) ; |
889 | while (allOptions[count].name != NULL) | 894 | |
890 | count++; | 895 | long_options = GNUNET_new_array (count + 1, |
891 | long_options = GNUNET_malloc (sizeof (struct GNoption) * (count + 1)); | 896 | struct GNoption); |
897 | seen = GNUNET_new_array (count, | ||
898 | uint8_t); | ||
892 | shorts = GNUNET_malloc (count * 2 + 1); | 899 | shorts = GNUNET_malloc (count * 2 + 1); |
893 | spos = 0; | 900 | spos = 0; |
894 | for (i = 0; i < count; i++) | 901 | for (unsigned i = 0; i < count; i++) |
895 | { | 902 | { |
896 | long_options[i].name = allOptions[i].name; | 903 | long_options[i].name = allOptions[i].name; |
897 | long_options[i].has_arg = allOptions[i].require_argument; | 904 | long_options[i].has_arg = allOptions[i].require_argument; |
@@ -907,13 +914,17 @@ GNUNET_GETOPT_run (const char *binaryOptions, | |||
907 | long_options[count].val = '\0'; | 914 | long_options[count].val = '\0'; |
908 | shorts[spos] = '\0'; | 915 | shorts[spos] = '\0'; |
909 | cont = GNUNET_OK; | 916 | cont = GNUNET_OK; |
917 | |||
910 | /* main getopt loop */ | 918 | /* main getopt loop */ |
911 | while (cont == GNUNET_OK) | 919 | while (GNUNET_OK == cont) |
912 | { | 920 | { |
913 | int option_index = 0; | 921 | int option_index = 0; |
922 | unsigned int i; | ||
914 | 923 | ||
915 | c = GNgetopt_long (argc, argv, shorts, long_options, &option_index); | 924 | c = GNgetopt_long (argc, argv, |
916 | 925 | shorts, | |
926 | long_options, | ||
927 | &option_index); | ||
917 | if (c == GNUNET_SYSERR) | 928 | if (c == GNUNET_SYSERR) |
918 | break; /* No more flags to process */ | 929 | break; /* No more flags to process */ |
919 | 930 | ||
@@ -922,25 +933,46 @@ GNUNET_GETOPT_run (const char *binaryOptions, | |||
922 | clpc.currentArgument = GNoptind - 1; | 933 | clpc.currentArgument = GNoptind - 1; |
923 | if ((char) c == allOptions[i].shortName) | 934 | if ((char) c == allOptions[i].shortName) |
924 | { | 935 | { |
925 | cont = | 936 | cont = allOptions[i].processor (&clpc, |
926 | allOptions[i].processor (&clpc, allOptions[i].scls, | 937 | allOptions[i].scls, |
927 | allOptions[i].name, GNoptarg); | 938 | allOptions[i].name, |
939 | GNoptarg); | ||
940 | seen[i] = 1; | ||
928 | break; | 941 | break; |
929 | } | 942 | } |
930 | } | 943 | } |
931 | if (i == count) | 944 | if (i == count) |
932 | { | 945 | { |
933 | FPRINTF (stderr, _("Use %s to get a list of options.\n"), "--help"); | 946 | FPRINTF (stderr, |
947 | _("Use %s to get a list of options.\n"), | ||
948 | "--help"); | ||
934 | cont = GNUNET_SYSERR; | 949 | cont = GNUNET_SYSERR; |
935 | } | 950 | } |
936 | } | 951 | } |
937 | |||
938 | GNUNET_free (shorts); | 952 | GNUNET_free (shorts); |
939 | GNUNET_free (long_options); | 953 | GNUNET_free (long_options); |
940 | if (cont != GNUNET_OK) | 954 | |
955 | if (GNUNET_YES == cont) | ||
941 | { | 956 | { |
942 | return cont; | 957 | for (count = 0; NULL != allOptions[count].name; count++) |
958 | if ( (0 == seen[count]) && | ||
959 | (allOptions[count].option_mandatory) ) | ||
960 | { | ||
961 | FPRINTF (stderr, | ||
962 | _("Missing mandatory option `%s'.\n"), | ||
963 | allOptions[count].name); | ||
964 | cont = GNUNET_SYSERR; | ||
965 | } | ||
943 | } | 966 | } |
967 | GNUNET_free (seen); | ||
968 | |||
969 | /* call cleaners, if available */ | ||
970 | for (count = 0; NULL != allOptions[count].name; count++) | ||
971 | if (NULL != allOptions[count].cleaner) | ||
972 | allOptions[count].cleaner (allOptions[count].scls); | ||
973 | |||
974 | if (GNUNET_OK != cont) | ||
975 | return cont; | ||
944 | return GNoptind; | 976 | return GNoptind; |
945 | } | 977 | } |
946 | 978 | ||
diff --git a/src/util/getopt_helpers.c b/src/util/getopt_helpers.c index 4d7104503..76342a6c9 100644 --- a/src/util/getopt_helpers.c +++ b/src/util/getopt_helpers.c | |||
@@ -38,11 +38,11 @@ | |||
38 | * @param value not used (NULL) | 38 | * @param value not used (NULL) |
39 | * @return #GNUNET_NO (do not continue, not an error) | 39 | * @return #GNUNET_NO (do not continue, not an error) |
40 | */ | 40 | */ |
41 | int | 41 | static int |
42 | GNUNET_GETOPT_print_version_ (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, | 42 | print_version (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, |
43 | void *scls, | 43 | void *scls, |
44 | const char *option, | 44 | const char *option, |
45 | const char *value) | 45 | const char *value) |
46 | { | 46 | { |
47 | const char *version = scls; | 47 | const char *version = scls; |
48 | 48 | ||
@@ -54,6 +54,26 @@ GNUNET_GETOPT_print_version_ (struct GNUNET_GETOPT_CommandLineProcessorContext * | |||
54 | 54 | ||
55 | 55 | ||
56 | /** | 56 | /** |
57 | * Define the option to print the version of | ||
58 | * the application (-v option) | ||
59 | * | ||
60 | * @param version string with the version number | ||
61 | */ | ||
62 | struct GNUNET_GETOPT_CommandLineOption | ||
63 | GNUNET_GETOPT_OPTION_VERSION (const char *version) | ||
64 | { | ||
65 | struct GNUNET_GETOPT_CommandLineOption clo = { | ||
66 | .shortName = 'v', | ||
67 | .name = "version", | ||
68 | .description = gettext_noop("print the version number"), | ||
69 | .processor = &print_version, | ||
70 | .scls = (void *) version | ||
71 | }; | ||
72 | return clo; | ||
73 | } | ||
74 | |||
75 | |||
76 | /** | ||
57 | * At what offset does the help text start? | 77 | * At what offset does the help text start? |
58 | */ | 78 | */ |
59 | #define BORDER 29 | 79 | #define BORDER 29 |
@@ -67,11 +87,11 @@ GNUNET_GETOPT_print_version_ (struct GNUNET_GETOPT_CommandLineProcessorContext * | |||
67 | * @param value not used (NULL) | 87 | * @param value not used (NULL) |
68 | * @return #GNUNET_NO (do not continue, not an error) | 88 | * @return #GNUNET_NO (do not continue, not an error) |
69 | */ | 89 | */ |
70 | int | 90 | static int |
71 | GNUNET_GETOPT_format_help_ (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, | 91 | format_help (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, |
72 | void *scls, | 92 | void *scls, |
73 | const char *option, | 93 | const char *option, |
74 | const char *value) | 94 | const char *value) |
75 | { | 95 | { |
76 | const char *about = scls; | 96 | const char *about = scls; |
77 | size_t slen; | 97 | size_t slen; |
@@ -165,6 +185,27 @@ OUTER: | |||
165 | 185 | ||
166 | 186 | ||
167 | /** | 187 | /** |
188 | * Defining the option to print the command line | ||
189 | * help text (-h option). | ||
190 | * | ||
191 | * @param about string with brief description of the application | ||
192 | */ | ||
193 | struct GNUNET_GETOPT_CommandLineOption | ||
194 | GNUNET_GETOPT_OPTION_HELP (const char *about) | ||
195 | { | ||
196 | struct GNUNET_GETOPT_CommandLineOption clo = { | ||
197 | .shortName = 'h', | ||
198 | .name = "help", | ||
199 | .description = gettext_noop("print this help"), | ||
200 | .processor = format_help, | ||
201 | .scls = (void *) about | ||
202 | }; | ||
203 | |||
204 | return clo; | ||
205 | } | ||
206 | |||
207 | |||
208 | /** | ||
168 | * Set an option of type 'unsigned int' from the command line. Each | 209 | * Set an option of type 'unsigned int' from the command line. Each |
169 | * time the option flag is given, the value is incremented by one. | 210 | * time the option flag is given, the value is incremented by one. |
170 | * A pointer to this function should be passed as part of the | 211 | * A pointer to this function should be passed as part of the |
@@ -173,17 +214,18 @@ OUTER: | |||
173 | * type 'int'. | 214 | * type 'int'. |
174 | * | 215 | * |
175 | * @param ctx command line processing context | 216 | * @param ctx command line processing context |
176 | * @param scls additional closure (will point to the 'int') | 217 | * @param scls additional closure (will point to the 'unsigned int') |
177 | * @param option name of the option | 218 | * @param option name of the option |
178 | * @param value not used (NULL) | 219 | * @param value not used (NULL) |
179 | * @return #GNUNET_OK | 220 | * @return #GNUNET_OK |
180 | */ | 221 | */ |
181 | int | 222 | static int |
182 | GNUNET_GETOPT_increment_value (struct GNUNET_GETOPT_CommandLineProcessorContext | 223 | increment_value (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, |
183 | *ctx, void *scls, const char *option, | 224 | void *scls, |
184 | const char *value) | 225 | const char *option, |
226 | const char *value) | ||
185 | { | 227 | { |
186 | int *val = scls; | 228 | unsigned int *val = scls; |
187 | 229 | ||
188 | (*val)++; | 230 | (*val)++; |
189 | return GNUNET_OK; | 231 | return GNUNET_OK; |
@@ -191,6 +233,54 @@ GNUNET_GETOPT_increment_value (struct GNUNET_GETOPT_CommandLineProcessorContext | |||
191 | 233 | ||
192 | 234 | ||
193 | /** | 235 | /** |
236 | * Increment @a val each time the option flag is given by one. | ||
237 | * | ||
238 | * @param shortName short name of the option | ||
239 | * @param name long name of the option | ||
240 | * @param argumentHelp help text for the option argument | ||
241 | * @param description long help text for the option | ||
242 | * @param[out] val increment by 1 each time the option is present | ||
243 | */ | ||
244 | struct GNUNET_GETOPT_CommandLineOption | ||
245 | GNUNET_GETOPT_OPTION_INCREMENT_VALUE (char shortName, | ||
246 | const char *name, | ||
247 | const char *description, | ||
248 | unsigned int *val) | ||
249 | { | ||
250 | struct GNUNET_GETOPT_CommandLineOption clo = { | ||
251 | .shortName = shortName, | ||
252 | .name = name, | ||
253 | .description = description, | ||
254 | .processor = &increment_value, | ||
255 | .scls = (void *) val | ||
256 | }; | ||
257 | |||
258 | return clo; | ||
259 | } | ||
260 | |||
261 | |||
262 | /** | ||
263 | * Define the '-V' verbosity option. Using the option more | ||
264 | * than once increments @a level each time. | ||
265 | * | ||
266 | * @param[out] level set to the verbosity level | ||
267 | */ | ||
268 | struct GNUNET_GETOPT_CommandLineOption | ||
269 | GNUNET_GETOPT_OPTION_VERBOSE (unsigned int *level) | ||
270 | { | ||
271 | struct GNUNET_GETOPT_CommandLineOption clo = { | ||
272 | .shortName = 'V', | ||
273 | .name = "verbose", | ||
274 | .description = gettext_noop("be verbose"), | ||
275 | .processor = &increment_value, | ||
276 | .scls = (void *) level | ||
277 | }; | ||
278 | |||
279 | return clo; | ||
280 | } | ||
281 | |||
282 | |||
283 | /** | ||
194 | * Set an option of type 'int' from the command line to 1 if the | 284 | * Set an option of type 'int' from the command line to 1 if the |
195 | * given option is present. | 285 | * given option is present. |
196 | * A pointer to this function should be passed as part of the | 286 | * A pointer to this function should be passed as part of the |
@@ -204,9 +294,11 @@ GNUNET_GETOPT_increment_value (struct GNUNET_GETOPT_CommandLineProcessorContext | |||
204 | * @param value not used (NULL) | 294 | * @param value not used (NULL) |
205 | * @return #GNUNET_OK | 295 | * @return #GNUNET_OK |
206 | */ | 296 | */ |
207 | int | 297 | static int |
208 | GNUNET_GETOPT_set_one (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, | 298 | set_one (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, |
209 | void *scls, const char *option, const char *value) | 299 | void *scls, |
300 | const char *option, | ||
301 | const char *value) | ||
210 | { | 302 | { |
211 | int *val = scls; | 303 | int *val = scls; |
212 | 304 | ||
@@ -216,6 +308,34 @@ GNUNET_GETOPT_set_one (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, | |||
216 | 308 | ||
217 | 309 | ||
218 | /** | 310 | /** |
311 | * Allow user to specify a flag (which internally means setting | ||
312 | * an integer to 1/#GNUNET_YES/#GNUNET_OK. | ||
313 | * | ||
314 | * @param shortName short name of the option | ||
315 | * @param name long name of the option | ||
316 | * @param argumentHelp help text for the option argument | ||
317 | * @param description long help text for the option | ||
318 | * @param[out] val set to 1 if the option is present | ||
319 | */ | ||
320 | struct GNUNET_GETOPT_CommandLineOption | ||
321 | GNUNET_GETOPT_OPTION_SET_ONE (char shortName, | ||
322 | const char *name, | ||
323 | const char *description, | ||
324 | int *val) | ||
325 | { | ||
326 | struct GNUNET_GETOPT_CommandLineOption clo = { | ||
327 | .shortName = shortName, | ||
328 | .name = name, | ||
329 | .description = description, | ||
330 | .processor = &set_one, | ||
331 | .scls = (void *) val | ||
332 | }; | ||
333 | |||
334 | return clo; | ||
335 | } | ||
336 | |||
337 | |||
338 | /** | ||
219 | * Set an option of type 'char *' from the command line. | 339 | * Set an option of type 'char *' from the command line. |
220 | * A pointer to this function should be passed as part of the | 340 | * A pointer to this function should be passed as part of the |
221 | * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options | 341 | * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options |
@@ -229,31 +349,174 @@ GNUNET_GETOPT_set_one (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, | |||
229 | * @param value actual value of the option (a string) | 349 | * @param value actual value of the option (a string) |
230 | * @return #GNUNET_OK | 350 | * @return #GNUNET_OK |
231 | */ | 351 | */ |
232 | int | 352 | static int |
233 | GNUNET_GETOPT_set_string (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, | 353 | set_string (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, |
234 | void *scls, const char *option, const char *value) | 354 | void *scls, |
355 | const char *option, | ||
356 | const char *value) | ||
235 | { | 357 | { |
236 | char **val = scls; | 358 | char **val = scls; |
237 | 359 | ||
238 | GNUNET_assert (value != NULL); | 360 | GNUNET_assert (NULL != value); |
239 | GNUNET_free_non_null (*val); | 361 | GNUNET_free_non_null (*val); |
240 | *val = GNUNET_strdup (value); | 362 | *val = GNUNET_strdup (value); |
241 | return GNUNET_OK; | 363 | return GNUNET_OK; |
242 | } | 364 | } |
243 | 365 | ||
244 | 366 | ||
245 | int | 367 | /** |
246 | GNUNET_GETOPT_set_filename (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, | 368 | * Allow user to specify a string. |
247 | void *scls, const char *option, const char *value) | 369 | * |
370 | * @param shortName short name of the option | ||
371 | * @param name long name of the option | ||
372 | * @param argumentHelp help text for the option argument | ||
373 | * @param description long help text for the option | ||
374 | * @param[out] str set to the string | ||
375 | */ | ||
376 | struct GNUNET_GETOPT_CommandLineOption | ||
377 | GNUNET_GETOPT_OPTION_STRING (char shortName, | ||
378 | const char *name, | ||
379 | const char *argumentHelp, | ||
380 | const char *description, | ||
381 | char **str) | ||
382 | { | ||
383 | struct GNUNET_GETOPT_CommandLineOption clo = { | ||
384 | .shortName = shortName, | ||
385 | .name = name, | ||
386 | .argumentHelp = argumentHelp, | ||
387 | .description = description, | ||
388 | .require_argument = 1, | ||
389 | .processor = &set_string, | ||
390 | .scls = (void *) str | ||
391 | }; | ||
392 | |||
393 | return clo; | ||
394 | } | ||
395 | |||
396 | |||
397 | /** | ||
398 | * Define the '-L' log level option. Note that we do not check | ||
399 | * that the log level is valid here. | ||
400 | * | ||
401 | * @param[out] level set to the log level | ||
402 | */ | ||
403 | struct GNUNET_GETOPT_CommandLineOption | ||
404 | GNUNET_GETOPT_OPTION_LOGLEVEL (char **level) | ||
405 | { | ||
406 | struct GNUNET_GETOPT_CommandLineOption clo = { | ||
407 | .shortName = 'L', | ||
408 | .name = "log", | ||
409 | .argumentHelp = "LOGLEVEL", | ||
410 | .description = gettext_noop("configure logging to use LOGLEVEL"), | ||
411 | .require_argument = 1, | ||
412 | .processor = &set_string, | ||
413 | .scls = (void *) level | ||
414 | }; | ||
415 | |||
416 | return clo; | ||
417 | } | ||
418 | |||
419 | |||
420 | /** | ||
421 | * Set an option of type 'char *' from the command line with | ||
422 | * filename expansion a la #GNUNET_STRINGS_filename_expand(). | ||
423 | * | ||
424 | * @param ctx command line processing context | ||
425 | * @param scls additional closure (will point to the `char *`, | ||
426 | * which will be allocated) | ||
427 | * @param option name of the option | ||
428 | * @param value actual value of the option (a string) | ||
429 | * @return #GNUNET_OK | ||
430 | */ | ||
431 | static int | ||
432 | set_filename (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, | ||
433 | void *scls, | ||
434 | const char *option, | ||
435 | const char *value) | ||
248 | { | 436 | { |
249 | char **val = scls; | 437 | char **val = scls; |
250 | 438 | ||
251 | GNUNET_assert (value != NULL); | 439 | GNUNET_assert (NULL != value); |
252 | GNUNET_free_non_null (*val); | 440 | GNUNET_free_non_null (*val); |
253 | *val = GNUNET_STRINGS_filename_expand (value); | 441 | *val = GNUNET_STRINGS_filename_expand (value); |
254 | return GNUNET_OK; | 442 | return GNUNET_OK; |
255 | } | 443 | } |
256 | 444 | ||
445 | |||
446 | /** | ||
447 | * Allow user to specify a filename (automatically path expanded). | ||
448 | * | ||
449 | * @param shortName short name of the option | ||
450 | * @param name long name of the option | ||
451 | * @param argumentHelp help text for the option argument | ||
452 | * @param description long help text for the option | ||
453 | * @param[out] str set to the string | ||
454 | */ | ||
455 | struct GNUNET_GETOPT_CommandLineOption | ||
456 | GNUNET_GETOPT_OPTION_FILENAME (char shortName, | ||
457 | const char *name, | ||
458 | const char *argumentHelp, | ||
459 | const char *description, | ||
460 | char **str) | ||
461 | { | ||
462 | struct GNUNET_GETOPT_CommandLineOption clo = { | ||
463 | .shortName = shortName, | ||
464 | .name = name, | ||
465 | .argumentHelp = argumentHelp, | ||
466 | .description = description, | ||
467 | .require_argument = 1, | ||
468 | .processor = &set_filename, | ||
469 | .scls = (void *) str | ||
470 | }; | ||
471 | |||
472 | return clo; | ||
473 | } | ||
474 | |||
475 | |||
476 | /** | ||
477 | * Allow user to specify log file name (-l option) | ||
478 | * | ||
479 | * @param[out] logfn set to the name of the logfile | ||
480 | */ | ||
481 | struct GNUNET_GETOPT_CommandLineOption | ||
482 | GNUNET_GETOPT_OPTION_LOGFILE (char **logfn) | ||
483 | { | ||
484 | struct GNUNET_GETOPT_CommandLineOption clo = { | ||
485 | .shortName = 'l', | ||
486 | .name = "logfile", | ||
487 | .argumentHelp = "FILENAME", | ||
488 | .description = gettext_noop ("configure logging to write logs to FILENAME"), | ||
489 | .require_argument = 1, | ||
490 | .processor = &set_filename, | ||
491 | .scls = (void *) logfn | ||
492 | }; | ||
493 | |||
494 | return clo; | ||
495 | } | ||
496 | |||
497 | |||
498 | /** | ||
499 | * Allow user to specify configuration file name (-c option) | ||
500 | * | ||
501 | * @param[out] fn set to the name of the configuration file | ||
502 | */ | ||
503 | struct GNUNET_GETOPT_CommandLineOption | ||
504 | GNUNET_GETOPT_OPTION_CFG_FILE (char **fn) | ||
505 | { | ||
506 | struct GNUNET_GETOPT_CommandLineOption clo = { | ||
507 | .shortName = 'c', | ||
508 | .name = "config", | ||
509 | .argumentHelp = "FILENAME", | ||
510 | .description = gettext_noop("use configuration file FILENAME"), | ||
511 | .require_argument = 1, | ||
512 | .processor = &set_filename, | ||
513 | .scls = (void *) fn | ||
514 | }; | ||
515 | |||
516 | return clo; | ||
517 | } | ||
518 | |||
519 | |||
257 | /** | 520 | /** |
258 | * Set an option of type 'unsigned long long' from the command line. | 521 | * Set an option of type 'unsigned long long' from the command line. |
259 | * A pointer to this function should be passed as part of the | 522 | * A pointer to this function should be passed as part of the |
@@ -267,15 +530,21 @@ GNUNET_GETOPT_set_filename (struct GNUNET_GETOPT_CommandLineProcessorContext *ct | |||
267 | * @param value actual value of the option as a string. | 530 | * @param value actual value of the option as a string. |
268 | * @return #GNUNET_OK if parsing the value worked | 531 | * @return #GNUNET_OK if parsing the value worked |
269 | */ | 532 | */ |
270 | int | 533 | static int |
271 | GNUNET_GETOPT_set_ulong (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, | 534 | set_ulong (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, |
272 | void *scls, const char *option, const char *value) | 535 | void *scls, |
536 | const char *option, | ||
537 | const char *value) | ||
273 | { | 538 | { |
274 | unsigned long long *val = scls; | 539 | unsigned long long *val = scls; |
275 | 540 | ||
276 | if (1 != SSCANF (value, "%llu", val)) | 541 | if (1 != SSCANF (value, |
542 | "%llu", | ||
543 | val)) | ||
277 | { | 544 | { |
278 | FPRINTF (stderr, _("You must pass a number to the `%s' option.\n"), option); | 545 | FPRINTF (stderr, |
546 | _("You must pass a number to the `%s' option.\n"), | ||
547 | option); | ||
279 | return GNUNET_SYSERR; | 548 | return GNUNET_SYSERR; |
280 | } | 549 | } |
281 | return GNUNET_OK; | 550 | return GNUNET_OK; |
@@ -283,6 +552,36 @@ GNUNET_GETOPT_set_ulong (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, | |||
283 | 552 | ||
284 | 553 | ||
285 | /** | 554 | /** |
555 | * Allow user to specify an `unsigned long long` | ||
556 | * | ||
557 | * @param shortName short name of the option | ||
558 | * @param name long name of the option | ||
559 | * @param argumentHelp help text for the option argument | ||
560 | * @param description long help text for the option | ||
561 | * @param[out] val set to the value specified at the command line | ||
562 | */ | ||
563 | struct GNUNET_GETOPT_CommandLineOption | ||
564 | GNUNET_GETOPT_OPTION_SET_ULONG (char shortName, | ||
565 | const char *name, | ||
566 | const char *argumentHelp, | ||
567 | const char *description, | ||
568 | unsigned long long *val) | ||
569 | { | ||
570 | struct GNUNET_GETOPT_CommandLineOption clo = { | ||
571 | .shortName = shortName, | ||
572 | .name = name, | ||
573 | .argumentHelp = argumentHelp, | ||
574 | .description = description, | ||
575 | .require_argument = 1, | ||
576 | .processor = &set_ulong, | ||
577 | .scls = (void *) val | ||
578 | }; | ||
579 | |||
580 | return clo; | ||
581 | } | ||
582 | |||
583 | |||
584 | /** | ||
286 | * Set an option of type 'struct GNUNET_TIME_Relative' from the command line. | 585 | * Set an option of type 'struct GNUNET_TIME_Relative' from the command line. |
287 | * A pointer to this function should be passed as part of the | 586 | * A pointer to this function should be passed as part of the |
288 | * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options | 587 | * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options |
@@ -295,9 +594,11 @@ GNUNET_GETOPT_set_ulong (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, | |||
295 | * @param value actual value of the option as a string. | 594 | * @param value actual value of the option as a string. |
296 | * @return #GNUNET_OK if parsing the value worked | 595 | * @return #GNUNET_OK if parsing the value worked |
297 | */ | 596 | */ |
298 | int | 597 | static int |
299 | GNUNET_GETOPT_set_relative_time (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, | 598 | set_relative_time (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, |
300 | void *scls, const char *option, const char *value) | 599 | void *scls, |
600 | const char *option, | ||
601 | const char *value) | ||
301 | { | 602 | { |
302 | struct GNUNET_TIME_Relative *val = scls; | 603 | struct GNUNET_TIME_Relative *val = scls; |
303 | 604 | ||
@@ -305,7 +606,74 @@ GNUNET_GETOPT_set_relative_time (struct GNUNET_GETOPT_CommandLineProcessorContex | |||
305 | GNUNET_STRINGS_fancy_time_to_relative (value, | 606 | GNUNET_STRINGS_fancy_time_to_relative (value, |
306 | val)) | 607 | val)) |
307 | { | 608 | { |
308 | FPRINTF (stderr, _("You must pass relative time to the `%s' option.\n"), option); | 609 | FPRINTF (stderr, |
610 | _("You must pass relative time to the `%s' option.\n"), | ||
611 | option); | ||
612 | return GNUNET_SYSERR; | ||
613 | } | ||
614 | return GNUNET_OK; | ||
615 | } | ||
616 | |||
617 | |||
618 | /** | ||
619 | * Allow user to specify a `struct GNUNET_TIME_Relative` | ||
620 | * (using human-readable "fancy" time). | ||
621 | * | ||
622 | * @param shortName short name of the option | ||
623 | * @param name long name of the option | ||
624 | * @param argumentHelp help text for the option argument | ||
625 | * @param description long help text for the option | ||
626 | * @param[out] val set to the time specified at the command line | ||
627 | */ | ||
628 | struct GNUNET_GETOPT_CommandLineOption | ||
629 | GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME (char shortName, | ||
630 | const char *name, | ||
631 | const char *argumentHelp, | ||
632 | const char *description, | ||
633 | struct GNUNET_TIME_Relative *val) | ||
634 | { | ||
635 | struct GNUNET_GETOPT_CommandLineOption clo = { | ||
636 | .shortName = shortName, | ||
637 | .name = name, | ||
638 | .argumentHelp = argumentHelp, | ||
639 | .description = description, | ||
640 | .require_argument = 1, | ||
641 | .processor = &set_relative_time, | ||
642 | .scls = (void *) val | ||
643 | }; | ||
644 | |||
645 | return clo; | ||
646 | } | ||
647 | |||
648 | |||
649 | /** | ||
650 | * Set an option of type 'struct GNUNET_TIME_Absolute' from the command line. | ||
651 | * A pointer to this function should be passed as part of the | ||
652 | * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options | ||
653 | * of this type. It should be followed by a pointer to a value of | ||
654 | * type 'struct GNUNET_TIME_Absolute'. | ||
655 | * | ||
656 | * @param ctx command line processing context | ||
657 | * @param scls additional closure (will point to the `struct GNUNET_TIME_Absolute`) | ||
658 | * @param option name of the option | ||
659 | * @param value actual value of the option as a string. | ||
660 | * @return #GNUNET_OK if parsing the value worked | ||
661 | */ | ||
662 | static int | ||
663 | set_absolute_time (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, | ||
664 | void *scls, | ||
665 | const char *option, | ||
666 | const char *value) | ||
667 | { | ||
668 | struct GNUNET_TIME_Absolute *val = scls; | ||
669 | |||
670 | if (GNUNET_OK != | ||
671 | GNUNET_STRINGS_fancy_time_to_absolute (value, | ||
672 | val)) | ||
673 | { | ||
674 | FPRINTF (stderr, | ||
675 | _("You must pass absolute time to the `%s' option.\n"), | ||
676 | option); | ||
309 | return GNUNET_SYSERR; | 677 | return GNUNET_SYSERR; |
310 | } | 678 | } |
311 | return GNUNET_OK; | 679 | return GNUNET_OK; |
@@ -313,6 +681,37 @@ GNUNET_GETOPT_set_relative_time (struct GNUNET_GETOPT_CommandLineProcessorContex | |||
313 | 681 | ||
314 | 682 | ||
315 | /** | 683 | /** |
684 | * Allow user to specify a `struct GNUNET_TIME_Absolute` | ||
685 | * (using human-readable "fancy" time). | ||
686 | * | ||
687 | * @param shortName short name of the option | ||
688 | * @param name long name of the option | ||
689 | * @param argumentHelp help text for the option argument | ||
690 | * @param description long help text for the option | ||
691 | * @param[out] val set to the time specified at the command line | ||
692 | */ | ||
693 | struct GNUNET_GETOPT_CommandLineOption | ||
694 | GNUNET_GETOPT_OPTION_SET_ABSOLUTE_TIME (char shortName, | ||
695 | const char *name, | ||
696 | const char *argumentHelp, | ||
697 | const char *description, | ||
698 | struct GNUNET_TIME_Absolute *val) | ||
699 | { | ||
700 | struct GNUNET_GETOPT_CommandLineOption clo = { | ||
701 | .shortName = shortName, | ||
702 | .name = name, | ||
703 | .argumentHelp = argumentHelp, | ||
704 | .description = description, | ||
705 | .require_argument = 1, | ||
706 | .processor = &set_absolute_time, | ||
707 | .scls = (void *) val | ||
708 | }; | ||
709 | |||
710 | return clo; | ||
711 | } | ||
712 | |||
713 | |||
714 | /** | ||
316 | * Set an option of type 'unsigned int' from the command line. | 715 | * Set an option of type 'unsigned int' from the command line. |
317 | * A pointer to this function should be passed as part of the | 716 | * A pointer to this function should be passed as part of the |
318 | * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options | 717 | * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options |
@@ -325,19 +724,172 @@ GNUNET_GETOPT_set_relative_time (struct GNUNET_GETOPT_CommandLineProcessorContex | |||
325 | * @param value actual value of the option as a string. | 724 | * @param value actual value of the option as a string. |
326 | * @return #GNUNET_OK if parsing the value worked | 725 | * @return #GNUNET_OK if parsing the value worked |
327 | */ | 726 | */ |
328 | int | 727 | static int |
329 | GNUNET_GETOPT_set_uint (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, | 728 | set_uint (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, |
330 | void *scls, const char *option, const char *value) | 729 | void *scls, |
730 | const char *option, | ||
731 | const char *value) | ||
331 | { | 732 | { |
332 | unsigned int *val = scls; | 733 | unsigned int *val = scls; |
333 | 734 | ||
334 | if (1 != SSCANF (value, "%u", val)) | 735 | if (1 != SSCANF (value, |
736 | "%u", | ||
737 | val)) | ||
335 | { | 738 | { |
336 | FPRINTF (stderr, _("You must pass a number to the `%s' option.\n"), option); | 739 | FPRINTF (stderr, |
740 | _("You must pass a number to the `%s' option.\n"), | ||
741 | option); | ||
337 | return GNUNET_SYSERR; | 742 | return GNUNET_SYSERR; |
338 | } | 743 | } |
339 | return GNUNET_OK; | 744 | return GNUNET_OK; |
340 | } | 745 | } |
341 | 746 | ||
342 | 747 | ||
748 | /** | ||
749 | * Allow user to specify an unsigned integer. | ||
750 | * | ||
751 | * @param shortName short name of the option | ||
752 | * @param name long name of the option | ||
753 | * @param argumentHelp help text for the option argument | ||
754 | * @param description long help text for the option | ||
755 | * @param[out] val set to the value specified at the command line | ||
756 | */ | ||
757 | struct GNUNET_GETOPT_CommandLineOption | ||
758 | GNUNET_GETOPT_OPTION_SET_UINT (char shortName, | ||
759 | const char *name, | ||
760 | const char *argumentHelp, | ||
761 | const char *description, | ||
762 | unsigned int *val) | ||
763 | { | ||
764 | struct GNUNET_GETOPT_CommandLineOption clo = { | ||
765 | .shortName = shortName, | ||
766 | .name = name, | ||
767 | .argumentHelp = argumentHelp, | ||
768 | .description = description, | ||
769 | .require_argument = 1, | ||
770 | .processor = &set_uint, | ||
771 | .scls = (void *) val | ||
772 | }; | ||
773 | |||
774 | return clo; | ||
775 | } | ||
776 | |||
777 | |||
778 | /** | ||
779 | * Closure for #set_base32(). | ||
780 | */ | ||
781 | struct Base32Context | ||
782 | { | ||
783 | /** | ||
784 | * Value to initialize (already allocated) | ||
785 | */ | ||
786 | void *val; | ||
787 | |||
788 | /** | ||
789 | * Number of bytes expected for @e val. | ||
790 | */ | ||
791 | size_t val_size; | ||
792 | }; | ||
793 | |||
794 | |||
795 | /** | ||
796 | * Set an option of type 'unsigned int' from the command line. | ||
797 | * A pointer to this function should be passed as part of the | ||
798 | * 'struct GNUNET_GETOPT_CommandLineOption' array to initialize options | ||
799 | * of this type. It should be followed by a pointer to a value of | ||
800 | * type 'unsigned int'. | ||
801 | * | ||
802 | * @param ctx command line processing context | ||
803 | * @param scls additional closure (will point to the 'unsigned int') | ||
804 | * @param option name of the option | ||
805 | * @param value actual value of the option as a string. | ||
806 | * @return #GNUNET_OK if parsing the value worked | ||
807 | */ | ||
808 | static int | ||
809 | set_base32 (struct GNUNET_GETOPT_CommandLineProcessorContext *ctx, | ||
810 | void *scls, | ||
811 | const char *option, | ||
812 | const char *value) | ||
813 | { | ||
814 | struct Base32Context *bc = scls; | ||
815 | |||
816 | if (GNUNET_OK != | ||
817 | GNUNET_STRINGS_string_to_data (value, | ||
818 | strlen (value), | ||
819 | bc->val, | ||
820 | bc->val_size)) | ||
821 | { | ||
822 | fprintf (stderr, | ||
823 | _("Argument `%s' malformed. Expected base32 (Crockford) encoded value.\n"), | ||
824 | option); | ||
825 | return GNUNET_SYSERR; | ||
826 | } | ||
827 | return GNUNET_OK; | ||
828 | } | ||
829 | |||
830 | |||
831 | /** | ||
832 | * Helper function to clean up after | ||
833 | * #GNUNET_GETOPT_OPTION_SET_BASE32_FIXED_SIZE. | ||
834 | * | ||
835 | * @param cls value to GNUNET_free() | ||
836 | */ | ||
837 | static void | ||
838 | free_bc (void *cls) | ||
839 | { | ||
840 | GNUNET_free (cls); | ||
841 | } | ||
842 | |||
843 | |||
844 | /** | ||
845 | * Allow user to specify a binary value using Crockford | ||
846 | * Base32 encoding. | ||
847 | * | ||
848 | * @param shortName short name of the option | ||
849 | * @param name long name of the option | ||
850 | * @param argumentHelp help text for the option argument | ||
851 | * @param description long help text for the option | ||
852 | * @param[out] val binary value decoded from Crockford Base32-encoded argument | ||
853 | * @param val_size size of @a val in bytes | ||
854 | */ | ||
855 | struct GNUNET_GETOPT_CommandLineOption | ||
856 | GNUNET_GETOPT_OPTION_SET_BASE32_FIXED_SIZE (char shortName, | ||
857 | const char *name, | ||
858 | const char *argumentHelp, | ||
859 | const char *description, | ||
860 | void *val, | ||
861 | size_t val_size) | ||
862 | { | ||
863 | struct Base32Context *bc = GNUNET_new (struct Base32Context); | ||
864 | struct GNUNET_GETOPT_CommandLineOption clo = { | ||
865 | .shortName = shortName, | ||
866 | .name = name, | ||
867 | .argumentHelp = argumentHelp, | ||
868 | .description = description, | ||
869 | .require_argument = 1, | ||
870 | .processor = &set_base32, | ||
871 | .cleaner = &free_bc, | ||
872 | .scls = (void *) bc | ||
873 | }; | ||
874 | |||
875 | bc->val = val; | ||
876 | bc->val_size = val_size; | ||
877 | return clo; | ||
878 | } | ||
879 | |||
880 | |||
881 | /** | ||
882 | * Make the given option mandatory. | ||
883 | * | ||
884 | * @param opt option to modify | ||
885 | * @return @a opt with the mandatory flag set. | ||
886 | */ | ||
887 | struct GNUNET_GETOPT_CommandLineOption | ||
888 | GNUNET_GETOPT_OPTION_MANDATORY (struct GNUNET_GETOPT_CommandLineOption opt) | ||
889 | { | ||
890 | opt.option_mandatory = 1; | ||
891 | return opt; | ||
892 | } | ||
893 | |||
894 | |||
343 | /* end of getopt_helpers.c */ | 895 | /* end of getopt_helpers.c */ |
diff --git a/src/util/gnunet-config.c b/src/util/gnunet-config.c index 7ec7162f1..2beb772a9 100644 --- a/src/util/gnunet-config.c +++ b/src/util/gnunet-config.c | |||
@@ -223,34 +223,48 @@ run (void *cls, | |||
223 | int | 223 | int |
224 | main (int argc, char *const *argv) | 224 | main (int argc, char *const *argv) |
225 | { | 225 | { |
226 | static const struct GNUNET_GETOPT_CommandLineOption options[] = { | 226 | struct GNUNET_GETOPT_CommandLineOption options[] = { |
227 | { 'f', "filename", NULL, | 227 | GNUNET_GETOPT_OPTION_SET_ONE ('f', |
228 | gettext_noop ("obtain option of value as a filename (with $-expansion)"), | 228 | "filename", |
229 | 0, &GNUNET_GETOPT_set_one, &is_filename }, | 229 | gettext_noop ("obtain option of value as a filename (with $-expansion)"), |
230 | { 's', "section", "SECTION", | 230 | &is_filename), |
231 | gettext_noop ("name of the section to access"), | 231 | GNUNET_GETOPT_OPTION_STRING ('s', |
232 | 1, &GNUNET_GETOPT_set_string, §ion }, | 232 | "section", |
233 | { 'o', "option", "OPTION", | 233 | "SECTION", |
234 | gettext_noop ("name of the option to access"), | 234 | gettext_noop ("name of the section to access"), |
235 | 1, &GNUNET_GETOPT_set_string, &option }, | 235 | §ion), |
236 | { 'V', "value", "VALUE", | 236 | GNUNET_GETOPT_OPTION_STRING ('o', |
237 | gettext_noop ("value to set"), | 237 | "option", |
238 | 1, &GNUNET_GETOPT_set_string, &value }, | 238 | "OPTION", |
239 | { 'S', "list-sections", NULL, | 239 | gettext_noop ("name of the option to access"), |
240 | gettext_noop ("print available configuration sections"), | 240 | &option), |
241 | 0, &GNUNET_GETOPT_set_one, &list_sections }, | 241 | GNUNET_GETOPT_OPTION_STRING ('V', |
242 | { 'w', "rewrite", NULL, | 242 | "value", |
243 | gettext_noop ("write configuration file that only contains delta to defaults"), | 243 | "VALUE", |
244 | 0, &GNUNET_GETOPT_set_one, &rewrite }, | 244 | gettext_noop ("value to set"), |
245 | &value), | ||
246 | GNUNET_GETOPT_OPTION_SET_ONE ('S', | ||
247 | "list-sections", | ||
248 | gettext_noop ("print available configuration sections"), | ||
249 | &list_sections), | ||
250 | GNUNET_GETOPT_OPTION_SET_ONE ('w', | ||
251 | "rewrite", | ||
252 | gettext_noop ("write configuration file that only contains delta to defaults"), | ||
253 | &rewrite), | ||
245 | GNUNET_GETOPT_OPTION_END | 254 | GNUNET_GETOPT_OPTION_END |
246 | }; | 255 | }; |
247 | if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) | 256 | if (GNUNET_OK != |
257 | GNUNET_STRINGS_get_utf8_args (argc, argv, | ||
258 | &argc, &argv)) | ||
248 | return 2; | 259 | return 2; |
249 | 260 | ||
250 | ret = (GNUNET_OK == | 261 | ret = (GNUNET_OK == |
251 | GNUNET_PROGRAM_run (argc, argv, "gnunet-config [OPTIONS]", | 262 | GNUNET_PROGRAM_run (argc, |
263 | argv, | ||
264 | "gnunet-config [OPTIONS]", | ||
252 | gettext_noop ("Manipulate GNUnet configuration files"), | 265 | gettext_noop ("Manipulate GNUnet configuration files"), |
253 | options, &run, NULL)) ? 0 : ret; | 266 | options, |
267 | &run, NULL)) ? 0 : ret; | ||
254 | GNUNET_free ((void*) argv); | 268 | GNUNET_free ((void*) argv); |
255 | return ret; | 269 | return ret; |
256 | } | 270 | } |
diff --git a/src/util/gnunet-ecc.c b/src/util/gnunet-ecc.c index ddfd9b1c3..732228b52 100644 --- a/src/util/gnunet-ecc.c +++ b/src/util/gnunet-ecc.c | |||
@@ -41,7 +41,7 @@ static int list_keys; | |||
41 | /** | 41 | /** |
42 | * Flag for listing public key. | 42 | * Flag for listing public key. |
43 | */ | 43 | */ |
44 | static int list_keys_count; | 44 | static unsigned int list_keys_count; |
45 | 45 | ||
46 | /** | 46 | /** |
47 | * Flag for printing public key. | 47 | * Flag for printing public key. |
@@ -406,36 +406,50 @@ run (void *cls, char *const *args, const char *cfgfile, | |||
406 | * @return 0 ok, 1 on error | 406 | * @return 0 ok, 1 on error |
407 | */ | 407 | */ |
408 | int | 408 | int |
409 | main (int argc, char *const *argv) | 409 | main (int argc, |
410 | char *const *argv) | ||
410 | { | 411 | { |
411 | list_keys_count = UINT32_MAX; | 412 | list_keys_count = UINT32_MAX; |
412 | static const struct GNUNET_GETOPT_CommandLineOption options[] = { | 413 | struct GNUNET_GETOPT_CommandLineOption options[] = { |
413 | { 'i', "iterate", "FILE", | 414 | GNUNET_GETOPT_OPTION_SET_ONE ('i', |
414 | gettext_noop ("list keys included in a file (for testing)"), | 415 | "iterate", |
415 | 0, &GNUNET_GETOPT_set_one, &list_keys }, | 416 | gettext_noop ("list keys included in a file (for testing)"), |
416 | { 'e', "end=", "COUNT", | 417 | &list_keys), |
417 | gettext_noop ("number of keys to list included in a file (for testing)"), | 418 | GNUNET_GETOPT_OPTION_SET_UINT ('e', |
418 | 1, &GNUNET_GETOPT_set_uint, &list_keys_count }, | 419 | "end=", |
419 | { 'g', "generate-keys", "COUNT", | 420 | "COUNT", |
420 | gettext_noop ("create COUNT public-private key pairs (for testing)"), | 421 | gettext_noop ("number of keys to list included in a file (for testing)"), |
421 | 1, &GNUNET_GETOPT_set_uint, &make_keys }, | 422 | &list_keys_count), |
422 | { 'p', "print-public-key", NULL, | 423 | GNUNET_GETOPT_OPTION_SET_UINT ('g', |
423 | gettext_noop ("print the public key in ASCII format"), | 424 | "generate-keys", |
424 | 0, &GNUNET_GETOPT_set_one, &print_public_key }, | 425 | "COUNT", |
425 | { 'E', "examples", NULL, | 426 | gettext_noop ("create COUNT public-private key pairs (for testing)"), |
426 | gettext_noop ("print examples of ECC operations (used for compatibility testing)"), | 427 | &make_keys), |
427 | 0, &GNUNET_GETOPT_set_one, &print_examples_flag }, | 428 | GNUNET_GETOPT_OPTION_SET_ONE ('p', |
429 | "print-public-key", | ||
430 | gettext_noop ("print the public key in ASCII format"), | ||
431 | &print_public_key), | ||
432 | GNUNET_GETOPT_OPTION_SET_ONE ('E', | ||
433 | "examples", | ||
434 | gettext_noop ("print examples of ECC operations (used for compatibility testing)"), | ||
435 | &print_examples_flag), | ||
428 | GNUNET_GETOPT_OPTION_END | 436 | GNUNET_GETOPT_OPTION_END |
429 | }; | 437 | }; |
430 | int ret; | 438 | int ret; |
431 | 439 | ||
432 | if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) | 440 | if (GNUNET_OK != |
441 | GNUNET_STRINGS_get_utf8_args (argc, argv, | ||
442 | &argc, &argv)) | ||
433 | return 2; | 443 | return 2; |
434 | 444 | ||
435 | ret = (GNUNET_OK == | 445 | ret = (GNUNET_OK == |
436 | GNUNET_PROGRAM_run (argc, argv, "gnunet-ecc [OPTIONS] keyfile [VANITY_PREFIX]", | 446 | GNUNET_PROGRAM_run (argc, |
447 | argv, | ||
448 | "gnunet-ecc [OPTIONS] keyfile [VANITY_PREFIX]", | ||
437 | gettext_noop ("Manipulate GNUnet private ECC key files"), | 449 | gettext_noop ("Manipulate GNUnet private ECC key files"), |
438 | options, &run, NULL)) ? 0 : 1; | 450 | options, |
451 | &run, | ||
452 | NULL)) ? 0 : 1; | ||
439 | GNUNET_free ((void*) argv); | 453 | GNUNET_free ((void*) argv); |
440 | return ret; | 454 | return ret; |
441 | } | 455 | } |
diff --git a/src/util/gnunet-resolver.c b/src/util/gnunet-resolver.c index e84a2332f..563cf9fce 100644 --- a/src/util/gnunet-resolver.c +++ b/src/util/gnunet-resolver.c | |||
@@ -144,10 +144,11 @@ run (void *cls, char *const *args, const char *cfgfile, | |||
144 | int | 144 | int |
145 | main (int argc, char *const *argv) | 145 | main (int argc, char *const *argv) |
146 | { | 146 | { |
147 | static const struct GNUNET_GETOPT_CommandLineOption options[] = { | 147 | struct GNUNET_GETOPT_CommandLineOption options[] = { |
148 | { 'r', "reverse", NULL, | 148 | GNUNET_GETOPT_OPTION_SET_ONE ('r', |
149 | gettext_noop ("perform a reverse lookup"), | 149 | "reverse", |
150 | 0, &GNUNET_GETOPT_set_one, &reverse }, | 150 | gettext_noop ("perform a reverse lookup"), |
151 | &reverse), | ||
151 | GNUNET_GETOPT_OPTION_END | 152 | GNUNET_GETOPT_OPTION_END |
152 | }; | 153 | }; |
153 | int ret; | 154 | int ret; |
diff --git a/src/util/gnunet-scrypt.c b/src/util/gnunet-scrypt.c index ab0cf92e0..7c73cfe1e 100644 --- a/src/util/gnunet-scrypt.c +++ b/src/util/gnunet-scrypt.c | |||
@@ -307,21 +307,30 @@ run (void *cls, | |||
307 | * @return 0 ok, 1 on error | 307 | * @return 0 ok, 1 on error |
308 | */ | 308 | */ |
309 | int | 309 | int |
310 | main (int argc, char *const *argv) | 310 | main (int argc, |
311 | char *const *argv) | ||
311 | { | 312 | { |
312 | static const struct GNUNET_GETOPT_CommandLineOption options[] = { | 313 | struct GNUNET_GETOPT_CommandLineOption options[] = { |
313 | { 'b', "bits", "BITS", | 314 | GNUNET_GETOPT_OPTION_SET_ULONG ('b', |
314 | gettext_noop ("number of bits to require for the proof of work"), | 315 | "bits", |
315 | 1, &GNUNET_GETOPT_set_ulong, &nse_work_required }, | 316 | "BITS", |
316 | { 'k', "keyfile", "FILE", | 317 | gettext_noop ("number of bits to require for the proof of work"), |
317 | gettext_noop ("file with private key, otherwise default is used"), | 318 | &nse_work_required), |
318 | 1, &GNUNET_GETOPT_set_filename, &pkfn }, | 319 | GNUNET_GETOPT_OPTION_FILENAME ('k', |
319 | { 'o', "outfile", "FILE", | 320 | "keyfile", |
320 | gettext_noop ("file with proof of work, otherwise default is used"), | 321 | "FILE", |
321 | 1, &GNUNET_GETOPT_set_filename, &pwfn }, | 322 | gettext_noop ("file with private key, otherwise default is used"), |
322 | { 't', "timeout", "TIME", | 323 | &pkfn), |
323 | gettext_noop ("time to wait between calculations"), | 324 | GNUNET_GETOPT_OPTION_FILENAME ('o', |
324 | 1, &GNUNET_GETOPT_set_relative_time, &proof_find_delay }, | 325 | "outfile", |
326 | "FILE", | ||
327 | gettext_noop ("file with proof of work, otherwise default is used"), | ||
328 | &pwfn), | ||
329 | GNUNET_GETOPT_OPTION_SET_RELATIVE_TIME ('t', | ||
330 | "timeout", | ||
331 | "TIME", | ||
332 | gettext_noop ("time to wait between calculations"), | ||
333 | &proof_find_delay), | ||
325 | GNUNET_GETOPT_OPTION_END | 334 | GNUNET_GETOPT_OPTION_END |
326 | }; | 335 | }; |
327 | int ret; | 336 | int ret; |
@@ -334,7 +343,9 @@ main (int argc, char *const *argv) | |||
334 | GNUNET_PROGRAM_run (argc, argv, | 343 | GNUNET_PROGRAM_run (argc, argv, |
335 | "gnunet-scrypt [OPTIONS] prooffile", | 344 | "gnunet-scrypt [OPTIONS] prooffile", |
336 | gettext_noop ("Manipulate GNUnet proof of work files"), | 345 | gettext_noop ("Manipulate GNUnet proof of work files"), |
337 | options, &run, NULL)) ? 0 : 1; | 346 | options, |
347 | &run, | ||
348 | NULL)) ? 0 : 1; | ||
338 | GNUNET_free ((void*) argv); | 349 | GNUNET_free ((void*) argv); |
339 | GNUNET_free_non_null (pwfn); | 350 | GNUNET_free_non_null (pwfn); |
340 | return ret; | 351 | return ret; |
diff --git a/src/util/helper.c b/src/util/helper.c index cdb1b01d4..a84b06e66 100644 --- a/src/util/helper.c +++ b/src/util/helper.c | |||
@@ -27,6 +27,7 @@ | |||
27 | */ | 27 | */ |
28 | #include "platform.h" | 28 | #include "platform.h" |
29 | #include "gnunet_util_lib.h" | 29 | #include "gnunet_util_lib.h" |
30 | #include "gnunet_mst_lib.h" | ||
30 | 31 | ||
31 | 32 | ||
32 | /** | 33 | /** |
@@ -107,7 +108,7 @@ struct GNUNET_HELPER_Handle | |||
107 | /** | 108 | /** |
108 | * The Message-Tokenizer that tokenizes the messages comming from the helper | 109 | * The Message-Tokenizer that tokenizes the messages comming from the helper |
109 | */ | 110 | */ |
110 | struct GNUNET_SERVER_MessageStreamTokenizer *mst; | 111 | struct GNUNET_MessageStreamTokenizer *mst; |
111 | 112 | ||
112 | /** | 113 | /** |
113 | * The exception callback | 114 | * The exception callback |
@@ -272,7 +273,10 @@ GNUNET_HELPER_wait (struct GNUNET_HELPER_Handle *h) | |||
272 | } | 273 | } |
273 | /* purge MST buffer */ | 274 | /* purge MST buffer */ |
274 | if (NULL != h->mst) | 275 | if (NULL != h->mst) |
275 | (void) GNUNET_SERVER_mst_receive (h->mst, NULL, NULL, 0, GNUNET_YES, GNUNET_NO); | 276 | (void) GNUNET_MST_from_buffer (h->mst, |
277 | NULL, 0, | ||
278 | GNUNET_YES, | ||
279 | GNUNET_NO); | ||
276 | return ret; | 280 | return ret; |
277 | } | 281 | } |
278 | 282 | ||
@@ -319,7 +323,7 @@ static void | |||
319 | helper_read (void *cls) | 323 | helper_read (void *cls) |
320 | { | 324 | { |
321 | struct GNUNET_HELPER_Handle *h = cls; | 325 | struct GNUNET_HELPER_Handle *h = cls; |
322 | char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE] GNUNET_ALIGN; | 326 | char buf[GNUNET_MAX_MESSAGE_SIZE] GNUNET_ALIGN; |
323 | ssize_t t; | 327 | ssize_t t; |
324 | 328 | ||
325 | h->read_task = NULL; | 329 | h->read_task = NULL; |
@@ -373,10 +377,10 @@ helper_read (void *cls) | |||
373 | h->fh_from_helper, | 377 | h->fh_from_helper, |
374 | &helper_read, h); | 378 | &helper_read, h); |
375 | if (GNUNET_SYSERR == | 379 | if (GNUNET_SYSERR == |
376 | GNUNET_SERVER_mst_receive (h->mst, | 380 | GNUNET_MST_from_buffer (h->mst, |
377 | NULL, | 381 | buf, t, |
378 | buf, t, | 382 | GNUNET_NO, |
379 | GNUNET_NO, GNUNET_NO)) | 383 | GNUNET_NO)) |
380 | { | 384 | { |
381 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | 385 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, |
382 | _("Failed to parse inbound message from helper `%s'\n"), | 386 | _("Failed to parse inbound message from helper `%s'\n"), |
@@ -487,7 +491,7 @@ struct GNUNET_HELPER_Handle * | |||
487 | GNUNET_HELPER_start (int with_control_pipe, | 491 | GNUNET_HELPER_start (int with_control_pipe, |
488 | const char *binary_name, | 492 | const char *binary_name, |
489 | char *const binary_argv[], | 493 | char *const binary_argv[], |
490 | GNUNET_SERVER_MessageTokenizerCallback cb, | 494 | GNUNET_MessageTokenizerCallback cb, |
491 | GNUNET_HELPER_ExceptionCallback exp_cb, | 495 | GNUNET_HELPER_ExceptionCallback exp_cb, |
492 | void *cb_cls) | 496 | void *cb_cls) |
493 | { | 497 | { |
@@ -508,7 +512,8 @@ GNUNET_HELPER_start (int with_control_pipe, | |||
508 | h->binary_argv[c] = NULL; | 512 | h->binary_argv[c] = NULL; |
509 | h->cb_cls = cb_cls; | 513 | h->cb_cls = cb_cls; |
510 | if (NULL != cb) | 514 | if (NULL != cb) |
511 | h->mst = GNUNET_SERVER_mst_create (cb, h->cb_cls); | 515 | h->mst = GNUNET_MST_create (cb, |
516 | h->cb_cls); | ||
512 | h->exp_cb = exp_cb; | 517 | h->exp_cb = exp_cb; |
513 | h->retry_back_off = 0; | 518 | h->retry_back_off = 0; |
514 | start_helper (h); | 519 | start_helper (h); |
@@ -544,7 +549,7 @@ GNUNET_HELPER_destroy (struct GNUNET_HELPER_Handle *h) | |||
544 | GNUNET_free (sh); | 549 | GNUNET_free (sh); |
545 | } | 550 | } |
546 | if (NULL != h->mst) | 551 | if (NULL != h->mst) |
547 | GNUNET_SERVER_mst_destroy (h->mst); | 552 | GNUNET_MST_destroy (h->mst); |
548 | GNUNET_free (h->binary_name); | 553 | GNUNET_free (h->binary_name); |
549 | for (c = 0; h->binary_argv[c] != NULL; c++) | 554 | for (c = 0; h->binary_argv[c] != NULL; c++) |
550 | GNUNET_free (h->binary_argv[c]); | 555 | GNUNET_free (h->binary_argv[c]); |
diff --git a/src/util/mq.c b/src/util/mq.c index 79e2d0455..90b2aa968 100644 --- a/src/util/mq.c +++ b/src/util/mq.c | |||
@@ -202,24 +202,6 @@ struct GNUNET_MQ_Handle | |||
202 | 202 | ||
203 | 203 | ||
204 | /** | 204 | /** |
205 | * Implementation-specific state for connection to | ||
206 | * client (MQ for server). | ||
207 | */ | ||
208 | struct ServerClientSocketState | ||
209 | { | ||
210 | /** | ||
211 | * Handle of the client that connected to the server. | ||
212 | */ | ||
213 | struct GNUNET_SERVER_Client *client; | ||
214 | |||
215 | /** | ||
216 | * Active transmission request to the client. | ||
217 | */ | ||
218 | struct GNUNET_SERVER_TransmitHandle *th; | ||
219 | }; | ||
220 | |||
221 | |||
222 | /** | ||
223 | * Call the message message handler that was registered | 205 | * Call the message message handler that was registered |
224 | * for the type of the given message in the given message queue. | 206 | * for the type of the given message in the given message queue. |
225 | * | 207 | * |
@@ -708,92 +690,6 @@ GNUNET_MQ_msg_nested_mh_ (struct GNUNET_MessageHeader **mhp, | |||
708 | 690 | ||
709 | 691 | ||
710 | /** | 692 | /** |
711 | * Transmit a queued message to the session's client. | ||
712 | * | ||
713 | * @param cls consensus session | ||
714 | * @param size number of bytes available in @a buf | ||
715 | * @param buf where the callee should write the message | ||
716 | * @return number of bytes written to @a buf | ||
717 | */ | ||
718 | static size_t | ||
719 | transmit_queued (void *cls, | ||
720 | size_t size, | ||
721 | void *buf) | ||
722 | { | ||
723 | struct GNUNET_MQ_Handle *mq = cls; | ||
724 | struct ServerClientSocketState *state = GNUNET_MQ_impl_state (mq); | ||
725 | const struct GNUNET_MessageHeader *msg = GNUNET_MQ_impl_current (mq); | ||
726 | size_t msg_size; | ||
727 | |||
728 | GNUNET_assert (NULL != buf); | ||
729 | msg_size = ntohs (msg->size); | ||
730 | GNUNET_assert (size >= msg_size); | ||
731 | GNUNET_memcpy (buf, msg, msg_size); | ||
732 | state->th = NULL; | ||
733 | |||
734 | GNUNET_MQ_impl_send_continue (mq); | ||
735 | |||
736 | return msg_size; | ||
737 | } | ||
738 | |||
739 | |||
740 | static void | ||
741 | server_client_destroy_impl (struct GNUNET_MQ_Handle *mq, | ||
742 | void *impl_state) | ||
743 | { | ||
744 | struct ServerClientSocketState *state = impl_state; | ||
745 | |||
746 | if (NULL != state->th) | ||
747 | { | ||
748 | GNUNET_SERVER_notify_transmit_ready_cancel (state->th); | ||
749 | state->th = NULL; | ||
750 | } | ||
751 | |||
752 | GNUNET_assert (NULL != mq); | ||
753 | GNUNET_assert (NULL != state); | ||
754 | GNUNET_SERVER_client_drop (state->client); | ||
755 | GNUNET_free (state); | ||
756 | } | ||
757 | |||
758 | |||
759 | static void | ||
760 | server_client_send_impl (struct GNUNET_MQ_Handle *mq, | ||
761 | const struct GNUNET_MessageHeader *msg, | ||
762 | void *impl_state) | ||
763 | { | ||
764 | GNUNET_assert (NULL != mq); | ||
765 | |||
766 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
767 | "Sending message of type %u and size %u\n", | ||
768 | ntohs (msg->type), ntohs (msg->size)); | ||
769 | |||
770 | struct ServerClientSocketState *state = impl_state; | ||
771 | state->th = GNUNET_SERVER_notify_transmit_ready (state->client, | ||
772 | ntohs (msg->size), | ||
773 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
774 | &transmit_queued, | ||
775 | mq); | ||
776 | } | ||
777 | |||
778 | |||
779 | struct GNUNET_MQ_Handle * | ||
780 | GNUNET_MQ_queue_for_server_client (struct GNUNET_SERVER_Client *client) | ||
781 | { | ||
782 | struct GNUNET_MQ_Handle *mq; | ||
783 | struct ServerClientSocketState *scss; | ||
784 | |||
785 | mq = GNUNET_new (struct GNUNET_MQ_Handle); | ||
786 | scss = GNUNET_new (struct ServerClientSocketState); | ||
787 | mq->impl_state = scss; | ||
788 | scss->client = client; | ||
789 | GNUNET_SERVER_client_keep (client); | ||
790 | mq->send_impl = &server_client_send_impl; | ||
791 | mq->destroy_impl = &server_client_destroy_impl; | ||
792 | return mq; | ||
793 | } | ||
794 | |||
795 | |||
796 | /** | ||
797 | * Associate the assoc_data in mq with a unique request id. | 693 | * Associate the assoc_data in mq with a unique request id. |
798 | * | 694 | * |
799 | * @param mq message queue, id will be unique for the queue | 695 | * @param mq message queue, id will be unique for the queue |
@@ -811,22 +707,40 @@ GNUNET_MQ_assoc_add (struct GNUNET_MQ_Handle *mq, | |||
811 | mq->assoc_id = 1; | 707 | mq->assoc_id = 1; |
812 | } | 708 | } |
813 | id = mq->assoc_id++; | 709 | id = mq->assoc_id++; |
814 | GNUNET_CONTAINER_multihashmap32_put (mq->assoc_map, id, assoc_data, | 710 | GNUNET_assert (GNUNET_OK == |
815 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY); | 711 | GNUNET_CONTAINER_multihashmap32_put (mq->assoc_map, |
712 | id, | ||
713 | assoc_data, | ||
714 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
816 | return id; | 715 | return id; |
817 | } | 716 | } |
818 | 717 | ||
819 | 718 | ||
719 | /** | ||
720 | * Get the data associated with a @a request_id in a queue | ||
721 | * | ||
722 | * @param mq the message queue with the association | ||
723 | * @param request_id the request id we are interested in | ||
724 | * @return the associated data | ||
725 | */ | ||
820 | void * | 726 | void * |
821 | GNUNET_MQ_assoc_get (struct GNUNET_MQ_Handle *mq, | 727 | GNUNET_MQ_assoc_get (struct GNUNET_MQ_Handle *mq, |
822 | uint32_t request_id) | 728 | uint32_t request_id) |
823 | { | 729 | { |
824 | if (NULL == mq->assoc_map) | 730 | if (NULL == mq->assoc_map) |
825 | return NULL; | 731 | return NULL; |
826 | return GNUNET_CONTAINER_multihashmap32_get (mq->assoc_map, request_id); | 732 | return GNUNET_CONTAINER_multihashmap32_get (mq->assoc_map, |
733 | request_id); | ||
827 | } | 734 | } |
828 | 735 | ||
829 | 736 | ||
737 | /** | ||
738 | * Remove the association for a @a request_id | ||
739 | * | ||
740 | * @param mq the message queue with the association | ||
741 | * @param request_id the request id we want to remove | ||
742 | * @return the associated data | ||
743 | */ | ||
830 | void * | 744 | void * |
831 | GNUNET_MQ_assoc_remove (struct GNUNET_MQ_Handle *mq, | 745 | GNUNET_MQ_assoc_remove (struct GNUNET_MQ_Handle *mq, |
832 | uint32_t request_id) | 746 | uint32_t request_id) |
diff --git a/src/util/mst.c b/src/util/mst.c index 9f1d30d7a..0d90c5d10 100644 --- a/src/util/mst.c +++ b/src/util/mst.c | |||
@@ -90,8 +90,8 @@ GNUNET_MST_create (GNUNET_MessageTokenizerCallback cb, | |||
90 | struct GNUNET_MessageStreamTokenizer *ret; | 90 | struct GNUNET_MessageStreamTokenizer *ret; |
91 | 91 | ||
92 | ret = GNUNET_new (struct GNUNET_MessageStreamTokenizer); | 92 | ret = GNUNET_new (struct GNUNET_MessageStreamTokenizer); |
93 | ret->hdr = GNUNET_malloc (GNUNET_SERVER_MIN_BUFFER_SIZE); | 93 | ret->hdr = GNUNET_malloc (GNUNET_MIN_MESSAGE_SIZE); |
94 | ret->curr_buf = GNUNET_SERVER_MIN_BUFFER_SIZE; | 94 | ret->curr_buf = GNUNET_MIN_MESSAGE_SIZE; |
95 | ret->cb = cb; | 95 | ret->cb = cb; |
96 | ret->cb_cls = cb_cls; | 96 | ret->cb_cls = cb_cls; |
97 | return ret; | 97 | return ret; |
diff --git a/src/util/resolver_api.c b/src/util/resolver_api.c index f33c31f1c..0c915932c 100644 --- a/src/util/resolver_api.c +++ b/src/util/resolver_api.c | |||
@@ -876,7 +876,7 @@ GNUNET_RESOLVER_ip_get (const char *hostname, | |||
876 | 876 | ||
877 | slen = strlen (hostname) + 1; | 877 | slen = strlen (hostname) + 1; |
878 | if (slen + sizeof (struct GNUNET_RESOLVER_GetMessage) >= | 878 | if (slen + sizeof (struct GNUNET_RESOLVER_GetMessage) >= |
879 | GNUNET_SERVER_MAX_MESSAGE_SIZE) | 879 | GNUNET_MAX_MESSAGE_SIZE) |
880 | { | 880 | { |
881 | GNUNET_break (0); | 881 | GNUNET_break (0); |
882 | return NULL; | 882 | return NULL; |
diff --git a/src/util/server.c b/src/util/server.c deleted file mode 100644 index 83c30e328..000000000 --- a/src/util/server.c +++ /dev/null | |||
@@ -1,1752 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009-2013 GNUnet e.V. | ||
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., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file util/server.c | ||
23 | * @brief library for building GNUnet network servers | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | |||
27 | #include "platform.h" | ||
28 | #include "gnunet_util_lib.h" | ||
29 | #include "gnunet_protocols.h" | ||
30 | |||
31 | #define LOG(kind,...) GNUNET_log_from (kind, "util-server", __VA_ARGS__) | ||
32 | |||
33 | #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-server", syscall) | ||
34 | |||
35 | #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util-server", syscall, filename) | ||
36 | |||
37 | |||
38 | /** | ||
39 | * List of arrays of message handlers. | ||
40 | */ | ||
41 | struct HandlerList | ||
42 | { | ||
43 | /** | ||
44 | * This is a linked list. | ||
45 | */ | ||
46 | struct HandlerList *next; | ||
47 | |||
48 | /** | ||
49 | * NULL-terminated array of handlers. | ||
50 | */ | ||
51 | const struct GNUNET_SERVER_MessageHandler *handlers; | ||
52 | }; | ||
53 | |||
54 | |||
55 | /** | ||
56 | * List of arrays of message handlers. | ||
57 | */ | ||
58 | struct NotifyList | ||
59 | { | ||
60 | /** | ||
61 | * This is a doubly linked list. | ||
62 | */ | ||
63 | struct NotifyList *next; | ||
64 | |||
65 | /** | ||
66 | * This is a doubly linked list. | ||
67 | */ | ||
68 | struct NotifyList *prev; | ||
69 | |||
70 | /** | ||
71 | * Function to call. | ||
72 | */ | ||
73 | GNUNET_SERVER_DisconnectCallback callback; | ||
74 | |||
75 | /** | ||
76 | * Closure for callback. | ||
77 | */ | ||
78 | void *callback_cls; | ||
79 | }; | ||
80 | |||
81 | |||
82 | /** | ||
83 | * @brief handle for a server | ||
84 | */ | ||
85 | struct GNUNET_SERVER_Handle | ||
86 | { | ||
87 | /** | ||
88 | * List of handlers for incoming messages. | ||
89 | */ | ||
90 | struct HandlerList *handlers; | ||
91 | |||
92 | /** | ||
93 | * Head of list of our current clients. | ||
94 | */ | ||
95 | struct GNUNET_SERVER_Client *clients_head; | ||
96 | |||
97 | /** | ||
98 | * Head of list of our current clients. | ||
99 | */ | ||
100 | struct GNUNET_SERVER_Client *clients_tail; | ||
101 | |||
102 | /** | ||
103 | * Head of linked list of functions to call on disconnects by clients. | ||
104 | */ | ||
105 | struct NotifyList *disconnect_notify_list_head; | ||
106 | |||
107 | /** | ||
108 | * Tail of linked list of functions to call on disconnects by clients. | ||
109 | */ | ||
110 | struct NotifyList *disconnect_notify_list_tail; | ||
111 | |||
112 | /** | ||
113 | * Head of linked list of functions to call on connects by clients. | ||
114 | */ | ||
115 | struct NotifyList *connect_notify_list_head; | ||
116 | |||
117 | /** | ||
118 | * Tail of linked list of functions to call on connects by clients. | ||
119 | */ | ||
120 | struct NotifyList *connect_notify_list_tail; | ||
121 | |||
122 | /** | ||
123 | * Function to call for access control. | ||
124 | */ | ||
125 | GNUNET_CONNECTION_AccessCheck access_cb; | ||
126 | |||
127 | /** | ||
128 | * Closure for @e access_cb. | ||
129 | */ | ||
130 | void *access_cb_cls; | ||
131 | |||
132 | /** | ||
133 | * NULL-terminated array of sockets used to listen for new | ||
134 | * connections. | ||
135 | */ | ||
136 | struct GNUNET_NETWORK_Handle **listen_sockets; | ||
137 | |||
138 | /** | ||
139 | * After how long should an idle connection time | ||
140 | * out (on write). | ||
141 | */ | ||
142 | struct GNUNET_TIME_Relative idle_timeout; | ||
143 | |||
144 | /** | ||
145 | * Task scheduled to do the listening. | ||
146 | */ | ||
147 | struct GNUNET_SCHEDULER_Task * listen_task; | ||
148 | |||
149 | /** | ||
150 | * Alternative function to create a MST instance. | ||
151 | */ | ||
152 | GNUNET_SERVER_MstCreateCallback mst_create; | ||
153 | |||
154 | /** | ||
155 | * Alternative function to destroy a MST instance. | ||
156 | */ | ||
157 | GNUNET_SERVER_MstDestroyCallback mst_destroy; | ||
158 | |||
159 | /** | ||
160 | * Alternative function to give data to a MST instance. | ||
161 | */ | ||
162 | GNUNET_SERVER_MstReceiveCallback mst_receive; | ||
163 | |||
164 | /** | ||
165 | * Closure for 'mst_'-callbacks. | ||
166 | */ | ||
167 | void *mst_cls; | ||
168 | |||
169 | /** | ||
170 | * Do we ignore messages of types that we do not understand or do we | ||
171 | * require that a handler is found (and if not kill the connection)? | ||
172 | */ | ||
173 | int require_found; | ||
174 | |||
175 | /** | ||
176 | * Set to #GNUNET_YES once we are in 'soft' shutdown where we wait for | ||
177 | * all non-monitor clients to disconnect before we call | ||
178 | * #GNUNET_SERVER_destroy. See test_monitor_clients(). Set to | ||
179 | * #GNUNET_SYSERR once the final destroy task has been scheduled | ||
180 | * (we cannot run it in the same task). | ||
181 | */ | ||
182 | int in_soft_shutdown; | ||
183 | }; | ||
184 | |||
185 | |||
186 | /** | ||
187 | * Handle server returns for aborting transmission to a client. | ||
188 | */ | ||
189 | struct GNUNET_SERVER_TransmitHandle | ||
190 | { | ||
191 | /** | ||
192 | * Function to call to get the message. | ||
193 | */ | ||
194 | GNUNET_CONNECTION_TransmitReadyNotify callback; | ||
195 | |||
196 | /** | ||
197 | * Closure for @e callback | ||
198 | */ | ||
199 | void *callback_cls; | ||
200 | |||
201 | /** | ||
202 | * Active connection transmission handle. | ||
203 | */ | ||
204 | struct GNUNET_CONNECTION_TransmitHandle *cth; | ||
205 | |||
206 | }; | ||
207 | |||
208 | |||
209 | /** | ||
210 | * @brief handle for a client of the server | ||
211 | */ | ||
212 | struct GNUNET_SERVER_Client | ||
213 | { | ||
214 | |||
215 | /** | ||
216 | * This is a doubly linked list. | ||
217 | */ | ||
218 | struct GNUNET_SERVER_Client *next; | ||
219 | |||
220 | /** | ||
221 | * This is a doubly linked list. | ||
222 | */ | ||
223 | struct GNUNET_SERVER_Client *prev; | ||
224 | |||
225 | /** | ||
226 | * Processing of incoming data. | ||
227 | */ | ||
228 | void *mst; | ||
229 | |||
230 | /** | ||
231 | * Server that this client belongs to. | ||
232 | */ | ||
233 | struct GNUNET_SERVER_Handle *server; | ||
234 | |||
235 | /** | ||
236 | * Client closure for callbacks. | ||
237 | */ | ||
238 | struct GNUNET_CONNECTION_Handle *connection; | ||
239 | |||
240 | /** | ||
241 | * User context value, manipulated using | ||
242 | * 'GNUNET_SERVER_client_{get/set}_user_context' functions. | ||
243 | */ | ||
244 | void *user_context; | ||
245 | |||
246 | /** | ||
247 | * ID of task used to restart processing. | ||
248 | */ | ||
249 | struct GNUNET_SCHEDULER_Task * restart_task; | ||
250 | |||
251 | /** | ||
252 | * Task that warns about missing calls to #GNUNET_SERVER_receive_done. | ||
253 | */ | ||
254 | struct GNUNET_SCHEDULER_Task * warn_task; | ||
255 | |||
256 | /** | ||
257 | * Time when the warn task was started. | ||
258 | */ | ||
259 | struct GNUNET_TIME_Absolute warn_start; | ||
260 | |||
261 | /** | ||
262 | * Last activity on this socket (used to time it out | ||
263 | * if reference_count == 0). | ||
264 | */ | ||
265 | struct GNUNET_TIME_Absolute last_activity; | ||
266 | |||
267 | /** | ||
268 | * Transmission handle we return for this client from | ||
269 | * #GNUNET_SERVER_notify_transmit_ready. | ||
270 | */ | ||
271 | struct GNUNET_SERVER_TransmitHandle th; | ||
272 | |||
273 | /** | ||
274 | * After how long should an idle connection time | ||
275 | * out (on write). | ||
276 | */ | ||
277 | struct GNUNET_TIME_Relative idle_timeout; | ||
278 | |||
279 | /** | ||
280 | * Number of external entities with a reference to | ||
281 | * this client object. | ||
282 | */ | ||
283 | unsigned int reference_count; | ||
284 | |||
285 | /** | ||
286 | * Was processing if incoming messages suspended while | ||
287 | * we were still processing data already received? | ||
288 | * This is a counter saying how often processing was | ||
289 | * suspended (once per handler invoked). | ||
290 | */ | ||
291 | unsigned int suspended; | ||
292 | |||
293 | /** | ||
294 | * Last size given when user context was initialized; used for | ||
295 | * sanity check. | ||
296 | */ | ||
297 | size_t user_context_size; | ||
298 | |||
299 | /** | ||
300 | * Are we currently in the "process_client_buffer" function (and | ||
301 | * will hence restart the receive job on exit if suspended == 0 once | ||
302 | * we are done?). If this is set, then "receive_done" will | ||
303 | * essentially only decrement suspended; if this is not set, then | ||
304 | * "receive_done" may need to restart the receive process (either | ||
305 | * from the side-buffer or via select/recv). | ||
306 | */ | ||
307 | int in_process_client_buffer; | ||
308 | |||
309 | /** | ||
310 | * We're about to close down this client. | ||
311 | */ | ||
312 | int shutdown_now; | ||
313 | |||
314 | /** | ||
315 | * Are we currently trying to receive? (#GNUNET_YES if we are, | ||
316 | * #GNUNET_NO if we are not, #GNUNET_SYSERR if data is already | ||
317 | * available in MST). | ||
318 | */ | ||
319 | int receive_pending; | ||
320 | |||
321 | /** | ||
322 | * Persist the file handle for this client no matter what happens, | ||
323 | * force the OS to close once the process actually dies. Should only | ||
324 | * be used in special cases! | ||
325 | */ | ||
326 | int persist; | ||
327 | |||
328 | /** | ||
329 | * Is this client a 'monitor' client that should not be counted | ||
330 | * when deciding on destroying the server during soft shutdown? | ||
331 | * (see also #GNUNET_SERVICE_start) | ||
332 | */ | ||
333 | int is_monitor; | ||
334 | |||
335 | /** | ||
336 | * Type of last message processed (for warn_no_receive_done). | ||
337 | */ | ||
338 | uint16_t warn_type; | ||
339 | }; | ||
340 | |||
341 | |||
342 | |||
343 | /** | ||
344 | * Return user context associated with the given client. | ||
345 | * Note: you should probably use the macro (call without the underscore). | ||
346 | * | ||
347 | * @param client client to query | ||
348 | * @param size number of bytes in user context struct (for verification only) | ||
349 | * @return pointer to user context | ||
350 | */ | ||
351 | void * | ||
352 | GNUNET_SERVER_client_get_user_context_ (struct GNUNET_SERVER_Client *client, | ||
353 | size_t size) | ||
354 | { | ||
355 | if ((0 == client->user_context_size) && | ||
356 | (NULL == client->user_context)) | ||
357 | return NULL; /* never set */ | ||
358 | GNUNET_assert (size == client->user_context_size); | ||
359 | return client->user_context; | ||
360 | } | ||
361 | |||
362 | |||
363 | /** | ||
364 | * Set user context to be associated with the given client. | ||
365 | * Note: you should probably use the macro (call without the underscore). | ||
366 | * | ||
367 | * @param client client to query | ||
368 | * @param ptr pointer to user context | ||
369 | * @param size number of bytes in user context struct (for verification only) | ||
370 | */ | ||
371 | void | ||
372 | GNUNET_SERVER_client_set_user_context_ (struct GNUNET_SERVER_Client *client, | ||
373 | void *ptr, | ||
374 | size_t size) | ||
375 | { | ||
376 | if (NULL == ptr) | ||
377 | { | ||
378 | client->user_context_size = 0; | ||
379 | client->user_context = ptr; | ||
380 | return; | ||
381 | } | ||
382 | client->user_context_size = size; | ||
383 | client->user_context = ptr; | ||
384 | } | ||
385 | |||
386 | |||
387 | /** | ||
388 | * Scheduler says our listen socket is ready. Process it! | ||
389 | * | ||
390 | * @param cls handle to our server for which we are processing the listen | ||
391 | * socket | ||
392 | */ | ||
393 | static void | ||
394 | process_listen_socket (void *cls) | ||
395 | { | ||
396 | struct GNUNET_SERVER_Handle *server = cls; | ||
397 | const struct GNUNET_SCHEDULER_TaskContext *tc; | ||
398 | struct GNUNET_CONNECTION_Handle *sock; | ||
399 | unsigned int i; | ||
400 | |||
401 | server->listen_task = NULL; | ||
402 | tc = GNUNET_SCHEDULER_get_task_context (); | ||
403 | for (i = 0; NULL != server->listen_sockets[i]; i++) | ||
404 | { | ||
405 | if (GNUNET_NETWORK_fdset_isset (tc->read_ready, | ||
406 | server->listen_sockets[i])) | ||
407 | { | ||
408 | sock = | ||
409 | GNUNET_CONNECTION_create_from_accept (server->access_cb, | ||
410 | server->access_cb_cls, | ||
411 | server->listen_sockets[i]); | ||
412 | if (NULL != sock) | ||
413 | { | ||
414 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
415 | "Server accepted incoming connection.\n"); | ||
416 | (void) GNUNET_SERVER_connect_socket (server, | ||
417 | sock); | ||
418 | } | ||
419 | } | ||
420 | } | ||
421 | /* listen for more! */ | ||
422 | GNUNET_SERVER_resume (server); | ||
423 | } | ||
424 | |||
425 | |||
426 | /** | ||
427 | * Create and initialize a listen socket for the server. | ||
428 | * | ||
429 | * @param server_addr address to listen on | ||
430 | * @param socklen length of @a server_addr | ||
431 | * @return NULL on error, otherwise the listen socket | ||
432 | */ | ||
433 | static struct GNUNET_NETWORK_Handle * | ||
434 | open_listen_socket (const struct sockaddr *server_addr, | ||
435 | socklen_t socklen) | ||
436 | { | ||
437 | struct GNUNET_NETWORK_Handle *sock; | ||
438 | uint16_t port; | ||
439 | int eno; | ||
440 | |||
441 | switch (server_addr->sa_family) | ||
442 | { | ||
443 | case AF_INET: | ||
444 | port = ntohs (((const struct sockaddr_in *) server_addr)->sin_port); | ||
445 | break; | ||
446 | case AF_INET6: | ||
447 | port = ntohs (((const struct sockaddr_in6 *) server_addr)->sin6_port); | ||
448 | break; | ||
449 | case AF_UNIX: | ||
450 | port = 0; | ||
451 | break; | ||
452 | default: | ||
453 | GNUNET_break (0); | ||
454 | port = 0; | ||
455 | break; | ||
456 | } | ||
457 | sock = GNUNET_NETWORK_socket_create (server_addr->sa_family, SOCK_STREAM, 0); | ||
458 | if (NULL == sock) | ||
459 | { | ||
460 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket"); | ||
461 | errno = 0; | ||
462 | return NULL; | ||
463 | } | ||
464 | /* bind the socket */ | ||
465 | if (GNUNET_OK != GNUNET_NETWORK_socket_bind (sock, server_addr, socklen)) | ||
466 | { | ||
467 | eno = errno; | ||
468 | if (EADDRINUSE != errno) | ||
469 | { | ||
470 | /* we don't log 'EADDRINUSE' here since an IPv4 bind may | ||
471 | * fail if we already took the port on IPv6; if both IPv4 and | ||
472 | * IPv6 binds fail, then our caller will log using the | ||
473 | * errno preserved in 'eno' */ | ||
474 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, | ||
475 | "bind"); | ||
476 | if (0 != port) | ||
477 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
478 | _("`%s' failed for port %d (%s).\n"), | ||
479 | "bind", | ||
480 | port, | ||
481 | (AF_INET == server_addr->sa_family) ? "IPv4" : "IPv6"); | ||
482 | eno = 0; | ||
483 | } | ||
484 | else | ||
485 | { | ||
486 | if (0 != port) | ||
487 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
488 | _("`%s' failed for port %d (%s): address already in use\n"), | ||
489 | "bind", port, | ||
490 | (AF_INET == server_addr->sa_family) ? "IPv4" : "IPv6"); | ||
491 | else if (AF_UNIX == server_addr->sa_family) | ||
492 | { | ||
493 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
494 | _("`%s' failed for `%s': address already in use\n"), | ||
495 | "bind", | ||
496 | GNUNET_a2s (server_addr, socklen)); | ||
497 | } | ||
498 | } | ||
499 | GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock)); | ||
500 | errno = eno; | ||
501 | return NULL; | ||
502 | } | ||
503 | if (GNUNET_OK != GNUNET_NETWORK_socket_listen (sock, 5)) | ||
504 | { | ||
505 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, | ||
506 | "listen"); | ||
507 | GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock)); | ||
508 | errno = 0; | ||
509 | return NULL; | ||
510 | } | ||
511 | if (0 != port) | ||
512 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
513 | "Server starts to listen on port %u.\n", | ||
514 | port); | ||
515 | return sock; | ||
516 | } | ||
517 | |||
518 | |||
519 | /** | ||
520 | * Create a new server. | ||
521 | * | ||
522 | * @param access_cb function for access control | ||
523 | * @param access_cb_cls closure for @a access_cb | ||
524 | * @param lsocks NULL-terminated array of listen sockets | ||
525 | * @param idle_timeout after how long should we timeout idle connections? | ||
526 | * @param require_found if #GNUNET_YES, connections sending messages of unknown type | ||
527 | * will be closed | ||
528 | * @return handle for the new server, NULL on error | ||
529 | * (typically, "port" already in use) | ||
530 | */ | ||
531 | struct GNUNET_SERVER_Handle * | ||
532 | GNUNET_SERVER_create_with_sockets (GNUNET_CONNECTION_AccessCheck access_cb, | ||
533 | void *access_cb_cls, | ||
534 | struct GNUNET_NETWORK_Handle **lsocks, | ||
535 | struct GNUNET_TIME_Relative idle_timeout, | ||
536 | int require_found) | ||
537 | { | ||
538 | struct GNUNET_SERVER_Handle *server; | ||
539 | |||
540 | server = GNUNET_new (struct GNUNET_SERVER_Handle); | ||
541 | server->idle_timeout = idle_timeout; | ||
542 | server->listen_sockets = lsocks; | ||
543 | server->access_cb = access_cb; | ||
544 | server->access_cb_cls = access_cb_cls; | ||
545 | server->require_found = require_found; | ||
546 | if (NULL != lsocks) | ||
547 | GNUNET_SERVER_resume (server); | ||
548 | return server; | ||
549 | } | ||
550 | |||
551 | |||
552 | /** | ||
553 | * Create a new server. | ||
554 | * | ||
555 | * @param access_cb function for access control | ||
556 | * @param access_cb_cls closure for @a access_cb | ||
557 | * @param server_addr address to listen on (including port), NULL terminated array | ||
558 | * @param socklen length of server_addr | ||
559 | * @param idle_timeout after how long should we timeout idle connections? | ||
560 | * @param require_found if YES, connections sending messages of unknown type | ||
561 | * will be closed | ||
562 | * @return handle for the new server, NULL on error | ||
563 | * (typically, "port" already in use) | ||
564 | */ | ||
565 | struct GNUNET_SERVER_Handle * | ||
566 | GNUNET_SERVER_create (GNUNET_CONNECTION_AccessCheck access_cb, | ||
567 | void *access_cb_cls, | ||
568 | struct sockaddr *const *server_addr, | ||
569 | const socklen_t * socklen, | ||
570 | struct GNUNET_TIME_Relative idle_timeout, | ||
571 | int require_found) | ||
572 | { | ||
573 | struct GNUNET_NETWORK_Handle **lsocks; | ||
574 | unsigned int i; | ||
575 | unsigned int j; | ||
576 | unsigned int k; | ||
577 | int seen; | ||
578 | |||
579 | i = 0; | ||
580 | while (NULL != server_addr[i]) | ||
581 | i++; | ||
582 | if (i > 0) | ||
583 | { | ||
584 | lsocks = GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (i + 1)); | ||
585 | i = 0; | ||
586 | j = 0; | ||
587 | while (NULL != server_addr[i]) | ||
588 | { | ||
589 | seen = 0; | ||
590 | for (k=0;k<i;k++) | ||
591 | if ( (socklen[k] == socklen[i]) && | ||
592 | (0 == memcmp (server_addr[k], server_addr[i], socklen[i])) ) | ||
593 | { | ||
594 | seen = 1; | ||
595 | break; | ||
596 | } | ||
597 | if (0 != seen) | ||
598 | { | ||
599 | /* duplicate address, skip */ | ||
600 | i++; | ||
601 | continue; | ||
602 | } | ||
603 | lsocks[j] = open_listen_socket (server_addr[i], socklen[i]); | ||
604 | if (NULL != lsocks[j]) | ||
605 | j++; | ||
606 | i++; | ||
607 | } | ||
608 | if (0 == j) | ||
609 | { | ||
610 | if (0 != errno) | ||
611 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "bind"); | ||
612 | GNUNET_free (lsocks); | ||
613 | lsocks = NULL; | ||
614 | } | ||
615 | } | ||
616 | else | ||
617 | { | ||
618 | lsocks = NULL; | ||
619 | } | ||
620 | return GNUNET_SERVER_create_with_sockets (access_cb, | ||
621 | access_cb_cls, | ||
622 | lsocks, | ||
623 | idle_timeout, | ||
624 | require_found); | ||
625 | } | ||
626 | |||
627 | |||
628 | /** | ||
629 | * Set the 'monitor' flag on this client. Clients which have been | ||
630 | * marked as 'monitors' won't prevent the server from shutting down | ||
631 | * once '#GNUNET_SERVER_stop_listening()' has been invoked. The idea is | ||
632 | * that for "normal" clients we likely want to allow them to process | ||
633 | * their requests; however, monitor-clients are likely to 'never' | ||
634 | * disconnect during shutdown and thus will not be considered when | ||
635 | * determining if the server should continue to exist after | ||
636 | * #GNUNET_SERVER_destroy() has been called. | ||
637 | * | ||
638 | * @param client the client to set the 'monitor' flag on | ||
639 | */ | ||
640 | void | ||
641 | GNUNET_SERVER_client_mark_monitor (struct GNUNET_SERVER_Client *client) | ||
642 | { | ||
643 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
644 | "Marking client as monitor!\n"); | ||
645 | client->is_monitor = GNUNET_YES; | ||
646 | } | ||
647 | |||
648 | |||
649 | /** | ||
650 | * Helper function for #test_monitor_clients() to trigger | ||
651 | * #GNUNET_SERVER_destroy() after the stack has unwound. | ||
652 | * | ||
653 | * @param cls the `struct GNUNET_SERVER_Handle *` to destroy | ||
654 | */ | ||
655 | static void | ||
656 | do_destroy (void *cls) | ||
657 | { | ||
658 | struct GNUNET_SERVER_Handle *server = cls; | ||
659 | |||
660 | GNUNET_SERVER_destroy (server); | ||
661 | } | ||
662 | |||
663 | |||
664 | /** | ||
665 | * Check if only 'monitor' clients are left. If so, destroy the | ||
666 | * server completely. | ||
667 | * | ||
668 | * @param server server to test for full shutdown | ||
669 | */ | ||
670 | static void | ||
671 | test_monitor_clients (struct GNUNET_SERVER_Handle *server) | ||
672 | { | ||
673 | struct GNUNET_SERVER_Client *client; | ||
674 | |||
675 | if (GNUNET_YES != server->in_soft_shutdown) | ||
676 | return; | ||
677 | for (client = server->clients_head; NULL != client; client = client->next) | ||
678 | if (GNUNET_NO == client->is_monitor) | ||
679 | return; /* not done yet */ | ||
680 | server->in_soft_shutdown = GNUNET_SYSERR; | ||
681 | (void) GNUNET_SCHEDULER_add_now (&do_destroy, server); | ||
682 | } | ||
683 | |||
684 | |||
685 | /** | ||
686 | * Suspend accepting connections from the listen socket temporarily. | ||
687 | * | ||
688 | * @param server server to stop accepting connections. | ||
689 | */ | ||
690 | void | ||
691 | GNUNET_SERVER_suspend (struct GNUNET_SERVER_Handle *server) | ||
692 | { | ||
693 | if (NULL != server->listen_task) | ||
694 | { | ||
695 | GNUNET_SCHEDULER_cancel (server->listen_task); | ||
696 | server->listen_task = NULL; | ||
697 | } | ||
698 | } | ||
699 | |||
700 | |||
701 | /** | ||
702 | * Resume accepting connections from the listen socket. | ||
703 | * | ||
704 | * @param server server to stop accepting connections. | ||
705 | */ | ||
706 | void | ||
707 | GNUNET_SERVER_resume (struct GNUNET_SERVER_Handle *server) | ||
708 | { | ||
709 | struct GNUNET_NETWORK_FDSet *r; | ||
710 | unsigned int i; | ||
711 | |||
712 | if (NULL == server->listen_sockets) | ||
713 | return; | ||
714 | if (NULL == server->listen_sockets[0]) | ||
715 | return; /* nothing to do, no listen sockets! */ | ||
716 | if (NULL == server->listen_sockets[1]) | ||
717 | { | ||
718 | /* simplified method: no fd set needed; this is then much simpler | ||
719 | and much more efficient */ | ||
720 | server->listen_task = | ||
721 | GNUNET_SCHEDULER_add_read_net_with_priority (GNUNET_TIME_UNIT_FOREVER_REL, | ||
722 | GNUNET_SCHEDULER_PRIORITY_HIGH, | ||
723 | server->listen_sockets[0], | ||
724 | &process_listen_socket, server); | ||
725 | return; | ||
726 | } | ||
727 | r = GNUNET_NETWORK_fdset_create (); | ||
728 | i = 0; | ||
729 | while (NULL != server->listen_sockets[i]) | ||
730 | GNUNET_NETWORK_fdset_set (r, server->listen_sockets[i++]); | ||
731 | server->listen_task = | ||
732 | GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_HIGH, | ||
733 | GNUNET_TIME_UNIT_FOREVER_REL, r, NULL, | ||
734 | &process_listen_socket, server); | ||
735 | GNUNET_NETWORK_fdset_destroy (r); | ||
736 | } | ||
737 | |||
738 | |||
739 | /** | ||
740 | * Stop the listen socket and get ready to shutdown the server | ||
741 | * once only 'monitor' clients are left. | ||
742 | * | ||
743 | * @param server server to stop listening on | ||
744 | */ | ||
745 | void | ||
746 | GNUNET_SERVER_stop_listening (struct GNUNET_SERVER_Handle *server) | ||
747 | { | ||
748 | unsigned int i; | ||
749 | |||
750 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
751 | "Server in soft shutdown\n"); | ||
752 | if (NULL != server->listen_task) | ||
753 | { | ||
754 | GNUNET_SCHEDULER_cancel (server->listen_task); | ||
755 | server->listen_task = NULL; | ||
756 | } | ||
757 | if (NULL != server->listen_sockets) | ||
758 | { | ||
759 | i = 0; | ||
760 | while (NULL != server->listen_sockets[i]) | ||
761 | GNUNET_break (GNUNET_OK == | ||
762 | GNUNET_NETWORK_socket_close (server->listen_sockets[i++])); | ||
763 | GNUNET_free (server->listen_sockets); | ||
764 | server->listen_sockets = NULL; | ||
765 | } | ||
766 | if (GNUNET_NO == server->in_soft_shutdown) | ||
767 | server->in_soft_shutdown = GNUNET_YES; | ||
768 | test_monitor_clients (server); | ||
769 | } | ||
770 | |||
771 | |||
772 | /** | ||
773 | * Free resources held by this server. | ||
774 | * | ||
775 | * @param server server to destroy | ||
776 | */ | ||
777 | void | ||
778 | GNUNET_SERVER_destroy (struct GNUNET_SERVER_Handle *server) | ||
779 | { | ||
780 | struct HandlerList *hpos; | ||
781 | struct NotifyList *npos; | ||
782 | unsigned int i; | ||
783 | |||
784 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
785 | "Server shutting down.\n"); | ||
786 | if (NULL != server->listen_task) | ||
787 | { | ||
788 | GNUNET_SCHEDULER_cancel (server->listen_task); | ||
789 | server->listen_task = NULL; | ||
790 | } | ||
791 | if (NULL != server->listen_sockets) | ||
792 | { | ||
793 | i = 0; | ||
794 | while (NULL != server->listen_sockets[i]) | ||
795 | GNUNET_break (GNUNET_OK == | ||
796 | GNUNET_NETWORK_socket_close (server->listen_sockets[i++])); | ||
797 | GNUNET_free (server->listen_sockets); | ||
798 | server->listen_sockets = NULL; | ||
799 | } | ||
800 | while (NULL != server->clients_head) | ||
801 | GNUNET_SERVER_client_disconnect (server->clients_head); | ||
802 | while (NULL != (hpos = server->handlers)) | ||
803 | { | ||
804 | server->handlers = hpos->next; | ||
805 | GNUNET_free (hpos); | ||
806 | } | ||
807 | while (NULL != (npos = server->disconnect_notify_list_head)) | ||
808 | { | ||
809 | npos->callback (npos->callback_cls, | ||
810 | NULL); | ||
811 | GNUNET_CONTAINER_DLL_remove (server->disconnect_notify_list_head, | ||
812 | server->disconnect_notify_list_tail, | ||
813 | npos); | ||
814 | GNUNET_free (npos); | ||
815 | } | ||
816 | while (NULL != (npos = server->connect_notify_list_head)) | ||
817 | { | ||
818 | npos->callback (npos->callback_cls, | ||
819 | NULL); | ||
820 | GNUNET_CONTAINER_DLL_remove (server->connect_notify_list_head, | ||
821 | server->connect_notify_list_tail, | ||
822 | npos); | ||
823 | GNUNET_free (npos); | ||
824 | } | ||
825 | GNUNET_free (server); | ||
826 | } | ||
827 | |||
828 | |||
829 | /** | ||
830 | * Add additional handlers to an existing server. | ||
831 | * | ||
832 | * @param server the server to add handlers to | ||
833 | * @param handlers array of message handlers for | ||
834 | * incoming messages; the last entry must | ||
835 | * have "NULL" for the "callback"; multiple | ||
836 | * entries for the same type are allowed, | ||
837 | * they will be called in order of occurence. | ||
838 | * These handlers can be removed later; | ||
839 | * the handlers array must exist until removed | ||
840 | * (or server is destroyed). | ||
841 | */ | ||
842 | void | ||
843 | GNUNET_SERVER_add_handlers (struct GNUNET_SERVER_Handle *server, | ||
844 | const struct GNUNET_SERVER_MessageHandler *handlers) | ||
845 | { | ||
846 | struct HandlerList *p; | ||
847 | |||
848 | p = GNUNET_new (struct HandlerList); | ||
849 | p->handlers = handlers; | ||
850 | p->next = server->handlers; | ||
851 | server->handlers = p; | ||
852 | } | ||
853 | |||
854 | |||
855 | /** | ||
856 | * Change functions used by the server to tokenize the message stream. | ||
857 | * (very rarely used). | ||
858 | * | ||
859 | * @param server server to modify | ||
860 | * @param create new tokenizer initialization function | ||
861 | * @param destroy new tokenizer destruction function | ||
862 | * @param receive new tokenizer receive function | ||
863 | * @param cls closure for @a create, @a receive, @a destroy | ||
864 | */ | ||
865 | void | ||
866 | GNUNET_SERVER_set_callbacks (struct GNUNET_SERVER_Handle *server, | ||
867 | GNUNET_SERVER_MstCreateCallback create, | ||
868 | GNUNET_SERVER_MstDestroyCallback destroy, | ||
869 | GNUNET_SERVER_MstReceiveCallback receive, | ||
870 | void *cls) | ||
871 | { | ||
872 | server->mst_create = create; | ||
873 | server->mst_destroy = destroy; | ||
874 | server->mst_receive = receive; | ||
875 | server->mst_cls = cls; | ||
876 | } | ||
877 | |||
878 | |||
879 | /** | ||
880 | * Task run to warn about missing calls to #GNUNET_SERVER_receive_done. | ||
881 | * | ||
882 | * @param cls our `struct GNUNET_SERVER_Client *` to process more requests from | ||
883 | */ | ||
884 | static void | ||
885 | warn_no_receive_done (void *cls) | ||
886 | { | ||
887 | struct GNUNET_SERVER_Client *client = cls; | ||
888 | |||
889 | GNUNET_break (0 != client->warn_type); /* type should never be 0 here, as we don't use 0 */ | ||
890 | client->warn_task = | ||
891 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, | ||
892 | &warn_no_receive_done, client); | ||
893 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
894 | _("Processing code for message of type %u did not call `GNUNET_SERVER_receive_done' after %s\n"), | ||
895 | (unsigned int) client->warn_type, | ||
896 | GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (client->warn_start), | ||
897 | GNUNET_YES)); | ||
898 | } | ||
899 | |||
900 | |||
901 | /** | ||
902 | * Disable the warning the server issues if a message is not acknowledged | ||
903 | * in a timely fashion. Use this call if a client is intentionally delayed | ||
904 | * for a while. Only applies to the current message. | ||
905 | * | ||
906 | * @param client client for which to disable the warning | ||
907 | */ | ||
908 | void | ||
909 | GNUNET_SERVER_disable_receive_done_warning (struct GNUNET_SERVER_Client *client) | ||
910 | { | ||
911 | if (NULL != client->warn_task) | ||
912 | { | ||
913 | GNUNET_SCHEDULER_cancel (client->warn_task); | ||
914 | client->warn_task = NULL; | ||
915 | } | ||
916 | } | ||
917 | |||
918 | |||
919 | /** | ||
920 | * Inject a message into the server, pretend it came | ||
921 | * from the specified client. Delivery of the message | ||
922 | * will happen instantly (if a handler is installed; | ||
923 | * otherwise the call does nothing). | ||
924 | * | ||
925 | * @param server the server receiving the message | ||
926 | * @param sender the "pretended" sender of the message | ||
927 | * can be NULL! | ||
928 | * @param message message to transmit | ||
929 | * @return #GNUNET_OK if the message was OK and the | ||
930 | * connection can stay open | ||
931 | * #GNUNET_SYSERR if the connection to the | ||
932 | * client should be shut down | ||
933 | */ | ||
934 | int | ||
935 | GNUNET_SERVER_inject (struct GNUNET_SERVER_Handle *server, | ||
936 | struct GNUNET_SERVER_Client *sender, | ||
937 | const struct GNUNET_MessageHeader *message) | ||
938 | { | ||
939 | struct HandlerList *pos; | ||
940 | const struct GNUNET_SERVER_MessageHandler *mh; | ||
941 | unsigned int i; | ||
942 | uint16_t type; | ||
943 | uint16_t size; | ||
944 | int found; | ||
945 | |||
946 | type = ntohs (message->type); | ||
947 | size = ntohs (message->size); | ||
948 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
949 | "Received message of type %u and size %u from client\n", | ||
950 | type, size); | ||
951 | found = GNUNET_NO; | ||
952 | for (pos = server->handlers; NULL != pos; pos = pos->next) | ||
953 | { | ||
954 | i = 0; | ||
955 | while (pos->handlers[i].callback != NULL) | ||
956 | { | ||
957 | mh = &pos->handlers[i]; | ||
958 | if ((mh->type == type) || (mh->type == GNUNET_MESSAGE_TYPE_ALL)) | ||
959 | { | ||
960 | if ((0 != mh->expected_size) && (mh->expected_size != size)) | ||
961 | { | ||
962 | #if GNUNET8_NETWORK_IS_DEAD | ||
963 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
964 | "Expected %u bytes for message of type %u, got %u\n", | ||
965 | mh->expected_size, mh->type, size); | ||
966 | GNUNET_break_op (0); | ||
967 | #else | ||
968 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
969 | "Expected %u bytes for message of type %u, got %u\n", | ||
970 | mh->expected_size, mh->type, size); | ||
971 | #endif | ||
972 | return GNUNET_SYSERR; | ||
973 | } | ||
974 | if (NULL != sender) | ||
975 | { | ||
976 | if ( (0 == sender->suspended) && | ||
977 | (NULL == sender->warn_task) ) | ||
978 | { | ||
979 | GNUNET_break (0 != type); /* type should never be 0 here, as we don't use 0 */ | ||
980 | sender->warn_start = GNUNET_TIME_absolute_get (); | ||
981 | sender->warn_task = | ||
982 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, | ||
983 | &warn_no_receive_done, | ||
984 | sender); | ||
985 | sender->warn_type = type; | ||
986 | } | ||
987 | sender->suspended++; | ||
988 | } | ||
989 | mh->callback (mh->callback_cls, sender, message); | ||
990 | found = GNUNET_YES; | ||
991 | } | ||
992 | i++; | ||
993 | } | ||
994 | } | ||
995 | if (GNUNET_NO == found) | ||
996 | { | ||
997 | LOG (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK, | ||
998 | "Received message of unknown type %d\n", type); | ||
999 | if (GNUNET_YES == server->require_found) | ||
1000 | return GNUNET_SYSERR; | ||
1001 | } | ||
1002 | return GNUNET_OK; | ||
1003 | } | ||
1004 | |||
1005 | |||
1006 | /** | ||
1007 | * We are receiving an incoming message. Process it. | ||
1008 | * | ||
1009 | * @param cls our closure (handle for the client) | ||
1010 | * @param buf buffer with data received from network | ||
1011 | * @param available number of bytes available in buf | ||
1012 | * @param addr address of the sender | ||
1013 | * @param addrlen length of @a addr | ||
1014 | * @param errCode code indicating errors receiving, 0 for success | ||
1015 | */ | ||
1016 | static void | ||
1017 | process_incoming (void *cls, | ||
1018 | const void *buf, | ||
1019 | size_t available, | ||
1020 | const struct sockaddr *addr, | ||
1021 | socklen_t addrlen, | ||
1022 | int errCode); | ||
1023 | |||
1024 | |||
1025 | /** | ||
1026 | * Process messages from the client's message tokenizer until either | ||
1027 | * the tokenizer is empty (and then schedule receiving more), or | ||
1028 | * until some handler is not immediately done (then wait for restart_processing) | ||
1029 | * or shutdown. | ||
1030 | * | ||
1031 | * @param client the client to process, RC must have already been increased | ||
1032 | * using #GNUNET_SERVER_client_keep and will be decreased by one in this | ||
1033 | * function | ||
1034 | * @param ret #GNUNET_NO to start processing from the buffer, | ||
1035 | * #GNUNET_OK if the mst buffer is drained and we should instantly go back to receiving | ||
1036 | * #GNUNET_SYSERR if we should instantly abort due to error in a previous step | ||
1037 | */ | ||
1038 | static void | ||
1039 | process_mst (struct GNUNET_SERVER_Client *client, | ||
1040 | int ret) | ||
1041 | { | ||
1042 | while ((GNUNET_SYSERR != ret) && (NULL != client->server) && | ||
1043 | (GNUNET_YES != client->shutdown_now) && (0 == client->suspended)) | ||
1044 | { | ||
1045 | if (GNUNET_OK == ret) | ||
1046 | { | ||
1047 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1048 | "Server re-enters receive loop, timeout: %s.\n", | ||
1049 | GNUNET_STRINGS_relative_time_to_string (client->idle_timeout, GNUNET_YES)); | ||
1050 | client->receive_pending = GNUNET_YES; | ||
1051 | GNUNET_CONNECTION_receive (client->connection, | ||
1052 | GNUNET_SERVER_MAX_MESSAGE_SIZE - 1, | ||
1053 | client->idle_timeout, | ||
1054 | &process_incoming, | ||
1055 | client); | ||
1056 | break; | ||
1057 | } | ||
1058 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1059 | "Server processes additional messages instantly.\n"); | ||
1060 | if (NULL != client->server->mst_receive) | ||
1061 | ret = | ||
1062 | client->server->mst_receive (client->server->mst_cls, client->mst, | ||
1063 | client, NULL, 0, GNUNET_NO, GNUNET_YES); | ||
1064 | else | ||
1065 | ret = | ||
1066 | GNUNET_SERVER_mst_receive (client->mst, client, NULL, 0, GNUNET_NO, | ||
1067 | GNUNET_YES); | ||
1068 | } | ||
1069 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1070 | "Server leaves instant processing loop: ret = %d, server = %p, shutdown = %d, suspended = %u\n", | ||
1071 | ret, client->server, | ||
1072 | client->shutdown_now, | ||
1073 | client->suspended); | ||
1074 | if (GNUNET_NO == ret) | ||
1075 | { | ||
1076 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1077 | "Server has more data pending but is suspended.\n"); | ||
1078 | client->receive_pending = GNUNET_SYSERR; /* data pending */ | ||
1079 | } | ||
1080 | if ( (GNUNET_SYSERR == ret) || | ||
1081 | (GNUNET_YES == client->shutdown_now) ) | ||
1082 | GNUNET_SERVER_client_disconnect (client); | ||
1083 | } | ||
1084 | |||
1085 | |||
1086 | /** | ||
1087 | * We are receiving an incoming message. Process it. | ||
1088 | * | ||
1089 | * @param cls our closure (handle for the client) | ||
1090 | * @param buf buffer with data received from network | ||
1091 | * @param available number of bytes available in buf | ||
1092 | * @param addr address of the sender | ||
1093 | * @param addrlen length of @a addr | ||
1094 | * @param errCode code indicating errors receiving, 0 for success | ||
1095 | */ | ||
1096 | static void | ||
1097 | process_incoming (void *cls, | ||
1098 | const void *buf, | ||
1099 | size_t available, | ||
1100 | const struct sockaddr *addr, | ||
1101 | socklen_t addrlen, | ||
1102 | int errCode) | ||
1103 | { | ||
1104 | struct GNUNET_SERVER_Client *client = cls; | ||
1105 | struct GNUNET_SERVER_Handle *server = client->server; | ||
1106 | struct GNUNET_TIME_Absolute end; | ||
1107 | struct GNUNET_TIME_Absolute now; | ||
1108 | int ret; | ||
1109 | |||
1110 | GNUNET_assert (GNUNET_YES == client->receive_pending); | ||
1111 | client->receive_pending = GNUNET_NO; | ||
1112 | now = GNUNET_TIME_absolute_get (); | ||
1113 | end = GNUNET_TIME_absolute_add (client->last_activity, | ||
1114 | client->idle_timeout); | ||
1115 | |||
1116 | if ( (NULL == buf) && | ||
1117 | (0 == available) && | ||
1118 | (NULL == addr) && | ||
1119 | (0 == errCode) && | ||
1120 | (GNUNET_YES != client->shutdown_now) && | ||
1121 | (NULL != server) && | ||
1122 | (GNUNET_YES == GNUNET_CONNECTION_check (client->connection)) && | ||
1123 | (end.abs_value_us > now.abs_value_us) ) | ||
1124 | { | ||
1125 | /* wait longer, timeout changed (i.e. due to us sending) */ | ||
1126 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1127 | "Receive time out, but no disconnect due to sending (%p)\n", | ||
1128 | client); | ||
1129 | client->receive_pending = GNUNET_YES; | ||
1130 | GNUNET_CONNECTION_receive (client->connection, | ||
1131 | GNUNET_SERVER_MAX_MESSAGE_SIZE - 1, | ||
1132 | GNUNET_TIME_absolute_get_remaining (end), | ||
1133 | &process_incoming, | ||
1134 | client); | ||
1135 | return; | ||
1136 | } | ||
1137 | if ( (NULL == buf) || | ||
1138 | (0 == available) || | ||
1139 | (0 != errCode) || | ||
1140 | (NULL == server) || | ||
1141 | (GNUNET_YES == client->shutdown_now) || | ||
1142 | (GNUNET_YES != GNUNET_CONNECTION_check (client->connection)) ) | ||
1143 | { | ||
1144 | /* other side closed connection, error connecting, etc. */ | ||
1145 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1146 | "Failed to connect or other side closed connection (%p)\n", | ||
1147 | client); | ||
1148 | GNUNET_SERVER_client_disconnect (client); | ||
1149 | return; | ||
1150 | } | ||
1151 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1152 | "Server receives %u bytes from `%s'.\n", | ||
1153 | (unsigned int) available, | ||
1154 | GNUNET_a2s (addr, addrlen)); | ||
1155 | GNUNET_SERVER_client_keep (client); | ||
1156 | client->last_activity = now; | ||
1157 | |||
1158 | if (NULL != server->mst_receive) | ||
1159 | { | ||
1160 | ret = client->server->mst_receive (client->server->mst_cls, | ||
1161 | client->mst, | ||
1162 | client, | ||
1163 | buf, | ||
1164 | available, | ||
1165 | GNUNET_NO, | ||
1166 | GNUNET_YES); | ||
1167 | } | ||
1168 | else if (NULL != client->mst) | ||
1169 | { | ||
1170 | ret = | ||
1171 | GNUNET_SERVER_mst_receive (client->mst, | ||
1172 | client, | ||
1173 | buf, | ||
1174 | available, | ||
1175 | GNUNET_NO, | ||
1176 | GNUNET_YES); | ||
1177 | } | ||
1178 | else | ||
1179 | { | ||
1180 | GNUNET_break (0); | ||
1181 | return; | ||
1182 | } | ||
1183 | process_mst (client, | ||
1184 | ret); | ||
1185 | GNUNET_SERVER_client_drop (client); | ||
1186 | } | ||
1187 | |||
1188 | |||
1189 | /** | ||
1190 | * Task run to start again receiving from the network | ||
1191 | * and process requests. | ||
1192 | * | ||
1193 | * @param cls our `struct GNUNET_SERVER_Client *` to process more requests from | ||
1194 | */ | ||
1195 | static void | ||
1196 | restart_processing (void *cls) | ||
1197 | { | ||
1198 | struct GNUNET_SERVER_Client *client = cls; | ||
1199 | |||
1200 | GNUNET_assert (GNUNET_YES != client->shutdown_now); | ||
1201 | client->restart_task = NULL; | ||
1202 | if (GNUNET_NO == client->receive_pending) | ||
1203 | { | ||
1204 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Server begins to read again from client.\n"); | ||
1205 | client->receive_pending = GNUNET_YES; | ||
1206 | GNUNET_CONNECTION_receive (client->connection, | ||
1207 | GNUNET_SERVER_MAX_MESSAGE_SIZE - 1, | ||
1208 | client->idle_timeout, | ||
1209 | &process_incoming, | ||
1210 | client); | ||
1211 | return; | ||
1212 | } | ||
1213 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1214 | "Server continues processing messages still in the buffer.\n"); | ||
1215 | GNUNET_SERVER_client_keep (client); | ||
1216 | client->receive_pending = GNUNET_NO; | ||
1217 | process_mst (client, | ||
1218 | GNUNET_NO); | ||
1219 | GNUNET_SERVER_client_drop (client); | ||
1220 | } | ||
1221 | |||
1222 | |||
1223 | /** | ||
1224 | * This function is called whenever our inbound message tokenizer has | ||
1225 | * received a complete message. | ||
1226 | * | ||
1227 | * @param cls closure (struct GNUNET_SERVER_Handle) | ||
1228 | * @param client identification of the client (`struct GNUNET_SERVER_Client *`) | ||
1229 | * @param message the actual message | ||
1230 | * | ||
1231 | * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing | ||
1232 | */ | ||
1233 | static int | ||
1234 | client_message_tokenizer_callback (void *cls, | ||
1235 | void *client, | ||
1236 | const struct GNUNET_MessageHeader *message) | ||
1237 | { | ||
1238 | struct GNUNET_SERVER_Handle *server = cls; | ||
1239 | struct GNUNET_SERVER_Client *sender = client; | ||
1240 | int ret; | ||
1241 | |||
1242 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1243 | "Tokenizer gives server message of type %u and size %u from client\n", | ||
1244 | ntohs (message->type), ntohs (message->size)); | ||
1245 | sender->in_process_client_buffer = GNUNET_YES; | ||
1246 | ret = GNUNET_SERVER_inject (server, sender, message); | ||
1247 | sender->in_process_client_buffer = GNUNET_NO; | ||
1248 | if ( (GNUNET_OK != ret) || (GNUNET_YES == sender->shutdown_now) ) | ||
1249 | { | ||
1250 | GNUNET_SERVER_client_disconnect (sender); | ||
1251 | return GNUNET_SYSERR; | ||
1252 | } | ||
1253 | return GNUNET_OK; | ||
1254 | } | ||
1255 | |||
1256 | |||
1257 | /** | ||
1258 | * Add a TCP socket-based connection to the set of handles managed by | ||
1259 | * this server. Use this function for outgoing (P2P) connections that | ||
1260 | * we initiated (and where this server should process incoming | ||
1261 | * messages). | ||
1262 | * | ||
1263 | * @param server the server to use | ||
1264 | * @param connection the connection to manage (client must | ||
1265 | * stop using this connection from now on) | ||
1266 | * @return the client handle | ||
1267 | */ | ||
1268 | struct GNUNET_SERVER_Client * | ||
1269 | GNUNET_SERVER_connect_socket (struct GNUNET_SERVER_Handle *server, | ||
1270 | struct GNUNET_CONNECTION_Handle *connection) | ||
1271 | { | ||
1272 | struct GNUNET_SERVER_Client *client; | ||
1273 | struct NotifyList *n; | ||
1274 | |||
1275 | client = GNUNET_new (struct GNUNET_SERVER_Client); | ||
1276 | client->connection = connection; | ||
1277 | client->server = server; | ||
1278 | client->last_activity = GNUNET_TIME_absolute_get (); | ||
1279 | client->idle_timeout = server->idle_timeout; | ||
1280 | GNUNET_CONTAINER_DLL_insert (server->clients_head, | ||
1281 | server->clients_tail, | ||
1282 | client); | ||
1283 | if (NULL != server->mst_create) | ||
1284 | client->mst = | ||
1285 | server->mst_create (server->mst_cls, client); | ||
1286 | else | ||
1287 | client->mst = | ||
1288 | GNUNET_SERVER_mst_create (&client_message_tokenizer_callback, | ||
1289 | server); | ||
1290 | GNUNET_assert (NULL != client->mst); | ||
1291 | for (n = server->connect_notify_list_head; NULL != n; n = n->next) | ||
1292 | n->callback (n->callback_cls, client); | ||
1293 | client->receive_pending = GNUNET_YES; | ||
1294 | GNUNET_CONNECTION_receive (client->connection, | ||
1295 | GNUNET_SERVER_MAX_MESSAGE_SIZE - 1, | ||
1296 | client->idle_timeout, | ||
1297 | &process_incoming, | ||
1298 | client); | ||
1299 | return client; | ||
1300 | } | ||
1301 | |||
1302 | |||
1303 | /** | ||
1304 | * Change the timeout for a particular client. Decreasing the timeout | ||
1305 | * may not go into effect immediately (only after the previous timeout | ||
1306 | * times out or activity happens on the socket). | ||
1307 | * | ||
1308 | * @param client the client to update | ||
1309 | * @param timeout new timeout for activities on the socket | ||
1310 | */ | ||
1311 | void | ||
1312 | GNUNET_SERVER_client_set_timeout (struct GNUNET_SERVER_Client *client, | ||
1313 | struct GNUNET_TIME_Relative timeout) | ||
1314 | { | ||
1315 | client->idle_timeout = timeout; | ||
1316 | } | ||
1317 | |||
1318 | |||
1319 | /** | ||
1320 | * Notify the server that the given client handle should | ||
1321 | * be kept (keeps the connection up if possible, increments | ||
1322 | * the internal reference counter). | ||
1323 | * | ||
1324 | * @param client the client to keep | ||
1325 | */ | ||
1326 | void | ||
1327 | GNUNET_SERVER_client_keep (struct GNUNET_SERVER_Client *client) | ||
1328 | { | ||
1329 | client->reference_count++; | ||
1330 | } | ||
1331 | |||
1332 | |||
1333 | /** | ||
1334 | * Notify the server that the given client handle is no | ||
1335 | * longer required. Decrements the reference counter. If | ||
1336 | * that counter reaches zero an inactive connection maybe | ||
1337 | * closed. | ||
1338 | * | ||
1339 | * @param client the client to drop | ||
1340 | */ | ||
1341 | void | ||
1342 | GNUNET_SERVER_client_drop (struct GNUNET_SERVER_Client *client) | ||
1343 | { | ||
1344 | GNUNET_assert (client->reference_count > 0); | ||
1345 | client->reference_count--; | ||
1346 | if ((GNUNET_YES == client->shutdown_now) && (0 == client->reference_count)) | ||
1347 | GNUNET_SERVER_client_disconnect (client); | ||
1348 | } | ||
1349 | |||
1350 | |||
1351 | /** | ||
1352 | * Obtain the network address of the other party. | ||
1353 | * | ||
1354 | * @param client the client to get the address for | ||
1355 | * @param addr where to store the address | ||
1356 | * @param addrlen where to store the length of the @a addr | ||
1357 | * @return #GNUNET_OK on success | ||
1358 | */ | ||
1359 | int | ||
1360 | GNUNET_SERVER_client_get_address (struct GNUNET_SERVER_Client *client, | ||
1361 | void **addr, size_t * addrlen) | ||
1362 | { | ||
1363 | return GNUNET_CONNECTION_get_address (client->connection, addr, addrlen); | ||
1364 | } | ||
1365 | |||
1366 | |||
1367 | /** | ||
1368 | * Ask the server to notify us whenever a client disconnects. | ||
1369 | * This function is called whenever the actual network connection | ||
1370 | * is closed; the reference count may be zero or larger than zero | ||
1371 | * at this point. | ||
1372 | * | ||
1373 | * @param server the server manageing the clients | ||
1374 | * @param callback function to call on disconnect | ||
1375 | * @param callback_cls closure for @a callback | ||
1376 | */ | ||
1377 | void | ||
1378 | GNUNET_SERVER_disconnect_notify (struct GNUNET_SERVER_Handle *server, | ||
1379 | GNUNET_SERVER_DisconnectCallback callback, | ||
1380 | void *callback_cls) | ||
1381 | { | ||
1382 | struct NotifyList *n; | ||
1383 | |||
1384 | n = GNUNET_new (struct NotifyList); | ||
1385 | n->callback = callback; | ||
1386 | n->callback_cls = callback_cls; | ||
1387 | GNUNET_CONTAINER_DLL_insert (server->disconnect_notify_list_head, | ||
1388 | server->disconnect_notify_list_tail, | ||
1389 | n); | ||
1390 | } | ||
1391 | |||
1392 | |||
1393 | /** | ||
1394 | * Ask the server to notify us whenever a client connects. | ||
1395 | * This function is called whenever the actual network connection | ||
1396 | * is opened. If the server is destroyed before this | ||
1397 | * notification is explicitly cancelled, the 'callback' will | ||
1398 | * once be called with a 'client' argument of NULL to indicate | ||
1399 | * that the server itself is now gone (and that the callback | ||
1400 | * won't be called anymore and also can no longer be cancelled). | ||
1401 | * | ||
1402 | * @param server the server manageing the clients | ||
1403 | * @param callback function to call on sconnect | ||
1404 | * @param callback_cls closure for @a callback | ||
1405 | */ | ||
1406 | void | ||
1407 | GNUNET_SERVER_connect_notify (struct GNUNET_SERVER_Handle *server, | ||
1408 | GNUNET_SERVER_ConnectCallback callback, | ||
1409 | void *callback_cls) | ||
1410 | { | ||
1411 | struct NotifyList *n; | ||
1412 | struct GNUNET_SERVER_Client *client; | ||
1413 | |||
1414 | n = GNUNET_new (struct NotifyList); | ||
1415 | n->callback = callback; | ||
1416 | n->callback_cls = callback_cls; | ||
1417 | GNUNET_CONTAINER_DLL_insert (server->connect_notify_list_head, | ||
1418 | server->connect_notify_list_tail, | ||
1419 | n); | ||
1420 | for (client = server->clients_head; NULL != client; client = client->next) | ||
1421 | callback (callback_cls, client); | ||
1422 | } | ||
1423 | |||
1424 | |||
1425 | /** | ||
1426 | * Ask the server to stop notifying us whenever a client connects. | ||
1427 | * | ||
1428 | * @param server the server manageing the clients | ||
1429 | * @param callback function to call on connect | ||
1430 | * @param callback_cls closure for @a callback | ||
1431 | */ | ||
1432 | void | ||
1433 | GNUNET_SERVER_disconnect_notify_cancel (struct GNUNET_SERVER_Handle *server, | ||
1434 | GNUNET_SERVER_DisconnectCallback callback, | ||
1435 | void *callback_cls) | ||
1436 | { | ||
1437 | struct NotifyList *pos; | ||
1438 | |||
1439 | for (pos = server->disconnect_notify_list_head; NULL != pos; pos = pos->next) | ||
1440 | if ((pos->callback == callback) && (pos->callback_cls == callback_cls)) | ||
1441 | break; | ||
1442 | if (NULL == pos) | ||
1443 | { | ||
1444 | GNUNET_break (0); | ||
1445 | return; | ||
1446 | } | ||
1447 | GNUNET_CONTAINER_DLL_remove (server->disconnect_notify_list_head, | ||
1448 | server->disconnect_notify_list_tail, | ||
1449 | pos); | ||
1450 | GNUNET_free (pos); | ||
1451 | } | ||
1452 | |||
1453 | |||
1454 | /** | ||
1455 | * Ask the server to stop notifying us whenever a client disconnects. | ||
1456 | * | ||
1457 | * @param server the server manageing the clients | ||
1458 | * @param callback function to call on disconnect | ||
1459 | * @param callback_cls closure for @a callback | ||
1460 | */ | ||
1461 | void | ||
1462 | GNUNET_SERVER_connect_notify_cancel (struct GNUNET_SERVER_Handle *server, | ||
1463 | GNUNET_SERVER_ConnectCallback callback, | ||
1464 | void *callback_cls) | ||
1465 | { | ||
1466 | struct NotifyList *pos; | ||
1467 | |||
1468 | for (pos = server->connect_notify_list_head; NULL != pos; pos = pos->next) | ||
1469 | if ((pos->callback == callback) && (pos->callback_cls == callback_cls)) | ||
1470 | break; | ||
1471 | if (NULL == pos) | ||
1472 | { | ||
1473 | GNUNET_break (0); | ||
1474 | return; | ||
1475 | } | ||
1476 | GNUNET_CONTAINER_DLL_remove (server->connect_notify_list_head, | ||
1477 | server->connect_notify_list_tail, | ||
1478 | pos); | ||
1479 | GNUNET_free (pos); | ||
1480 | } | ||
1481 | |||
1482 | |||
1483 | /** | ||
1484 | * Destroy the connection that is passed in via @a cls. Used | ||
1485 | * as calling #GNUNET_CONNECTION_destroy from within a function | ||
1486 | * that was itself called from within process_notify() of | ||
1487 | * 'connection.c' is not allowed (see #2329). | ||
1488 | * | ||
1489 | * @param cls connection to destroy | ||
1490 | */ | ||
1491 | static void | ||
1492 | destroy_connection (void *cls) | ||
1493 | { | ||
1494 | struct GNUNET_CONNECTION_Handle *connection = cls; | ||
1495 | |||
1496 | GNUNET_CONNECTION_destroy (connection); | ||
1497 | } | ||
1498 | |||
1499 | |||
1500 | /** | ||
1501 | * Ask the server to disconnect from the given client. | ||
1502 | * This is the same as returning #GNUNET_SYSERR from a message | ||
1503 | * handler, except that it allows dropping of a client even | ||
1504 | * when not handling a message from that client. | ||
1505 | * | ||
1506 | * @param client the client to disconnect from | ||
1507 | */ | ||
1508 | void | ||
1509 | GNUNET_SERVER_client_disconnect (struct GNUNET_SERVER_Client *client) | ||
1510 | { | ||
1511 | struct GNUNET_SERVER_Handle *server = client->server; | ||
1512 | struct NotifyList *n; | ||
1513 | |||
1514 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1515 | "Client is being disconnected from the server.\n"); | ||
1516 | if (NULL != client->restart_task) | ||
1517 | { | ||
1518 | GNUNET_SCHEDULER_cancel (client->restart_task); | ||
1519 | client->restart_task = NULL; | ||
1520 | } | ||
1521 | if (NULL != client->warn_task) | ||
1522 | { | ||
1523 | GNUNET_SCHEDULER_cancel (client->warn_task); | ||
1524 | client->warn_task = NULL; | ||
1525 | } | ||
1526 | if (GNUNET_YES == client->receive_pending) | ||
1527 | { | ||
1528 | GNUNET_CONNECTION_receive_cancel (client->connection); | ||
1529 | client->receive_pending = GNUNET_NO; | ||
1530 | } | ||
1531 | client->shutdown_now = GNUNET_YES; | ||
1532 | client->reference_count++; /* make sure nobody else clean up client... */ | ||
1533 | if ( (NULL != client->mst) && | ||
1534 | (NULL != server) ) | ||
1535 | { | ||
1536 | GNUNET_CONTAINER_DLL_remove (server->clients_head, | ||
1537 | server->clients_tail, | ||
1538 | client); | ||
1539 | if (NULL != server->mst_destroy) | ||
1540 | server->mst_destroy (server->mst_cls, | ||
1541 | client->mst); | ||
1542 | else | ||
1543 | GNUNET_SERVER_mst_destroy (client->mst); | ||
1544 | client->mst = NULL; | ||
1545 | for (n = server->disconnect_notify_list_head; NULL != n; n = n->next) | ||
1546 | n->callback (n->callback_cls, | ||
1547 | client); | ||
1548 | } | ||
1549 | client->reference_count--; | ||
1550 | if (client->reference_count > 0) | ||
1551 | { | ||
1552 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1553 | "RC of %p still positive, not destroying everything.\n", | ||
1554 | client); | ||
1555 | client->server = NULL; | ||
1556 | return; | ||
1557 | } | ||
1558 | if (GNUNET_YES == client->in_process_client_buffer) | ||
1559 | { | ||
1560 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1561 | "Still processing inputs of %p, not destroying everything.\n", | ||
1562 | client); | ||
1563 | return; | ||
1564 | } | ||
1565 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1566 | "RC of %p now zero, destroying everything.\n", | ||
1567 | client); | ||
1568 | if (GNUNET_YES == client->persist) | ||
1569 | GNUNET_CONNECTION_persist_ (client->connection); | ||
1570 | if (NULL != client->th.cth) | ||
1571 | GNUNET_SERVER_notify_transmit_ready_cancel (&client->th); | ||
1572 | (void) GNUNET_SCHEDULER_add_now (&destroy_connection, | ||
1573 | client->connection); | ||
1574 | /* need to cancel again, as it might have been re-added | ||
1575 | in the meantime (i.e. during callbacks) */ | ||
1576 | if (NULL != client->warn_task) | ||
1577 | { | ||
1578 | GNUNET_SCHEDULER_cancel (client->warn_task); | ||
1579 | client->warn_task = NULL; | ||
1580 | } | ||
1581 | if (GNUNET_YES == client->receive_pending) | ||
1582 | { | ||
1583 | GNUNET_CONNECTION_receive_cancel (client->connection); | ||
1584 | client->receive_pending = GNUNET_NO; | ||
1585 | } | ||
1586 | GNUNET_free (client); | ||
1587 | /* we might be in soft-shutdown, test if we're done */ | ||
1588 | if (NULL != server) | ||
1589 | test_monitor_clients (server); | ||
1590 | } | ||
1591 | |||
1592 | |||
1593 | /** | ||
1594 | * Disable the "CORK" feature for communication with the given client, | ||
1595 | * forcing the OS to immediately flush the buffer on transmission | ||
1596 | * instead of potentially buffering multiple messages. | ||
1597 | * | ||
1598 | * @param client handle to the client | ||
1599 | * @return #GNUNET_OK on success | ||
1600 | */ | ||
1601 | int | ||
1602 | GNUNET_SERVER_client_disable_corking (struct GNUNET_SERVER_Client *client) | ||
1603 | { | ||
1604 | return GNUNET_CONNECTION_disable_corking (client->connection); | ||
1605 | } | ||
1606 | |||
1607 | |||
1608 | /** | ||
1609 | * Wrapper for transmission notification that calls the original | ||
1610 | * callback and update the last activity time for our connection. | ||
1611 | * | ||
1612 | * @param cls the `struct GNUNET_SERVER_Client *` | ||
1613 | * @param size number of bytes we can transmit | ||
1614 | * @param buf where to copy the message | ||
1615 | * @return number of bytes actually transmitted | ||
1616 | */ | ||
1617 | static size_t | ||
1618 | transmit_ready_callback_wrapper (void *cls, size_t size, void *buf) | ||
1619 | { | ||
1620 | struct GNUNET_SERVER_Client *client = cls; | ||
1621 | GNUNET_CONNECTION_TransmitReadyNotify callback; | ||
1622 | |||
1623 | client->th.cth = NULL; | ||
1624 | callback = client->th.callback; | ||
1625 | client->th.callback = NULL; | ||
1626 | client->last_activity = GNUNET_TIME_absolute_get (); | ||
1627 | return callback (client->th.callback_cls, size, buf); | ||
1628 | } | ||
1629 | |||
1630 | |||
1631 | /** | ||
1632 | * Notify us when the server has enough space to transmit | ||
1633 | * a message of the given size to the given client. | ||
1634 | * | ||
1635 | * @param client client to transmit message to | ||
1636 | * @param size requested amount of buffer space | ||
1637 | * @param timeout after how long should we give up (and call | ||
1638 | * notify with buf NULL and size 0)? | ||
1639 | * @param callback function to call when space is available | ||
1640 | * @param callback_cls closure for @a callback | ||
1641 | * @return non-NULL if the notify callback was queued; can be used | ||
1642 | * to cancel the request using | ||
1643 | * #GNUNET_SERVER_notify_transmit_ready_cancel(). | ||
1644 | * NULL if we are already going to notify someone else (busy) | ||
1645 | */ | ||
1646 | struct GNUNET_SERVER_TransmitHandle * | ||
1647 | GNUNET_SERVER_notify_transmit_ready (struct GNUNET_SERVER_Client *client, | ||
1648 | size_t size, | ||
1649 | struct GNUNET_TIME_Relative timeout, | ||
1650 | GNUNET_CONNECTION_TransmitReadyNotify callback, | ||
1651 | void *callback_cls) | ||
1652 | { | ||
1653 | if (NULL != client->th.callback) | ||
1654 | return NULL; | ||
1655 | client->th.callback_cls = callback_cls; | ||
1656 | client->th.callback = callback; | ||
1657 | client->th.cth = GNUNET_CONNECTION_notify_transmit_ready (client->connection, size, | ||
1658 | timeout, | ||
1659 | &transmit_ready_callback_wrapper, | ||
1660 | client); | ||
1661 | return &client->th; | ||
1662 | } | ||
1663 | |||
1664 | |||
1665 | /** | ||
1666 | * Abort transmission request. | ||
1667 | * | ||
1668 | * @param th request to abort | ||
1669 | */ | ||
1670 | void | ||
1671 | GNUNET_SERVER_notify_transmit_ready_cancel (struct GNUNET_SERVER_TransmitHandle *th) | ||
1672 | { | ||
1673 | GNUNET_CONNECTION_notify_transmit_ready_cancel (th->cth); | ||
1674 | th->cth = NULL; | ||
1675 | th->callback = NULL; | ||
1676 | } | ||
1677 | |||
1678 | |||
1679 | /** | ||
1680 | * Set the persistent flag on this client, used to setup client connection | ||
1681 | * to only be killed when the service it's connected to is actually dead. | ||
1682 | * | ||
1683 | * @param client the client to set the persistent flag on | ||
1684 | */ | ||
1685 | void | ||
1686 | GNUNET_SERVER_client_persist_ (struct GNUNET_SERVER_Client *client) | ||
1687 | { | ||
1688 | client->persist = GNUNET_YES; | ||
1689 | } | ||
1690 | |||
1691 | |||
1692 | /** | ||
1693 | * Resume receiving from this client, we are done processing the | ||
1694 | * current request. This function must be called from within each | ||
1695 | * GNUNET_SERVER_MessageCallback (or its respective continuations). | ||
1696 | * | ||
1697 | * @param client client we were processing a message of | ||
1698 | * @param success #GNUNET_OK to keep the connection open and | ||
1699 | * continue to receive | ||
1700 | * #GNUNET_NO to close the connection (normal behavior) | ||
1701 | * #GNUNET_SYSERR to close the connection (signal | ||
1702 | * serious error) | ||
1703 | */ | ||
1704 | void | ||
1705 | GNUNET_SERVER_receive_done (struct GNUNET_SERVER_Client *client, | ||
1706 | int success) | ||
1707 | { | ||
1708 | if (NULL == client) | ||
1709 | return; | ||
1710 | GNUNET_assert (client->suspended > 0); | ||
1711 | client->suspended--; | ||
1712 | if (GNUNET_OK != success) | ||
1713 | { | ||
1714 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1715 | "GNUNET_SERVER_receive_done called with failure indication\n"); | ||
1716 | if ( (client->reference_count > 0) || (client->suspended > 0) ) | ||
1717 | client->shutdown_now = GNUNET_YES; | ||
1718 | else | ||
1719 | GNUNET_SERVER_client_disconnect (client); | ||
1720 | return; | ||
1721 | } | ||
1722 | if (client->suspended > 0) | ||
1723 | { | ||
1724 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1725 | "GNUNET_SERVER_receive_done called, but more clients pending\n"); | ||
1726 | return; | ||
1727 | } | ||
1728 | if (NULL != client->warn_task) | ||
1729 | { | ||
1730 | GNUNET_SCHEDULER_cancel (client->warn_task); | ||
1731 | client->warn_task = NULL; | ||
1732 | } | ||
1733 | if (GNUNET_YES == client->in_process_client_buffer) | ||
1734 | { | ||
1735 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1736 | "GNUNET_SERVER_receive_done called while still in processing loop\n"); | ||
1737 | return; | ||
1738 | } | ||
1739 | if ((NULL == client->server) || (GNUNET_YES == client->shutdown_now)) | ||
1740 | { | ||
1741 | GNUNET_SERVER_client_disconnect (client); | ||
1742 | return; | ||
1743 | } | ||
1744 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1745 | "GNUNET_SERVER_receive_done causes restart in reading from the socket\n"); | ||
1746 | GNUNET_assert (NULL == client->restart_task); | ||
1747 | client->restart_task = GNUNET_SCHEDULER_add_now (&restart_processing, | ||
1748 | client); | ||
1749 | } | ||
1750 | |||
1751 | |||
1752 | /* end of server.c */ | ||
diff --git a/src/util/server_mst.c b/src/util/server_mst.c deleted file mode 100644 index 5155b54da..000000000 --- a/src/util/server_mst.c +++ /dev/null | |||
@@ -1,313 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2010 GNUnet e.V. | ||
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., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file util/server_mst.c | ||
23 | * @brief convenience functions for handling inbound message buffers | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | |||
27 | #include "platform.h" | ||
28 | #include "gnunet_util_lib.h" | ||
29 | |||
30 | |||
31 | #if HAVE_UNALIGNED_64_ACCESS | ||
32 | #define ALIGN_FACTOR 4 | ||
33 | #else | ||
34 | #define ALIGN_FACTOR 8 | ||
35 | #endif | ||
36 | |||
37 | #define LOG(kind,...) GNUNET_log_from (kind, "util-server-mst", __VA_ARGS__) | ||
38 | |||
39 | |||
40 | /** | ||
41 | * Handle to a message stream tokenizer. | ||
42 | */ | ||
43 | struct GNUNET_SERVER_MessageStreamTokenizer | ||
44 | { | ||
45 | |||
46 | /** | ||
47 | * Function to call on completed messages. | ||
48 | */ | ||
49 | GNUNET_SERVER_MessageTokenizerCallback cb; | ||
50 | |||
51 | /** | ||
52 | * Closure for @e cb. | ||
53 | */ | ||
54 | void *cb_cls; | ||
55 | |||
56 | /** | ||
57 | * Size of the buffer (starting at @e hdr). | ||
58 | */ | ||
59 | size_t curr_buf; | ||
60 | |||
61 | /** | ||
62 | * How many bytes in buffer have we already processed? | ||
63 | */ | ||
64 | size_t off; | ||
65 | |||
66 | /** | ||
67 | * How many bytes in buffer are valid right now? | ||
68 | */ | ||
69 | size_t pos; | ||
70 | |||
71 | /** | ||
72 | * Beginning of the buffer. Typed like this to force alignment. | ||
73 | */ | ||
74 | struct GNUNET_MessageHeader *hdr; | ||
75 | |||
76 | }; | ||
77 | |||
78 | |||
79 | |||
80 | /** | ||
81 | * Create a message stream tokenizer. | ||
82 | * | ||
83 | * @param cb function to call on completed messages | ||
84 | * @param cb_cls closure for @a cb | ||
85 | * @return handle to tokenizer | ||
86 | */ | ||
87 | struct GNUNET_SERVER_MessageStreamTokenizer * | ||
88 | GNUNET_SERVER_mst_create (GNUNET_SERVER_MessageTokenizerCallback cb, | ||
89 | void *cb_cls) | ||
90 | { | ||
91 | struct GNUNET_SERVER_MessageStreamTokenizer *ret; | ||
92 | |||
93 | ret = GNUNET_new (struct GNUNET_SERVER_MessageStreamTokenizer); | ||
94 | ret->hdr = GNUNET_malloc (GNUNET_SERVER_MIN_BUFFER_SIZE); | ||
95 | ret->curr_buf = GNUNET_SERVER_MIN_BUFFER_SIZE; | ||
96 | ret->cb = cb; | ||
97 | ret->cb_cls = cb_cls; | ||
98 | return ret; | ||
99 | } | ||
100 | |||
101 | |||
102 | /** | ||
103 | * Add incoming data to the receive buffer and call the | ||
104 | * callback for all complete messages. | ||
105 | * | ||
106 | * @param mst tokenizer to use | ||
107 | * @param client_identity ID of client for which this is a buffer | ||
108 | * @param buf input data to add | ||
109 | * @param size number of bytes in @a buf | ||
110 | * @param purge should any excess bytes in the buffer be discarded | ||
111 | * (i.e. for packet-based services like UDP) | ||
112 | * @param one_shot only call callback once, keep rest of message in buffer | ||
113 | * @return #GNUNET_OK if we are done processing (need more data) | ||
114 | * #GNUNET_NO if @a one_shot was set and we have another message ready | ||
115 | * #GNUNET_SYSERR if the data stream is corrupt | ||
116 | */ | ||
117 | int | ||
118 | GNUNET_SERVER_mst_receive (struct GNUNET_SERVER_MessageStreamTokenizer *mst, | ||
119 | void *client_identity, | ||
120 | const char *buf, size_t size, | ||
121 | int purge, int one_shot) | ||
122 | { | ||
123 | const struct GNUNET_MessageHeader *hdr; | ||
124 | size_t delta; | ||
125 | uint16_t want; | ||
126 | char *ibuf; | ||
127 | int need_align; | ||
128 | unsigned long offset; | ||
129 | int ret; | ||
130 | |||
131 | GNUNET_assert (mst->off <= mst->pos); | ||
132 | GNUNET_assert (mst->pos <= mst->curr_buf); | ||
133 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
134 | "Server-mst receives %u bytes with %u bytes already in private buffer\n", | ||
135 | (unsigned int) size, (unsigned int) (mst->pos - mst->off)); | ||
136 | ret = GNUNET_OK; | ||
137 | ibuf = (char *) mst->hdr; | ||
138 | while (mst->pos > 0) | ||
139 | { | ||
140 | do_align: | ||
141 | GNUNET_assert (mst->pos >= mst->off); | ||
142 | if ((mst->curr_buf - mst->off < sizeof (struct GNUNET_MessageHeader)) || | ||
143 | (0 != (mst->off % ALIGN_FACTOR))) | ||
144 | { | ||
145 | /* need to align or need more space */ | ||
146 | mst->pos -= mst->off; | ||
147 | memmove (ibuf, &ibuf[mst->off], mst->pos); | ||
148 | mst->off = 0; | ||
149 | } | ||
150 | if (mst->pos - mst->off < sizeof (struct GNUNET_MessageHeader)) | ||
151 | { | ||
152 | delta = | ||
153 | GNUNET_MIN (sizeof (struct GNUNET_MessageHeader) - | ||
154 | (mst->pos - mst->off), size); | ||
155 | GNUNET_memcpy (&ibuf[mst->pos], buf, delta); | ||
156 | mst->pos += delta; | ||
157 | buf += delta; | ||
158 | size -= delta; | ||
159 | } | ||
160 | if (mst->pos - mst->off < sizeof (struct GNUNET_MessageHeader)) | ||
161 | { | ||
162 | if (purge) | ||
163 | { | ||
164 | mst->off = 0; | ||
165 | mst->pos = 0; | ||
166 | } | ||
167 | return GNUNET_OK; | ||
168 | } | ||
169 | hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off]; | ||
170 | want = ntohs (hdr->size); | ||
171 | if (want < sizeof (struct GNUNET_MessageHeader)) | ||
172 | { | ||
173 | GNUNET_break_op (0); | ||
174 | return GNUNET_SYSERR; | ||
175 | } | ||
176 | if ( (mst->curr_buf - mst->off < want) && | ||
177 | (mst->off > 0) ) | ||
178 | { | ||
179 | /* can get more space by moving */ | ||
180 | mst->pos -= mst->off; | ||
181 | memmove (ibuf, &ibuf[mst->off], mst->pos); | ||
182 | mst->off = 0; | ||
183 | } | ||
184 | if (mst->curr_buf < want) | ||
185 | { | ||
186 | /* need to get more space by growing buffer */ | ||
187 | GNUNET_assert (0 == mst->off); | ||
188 | mst->hdr = GNUNET_realloc (mst->hdr, want); | ||
189 | ibuf = (char *) mst->hdr; | ||
190 | mst->curr_buf = want; | ||
191 | } | ||
192 | hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off]; | ||
193 | if (mst->pos - mst->off < want) | ||
194 | { | ||
195 | delta = GNUNET_MIN (want - (mst->pos - mst->off), size); | ||
196 | GNUNET_assert (mst->pos + delta <= mst->curr_buf); | ||
197 | GNUNET_memcpy (&ibuf[mst->pos], buf, delta); | ||
198 | mst->pos += delta; | ||
199 | buf += delta; | ||
200 | size -= delta; | ||
201 | } | ||
202 | if (mst->pos - mst->off < want) | ||
203 | { | ||
204 | if (purge) | ||
205 | { | ||
206 | mst->off = 0; | ||
207 | mst->pos = 0; | ||
208 | } | ||
209 | return GNUNET_OK; | ||
210 | } | ||
211 | if (one_shot == GNUNET_SYSERR) | ||
212 | { | ||
213 | /* cannot call callback again, but return value saying that | ||
214 | * we have another full message in the buffer */ | ||
215 | ret = GNUNET_NO; | ||
216 | goto copy; | ||
217 | } | ||
218 | if (one_shot == GNUNET_YES) | ||
219 | one_shot = GNUNET_SYSERR; | ||
220 | mst->off += want; | ||
221 | if (GNUNET_SYSERR == mst->cb (mst->cb_cls, client_identity, hdr)) | ||
222 | return GNUNET_SYSERR; | ||
223 | if (mst->off == mst->pos) | ||
224 | { | ||
225 | /* reset to beginning of buffer, it's free right now! */ | ||
226 | mst->off = 0; | ||
227 | mst->pos = 0; | ||
228 | } | ||
229 | } | ||
230 | GNUNET_assert (0 == mst->pos); | ||
231 | while (size > 0) | ||
232 | { | ||
233 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
234 | "Server-mst has %u bytes left in inbound buffer\n", | ||
235 | (unsigned int) size); | ||
236 | if (size < sizeof (struct GNUNET_MessageHeader)) | ||
237 | break; | ||
238 | offset = (unsigned long) buf; | ||
239 | need_align = (0 != (offset % ALIGN_FACTOR)) ? GNUNET_YES : GNUNET_NO; | ||
240 | if (GNUNET_NO == need_align) | ||
241 | { | ||
242 | /* can try to do zero-copy and process directly from original buffer */ | ||
243 | hdr = (const struct GNUNET_MessageHeader *) buf; | ||
244 | want = ntohs (hdr->size); | ||
245 | if (want < sizeof (struct GNUNET_MessageHeader)) | ||
246 | { | ||
247 | GNUNET_break_op (0); | ||
248 | mst->off = 0; | ||
249 | return GNUNET_SYSERR; | ||
250 | } | ||
251 | if (size < want) | ||
252 | break; /* or not: buffer incomplete, so copy to private buffer... */ | ||
253 | if (one_shot == GNUNET_SYSERR) | ||
254 | { | ||
255 | /* cannot call callback again, but return value saying that | ||
256 | * we have another full message in the buffer */ | ||
257 | ret = GNUNET_NO; | ||
258 | goto copy; | ||
259 | } | ||
260 | if (one_shot == GNUNET_YES) | ||
261 | one_shot = GNUNET_SYSERR; | ||
262 | if (GNUNET_SYSERR == mst->cb (mst->cb_cls, client_identity, hdr)) | ||
263 | return GNUNET_SYSERR; | ||
264 | buf += want; | ||
265 | size -= want; | ||
266 | } | ||
267 | else | ||
268 | { | ||
269 | /* need to copy to private buffer to align; | ||
270 | * yes, we go a bit more spagetti than usual here */ | ||
271 | goto do_align; | ||
272 | } | ||
273 | } | ||
274 | copy: | ||
275 | if ((size > 0) && (!purge)) | ||
276 | { | ||
277 | if (size + mst->pos > mst->curr_buf) | ||
278 | { | ||
279 | mst->hdr = GNUNET_realloc (mst->hdr, size + mst->pos); | ||
280 | ibuf = (char *) mst->hdr; | ||
281 | mst->curr_buf = size + mst->pos; | ||
282 | } | ||
283 | GNUNET_assert (size + mst->pos <= mst->curr_buf); | ||
284 | GNUNET_memcpy (&ibuf[mst->pos], buf, size); | ||
285 | mst->pos += size; | ||
286 | } | ||
287 | if (purge) | ||
288 | { | ||
289 | mst->off = 0; | ||
290 | mst->pos = 0; | ||
291 | } | ||
292 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
293 | "Server-mst leaves %u bytes in private buffer\n", | ||
294 | (unsigned int) (mst->pos - mst->off)); | ||
295 | return ret; | ||
296 | } | ||
297 | |||
298 | |||
299 | /** | ||
300 | * Destroys a tokenizer. | ||
301 | * | ||
302 | * @param mst tokenizer to destroy | ||
303 | */ | ||
304 | void | ||
305 | GNUNET_SERVER_mst_destroy (struct GNUNET_SERVER_MessageStreamTokenizer *mst) | ||
306 | { | ||
307 | GNUNET_free (mst->hdr); | ||
308 | GNUNET_free (mst); | ||
309 | } | ||
310 | |||
311 | |||
312 | |||
313 | /* end of server_mst.c */ | ||
diff --git a/src/util/server_nc.c b/src/util/server_nc.c deleted file mode 100644 index a95cd7f6d..000000000 --- a/src/util/server_nc.c +++ /dev/null | |||
@@ -1,472 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2010 GNUnet e.V. | ||
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., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file util/server_nc.c | ||
23 | * @brief convenience functions for transmission of | ||
24 | * a notification stream | ||
25 | * @author Christian Grothoff | ||
26 | */ | ||
27 | |||
28 | #include "platform.h" | ||
29 | #include "gnunet_util_lib.h" | ||
30 | |||
31 | #define LOG(kind,...) GNUNET_log_from (kind, "util-server-nc", __VA_ARGS__) | ||
32 | |||
33 | |||
34 | /** | ||
35 | * Entry in list of messages pending to be transmitted. | ||
36 | */ | ||
37 | struct PendingMessageList | ||
38 | { | ||
39 | |||
40 | /** | ||
41 | * This is a doubly-linked list. | ||
42 | */ | ||
43 | struct PendingMessageList *next; | ||
44 | |||
45 | /** | ||
46 | * This is a doubly-linked list. | ||
47 | */ | ||
48 | struct PendingMessageList *prev; | ||
49 | |||
50 | /** | ||
51 | * Message to transmit (allocated at the end of this | ||
52 | * struct, do not free) | ||
53 | */ | ||
54 | const struct GNUNET_MessageHeader *msg; | ||
55 | |||
56 | /** | ||
57 | * Can this message be dropped? | ||
58 | */ | ||
59 | int can_drop; | ||
60 | |||
61 | }; | ||
62 | |||
63 | |||
64 | /** | ||
65 | * Lists of clients we manage for notifications. | ||
66 | */ | ||
67 | struct ClientList | ||
68 | { | ||
69 | |||
70 | /** | ||
71 | * This is a doubly linked list. | ||
72 | */ | ||
73 | struct ClientList *next; | ||
74 | |||
75 | /** | ||
76 | * This is a doubly linked list. | ||
77 | */ | ||
78 | struct ClientList *prev; | ||
79 | |||
80 | /** | ||
81 | * Overall context this client belongs to. | ||
82 | */ | ||
83 | struct GNUNET_SERVER_NotificationContext *nc; | ||
84 | |||
85 | /** | ||
86 | * Handle to the client. | ||
87 | */ | ||
88 | struct GNUNET_SERVER_Client *client; | ||
89 | |||
90 | /** | ||
91 | * Handle for pending transmission request to the client (or NULL). | ||
92 | */ | ||
93 | struct GNUNET_SERVER_TransmitHandle *th; | ||
94 | |||
95 | /** | ||
96 | * Head of linked list of requests queued for transmission. | ||
97 | */ | ||
98 | struct PendingMessageList *pending_head; | ||
99 | |||
100 | /** | ||
101 | * Tail of linked list of requests queued for transmission. | ||
102 | */ | ||
103 | struct PendingMessageList *pending_tail; | ||
104 | |||
105 | /** | ||
106 | * Number of messages currently in the list. | ||
107 | */ | ||
108 | unsigned int num_pending; | ||
109 | |||
110 | }; | ||
111 | |||
112 | |||
113 | /** | ||
114 | * The notification context is the key datastructure for a convenience | ||
115 | * API used for transmission of notifications to the client until the | ||
116 | * client disconnects (or the notification context is destroyed, in | ||
117 | * which case we disconnect these clients). Essentially, all | ||
118 | * (notification) messages are queued up until the client is able to | ||
119 | * read them. | ||
120 | */ | ||
121 | struct GNUNET_SERVER_NotificationContext | ||
122 | { | ||
123 | |||
124 | /** | ||
125 | * Server we do notifications for. | ||
126 | */ | ||
127 | struct GNUNET_SERVER_Handle *server; | ||
128 | |||
129 | /** | ||
130 | * Head of list of clients receiving notifications. | ||
131 | */ | ||
132 | struct ClientList *clients_head; | ||
133 | |||
134 | /** | ||
135 | * Tail of list of clients receiving notifications. | ||
136 | */ | ||
137 | struct ClientList *clients_tail; | ||
138 | |||
139 | /** | ||
140 | * Maximum number of optional messages to queue per client. | ||
141 | */ | ||
142 | unsigned int queue_length; | ||
143 | |||
144 | }; | ||
145 | |||
146 | |||
147 | /** | ||
148 | * Client has disconnected, clean up. | ||
149 | * | ||
150 | * @param cls our `struct GNUNET_SERVER_NotificationContext *` | ||
151 | * @param client handle of client that disconnected | ||
152 | */ | ||
153 | static void | ||
154 | handle_client_disconnect (void *cls, | ||
155 | struct GNUNET_SERVER_Client *client) | ||
156 | { | ||
157 | struct GNUNET_SERVER_NotificationContext *nc = cls; | ||
158 | struct ClientList *pos; | ||
159 | struct PendingMessageList *pml; | ||
160 | |||
161 | if (NULL == client) | ||
162 | { | ||
163 | nc->server = NULL; | ||
164 | return; | ||
165 | } | ||
166 | for (pos = nc->clients_head; NULL != pos; pos = pos->next) | ||
167 | if (pos->client == client) | ||
168 | break; | ||
169 | if (NULL == pos) | ||
170 | return; | ||
171 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
172 | "Client disconnected, cleaning up %u messages in NC queue\n", | ||
173 | pos->num_pending); | ||
174 | GNUNET_CONTAINER_DLL_remove (nc->clients_head, | ||
175 | nc->clients_tail, | ||
176 | pos); | ||
177 | while (NULL != (pml = pos->pending_head)) | ||
178 | { | ||
179 | GNUNET_CONTAINER_DLL_remove (pos->pending_head, | ||
180 | pos->pending_tail, | ||
181 | pml); | ||
182 | GNUNET_free (pml); | ||
183 | pos->num_pending--; | ||
184 | } | ||
185 | if (NULL != pos->th) | ||
186 | { | ||
187 | GNUNET_SERVER_notify_transmit_ready_cancel (pos->th); | ||
188 | pos->th = NULL; | ||
189 | } | ||
190 | GNUNET_SERVER_client_drop (client); | ||
191 | GNUNET_assert (0 == pos->num_pending); | ||
192 | GNUNET_free (pos); | ||
193 | } | ||
194 | |||
195 | |||
196 | /** | ||
197 | * Create a new notification context. | ||
198 | * | ||
199 | * @param server server for which this function creates the context | ||
200 | * @param queue_length maximum number of messages to keep in | ||
201 | * the notification queue; optional messages are dropped | ||
202 | * if the queue gets longer than this number of messages | ||
203 | * @return handle to the notification context | ||
204 | */ | ||
205 | struct GNUNET_SERVER_NotificationContext * | ||
206 | GNUNET_SERVER_notification_context_create (struct GNUNET_SERVER_Handle *server, | ||
207 | unsigned int queue_length) | ||
208 | { | ||
209 | struct GNUNET_SERVER_NotificationContext *ret; | ||
210 | |||
211 | ret = GNUNET_new (struct GNUNET_SERVER_NotificationContext); | ||
212 | ret->server = server; | ||
213 | ret->queue_length = queue_length; | ||
214 | GNUNET_SERVER_disconnect_notify (server, | ||
215 | &handle_client_disconnect, | ||
216 | ret); | ||
217 | return ret; | ||
218 | } | ||
219 | |||
220 | |||
221 | /** | ||
222 | * Destroy the context, force disconnect for all clients. | ||
223 | * | ||
224 | * @param nc context to destroy. | ||
225 | */ | ||
226 | void | ||
227 | GNUNET_SERVER_notification_context_destroy (struct GNUNET_SERVER_NotificationContext *nc) | ||
228 | { | ||
229 | struct ClientList *pos; | ||
230 | struct PendingMessageList *pml; | ||
231 | |||
232 | while (NULL != (pos = nc->clients_head)) | ||
233 | { | ||
234 | GNUNET_CONTAINER_DLL_remove (nc->clients_head, | ||
235 | nc->clients_tail, | ||
236 | pos); | ||
237 | if (NULL != pos->th) | ||
238 | { | ||
239 | GNUNET_SERVER_notify_transmit_ready_cancel (pos->th); | ||
240 | pos->th = NULL; | ||
241 | } | ||
242 | GNUNET_SERVER_client_drop (pos->client); | ||
243 | while (NULL != (pml = pos->pending_head)) | ||
244 | { | ||
245 | GNUNET_CONTAINER_DLL_remove (pos->pending_head, | ||
246 | pos->pending_tail, | ||
247 | pml); | ||
248 | GNUNET_free (pml); | ||
249 | pos->num_pending--; | ||
250 | } | ||
251 | GNUNET_assert (0 == pos->num_pending); | ||
252 | GNUNET_free (pos); | ||
253 | } | ||
254 | if (NULL != nc->server) | ||
255 | GNUNET_SERVER_disconnect_notify_cancel (nc->server, | ||
256 | &handle_client_disconnect, | ||
257 | nc); | ||
258 | GNUNET_free (nc); | ||
259 | } | ||
260 | |||
261 | |||
262 | /** | ||
263 | * Add a client to the notification context. | ||
264 | * | ||
265 | * @param nc context to modify | ||
266 | * @param client client to add | ||
267 | */ | ||
268 | void | ||
269 | GNUNET_SERVER_notification_context_add (struct GNUNET_SERVER_NotificationContext *nc, | ||
270 | struct GNUNET_SERVER_Client *client) | ||
271 | { | ||
272 | struct ClientList *cl; | ||
273 | |||
274 | for (cl = nc->clients_head; NULL != cl; cl = cl->next) | ||
275 | if (cl->client == client) | ||
276 | return; /* already present */ | ||
277 | cl = GNUNET_new (struct ClientList); | ||
278 | GNUNET_CONTAINER_DLL_insert (nc->clients_head, | ||
279 | nc->clients_tail, | ||
280 | cl); | ||
281 | cl->nc = nc; | ||
282 | cl->client = client; | ||
283 | GNUNET_SERVER_client_keep (client); | ||
284 | } | ||
285 | |||
286 | |||
287 | /** | ||
288 | * Function called to notify a client about the socket begin ready to | ||
289 | * queue more data. @a buf will be NULL and @a size zero if the socket | ||
290 | * was closed for writing in the meantime. | ||
291 | * | ||
292 | * @param cls the `struct ClientList *` | ||
293 | * @param size number of bytes available in @a buf | ||
294 | * @param buf where the callee should write the message | ||
295 | * @return number of bytes written to buf | ||
296 | */ | ||
297 | static size_t | ||
298 | transmit_message (void *cls, | ||
299 | size_t size, | ||
300 | void *buf) | ||
301 | { | ||
302 | struct ClientList *cl = cls; | ||
303 | char *cbuf = buf; | ||
304 | struct PendingMessageList *pml; | ||
305 | uint16_t msize; | ||
306 | size_t ret; | ||
307 | |||
308 | cl->th = NULL; | ||
309 | if (NULL == buf) | ||
310 | { | ||
311 | /* 'cl' should be freed via disconnect notification shortly */ | ||
312 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
313 | "Failed to transmit message from NC queue to client\n"); | ||
314 | return 0; | ||
315 | } | ||
316 | ret = 0; | ||
317 | while (NULL != (pml = cl->pending_head)) | ||
318 | { | ||
319 | msize = ntohs (pml->msg->size); | ||
320 | if (size < msize) | ||
321 | break; | ||
322 | GNUNET_CONTAINER_DLL_remove (cl->pending_head, | ||
323 | cl->pending_tail, | ||
324 | pml); | ||
325 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
326 | "Copying message of type %u and size %u from pending queue to transmission buffer\n", | ||
327 | ntohs (pml->msg->type), | ||
328 | msize); | ||
329 | GNUNET_memcpy (&cbuf[ret], pml->msg, msize); | ||
330 | ret += msize; | ||
331 | size -= msize; | ||
332 | GNUNET_free (pml); | ||
333 | cl->num_pending--; | ||
334 | } | ||
335 | if (NULL != pml) | ||
336 | { | ||
337 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
338 | "Have %u messages left in NC queue, will try transmission again\n", | ||
339 | cl->num_pending); | ||
340 | cl->th = | ||
341 | GNUNET_SERVER_notify_transmit_ready (cl->client, | ||
342 | ntohs (pml->msg->size), | ||
343 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
344 | &transmit_message, cl); | ||
345 | } | ||
346 | else | ||
347 | { | ||
348 | GNUNET_assert (0 == cl->num_pending); | ||
349 | } | ||
350 | return ret; | ||
351 | } | ||
352 | |||
353 | |||
354 | /** | ||
355 | * Send a message to a particular client. | ||
356 | * | ||
357 | * @param nc context to modify | ||
358 | * @param client client to transmit to | ||
359 | * @param msg message to send | ||
360 | * @param can_drop can this message be dropped due to queue length limitations | ||
361 | */ | ||
362 | static void | ||
363 | do_unicast (struct GNUNET_SERVER_NotificationContext *nc, | ||
364 | struct ClientList *client, | ||
365 | const struct GNUNET_MessageHeader *msg, | ||
366 | int can_drop) | ||
367 | { | ||
368 | struct PendingMessageList *pml; | ||
369 | uint16_t size; | ||
370 | |||
371 | if ( (client->num_pending > nc->queue_length) && | ||
372 | (GNUNET_YES == can_drop) ) | ||
373 | { | ||
374 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
375 | "Dropping message of type %u and size %u due to full queue (%u entries)\n", | ||
376 | ntohs (msg->type), ntohs (msg->size), (unsigned int) nc->queue_length); | ||
377 | return; /* drop! */ | ||
378 | } | ||
379 | if (client->num_pending > nc->queue_length) | ||
380 | { | ||
381 | /* FIXME: consider checking for other messages in the | ||
382 | * queue that are 'droppable' */ | ||
383 | } | ||
384 | client->num_pending++; | ||
385 | size = ntohs (msg->size); | ||
386 | pml = GNUNET_malloc (sizeof (struct PendingMessageList) + size); | ||
387 | pml->msg = (const struct GNUNET_MessageHeader *) &pml[1]; | ||
388 | pml->can_drop = can_drop; | ||
389 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
390 | "Adding message of type %u and size %u to pending queue (which has %u entries)\n", | ||
391 | ntohs (msg->type), | ||
392 | ntohs (msg->size), | ||
393 | (unsigned int) nc->queue_length); | ||
394 | GNUNET_memcpy (&pml[1], msg, size); | ||
395 | /* append */ | ||
396 | GNUNET_CONTAINER_DLL_insert_tail (client->pending_head, | ||
397 | client->pending_tail, | ||
398 | pml); | ||
399 | if (NULL == client->th) | ||
400 | client->th = | ||
401 | GNUNET_SERVER_notify_transmit_ready (client->client, | ||
402 | ntohs (client->pending_head-> | ||
403 | msg->size), | ||
404 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
405 | &transmit_message, client); | ||
406 | } | ||
407 | |||
408 | |||
409 | /** | ||
410 | * Send a message to a particular client; must have | ||
411 | * already been added to the notification context. | ||
412 | * | ||
413 | * @param nc context to modify | ||
414 | * @param client client to transmit to | ||
415 | * @param msg message to send | ||
416 | * @param can_drop can this message be dropped due to queue length limitations | ||
417 | */ | ||
418 | void | ||
419 | GNUNET_SERVER_notification_context_unicast (struct GNUNET_SERVER_NotificationContext *nc, | ||
420 | struct GNUNET_SERVER_Client *client, | ||
421 | const struct GNUNET_MessageHeader *msg, | ||
422 | int can_drop) | ||
423 | { | ||
424 | struct ClientList *pos; | ||
425 | |||
426 | for (pos = nc->clients_head; NULL != pos; pos = pos->next) | ||
427 | if (pos->client == client) | ||
428 | break; | ||
429 | GNUNET_assert (NULL != pos); | ||
430 | do_unicast (nc, pos, msg, can_drop); | ||
431 | } | ||
432 | |||
433 | |||
434 | /** | ||
435 | * Send a message to all clients of this context. | ||
436 | * | ||
437 | * @param nc context to modify | ||
438 | * @param msg message to send | ||
439 | * @param can_drop can this message be dropped due to queue length limitations | ||
440 | */ | ||
441 | void | ||
442 | GNUNET_SERVER_notification_context_broadcast (struct | ||
443 | GNUNET_SERVER_NotificationContext *nc, | ||
444 | const struct GNUNET_MessageHeader *msg, | ||
445 | int can_drop) | ||
446 | { | ||
447 | struct ClientList *pos; | ||
448 | |||
449 | for (pos = nc->clients_head; NULL != pos; pos = pos->next) | ||
450 | do_unicast (nc, pos, msg, can_drop); | ||
451 | } | ||
452 | |||
453 | |||
454 | /** | ||
455 | * Return active number of subscribers in this context. | ||
456 | * | ||
457 | * @param nc context to query | ||
458 | * @return number of current subscribers | ||
459 | */ | ||
460 | unsigned int | ||
461 | GNUNET_SERVER_notification_context_get_size (struct GNUNET_SERVER_NotificationContext *nc) | ||
462 | { | ||
463 | unsigned int num; | ||
464 | struct ClientList *pos; | ||
465 | |||
466 | num = 0; | ||
467 | for (pos = nc->clients_head; NULL != pos; pos = pos->next) | ||
468 | num++; | ||
469 | return num; | ||
470 | } | ||
471 | |||
472 | /* end of server_nc.c */ | ||
diff --git a/src/util/server_tc.c b/src/util/server_tc.c deleted file mode 100644 index 8ae380a85..000000000 --- a/src/util/server_tc.c +++ /dev/null | |||
@@ -1,242 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009 GNUnet e.V. | ||
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., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file util/server_tc.c | ||
23 | * @brief convenience functions for transmission of | ||
24 | * complex responses as a server | ||
25 | * @author Christian Grothoff | ||
26 | */ | ||
27 | |||
28 | #include "platform.h" | ||
29 | #include "gnunet_util_lib.h" | ||
30 | |||
31 | |||
32 | #define LOG(kind,...) GNUNET_log_from (kind, "util-server-tc", __VA_ARGS__) | ||
33 | |||
34 | |||
35 | /** | ||
36 | * How much buffer space do we want to have at least | ||
37 | * before transmitting another increment? | ||
38 | */ | ||
39 | #define MIN_BLOCK_SIZE 128 | ||
40 | |||
41 | |||
42 | |||
43 | struct GNUNET_SERVER_TransmitContext | ||
44 | { | ||
45 | /** | ||
46 | * Which client are we transmitting to? | ||
47 | */ | ||
48 | struct GNUNET_SERVER_Client *client; | ||
49 | |||
50 | /** | ||
51 | * Transmission buffer. (current offset for writing). | ||
52 | */ | ||
53 | char *buf; | ||
54 | |||
55 | /** | ||
56 | * Number of bytes in buf. | ||
57 | */ | ||
58 | size_t total; | ||
59 | |||
60 | /** | ||
61 | * Offset for writing in buf. | ||
62 | */ | ||
63 | size_t off; | ||
64 | |||
65 | /** | ||
66 | * Timeout for this request. | ||
67 | */ | ||
68 | struct GNUNET_TIME_Absolute timeout; | ||
69 | }; | ||
70 | |||
71 | |||
72 | /** | ||
73 | * Helper function for incremental transmission of the response. | ||
74 | */ | ||
75 | static size_t | ||
76 | transmit_response (void *cls, size_t size, void *buf) | ||
77 | { | ||
78 | struct GNUNET_SERVER_TransmitContext *tc = cls; | ||
79 | size_t msize; | ||
80 | |||
81 | if (NULL == buf) | ||
82 | { | ||
83 | GNUNET_SERVER_transmit_context_destroy (tc, GNUNET_SYSERR); | ||
84 | return 0; | ||
85 | } | ||
86 | if (tc->total - tc->off > size) | ||
87 | msize = size; | ||
88 | else | ||
89 | msize = tc->total - tc->off; | ||
90 | GNUNET_memcpy (buf, &tc->buf[tc->off], msize); | ||
91 | tc->off += msize; | ||
92 | if (tc->total == tc->off) | ||
93 | { | ||
94 | GNUNET_SERVER_receive_done (tc->client, GNUNET_OK); | ||
95 | GNUNET_SERVER_client_drop (tc->client); | ||
96 | GNUNET_free_non_null (tc->buf); | ||
97 | GNUNET_free (tc); | ||
98 | } | ||
99 | else | ||
100 | { | ||
101 | if (NULL == | ||
102 | GNUNET_SERVER_notify_transmit_ready (tc->client, | ||
103 | GNUNET_MIN (MIN_BLOCK_SIZE, | ||
104 | tc->total - tc->off), | ||
105 | GNUNET_TIME_absolute_get_remaining | ||
106 | (tc->timeout), &transmit_response, | ||
107 | tc)) | ||
108 | { | ||
109 | GNUNET_break (0); | ||
110 | GNUNET_SERVER_transmit_context_destroy (tc, GNUNET_SYSERR); | ||
111 | } | ||
112 | } | ||
113 | return msize; | ||
114 | } | ||
115 | |||
116 | |||
117 | /** | ||
118 | * Create a new transmission context for the | ||
119 | * given client. | ||
120 | * | ||
121 | * @param client client to create the context for. | ||
122 | * @return NULL on error | ||
123 | */ | ||
124 | struct GNUNET_SERVER_TransmitContext * | ||
125 | GNUNET_SERVER_transmit_context_create (struct GNUNET_SERVER_Client *client) | ||
126 | { | ||
127 | struct GNUNET_SERVER_TransmitContext *tc; | ||
128 | |||
129 | GNUNET_assert (NULL != client); | ||
130 | tc = GNUNET_new (struct GNUNET_SERVER_TransmitContext); | ||
131 | GNUNET_SERVER_client_keep (client); | ||
132 | tc->client = client; | ||
133 | return tc; | ||
134 | } | ||
135 | |||
136 | |||
137 | /** | ||
138 | * Append a message to the transmission context. | ||
139 | * All messages in the context will be sent by | ||
140 | * the transmit_context_run method. | ||
141 | * | ||
142 | * @param tc context to use | ||
143 | * @param data what to append to the result message | ||
144 | * @param length length of data | ||
145 | * @param type type of the message | ||
146 | */ | ||
147 | void | ||
148 | GNUNET_SERVER_transmit_context_append_data (struct GNUNET_SERVER_TransmitContext | ||
149 | *tc, const void *data, | ||
150 | size_t length, uint16_t type) | ||
151 | { | ||
152 | struct GNUNET_MessageHeader *msg; | ||
153 | size_t size; | ||
154 | |||
155 | GNUNET_assert (length < GNUNET_SERVER_MAX_MESSAGE_SIZE); | ||
156 | size = length + sizeof (struct GNUNET_MessageHeader); | ||
157 | GNUNET_assert (size > length); | ||
158 | tc->buf = GNUNET_realloc (tc->buf, tc->total + size); | ||
159 | msg = (struct GNUNET_MessageHeader *) &tc->buf[tc->total]; | ||
160 | tc->total += size; | ||
161 | msg->size = htons (size); | ||
162 | msg->type = htons (type); | ||
163 | GNUNET_memcpy (&msg[1], data, length); | ||
164 | } | ||
165 | |||
166 | |||
167 | /** | ||
168 | * Append a message to the transmission context. | ||
169 | * All messages in the context will be sent by | ||
170 | * the transmit_context_run method. | ||
171 | * | ||
172 | * @param tc context to use | ||
173 | * @param msg message to append | ||
174 | */ | ||
175 | void | ||
176 | GNUNET_SERVER_transmit_context_append_message (struct | ||
177 | GNUNET_SERVER_TransmitContext | ||
178 | *tc, | ||
179 | const struct GNUNET_MessageHeader | ||
180 | *msg) | ||
181 | { | ||
182 | struct GNUNET_MessageHeader *m; | ||
183 | uint16_t size; | ||
184 | |||
185 | size = ntohs (msg->size); | ||
186 | tc->buf = GNUNET_realloc (tc->buf, tc->total + size); | ||
187 | m = (struct GNUNET_MessageHeader *) &tc->buf[tc->total]; | ||
188 | tc->total += size; | ||
189 | GNUNET_memcpy (m, msg, size); | ||
190 | } | ||
191 | |||
192 | |||
193 | /** | ||
194 | * Execute a transmission context. If there is | ||
195 | * an error in the transmission, the #GNUNET_SERVER_receive_done() | ||
196 | * method will be called with an error code (#GNUNET_SYSERR), | ||
197 | * otherwise with #GNUNET_OK. | ||
198 | * | ||
199 | * @param tc transmission context to use | ||
200 | * @param timeout when to time out and abort the transmission | ||
201 | */ | ||
202 | void | ||
203 | GNUNET_SERVER_transmit_context_run (struct GNUNET_SERVER_TransmitContext *tc, | ||
204 | struct GNUNET_TIME_Relative timeout) | ||
205 | { | ||
206 | tc->timeout = GNUNET_TIME_relative_to_absolute (timeout); | ||
207 | if (NULL == | ||
208 | GNUNET_SERVER_notify_transmit_ready (tc->client, | ||
209 | GNUNET_MIN (MIN_BLOCK_SIZE, | ||
210 | tc->total), timeout, | ||
211 | &transmit_response, tc)) | ||
212 | { | ||
213 | GNUNET_break (0); | ||
214 | GNUNET_SERVER_transmit_context_destroy (tc, GNUNET_SYSERR); | ||
215 | } | ||
216 | } | ||
217 | |||
218 | |||
219 | /** | ||
220 | * Destroy a transmission context. This function must not be called | ||
221 | * after 'GNUNET_SERVER_transmit_context_run'. | ||
222 | * | ||
223 | * @param tc transmission context to destroy | ||
224 | * @param success code to give to 'GNUNET_SERVER_receive_done' for | ||
225 | * the client: GNUNET_OK to keep the connection open and | ||
226 | * continue to receive | ||
227 | * GNUNET_NO to close the connection (normal behavior) | ||
228 | * GNUNET_SYSERR to close the connection (signal | ||
229 | * serious error) | ||
230 | */ | ||
231 | void | ||
232 | GNUNET_SERVER_transmit_context_destroy (struct GNUNET_SERVER_TransmitContext | ||
233 | *tc, int success) | ||
234 | { | ||
235 | GNUNET_SERVER_receive_done (tc->client, success); | ||
236 | GNUNET_SERVER_client_drop (tc->client); | ||
237 | GNUNET_free_non_null (tc->buf); | ||
238 | GNUNET_free (tc); | ||
239 | } | ||
240 | |||
241 | |||
242 | /* end of server_tc.c */ | ||
diff --git a/src/util/service.c b/src/util/service.c index 496904fb1..800d09a42 100644 --- a/src/util/service.c +++ b/src/util/service.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet. | 2 | This file is part of GNUnet. |
3 | Copyright (C) 2009, 2012 GNUnet e.V. | 3 | Copyright (C) 2016 GNUnet e.V. |
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 |
@@ -19,9 +19,10 @@ | |||
19 | */ | 19 | */ |
20 | 20 | ||
21 | /** | 21 | /** |
22 | * @file util/service.c | 22 | * @file util/service_new.c |
23 | * @brief functions related to starting services | 23 | * @brief functions related to starting services (redesign) |
24 | * @author Christian Grothoff | 24 | * @author Christian Grothoff |
25 | * @author Florian Dold | ||
25 | */ | 26 | */ |
26 | #include "platform.h" | 27 | #include "platform.h" |
27 | #include "gnunet_util_lib.h" | 28 | #include "gnunet_util_lib.h" |
@@ -43,77 +44,44 @@ | |||
43 | #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util-service", syscall, filename) | 44 | #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util-service", syscall, filename) |
44 | 45 | ||
45 | 46 | ||
46 | /* ******************* access control ******************** */ | ||
47 | |||
48 | /** | 47 | /** |
49 | * Check if the given IP address is in the list of IP addresses. | 48 | * Information the service tracks per listen operation. |
50 | * | ||
51 | * @param list a list of networks | ||
52 | * @param add the IP to check (in network byte order) | ||
53 | * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is | ||
54 | */ | 49 | */ |
55 | static int | 50 | struct ServiceListenContext |
56 | check_ipv4_listed (const struct GNUNET_STRINGS_IPv4NetworkPolicy *list, | ||
57 | const struct in_addr *add) | ||
58 | { | 51 | { |
59 | unsigned int i; | ||
60 | 52 | ||
61 | if (NULL == list) | 53 | /** |
62 | return GNUNET_NO; | 54 | * Kept in a DLL. |
63 | i = 0; | 55 | */ |
64 | while ((list[i].network.s_addr != 0) || (list[i].netmask.s_addr != 0)) | 56 | struct ServiceListenContext *next; |
65 | { | ||
66 | if ((add->s_addr & list[i].netmask.s_addr) == | ||
67 | (list[i].network.s_addr & list[i].netmask.s_addr)) | ||
68 | return GNUNET_YES; | ||
69 | i++; | ||
70 | } | ||
71 | return GNUNET_NO; | ||
72 | } | ||
73 | 57 | ||
58 | /** | ||
59 | * Kept in a DLL. | ||
60 | */ | ||
61 | struct ServiceListenContext *prev; | ||
74 | 62 | ||
75 | /** | 63 | /** |
76 | * Check if the given IP address is in the list of IP addresses. | 64 | * Service this listen context belongs to. |
77 | * | 65 | */ |
78 | * @param list a list of networks | 66 | struct GNUNET_SERVICE_Handle *sh; |
79 | * @param ip the IP to check (in network byte order) | ||
80 | * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is | ||
81 | */ | ||
82 | static int | ||
83 | check_ipv6_listed (const struct GNUNET_STRINGS_IPv6NetworkPolicy *list, | ||
84 | const struct in6_addr *ip) | ||
85 | { | ||
86 | unsigned int i; | ||
87 | unsigned int j; | ||
88 | struct in6_addr zero; | ||
89 | 67 | ||
90 | if (NULL == list) | 68 | /** |
91 | return GNUNET_NO; | 69 | * Socket we are listening on. |
92 | memset (&zero, 0, sizeof (struct in6_addr)); | 70 | */ |
93 | i = 0; | 71 | struct GNUNET_NETWORK_Handle *listen_socket; |
94 | NEXT: | ||
95 | while (0 != memcmp (&zero, &list[i].network, sizeof (struct in6_addr))) | ||
96 | { | ||
97 | for (j = 0; j < sizeof (struct in6_addr) / sizeof (int); j++) | ||
98 | if (((((int *) ip)[j] & ((int *) &list[i].netmask)[j])) != | ||
99 | (((int *) &list[i].network)[j] & ((int *) &list[i].netmask)[j])) | ||
100 | { | ||
101 | i++; | ||
102 | goto NEXT; | ||
103 | } | ||
104 | return GNUNET_YES; | ||
105 | } | ||
106 | return GNUNET_NO; | ||
107 | } | ||
108 | 72 | ||
73 | /** | ||
74 | * Task scheduled to do the listening. | ||
75 | */ | ||
76 | struct GNUNET_SCHEDULER_Task *listen_task; | ||
109 | 77 | ||
110 | /* ****************** service struct ****************** */ | 78 | }; |
111 | 79 | ||
112 | 80 | ||
113 | /** | 81 | /** |
114 | * Context for "service_task". | 82 | * Handle to a service. |
115 | */ | 83 | */ |
116 | struct GNUNET_SERVICE_Context | 84 | struct GNUNET_SERVICE_Handle |
117 | { | 85 | { |
118 | /** | 86 | /** |
119 | * Our configuration. | 87 | * Our configuration. |
@@ -121,25 +89,54 @@ struct GNUNET_SERVICE_Context | |||
121 | const struct GNUNET_CONFIGURATION_Handle *cfg; | 89 | const struct GNUNET_CONFIGURATION_Handle *cfg; |
122 | 90 | ||
123 | /** | 91 | /** |
124 | * Handle for the server. | 92 | * Name of our service. |
125 | */ | 93 | */ |
126 | struct GNUNET_SERVER_Handle *server; | 94 | const char *service_name; |
127 | 95 | ||
128 | /** | 96 | /** |
129 | * NULL-terminated array of addresses to bind to, NULL if we got pre-bound | 97 | * Main service-specific task to run. |
130 | * listen sockets. | ||
131 | */ | 98 | */ |
132 | struct sockaddr **addrs; | 99 | GNUNET_SERVICE_InitCallback service_init_cb; |
133 | 100 | ||
134 | /** | 101 | /** |
135 | * Name of our service. | 102 | * Function to call when clients connect. |
136 | */ | 103 | */ |
137 | const char *service_name; | 104 | GNUNET_SERVICE_ConnectHandler connect_cb; |
138 | 105 | ||
139 | /** | 106 | /** |
140 | * Main service-specific task to run. | 107 | * Function to call when clients disconnect / are disconnected. |
141 | */ | 108 | */ |
142 | GNUNET_SERVICE_Main task; | 109 | GNUNET_SERVICE_DisconnectHandler disconnect_cb; |
110 | |||
111 | /** | ||
112 | * Closure for @e service_init_cb, @e connect_cb, @e disconnect_cb. | ||
113 | */ | ||
114 | void *cb_cls; | ||
115 | |||
116 | /** | ||
117 | * DLL of listen sockets used to accept new connections. | ||
118 | */ | ||
119 | struct ServiceListenContext *slc_head; | ||
120 | |||
121 | /** | ||
122 | * DLL of listen sockets used to accept new connections. | ||
123 | */ | ||
124 | struct ServiceListenContext *slc_tail; | ||
125 | |||
126 | /** | ||
127 | * Our clients, kept in a DLL. | ||
128 | */ | ||
129 | struct GNUNET_SERVICE_Client *clients_head; | ||
130 | |||
131 | /** | ||
132 | * Our clients, kept in a DLL. | ||
133 | */ | ||
134 | struct GNUNET_SERVICE_Client *clients_tail; | ||
135 | |||
136 | /** | ||
137 | * Message handlers to use for all clients. | ||
138 | */ | ||
139 | struct GNUNET_MQ_MessageHandler *handlers; | ||
143 | 140 | ||
144 | /** | 141 | /** |
145 | * Closure for @e task. | 142 | * Closure for @e task. |
@@ -169,30 +166,38 @@ struct GNUNET_SERVICE_Context | |||
169 | struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_allowed; | 166 | struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_allowed; |
170 | 167 | ||
171 | /** | 168 | /** |
172 | * My (default) message handlers. Adjusted copy | 169 | * Do we require a matching UID for UNIX domain socket connections? |
173 | * of "defhandlers". | 170 | * #GNUNET_NO means that the UID does not have to match (however, |
171 | * @e match_gid may still impose other access control checks). | ||
174 | */ | 172 | */ |
175 | struct GNUNET_SERVER_MessageHandler *my_handlers; | 173 | int match_uid; |
176 | 174 | ||
177 | /** | 175 | /** |
178 | * Array of the lengths of the entries in addrs. | 176 | * Do we require a matching GID for UNIX domain socket connections? |
177 | * Ignored if @e match_uid is #GNUNET_YES. Note that this is about | ||
178 | * checking that the client's UID is in our group OR that the | ||
179 | * client's GID is our GID. If both "match_gid" and @e match_uid are | ||
180 | * #GNUNET_NO, all users on the local system have access. | ||
179 | */ | 181 | */ |
180 | socklen_t *addrlens; | 182 | int match_gid; |
181 | 183 | ||
182 | /** | 184 | /** |
183 | * NULL-terminated array of listen sockets we should take over. | 185 | * Set to #GNUNET_YES if we got a shutdown signal and terminate |
186 | * the service if #have_non_monitor_clients() returns #GNUNET_YES. | ||
184 | */ | 187 | */ |
185 | struct GNUNET_NETWORK_Handle **lsocks; | 188 | int got_shutdown; |
186 | 189 | ||
187 | /** | 190 | /** |
188 | * Task ID of the shutdown task. | 191 | * Our options. |
189 | */ | 192 | */ |
190 | struct GNUNET_SCHEDULER_Task *shutdown_task; | 193 | enum GNUNET_SERVICE_Options options; |
191 | 194 | ||
192 | /** | 195 | /** |
193 | * Idle timeout for server. | 196 | * If we are daemonizing, this FD is set to the |
197 | * pipe to the parent. Send '.' if we started | ||
198 | * ok, '!' if not. -1 if we are not daemonizing. | ||
194 | */ | 199 | */ |
195 | struct GNUNET_TIME_Relative timeout; | 200 | int ready_confirm_fd; |
196 | 201 | ||
197 | /** | 202 | /** |
198 | * Overall success/failure of the service start. | 203 | * Overall success/failure of the service start. |
@@ -200,182 +205,203 @@ struct GNUNET_SERVICE_Context | |||
200 | int ret; | 205 | int ret; |
201 | 206 | ||
202 | /** | 207 | /** |
203 | * If we are daemonizing, this FD is set to the | 208 | * If #GNUNET_YES, consider unknown message types an error where the |
204 | * pipe to the parent. Send '.' if we started | 209 | * client is disconnected. |
205 | * ok, '!' if not. -1 if we are not daemonizing. | ||
206 | */ | 210 | */ |
207 | int ready_confirm_fd; | 211 | int require_found; |
212 | }; | ||
213 | |||
214 | |||
215 | /** | ||
216 | * Handle to a client that is connected to a service. | ||
217 | */ | ||
218 | struct GNUNET_SERVICE_Client | ||
219 | { | ||
208 | 220 | ||
209 | /** | 221 | /** |
210 | * Do we close connections if we receive messages | 222 | * Kept in a DLL. |
211 | * for which we have no handler? | ||
212 | */ | 223 | */ |
213 | int require_found; | 224 | struct GNUNET_SERVICE_Client *next; |
214 | 225 | ||
215 | /** | 226 | /** |
216 | * Do we require a matching UID for UNIX domain socket connections? | 227 | * Kept in a DLL. |
217 | * #GNUNET_NO means that the UID does not have to match (however, | ||
218 | * @e match_gid may still impose other access control checks). | ||
219 | */ | 228 | */ |
220 | int match_uid; | 229 | struct GNUNET_SERVICE_Client *prev; |
221 | 230 | ||
222 | /** | 231 | /** |
223 | * Do we require a matching GID for UNIX domain socket connections? | 232 | * Service that this client belongs to. |
224 | * Ignored if @e match_uid is #GNUNET_YES. Note that this is about | ||
225 | * checking that the client's UID is in our group OR that the | ||
226 | * client's GID is our GID. If both "match_gid" and @e match_uid are | ||
227 | * #GNUNET_NO, all users on the local system have access. | ||
228 | */ | 233 | */ |
229 | int match_gid; | 234 | struct GNUNET_SERVICE_Handle *sh; |
230 | 235 | ||
231 | /** | 236 | /** |
232 | * Our options. | 237 | * Socket of this client. |
233 | */ | 238 | */ |
234 | enum GNUNET_SERVICE_Options options; | 239 | struct GNUNET_NETWORK_Handle *sock; |
235 | 240 | ||
236 | }; | 241 | /** |
242 | * Message queue for the client. | ||
243 | */ | ||
244 | struct GNUNET_MQ_Handle *mq; | ||
245 | |||
246 | /** | ||
247 | * Tokenizer we use for processing incoming data. | ||
248 | */ | ||
249 | struct GNUNET_MessageStreamTokenizer *mst; | ||
250 | |||
251 | /** | ||
252 | * Task that warns about missing calls to | ||
253 | * #GNUNET_SERVICE_client_continue(). | ||
254 | */ | ||
255 | struct GNUNET_SCHEDULER_Task *warn_task; | ||
237 | 256 | ||
257 | /** | ||
258 | * Task run to finish dropping the client after the stack has | ||
259 | * properly unwound. | ||
260 | */ | ||
261 | struct GNUNET_SCHEDULER_Task *drop_task; | ||
262 | |||
263 | /** | ||
264 | * Task that receives data from the client to | ||
265 | * pass it to the handlers. | ||
266 | */ | ||
267 | struct GNUNET_SCHEDULER_Task *recv_task; | ||
268 | |||
269 | /** | ||
270 | * Task that transmit data to the client. | ||
271 | */ | ||
272 | struct GNUNET_SCHEDULER_Task *send_task; | ||
273 | |||
274 | /** | ||
275 | * Pointer to the message to be transmitted by @e send_task. | ||
276 | */ | ||
277 | const struct GNUNET_MessageHeader *msg; | ||
278 | |||
279 | /** | ||
280 | * User context value, value returned from | ||
281 | * the connect callback. | ||
282 | */ | ||
283 | void *user_context; | ||
284 | |||
285 | /** | ||
286 | * Time when we last gave a message from this client | ||
287 | * to the application. | ||
288 | */ | ||
289 | struct GNUNET_TIME_Absolute warn_start; | ||
290 | |||
291 | /** | ||
292 | * Current position in @e msg at which we are transmitting. | ||
293 | */ | ||
294 | size_t msg_pos; | ||
295 | |||
296 | /** | ||
297 | * Persist the file handle for this client no matter what happens, | ||
298 | * force the OS to close once the process actually dies. Should only | ||
299 | * be used in special cases! | ||
300 | */ | ||
301 | int persist; | ||
302 | |||
303 | /** | ||
304 | * Is this client a 'monitor' client that should not be counted | ||
305 | * when deciding on destroying the server during soft shutdown? | ||
306 | * (see also #GNUNET_SERVICE_start) | ||
307 | */ | ||
308 | int is_monitor; | ||
309 | |||
310 | /** | ||
311 | * Are we waiting for the application to call #GNUNET_SERVICE_client_continue()? | ||
312 | */ | ||
313 | int needs_continue; | ||
314 | |||
315 | /** | ||
316 | * Type of last message processed (for warn_no_receive_done). | ||
317 | */ | ||
318 | uint16_t warn_type; | ||
319 | }; | ||
238 | 320 | ||
239 | /* ****************** message handlers ****************** */ | ||
240 | 321 | ||
241 | /** | 322 | /** |
242 | * Send a 'TEST' message back to the client. | 323 | * Check if any of the clients we have left are unrelated to |
324 | * monitoring. | ||
243 | * | 325 | * |
244 | * @param cls the 'struct GNUNET_SERVER_Client' to send TEST to | 326 | * @param sh service to check clients for |
245 | * @param size number of bytes available in 'buf' | 327 | * @return #GNUNET_YES if we have non-monitoring clients left |
246 | * @param buf where to copy the message | ||
247 | * @return number of bytes written to 'buf' | ||
248 | */ | 328 | */ |
249 | static size_t | 329 | static int |
250 | write_test (void *cls, size_t size, void *buf) | 330 | have_non_monitor_clients (struct GNUNET_SERVICE_Handle *sh) |
251 | { | 331 | { |
252 | struct GNUNET_SERVER_Client *client = cls; | 332 | struct GNUNET_SERVICE_Client *client; |
253 | struct GNUNET_MessageHeader *msg; | ||
254 | 333 | ||
255 | if (size < sizeof (struct GNUNET_MessageHeader)) | 334 | for (client = sh->clients_head;NULL != client; client = client->next) |
256 | { | 335 | { |
257 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | 336 | if (client->is_monitor) |
258 | return 0; /* client disconnected */ | 337 | continue; |
338 | return GNUNET_YES; | ||
259 | } | 339 | } |
260 | msg = (struct GNUNET_MessageHeader *) buf; | 340 | return GNUNET_NO; |
261 | msg->type = htons (GNUNET_MESSAGE_TYPE_TEST); | ||
262 | msg->size = htons (sizeof (struct GNUNET_MessageHeader)); | ||
263 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
264 | return sizeof (struct GNUNET_MessageHeader); | ||
265 | } | 341 | } |
266 | 342 | ||
267 | 343 | ||
268 | /** | 344 | /** |
269 | * Handler for TEST message. | 345 | * Shutdown task triggered when a service should be terminated. |
346 | * This considers active clients and the service options to see | ||
347 | * how this specific service is to be terminated, and depending | ||
348 | * on this proceeds with the shutdown logic. | ||
270 | * | 349 | * |
271 | * @param cls closure (refers to service) | 350 | * @param cls our `struct GNUNET_SERVICE_Handle` |
272 | * @param client identification of the client | ||
273 | * @param message the actual message | ||
274 | */ | 351 | */ |
275 | static void | 352 | static void |
276 | handle_test (void *cls, struct GNUNET_SERVER_Client *client, | 353 | service_shutdown (void *cls) |
277 | const struct GNUNET_MessageHeader *message) | ||
278 | { | 354 | { |
279 | /* simply bounce message back to acknowledge */ | 355 | struct GNUNET_SERVICE_Handle *sh = cls; |
280 | if (NULL == | ||
281 | GNUNET_SERVER_notify_transmit_ready (client, | ||
282 | sizeof (struct GNUNET_MessageHeader), | ||
283 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
284 | &write_test, client)) | ||
285 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
286 | } | ||
287 | |||
288 | |||
289 | /** | ||
290 | * Default handlers for all services. Will be copied and the | ||
291 | * "callback_cls" fields will be replaced with the specific service | ||
292 | * struct. | ||
293 | */ | ||
294 | static const struct GNUNET_SERVER_MessageHandler defhandlers[] = { | ||
295 | {&handle_test, NULL, GNUNET_MESSAGE_TYPE_TEST, | ||
296 | sizeof (struct GNUNET_MessageHeader)}, | ||
297 | {NULL, NULL, 0, 0} | ||
298 | }; | ||
299 | |||
300 | |||
301 | /* ****************** service core routines ************** */ | ||
302 | 356 | ||
303 | 357 | switch (sh->options) | |
304 | /** | ||
305 | * Check if access to the service is allowed from the given address. | ||
306 | * | ||
307 | * @param cls closure | ||
308 | * @param uc credentials, if available, otherwise NULL | ||
309 | * @param addr address | ||
310 | * @param addrlen length of address | ||
311 | * @return #GNUNET_YES to allow, #GNUNET_NO to deny, #GNUNET_SYSERR | ||
312 | * for unknown address family (will be denied). | ||
313 | */ | ||
314 | static int | ||
315 | check_access (void *cls, const struct GNUNET_CONNECTION_Credentials *uc, | ||
316 | const struct sockaddr *addr, socklen_t addrlen) | ||
317 | { | ||
318 | struct GNUNET_SERVICE_Context *sctx = cls; | ||
319 | const struct sockaddr_in *i4; | ||
320 | const struct sockaddr_in6 *i6; | ||
321 | int ret; | ||
322 | |||
323 | switch (addr->sa_family) | ||
324 | { | 358 | { |
325 | case AF_INET: | 359 | case GNUNET_SERVICE_OPTION_NONE: |
326 | GNUNET_assert (addrlen == sizeof (struct sockaddr_in)); | 360 | GNUNET_SERVICE_shutdown (sh); |
327 | i4 = (const struct sockaddr_in *) addr; | ||
328 | ret = ((NULL == sctx->v4_allowed) || | ||
329 | (check_ipv4_listed (sctx->v4_allowed, &i4->sin_addr))) && | ||
330 | ((NULL == sctx->v4_denied) || | ||
331 | (!check_ipv4_listed (sctx->v4_denied, &i4->sin_addr))); | ||
332 | break; | 361 | break; |
333 | case AF_INET6: | 362 | case GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN: |
334 | GNUNET_assert (addrlen == sizeof (struct sockaddr_in6)); | 363 | /* This task should never be run if we are using |
335 | i6 = (const struct sockaddr_in6 *) addr; | 364 | the manual shutdown. */ |
336 | ret = ((NULL == sctx->v6_allowed) || | 365 | GNUNET_assert (0); |
337 | (check_ipv6_listed (sctx->v6_allowed, &i6->sin6_addr))) && | ||
338 | ((NULL == sctx->v6_denied) || | ||
339 | (!check_ipv6_listed (sctx->v6_denied, &i6->sin6_addr))); | ||
340 | break; | 366 | break; |
341 | #ifndef WINDOWS | 367 | case GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN: |
342 | case AF_UNIX: | 368 | sh->got_shutdown = GNUNET_YES; |
343 | ret = GNUNET_OK; /* controlled using file-system ACL now */ | 369 | GNUNET_SERVICE_suspend (sh); |
370 | if (GNUNET_NO == have_non_monitor_clients (sh)) | ||
371 | GNUNET_SERVICE_shutdown (sh); | ||
344 | break; | 372 | break; |
345 | #endif | ||
346 | default: | ||
347 | LOG (GNUNET_ERROR_TYPE_WARNING, _("Unknown address family %d\n"), | ||
348 | addr->sa_family); | ||
349 | return GNUNET_SYSERR; | ||
350 | } | ||
351 | if (GNUNET_OK != ret) | ||
352 | { | ||
353 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
354 | _("Access from `%s' denied to service `%s'\n"), | ||
355 | GNUNET_a2s (addr, addrlen), | ||
356 | sctx->service_name); | ||
357 | } | 373 | } |
358 | return ret; | ||
359 | } | 374 | } |
360 | 375 | ||
361 | 376 | ||
362 | /** | 377 | /** |
363 | * Get the name of the file where we will | 378 | * First task run by any service. Initializes our shutdown task, |
364 | * write the PID of the service. | 379 | * starts the listening operation on our listen sockets and launches |
380 | * the custom logic of the application service. | ||
365 | * | 381 | * |
366 | * @param sctx service context | 382 | * @param cls our `struct GNUNET_SERVICE_Handle` |
367 | * @return name of the file for the process ID | ||
368 | */ | 383 | */ |
369 | static char * | 384 | static void |
370 | get_pid_file_name (struct GNUNET_SERVICE_Context *sctx) | 385 | service_main (void *cls) |
371 | { | 386 | { |
372 | char *pif; | 387 | struct GNUNET_SERVICE_Handle *sh = cls; |
373 | 388 | ||
374 | if (GNUNET_OK != | 389 | if (GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN != sh->options) |
375 | GNUNET_CONFIGURATION_get_value_filename (sctx->cfg, sctx->service_name, | 390 | GNUNET_SCHEDULER_add_shutdown (&service_shutdown, |
376 | "PIDFILE", &pif)) | 391 | sh); |
377 | return NULL; | 392 | GNUNET_SERVICE_resume (sh); |
378 | return pif; | 393 | |
394 | if (-1 != sh->ready_confirm_fd) | ||
395 | { | ||
396 | GNUNET_break (1 == WRITE (sh->ready_confirm_fd, ".", 1)); | ||
397 | GNUNET_break (0 == CLOSE (sh->ready_confirm_fd)); | ||
398 | sh->ready_confirm_fd = -1; | ||
399 | } | ||
400 | |||
401 | if (NULL != sh->service_init_cb) | ||
402 | sh->service_init_cb (sh->cb_cls, | ||
403 | sh->cfg, | ||
404 | sh); | ||
379 | } | 405 | } |
380 | 406 | ||
381 | 407 | ||
@@ -383,32 +409,37 @@ get_pid_file_name (struct GNUNET_SERVICE_Context *sctx) | |||
383 | * Parse an IPv4 access control list. | 409 | * Parse an IPv4 access control list. |
384 | * | 410 | * |
385 | * @param ret location where to write the ACL (set) | 411 | * @param ret location where to write the ACL (set) |
386 | * @param sctx service context to use to get the configuration | 412 | * @param sh service context to use to get the configuration |
387 | * @param option name of the ACL option to parse | 413 | * @param option name of the ACL option to parse |
388 | * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including | 414 | * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including |
389 | * no ACL configured) | 415 | * no ACL configured) |
390 | */ | 416 | */ |
391 | static int | 417 | static int |
392 | process_acl4 (struct GNUNET_STRINGS_IPv4NetworkPolicy **ret, | 418 | process_acl4 (struct GNUNET_STRINGS_IPv4NetworkPolicy **ret, |
393 | struct GNUNET_SERVICE_Context *sctx, | 419 | struct GNUNET_SERVICE_Handle *sh, |
394 | const char *option) | 420 | const char *option) |
395 | { | 421 | { |
396 | char *opt; | 422 | char *opt; |
397 | 423 | ||
398 | if (!GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, option)) | 424 | if (! GNUNET_CONFIGURATION_have_value (sh->cfg, |
425 | sh->service_name, | ||
426 | option)) | ||
399 | { | 427 | { |
400 | *ret = NULL; | 428 | *ret = NULL; |
401 | return GNUNET_OK; | 429 | return GNUNET_OK; |
402 | } | 430 | } |
403 | GNUNET_break (GNUNET_OK == | 431 | GNUNET_break (GNUNET_OK == |
404 | GNUNET_CONFIGURATION_get_value_string (sctx->cfg, | 432 | GNUNET_CONFIGURATION_get_value_string (sh->cfg, |
405 | sctx->service_name, | 433 | sh->service_name, |
406 | option, &opt)); | 434 | option, |
435 | &opt)); | ||
407 | if (NULL == (*ret = GNUNET_STRINGS_parse_ipv4_policy (opt))) | 436 | if (NULL == (*ret = GNUNET_STRINGS_parse_ipv4_policy (opt))) |
408 | { | 437 | { |
409 | LOG (GNUNET_ERROR_TYPE_WARNING, | 438 | LOG (GNUNET_ERROR_TYPE_WARNING, |
410 | _("Could not parse IPv4 network specification `%s' for `%s:%s'\n"), | 439 | _("Could not parse IPv4 network specification `%s' for `%s:%s'\n"), |
411 | opt, sctx->service_name, option); | 440 | opt, |
441 | sh->service_name, | ||
442 | option); | ||
412 | GNUNET_free (opt); | 443 | GNUNET_free (opt); |
413 | return GNUNET_SYSERR; | 444 | return GNUNET_SYSERR; |
414 | } | 445 | } |
@@ -421,32 +452,37 @@ process_acl4 (struct GNUNET_STRINGS_IPv4NetworkPolicy **ret, | |||
421 | * Parse an IPv6 access control list. | 452 | * Parse an IPv6 access control list. |
422 | * | 453 | * |
423 | * @param ret location where to write the ACL (set) | 454 | * @param ret location where to write the ACL (set) |
424 | * @param sctx service context to use to get the configuration | 455 | * @param sh service context to use to get the configuration |
425 | * @param option name of the ACL option to parse | 456 | * @param option name of the ACL option to parse |
426 | * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including | 457 | * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including |
427 | * no ACL configured) | 458 | * no ACL configured) |
428 | */ | 459 | */ |
429 | static int | 460 | static int |
430 | process_acl6 (struct GNUNET_STRINGS_IPv6NetworkPolicy **ret, | 461 | process_acl6 (struct GNUNET_STRINGS_IPv6NetworkPolicy **ret, |
431 | struct GNUNET_SERVICE_Context *sctx, | 462 | struct GNUNET_SERVICE_Handle *sh, |
432 | const char *option) | 463 | const char *option) |
433 | { | 464 | { |
434 | char *opt; | 465 | char *opt; |
435 | 466 | ||
436 | if (!GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, option)) | 467 | if (! GNUNET_CONFIGURATION_have_value (sh->cfg, |
468 | sh->service_name, | ||
469 | option)) | ||
437 | { | 470 | { |
438 | *ret = NULL; | 471 | *ret = NULL; |
439 | return GNUNET_OK; | 472 | return GNUNET_OK; |
440 | } | 473 | } |
441 | GNUNET_break (GNUNET_OK == | 474 | GNUNET_break (GNUNET_OK == |
442 | GNUNET_CONFIGURATION_get_value_string (sctx->cfg, | 475 | GNUNET_CONFIGURATION_get_value_string (sh->cfg, |
443 | sctx->service_name, | 476 | sh->service_name, |
444 | option, &opt)); | 477 | option, |
478 | &opt)); | ||
445 | if (NULL == (*ret = GNUNET_STRINGS_parse_ipv6_policy (opt))) | 479 | if (NULL == (*ret = GNUNET_STRINGS_parse_ipv6_policy (opt))) |
446 | { | 480 | { |
447 | LOG (GNUNET_ERROR_TYPE_WARNING, | 481 | LOG (GNUNET_ERROR_TYPE_WARNING, |
448 | _("Could not parse IPv6 network specification `%s' for `%s:%s'\n"), | 482 | _("Could not parse IPv6 network specification `%s' for `%s:%s'\n"), |
449 | opt, sctx->service_name, option); | 483 | opt, |
484 | sh->service_name, | ||
485 | option); | ||
450 | GNUNET_free (opt); | 486 | GNUNET_free (opt); |
451 | return GNUNET_SYSERR; | 487 | return GNUNET_SYSERR; |
452 | } | 488 | } |
@@ -476,7 +512,9 @@ add_unixpath (struct sockaddr **saddrs, | |||
476 | 512 | ||
477 | un = GNUNET_new (struct sockaddr_un); | 513 | un = GNUNET_new (struct sockaddr_un); |
478 | un->sun_family = AF_UNIX; | 514 | un->sun_family = AF_UNIX; |
479 | strncpy (un->sun_path, unixpath, sizeof (un->sun_path) - 1); | 515 | strncpy (un->sun_path, |
516 | unixpath, | ||
517 | sizeof (un->sun_path) - 1); | ||
480 | #ifdef LINUX | 518 | #ifdef LINUX |
481 | if (GNUNET_YES == abstract) | 519 | if (GNUNET_YES == abstract) |
482 | un->sun_path[0] = '\0'; | 520 | un->sun_path[0] = '\0'; |
@@ -514,11 +552,11 @@ add_unixpath (struct sockaddr **saddrs, | |||
514 | * zero (in this case, `*addrs` and `*addr_lens` will be | 552 | * zero (in this case, `*addrs` and `*addr_lens` will be |
515 | * set to NULL). | 553 | * set to NULL). |
516 | */ | 554 | */ |
517 | int | 555 | static int |
518 | GNUNET_SERVICE_get_server_addresses (const char *service_name, | 556 | get_server_addresses (const char *service_name, |
519 | const struct GNUNET_CONFIGURATION_Handle *cfg, | 557 | const struct GNUNET_CONFIGURATION_Handle *cfg, |
520 | struct sockaddr ***addrs, | 558 | struct sockaddr ***addrs, |
521 | socklen_t ** addr_lens) | 559 | socklen_t **addr_lens) |
522 | { | 560 | { |
523 | int disablev6; | 561 | int disablev6; |
524 | struct GNUNET_NETWORK_Handle *desc; | 562 | struct GNUNET_NETWORK_Handle *desc; |
@@ -539,11 +577,15 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name, | |||
539 | *addrs = NULL; | 577 | *addrs = NULL; |
540 | *addr_lens = NULL; | 578 | *addr_lens = NULL; |
541 | desc = NULL; | 579 | desc = NULL; |
542 | if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "DISABLEV6")) | 580 | if (GNUNET_CONFIGURATION_have_value (cfg, |
581 | service_name, | ||
582 | "DISABLEV6")) | ||
543 | { | 583 | { |
544 | if (GNUNET_SYSERR == | 584 | if (GNUNET_SYSERR == |
545 | (disablev6 = | 585 | (disablev6 = |
546 | GNUNET_CONFIGURATION_get_value_yesno (cfg, service_name, "DISABLEV6"))) | 586 | GNUNET_CONFIGURATION_get_value_yesno (cfg, |
587 | service_name, | ||
588 | "DISABLEV6"))) | ||
547 | return GNUNET_SYSERR; | 589 | return GNUNET_SYSERR; |
548 | } | 590 | } |
549 | else | 591 | else |
@@ -552,33 +594,44 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name, | |||
552 | if (! disablev6) | 594 | if (! disablev6) |
553 | { | 595 | { |
554 | /* probe IPv6 support */ | 596 | /* probe IPv6 support */ |
555 | desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0); | 597 | desc = GNUNET_NETWORK_socket_create (PF_INET6, |
598 | SOCK_STREAM, | ||
599 | 0); | ||
556 | if (NULL == desc) | 600 | if (NULL == desc) |
557 | { | 601 | { |
558 | if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) || | 602 | if ( (ENOBUFS == errno) || |
559 | (EACCES == errno)) | 603 | (ENOMEM == errno) || |
604 | (ENFILE == errno) || | ||
605 | (EACCES == errno) ) | ||
560 | { | 606 | { |
561 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket"); | 607 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, |
608 | "socket"); | ||
562 | return GNUNET_SYSERR; | 609 | return GNUNET_SYSERR; |
563 | } | 610 | } |
564 | LOG (GNUNET_ERROR_TYPE_INFO, | 611 | LOG (GNUNET_ERROR_TYPE_INFO, |
565 | _("Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"), | 612 | _("Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"), |
566 | service_name, STRERROR (errno)); | 613 | service_name, |
614 | STRERROR (errno)); | ||
567 | disablev6 = GNUNET_YES; | 615 | disablev6 = GNUNET_YES; |
568 | } | 616 | } |
569 | else | 617 | else |
570 | { | 618 | { |
571 | GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc)); | 619 | GNUNET_break (GNUNET_OK == |
620 | GNUNET_NETWORK_socket_close (desc)); | ||
572 | desc = NULL; | 621 | desc = NULL; |
573 | } | 622 | } |
574 | } | 623 | } |
575 | 624 | ||
576 | port = 0; | 625 | port = 0; |
577 | if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT")) | 626 | if (GNUNET_CONFIGURATION_have_value (cfg, |
627 | service_name, | ||
628 | "PORT")) | ||
578 | { | 629 | { |
579 | if (GNUNET_OK != | 630 | if (GNUNET_OK != |
580 | GNUNET_CONFIGURATION_get_value_number (cfg, service_name, | 631 | GNUNET_CONFIGURATION_get_value_number (cfg, |
581 | "PORT", &port)) | 632 | service_name, |
633 | "PORT", | ||
634 | &port)) | ||
582 | { | 635 | { |
583 | LOG (GNUNET_ERROR_TYPE_ERROR, | 636 | LOG (GNUNET_ERROR_TYPE_ERROR, |
584 | _("Require valid port number for service `%s' in configuration!\n"), | 637 | _("Require valid port number for service `%s' in configuration!\n"), |
@@ -593,11 +646,15 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name, | |||
593 | } | 646 | } |
594 | } | 647 | } |
595 | 648 | ||
596 | if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO")) | 649 | if (GNUNET_CONFIGURATION_have_value (cfg, |
650 | service_name, | ||
651 | "BINDTO")) | ||
597 | { | 652 | { |
598 | GNUNET_break (GNUNET_OK == | 653 | GNUNET_break (GNUNET_OK == |
599 | GNUNET_CONFIGURATION_get_value_string (cfg, service_name, | 654 | GNUNET_CONFIGURATION_get_value_string (cfg, |
600 | "BINDTO", &hostname)); | 655 | service_name, |
656 | "BINDTO", | ||
657 | &hostname)); | ||
601 | } | 658 | } |
602 | else | 659 | else |
603 | hostname = NULL; | 660 | hostname = NULL; |
@@ -606,10 +663,14 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name, | |||
606 | abstract = GNUNET_NO; | 663 | abstract = GNUNET_NO; |
607 | #ifdef AF_UNIX | 664 | #ifdef AF_UNIX |
608 | if ((GNUNET_YES == | 665 | if ((GNUNET_YES == |
609 | GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) && | 666 | GNUNET_CONFIGURATION_have_value (cfg, |
667 | service_name, | ||
668 | "UNIXPATH")) && | ||
610 | (GNUNET_OK == | 669 | (GNUNET_OK == |
611 | GNUNET_CONFIGURATION_get_value_filename (cfg, service_name, "UNIXPATH", | 670 | GNUNET_CONFIGURATION_get_value_filename (cfg, |
612 | &unixpath)) && | 671 | service_name, |
672 | "UNIXPATH", | ||
673 | &unixpath)) && | ||
613 | (0 < strlen (unixpath))) | 674 | (0 < strlen (unixpath))) |
614 | { | 675 | { |
615 | /* probe UNIX support */ | 676 | /* probe UNIX support */ |
@@ -618,7 +679,8 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name, | |||
618 | if (strlen (unixpath) >= sizeof (s_un.sun_path)) | 679 | if (strlen (unixpath) >= sizeof (s_un.sun_path)) |
619 | { | 680 | { |
620 | LOG (GNUNET_ERROR_TYPE_WARNING, | 681 | LOG (GNUNET_ERROR_TYPE_WARNING, |
621 | _("UNIXPATH `%s' too long, maximum length is %llu\n"), unixpath, | 682 | _("UNIXPATH `%s' too long, maximum length is %llu\n"), |
683 | unixpath, | ||
622 | (unsigned long long) sizeof (s_un.sun_path)); | 684 | (unsigned long long) sizeof (s_un.sun_path)); |
623 | unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath); | 685 | unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath); |
624 | LOG (GNUNET_ERROR_TYPE_INFO, | 686 | LOG (GNUNET_ERROR_TYPE_INFO, |
@@ -632,22 +694,27 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name, | |||
632 | if (GNUNET_SYSERR == abstract) | 694 | if (GNUNET_SYSERR == abstract) |
633 | abstract = GNUNET_NO; | 695 | abstract = GNUNET_NO; |
634 | #endif | 696 | #endif |
635 | if ((GNUNET_YES != abstract) | 697 | if ( (GNUNET_YES != abstract) && |
636 | && (GNUNET_OK != | 698 | (GNUNET_OK != |
637 | GNUNET_DISK_directory_create_for_file (unixpath))) | 699 | GNUNET_DISK_directory_create_for_file (unixpath)) ) |
638 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, | 700 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, |
639 | "mkdir", | 701 | "mkdir", |
640 | unixpath); | 702 | unixpath); |
641 | } | 703 | } |
642 | if (NULL != unixpath) | 704 | if (NULL != unixpath) |
643 | { | 705 | { |
644 | desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0); | 706 | desc = GNUNET_NETWORK_socket_create (AF_UNIX, |
707 | SOCK_STREAM, | ||
708 | 0); | ||
645 | if (NULL == desc) | 709 | if (NULL == desc) |
646 | { | 710 | { |
647 | if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) || | 711 | if ((ENOBUFS == errno) || |
712 | (ENOMEM == errno) || | ||
713 | (ENFILE == errno) || | ||
648 | (EACCES == errno)) | 714 | (EACCES == errno)) |
649 | { | 715 | { |
650 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket"); | 716 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, |
717 | "socket"); | ||
651 | GNUNET_free_non_null (hostname); | 718 | GNUNET_free_non_null (hostname); |
652 | GNUNET_free (unixpath); | 719 | GNUNET_free (unixpath); |
653 | return GNUNET_SYSERR; | 720 | return GNUNET_SYSERR; |
@@ -661,7 +728,8 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name, | |||
661 | } | 728 | } |
662 | else | 729 | else |
663 | { | 730 | { |
664 | GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc)); | 731 | GNUNET_break (GNUNET_OK == |
732 | GNUNET_NETWORK_socket_close (desc)); | ||
665 | desc = NULL; | 733 | desc = NULL; |
666 | } | 734 | } |
667 | } | 735 | } |
@@ -677,9 +745,14 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name, | |||
677 | } | 745 | } |
678 | if (0 == port) | 746 | if (0 == port) |
679 | { | 747 | { |
680 | saddrs = GNUNET_malloc (2 * sizeof (struct sockaddr *)); | 748 | saddrs = GNUNET_new_array (2, |
681 | saddrlens = GNUNET_malloc (2 * sizeof (socklen_t)); | 749 | struct sockaddr *); |
682 | add_unixpath (saddrs, saddrlens, unixpath, abstract); | 750 | saddrlens = GNUNET_new_array (2, |
751 | socklen_t); | ||
752 | add_unixpath (saddrs, | ||
753 | saddrlens, | ||
754 | unixpath, | ||
755 | abstract); | ||
683 | GNUNET_free_non_null (unixpath); | 756 | GNUNET_free_non_null (unixpath); |
684 | GNUNET_free_non_null (hostname); | 757 | GNUNET_free_non_null (hostname); |
685 | *addrs = saddrs; | 758 | *addrs = saddrs; |
@@ -693,11 +766,16 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name, | |||
693 | "Resolving `%s' since that is where `%s' will bind to.\n", | 766 | "Resolving `%s' since that is where `%s' will bind to.\n", |
694 | hostname, | 767 | hostname, |
695 | service_name); | 768 | service_name); |
696 | memset (&hints, 0, sizeof (struct addrinfo)); | 769 | memset (&hints, |
770 | 0, | ||
771 | sizeof (struct addrinfo)); | ||
697 | if (disablev6) | 772 | if (disablev6) |
698 | hints.ai_family = AF_INET; | 773 | hints.ai_family = AF_INET; |
699 | hints.ai_protocol = IPPROTO_TCP; | 774 | hints.ai_protocol = IPPROTO_TCP; |
700 | if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) || | 775 | if ((0 != (ret = getaddrinfo (hostname, |
776 | NULL, | ||
777 | &hints, | ||
778 | &res))) || | ||
701 | (NULL == res)) | 779 | (NULL == res)) |
702 | { | 780 | { |
703 | LOG (GNUNET_ERROR_TYPE_ERROR, | 781 | LOG (GNUNET_ERROR_TYPE_ERROR, |
@@ -713,7 +791,8 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name, | |||
713 | while (NULL != (pos = next)) | 791 | while (NULL != (pos = next)) |
714 | { | 792 | { |
715 | next = pos->ai_next; | 793 | next = pos->ai_next; |
716 | if ((disablev6) && (pos->ai_family == AF_INET6)) | 794 | if ( (disablev6) && |
795 | (pos->ai_family == AF_INET6) ) | ||
717 | continue; | 796 | continue; |
718 | i++; | 797 | i++; |
719 | } | 798 | } |
@@ -731,32 +810,45 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name, | |||
731 | resi = i; | 810 | resi = i; |
732 | if (NULL != unixpath) | 811 | if (NULL != unixpath) |
733 | resi++; | 812 | resi++; |
734 | saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *)); | 813 | saddrs = GNUNET_new_array (resi + 1, |
735 | saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t)); | 814 | struct sockaddr *); |
815 | saddrlens = GNUNET_new_array (resi + 1, | ||
816 | socklen_t); | ||
736 | i = 0; | 817 | i = 0; |
737 | if (NULL != unixpath) | 818 | if (NULL != unixpath) |
738 | { | 819 | { |
739 | add_unixpath (saddrs, saddrlens, unixpath, abstract); | 820 | add_unixpath (saddrs, |
821 | saddrlens, | ||
822 | unixpath, | ||
823 | abstract); | ||
740 | i++; | 824 | i++; |
741 | } | 825 | } |
742 | next = res; | 826 | next = res; |
743 | while (NULL != (pos = next)) | 827 | while (NULL != (pos = next)) |
744 | { | 828 | { |
745 | next = pos->ai_next; | 829 | next = pos->ai_next; |
746 | if ((disablev6) && (AF_INET6 == pos->ai_family)) | 830 | if ( (disablev6) && |
831 | (AF_INET6 == pos->ai_family) ) | ||
747 | continue; | 832 | continue; |
748 | if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol)) | 833 | if ( (IPPROTO_TCP != pos->ai_protocol) && |
834 | (0 != pos->ai_protocol) ) | ||
749 | continue; /* not TCP */ | 835 | continue; /* not TCP */ |
750 | if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype)) | 836 | if ( (SOCK_STREAM != pos->ai_socktype) && |
837 | (0 != pos->ai_socktype) ) | ||
751 | continue; /* huh? */ | 838 | continue; /* huh? */ |
752 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Service `%s' will bind to `%s'\n", | 839 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
753 | service_name, GNUNET_a2s (pos->ai_addr, pos->ai_addrlen)); | 840 | "Service `%s' will bind to `%s'\n", |
841 | service_name, | ||
842 | GNUNET_a2s (pos->ai_addr, | ||
843 | pos->ai_addrlen)); | ||
754 | if (AF_INET == pos->ai_family) | 844 | if (AF_INET == pos->ai_family) |
755 | { | 845 | { |
756 | GNUNET_assert (sizeof (struct sockaddr_in) == pos->ai_addrlen); | 846 | GNUNET_assert (sizeof (struct sockaddr_in) == pos->ai_addrlen); |
757 | saddrlens[i] = pos->ai_addrlen; | 847 | saddrlens[i] = pos->ai_addrlen; |
758 | saddrs[i] = GNUNET_malloc (saddrlens[i]); | 848 | saddrs[i] = GNUNET_malloc (saddrlens[i]); |
759 | GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]); | 849 | GNUNET_memcpy (saddrs[i], |
850 | pos->ai_addr, | ||
851 | saddrlens[i]); | ||
760 | ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port); | 852 | ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port); |
761 | } | 853 | } |
762 | else | 854 | else |
@@ -765,7 +857,9 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name, | |||
765 | GNUNET_assert (sizeof (struct sockaddr_in6) == pos->ai_addrlen); | 857 | GNUNET_assert (sizeof (struct sockaddr_in6) == pos->ai_addrlen); |
766 | saddrlens[i] = pos->ai_addrlen; | 858 | saddrlens[i] = pos->ai_addrlen; |
767 | saddrs[i] = GNUNET_malloc (saddrlens[i]); | 859 | saddrs[i] = GNUNET_malloc (saddrlens[i]); |
768 | GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]); | 860 | GNUNET_memcpy (saddrs[i], |
861 | pos->ai_addr, | ||
862 | saddrlens[i]); | ||
769 | ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port); | 863 | ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port); |
770 | } | 864 | } |
771 | i++; | 865 | i++; |
@@ -784,11 +878,16 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name, | |||
784 | if (NULL != unixpath) | 878 | if (NULL != unixpath) |
785 | resi++; | 879 | resi++; |
786 | i = 0; | 880 | i = 0; |
787 | saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *)); | 881 | saddrs = GNUNET_new_array (resi + 1, |
788 | saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t)); | 882 | struct sockaddr *); |
883 | saddrlens = GNUNET_new_array (resi + 1, | ||
884 | socklen_t); | ||
789 | if (NULL != unixpath) | 885 | if (NULL != unixpath) |
790 | { | 886 | { |
791 | add_unixpath (saddrs, saddrlens, unixpath, abstract); | 887 | add_unixpath (saddrs, |
888 | saddrlens, | ||
889 | unixpath, | ||
890 | abstract); | ||
792 | i++; | 891 | i++; |
793 | } | 892 | } |
794 | saddrlens[i] = sizeof (struct sockaddr_in); | 893 | saddrlens[i] = sizeof (struct sockaddr_in); |
@@ -805,12 +904,17 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name, | |||
805 | resi = 2; | 904 | resi = 2; |
806 | if (NULL != unixpath) | 905 | if (NULL != unixpath) |
807 | resi++; | 906 | resi++; |
808 | saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *)); | 907 | saddrs = GNUNET_new_array (resi + 1, |
809 | saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t)); | 908 | struct sockaddr *); |
909 | saddrlens = GNUNET_new_array (resi + 1, | ||
910 | socklen_t); | ||
810 | i = 0; | 911 | i = 0; |
811 | if (NULL != unixpath) | 912 | if (NULL != unixpath) |
812 | { | 913 | { |
813 | add_unixpath (saddrs, saddrlens, unixpath, abstract); | 914 | add_unixpath (saddrs, |
915 | saddrlens, | ||
916 | unixpath, | ||
917 | abstract); | ||
814 | i++; | 918 | i++; |
815 | } | 919 | } |
816 | saddrlens[i] = sizeof (struct sockaddr_in6); | 920 | saddrlens[i] = sizeof (struct sockaddr_in6); |
@@ -841,13 +945,14 @@ GNUNET_SERVICE_get_server_addresses (const char *service_name, | |||
841 | /** | 945 | /** |
842 | * Read listen sockets from the parent process (ARM). | 946 | * Read listen sockets from the parent process (ARM). |
843 | * | 947 | * |
844 | * @param sctx service context to initialize | 948 | * @param sh service context to initialize |
845 | * @return #GNUNET_YES if ok, #GNUNET_NO if not ok (must bind yourself), | 949 | * @return NULL-terminated array of sockets on success, |
846 | * and #GNUNET_SYSERR on error. | 950 | * NULL if not ok (must bind yourself) |
847 | */ | 951 | */ |
848 | static int | 952 | static struct GNUNET_NETWORK_Handle ** |
849 | receive_sockets_from_parent (struct GNUNET_SERVICE_Context *sctx) | 953 | receive_sockets_from_parent (struct GNUNET_SERVICE_Handle *sh) |
850 | { | 954 | { |
955 | static struct GNUNET_NETWORK_Handle **lsocks; | ||
851 | const char *env_buf; | 956 | const char *env_buf; |
852 | int fail; | 957 | int fail; |
853 | uint64_t count; | 958 | uint64_t count; |
@@ -855,15 +960,19 @@ receive_sockets_from_parent (struct GNUNET_SERVICE_Context *sctx) | |||
855 | HANDLE lsocks_pipe; | 960 | HANDLE lsocks_pipe; |
856 | 961 | ||
857 | env_buf = getenv ("GNUNET_OS_READ_LSOCKS"); | 962 | env_buf = getenv ("GNUNET_OS_READ_LSOCKS"); |
858 | if ((NULL == env_buf) || (strlen (env_buf) <= 0)) | 963 | if ( (NULL == env_buf) || |
859 | return GNUNET_NO; | 964 | (strlen (env_buf) <= 0) ) |
965 | return NULL; | ||
860 | /* Using W32 API directly here, because this pipe will | 966 | /* Using W32 API directly here, because this pipe will |
861 | * never be used outside of this function, and it's just too much of a bother | 967 | * never be used outside of this function, and it's just too much of a bother |
862 | * to create a GNUnet API that boxes a HANDLE (the way it is done with socks) | 968 | * to create a GNUnet API that boxes a HANDLE (the way it is done with socks) |
863 | */ | 969 | */ |
864 | lsocks_pipe = (HANDLE) strtoul (env_buf, NULL, 10); | 970 | lsocks_pipe = (HANDLE) strtoul (env_buf, |
865 | if ( (0 == lsocks_pipe) || (INVALID_HANDLE_VALUE == lsocks_pipe)) | 971 | NULL, |
866 | return GNUNET_NO; | 972 | 10); |
973 | if ( (0 == lsocks_pipe) || | ||
974 | (INVALID_HANDLE_VALUE == lsocks_pipe)) | ||
975 | return NULL; | ||
867 | fail = 1; | 976 | fail = 1; |
868 | do | 977 | do |
869 | { | 978 | { |
@@ -871,11 +980,17 @@ receive_sockets_from_parent (struct GNUNET_SERVICE_Context *sctx) | |||
871 | int fail2; | 980 | int fail2; |
872 | DWORD rd; | 981 | DWORD rd; |
873 | 982 | ||
874 | ret = ReadFile (lsocks_pipe, &count, sizeof (count), &rd, NULL); | 983 | ret = ReadFile (lsocks_pipe, |
875 | if ((0 == ret) || (sizeof (count) != rd) || (0 == count)) | 984 | &count, |
985 | sizeof (count), | ||
986 | &rd, | ||
987 | NULL); | ||
988 | if ( (0 == ret) || | ||
989 | (sizeof (count) != rd) || | ||
990 | (0 == count) ) | ||
876 | break; | 991 | break; |
877 | sctx->lsocks = | 992 | lsocks = GNUNET_new_array (count + 1, |
878 | GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (count + 1)); | 993 | struct GNUNET_NETWORK_Handle *); |
879 | 994 | ||
880 | fail2 = 1; | 995 | fail2 = 1; |
881 | for (i = 0; i < count; i++) | 996 | for (i = 0; i < count; i++) |
@@ -884,51 +999,165 @@ receive_sockets_from_parent (struct GNUNET_SERVICE_Context *sctx) | |||
884 | uint64_t size; | 999 | uint64_t size; |
885 | SOCKET s; | 1000 | SOCKET s; |
886 | 1001 | ||
887 | ret = ReadFile (lsocks_pipe, &size, sizeof (size), &rd, NULL); | 1002 | ret = ReadFile (lsocks_pipe, |
888 | if ( (0 == ret) || (sizeof (size) != rd) || (sizeof (pi) != size) ) | 1003 | &size, |
1004 | sizeof (size), | ||
1005 | &rd, | ||
1006 | NULL); | ||
1007 | if ( (0 == ret) || | ||
1008 | (sizeof (size) != rd) || | ||
1009 | (sizeof (pi) != size) ) | ||
889 | break; | 1010 | break; |
890 | ret = ReadFile (lsocks_pipe, &pi, sizeof (pi), &rd, NULL); | 1011 | ret = ReadFile (lsocks_pipe, |
891 | if ( (0 == ret) || (sizeof (pi) != rd)) | 1012 | &pi, |
1013 | sizeof (pi), | ||
1014 | &rd, | ||
1015 | NULL); | ||
1016 | if ( (0 == ret) || | ||
1017 | (sizeof (pi) != rd)) | ||
892 | break; | 1018 | break; |
893 | s = WSASocketA (pi.iAddressFamily, pi.iSocketType, pi.iProtocol, &pi, 0, WSA_FLAG_OVERLAPPED); | 1019 | s = WSASocketA (pi.iAddressFamily, |
894 | sctx->lsocks[i] = GNUNET_NETWORK_socket_box_native (s); | 1020 | pi.iSocketType, |
895 | if (NULL == sctx->lsocks[i]) | 1021 | pi.iProtocol, |
1022 | &pi, | ||
1023 | 0, | ||
1024 | WSA_FLAG_OVERLAPPED); | ||
1025 | lsocks[i] = GNUNET_NETWORK_socket_box_native (s); | ||
1026 | if (NULL == lsocks[i]) | ||
896 | break; | 1027 | break; |
897 | else if (i == count - 1) | 1028 | else if (i == count - 1) |
898 | fail2 = 0; | 1029 | fail2 = 0; |
899 | } | 1030 | } |
900 | if (fail2) | 1031 | if (fail2) |
901 | break; | 1032 | break; |
902 | sctx->lsocks[count] = NULL; | 1033 | lsocks[count] = NULL; |
903 | fail = 0; | 1034 | fail = 0; |
904 | } | 1035 | } |
905 | while (fail); | 1036 | while (fail); |
906 | |||
907 | CloseHandle (lsocks_pipe); | 1037 | CloseHandle (lsocks_pipe); |
908 | 1038 | ||
909 | if (fail) | 1039 | if (fail) |
910 | { | 1040 | { |
911 | LOG (GNUNET_ERROR_TYPE_ERROR, | 1041 | LOG (GNUNET_ERROR_TYPE_ERROR, |
912 | _("Could not access a pre-bound socket, will try to bind myself\n")); | 1042 | _("Could not access a pre-bound socket, will try to bind myself\n")); |
913 | for (i = 0; (i < count) && (NULL != sctx->lsocks[i]); i++) | 1043 | for (i = 0; (i < count) && (NULL != lsocks[i]); i++) |
914 | GNUNET_break (0 == GNUNET_NETWORK_socket_close (sctx->lsocks[i])); | 1044 | GNUNET_break (GNUNET_OK == |
915 | GNUNET_free_non_null (sctx->lsocks); | 1045 | GNUNET_NETWORK_socket_close (lsocks[i])); |
916 | sctx->lsocks = NULL; | 1046 | GNUNET_free (lsocks); |
917 | return GNUNET_NO; | 1047 | return NULL; |
918 | } | 1048 | } |
919 | return GNUNET_YES; | 1049 | return lsocks; |
920 | } | 1050 | } |
921 | #endif | 1051 | #endif |
922 | 1052 | ||
923 | 1053 | ||
924 | /** | 1054 | /** |
925 | * Setup addr, addrlen, idle_timeout | 1055 | * Create and initialize a listen socket for the server. |
926 | * based on configuration! | 1056 | * |
1057 | * @param server_addr address to listen on | ||
1058 | * @param socklen length of @a server_addr | ||
1059 | * @return NULL on error, otherwise the listen socket | ||
1060 | */ | ||
1061 | static struct GNUNET_NETWORK_Handle * | ||
1062 | open_listen_socket (const struct sockaddr *server_addr, | ||
1063 | socklen_t socklen) | ||
1064 | { | ||
1065 | struct GNUNET_NETWORK_Handle *sock; | ||
1066 | uint16_t port; | ||
1067 | int eno; | ||
1068 | |||
1069 | switch (server_addr->sa_family) | ||
1070 | { | ||
1071 | case AF_INET: | ||
1072 | port = ntohs (((const struct sockaddr_in *) server_addr)->sin_port); | ||
1073 | break; | ||
1074 | case AF_INET6: | ||
1075 | port = ntohs (((const struct sockaddr_in6 *) server_addr)->sin6_port); | ||
1076 | break; | ||
1077 | case AF_UNIX: | ||
1078 | port = 0; | ||
1079 | break; | ||
1080 | default: | ||
1081 | GNUNET_break (0); | ||
1082 | port = 0; | ||
1083 | break; | ||
1084 | } | ||
1085 | sock = GNUNET_NETWORK_socket_create (server_addr->sa_family, | ||
1086 | SOCK_STREAM, | ||
1087 | 0); | ||
1088 | if (NULL == sock) | ||
1089 | { | ||
1090 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, | ||
1091 | "socket"); | ||
1092 | errno = 0; | ||
1093 | return NULL; | ||
1094 | } | ||
1095 | /* bind the socket */ | ||
1096 | if (GNUNET_OK != GNUNET_NETWORK_socket_bind (sock, | ||
1097 | server_addr, | ||
1098 | socklen)) | ||
1099 | { | ||
1100 | eno = errno; | ||
1101 | if (EADDRINUSE != errno) | ||
1102 | { | ||
1103 | /* we don't log 'EADDRINUSE' here since an IPv4 bind may | ||
1104 | * fail if we already took the port on IPv6; if both IPv4 and | ||
1105 | * IPv6 binds fail, then our caller will log using the | ||
1106 | * errno preserved in 'eno' */ | ||
1107 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, | ||
1108 | "bind"); | ||
1109 | if (0 != port) | ||
1110 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1111 | _("`%s' failed for port %d (%s).\n"), | ||
1112 | "bind", | ||
1113 | port, | ||
1114 | (AF_INET == server_addr->sa_family) ? "IPv4" : "IPv6"); | ||
1115 | eno = 0; | ||
1116 | } | ||
1117 | else | ||
1118 | { | ||
1119 | if (0 != port) | ||
1120 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
1121 | _("`%s' failed for port %d (%s): address already in use\n"), | ||
1122 | "bind", port, | ||
1123 | (AF_INET == server_addr->sa_family) ? "IPv4" : "IPv6"); | ||
1124 | else if (AF_UNIX == server_addr->sa_family) | ||
1125 | { | ||
1126 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
1127 | _("`%s' failed for `%s': address already in use\n"), | ||
1128 | "bind", | ||
1129 | GNUNET_a2s (server_addr, socklen)); | ||
1130 | } | ||
1131 | } | ||
1132 | GNUNET_break (GNUNET_OK == | ||
1133 | GNUNET_NETWORK_socket_close (sock)); | ||
1134 | errno = eno; | ||
1135 | return NULL; | ||
1136 | } | ||
1137 | if (GNUNET_OK != GNUNET_NETWORK_socket_listen (sock, | ||
1138 | 5)) | ||
1139 | { | ||
1140 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, | ||
1141 | "listen"); | ||
1142 | GNUNET_break (GNUNET_OK == | ||
1143 | GNUNET_NETWORK_socket_close (sock)); | ||
1144 | errno = 0; | ||
1145 | return NULL; | ||
1146 | } | ||
1147 | if (0 != port) | ||
1148 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1149 | "Server starts to listen on port %u.\n", | ||
1150 | port); | ||
1151 | return sock; | ||
1152 | } | ||
1153 | |||
1154 | |||
1155 | /** | ||
1156 | * Setup service handle | ||
927 | * | 1157 | * |
928 | * Configuration may specify: | 1158 | * Configuration may specify: |
929 | * - PORT (where to bind to for TCP) | 1159 | * - PORT (where to bind to for TCP) |
930 | * - UNIXPATH (where to bind to for UNIX domain sockets) | 1160 | * - UNIXPATH (where to bind to for UNIX domain sockets) |
931 | * - TIMEOUT (after how many ms does an inactive service timeout); | ||
932 | * - DISABLEV6 (disable support for IPv6, otherwise we use dual-stack) | 1161 | * - DISABLEV6 (disable support for IPv6, otherwise we use dual-stack) |
933 | * - BINDTO (hostname or IP address to bind to, otherwise we take everything) | 1162 | * - BINDTO (hostname or IP address to bind to, otherwise we take everything) |
934 | * - ACCEPT_FROM (only allow connections from specified IPv4 subnets) | 1163 | * - ACCEPT_FROM (only allow connections from specified IPv4 subnets) |
@@ -936,108 +1165,170 @@ receive_sockets_from_parent (struct GNUNET_SERVICE_Context *sctx) | |||
936 | * - REJECT_FROM (disallow allow connections from specified IPv4 subnets) | 1165 | * - REJECT_FROM (disallow allow connections from specified IPv4 subnets) |
937 | * - REJECT_FROM6 (disallow allow connections from specified IPv6 subnets) | 1166 | * - REJECT_FROM6 (disallow allow connections from specified IPv6 subnets) |
938 | * | 1167 | * |
939 | * @param sctx service context to initialize | 1168 | * @param sh service context to initialize |
940 | * @return #GNUNET_OK if configuration succeeded | 1169 | * @return #GNUNET_OK if configuration succeeded |
941 | */ | 1170 | */ |
942 | static int | 1171 | static int |
943 | setup_service (struct GNUNET_SERVICE_Context *sctx) | 1172 | setup_service (struct GNUNET_SERVICE_Handle *sh) |
944 | { | 1173 | { |
945 | struct GNUNET_TIME_Relative idleout; | ||
946 | int tolerant; | 1174 | int tolerant; |
947 | 1175 | struct GNUNET_NETWORK_Handle **lsocks; | |
948 | #ifndef MINGW | 1176 | #ifndef MINGW |
949 | const char *nfds; | 1177 | const char *nfds; |
950 | unsigned int cnt; | 1178 | unsigned int cnt; |
951 | int flags; | 1179 | int flags; |
952 | #endif | 1180 | #endif |
953 | 1181 | ||
954 | if (GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, "TIMEOUT")) | ||
955 | { | ||
956 | if (GNUNET_OK != | ||
957 | GNUNET_CONFIGURATION_get_value_time (sctx->cfg, sctx->service_name, | ||
958 | "TIMEOUT", &idleout)) | ||
959 | { | ||
960 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
961 | _("Specified value for `%s' of service `%s' is invalid\n"), | ||
962 | "TIMEOUT", sctx->service_name); | ||
963 | return GNUNET_SYSERR; | ||
964 | } | ||
965 | sctx->timeout = idleout; | ||
966 | } | ||
967 | else | ||
968 | sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL; | ||
969 | |||
970 | if (GNUNET_CONFIGURATION_have_value | 1182 | if (GNUNET_CONFIGURATION_have_value |
971 | (sctx->cfg, sctx->service_name, "TOLERANT")) | 1183 | (sh->cfg, |
1184 | sh->service_name, | ||
1185 | "TOLERANT")) | ||
972 | { | 1186 | { |
973 | if (GNUNET_SYSERR == | 1187 | if (GNUNET_SYSERR == |
974 | (tolerant = | 1188 | (tolerant = |
975 | GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name, | 1189 | GNUNET_CONFIGURATION_get_value_yesno (sh->cfg, |
1190 | sh->service_name, | ||
976 | "TOLERANT"))) | 1191 | "TOLERANT"))) |
977 | { | 1192 | { |
978 | LOG (GNUNET_ERROR_TYPE_ERROR, | 1193 | LOG (GNUNET_ERROR_TYPE_ERROR, |
979 | _("Specified value for `%s' of service `%s' is invalid\n"), | 1194 | _("Specified value for `%s' of service `%s' is invalid\n"), |
980 | "TOLERANT", sctx->service_name); | 1195 | "TOLERANT", |
1196 | sh->service_name); | ||
981 | return GNUNET_SYSERR; | 1197 | return GNUNET_SYSERR; |
982 | } | 1198 | } |
983 | } | 1199 | } |
984 | else | 1200 | else |
985 | tolerant = GNUNET_NO; | 1201 | tolerant = GNUNET_NO; |
986 | 1202 | ||
1203 | lsocks = NULL; | ||
987 | #ifndef MINGW | 1204 | #ifndef MINGW |
988 | errno = 0; | 1205 | errno = 0; |
989 | if ((NULL != (nfds = getenv ("LISTEN_FDS"))) && | 1206 | if ( (NULL != (nfds = getenv ("LISTEN_FDS"))) && |
990 | (1 == SSCANF (nfds, "%u", &cnt)) && (cnt > 0) && (cnt < FD_SETSIZE) && | 1207 | (1 == SSCANF (nfds, |
991 | (cnt + 4 < FD_SETSIZE)) | 1208 | "%u", |
1209 | &cnt)) && | ||
1210 | (cnt > 0) && | ||
1211 | (cnt < FD_SETSIZE) && | ||
1212 | (cnt + 4 < FD_SETSIZE) ) | ||
992 | { | 1213 | { |
993 | sctx->lsocks = | 1214 | lsocks = GNUNET_new_array (cnt + 1, |
994 | GNUNET_malloc (sizeof (struct GNUNET_NETWORK_Handle *) * (cnt + 1)); | 1215 | struct GNUNET_NETWORK_Handle *); |
995 | while (0 < cnt--) | 1216 | while (0 < cnt--) |
996 | { | 1217 | { |
997 | flags = fcntl (3 + cnt, F_GETFD); | 1218 | flags = fcntl (3 + cnt, |
998 | if ((flags < 0) || (0 != (flags & FD_CLOEXEC)) || | 1219 | F_GETFD); |
999 | (NULL == | 1220 | if ( (flags < 0) || |
1000 | (sctx->lsocks[cnt] = GNUNET_NETWORK_socket_box_native (3 + cnt)))) | 1221 | (0 != (flags & FD_CLOEXEC)) || |
1222 | (NULL == | ||
1223 | (lsocks[cnt] = GNUNET_NETWORK_socket_box_native (3 + cnt)))) | ||
1001 | { | 1224 | { |
1002 | LOG (GNUNET_ERROR_TYPE_ERROR, | 1225 | LOG (GNUNET_ERROR_TYPE_ERROR, |
1003 | _ | 1226 | _("Could not access pre-bound socket %u, will try to bind myself\n"), |
1004 | ("Could not access pre-bound socket %u, will try to bind myself\n"), | ||
1005 | (unsigned int) 3 + cnt); | 1227 | (unsigned int) 3 + cnt); |
1006 | cnt++; | 1228 | cnt++; |
1007 | while (sctx->lsocks[cnt] != NULL) | 1229 | while (NULL != lsocks[cnt]) |
1008 | GNUNET_break (0 == GNUNET_NETWORK_socket_close (sctx->lsocks[cnt++])); | 1230 | GNUNET_break (GNUNET_OK == |
1009 | GNUNET_free (sctx->lsocks); | 1231 | GNUNET_NETWORK_socket_close (lsocks[cnt++])); |
1010 | sctx->lsocks = NULL; | 1232 | GNUNET_free (lsocks); |
1233 | lsocks = NULL; | ||
1011 | break; | 1234 | break; |
1012 | } | 1235 | } |
1013 | } | 1236 | } |
1014 | unsetenv ("LISTEN_FDS"); | 1237 | unsetenv ("LISTEN_FDS"); |
1015 | } | 1238 | } |
1016 | #else | 1239 | #else |
1017 | if (getenv ("GNUNET_OS_READ_LSOCKS") != NULL) | 1240 | if (NULL != getenv ("GNUNET_OS_READ_LSOCKS")) |
1018 | { | 1241 | { |
1019 | receive_sockets_from_parent (sctx); | 1242 | lsocks = receive_sockets_from_parent (sh); |
1020 | putenv ("GNUNET_OS_READ_LSOCKS="); | 1243 | putenv ("GNUNET_OS_READ_LSOCKS="); |
1021 | } | 1244 | } |
1022 | #endif | 1245 | #endif |
1023 | 1246 | ||
1024 | if ((NULL == sctx->lsocks) && | 1247 | if (NULL != lsocks) |
1025 | (GNUNET_SYSERR == | 1248 | { |
1026 | GNUNET_SERVICE_get_server_addresses (sctx->service_name, sctx->cfg, | 1249 | /* listen only on inherited sockets if we have any */ |
1027 | &sctx->addrs, &sctx->addrlens))) | 1250 | struct GNUNET_NETWORK_Handle **ls; |
1028 | return GNUNET_SYSERR; | 1251 | |
1029 | sctx->require_found = tolerant ? GNUNET_NO : GNUNET_YES; | 1252 | for (ls = lsocks; NULL != *ls; ls++) |
1030 | sctx->match_uid = | 1253 | { |
1031 | GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name, | 1254 | struct ServiceListenContext *slc; |
1255 | |||
1256 | slc = GNUNET_new (struct ServiceListenContext); | ||
1257 | slc->sh = sh; | ||
1258 | slc->listen_socket = *ls; | ||
1259 | GNUNET_CONTAINER_DLL_insert (sh->slc_head, | ||
1260 | sh->slc_tail, | ||
1261 | slc); | ||
1262 | } | ||
1263 | GNUNET_free (lsocks); | ||
1264 | } | ||
1265 | else | ||
1266 | { | ||
1267 | struct sockaddr **addrs; | ||
1268 | socklen_t *addrlens; | ||
1269 | int num; | ||
1270 | |||
1271 | num = get_server_addresses (sh->service_name, | ||
1272 | sh->cfg, | ||
1273 | &addrs, | ||
1274 | &addrlens); | ||
1275 | if (GNUNET_SYSERR == num) | ||
1276 | return GNUNET_SYSERR; | ||
1277 | |||
1278 | for (int i = 0; i < num; i++) | ||
1279 | { | ||
1280 | struct ServiceListenContext *slc; | ||
1281 | |||
1282 | slc = GNUNET_new (struct ServiceListenContext); | ||
1283 | slc->sh = sh; | ||
1284 | slc->listen_socket = open_listen_socket (addrs[i], | ||
1285 | addrlens[i]); | ||
1286 | if (NULL == slc->listen_socket) | ||
1287 | { | ||
1288 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, | ||
1289 | "bind"); | ||
1290 | GNUNET_free (addrs[i++]); | ||
1291 | GNUNET_free (slc); | ||
1292 | continue; | ||
1293 | } | ||
1294 | GNUNET_free (addrs[i++]); | ||
1295 | GNUNET_CONTAINER_DLL_insert (sh->slc_head, | ||
1296 | sh->slc_tail, | ||
1297 | slc); | ||
1298 | } | ||
1299 | GNUNET_free_non_null (addrlens); | ||
1300 | GNUNET_free_non_null (addrs); | ||
1301 | if ( (0 != num) && | ||
1302 | (NULL == sh->slc_head) ) | ||
1303 | { | ||
1304 | /* All attempts to bind failed, hard failure */ | ||
1305 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1306 | _("Could not bind to any of the ports I was supposed to, refusing to run!\n")); | ||
1307 | return GNUNET_SYSERR; | ||
1308 | } | ||
1309 | } | ||
1310 | |||
1311 | sh->require_found = tolerant ? GNUNET_NO : GNUNET_YES; | ||
1312 | sh->match_uid | ||
1313 | = GNUNET_CONFIGURATION_get_value_yesno (sh->cfg, | ||
1314 | sh->service_name, | ||
1032 | "UNIX_MATCH_UID"); | 1315 | "UNIX_MATCH_UID"); |
1033 | sctx->match_gid = | 1316 | sh->match_gid |
1034 | GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg, sctx->service_name, | 1317 | = GNUNET_CONFIGURATION_get_value_yesno (sh->cfg, |
1318 | sh->service_name, | ||
1035 | "UNIX_MATCH_GID"); | 1319 | "UNIX_MATCH_GID"); |
1036 | process_acl4 (&sctx->v4_denied, sctx, "REJECT_FROM"); | 1320 | process_acl4 (&sh->v4_denied, |
1037 | process_acl4 (&sctx->v4_allowed, sctx, "ACCEPT_FROM"); | 1321 | sh, |
1038 | process_acl6 (&sctx->v6_denied, sctx, "REJECT_FROM6"); | 1322 | "REJECT_FROM"); |
1039 | process_acl6 (&sctx->v6_allowed, sctx, "ACCEPT_FROM6"); | 1323 | process_acl4 (&sh->v4_allowed, |
1040 | 1324 | sh, | |
1325 | "ACCEPT_FROM"); | ||
1326 | process_acl6 (&sh->v6_denied, | ||
1327 | sh, | ||
1328 | "REJECT_FROM6"); | ||
1329 | process_acl6 (&sh->v6_allowed, | ||
1330 | sh, | ||
1331 | "ACCEPT_FROM6"); | ||
1041 | return GNUNET_OK; | 1332 | return GNUNET_OK; |
1042 | } | 1333 | } |
1043 | 1334 | ||
@@ -1046,185 +1337,129 @@ setup_service (struct GNUNET_SERVICE_Context *sctx) | |||
1046 | * Get the name of the user that'll be used | 1337 | * Get the name of the user that'll be used |
1047 | * to provide the service. | 1338 | * to provide the service. |
1048 | * | 1339 | * |
1049 | * @param sctx service context | 1340 | * @param sh service context |
1050 | * @return value of the 'USERNAME' option | 1341 | * @return value of the 'USERNAME' option |
1051 | */ | 1342 | */ |
1052 | static char * | 1343 | static char * |
1053 | get_user_name (struct GNUNET_SERVICE_Context *sctx) | 1344 | get_user_name (struct GNUNET_SERVICE_Handle *sh) |
1054 | { | 1345 | { |
1055 | char *un; | 1346 | char *un; |
1056 | 1347 | ||
1057 | if (GNUNET_OK != | 1348 | if (GNUNET_OK != |
1058 | GNUNET_CONFIGURATION_get_value_filename (sctx->cfg, sctx->service_name, | 1349 | GNUNET_CONFIGURATION_get_value_filename (sh->cfg, |
1059 | "USERNAME", &un)) | 1350 | sh->service_name, |
1351 | "USERNAME", | ||
1352 | &un)) | ||
1060 | return NULL; | 1353 | return NULL; |
1061 | return un; | 1354 | return un; |
1062 | } | 1355 | } |
1063 | 1356 | ||
1064 | 1357 | ||
1065 | /** | 1358 | /** |
1066 | * Write PID file. | 1359 | * Set user ID. |
1067 | * | 1360 | * |
1068 | * @param sctx service context | 1361 | * @param sh service context |
1069 | * @param pid PID to write (should be equal to 'getpid()' | 1362 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on error |
1070 | * @return #GNUNET_OK on success (including no work to be done) | ||
1071 | */ | 1363 | */ |
1072 | static int | 1364 | static int |
1073 | write_pid_file (struct GNUNET_SERVICE_Context *sctx, pid_t pid) | 1365 | set_user_id (struct GNUNET_SERVICE_Handle *sh) |
1074 | { | 1366 | { |
1075 | FILE *pidfd; | ||
1076 | char *pif; | ||
1077 | char *user; | 1367 | char *user; |
1078 | char *rdir; | 1368 | |
1079 | int len; | 1369 | if (NULL == (user = get_user_name (sh))) |
1080 | 1370 | return GNUNET_OK; /* keep */ | |
1081 | if (NULL == (pif = get_pid_file_name (sctx))) | 1371 | #ifndef MINGW |
1082 | return GNUNET_OK; /* no file desired */ | 1372 | struct passwd *pws; |
1083 | user = get_user_name (sctx); | 1373 | |
1084 | rdir = GNUNET_strdup (pif); | 1374 | errno = 0; |
1085 | len = strlen (rdir); | 1375 | pws = getpwnam (user); |
1086 | while ((len > 0) && (rdir[len] != DIR_SEPARATOR)) | 1376 | if (NULL == pws) |
1087 | len--; | 1377 | { |
1088 | rdir[len] = '\0'; | 1378 | LOG (GNUNET_ERROR_TYPE_ERROR, |
1089 | if (0 != ACCESS (rdir, F_OK)) | 1379 | _("Cannot obtain information about user `%s': %s\n"), |
1090 | { | 1380 | user, |
1091 | /* we get to create a directory -- and claim it | 1381 | errno == 0 ? _("No such user") : STRERROR (errno)); |
1092 | * as ours! */ | 1382 | GNUNET_free (user); |
1093 | (void) GNUNET_DISK_directory_create (rdir); | ||
1094 | if ((NULL != user) && (0 < strlen (user))) | ||
1095 | GNUNET_DISK_file_change_owner (rdir, user); | ||
1096 | } | ||
1097 | if (0 != ACCESS (rdir, W_OK | X_OK)) | ||
1098 | { | ||
1099 | LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "access", rdir); | ||
1100 | GNUNET_free (rdir); | ||
1101 | GNUNET_free_non_null (user); | ||
1102 | GNUNET_free (pif); | ||
1103 | return GNUNET_SYSERR; | 1383 | return GNUNET_SYSERR; |
1104 | } | 1384 | } |
1105 | GNUNET_free (rdir); | 1385 | if ( (0 != setgid (pws->pw_gid)) || |
1106 | pidfd = FOPEN (pif, "w"); | 1386 | (0 != setegid (pws->pw_gid)) || |
1107 | if (NULL == pidfd) | 1387 | #if HAVE_INITGROUPS |
1388 | (0 != initgroups (user, | ||
1389 | pws->pw_gid)) || | ||
1390 | #endif | ||
1391 | (0 != setuid (pws->pw_uid)) || | ||
1392 | (0 != seteuid (pws->pw_uid))) | ||
1108 | { | 1393 | { |
1109 | LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "fopen", pif); | 1394 | if ((0 != setregid (pws->pw_gid, |
1110 | GNUNET_free (pif); | 1395 | pws->pw_gid)) || |
1111 | GNUNET_free_non_null (user); | 1396 | (0 != setreuid (pws->pw_uid, |
1112 | return GNUNET_SYSERR; | 1397 | pws->pw_uid))) |
1398 | { | ||
1399 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1400 | _("Cannot change user/group to `%s': %s\n"), | ||
1401 | user, | ||
1402 | STRERROR (errno)); | ||
1403 | GNUNET_free (user); | ||
1404 | return GNUNET_SYSERR; | ||
1405 | } | ||
1113 | } | 1406 | } |
1114 | if (0 > FPRINTF (pidfd, "%u", pid)) | 1407 | #endif |
1115 | LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fprintf", pif); | 1408 | GNUNET_free (user); |
1116 | GNUNET_break (0 == FCLOSE (pidfd)); | ||
1117 | if ((NULL != user) && (0 < strlen (user))) | ||
1118 | GNUNET_DISK_file_change_owner (pif, user); | ||
1119 | GNUNET_free_non_null (user); | ||
1120 | GNUNET_free (pif); | ||
1121 | return GNUNET_OK; | 1409 | return GNUNET_OK; |
1122 | } | 1410 | } |
1123 | 1411 | ||
1124 | 1412 | ||
1125 | /** | 1413 | /** |
1126 | * Task run during shutdown. Stops the server/service. | 1414 | * Get the name of the file where we will |
1415 | * write the PID of the service. | ||
1127 | * | 1416 | * |
1128 | * @param cls the `struct GNUNET_SERVICE_Context` | 1417 | * @param sh service context |
1418 | * @return name of the file for the process ID | ||
1129 | */ | 1419 | */ |
1130 | static void | 1420 | static char * |
1131 | shutdown_task (void *cls) | 1421 | get_pid_file_name (struct GNUNET_SERVICE_Handle *sh) |
1132 | { | 1422 | { |
1133 | struct GNUNET_SERVICE_Context *service = cls; | 1423 | char *pif; |
1134 | struct GNUNET_SERVER_Handle *server = service->server; | ||
1135 | 1424 | ||
1136 | service->shutdown_task = NULL; | 1425 | if (GNUNET_OK != |
1137 | if (0 != (service->options & GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN)) | 1426 | GNUNET_CONFIGURATION_get_value_filename (sh->cfg, |
1138 | GNUNET_SERVER_stop_listening (server); | 1427 | sh->service_name, |
1139 | else | 1428 | "PIDFILE", |
1140 | GNUNET_SERVER_destroy (server); | 1429 | &pif)) |
1430 | return NULL; | ||
1431 | return pif; | ||
1141 | } | 1432 | } |
1142 | 1433 | ||
1143 | 1434 | ||
1144 | /** | 1435 | /** |
1145 | * Initial task for the service. | 1436 | * Delete the PID file that was created by our parent. |
1146 | * | 1437 | * |
1147 | * @param cls service context | 1438 | * @param sh service context |
1148 | */ | 1439 | */ |
1149 | static void | 1440 | static void |
1150 | service_task (void *cls) | 1441 | pid_file_delete (struct GNUNET_SERVICE_Handle *sh) |
1151 | { | 1442 | { |
1152 | struct GNUNET_SERVICE_Context *sctx = cls; | 1443 | char *pif = get_pid_file_name (sh); |
1153 | unsigned int i; | ||
1154 | 1444 | ||
1155 | (void) GNUNET_SPEEDUP_start_ (sctx->cfg); | 1445 | if (NULL == pif) |
1156 | GNUNET_RESOLVER_connect (sctx->cfg); | 1446 | return; /* no PID file */ |
1157 | if (NULL != sctx->lsocks) | 1447 | if (0 != UNLINK (pif)) |
1158 | sctx->server | 1448 | LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, |
1159 | = GNUNET_SERVER_create_with_sockets (&check_access, sctx, sctx->lsocks, | 1449 | "unlink", |
1160 | sctx->timeout, sctx->require_found); | 1450 | pif); |
1161 | else | 1451 | GNUNET_free (pif); |
1162 | sctx->server | ||
1163 | = GNUNET_SERVER_create (&check_access, sctx, sctx->addrs, sctx->addrlens, | ||
1164 | sctx->timeout, sctx->require_found); | ||
1165 | if (NULL == sctx->server) | ||
1166 | { | ||
1167 | if (NULL != sctx->addrs) | ||
1168 | for (i = 0; NULL != sctx->addrs[i]; i++) | ||
1169 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
1170 | _("Failed to start `%s' at `%s'\n"), | ||
1171 | sctx->service_name, GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i])); | ||
1172 | sctx->ret = GNUNET_SYSERR; | ||
1173 | return; | ||
1174 | } | ||
1175 | #ifndef WINDOWS | ||
1176 | if (NULL != sctx->addrs) | ||
1177 | for (i = 0; NULL != sctx->addrs[i]; i++) | ||
1178 | if ((AF_UNIX == sctx->addrs[i]->sa_family) | ||
1179 | && ('\0' != ((const struct sockaddr_un *)sctx->addrs[i])->sun_path[0])) | ||
1180 | GNUNET_DISK_fix_permissions (((const struct sockaddr_un *)sctx->addrs[i])->sun_path, | ||
1181 | sctx->match_uid, | ||
1182 | sctx->match_gid); | ||
1183 | #endif | ||
1184 | |||
1185 | |||
1186 | if (0 == (sctx->options & GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN)) | ||
1187 | { | ||
1188 | /* install a task that will kill the server | ||
1189 | * process if the scheduler ever gets a shutdown signal */ | ||
1190 | sctx->shutdown_task = GNUNET_SCHEDULER_add_shutdown (&shutdown_task, | ||
1191 | sctx); | ||
1192 | } | ||
1193 | sctx->my_handlers = GNUNET_malloc (sizeof (defhandlers)); | ||
1194 | GNUNET_memcpy (sctx->my_handlers, defhandlers, sizeof (defhandlers)); | ||
1195 | i = 0; | ||
1196 | while (NULL != sctx->my_handlers[i].callback) | ||
1197 | sctx->my_handlers[i++].callback_cls = sctx; | ||
1198 | GNUNET_SERVER_add_handlers (sctx->server, sctx->my_handlers); | ||
1199 | if (-1 != sctx->ready_confirm_fd) | ||
1200 | { | ||
1201 | GNUNET_break (1 == WRITE (sctx->ready_confirm_fd, ".", 1)); | ||
1202 | GNUNET_break (0 == CLOSE (sctx->ready_confirm_fd)); | ||
1203 | sctx->ready_confirm_fd = -1; | ||
1204 | write_pid_file (sctx, getpid ()); | ||
1205 | } | ||
1206 | if (NULL != sctx->addrs) | ||
1207 | { | ||
1208 | i = 0; | ||
1209 | while (NULL != sctx->addrs[i]) | ||
1210 | { | ||
1211 | LOG (GNUNET_ERROR_TYPE_INFO, _("Service `%s' runs at %s\n"), | ||
1212 | sctx->service_name, GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i])); | ||
1213 | i++; | ||
1214 | } | ||
1215 | } | ||
1216 | sctx->task (sctx->task_cls, sctx->server, sctx->cfg); | ||
1217 | } | 1452 | } |
1218 | 1453 | ||
1219 | 1454 | ||
1220 | /** | 1455 | /** |
1221 | * Detach from terminal. | 1456 | * Detach from terminal. |
1222 | * | 1457 | * |
1223 | * @param sctx service context | 1458 | * @param sh service context |
1224 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on error | 1459 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on error |
1225 | */ | 1460 | */ |
1226 | static int | 1461 | static int |
1227 | detach_terminal (struct GNUNET_SERVICE_Context *sctx) | 1462 | detach_terminal (struct GNUNET_SERVICE_Handle *sh) |
1228 | { | 1463 | { |
1229 | #ifndef MINGW | 1464 | #ifndef MINGW |
1230 | pid_t pid; | 1465 | pid_t pid; |
@@ -1233,13 +1468,15 @@ detach_terminal (struct GNUNET_SERVICE_Context *sctx) | |||
1233 | 1468 | ||
1234 | if (0 != PIPE (filedes)) | 1469 | if (0 != PIPE (filedes)) |
1235 | { | 1470 | { |
1236 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "pipe"); | 1471 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, |
1472 | "pipe"); | ||
1237 | return GNUNET_SYSERR; | 1473 | return GNUNET_SYSERR; |
1238 | } | 1474 | } |
1239 | pid = fork (); | 1475 | pid = fork (); |
1240 | if (pid < 0) | 1476 | if (pid < 0) |
1241 | { | 1477 | { |
1242 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork"); | 1478 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, |
1479 | "fork"); | ||
1243 | return GNUNET_SYSERR; | 1480 | return GNUNET_SYSERR; |
1244 | } | 1481 | } |
1245 | if (0 != pid) | 1482 | if (0 != pid) |
@@ -1249,15 +1486,19 @@ detach_terminal (struct GNUNET_SERVICE_Context *sctx) | |||
1249 | 1486 | ||
1250 | GNUNET_break (0 == CLOSE (filedes[1])); | 1487 | GNUNET_break (0 == CLOSE (filedes[1])); |
1251 | c = 'X'; | 1488 | c = 'X'; |
1252 | if (1 != READ (filedes[0], &c, sizeof (char))) | 1489 | if (1 != READ (filedes[0], |
1253 | LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "read"); | 1490 | &c, |
1491 | sizeof (char))) | ||
1492 | LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, | ||
1493 | "read"); | ||
1254 | fflush (stdout); | 1494 | fflush (stdout); |
1255 | switch (c) | 1495 | switch (c) |
1256 | { | 1496 | { |
1257 | case '.': | 1497 | case '.': |
1258 | exit (0); | 1498 | exit (0); |
1259 | case 'I': | 1499 | case 'I': |
1260 | LOG (GNUNET_ERROR_TYPE_INFO, _("Service process failed to initialize\n")); | 1500 | LOG (GNUNET_ERROR_TYPE_INFO, |
1501 | _("Service process failed to initialize\n")); | ||
1261 | break; | 1502 | break; |
1262 | case 'S': | 1503 | case 'S': |
1263 | LOG (GNUNET_ERROR_TYPE_INFO, | 1504 | LOG (GNUNET_ERROR_TYPE_INFO, |
@@ -1273,13 +1514,16 @@ detach_terminal (struct GNUNET_SERVICE_Context *sctx) | |||
1273 | GNUNET_break (0 == CLOSE (0)); | 1514 | GNUNET_break (0 == CLOSE (0)); |
1274 | GNUNET_break (0 == CLOSE (1)); | 1515 | GNUNET_break (0 == CLOSE (1)); |
1275 | GNUNET_break (0 == CLOSE (filedes[0])); | 1516 | GNUNET_break (0 == CLOSE (filedes[0])); |
1276 | nullfd = OPEN ("/dev/null", O_RDWR | O_APPEND); | 1517 | nullfd = OPEN ("/dev/null", |
1518 | O_RDWR | O_APPEND); | ||
1277 | if (nullfd < 0) | 1519 | if (nullfd < 0) |
1278 | return GNUNET_SYSERR; | 1520 | return GNUNET_SYSERR; |
1279 | /* set stdin/stdout to /dev/null */ | 1521 | /* set stdin/stdout to /dev/null */ |
1280 | if ((dup2 (nullfd, 0) < 0) || (dup2 (nullfd, 1) < 0)) | 1522 | if ( (dup2 (nullfd, 0) < 0) || |
1523 | (dup2 (nullfd, 1) < 0) ) | ||
1281 | { | 1524 | { |
1282 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2"); | 1525 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, |
1526 | "dup2"); | ||
1283 | (void) CLOSE (nullfd); | 1527 | (void) CLOSE (nullfd); |
1284 | return GNUNET_SYSERR; | 1528 | return GNUNET_SYSERR; |
1285 | } | 1529 | } |
@@ -1287,8 +1531,9 @@ detach_terminal (struct GNUNET_SERVICE_Context *sctx) | |||
1287 | /* Detach from controlling terminal */ | 1531 | /* Detach from controlling terminal */ |
1288 | pid = setsid (); | 1532 | pid = setsid (); |
1289 | if (-1 == pid) | 1533 | if (-1 == pid) |
1290 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "setsid"); | 1534 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, |
1291 | sctx->ready_confirm_fd = filedes[1]; | 1535 | "setsid"); |
1536 | sh->ready_confirm_fd = filedes[1]; | ||
1292 | #else | 1537 | #else |
1293 | /* FIXME: we probably need to do something else | 1538 | /* FIXME: we probably need to do something else |
1294 | * elsewhere in order to fork the process itself... */ | 1539 | * elsewhere in order to fork the process itself... */ |
@@ -1299,144 +1544,228 @@ detach_terminal (struct GNUNET_SERVICE_Context *sctx) | |||
1299 | 1544 | ||
1300 | 1545 | ||
1301 | /** | 1546 | /** |
1302 | * Set user ID. | 1547 | * Tear down the service, closing the listen sockets and |
1548 | * freeing the ACLs. | ||
1303 | * | 1549 | * |
1304 | * @param sctx service context | 1550 | * @param sh handle to the service to tear down. |
1305 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on error | ||
1306 | */ | 1551 | */ |
1307 | static int | 1552 | static void |
1308 | set_user_id (struct GNUNET_SERVICE_Context *sctx) | 1553 | teardown_service (struct GNUNET_SERVICE_Handle *sh) |
1309 | { | 1554 | { |
1310 | char *user; | 1555 | struct ServiceListenContext *slc; |
1311 | |||
1312 | if (NULL == (user = get_user_name (sctx))) | ||
1313 | return GNUNET_OK; /* keep */ | ||
1314 | #ifndef MINGW | ||
1315 | struct passwd *pws; | ||
1316 | 1556 | ||
1317 | errno = 0; | 1557 | GNUNET_free_non_null (sh->v4_denied); |
1318 | pws = getpwnam (user); | 1558 | GNUNET_free_non_null (sh->v6_denied); |
1319 | if (NULL == pws) | 1559 | GNUNET_free_non_null (sh->v4_allowed); |
1560 | GNUNET_free_non_null (sh->v6_allowed); | ||
1561 | while (NULL != (slc = sh->slc_head)) | ||
1320 | { | 1562 | { |
1321 | LOG (GNUNET_ERROR_TYPE_ERROR, | 1563 | GNUNET_CONTAINER_DLL_remove (sh->slc_head, |
1322 | _("Cannot obtain information about user `%s': %s\n"), user, | 1564 | sh->slc_tail, |
1323 | errno == 0 ? _("No such user") : STRERROR (errno)); | 1565 | slc); |
1324 | GNUNET_free (user); | 1566 | if (NULL != slc->listen_task) |
1325 | return GNUNET_SYSERR; | 1567 | GNUNET_SCHEDULER_cancel (slc->listen_task); |
1568 | GNUNET_break (GNUNET_OK == | ||
1569 | GNUNET_NETWORK_socket_close (slc->listen_socket)); | ||
1570 | GNUNET_free (slc); | ||
1326 | } | 1571 | } |
1327 | if ((0 != setgid (pws->pw_gid)) || (0 != setegid (pws->pw_gid)) || | 1572 | } |
1328 | #if HAVE_INITGROUPS | 1573 | |
1329 | (0 != initgroups (user, pws->pw_gid)) || | 1574 | |
1330 | #endif | 1575 | /** |
1331 | (0 != setuid (pws->pw_uid)) || (0 != seteuid (pws->pw_uid))) | 1576 | * Low-level function to start a service if the scheduler |
1577 | * is already running. Should only be used directly in | ||
1578 | * special cases. | ||
1579 | * | ||
1580 | * The function will launch the service with the name @a service_name | ||
1581 | * using the @a service_options to configure its shutdown | ||
1582 | * behavior. When clients connect or disconnect, the respective | ||
1583 | * @a connect_cb or @a disconnect_cb functions will be called. For | ||
1584 | * messages received from the clients, the respective @a handlers will | ||
1585 | * be invoked; for the closure of the handlers we use the return value | ||
1586 | * from the @a connect_cb invocation of the respective client. | ||
1587 | * | ||
1588 | * Each handler MUST call #GNUNET_SERVICE_client_continue() after each | ||
1589 | * message to receive further messages from this client. If | ||
1590 | * #GNUNET_SERVICE_client_continue() is not called within a short | ||
1591 | * time, a warning will be logged. If delays are expected, services | ||
1592 | * should call #GNUNET_SERVICE_client_disable_continue_warning() to | ||
1593 | * disable the warning. | ||
1594 | * | ||
1595 | * Clients sending invalid messages (based on @a handlers) will be | ||
1596 | * dropped. Additionally, clients can be dropped at any time using | ||
1597 | * #GNUNET_SERVICE_client_drop(). | ||
1598 | * | ||
1599 | * The service must be stopped using #GNUNET_SERVICE_stop(). | ||
1600 | * | ||
1601 | * @param service_name name of the service to run | ||
1602 | * @param cfg configuration to use | ||
1603 | * @param connect_cb function to call whenever a client connects | ||
1604 | * @param disconnect_cb function to call whenever a client disconnects | ||
1605 | * @param cls closure argument for @a connect_cb and @a disconnect_cb | ||
1606 | * @param handlers NULL-terminated array of message handlers for the service, | ||
1607 | * the closure will be set to the value returned by | ||
1608 | * the @a connect_cb for the respective connection | ||
1609 | * @return NULL on error | ||
1610 | */ | ||
1611 | struct GNUNET_SERVICE_Handle * | ||
1612 | GNUNET_SERVICE_start (const char *service_name, | ||
1613 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
1614 | GNUNET_SERVICE_ConnectHandler connect_cb, | ||
1615 | GNUNET_SERVICE_DisconnectHandler disconnect_cb, | ||
1616 | void *cls, | ||
1617 | const struct GNUNET_MQ_MessageHandler *handlers) | ||
1618 | { | ||
1619 | struct GNUNET_SERVICE_Handle *sh; | ||
1620 | |||
1621 | sh = GNUNET_new (struct GNUNET_SERVICE_Handle); | ||
1622 | sh->service_name = service_name; | ||
1623 | sh->cfg = cfg; | ||
1624 | sh->connect_cb = connect_cb; | ||
1625 | sh->disconnect_cb = disconnect_cb; | ||
1626 | sh->cb_cls = cls; | ||
1627 | sh->handlers = GNUNET_MQ_copy_handlers (handlers); | ||
1628 | if (GNUNET_OK != setup_service (sh)) | ||
1332 | { | 1629 | { |
1333 | if ((0 != setregid (pws->pw_gid, pws->pw_gid)) || | 1630 | GNUNET_free_non_null (sh->handlers); |
1334 | (0 != setreuid (pws->pw_uid, pws->pw_uid))) | 1631 | GNUNET_free (sh); |
1335 | { | 1632 | return NULL; |
1336 | LOG (GNUNET_ERROR_TYPE_ERROR, _("Cannot change user/group to `%s': %s\n"), | ||
1337 | user, STRERROR (errno)); | ||
1338 | GNUNET_free (user); | ||
1339 | return GNUNET_SYSERR; | ||
1340 | } | ||
1341 | } | 1633 | } |
1342 | #endif | 1634 | GNUNET_SERVICE_resume (sh); |
1343 | GNUNET_free (user); | 1635 | return sh; |
1344 | return GNUNET_OK; | ||
1345 | } | 1636 | } |
1346 | 1637 | ||
1347 | 1638 | ||
1348 | /** | 1639 | /** |
1349 | * Delete the PID file that was created by our parent. | 1640 | * Stops a service that was started with #GNUNET_SERVICE_start(). |
1350 | * | 1641 | * |
1351 | * @param sctx service context | 1642 | * @param srv service to stop |
1352 | */ | 1643 | */ |
1353 | static void | 1644 | void |
1354 | pid_file_delete (struct GNUNET_SERVICE_Context *sctx) | 1645 | GNUNET_SERVICE_stop (struct GNUNET_SERVICE_Handle *srv) |
1355 | { | 1646 | { |
1356 | char *pif = get_pid_file_name (sctx); | 1647 | struct GNUNET_SERVICE_Client *client; |
1357 | 1648 | ||
1358 | if (NULL == pif) | 1649 | GNUNET_SERVICE_suspend (srv); |
1359 | return; /* no PID file */ | 1650 | while (NULL != (client = srv->clients_head)) |
1360 | if (0 != UNLINK (pif)) | 1651 | GNUNET_SERVICE_client_drop (client); |
1361 | LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", pif); | 1652 | teardown_service (srv); |
1362 | GNUNET_free (pif); | 1653 | GNUNET_free_non_null (srv->handlers); |
1654 | GNUNET_free (srv); | ||
1363 | } | 1655 | } |
1364 | 1656 | ||
1365 | 1657 | ||
1366 | /** | 1658 | /** |
1367 | * Run a standard GNUnet service startup sequence (initialize loggers | 1659 | * Creates the "main" function for a GNUnet service. You |
1368 | * and configuration, parse options). | 1660 | * should almost always use the #GNUNET_SERVICE_MAIN macro |
1661 | * instead of calling this function directly (except | ||
1662 | * for ARM, which should call this function directly). | ||
1663 | * | ||
1664 | * The function will launch the service with the name @a service_name | ||
1665 | * using the @a service_options to configure its shutdown | ||
1666 | * behavior. Once the service is ready, the @a init_cb will be called | ||
1667 | * for service-specific initialization. @a init_cb will be given the | ||
1668 | * service handler which can be used to control the service's | ||
1669 | * availability. When clients connect or disconnect, the respective | ||
1670 | * @a connect_cb or @a disconnect_cb functions will be called. For | ||
1671 | * messages received from the clients, the respective @a handlers will | ||
1672 | * be invoked; for the closure of the handlers we use the return value | ||
1673 | * from the @a connect_cb invocation of the respective client. | ||
1369 | * | 1674 | * |
1370 | * @param argc number of command line arguments | 1675 | * Each handler MUST call #GNUNET_SERVICE_client_continue() after each |
1371 | * @param argv command line arguments | 1676 | * message to receive further messages from this client. If |
1372 | * @param service_name our service name | 1677 | * #GNUNET_SERVICE_client_continue() is not called within a short |
1373 | * @param options service options | 1678 | * time, a warning will be logged. If delays are expected, services |
1374 | * @param task main task of the service | 1679 | * should call #GNUNET_SERVICE_client_disable_continue_warning() to |
1375 | * @param task_cls closure for @a task | 1680 | * disable the warning. |
1376 | * @return #GNUNET_SYSERR on error, #GNUNET_OK | 1681 | * |
1377 | * if we shutdown nicely | 1682 | * Clients sending invalid messages (based on @a handlers) will be |
1683 | * dropped. Additionally, clients can be dropped at any time using | ||
1684 | * #GNUNET_SERVICE_client_drop(). | ||
1685 | * | ||
1686 | * @param argc number of command-line arguments in @a argv | ||
1687 | * @param argv array of command-line arguments | ||
1688 | * @param service_name name of the service to run | ||
1689 | * @param options options controlling shutdown of the service | ||
1690 | * @param service_init_cb function to call once the service is ready | ||
1691 | * @param connect_cb function to call whenever a client connects | ||
1692 | * @param disconnect_cb function to call whenever a client disconnects | ||
1693 | * @param cls closure argument for @a service_init_cb, @a connect_cb and @a disconnect_cb | ||
1694 | * @param handlers NULL-terminated array of message handlers for the service, | ||
1695 | * the closure will be set to the value returned by | ||
1696 | * the @a connect_cb for the respective connection | ||
1697 | * @return 0 on success, non-zero on error | ||
1378 | */ | 1698 | */ |
1379 | int | 1699 | int |
1380 | GNUNET_SERVICE_run (int argc, char *const *argv, | 1700 | GNUNET_SERVICE_run_ (int argc, |
1381 | const char *service_name, | 1701 | char *const *argv, |
1382 | enum GNUNET_SERVICE_Options options, | 1702 | const char *service_name, |
1383 | GNUNET_SERVICE_Main task, | 1703 | enum GNUNET_SERVICE_Options options, |
1384 | void *task_cls) | 1704 | GNUNET_SERVICE_InitCallback service_init_cb, |
1705 | GNUNET_SERVICE_ConnectHandler connect_cb, | ||
1706 | GNUNET_SERVICE_DisconnectHandler disconnect_cb, | ||
1707 | void *cls, | ||
1708 | const struct GNUNET_MQ_MessageHandler *handlers) | ||
1385 | { | 1709 | { |
1386 | #define HANDLE_ERROR do { GNUNET_break (0); goto shutdown; } while (0) | 1710 | struct GNUNET_SERVICE_Handle sh; |
1387 | 1711 | char *cfg_filename; | |
1388 | int err; | 1712 | char *opt_cfg_filename; |
1389 | int ret; | ||
1390 | char *cfg_fn; | ||
1391 | char *opt_cfg_fn; | ||
1392 | char *loglev; | 1713 | char *loglev; |
1714 | const char *xdg; | ||
1393 | char *logfile; | 1715 | char *logfile; |
1394 | int do_daemonize; | 1716 | int do_daemonize; |
1395 | unsigned int i; | ||
1396 | unsigned long long skew_offset; | 1717 | unsigned long long skew_offset; |
1397 | unsigned long long skew_variance; | 1718 | unsigned long long skew_variance; |
1398 | long long clock_offset; | 1719 | long long clock_offset; |
1399 | struct GNUNET_SERVICE_Context sctx; | ||
1400 | struct GNUNET_CONFIGURATION_Handle *cfg; | 1720 | struct GNUNET_CONFIGURATION_Handle *cfg; |
1401 | const char *xdg; | 1721 | int ret; |
1722 | int err; | ||
1402 | 1723 | ||
1403 | struct GNUNET_GETOPT_CommandLineOption service_options[] = { | 1724 | struct GNUNET_GETOPT_CommandLineOption service_options[] = { |
1404 | GNUNET_GETOPT_OPTION_CFG_FILE (&opt_cfg_fn), | 1725 | GNUNET_GETOPT_OPTION_CFG_FILE (&opt_cfg_filename), |
1405 | {'d', "daemonize", NULL, | 1726 | GNUNET_GETOPT_OPTION_SET_ONE ('d', |
1406 | gettext_noop ("do daemonize (detach from terminal)"), 0, | 1727 | "daemonize", |
1407 | GNUNET_GETOPT_set_one, &do_daemonize}, | 1728 | gettext_noop ("do daemonize (detach from terminal)"), |
1729 | &do_daemonize), | ||
1408 | GNUNET_GETOPT_OPTION_HELP (NULL), | 1730 | GNUNET_GETOPT_OPTION_HELP (NULL), |
1409 | GNUNET_GETOPT_OPTION_LOGLEVEL (&loglev), | 1731 | GNUNET_GETOPT_OPTION_LOGLEVEL (&loglev), |
1410 | GNUNET_GETOPT_OPTION_LOGFILE (&logfile), | 1732 | GNUNET_GETOPT_OPTION_LOGFILE (&logfile), |
1411 | GNUNET_GETOPT_OPTION_VERSION (PACKAGE_VERSION " " VCS_VERSION), | 1733 | GNUNET_GETOPT_OPTION_VERSION (PACKAGE_VERSION " " VCS_VERSION), |
1412 | GNUNET_GETOPT_OPTION_END | 1734 | GNUNET_GETOPT_OPTION_END |
1413 | }; | 1735 | }; |
1736 | |||
1414 | err = 1; | 1737 | err = 1; |
1415 | do_daemonize = 0; | 1738 | memset (&sh, |
1416 | logfile = NULL; | 1739 | 0, |
1417 | loglev = NULL; | 1740 | sizeof (sh)); |
1418 | opt_cfg_fn = NULL; | ||
1419 | xdg = getenv ("XDG_CONFIG_HOME"); | 1741 | xdg = getenv ("XDG_CONFIG_HOME"); |
1420 | if (NULL != xdg) | 1742 | if (NULL != xdg) |
1421 | GNUNET_asprintf (&cfg_fn, | 1743 | GNUNET_asprintf (&cfg_filename, |
1422 | "%s%s%s", | 1744 | "%s%s%s", |
1423 | xdg, | 1745 | xdg, |
1424 | DIR_SEPARATOR_STR, | 1746 | DIR_SEPARATOR_STR, |
1425 | GNUNET_OS_project_data_get ()->config_file); | 1747 | GNUNET_OS_project_data_get ()->config_file); |
1426 | else | 1748 | else |
1427 | cfg_fn = GNUNET_strdup (GNUNET_OS_project_data_get ()->user_config_file); | 1749 | cfg_filename = GNUNET_strdup (GNUNET_OS_project_data_get ()->user_config_file); |
1428 | memset (&sctx, 0, sizeof (sctx)); | 1750 | sh.ready_confirm_fd = -1; |
1429 | sctx.options = options; | 1751 | sh.options = options; |
1430 | sctx.ready_confirm_fd = -1; | 1752 | sh.cfg = cfg = GNUNET_CONFIGURATION_create (); |
1431 | sctx.ret = GNUNET_OK; | 1753 | sh.service_init_cb = service_init_cb; |
1432 | sctx.timeout = GNUNET_TIME_UNIT_FOREVER_REL; | 1754 | sh.connect_cb = connect_cb; |
1433 | sctx.task = task; | 1755 | sh.disconnect_cb = disconnect_cb; |
1434 | sctx.task_cls = task_cls; | 1756 | sh.cb_cls = cls; |
1435 | sctx.service_name = service_name; | 1757 | sh.handlers = GNUNET_MQ_copy_handlers (handlers); |
1436 | sctx.cfg = cfg = GNUNET_CONFIGURATION_create (); | 1758 | sh.service_name = service_name; |
1437 | 1759 | ||
1438 | /* setup subsystems */ | 1760 | /* setup subsystems */ |
1439 | ret = GNUNET_GETOPT_run (service_name, service_options, argc, argv); | 1761 | loglev = NULL; |
1762 | logfile = NULL; | ||
1763 | opt_cfg_filename = NULL; | ||
1764 | do_daemonize = 0; | ||
1765 | ret = GNUNET_GETOPT_run (service_name, | ||
1766 | service_options, | ||
1767 | argc, | ||
1768 | argv); | ||
1440 | if (GNUNET_SYSERR == ret) | 1769 | if (GNUNET_SYSERR == ret) |
1441 | goto shutdown; | 1770 | goto shutdown; |
1442 | if (GNUNET_NO == ret) | 1771 | if (GNUNET_NO == ret) |
@@ -1444,254 +1773,844 @@ GNUNET_SERVICE_run (int argc, char *const *argv, | |||
1444 | err = 0; | 1773 | err = 0; |
1445 | goto shutdown; | 1774 | goto shutdown; |
1446 | } | 1775 | } |
1447 | if (GNUNET_OK != GNUNET_log_setup (service_name, loglev, logfile)) | 1776 | if (GNUNET_OK != GNUNET_log_setup (service_name, |
1448 | HANDLE_ERROR; | 1777 | loglev, |
1449 | if (NULL == opt_cfg_fn) | 1778 | logfile)) |
1450 | opt_cfg_fn = GNUNET_strdup (cfg_fn); | 1779 | { |
1451 | if (GNUNET_YES == GNUNET_DISK_file_test (opt_cfg_fn)) | 1780 | GNUNET_break (0); |
1781 | goto shutdown; | ||
1782 | } | ||
1783 | if (NULL == opt_cfg_filename) | ||
1784 | opt_cfg_filename = GNUNET_strdup (cfg_filename); | ||
1785 | if (GNUNET_YES == GNUNET_DISK_file_test (opt_cfg_filename)) | ||
1452 | { | 1786 | { |
1453 | if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, opt_cfg_fn)) | 1787 | if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, |
1788 | opt_cfg_filename)) | ||
1454 | { | 1789 | { |
1455 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 1790 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
1456 | _("Malformed configuration file `%s', exit ...\n"), | 1791 | _("Malformed configuration file `%s', exit ...\n"), |
1457 | opt_cfg_fn); | 1792 | opt_cfg_filename); |
1458 | goto shutdown; | 1793 | goto shutdown; |
1459 | } | 1794 | } |
1460 | } | 1795 | } |
1461 | else | 1796 | else |
1462 | { | 1797 | { |
1463 | if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, NULL)) | 1798 | if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, |
1799 | NULL)) | ||
1464 | { | 1800 | { |
1465 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 1801 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
1466 | _("Malformed configuration, exit ...\n")); | 1802 | _("Malformed configuration, exit ...\n")); |
1467 | goto shutdown; | 1803 | goto shutdown; |
1468 | } | 1804 | } |
1469 | if (0 != strcmp (opt_cfg_fn, cfg_fn)) | 1805 | if (0 != strcmp (opt_cfg_filename, |
1806 | cfg_filename)) | ||
1470 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | 1807 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
1471 | _("Could not access configuration file `%s'\n"), | 1808 | _("Could not access configuration file `%s'\n"), |
1472 | opt_cfg_fn); | 1809 | opt_cfg_filename); |
1473 | } | 1810 | } |
1474 | if (GNUNET_OK != setup_service (&sctx)) | 1811 | if (GNUNET_OK != setup_service (&sh)) |
1475 | goto shutdown; | 1812 | goto shutdown; |
1476 | if ((1 == do_daemonize) && (GNUNET_OK != detach_terminal (&sctx))) | 1813 | if ( (1 == do_daemonize) && |
1477 | HANDLE_ERROR; | 1814 | (GNUNET_OK != detach_terminal (&sh)) ) |
1478 | if (GNUNET_OK != set_user_id (&sctx)) | 1815 | { |
1816 | GNUNET_break (0); | ||
1817 | goto shutdown; | ||
1818 | } | ||
1819 | if (GNUNET_OK != set_user_id (&sh)) | ||
1479 | goto shutdown; | 1820 | goto shutdown; |
1480 | LOG (GNUNET_ERROR_TYPE_DEBUG, | 1821 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1481 | "Service `%s' runs with configuration from `%s'\n", | 1822 | "Service `%s' runs with configuration from `%s'\n", |
1482 | service_name, | 1823 | service_name, |
1483 | opt_cfg_fn); | 1824 | opt_cfg_filename); |
1484 | if ((GNUNET_OK == | 1825 | if ((GNUNET_OK == |
1485 | GNUNET_CONFIGURATION_get_value_number (sctx.cfg, "TESTING", | 1826 | GNUNET_CONFIGURATION_get_value_number (sh.cfg, |
1486 | "SKEW_OFFSET", &skew_offset)) && | 1827 | "TESTING", |
1828 | "SKEW_OFFSET", | ||
1829 | &skew_offset)) && | ||
1487 | (GNUNET_OK == | 1830 | (GNUNET_OK == |
1488 | GNUNET_CONFIGURATION_get_value_number (sctx.cfg, "TESTING", | 1831 | GNUNET_CONFIGURATION_get_value_number (sh.cfg, |
1489 | "SKEW_VARIANCE", &skew_variance))) | 1832 | "TESTING", |
1833 | "SKEW_VARIANCE", | ||
1834 | &skew_variance))) | ||
1490 | { | 1835 | { |
1491 | clock_offset = skew_offset - skew_variance; | 1836 | clock_offset = skew_offset - skew_variance; |
1492 | GNUNET_TIME_set_offset (clock_offset); | 1837 | GNUNET_TIME_set_offset (clock_offset); |
1493 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Skewing clock by %dll ms\n", clock_offset); | 1838 | LOG (GNUNET_ERROR_TYPE_DEBUG, |
1839 | "Skewing clock by %dll ms\n", | ||
1840 | clock_offset); | ||
1494 | } | 1841 | } |
1842 | GNUNET_RESOLVER_connect (sh.cfg); | ||
1843 | |||
1495 | /* actually run service */ | 1844 | /* actually run service */ |
1496 | err = 0; | 1845 | err = 0; |
1497 | GNUNET_SCHEDULER_run (&service_task, &sctx); | 1846 | GNUNET_SCHEDULER_run (&service_main, |
1847 | &sh); | ||
1498 | /* shutdown */ | 1848 | /* shutdown */ |
1499 | if ((1 == do_daemonize) && (NULL != sctx.server)) | 1849 | if (1 == do_daemonize) |
1500 | pid_file_delete (&sctx); | 1850 | pid_file_delete (&sh); |
1501 | GNUNET_free_non_null (sctx.my_handlers); | ||
1502 | 1851 | ||
1503 | shutdown: | 1852 | shutdown: |
1504 | if (-1 != sctx.ready_confirm_fd) | 1853 | if (-1 != sh.ready_confirm_fd) |
1505 | { | 1854 | { |
1506 | if (1 != WRITE (sctx.ready_confirm_fd, err ? "I" : "S", 1)) | 1855 | if (1 != WRITE (sh.ready_confirm_fd, |
1507 | LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "write"); | 1856 | err ? "I" : "S", |
1508 | GNUNET_break (0 == CLOSE (sctx.ready_confirm_fd)); | 1857 | 1)) |
1858 | LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, | ||
1859 | "write"); | ||
1860 | GNUNET_break (0 == CLOSE (sh.ready_confirm_fd)); | ||
1509 | } | 1861 | } |
1510 | #if HAVE_MALLINFO | 1862 | #if HAVE_MALLINFO |
1511 | { | 1863 | { |
1512 | char *counter; | 1864 | char *counter; |
1513 | 1865 | ||
1514 | if ( (GNUNET_YES == | 1866 | if ( (GNUNET_YES == |
1515 | GNUNET_CONFIGURATION_have_value (sctx.cfg, service_name, | 1867 | GNUNET_CONFIGURATION_have_value (sh.cfg, |
1868 | service_name, | ||
1516 | "GAUGER_HEAP")) && | 1869 | "GAUGER_HEAP")) && |
1517 | (GNUNET_OK == | 1870 | (GNUNET_OK == |
1518 | GNUNET_CONFIGURATION_get_value_string (sctx.cfg, service_name, | 1871 | GNUNET_CONFIGURATION_get_value_string (sh.cfg, |
1872 | service_name, | ||
1519 | "GAUGER_HEAP", | 1873 | "GAUGER_HEAP", |
1520 | &counter)) ) | 1874 | &counter)) ) |
1521 | { | 1875 | { |
1522 | struct mallinfo mi; | 1876 | struct mallinfo mi; |
1523 | 1877 | ||
1524 | mi = mallinfo (); | 1878 | mi = mallinfo (); |
1525 | GAUGER (service_name, counter, mi.usmblks, "blocks"); | 1879 | GAUGER (service_name, |
1880 | counter, | ||
1881 | mi.usmblks, | ||
1882 | "blocks"); | ||
1526 | GNUNET_free (counter); | 1883 | GNUNET_free (counter); |
1527 | } | 1884 | } |
1528 | } | 1885 | } |
1529 | #endif | 1886 | #endif |
1887 | teardown_service (&sh); | ||
1888 | GNUNET_free_non_null (sh.handlers); | ||
1530 | GNUNET_SPEEDUP_stop_ (); | 1889 | GNUNET_SPEEDUP_stop_ (); |
1531 | GNUNET_CONFIGURATION_destroy (cfg); | 1890 | GNUNET_CONFIGURATION_destroy (cfg); |
1532 | i = 0; | ||
1533 | if (NULL != sctx.addrs) | ||
1534 | while (NULL != sctx.addrs[i]) | ||
1535 | GNUNET_free (sctx.addrs[i++]); | ||
1536 | GNUNET_free_non_null (sctx.addrs); | ||
1537 | GNUNET_free_non_null (sctx.addrlens); | ||
1538 | GNUNET_free_non_null (logfile); | 1891 | GNUNET_free_non_null (logfile); |
1539 | GNUNET_free_non_null (loglev); | 1892 | GNUNET_free_non_null (loglev); |
1540 | GNUNET_free (cfg_fn); | 1893 | GNUNET_free (cfg_filename); |
1541 | GNUNET_free_non_null (opt_cfg_fn); | 1894 | GNUNET_free_non_null (opt_cfg_filename); |
1542 | GNUNET_free_non_null (sctx.v4_denied); | 1895 | |
1543 | GNUNET_free_non_null (sctx.v6_denied); | 1896 | return err ? GNUNET_SYSERR : sh.ret; |
1544 | GNUNET_free_non_null (sctx.v4_allowed); | ||
1545 | GNUNET_free_non_null (sctx.v6_allowed); | ||
1546 | |||
1547 | return err ? GNUNET_SYSERR : sctx.ret; | ||
1548 | } | 1897 | } |
1549 | 1898 | ||
1550 | 1899 | ||
1551 | /** | 1900 | /** |
1552 | * Run a service startup sequence within an existing | 1901 | * Suspend accepting connections from the listen socket temporarily. |
1553 | * initialized system. | 1902 | * Resume activity using #GNUNET_SERVICE_resume. |
1554 | * | 1903 | * |
1555 | * @param service_name our service name | 1904 | * @param sh service to stop accepting connections. |
1556 | * @param cfg configuration to use | ||
1557 | * @param options service options | ||
1558 | * @return NULL on error, service handle | ||
1559 | */ | 1905 | */ |
1560 | struct GNUNET_SERVICE_Context * | 1906 | void |
1561 | GNUNET_SERVICE_start (const char *service_name, | 1907 | GNUNET_SERVICE_suspend (struct GNUNET_SERVICE_Handle *sh) |
1562 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
1563 | enum GNUNET_SERVICE_Options options) | ||
1564 | { | 1908 | { |
1565 | int i; | 1909 | struct ServiceListenContext *slc; |
1566 | struct GNUNET_SERVICE_Context *sctx; | ||
1567 | 1910 | ||
1568 | sctx = GNUNET_new (struct GNUNET_SERVICE_Context); | 1911 | for (slc = sh->slc_head; NULL != slc; slc = slc->next) |
1569 | sctx->ready_confirm_fd = -1; /* no daemonizing */ | 1912 | { |
1570 | sctx->ret = GNUNET_OK; | 1913 | if (NULL != slc->listen_task) |
1571 | sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL; | 1914 | { |
1572 | sctx->service_name = service_name; | 1915 | GNUNET_SCHEDULER_cancel (slc->listen_task); |
1573 | sctx->cfg = cfg; | 1916 | slc->listen_task = NULL; |
1574 | sctx->options = options; | 1917 | } |
1918 | } | ||
1919 | } | ||
1575 | 1920 | ||
1576 | /* setup subsystems */ | 1921 | |
1577 | if (GNUNET_OK != setup_service (sctx)) | 1922 | /** |
1923 | * Task run when we are ready to transmit data to the | ||
1924 | * client. | ||
1925 | * | ||
1926 | * @param cls the `struct GNUNET_SERVICE_Client *` to send to | ||
1927 | */ | ||
1928 | static void | ||
1929 | do_send (void *cls) | ||
1930 | { | ||
1931 | struct GNUNET_SERVICE_Client *client = cls; | ||
1932 | ssize_t ret; | ||
1933 | size_t left; | ||
1934 | const char *buf; | ||
1935 | |||
1936 | client->send_task = NULL; | ||
1937 | buf = (const char *) client->msg; | ||
1938 | left = ntohs (client->msg->size) - client->msg_pos; | ||
1939 | ret = GNUNET_NETWORK_socket_send (client->sock, | ||
1940 | &buf[client->msg_pos], | ||
1941 | left); | ||
1942 | GNUNET_assert (ret <= (ssize_t) left); | ||
1943 | if (0 == ret) | ||
1578 | { | 1944 | { |
1579 | GNUNET_SERVICE_stop (sctx); | 1945 | GNUNET_MQ_inject_error (client->mq, |
1580 | return NULL; | 1946 | GNUNET_MQ_ERROR_WRITE); |
1947 | return; | ||
1581 | } | 1948 | } |
1582 | if (NULL != sctx->lsocks) | 1949 | if (-1 == ret) |
1583 | sctx->server = | 1950 | { |
1584 | GNUNET_SERVER_create_with_sockets (&check_access, sctx, sctx->lsocks, | 1951 | if ( (EAGAIN == errno) || |
1585 | sctx->timeout, sctx->require_found); | 1952 | (EINTR == errno) ) |
1586 | else | 1953 | { |
1587 | sctx->server = | 1954 | /* ignore */ |
1588 | GNUNET_SERVER_create (&check_access, sctx, sctx->addrs, sctx->addrlens, | 1955 | ret = 0; |
1589 | sctx->timeout, sctx->require_found); | 1956 | } |
1957 | else | ||
1958 | { | ||
1959 | if (EPIPE != errno) | ||
1960 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, | ||
1961 | "send"); | ||
1962 | GNUNET_MQ_inject_error (client->mq, | ||
1963 | GNUNET_MQ_ERROR_WRITE); | ||
1964 | return; | ||
1965 | } | ||
1966 | } | ||
1967 | if (0 == client->msg_pos) | ||
1968 | { | ||
1969 | GNUNET_MQ_impl_send_in_flight (client->mq); | ||
1970 | } | ||
1971 | client->msg_pos += ret; | ||
1972 | if (left > ret) | ||
1973 | { | ||
1974 | GNUNET_assert (NULL == client->drop_task); | ||
1975 | client->send_task | ||
1976 | = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
1977 | client->sock, | ||
1978 | &do_send, | ||
1979 | client); | ||
1980 | return; | ||
1981 | } | ||
1982 | GNUNET_MQ_impl_send_continue (client->mq); | ||
1983 | } | ||
1984 | |||
1590 | 1985 | ||
1591 | if (NULL == sctx->server) | 1986 | /** |
1987 | * Signature of functions implementing the sending functionality of a | ||
1988 | * message queue. | ||
1989 | * | ||
1990 | * @param mq the message queue | ||
1991 | * @param msg the message to send | ||
1992 | * @param impl_state our `struct GNUNET_SERVICE_Client *` | ||
1993 | */ | ||
1994 | static void | ||
1995 | service_mq_send (struct GNUNET_MQ_Handle *mq, | ||
1996 | const struct GNUNET_MessageHeader *msg, | ||
1997 | void *impl_state) | ||
1998 | { | ||
1999 | struct GNUNET_SERVICE_Client *client = impl_state; | ||
2000 | |||
2001 | if (NULL != client->drop_task) | ||
2002 | return; /* we're going down right now, do not try to send */ | ||
2003 | GNUNET_assert (NULL == client->send_task); | ||
2004 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2005 | "Sending message of type %u and size %u to client\n", | ||
2006 | ntohs (msg->type), | ||
2007 | ntohs (msg->size)); | ||
2008 | client->msg = msg; | ||
2009 | client->msg_pos = 0; | ||
2010 | client->send_task | ||
2011 | = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
2012 | client->sock, | ||
2013 | &do_send, | ||
2014 | client); | ||
2015 | } | ||
2016 | |||
2017 | |||
2018 | /** | ||
2019 | * Implementation function that cancels the currently sent message. | ||
2020 | * | ||
2021 | * @param mq message queue | ||
2022 | * @param impl_state state specific to the implementation | ||
2023 | */ | ||
2024 | static void | ||
2025 | service_mq_cancel (struct GNUNET_MQ_Handle *mq, | ||
2026 | void *impl_state) | ||
2027 | { | ||
2028 | struct GNUNET_SERVICE_Client *client = impl_state; | ||
2029 | |||
2030 | GNUNET_assert (0 == client->msg_pos); | ||
2031 | client->msg = NULL; | ||
2032 | GNUNET_SCHEDULER_cancel (client->send_task); | ||
2033 | client->send_task = NULL; | ||
2034 | } | ||
2035 | |||
2036 | |||
2037 | /** | ||
2038 | * Generic error handler, called with the appropriate | ||
2039 | * error code and the same closure specified at the creation of | ||
2040 | * the message queue. | ||
2041 | * Not every message queue implementation supports an error handler. | ||
2042 | * | ||
2043 | * @param cls closure with our `struct GNUNET_SERVICE_Client` | ||
2044 | * @param error error code | ||
2045 | */ | ||
2046 | static void | ||
2047 | service_mq_error_handler (void *cls, | ||
2048 | enum GNUNET_MQ_Error error) | ||
2049 | { | ||
2050 | struct GNUNET_SERVICE_Client *client = cls; | ||
2051 | struct GNUNET_SERVICE_Handle *sh = client->sh; | ||
2052 | |||
2053 | if ( (GNUNET_MQ_ERROR_NO_MATCH == error) && | ||
2054 | (GNUNET_NO == sh->require_found) ) | ||
1592 | { | 2055 | { |
1593 | GNUNET_SERVICE_stop (sctx); | 2056 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
1594 | return NULL; | 2057 | "No handler for message of type %u found\n", |
2058 | (unsigned int) client->warn_type); | ||
2059 | GNUNET_SERVICE_client_continue (client); | ||
2060 | return; /* ignore error */ | ||
2061 | } | ||
2062 | GNUNET_SERVICE_client_drop (client); | ||
2063 | } | ||
2064 | |||
2065 | |||
2066 | /** | ||
2067 | * Task run to warn about missing calls to #GNUNET_SERVICE_client_continue(). | ||
2068 | * | ||
2069 | * @param cls our `struct GNUNET_SERVICE_Client *` to process more requests from | ||
2070 | */ | ||
2071 | static void | ||
2072 | warn_no_client_continue (void *cls) | ||
2073 | { | ||
2074 | struct GNUNET_SERVICE_Client *client = cls; | ||
2075 | |||
2076 | GNUNET_break (0 != client->warn_type); /* type should never be 0 here, as we don't use 0 */ | ||
2077 | client->warn_task | ||
2078 | = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, | ||
2079 | &warn_no_client_continue, | ||
2080 | client); | ||
2081 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
2082 | _("Processing code for message of type %u did not call `GNUNET_SERVICE_client_continue' after %s\n"), | ||
2083 | (unsigned int) client->warn_type, | ||
2084 | GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (client->warn_start), | ||
2085 | GNUNET_YES)); | ||
2086 | } | ||
2087 | |||
2088 | |||
2089 | /** | ||
2090 | * Functions with this signature are called whenever a | ||
2091 | * complete message is received by the tokenizer for a client. | ||
2092 | * | ||
2093 | * Do not call #GNUNET_MST_destroy() from within | ||
2094 | * the scope of this callback. | ||
2095 | * | ||
2096 | * @param cls closure with the `struct GNUNET_SERVICE_Client *` | ||
2097 | * @param message the actual message | ||
2098 | * @return #GNUNET_OK on success, #GNUNET_SYSERR if the client was dropped | ||
2099 | */ | ||
2100 | static int | ||
2101 | service_client_mst_cb (void *cls, | ||
2102 | const struct GNUNET_MessageHeader *message) | ||
2103 | { | ||
2104 | struct GNUNET_SERVICE_Client *client = cls; | ||
2105 | |||
2106 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2107 | "Received message of type %u and size %u from client\n", | ||
2108 | ntohs (message->type), | ||
2109 | ntohs (message->size)); | ||
2110 | GNUNET_assert (GNUNET_NO == client->needs_continue); | ||
2111 | client->needs_continue = GNUNET_YES; | ||
2112 | client->warn_type = ntohs (message->type); | ||
2113 | client->warn_start = GNUNET_TIME_absolute_get (); | ||
2114 | GNUNET_assert (NULL == client->warn_task); | ||
2115 | client->warn_task | ||
2116 | = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, | ||
2117 | &warn_no_client_continue, | ||
2118 | client); | ||
2119 | GNUNET_MQ_inject_message (client->mq, | ||
2120 | message); | ||
2121 | if (NULL != client->drop_task) | ||
2122 | return GNUNET_SYSERR; | ||
2123 | return GNUNET_OK; | ||
2124 | } | ||
2125 | |||
2126 | |||
2127 | /** | ||
2128 | * A client sent us data. Receive and process it. If we are done, | ||
2129 | * reschedule this task. | ||
2130 | * | ||
2131 | * @param cls the `struct GNUNET_SERVICE_Client` that sent us data. | ||
2132 | */ | ||
2133 | static void | ||
2134 | service_client_recv (void *cls) | ||
2135 | { | ||
2136 | struct GNUNET_SERVICE_Client *client = cls; | ||
2137 | int ret; | ||
2138 | |||
2139 | client->recv_task = NULL; | ||
2140 | ret = GNUNET_MST_read (client->mst, | ||
2141 | client->sock, | ||
2142 | GNUNET_NO, | ||
2143 | GNUNET_YES); | ||
2144 | if (GNUNET_SYSERR == ret) | ||
2145 | { | ||
2146 | /* client closed connection (or IO error) */ | ||
2147 | if (NULL == client->drop_task) | ||
2148 | { | ||
2149 | GNUNET_assert (GNUNET_NO == client->needs_continue); | ||
2150 | GNUNET_SERVICE_client_drop (client); | ||
2151 | } | ||
2152 | return; | ||
2153 | } | ||
2154 | if (GNUNET_NO == ret) | ||
2155 | return; /* more messages in buffer, wait for application | ||
2156 | to be done processing */ | ||
2157 | GNUNET_assert (GNUNET_OK == ret); | ||
2158 | if (GNUNET_YES == client->needs_continue) | ||
2159 | return; | ||
2160 | if (NULL != client->recv_task) | ||
2161 | return; | ||
2162 | /* MST needs more data, re-schedule read job */ | ||
2163 | client->recv_task | ||
2164 | = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
2165 | client->sock, | ||
2166 | &service_client_recv, | ||
2167 | client); | ||
2168 | } | ||
2169 | |||
2170 | |||
2171 | /** | ||
2172 | * We have successfully accepted a connection from a client. Now | ||
2173 | * setup the client (with the scheduler) and tell the application. | ||
2174 | * | ||
2175 | * @param sh service that accepted the client | ||
2176 | * @param sock socket associated with the client | ||
2177 | */ | ||
2178 | static void | ||
2179 | start_client (struct GNUNET_SERVICE_Handle *sh, | ||
2180 | struct GNUNET_NETWORK_Handle *csock) | ||
2181 | { | ||
2182 | struct GNUNET_SERVICE_Client *client; | ||
2183 | |||
2184 | client = GNUNET_new (struct GNUNET_SERVICE_Client); | ||
2185 | GNUNET_CONTAINER_DLL_insert (sh->clients_head, | ||
2186 | sh->clients_tail, | ||
2187 | client); | ||
2188 | client->sh = sh; | ||
2189 | client->sock = csock; | ||
2190 | client->mq = GNUNET_MQ_queue_for_callbacks (&service_mq_send, | ||
2191 | NULL, | ||
2192 | &service_mq_cancel, | ||
2193 | client, | ||
2194 | sh->handlers, | ||
2195 | &service_mq_error_handler, | ||
2196 | client); | ||
2197 | client->mst = GNUNET_MST_create (&service_client_mst_cb, | ||
2198 | client); | ||
2199 | if (NULL != sh->connect_cb) | ||
2200 | client->user_context = sh->connect_cb (sh->cb_cls, | ||
2201 | client, | ||
2202 | client->mq); | ||
2203 | GNUNET_MQ_set_handlers_closure (client->mq, | ||
2204 | client->user_context); | ||
2205 | client->recv_task | ||
2206 | = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
2207 | client->sock, | ||
2208 | &service_client_recv, | ||
2209 | client); | ||
2210 | } | ||
2211 | |||
2212 | |||
2213 | /** | ||
2214 | * Check if the given IP address is in the list of IP addresses. | ||
2215 | * | ||
2216 | * @param list a list of networks | ||
2217 | * @param add the IP to check (in network byte order) | ||
2218 | * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is | ||
2219 | */ | ||
2220 | static int | ||
2221 | check_ipv4_listed (const struct GNUNET_STRINGS_IPv4NetworkPolicy *list, | ||
2222 | const struct in_addr *add) | ||
2223 | { | ||
2224 | unsigned int i; | ||
2225 | |||
2226 | if (NULL == list) | ||
2227 | return GNUNET_NO; | ||
2228 | i = 0; | ||
2229 | while ( (0 != list[i].network.s_addr) || | ||
2230 | (0 != list[i].netmask.s_addr) ) | ||
2231 | { | ||
2232 | if ((add->s_addr & list[i].netmask.s_addr) == | ||
2233 | (list[i].network.s_addr & list[i].netmask.s_addr)) | ||
2234 | return GNUNET_YES; | ||
2235 | i++; | ||
2236 | } | ||
2237 | return GNUNET_NO; | ||
2238 | } | ||
2239 | |||
2240 | |||
2241 | /** | ||
2242 | * Check if the given IP address is in the list of IP addresses. | ||
2243 | * | ||
2244 | * @param list a list of networks | ||
2245 | * @param ip the IP to check (in network byte order) | ||
2246 | * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is | ||
2247 | */ | ||
2248 | static int | ||
2249 | check_ipv6_listed (const struct GNUNET_STRINGS_IPv6NetworkPolicy *list, | ||
2250 | const struct in6_addr *ip) | ||
2251 | { | ||
2252 | unsigned int i; | ||
2253 | unsigned int j; | ||
2254 | struct in6_addr zero; | ||
2255 | |||
2256 | if (NULL == list) | ||
2257 | return GNUNET_NO; | ||
2258 | memset (&zero, | ||
2259 | 0, | ||
2260 | sizeof (struct in6_addr)); | ||
2261 | i = 0; | ||
2262 | NEXT: | ||
2263 | while (0 != memcmp (&zero, | ||
2264 | &list[i].network, | ||
2265 | sizeof (struct in6_addr))) | ||
2266 | { | ||
2267 | for (j = 0; j < sizeof (struct in6_addr) / sizeof (int); j++) | ||
2268 | if (((((int *) ip)[j] & ((int *) &list[i].netmask)[j])) != | ||
2269 | (((int *) &list[i].network)[j] & ((int *) &list[i].netmask)[j])) | ||
2270 | { | ||
2271 | i++; | ||
2272 | goto NEXT; | ||
2273 | } | ||
2274 | return GNUNET_YES; | ||
1595 | } | 2275 | } |
2276 | return GNUNET_NO; | ||
2277 | } | ||
2278 | |||
2279 | |||
2280 | /** | ||
2281 | * We have a client. Accept the incoming socket(s) (and reschedule | ||
2282 | * the listen task). | ||
2283 | * | ||
2284 | * @param cls the `struct ServiceListenContext` of the ready listen socket | ||
2285 | */ | ||
2286 | static void | ||
2287 | accept_client (void *cls) | ||
2288 | { | ||
2289 | struct ServiceListenContext *slc = cls; | ||
2290 | struct GNUNET_SERVICE_Handle *sh = slc->sh; | ||
2291 | |||
2292 | slc->listen_task = NULL; | ||
2293 | while (1) | ||
2294 | { | ||
2295 | struct GNUNET_NETWORK_Handle *sock; | ||
2296 | const struct sockaddr_in *v4; | ||
2297 | const struct sockaddr_in6 *v6; | ||
2298 | struct sockaddr_storage sa; | ||
2299 | socklen_t addrlen; | ||
2300 | int ok; | ||
2301 | |||
2302 | addrlen = sizeof (sa); | ||
2303 | sock = GNUNET_NETWORK_socket_accept (slc->listen_socket, | ||
2304 | (struct sockaddr *) &sa, | ||
2305 | &addrlen); | ||
2306 | if (NULL == sock) | ||
2307 | break; | ||
2308 | switch (sa.ss_family) | ||
2309 | { | ||
2310 | case AF_INET: | ||
2311 | GNUNET_assert (addrlen == sizeof (struct sockaddr_in)); | ||
2312 | v4 = (const struct sockaddr_in *) &sa; | ||
2313 | ok = ( ( (NULL == sh->v4_allowed) || | ||
2314 | (check_ipv4_listed (sh->v4_allowed, | ||
2315 | &v4->sin_addr))) && | ||
2316 | ( (NULL == sh->v4_denied) || | ||
2317 | (! check_ipv4_listed (sh->v4_denied, | ||
2318 | &v4->sin_addr)) ) ); | ||
2319 | break; | ||
2320 | case AF_INET6: | ||
2321 | GNUNET_assert (addrlen == sizeof (struct sockaddr_in6)); | ||
2322 | v6 = (const struct sockaddr_in6 *) &sa; | ||
2323 | ok = ( ( (NULL == sh->v6_allowed) || | ||
2324 | (check_ipv6_listed (sh->v6_allowed, | ||
2325 | &v6->sin6_addr))) && | ||
2326 | ( (NULL == sh->v6_denied) || | ||
2327 | (! check_ipv6_listed (sh->v6_denied, | ||
2328 | &v6->sin6_addr)) ) ); | ||
2329 | break; | ||
1596 | #ifndef WINDOWS | 2330 | #ifndef WINDOWS |
1597 | if (NULL != sctx->addrs) | 2331 | case AF_UNIX: |
1598 | for (i = 0; NULL != sctx->addrs[i]; i++) | 2332 | ok = GNUNET_OK; /* controlled using file-system ACL now */ |
1599 | if ((AF_UNIX == sctx->addrs[i]->sa_family) | 2333 | break; |
1600 | && ('\0' != ((const struct sockaddr_un *)sctx->addrs[i])->sun_path[0])) | ||
1601 | GNUNET_DISK_fix_permissions (((const struct sockaddr_un *)sctx->addrs[i])->sun_path, | ||
1602 | sctx->match_uid, | ||
1603 | sctx->match_gid); | ||
1604 | #endif | 2334 | #endif |
1605 | sctx->my_handlers = GNUNET_malloc (sizeof (defhandlers)); | 2335 | default: |
1606 | GNUNET_memcpy (sctx->my_handlers, defhandlers, sizeof (defhandlers)); | 2336 | LOG (GNUNET_ERROR_TYPE_WARNING, |
1607 | i = 0; | 2337 | _("Unknown address family %d\n"), |
1608 | while ((sctx->my_handlers[i].callback != NULL)) | 2338 | sa.ss_family); |
1609 | sctx->my_handlers[i++].callback_cls = sctx; | 2339 | return; |
1610 | GNUNET_SERVER_add_handlers (sctx->server, sctx->my_handlers); | 2340 | } |
1611 | return sctx; | 2341 | if (! ok) |
2342 | { | ||
2343 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2344 | "Service rejected incoming connection from %s due to policy.\n", | ||
2345 | GNUNET_a2s ((const struct sockaddr *) &sa, | ||
2346 | addrlen)); | ||
2347 | GNUNET_break (GNUNET_OK == | ||
2348 | GNUNET_NETWORK_socket_close (sock)); | ||
2349 | continue; | ||
2350 | } | ||
2351 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2352 | "Service accepted incoming connection from %s.\n", | ||
2353 | GNUNET_a2s ((const struct sockaddr *) &sa, | ||
2354 | addrlen)); | ||
2355 | start_client (slc->sh, | ||
2356 | sock); | ||
2357 | } | ||
2358 | slc->listen_task | ||
2359 | = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
2360 | slc->listen_socket, | ||
2361 | &accept_client, | ||
2362 | slc); | ||
2363 | } | ||
2364 | |||
2365 | |||
2366 | /** | ||
2367 | * Resume accepting connections from the listen socket. | ||
2368 | * | ||
2369 | * @param sh service to resume accepting connections. | ||
2370 | */ | ||
2371 | void | ||
2372 | GNUNET_SERVICE_resume (struct GNUNET_SERVICE_Handle *sh) | ||
2373 | { | ||
2374 | struct ServiceListenContext *slc; | ||
2375 | |||
2376 | for (slc = sh->slc_head; NULL != slc; slc = slc->next) | ||
2377 | { | ||
2378 | GNUNET_assert (NULL == slc->listen_task); | ||
2379 | slc->listen_task | ||
2380 | = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
2381 | slc->listen_socket, | ||
2382 | &accept_client, | ||
2383 | slc); | ||
2384 | } | ||
1612 | } | 2385 | } |
1613 | 2386 | ||
1614 | 2387 | ||
1615 | /** | 2388 | /** |
1616 | * Obtain the server used by a service. Note that the server must NOT | 2389 | * Task run to resume receiving data from the client after |
1617 | * be destroyed by the caller. | 2390 | * the client called #GNUNET_SERVICE_client_continue(). |
1618 | * | 2391 | * |
1619 | * @param ctx the service context returned from the start function | 2392 | * @param cls our `struct GNUNET_SERVICE_Client` |
1620 | * @return handle to the server for this service, NULL if there is none | ||
1621 | */ | 2393 | */ |
1622 | struct GNUNET_SERVER_Handle * | 2394 | static void |
1623 | GNUNET_SERVICE_get_server (struct GNUNET_SERVICE_Context *ctx) | 2395 | resume_client_receive (void *cls) |
1624 | { | 2396 | { |
1625 | return ctx->server; | 2397 | struct GNUNET_SERVICE_Client *c = cls; |
2398 | int ret; | ||
2399 | |||
2400 | c->recv_task = NULL; | ||
2401 | /* first, check if there is still something in the buffer */ | ||
2402 | ret = GNUNET_MST_next (c->mst, | ||
2403 | GNUNET_YES); | ||
2404 | if (GNUNET_SYSERR == ret) | ||
2405 | { | ||
2406 | if (NULL != c->drop_task) | ||
2407 | GNUNET_SERVICE_client_drop (c); | ||
2408 | return; | ||
2409 | } | ||
2410 | if (GNUNET_NO == ret) | ||
2411 | return; /* done processing, wait for more later */ | ||
2412 | GNUNET_assert (GNUNET_OK == ret); | ||
2413 | if (GNUNET_YES == c->needs_continue) | ||
2414 | return; /* #GNUNET_MST_next() did give a message to the client */ | ||
2415 | /* need to receive more data from the network first */ | ||
2416 | if (NULL != c->recv_task) | ||
2417 | return; | ||
2418 | c->recv_task | ||
2419 | = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
2420 | c->sock, | ||
2421 | &service_client_recv, | ||
2422 | c); | ||
1626 | } | 2423 | } |
1627 | 2424 | ||
1628 | 2425 | ||
1629 | /** | 2426 | /** |
1630 | * Get the NULL-terminated array of listen sockets for this service. | 2427 | * Continue receiving further messages from the given client. |
2428 | * Must be called after each message received. | ||
1631 | * | 2429 | * |
1632 | * @param ctx service context to query | 2430 | * @param c the client to continue receiving from |
1633 | * @return NULL if there are no listen sockets, otherwise NULL-terminated | ||
1634 | * array of listen sockets. | ||
1635 | */ | 2431 | */ |
1636 | struct GNUNET_NETWORK_Handle *const* | 2432 | void |
1637 | GNUNET_SERVICE_get_listen_sockets (struct GNUNET_SERVICE_Context *ctx) | 2433 | GNUNET_SERVICE_client_continue (struct GNUNET_SERVICE_Client *c) |
1638 | { | 2434 | { |
1639 | return ctx->lsocks; | 2435 | GNUNET_assert (GNUNET_YES == c->needs_continue); |
2436 | GNUNET_assert (NULL == c->recv_task); | ||
2437 | c->needs_continue = GNUNET_NO; | ||
2438 | if (NULL != c->warn_task) | ||
2439 | { | ||
2440 | GNUNET_SCHEDULER_cancel (c->warn_task); | ||
2441 | c->warn_task = NULL; | ||
2442 | } | ||
2443 | c->recv_task | ||
2444 | = GNUNET_SCHEDULER_add_now (&resume_client_receive, | ||
2445 | c); | ||
1640 | } | 2446 | } |
1641 | 2447 | ||
1642 | 2448 | ||
1643 | /** | 2449 | /** |
1644 | * Stop a service that was started with "GNUNET_SERVICE_start". | 2450 | * Disable the warning the server issues if a message is not |
2451 | * acknowledged in a timely fashion. Use this call if a client is | ||
2452 | * intentionally delayed for a while. Only applies to the current | ||
2453 | * message. | ||
1645 | * | 2454 | * |
1646 | * @param sctx the service context returned from the start function | 2455 | * @param c client for which to disable the warning |
1647 | */ | 2456 | */ |
1648 | void | 2457 | void |
1649 | GNUNET_SERVICE_stop (struct GNUNET_SERVICE_Context *sctx) | 2458 | GNUNET_SERVICE_client_disable_continue_warning (struct GNUNET_SERVICE_Client *c) |
1650 | { | 2459 | { |
1651 | unsigned int i; | 2460 | GNUNET_break (NULL != c->warn_task); |
2461 | if (NULL != c->warn_task) | ||
2462 | { | ||
2463 | GNUNET_SCHEDULER_cancel (c->warn_task); | ||
2464 | c->warn_task = NULL; | ||
2465 | } | ||
2466 | } | ||
1652 | 2467 | ||
1653 | #if HAVE_MALLINFO | 2468 | |
2469 | /** | ||
2470 | * Asynchronously finish dropping the client. | ||
2471 | * | ||
2472 | * @param cls the `struct GNUNET_SERVICE_Client`. | ||
2473 | */ | ||
2474 | static void | ||
2475 | finish_client_drop (void *cls) | ||
2476 | { | ||
2477 | struct GNUNET_SERVICE_Client *c = cls; | ||
2478 | struct GNUNET_SERVICE_Handle *sh = c->sh; | ||
2479 | |||
2480 | c->drop_task = NULL; | ||
2481 | GNUNET_assert (NULL == c->send_task); | ||
2482 | GNUNET_assert (NULL == c->recv_task); | ||
2483 | GNUNET_assert (NULL == c->warn_task); | ||
2484 | GNUNET_MST_destroy (c->mst); | ||
2485 | GNUNET_MQ_destroy (c->mq); | ||
2486 | if (GNUNET_NO == c->persist) | ||
1654 | { | 2487 | { |
1655 | char *counter; | 2488 | GNUNET_break (GNUNET_OK == |
2489 | GNUNET_NETWORK_socket_close (c->sock)); | ||
2490 | } | ||
2491 | else | ||
2492 | { | ||
2493 | GNUNET_NETWORK_socket_free_memory_only_ (c->sock); | ||
2494 | } | ||
2495 | GNUNET_free (c); | ||
2496 | if ( (GNUNET_YES == sh->got_shutdown) && | ||
2497 | (GNUNET_NO == have_non_monitor_clients (sh)) ) | ||
2498 | GNUNET_SERVICE_shutdown (sh); | ||
2499 | } | ||
1656 | 2500 | ||
1657 | if ( (GNUNET_YES == | ||
1658 | GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, | ||
1659 | "GAUGER_HEAP")) && | ||
1660 | (GNUNET_OK == | ||
1661 | GNUNET_CONFIGURATION_get_value_string (sctx->cfg, sctx->service_name, | ||
1662 | "GAUGER_HEAP", | ||
1663 | &counter)) ) | ||
1664 | { | ||
1665 | struct mallinfo mi; | ||
1666 | 2501 | ||
1667 | mi = mallinfo (); | 2502 | /** |
1668 | GAUGER (sctx->service_name, counter, mi.usmblks, "blocks"); | 2503 | * Ask the server to disconnect from the given client. This is the |
1669 | GNUNET_free (counter); | 2504 | * same as returning #GNUNET_SYSERR within the check procedure when |
1670 | } | 2505 | * handling a message, wexcept that it allows dropping of a client even |
2506 | * when not handling a message from that client. The `disconnect_cb` | ||
2507 | * will be called on @a c even if the application closes the connection | ||
2508 | * using this function. | ||
2509 | * | ||
2510 | * @param c client to disconnect now | ||
2511 | */ | ||
2512 | void | ||
2513 | GNUNET_SERVICE_client_drop (struct GNUNET_SERVICE_Client *c) | ||
2514 | { | ||
2515 | struct GNUNET_SERVICE_Handle *sh = c->sh; | ||
2516 | |||
2517 | if (NULL != c->drop_task) | ||
2518 | { | ||
2519 | /* asked to drop twice! */ | ||
2520 | GNUNET_assert (0); | ||
2521 | return; | ||
1671 | } | 2522 | } |
1672 | #endif | 2523 | GNUNET_CONTAINER_DLL_remove (sh->clients_head, |
1673 | if (NULL != sctx->shutdown_task) | 2524 | sh->clients_tail, |
2525 | c); | ||
2526 | if (NULL != sh->disconnect_cb) | ||
2527 | sh->disconnect_cb (sh->cb_cls, | ||
2528 | c, | ||
2529 | c->user_context); | ||
2530 | if (NULL != c->warn_task) | ||
1674 | { | 2531 | { |
1675 | GNUNET_SCHEDULER_cancel (sctx->shutdown_task); | 2532 | GNUNET_SCHEDULER_cancel (c->warn_task); |
1676 | sctx->shutdown_task = NULL; | 2533 | c->warn_task = NULL; |
1677 | } | 2534 | } |
1678 | if (NULL != sctx->server) | 2535 | if (NULL != c->recv_task) |
1679 | GNUNET_SERVER_destroy (sctx->server); | ||
1680 | GNUNET_free_non_null (sctx->my_handlers); | ||
1681 | if (NULL != sctx->addrs) | ||
1682 | { | 2536 | { |
1683 | i = 0; | 2537 | GNUNET_SCHEDULER_cancel (c->recv_task); |
1684 | while (NULL != sctx->addrs[i]) | 2538 | c->recv_task = NULL; |
1685 | GNUNET_free (sctx->addrs[i++]); | 2539 | } |
1686 | GNUNET_free (sctx->addrs); | 2540 | if (NULL != c->send_task) |
1687 | } | 2541 | { |
1688 | GNUNET_free_non_null (sctx->addrlens); | 2542 | GNUNET_SCHEDULER_cancel (c->send_task); |
1689 | GNUNET_free_non_null (sctx->v4_denied); | 2543 | c->send_task = NULL; |
1690 | GNUNET_free_non_null (sctx->v6_denied); | 2544 | } |
1691 | GNUNET_free_non_null (sctx->v4_allowed); | 2545 | c->drop_task = GNUNET_SCHEDULER_add_now (&finish_client_drop, |
1692 | GNUNET_free_non_null (sctx->v6_allowed); | 2546 | c); |
1693 | GNUNET_free (sctx); | 2547 | } |
2548 | |||
2549 | |||
2550 | /** | ||
2551 | * Explicitly stops the service. | ||
2552 | * | ||
2553 | * @param sh server to shutdown | ||
2554 | */ | ||
2555 | void | ||
2556 | GNUNET_SERVICE_shutdown (struct GNUNET_SERVICE_Handle *sh) | ||
2557 | { | ||
2558 | struct GNUNET_SERVICE_Client *client; | ||
2559 | |||
2560 | GNUNET_SERVICE_suspend (sh); | ||
2561 | sh->got_shutdown = GNUNET_NO; | ||
2562 | while (NULL != (client = sh->clients_head)) | ||
2563 | GNUNET_SERVICE_client_drop (client); | ||
2564 | } | ||
2565 | |||
2566 | |||
2567 | /** | ||
2568 | * Set the 'monitor' flag on this client. Clients which have been | ||
2569 | * marked as 'monitors' won't prevent the server from shutting down | ||
2570 | * once #GNUNET_SERVICE_stop_listening() has been invoked. The idea is | ||
2571 | * that for "normal" clients we likely want to allow them to process | ||
2572 | * their requests; however, monitor-clients are likely to 'never' | ||
2573 | * disconnect during shutdown and thus will not be considered when | ||
2574 | * determining if the server should continue to exist after | ||
2575 | * shutdown has been triggered. | ||
2576 | * | ||
2577 | * @param c client to mark as a monitor | ||
2578 | */ | ||
2579 | void | ||
2580 | GNUNET_SERVICE_client_mark_monitor (struct GNUNET_SERVICE_Client *c) | ||
2581 | { | ||
2582 | c->is_monitor = GNUNET_YES; | ||
2583 | if ( (GNUNET_YES == c->sh->got_shutdown) && | ||
2584 | (GNUNET_NO == have_non_monitor_clients (c->sh)) ) | ||
2585 | GNUNET_SERVICE_shutdown (c->sh); | ||
2586 | } | ||
2587 | |||
2588 | |||
2589 | /** | ||
2590 | * Set the persist option on this client. Indicates that the | ||
2591 | * underlying socket or fd should never really be closed. Used for | ||
2592 | * indicating process death. | ||
2593 | * | ||
2594 | * @param c client to persist the socket (never to be closed) | ||
2595 | */ | ||
2596 | void | ||
2597 | GNUNET_SERVICE_client_persist (struct GNUNET_SERVICE_Client *c) | ||
2598 | { | ||
2599 | c->persist = GNUNET_YES; | ||
2600 | } | ||
2601 | |||
2602 | |||
2603 | /** | ||
2604 | * Obtain the message queue of @a c. Convenience function. | ||
2605 | * | ||
2606 | * @param c the client to continue receiving from | ||
2607 | * @return the message queue of @a c | ||
2608 | */ | ||
2609 | struct GNUNET_MQ_Handle * | ||
2610 | GNUNET_SERVICE_client_get_mq (struct GNUNET_SERVICE_Client *c) | ||
2611 | { | ||
2612 | return c->mq; | ||
1694 | } | 2613 | } |
1695 | 2614 | ||
1696 | 2615 | ||
1697 | /* end of service.c */ | 2616 | /* end of service_new.c */ |
diff --git a/src/util/service_new.c b/src/util/service_new.c deleted file mode 100644 index 22eec0bde..000000000 --- a/src/util/service_new.c +++ /dev/null | |||
@@ -1,2615 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2016 GNUnet e.V. | ||
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., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file util/service_new.c | ||
23 | * @brief functions related to starting services (redesign) | ||
24 | * @author Christian Grothoff | ||
25 | * @author Florian Dold | ||
26 | */ | ||
27 | #include "platform.h" | ||
28 | #include "gnunet_util_lib.h" | ||
29 | #include "gnunet_protocols.h" | ||
30 | #include "gnunet_constants.h" | ||
31 | #include "gnunet_resolver_service.h" | ||
32 | #include "speedup.h" | ||
33 | |||
34 | #if HAVE_MALLINFO | ||
35 | #include <malloc.h> | ||
36 | #include "gauger.h" | ||
37 | #endif | ||
38 | |||
39 | |||
40 | #define LOG(kind,...) GNUNET_log_from (kind, "util-service", __VA_ARGS__) | ||
41 | |||
42 | #define LOG_STRERROR(kind,syscall) GNUNET_log_from_strerror (kind, "util-service", syscall) | ||
43 | |||
44 | #define LOG_STRERROR_FILE(kind,syscall,filename) GNUNET_log_from_strerror_file (kind, "util-service", syscall, filename) | ||
45 | |||
46 | |||
47 | /** | ||
48 | * Information the service tracks per listen operation. | ||
49 | */ | ||
50 | struct ServiceListenContext | ||
51 | { | ||
52 | |||
53 | /** | ||
54 | * Kept in a DLL. | ||
55 | */ | ||
56 | struct ServiceListenContext *next; | ||
57 | |||
58 | /** | ||
59 | * Kept in a DLL. | ||
60 | */ | ||
61 | struct ServiceListenContext *prev; | ||
62 | |||
63 | /** | ||
64 | * Service this listen context belongs to. | ||
65 | */ | ||
66 | struct GNUNET_SERVICE_Handle *sh; | ||
67 | |||
68 | /** | ||
69 | * Socket we are listening on. | ||
70 | */ | ||
71 | struct GNUNET_NETWORK_Handle *listen_socket; | ||
72 | |||
73 | /** | ||
74 | * Task scheduled to do the listening. | ||
75 | */ | ||
76 | struct GNUNET_SCHEDULER_Task *listen_task; | ||
77 | |||
78 | }; | ||
79 | |||
80 | |||
81 | /** | ||
82 | * Handle to a service. | ||
83 | */ | ||
84 | struct GNUNET_SERVICE_Handle | ||
85 | { | ||
86 | /** | ||
87 | * Our configuration. | ||
88 | */ | ||
89 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
90 | |||
91 | /** | ||
92 | * Name of our service. | ||
93 | */ | ||
94 | const char *service_name; | ||
95 | |||
96 | /** | ||
97 | * Main service-specific task to run. | ||
98 | */ | ||
99 | GNUNET_SERVICE_InitCallback service_init_cb; | ||
100 | |||
101 | /** | ||
102 | * Function to call when clients connect. | ||
103 | */ | ||
104 | GNUNET_SERVICE_ConnectHandler connect_cb; | ||
105 | |||
106 | /** | ||
107 | * Function to call when clients disconnect / are disconnected. | ||
108 | */ | ||
109 | GNUNET_SERVICE_DisconnectHandler disconnect_cb; | ||
110 | |||
111 | /** | ||
112 | * Closure for @e service_init_cb, @e connect_cb, @e disconnect_cb. | ||
113 | */ | ||
114 | void *cb_cls; | ||
115 | |||
116 | /** | ||
117 | * DLL of listen sockets used to accept new connections. | ||
118 | */ | ||
119 | struct ServiceListenContext *slc_head; | ||
120 | |||
121 | /** | ||
122 | * DLL of listen sockets used to accept new connections. | ||
123 | */ | ||
124 | struct ServiceListenContext *slc_tail; | ||
125 | |||
126 | /** | ||
127 | * Our clients, kept in a DLL. | ||
128 | */ | ||
129 | struct GNUNET_SERVICE_Client *clients_head; | ||
130 | |||
131 | /** | ||
132 | * Our clients, kept in a DLL. | ||
133 | */ | ||
134 | struct GNUNET_SERVICE_Client *clients_tail; | ||
135 | |||
136 | /** | ||
137 | * Message handlers to use for all clients. | ||
138 | */ | ||
139 | struct GNUNET_MQ_MessageHandler *handlers; | ||
140 | |||
141 | /** | ||
142 | * Closure for @e task. | ||
143 | */ | ||
144 | void *task_cls; | ||
145 | |||
146 | /** | ||
147 | * IPv4 addresses that are not allowed to connect. | ||
148 | */ | ||
149 | struct GNUNET_STRINGS_IPv4NetworkPolicy *v4_denied; | ||
150 | |||
151 | /** | ||
152 | * IPv6 addresses that are not allowed to connect. | ||
153 | */ | ||
154 | struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_denied; | ||
155 | |||
156 | /** | ||
157 | * IPv4 addresses that are allowed to connect (if not | ||
158 | * set, all are allowed). | ||
159 | */ | ||
160 | struct GNUNET_STRINGS_IPv4NetworkPolicy *v4_allowed; | ||
161 | |||
162 | /** | ||
163 | * IPv6 addresses that are allowed to connect (if not | ||
164 | * set, all are allowed). | ||
165 | */ | ||
166 | struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_allowed; | ||
167 | |||
168 | /** | ||
169 | * Do we require a matching UID for UNIX domain socket connections? | ||
170 | * #GNUNET_NO means that the UID does not have to match (however, | ||
171 | * @e match_gid may still impose other access control checks). | ||
172 | */ | ||
173 | int match_uid; | ||
174 | |||
175 | /** | ||
176 | * Do we require a matching GID for UNIX domain socket connections? | ||
177 | * Ignored if @e match_uid is #GNUNET_YES. Note that this is about | ||
178 | * checking that the client's UID is in our group OR that the | ||
179 | * client's GID is our GID. If both "match_gid" and @e match_uid are | ||
180 | * #GNUNET_NO, all users on the local system have access. | ||
181 | */ | ||
182 | int match_gid; | ||
183 | |||
184 | /** | ||
185 | * Set to #GNUNET_YES if we got a shutdown signal and terminate | ||
186 | * the service if #have_non_monitor_clients() returns #GNUNET_YES. | ||
187 | */ | ||
188 | int got_shutdown; | ||
189 | |||
190 | /** | ||
191 | * Our options. | ||
192 | */ | ||
193 | enum GNUNET_SERVICE_Options options; | ||
194 | |||
195 | /** | ||
196 | * If we are daemonizing, this FD is set to the | ||
197 | * pipe to the parent. Send '.' if we started | ||
198 | * ok, '!' if not. -1 if we are not daemonizing. | ||
199 | */ | ||
200 | int ready_confirm_fd; | ||
201 | |||
202 | /** | ||
203 | * Overall success/failure of the service start. | ||
204 | */ | ||
205 | int ret; | ||
206 | |||
207 | /** | ||
208 | * If #GNUNET_YES, consider unknown message types an error where the | ||
209 | * client is disconnected. | ||
210 | */ | ||
211 | int require_found; | ||
212 | }; | ||
213 | |||
214 | |||
215 | /** | ||
216 | * Handle to a client that is connected to a service. | ||
217 | */ | ||
218 | struct GNUNET_SERVICE_Client | ||
219 | { | ||
220 | |||
221 | /** | ||
222 | * Kept in a DLL. | ||
223 | */ | ||
224 | struct GNUNET_SERVICE_Client *next; | ||
225 | |||
226 | /** | ||
227 | * Kept in a DLL. | ||
228 | */ | ||
229 | struct GNUNET_SERVICE_Client *prev; | ||
230 | |||
231 | /** | ||
232 | * Service that this client belongs to. | ||
233 | */ | ||
234 | struct GNUNET_SERVICE_Handle *sh; | ||
235 | |||
236 | /** | ||
237 | * Socket of this client. | ||
238 | */ | ||
239 | struct GNUNET_NETWORK_Handle *sock; | ||
240 | |||
241 | /** | ||
242 | * Message queue for the client. | ||
243 | */ | ||
244 | struct GNUNET_MQ_Handle *mq; | ||
245 | |||
246 | /** | ||
247 | * Tokenizer we use for processing incoming data. | ||
248 | */ | ||
249 | struct GNUNET_MessageStreamTokenizer *mst; | ||
250 | |||
251 | /** | ||
252 | * Task that warns about missing calls to | ||
253 | * #GNUNET_SERVICE_client_continue(). | ||
254 | */ | ||
255 | struct GNUNET_SCHEDULER_Task *warn_task; | ||
256 | |||
257 | /** | ||
258 | * Task run to finish dropping the client after the stack has | ||
259 | * properly unwound. | ||
260 | */ | ||
261 | struct GNUNET_SCHEDULER_Task *drop_task; | ||
262 | |||
263 | /** | ||
264 | * Task that receives data from the client to | ||
265 | * pass it to the handlers. | ||
266 | */ | ||
267 | struct GNUNET_SCHEDULER_Task *recv_task; | ||
268 | |||
269 | /** | ||
270 | * Task that transmit data to the client. | ||
271 | */ | ||
272 | struct GNUNET_SCHEDULER_Task *send_task; | ||
273 | |||
274 | /** | ||
275 | * Pointer to the message to be transmitted by @e send_task. | ||
276 | */ | ||
277 | const struct GNUNET_MessageHeader *msg; | ||
278 | |||
279 | /** | ||
280 | * User context value, value returned from | ||
281 | * the connect callback. | ||
282 | */ | ||
283 | void *user_context; | ||
284 | |||
285 | /** | ||
286 | * Time when we last gave a message from this client | ||
287 | * to the application. | ||
288 | */ | ||
289 | struct GNUNET_TIME_Absolute warn_start; | ||
290 | |||
291 | /** | ||
292 | * Current position in @e msg at which we are transmitting. | ||
293 | */ | ||
294 | size_t msg_pos; | ||
295 | |||
296 | /** | ||
297 | * Persist the file handle for this client no matter what happens, | ||
298 | * force the OS to close once the process actually dies. Should only | ||
299 | * be used in special cases! | ||
300 | */ | ||
301 | int persist; | ||
302 | |||
303 | /** | ||
304 | * Is this client a 'monitor' client that should not be counted | ||
305 | * when deciding on destroying the server during soft shutdown? | ||
306 | * (see also #GNUNET_SERVICE_start) | ||
307 | */ | ||
308 | int is_monitor; | ||
309 | |||
310 | /** | ||
311 | * Are we waiting for the application to call #GNUNET_SERVICE_client_continue()? | ||
312 | */ | ||
313 | int needs_continue; | ||
314 | |||
315 | /** | ||
316 | * Type of last message processed (for warn_no_receive_done). | ||
317 | */ | ||
318 | uint16_t warn_type; | ||
319 | }; | ||
320 | |||
321 | |||
322 | /** | ||
323 | * Check if any of the clients we have left are unrelated to | ||
324 | * monitoring. | ||
325 | * | ||
326 | * @param sh service to check clients for | ||
327 | * @return #GNUNET_YES if we have non-monitoring clients left | ||
328 | */ | ||
329 | static int | ||
330 | have_non_monitor_clients (struct GNUNET_SERVICE_Handle *sh) | ||
331 | { | ||
332 | struct GNUNET_SERVICE_Client *client; | ||
333 | |||
334 | for (client = sh->clients_head;NULL != client; client = client->next) | ||
335 | { | ||
336 | if (client->is_monitor) | ||
337 | continue; | ||
338 | return GNUNET_YES; | ||
339 | } | ||
340 | return GNUNET_NO; | ||
341 | } | ||
342 | |||
343 | |||
344 | /** | ||
345 | * Shutdown task triggered when a service should be terminated. | ||
346 | * This considers active clients and the service options to see | ||
347 | * how this specific service is to be terminated, and depending | ||
348 | * on this proceeds with the shutdown logic. | ||
349 | * | ||
350 | * @param cls our `struct GNUNET_SERVICE_Handle` | ||
351 | */ | ||
352 | static void | ||
353 | service_shutdown (void *cls) | ||
354 | { | ||
355 | struct GNUNET_SERVICE_Handle *sh = cls; | ||
356 | |||
357 | switch (sh->options) | ||
358 | { | ||
359 | case GNUNET_SERVICE_OPTION_NONE: | ||
360 | GNUNET_SERVICE_shutdown (sh); | ||
361 | break; | ||
362 | case GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN: | ||
363 | /* This task should never be run if we are using | ||
364 | the manual shutdown. */ | ||
365 | GNUNET_assert (0); | ||
366 | break; | ||
367 | case GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN: | ||
368 | sh->got_shutdown = GNUNET_YES; | ||
369 | GNUNET_SERVICE_suspend (sh); | ||
370 | if (GNUNET_NO == have_non_monitor_clients (sh)) | ||
371 | GNUNET_SERVICE_shutdown (sh); | ||
372 | break; | ||
373 | } | ||
374 | } | ||
375 | |||
376 | |||
377 | /** | ||
378 | * First task run by any service. Initializes our shutdown task, | ||
379 | * starts the listening operation on our listen sockets and launches | ||
380 | * the custom logic of the application service. | ||
381 | * | ||
382 | * @param cls our `struct GNUNET_SERVICE_Handle` | ||
383 | */ | ||
384 | static void | ||
385 | service_main (void *cls) | ||
386 | { | ||
387 | struct GNUNET_SERVICE_Handle *sh = cls; | ||
388 | |||
389 | if (GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN != sh->options) | ||
390 | GNUNET_SCHEDULER_add_shutdown (&service_shutdown, | ||
391 | sh); | ||
392 | GNUNET_SERVICE_resume (sh); | ||
393 | |||
394 | if (-1 != sh->ready_confirm_fd) | ||
395 | { | ||
396 | GNUNET_break (1 == WRITE (sh->ready_confirm_fd, ".", 1)); | ||
397 | GNUNET_break (0 == CLOSE (sh->ready_confirm_fd)); | ||
398 | sh->ready_confirm_fd = -1; | ||
399 | } | ||
400 | |||
401 | if (NULL != sh->service_init_cb) | ||
402 | sh->service_init_cb (sh->cb_cls, | ||
403 | sh->cfg, | ||
404 | sh); | ||
405 | } | ||
406 | |||
407 | |||
408 | /** | ||
409 | * Parse an IPv4 access control list. | ||
410 | * | ||
411 | * @param ret location where to write the ACL (set) | ||
412 | * @param sh service context to use to get the configuration | ||
413 | * @param option name of the ACL option to parse | ||
414 | * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including | ||
415 | * no ACL configured) | ||
416 | */ | ||
417 | static int | ||
418 | process_acl4 (struct GNUNET_STRINGS_IPv4NetworkPolicy **ret, | ||
419 | struct GNUNET_SERVICE_Handle *sh, | ||
420 | const char *option) | ||
421 | { | ||
422 | char *opt; | ||
423 | |||
424 | if (! GNUNET_CONFIGURATION_have_value (sh->cfg, | ||
425 | sh->service_name, | ||
426 | option)) | ||
427 | { | ||
428 | *ret = NULL; | ||
429 | return GNUNET_OK; | ||
430 | } | ||
431 | GNUNET_break (GNUNET_OK == | ||
432 | GNUNET_CONFIGURATION_get_value_string (sh->cfg, | ||
433 | sh->service_name, | ||
434 | option, | ||
435 | &opt)); | ||
436 | if (NULL == (*ret = GNUNET_STRINGS_parse_ipv4_policy (opt))) | ||
437 | { | ||
438 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
439 | _("Could not parse IPv4 network specification `%s' for `%s:%s'\n"), | ||
440 | opt, | ||
441 | sh->service_name, | ||
442 | option); | ||
443 | GNUNET_free (opt); | ||
444 | return GNUNET_SYSERR; | ||
445 | } | ||
446 | GNUNET_free (opt); | ||
447 | return GNUNET_OK; | ||
448 | } | ||
449 | |||
450 | |||
451 | /** | ||
452 | * Parse an IPv6 access control list. | ||
453 | * | ||
454 | * @param ret location where to write the ACL (set) | ||
455 | * @param sh service context to use to get the configuration | ||
456 | * @param option name of the ACL option to parse | ||
457 | * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including | ||
458 | * no ACL configured) | ||
459 | */ | ||
460 | static int | ||
461 | process_acl6 (struct GNUNET_STRINGS_IPv6NetworkPolicy **ret, | ||
462 | struct GNUNET_SERVICE_Handle *sh, | ||
463 | const char *option) | ||
464 | { | ||
465 | char *opt; | ||
466 | |||
467 | if (! GNUNET_CONFIGURATION_have_value (sh->cfg, | ||
468 | sh->service_name, | ||
469 | option)) | ||
470 | { | ||
471 | *ret = NULL; | ||
472 | return GNUNET_OK; | ||
473 | } | ||
474 | GNUNET_break (GNUNET_OK == | ||
475 | GNUNET_CONFIGURATION_get_value_string (sh->cfg, | ||
476 | sh->service_name, | ||
477 | option, | ||
478 | &opt)); | ||
479 | if (NULL == (*ret = GNUNET_STRINGS_parse_ipv6_policy (opt))) | ||
480 | { | ||
481 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
482 | _("Could not parse IPv6 network specification `%s' for `%s:%s'\n"), | ||
483 | opt, | ||
484 | sh->service_name, | ||
485 | option); | ||
486 | GNUNET_free (opt); | ||
487 | return GNUNET_SYSERR; | ||
488 | } | ||
489 | GNUNET_free (opt); | ||
490 | return GNUNET_OK; | ||
491 | } | ||
492 | |||
493 | |||
494 | /** | ||
495 | * Add the given UNIX domain path as an address to the | ||
496 | * list (as the first entry). | ||
497 | * | ||
498 | * @param saddrs array to update | ||
499 | * @param saddrlens where to store the address length | ||
500 | * @param unixpath path to add | ||
501 | * @param abstract #GNUNET_YES to add an abstract UNIX domain socket. This | ||
502 | * parameter is ignore on systems other than LINUX | ||
503 | */ | ||
504 | static void | ||
505 | add_unixpath (struct sockaddr **saddrs, | ||
506 | socklen_t *saddrlens, | ||
507 | const char *unixpath, | ||
508 | int abstract) | ||
509 | { | ||
510 | #ifdef AF_UNIX | ||
511 | struct sockaddr_un *un; | ||
512 | |||
513 | un = GNUNET_new (struct sockaddr_un); | ||
514 | un->sun_family = AF_UNIX; | ||
515 | strncpy (un->sun_path, | ||
516 | unixpath, | ||
517 | sizeof (un->sun_path) - 1); | ||
518 | #ifdef LINUX | ||
519 | if (GNUNET_YES == abstract) | ||
520 | un->sun_path[0] = '\0'; | ||
521 | #endif | ||
522 | #if HAVE_SOCKADDR_UN_SUN_LEN | ||
523 | un->sun_len = (u_char) sizeof (struct sockaddr_un); | ||
524 | #endif | ||
525 | *saddrs = (struct sockaddr *) un; | ||
526 | *saddrlens = sizeof (struct sockaddr_un); | ||
527 | #else | ||
528 | /* this function should never be called | ||
529 | * unless AF_UNIX is defined! */ | ||
530 | GNUNET_assert (0); | ||
531 | #endif | ||
532 | } | ||
533 | |||
534 | |||
535 | /** | ||
536 | * Get the list of addresses that a server for the given service | ||
537 | * should bind to. | ||
538 | * | ||
539 | * @param service_name name of the service | ||
540 | * @param cfg configuration (which specifies the addresses) | ||
541 | * @param addrs set (call by reference) to an array of pointers to the | ||
542 | * addresses the server should bind to and listen on; the | ||
543 | * array will be NULL-terminated (on success) | ||
544 | * @param addr_lens set (call by reference) to an array of the lengths | ||
545 | * of the respective `struct sockaddr` struct in the @a addrs | ||
546 | * array (on success) | ||
547 | * @return number of addresses found on success, | ||
548 | * #GNUNET_SYSERR if the configuration | ||
549 | * did not specify reasonable finding information or | ||
550 | * if it specified a hostname that could not be resolved; | ||
551 | * #GNUNET_NO if the number of addresses configured is | ||
552 | * zero (in this case, `*addrs` and `*addr_lens` will be | ||
553 | * set to NULL). | ||
554 | */ | ||
555 | static int | ||
556 | get_server_addresses (const char *service_name, | ||
557 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
558 | struct sockaddr ***addrs, | ||
559 | socklen_t **addr_lens) | ||
560 | { | ||
561 | int disablev6; | ||
562 | struct GNUNET_NETWORK_Handle *desc; | ||
563 | unsigned long long port; | ||
564 | char *unixpath; | ||
565 | struct addrinfo hints; | ||
566 | struct addrinfo *res; | ||
567 | struct addrinfo *pos; | ||
568 | struct addrinfo *next; | ||
569 | unsigned int i; | ||
570 | int resi; | ||
571 | int ret; | ||
572 | int abstract; | ||
573 | struct sockaddr **saddrs; | ||
574 | socklen_t *saddrlens; | ||
575 | char *hostname; | ||
576 | |||
577 | *addrs = NULL; | ||
578 | *addr_lens = NULL; | ||
579 | desc = NULL; | ||
580 | if (GNUNET_CONFIGURATION_have_value (cfg, | ||
581 | service_name, | ||
582 | "DISABLEV6")) | ||
583 | { | ||
584 | if (GNUNET_SYSERR == | ||
585 | (disablev6 = | ||
586 | GNUNET_CONFIGURATION_get_value_yesno (cfg, | ||
587 | service_name, | ||
588 | "DISABLEV6"))) | ||
589 | return GNUNET_SYSERR; | ||
590 | } | ||
591 | else | ||
592 | disablev6 = GNUNET_NO; | ||
593 | |||
594 | if (! disablev6) | ||
595 | { | ||
596 | /* probe IPv6 support */ | ||
597 | desc = GNUNET_NETWORK_socket_create (PF_INET6, | ||
598 | SOCK_STREAM, | ||
599 | 0); | ||
600 | if (NULL == desc) | ||
601 | { | ||
602 | if ( (ENOBUFS == errno) || | ||
603 | (ENOMEM == errno) || | ||
604 | (ENFILE == errno) || | ||
605 | (EACCES == errno) ) | ||
606 | { | ||
607 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, | ||
608 | "socket"); | ||
609 | return GNUNET_SYSERR; | ||
610 | } | ||
611 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
612 | _("Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"), | ||
613 | service_name, | ||
614 | STRERROR (errno)); | ||
615 | disablev6 = GNUNET_YES; | ||
616 | } | ||
617 | else | ||
618 | { | ||
619 | GNUNET_break (GNUNET_OK == | ||
620 | GNUNET_NETWORK_socket_close (desc)); | ||
621 | desc = NULL; | ||
622 | } | ||
623 | } | ||
624 | |||
625 | port = 0; | ||
626 | if (GNUNET_CONFIGURATION_have_value (cfg, | ||
627 | service_name, | ||
628 | "PORT")) | ||
629 | { | ||
630 | if (GNUNET_OK != | ||
631 | GNUNET_CONFIGURATION_get_value_number (cfg, | ||
632 | service_name, | ||
633 | "PORT", | ||
634 | &port)) | ||
635 | { | ||
636 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
637 | _("Require valid port number for service `%s' in configuration!\n"), | ||
638 | service_name); | ||
639 | } | ||
640 | if (port > 65535) | ||
641 | { | ||
642 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
643 | _("Require valid port number for service `%s' in configuration!\n"), | ||
644 | service_name); | ||
645 | return GNUNET_SYSERR; | ||
646 | } | ||
647 | } | ||
648 | |||
649 | if (GNUNET_CONFIGURATION_have_value (cfg, | ||
650 | service_name, | ||
651 | "BINDTO")) | ||
652 | { | ||
653 | GNUNET_break (GNUNET_OK == | ||
654 | GNUNET_CONFIGURATION_get_value_string (cfg, | ||
655 | service_name, | ||
656 | "BINDTO", | ||
657 | &hostname)); | ||
658 | } | ||
659 | else | ||
660 | hostname = NULL; | ||
661 | |||
662 | unixpath = NULL; | ||
663 | abstract = GNUNET_NO; | ||
664 | #ifdef AF_UNIX | ||
665 | if ((GNUNET_YES == | ||
666 | GNUNET_CONFIGURATION_have_value (cfg, | ||
667 | service_name, | ||
668 | "UNIXPATH")) && | ||
669 | (GNUNET_OK == | ||
670 | GNUNET_CONFIGURATION_get_value_filename (cfg, | ||
671 | service_name, | ||
672 | "UNIXPATH", | ||
673 | &unixpath)) && | ||
674 | (0 < strlen (unixpath))) | ||
675 | { | ||
676 | /* probe UNIX support */ | ||
677 | struct sockaddr_un s_un; | ||
678 | |||
679 | if (strlen (unixpath) >= sizeof (s_un.sun_path)) | ||
680 | { | ||
681 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
682 | _("UNIXPATH `%s' too long, maximum length is %llu\n"), | ||
683 | unixpath, | ||
684 | (unsigned long long) sizeof (s_un.sun_path)); | ||
685 | unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath); | ||
686 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
687 | _("Using `%s' instead\n"), | ||
688 | unixpath); | ||
689 | } | ||
690 | #ifdef LINUX | ||
691 | abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg, | ||
692 | "TESTING", | ||
693 | "USE_ABSTRACT_SOCKETS"); | ||
694 | if (GNUNET_SYSERR == abstract) | ||
695 | abstract = GNUNET_NO; | ||
696 | #endif | ||
697 | if ( (GNUNET_YES != abstract) && | ||
698 | (GNUNET_OK != | ||
699 | GNUNET_DISK_directory_create_for_file (unixpath)) ) | ||
700 | GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, | ||
701 | "mkdir", | ||
702 | unixpath); | ||
703 | } | ||
704 | if (NULL != unixpath) | ||
705 | { | ||
706 | desc = GNUNET_NETWORK_socket_create (AF_UNIX, | ||
707 | SOCK_STREAM, | ||
708 | 0); | ||
709 | if (NULL == desc) | ||
710 | { | ||
711 | if ((ENOBUFS == errno) || | ||
712 | (ENOMEM == errno) || | ||
713 | (ENFILE == errno) || | ||
714 | (EACCES == errno)) | ||
715 | { | ||
716 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, | ||
717 | "socket"); | ||
718 | GNUNET_free_non_null (hostname); | ||
719 | GNUNET_free (unixpath); | ||
720 | return GNUNET_SYSERR; | ||
721 | } | ||
722 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
723 | _("Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"), | ||
724 | service_name, | ||
725 | STRERROR (errno)); | ||
726 | GNUNET_free (unixpath); | ||
727 | unixpath = NULL; | ||
728 | } | ||
729 | else | ||
730 | { | ||
731 | GNUNET_break (GNUNET_OK == | ||
732 | GNUNET_NETWORK_socket_close (desc)); | ||
733 | desc = NULL; | ||
734 | } | ||
735 | } | ||
736 | #endif | ||
737 | |||
738 | if ((0 == port) && (NULL == unixpath)) | ||
739 | { | ||
740 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
741 | _("Have neither PORT nor UNIXPATH for service `%s', but one is required\n"), | ||
742 | service_name); | ||
743 | GNUNET_free_non_null (hostname); | ||
744 | return GNUNET_SYSERR; | ||
745 | } | ||
746 | if (0 == port) | ||
747 | { | ||
748 | saddrs = GNUNET_new_array (2, | ||
749 | struct sockaddr *); | ||
750 | saddrlens = GNUNET_new_array (2, | ||
751 | socklen_t); | ||
752 | add_unixpath (saddrs, | ||
753 | saddrlens, | ||
754 | unixpath, | ||
755 | abstract); | ||
756 | GNUNET_free_non_null (unixpath); | ||
757 | GNUNET_free_non_null (hostname); | ||
758 | *addrs = saddrs; | ||
759 | *addr_lens = saddrlens; | ||
760 | return 1; | ||
761 | } | ||
762 | |||
763 | if (NULL != hostname) | ||
764 | { | ||
765 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
766 | "Resolving `%s' since that is where `%s' will bind to.\n", | ||
767 | hostname, | ||
768 | service_name); | ||
769 | memset (&hints, | ||
770 | 0, | ||
771 | sizeof (struct addrinfo)); | ||
772 | if (disablev6) | ||
773 | hints.ai_family = AF_INET; | ||
774 | hints.ai_protocol = IPPROTO_TCP; | ||
775 | if ((0 != (ret = getaddrinfo (hostname, | ||
776 | NULL, | ||
777 | &hints, | ||
778 | &res))) || | ||
779 | (NULL == res)) | ||
780 | { | ||
781 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
782 | _("Failed to resolve `%s': %s\n"), | ||
783 | hostname, | ||
784 | gai_strerror (ret)); | ||
785 | GNUNET_free (hostname); | ||
786 | GNUNET_free_non_null (unixpath); | ||
787 | return GNUNET_SYSERR; | ||
788 | } | ||
789 | next = res; | ||
790 | i = 0; | ||
791 | while (NULL != (pos = next)) | ||
792 | { | ||
793 | next = pos->ai_next; | ||
794 | if ( (disablev6) && | ||
795 | (pos->ai_family == AF_INET6) ) | ||
796 | continue; | ||
797 | i++; | ||
798 | } | ||
799 | if (0 == i) | ||
800 | { | ||
801 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
802 | _("Failed to find %saddress for `%s'.\n"), | ||
803 | disablev6 ? "IPv4 " : "", | ||
804 | hostname); | ||
805 | freeaddrinfo (res); | ||
806 | GNUNET_free (hostname); | ||
807 | GNUNET_free_non_null (unixpath); | ||
808 | return GNUNET_SYSERR; | ||
809 | } | ||
810 | resi = i; | ||
811 | if (NULL != unixpath) | ||
812 | resi++; | ||
813 | saddrs = GNUNET_new_array (resi + 1, | ||
814 | struct sockaddr *); | ||
815 | saddrlens = GNUNET_new_array (resi + 1, | ||
816 | socklen_t); | ||
817 | i = 0; | ||
818 | if (NULL != unixpath) | ||
819 | { | ||
820 | add_unixpath (saddrs, | ||
821 | saddrlens, | ||
822 | unixpath, | ||
823 | abstract); | ||
824 | i++; | ||
825 | } | ||
826 | next = res; | ||
827 | while (NULL != (pos = next)) | ||
828 | { | ||
829 | next = pos->ai_next; | ||
830 | if ( (disablev6) && | ||
831 | (AF_INET6 == pos->ai_family) ) | ||
832 | continue; | ||
833 | if ( (IPPROTO_TCP != pos->ai_protocol) && | ||
834 | (0 != pos->ai_protocol) ) | ||
835 | continue; /* not TCP */ | ||
836 | if ( (SOCK_STREAM != pos->ai_socktype) && | ||
837 | (0 != pos->ai_socktype) ) | ||
838 | continue; /* huh? */ | ||
839 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
840 | "Service `%s' will bind to `%s'\n", | ||
841 | service_name, | ||
842 | GNUNET_a2s (pos->ai_addr, | ||
843 | pos->ai_addrlen)); | ||
844 | if (AF_INET == pos->ai_family) | ||
845 | { | ||
846 | GNUNET_assert (sizeof (struct sockaddr_in) == pos->ai_addrlen); | ||
847 | saddrlens[i] = pos->ai_addrlen; | ||
848 | saddrs[i] = GNUNET_malloc (saddrlens[i]); | ||
849 | GNUNET_memcpy (saddrs[i], | ||
850 | pos->ai_addr, | ||
851 | saddrlens[i]); | ||
852 | ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port); | ||
853 | } | ||
854 | else | ||
855 | { | ||
856 | GNUNET_assert (AF_INET6 == pos->ai_family); | ||
857 | GNUNET_assert (sizeof (struct sockaddr_in6) == pos->ai_addrlen); | ||
858 | saddrlens[i] = pos->ai_addrlen; | ||
859 | saddrs[i] = GNUNET_malloc (saddrlens[i]); | ||
860 | GNUNET_memcpy (saddrs[i], | ||
861 | pos->ai_addr, | ||
862 | saddrlens[i]); | ||
863 | ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port); | ||
864 | } | ||
865 | i++; | ||
866 | } | ||
867 | GNUNET_free (hostname); | ||
868 | freeaddrinfo (res); | ||
869 | resi = i; | ||
870 | } | ||
871 | else | ||
872 | { | ||
873 | /* will bind against everything, just set port */ | ||
874 | if (disablev6) | ||
875 | { | ||
876 | /* V4-only */ | ||
877 | resi = 1; | ||
878 | if (NULL != unixpath) | ||
879 | resi++; | ||
880 | i = 0; | ||
881 | saddrs = GNUNET_new_array (resi + 1, | ||
882 | struct sockaddr *); | ||
883 | saddrlens = GNUNET_new_array (resi + 1, | ||
884 | socklen_t); | ||
885 | if (NULL != unixpath) | ||
886 | { | ||
887 | add_unixpath (saddrs, | ||
888 | saddrlens, | ||
889 | unixpath, | ||
890 | abstract); | ||
891 | i++; | ||
892 | } | ||
893 | saddrlens[i] = sizeof (struct sockaddr_in); | ||
894 | saddrs[i] = GNUNET_malloc (saddrlens[i]); | ||
895 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
896 | ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i]; | ||
897 | #endif | ||
898 | ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET; | ||
899 | ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port); | ||
900 | } | ||
901 | else | ||
902 | { | ||
903 | /* dual stack */ | ||
904 | resi = 2; | ||
905 | if (NULL != unixpath) | ||
906 | resi++; | ||
907 | saddrs = GNUNET_new_array (resi + 1, | ||
908 | struct sockaddr *); | ||
909 | saddrlens = GNUNET_new_array (resi + 1, | ||
910 | socklen_t); | ||
911 | i = 0; | ||
912 | if (NULL != unixpath) | ||
913 | { | ||
914 | add_unixpath (saddrs, | ||
915 | saddrlens, | ||
916 | unixpath, | ||
917 | abstract); | ||
918 | i++; | ||
919 | } | ||
920 | saddrlens[i] = sizeof (struct sockaddr_in6); | ||
921 | saddrs[i] = GNUNET_malloc (saddrlens[i]); | ||
922 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
923 | ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0]; | ||
924 | #endif | ||
925 | ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6; | ||
926 | ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port); | ||
927 | i++; | ||
928 | saddrlens[i] = sizeof (struct sockaddr_in); | ||
929 | saddrs[i] = GNUNET_malloc (saddrlens[i]); | ||
930 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
931 | ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1]; | ||
932 | #endif | ||
933 | ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET; | ||
934 | ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port); | ||
935 | } | ||
936 | } | ||
937 | GNUNET_free_non_null (unixpath); | ||
938 | *addrs = saddrs; | ||
939 | *addr_lens = saddrlens; | ||
940 | return resi; | ||
941 | } | ||
942 | |||
943 | |||
944 | #ifdef MINGW | ||
945 | /** | ||
946 | * Read listen sockets from the parent process (ARM). | ||
947 | * | ||
948 | * @param sh service context to initialize | ||
949 | * @return NULL-terminated array of sockets on success, | ||
950 | * NULL if not ok (must bind yourself) | ||
951 | */ | ||
952 | static struct GNUNET_NETWORK_Handle ** | ||
953 | receive_sockets_from_parent (struct GNUNET_SERVICE_Handle *sh) | ||
954 | { | ||
955 | static struct GNUNET_NETWORK_Handle **lsocks; | ||
956 | const char *env_buf; | ||
957 | int fail; | ||
958 | uint64_t count; | ||
959 | uint64_t i; | ||
960 | HANDLE lsocks_pipe; | ||
961 | |||
962 | env_buf = getenv ("GNUNET_OS_READ_LSOCKS"); | ||
963 | if ( (NULL == env_buf) || | ||
964 | (strlen (env_buf) <= 0) ) | ||
965 | return NULL; | ||
966 | /* Using W32 API directly here, because this pipe will | ||
967 | * never be used outside of this function, and it's just too much of a bother | ||
968 | * to create a GNUnet API that boxes a HANDLE (the way it is done with socks) | ||
969 | */ | ||
970 | lsocks_pipe = (HANDLE) strtoul (env_buf, | ||
971 | NULL, | ||
972 | 10); | ||
973 | if ( (0 == lsocks_pipe) || | ||
974 | (INVALID_HANDLE_VALUE == lsocks_pipe)) | ||
975 | return NULL; | ||
976 | fail = 1; | ||
977 | do | ||
978 | { | ||
979 | int ret; | ||
980 | int fail2; | ||
981 | DWORD rd; | ||
982 | |||
983 | ret = ReadFile (lsocks_pipe, | ||
984 | &count, | ||
985 | sizeof (count), | ||
986 | &rd, | ||
987 | NULL); | ||
988 | if ( (0 == ret) || | ||
989 | (sizeof (count) != rd) || | ||
990 | (0 == count) ) | ||
991 | break; | ||
992 | lsocks = GNUNET_new_array (count + 1, | ||
993 | struct GNUNET_NETWORK_Handle *); | ||
994 | |||
995 | fail2 = 1; | ||
996 | for (i = 0; i < count; i++) | ||
997 | { | ||
998 | WSAPROTOCOL_INFOA pi; | ||
999 | uint64_t size; | ||
1000 | SOCKET s; | ||
1001 | |||
1002 | ret = ReadFile (lsocks_pipe, | ||
1003 | &size, | ||
1004 | sizeof (size), | ||
1005 | &rd, | ||
1006 | NULL); | ||
1007 | if ( (0 == ret) || | ||
1008 | (sizeof (size) != rd) || | ||
1009 | (sizeof (pi) != size) ) | ||
1010 | break; | ||
1011 | ret = ReadFile (lsocks_pipe, | ||
1012 | &pi, | ||
1013 | sizeof (pi), | ||
1014 | &rd, | ||
1015 | NULL); | ||
1016 | if ( (0 == ret) || | ||
1017 | (sizeof (pi) != rd)) | ||
1018 | break; | ||
1019 | s = WSASocketA (pi.iAddressFamily, | ||
1020 | pi.iSocketType, | ||
1021 | pi.iProtocol, | ||
1022 | &pi, | ||
1023 | 0, | ||
1024 | WSA_FLAG_OVERLAPPED); | ||
1025 | lsocks[i] = GNUNET_NETWORK_socket_box_native (s); | ||
1026 | if (NULL == lsocks[i]) | ||
1027 | break; | ||
1028 | else if (i == count - 1) | ||
1029 | fail2 = 0; | ||
1030 | } | ||
1031 | if (fail2) | ||
1032 | break; | ||
1033 | lsocks[count] = NULL; | ||
1034 | fail = 0; | ||
1035 | } | ||
1036 | while (fail); | ||
1037 | CloseHandle (lsocks_pipe); | ||
1038 | |||
1039 | if (fail) | ||
1040 | { | ||
1041 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1042 | _("Could not access a pre-bound socket, will try to bind myself\n")); | ||
1043 | for (i = 0; (i < count) && (NULL != lsocks[i]); i++) | ||
1044 | GNUNET_break (GNUNET_OK == | ||
1045 | GNUNET_NETWORK_socket_close (lsocks[i])); | ||
1046 | GNUNET_free (lsocks); | ||
1047 | return NULL; | ||
1048 | } | ||
1049 | return lsocks; | ||
1050 | } | ||
1051 | #endif | ||
1052 | |||
1053 | |||
1054 | /** | ||
1055 | * Create and initialize a listen socket for the server. | ||
1056 | * | ||
1057 | * @param server_addr address to listen on | ||
1058 | * @param socklen length of @a server_addr | ||
1059 | * @return NULL on error, otherwise the listen socket | ||
1060 | */ | ||
1061 | static struct GNUNET_NETWORK_Handle * | ||
1062 | open_listen_socket (const struct sockaddr *server_addr, | ||
1063 | socklen_t socklen) | ||
1064 | { | ||
1065 | struct GNUNET_NETWORK_Handle *sock; | ||
1066 | uint16_t port; | ||
1067 | int eno; | ||
1068 | |||
1069 | switch (server_addr->sa_family) | ||
1070 | { | ||
1071 | case AF_INET: | ||
1072 | port = ntohs (((const struct sockaddr_in *) server_addr)->sin_port); | ||
1073 | break; | ||
1074 | case AF_INET6: | ||
1075 | port = ntohs (((const struct sockaddr_in6 *) server_addr)->sin6_port); | ||
1076 | break; | ||
1077 | case AF_UNIX: | ||
1078 | port = 0; | ||
1079 | break; | ||
1080 | default: | ||
1081 | GNUNET_break (0); | ||
1082 | port = 0; | ||
1083 | break; | ||
1084 | } | ||
1085 | sock = GNUNET_NETWORK_socket_create (server_addr->sa_family, | ||
1086 | SOCK_STREAM, | ||
1087 | 0); | ||
1088 | if (NULL == sock) | ||
1089 | { | ||
1090 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, | ||
1091 | "socket"); | ||
1092 | errno = 0; | ||
1093 | return NULL; | ||
1094 | } | ||
1095 | /* bind the socket */ | ||
1096 | if (GNUNET_OK != GNUNET_NETWORK_socket_bind (sock, | ||
1097 | server_addr, | ||
1098 | socklen)) | ||
1099 | { | ||
1100 | eno = errno; | ||
1101 | if (EADDRINUSE != errno) | ||
1102 | { | ||
1103 | /* we don't log 'EADDRINUSE' here since an IPv4 bind may | ||
1104 | * fail if we already took the port on IPv6; if both IPv4 and | ||
1105 | * IPv6 binds fail, then our caller will log using the | ||
1106 | * errno preserved in 'eno' */ | ||
1107 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, | ||
1108 | "bind"); | ||
1109 | if (0 != port) | ||
1110 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1111 | _("`%s' failed for port %d (%s).\n"), | ||
1112 | "bind", | ||
1113 | port, | ||
1114 | (AF_INET == server_addr->sa_family) ? "IPv4" : "IPv6"); | ||
1115 | eno = 0; | ||
1116 | } | ||
1117 | else | ||
1118 | { | ||
1119 | if (0 != port) | ||
1120 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
1121 | _("`%s' failed for port %d (%s): address already in use\n"), | ||
1122 | "bind", port, | ||
1123 | (AF_INET == server_addr->sa_family) ? "IPv4" : "IPv6"); | ||
1124 | else if (AF_UNIX == server_addr->sa_family) | ||
1125 | { | ||
1126 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
1127 | _("`%s' failed for `%s': address already in use\n"), | ||
1128 | "bind", | ||
1129 | GNUNET_a2s (server_addr, socklen)); | ||
1130 | } | ||
1131 | } | ||
1132 | GNUNET_break (GNUNET_OK == | ||
1133 | GNUNET_NETWORK_socket_close (sock)); | ||
1134 | errno = eno; | ||
1135 | return NULL; | ||
1136 | } | ||
1137 | if (GNUNET_OK != GNUNET_NETWORK_socket_listen (sock, | ||
1138 | 5)) | ||
1139 | { | ||
1140 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, | ||
1141 | "listen"); | ||
1142 | GNUNET_break (GNUNET_OK == | ||
1143 | GNUNET_NETWORK_socket_close (sock)); | ||
1144 | errno = 0; | ||
1145 | return NULL; | ||
1146 | } | ||
1147 | if (0 != port) | ||
1148 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1149 | "Server starts to listen on port %u.\n", | ||
1150 | port); | ||
1151 | return sock; | ||
1152 | } | ||
1153 | |||
1154 | |||
1155 | /** | ||
1156 | * Setup service handle | ||
1157 | * | ||
1158 | * Configuration may specify: | ||
1159 | * - PORT (where to bind to for TCP) | ||
1160 | * - UNIXPATH (where to bind to for UNIX domain sockets) | ||
1161 | * - DISABLEV6 (disable support for IPv6, otherwise we use dual-stack) | ||
1162 | * - BINDTO (hostname or IP address to bind to, otherwise we take everything) | ||
1163 | * - ACCEPT_FROM (only allow connections from specified IPv4 subnets) | ||
1164 | * - ACCEPT_FROM6 (only allow connections from specified IPv6 subnets) | ||
1165 | * - REJECT_FROM (disallow allow connections from specified IPv4 subnets) | ||
1166 | * - REJECT_FROM6 (disallow allow connections from specified IPv6 subnets) | ||
1167 | * | ||
1168 | * @param sh service context to initialize | ||
1169 | * @return #GNUNET_OK if configuration succeeded | ||
1170 | */ | ||
1171 | static int | ||
1172 | setup_service (struct GNUNET_SERVICE_Handle *sh) | ||
1173 | { | ||
1174 | int tolerant; | ||
1175 | struct GNUNET_NETWORK_Handle **lsocks; | ||
1176 | #ifndef MINGW | ||
1177 | const char *nfds; | ||
1178 | unsigned int cnt; | ||
1179 | int flags; | ||
1180 | #endif | ||
1181 | |||
1182 | if (GNUNET_CONFIGURATION_have_value | ||
1183 | (sh->cfg, | ||
1184 | sh->service_name, | ||
1185 | "TOLERANT")) | ||
1186 | { | ||
1187 | if (GNUNET_SYSERR == | ||
1188 | (tolerant = | ||
1189 | GNUNET_CONFIGURATION_get_value_yesno (sh->cfg, | ||
1190 | sh->service_name, | ||
1191 | "TOLERANT"))) | ||
1192 | { | ||
1193 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1194 | _("Specified value for `%s' of service `%s' is invalid\n"), | ||
1195 | "TOLERANT", | ||
1196 | sh->service_name); | ||
1197 | return GNUNET_SYSERR; | ||
1198 | } | ||
1199 | } | ||
1200 | else | ||
1201 | tolerant = GNUNET_NO; | ||
1202 | |||
1203 | lsocks = NULL; | ||
1204 | #ifndef MINGW | ||
1205 | errno = 0; | ||
1206 | if ( (NULL != (nfds = getenv ("LISTEN_FDS"))) && | ||
1207 | (1 == SSCANF (nfds, | ||
1208 | "%u", | ||
1209 | &cnt)) && | ||
1210 | (cnt > 0) && | ||
1211 | (cnt < FD_SETSIZE) && | ||
1212 | (cnt + 4 < FD_SETSIZE) ) | ||
1213 | { | ||
1214 | lsocks = GNUNET_new_array (cnt + 1, | ||
1215 | struct GNUNET_NETWORK_Handle *); | ||
1216 | while (0 < cnt--) | ||
1217 | { | ||
1218 | flags = fcntl (3 + cnt, | ||
1219 | F_GETFD); | ||
1220 | if ( (flags < 0) || | ||
1221 | (0 != (flags & FD_CLOEXEC)) || | ||
1222 | (NULL == | ||
1223 | (lsocks[cnt] = GNUNET_NETWORK_socket_box_native (3 + cnt)))) | ||
1224 | { | ||
1225 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1226 | _("Could not access pre-bound socket %u, will try to bind myself\n"), | ||
1227 | (unsigned int) 3 + cnt); | ||
1228 | cnt++; | ||
1229 | while (NULL != lsocks[cnt]) | ||
1230 | GNUNET_break (GNUNET_OK == | ||
1231 | GNUNET_NETWORK_socket_close (lsocks[cnt++])); | ||
1232 | GNUNET_free (lsocks); | ||
1233 | lsocks = NULL; | ||
1234 | break; | ||
1235 | } | ||
1236 | } | ||
1237 | unsetenv ("LISTEN_FDS"); | ||
1238 | } | ||
1239 | #else | ||
1240 | if (NULL != getenv ("GNUNET_OS_READ_LSOCKS")) | ||
1241 | { | ||
1242 | lsocks = receive_sockets_from_parent (sh); | ||
1243 | putenv ("GNUNET_OS_READ_LSOCKS="); | ||
1244 | } | ||
1245 | #endif | ||
1246 | |||
1247 | if (NULL != lsocks) | ||
1248 | { | ||
1249 | /* listen only on inherited sockets if we have any */ | ||
1250 | struct GNUNET_NETWORK_Handle **ls; | ||
1251 | |||
1252 | for (ls = lsocks; NULL != *ls; ls++) | ||
1253 | { | ||
1254 | struct ServiceListenContext *slc; | ||
1255 | |||
1256 | slc = GNUNET_new (struct ServiceListenContext); | ||
1257 | slc->sh = sh; | ||
1258 | slc->listen_socket = *ls; | ||
1259 | GNUNET_CONTAINER_DLL_insert (sh->slc_head, | ||
1260 | sh->slc_tail, | ||
1261 | slc); | ||
1262 | } | ||
1263 | GNUNET_free (lsocks); | ||
1264 | } | ||
1265 | else | ||
1266 | { | ||
1267 | struct sockaddr **addrs; | ||
1268 | socklen_t *addrlens; | ||
1269 | int num; | ||
1270 | |||
1271 | num = get_server_addresses (sh->service_name, | ||
1272 | sh->cfg, | ||
1273 | &addrs, | ||
1274 | &addrlens); | ||
1275 | if (GNUNET_SYSERR == num) | ||
1276 | return GNUNET_SYSERR; | ||
1277 | |||
1278 | for (int i = 0; i < num; i++) | ||
1279 | { | ||
1280 | struct ServiceListenContext *slc; | ||
1281 | |||
1282 | slc = GNUNET_new (struct ServiceListenContext); | ||
1283 | slc->sh = sh; | ||
1284 | slc->listen_socket = open_listen_socket (addrs[i], | ||
1285 | addrlens[i]); | ||
1286 | if (NULL == slc->listen_socket) | ||
1287 | { | ||
1288 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, | ||
1289 | "bind"); | ||
1290 | GNUNET_free (addrs[i++]); | ||
1291 | GNUNET_free (slc); | ||
1292 | continue; | ||
1293 | } | ||
1294 | GNUNET_free (addrs[i++]); | ||
1295 | GNUNET_CONTAINER_DLL_insert (sh->slc_head, | ||
1296 | sh->slc_tail, | ||
1297 | slc); | ||
1298 | } | ||
1299 | GNUNET_free_non_null (addrlens); | ||
1300 | GNUNET_free_non_null (addrs); | ||
1301 | if ( (0 != num) && | ||
1302 | (NULL == sh->slc_head) ) | ||
1303 | { | ||
1304 | /* All attempts to bind failed, hard failure */ | ||
1305 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1306 | _("Could not bind to any of the ports I was supposed to, refusing to run!\n")); | ||
1307 | return GNUNET_SYSERR; | ||
1308 | } | ||
1309 | } | ||
1310 | |||
1311 | sh->require_found = tolerant ? GNUNET_NO : GNUNET_YES; | ||
1312 | sh->match_uid | ||
1313 | = GNUNET_CONFIGURATION_get_value_yesno (sh->cfg, | ||
1314 | sh->service_name, | ||
1315 | "UNIX_MATCH_UID"); | ||
1316 | sh->match_gid | ||
1317 | = GNUNET_CONFIGURATION_get_value_yesno (sh->cfg, | ||
1318 | sh->service_name, | ||
1319 | "UNIX_MATCH_GID"); | ||
1320 | process_acl4 (&sh->v4_denied, | ||
1321 | sh, | ||
1322 | "REJECT_FROM"); | ||
1323 | process_acl4 (&sh->v4_allowed, | ||
1324 | sh, | ||
1325 | "ACCEPT_FROM"); | ||
1326 | process_acl6 (&sh->v6_denied, | ||
1327 | sh, | ||
1328 | "REJECT_FROM6"); | ||
1329 | process_acl6 (&sh->v6_allowed, | ||
1330 | sh, | ||
1331 | "ACCEPT_FROM6"); | ||
1332 | return GNUNET_OK; | ||
1333 | } | ||
1334 | |||
1335 | |||
1336 | /** | ||
1337 | * Get the name of the user that'll be used | ||
1338 | * to provide the service. | ||
1339 | * | ||
1340 | * @param sh service context | ||
1341 | * @return value of the 'USERNAME' option | ||
1342 | */ | ||
1343 | static char * | ||
1344 | get_user_name (struct GNUNET_SERVICE_Handle *sh) | ||
1345 | { | ||
1346 | char *un; | ||
1347 | |||
1348 | if (GNUNET_OK != | ||
1349 | GNUNET_CONFIGURATION_get_value_filename (sh->cfg, | ||
1350 | sh->service_name, | ||
1351 | "USERNAME", | ||
1352 | &un)) | ||
1353 | return NULL; | ||
1354 | return un; | ||
1355 | } | ||
1356 | |||
1357 | |||
1358 | /** | ||
1359 | * Set user ID. | ||
1360 | * | ||
1361 | * @param sh service context | ||
1362 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on error | ||
1363 | */ | ||
1364 | static int | ||
1365 | set_user_id (struct GNUNET_SERVICE_Handle *sh) | ||
1366 | { | ||
1367 | char *user; | ||
1368 | |||
1369 | if (NULL == (user = get_user_name (sh))) | ||
1370 | return GNUNET_OK; /* keep */ | ||
1371 | #ifndef MINGW | ||
1372 | struct passwd *pws; | ||
1373 | |||
1374 | errno = 0; | ||
1375 | pws = getpwnam (user); | ||
1376 | if (NULL == pws) | ||
1377 | { | ||
1378 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1379 | _("Cannot obtain information about user `%s': %s\n"), | ||
1380 | user, | ||
1381 | errno == 0 ? _("No such user") : STRERROR (errno)); | ||
1382 | GNUNET_free (user); | ||
1383 | return GNUNET_SYSERR; | ||
1384 | } | ||
1385 | if ( (0 != setgid (pws->pw_gid)) || | ||
1386 | (0 != setegid (pws->pw_gid)) || | ||
1387 | #if HAVE_INITGROUPS | ||
1388 | (0 != initgroups (user, | ||
1389 | pws->pw_gid)) || | ||
1390 | #endif | ||
1391 | (0 != setuid (pws->pw_uid)) || | ||
1392 | (0 != seteuid (pws->pw_uid))) | ||
1393 | { | ||
1394 | if ((0 != setregid (pws->pw_gid, | ||
1395 | pws->pw_gid)) || | ||
1396 | (0 != setreuid (pws->pw_uid, | ||
1397 | pws->pw_uid))) | ||
1398 | { | ||
1399 | LOG (GNUNET_ERROR_TYPE_ERROR, | ||
1400 | _("Cannot change user/group to `%s': %s\n"), | ||
1401 | user, | ||
1402 | STRERROR (errno)); | ||
1403 | GNUNET_free (user); | ||
1404 | return GNUNET_SYSERR; | ||
1405 | } | ||
1406 | } | ||
1407 | #endif | ||
1408 | GNUNET_free (user); | ||
1409 | return GNUNET_OK; | ||
1410 | } | ||
1411 | |||
1412 | |||
1413 | /** | ||
1414 | * Get the name of the file where we will | ||
1415 | * write the PID of the service. | ||
1416 | * | ||
1417 | * @param sh service context | ||
1418 | * @return name of the file for the process ID | ||
1419 | */ | ||
1420 | static char * | ||
1421 | get_pid_file_name (struct GNUNET_SERVICE_Handle *sh) | ||
1422 | { | ||
1423 | char *pif; | ||
1424 | |||
1425 | if (GNUNET_OK != | ||
1426 | GNUNET_CONFIGURATION_get_value_filename (sh->cfg, | ||
1427 | sh->service_name, | ||
1428 | "PIDFILE", | ||
1429 | &pif)) | ||
1430 | return NULL; | ||
1431 | return pif; | ||
1432 | } | ||
1433 | |||
1434 | |||
1435 | /** | ||
1436 | * Delete the PID file that was created by our parent. | ||
1437 | * | ||
1438 | * @param sh service context | ||
1439 | */ | ||
1440 | static void | ||
1441 | pid_file_delete (struct GNUNET_SERVICE_Handle *sh) | ||
1442 | { | ||
1443 | char *pif = get_pid_file_name (sh); | ||
1444 | |||
1445 | if (NULL == pif) | ||
1446 | return; /* no PID file */ | ||
1447 | if (0 != UNLINK (pif)) | ||
1448 | LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, | ||
1449 | "unlink", | ||
1450 | pif); | ||
1451 | GNUNET_free (pif); | ||
1452 | } | ||
1453 | |||
1454 | |||
1455 | /** | ||
1456 | * Detach from terminal. | ||
1457 | * | ||
1458 | * @param sh service context | ||
1459 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on error | ||
1460 | */ | ||
1461 | static int | ||
1462 | detach_terminal (struct GNUNET_SERVICE_Handle *sh) | ||
1463 | { | ||
1464 | #ifndef MINGW | ||
1465 | pid_t pid; | ||
1466 | int nullfd; | ||
1467 | int filedes[2]; | ||
1468 | |||
1469 | if (0 != PIPE (filedes)) | ||
1470 | { | ||
1471 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, | ||
1472 | "pipe"); | ||
1473 | return GNUNET_SYSERR; | ||
1474 | } | ||
1475 | pid = fork (); | ||
1476 | if (pid < 0) | ||
1477 | { | ||
1478 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, | ||
1479 | "fork"); | ||
1480 | return GNUNET_SYSERR; | ||
1481 | } | ||
1482 | if (0 != pid) | ||
1483 | { | ||
1484 | /* Parent */ | ||
1485 | char c; | ||
1486 | |||
1487 | GNUNET_break (0 == CLOSE (filedes[1])); | ||
1488 | c = 'X'; | ||
1489 | if (1 != READ (filedes[0], | ||
1490 | &c, | ||
1491 | sizeof (char))) | ||
1492 | LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, | ||
1493 | "read"); | ||
1494 | fflush (stdout); | ||
1495 | switch (c) | ||
1496 | { | ||
1497 | case '.': | ||
1498 | exit (0); | ||
1499 | case 'I': | ||
1500 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
1501 | _("Service process failed to initialize\n")); | ||
1502 | break; | ||
1503 | case 'S': | ||
1504 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
1505 | _("Service process could not initialize server function\n")); | ||
1506 | break; | ||
1507 | case 'X': | ||
1508 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
1509 | _("Service process failed to report status\n")); | ||
1510 | break; | ||
1511 | } | ||
1512 | exit (1); /* child reported error */ | ||
1513 | } | ||
1514 | GNUNET_break (0 == CLOSE (0)); | ||
1515 | GNUNET_break (0 == CLOSE (1)); | ||
1516 | GNUNET_break (0 == CLOSE (filedes[0])); | ||
1517 | nullfd = OPEN ("/dev/null", | ||
1518 | O_RDWR | O_APPEND); | ||
1519 | if (nullfd < 0) | ||
1520 | return GNUNET_SYSERR; | ||
1521 | /* set stdin/stdout to /dev/null */ | ||
1522 | if ( (dup2 (nullfd, 0) < 0) || | ||
1523 | (dup2 (nullfd, 1) < 0) ) | ||
1524 | { | ||
1525 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, | ||
1526 | "dup2"); | ||
1527 | (void) CLOSE (nullfd); | ||
1528 | return GNUNET_SYSERR; | ||
1529 | } | ||
1530 | (void) CLOSE (nullfd); | ||
1531 | /* Detach from controlling terminal */ | ||
1532 | pid = setsid (); | ||
1533 | if (-1 == pid) | ||
1534 | LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, | ||
1535 | "setsid"); | ||
1536 | sh->ready_confirm_fd = filedes[1]; | ||
1537 | #else | ||
1538 | /* FIXME: we probably need to do something else | ||
1539 | * elsewhere in order to fork the process itself... */ | ||
1540 | FreeConsole (); | ||
1541 | #endif | ||
1542 | return GNUNET_OK; | ||
1543 | } | ||
1544 | |||
1545 | |||
1546 | /** | ||
1547 | * Tear down the service, closing the listen sockets and | ||
1548 | * freeing the ACLs. | ||
1549 | * | ||
1550 | * @param sh handle to the service to tear down. | ||
1551 | */ | ||
1552 | static void | ||
1553 | teardown_service (struct GNUNET_SERVICE_Handle *sh) | ||
1554 | { | ||
1555 | struct ServiceListenContext *slc; | ||
1556 | |||
1557 | GNUNET_free_non_null (sh->v4_denied); | ||
1558 | GNUNET_free_non_null (sh->v6_denied); | ||
1559 | GNUNET_free_non_null (sh->v4_allowed); | ||
1560 | GNUNET_free_non_null (sh->v6_allowed); | ||
1561 | while (NULL != (slc = sh->slc_head)) | ||
1562 | { | ||
1563 | GNUNET_CONTAINER_DLL_remove (sh->slc_head, | ||
1564 | sh->slc_tail, | ||
1565 | slc); | ||
1566 | if (NULL != slc->listen_task) | ||
1567 | GNUNET_SCHEDULER_cancel (slc->listen_task); | ||
1568 | GNUNET_break (GNUNET_OK == | ||
1569 | GNUNET_NETWORK_socket_close (slc->listen_socket)); | ||
1570 | GNUNET_free (slc); | ||
1571 | } | ||
1572 | } | ||
1573 | |||
1574 | |||
1575 | /** | ||
1576 | * Low-level function to start a service if the scheduler | ||
1577 | * is already running. Should only be used directly in | ||
1578 | * special cases. | ||
1579 | * | ||
1580 | * The function will launch the service with the name @a service_name | ||
1581 | * using the @a service_options to configure its shutdown | ||
1582 | * behavior. When clients connect or disconnect, the respective | ||
1583 | * @a connect_cb or @a disconnect_cb functions will be called. For | ||
1584 | * messages received from the clients, the respective @a handlers will | ||
1585 | * be invoked; for the closure of the handlers we use the return value | ||
1586 | * from the @a connect_cb invocation of the respective client. | ||
1587 | * | ||
1588 | * Each handler MUST call #GNUNET_SERVICE_client_continue() after each | ||
1589 | * message to receive further messages from this client. If | ||
1590 | * #GNUNET_SERVICE_client_continue() is not called within a short | ||
1591 | * time, a warning will be logged. If delays are expected, services | ||
1592 | * should call #GNUNET_SERVICE_client_disable_continue_warning() to | ||
1593 | * disable the warning. | ||
1594 | * | ||
1595 | * Clients sending invalid messages (based on @a handlers) will be | ||
1596 | * dropped. Additionally, clients can be dropped at any time using | ||
1597 | * #GNUNET_SERVICE_client_drop(). | ||
1598 | * | ||
1599 | * The service must be stopped using #GNUNET_SERVICE_stoP(). | ||
1600 | * | ||
1601 | * @param service_name name of the service to run | ||
1602 | * @param cfg configuration to use | ||
1603 | * @param connect_cb function to call whenever a client connects | ||
1604 | * @param disconnect_cb function to call whenever a client disconnects | ||
1605 | * @param cls closure argument for @a connect_cb and @a disconnect_cb | ||
1606 | * @param handlers NULL-terminated array of message handlers for the service, | ||
1607 | * the closure will be set to the value returned by | ||
1608 | * the @a connect_cb for the respective connection | ||
1609 | * @return NULL on error | ||
1610 | */ | ||
1611 | struct GNUNET_SERVICE_Handle * | ||
1612 | GNUNET_SERVICE_starT (const char *service_name, | ||
1613 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
1614 | GNUNET_SERVICE_ConnectHandler connect_cb, | ||
1615 | GNUNET_SERVICE_DisconnectHandler disconnect_cb, | ||
1616 | void *cls, | ||
1617 | const struct GNUNET_MQ_MessageHandler *handlers) | ||
1618 | { | ||
1619 | struct GNUNET_SERVICE_Handle *sh; | ||
1620 | |||
1621 | sh = GNUNET_new (struct GNUNET_SERVICE_Handle); | ||
1622 | sh->service_name = service_name; | ||
1623 | sh->cfg = cfg; | ||
1624 | sh->connect_cb = connect_cb; | ||
1625 | sh->disconnect_cb = disconnect_cb; | ||
1626 | sh->cb_cls = cls; | ||
1627 | sh->handlers = GNUNET_MQ_copy_handlers (handlers); | ||
1628 | if (GNUNET_OK != setup_service (sh)) | ||
1629 | { | ||
1630 | GNUNET_free_non_null (sh->handlers); | ||
1631 | GNUNET_free (sh); | ||
1632 | return NULL; | ||
1633 | } | ||
1634 | GNUNET_SERVICE_resume (sh); | ||
1635 | return sh; | ||
1636 | } | ||
1637 | |||
1638 | |||
1639 | /** | ||
1640 | * Stops a service that was started with #GNUNET_SERVICE_starT(). | ||
1641 | * | ||
1642 | * @param srv service to stop | ||
1643 | */ | ||
1644 | void | ||
1645 | GNUNET_SERVICE_stoP (struct GNUNET_SERVICE_Handle *srv) | ||
1646 | { | ||
1647 | struct GNUNET_SERVICE_Client *client; | ||
1648 | |||
1649 | GNUNET_SERVICE_suspend (srv); | ||
1650 | while (NULL != (client = srv->clients_head)) | ||
1651 | GNUNET_SERVICE_client_drop (client); | ||
1652 | teardown_service (srv); | ||
1653 | GNUNET_free_non_null (srv->handlers); | ||
1654 | GNUNET_free (srv); | ||
1655 | } | ||
1656 | |||
1657 | |||
1658 | /** | ||
1659 | * Creates the "main" function for a GNUnet service. You | ||
1660 | * should almost always use the #GNUNET_SERVICE_MAIN macro | ||
1661 | * instead of calling this function directly (except | ||
1662 | * for ARM, which should call this function directly). | ||
1663 | * | ||
1664 | * The function will launch the service with the name @a service_name | ||
1665 | * using the @a service_options to configure its shutdown | ||
1666 | * behavior. Once the service is ready, the @a init_cb will be called | ||
1667 | * for service-specific initialization. @a init_cb will be given the | ||
1668 | * service handler which can be used to control the service's | ||
1669 | * availability. When clients connect or disconnect, the respective | ||
1670 | * @a connect_cb or @a disconnect_cb functions will be called. For | ||
1671 | * messages received from the clients, the respective @a handlers will | ||
1672 | * be invoked; for the closure of the handlers we use the return value | ||
1673 | * from the @a connect_cb invocation of the respective client. | ||
1674 | * | ||
1675 | * Each handler MUST call #GNUNET_SERVICE_client_continue() after each | ||
1676 | * message to receive further messages from this client. If | ||
1677 | * #GNUNET_SERVICE_client_continue() is not called within a short | ||
1678 | * time, a warning will be logged. If delays are expected, services | ||
1679 | * should call #GNUNET_SERVICE_client_disable_continue_warning() to | ||
1680 | * disable the warning. | ||
1681 | * | ||
1682 | * Clients sending invalid messages (based on @a handlers) will be | ||
1683 | * dropped. Additionally, clients can be dropped at any time using | ||
1684 | * #GNUNET_SERVICE_client_drop(). | ||
1685 | * | ||
1686 | * @param argc number of command-line arguments in @a argv | ||
1687 | * @param argv array of command-line arguments | ||
1688 | * @param service_name name of the service to run | ||
1689 | * @param options options controlling shutdown of the service | ||
1690 | * @param service_init_cb function to call once the service is ready | ||
1691 | * @param connect_cb function to call whenever a client connects | ||
1692 | * @param disconnect_cb function to call whenever a client disconnects | ||
1693 | * @param cls closure argument for @a service_init_cb, @a connect_cb and @a disconnect_cb | ||
1694 | * @param handlers NULL-terminated array of message handlers for the service, | ||
1695 | * the closure will be set to the value returned by | ||
1696 | * the @a connect_cb for the respective connection | ||
1697 | * @return 0 on success, non-zero on error | ||
1698 | */ | ||
1699 | int | ||
1700 | GNUNET_SERVICE_ruN_ (int argc, | ||
1701 | char *const *argv, | ||
1702 | const char *service_name, | ||
1703 | enum GNUNET_SERVICE_Options options, | ||
1704 | GNUNET_SERVICE_InitCallback service_init_cb, | ||
1705 | GNUNET_SERVICE_ConnectHandler connect_cb, | ||
1706 | GNUNET_SERVICE_DisconnectHandler disconnect_cb, | ||
1707 | void *cls, | ||
1708 | const struct GNUNET_MQ_MessageHandler *handlers) | ||
1709 | { | ||
1710 | struct GNUNET_SERVICE_Handle sh; | ||
1711 | char *cfg_filename; | ||
1712 | char *opt_cfg_filename; | ||
1713 | char *loglev; | ||
1714 | const char *xdg; | ||
1715 | char *logfile; | ||
1716 | int do_daemonize; | ||
1717 | unsigned long long skew_offset; | ||
1718 | unsigned long long skew_variance; | ||
1719 | long long clock_offset; | ||
1720 | struct GNUNET_CONFIGURATION_Handle *cfg; | ||
1721 | int ret; | ||
1722 | int err; | ||
1723 | |||
1724 | struct GNUNET_GETOPT_CommandLineOption service_options[] = { | ||
1725 | GNUNET_GETOPT_OPTION_CFG_FILE (&opt_cfg_filename), | ||
1726 | {'d', "daemonize", NULL, | ||
1727 | gettext_noop ("do daemonize (detach from terminal)"), 0, | ||
1728 | GNUNET_GETOPT_set_one, &do_daemonize}, | ||
1729 | GNUNET_GETOPT_OPTION_HELP (NULL), | ||
1730 | GNUNET_GETOPT_OPTION_LOGLEVEL (&loglev), | ||
1731 | GNUNET_GETOPT_OPTION_LOGFILE (&logfile), | ||
1732 | GNUNET_GETOPT_OPTION_VERSION (PACKAGE_VERSION " " VCS_VERSION), | ||
1733 | GNUNET_GETOPT_OPTION_END | ||
1734 | }; | ||
1735 | |||
1736 | memset (&sh, | ||
1737 | 0, | ||
1738 | sizeof (sh)); | ||
1739 | xdg = getenv ("XDG_CONFIG_HOME"); | ||
1740 | if (NULL != xdg) | ||
1741 | GNUNET_asprintf (&cfg_filename, | ||
1742 | "%s%s%s", | ||
1743 | xdg, | ||
1744 | DIR_SEPARATOR_STR, | ||
1745 | GNUNET_OS_project_data_get ()->config_file); | ||
1746 | else | ||
1747 | cfg_filename = GNUNET_strdup (GNUNET_OS_project_data_get ()->user_config_file); | ||
1748 | sh.ready_confirm_fd = -1; | ||
1749 | sh.options = options; | ||
1750 | sh.cfg = cfg = GNUNET_CONFIGURATION_create (); | ||
1751 | sh.service_init_cb = service_init_cb; | ||
1752 | sh.connect_cb = connect_cb; | ||
1753 | sh.disconnect_cb = disconnect_cb; | ||
1754 | sh.cb_cls = cls; | ||
1755 | sh.handlers = GNUNET_MQ_copy_handlers (handlers); | ||
1756 | sh.service_name = service_name; | ||
1757 | |||
1758 | /* setup subsystems */ | ||
1759 | loglev = NULL; | ||
1760 | logfile = NULL; | ||
1761 | opt_cfg_filename = NULL; | ||
1762 | do_daemonize = 0; | ||
1763 | ret = GNUNET_GETOPT_run (service_name, | ||
1764 | service_options, | ||
1765 | argc, | ||
1766 | argv); | ||
1767 | if (GNUNET_SYSERR == ret) | ||
1768 | goto shutdown; | ||
1769 | if (GNUNET_NO == ret) | ||
1770 | { | ||
1771 | err = 0; | ||
1772 | goto shutdown; | ||
1773 | } | ||
1774 | if (GNUNET_OK != GNUNET_log_setup (service_name, | ||
1775 | loglev, | ||
1776 | logfile)) | ||
1777 | { | ||
1778 | GNUNET_break (0); | ||
1779 | goto shutdown; | ||
1780 | } | ||
1781 | if (NULL == opt_cfg_filename) | ||
1782 | opt_cfg_filename = GNUNET_strdup (cfg_filename); | ||
1783 | if (GNUNET_YES == GNUNET_DISK_file_test (opt_cfg_filename)) | ||
1784 | { | ||
1785 | if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, | ||
1786 | opt_cfg_filename)) | ||
1787 | { | ||
1788 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1789 | _("Malformed configuration file `%s', exit ...\n"), | ||
1790 | opt_cfg_filename); | ||
1791 | goto shutdown; | ||
1792 | } | ||
1793 | } | ||
1794 | else | ||
1795 | { | ||
1796 | if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, | ||
1797 | NULL)) | ||
1798 | { | ||
1799 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1800 | _("Malformed configuration, exit ...\n")); | ||
1801 | goto shutdown; | ||
1802 | } | ||
1803 | if (0 != strcmp (opt_cfg_filename, | ||
1804 | cfg_filename)) | ||
1805 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
1806 | _("Could not access configuration file `%s'\n"), | ||
1807 | opt_cfg_filename); | ||
1808 | } | ||
1809 | if (GNUNET_OK != setup_service (&sh)) | ||
1810 | goto shutdown; | ||
1811 | if ( (1 == do_daemonize) && | ||
1812 | (GNUNET_OK != detach_terminal (&sh)) ) | ||
1813 | { | ||
1814 | GNUNET_break (0); | ||
1815 | goto shutdown; | ||
1816 | } | ||
1817 | if (GNUNET_OK != set_user_id (&sh)) | ||
1818 | goto shutdown; | ||
1819 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1820 | "Service `%s' runs with configuration from `%s'\n", | ||
1821 | service_name, | ||
1822 | opt_cfg_filename); | ||
1823 | if ((GNUNET_OK == | ||
1824 | GNUNET_CONFIGURATION_get_value_number (sh.cfg, | ||
1825 | "TESTING", | ||
1826 | "SKEW_OFFSET", | ||
1827 | &skew_offset)) && | ||
1828 | (GNUNET_OK == | ||
1829 | GNUNET_CONFIGURATION_get_value_number (sh.cfg, | ||
1830 | "TESTING", | ||
1831 | "SKEW_VARIANCE", | ||
1832 | &skew_variance))) | ||
1833 | { | ||
1834 | clock_offset = skew_offset - skew_variance; | ||
1835 | GNUNET_TIME_set_offset (clock_offset); | ||
1836 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
1837 | "Skewing clock by %dll ms\n", | ||
1838 | clock_offset); | ||
1839 | } | ||
1840 | GNUNET_RESOLVER_connect (sh.cfg); | ||
1841 | |||
1842 | /* actually run service */ | ||
1843 | err = 0; | ||
1844 | GNUNET_SCHEDULER_run (&service_main, | ||
1845 | &sh); | ||
1846 | /* shutdown */ | ||
1847 | if (1 == do_daemonize) | ||
1848 | pid_file_delete (&sh); | ||
1849 | |||
1850 | shutdown: | ||
1851 | if (-1 != sh.ready_confirm_fd) | ||
1852 | { | ||
1853 | if (1 != WRITE (sh.ready_confirm_fd, | ||
1854 | err ? "I" : "S", | ||
1855 | 1)) | ||
1856 | LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, | ||
1857 | "write"); | ||
1858 | GNUNET_break (0 == CLOSE (sh.ready_confirm_fd)); | ||
1859 | } | ||
1860 | #if HAVE_MALLINFO | ||
1861 | { | ||
1862 | char *counter; | ||
1863 | |||
1864 | if ( (GNUNET_YES == | ||
1865 | GNUNET_CONFIGURATION_have_value (sh.cfg, | ||
1866 | service_name, | ||
1867 | "GAUGER_HEAP")) && | ||
1868 | (GNUNET_OK == | ||
1869 | GNUNET_CONFIGURATION_get_value_string (sh.cfg, | ||
1870 | service_name, | ||
1871 | "GAUGER_HEAP", | ||
1872 | &counter)) ) | ||
1873 | { | ||
1874 | struct mallinfo mi; | ||
1875 | |||
1876 | mi = mallinfo (); | ||
1877 | GAUGER (service_name, | ||
1878 | counter, | ||
1879 | mi.usmblks, | ||
1880 | "blocks"); | ||
1881 | GNUNET_free (counter); | ||
1882 | } | ||
1883 | } | ||
1884 | #endif | ||
1885 | teardown_service (&sh); | ||
1886 | GNUNET_free_non_null (sh.handlers); | ||
1887 | GNUNET_SPEEDUP_stop_ (); | ||
1888 | GNUNET_CONFIGURATION_destroy (cfg); | ||
1889 | GNUNET_free_non_null (logfile); | ||
1890 | GNUNET_free_non_null (loglev); | ||
1891 | GNUNET_free (cfg_filename); | ||
1892 | GNUNET_free_non_null (opt_cfg_filename); | ||
1893 | |||
1894 | return err ? GNUNET_SYSERR : sh.ret; | ||
1895 | } | ||
1896 | |||
1897 | |||
1898 | /** | ||
1899 | * Suspend accepting connections from the listen socket temporarily. | ||
1900 | * Resume activity using #GNUNET_SERVICE_resume. | ||
1901 | * | ||
1902 | * @param sh service to stop accepting connections. | ||
1903 | */ | ||
1904 | void | ||
1905 | GNUNET_SERVICE_suspend (struct GNUNET_SERVICE_Handle *sh) | ||
1906 | { | ||
1907 | struct ServiceListenContext *slc; | ||
1908 | |||
1909 | for (slc = sh->slc_head; NULL != slc; slc = slc->next) | ||
1910 | { | ||
1911 | if (NULL != slc->listen_task) | ||
1912 | { | ||
1913 | GNUNET_SCHEDULER_cancel (slc->listen_task); | ||
1914 | slc->listen_task = NULL; | ||
1915 | } | ||
1916 | } | ||
1917 | } | ||
1918 | |||
1919 | |||
1920 | /** | ||
1921 | * Task run when we are ready to transmit data to the | ||
1922 | * client. | ||
1923 | * | ||
1924 | * @param cls the `struct GNUNET_SERVICE_Client *` to send to | ||
1925 | */ | ||
1926 | static void | ||
1927 | do_send (void *cls) | ||
1928 | { | ||
1929 | struct GNUNET_SERVICE_Client *client = cls; | ||
1930 | ssize_t ret; | ||
1931 | size_t left; | ||
1932 | const char *buf; | ||
1933 | |||
1934 | client->send_task = NULL; | ||
1935 | buf = (const char *) client->msg; | ||
1936 | left = ntohs (client->msg->size) - client->msg_pos; | ||
1937 | ret = GNUNET_NETWORK_socket_send (client->sock, | ||
1938 | &buf[client->msg_pos], | ||
1939 | left); | ||
1940 | GNUNET_assert (ret <= (ssize_t) left); | ||
1941 | if (0 == ret) | ||
1942 | { | ||
1943 | GNUNET_MQ_inject_error (client->mq, | ||
1944 | GNUNET_MQ_ERROR_WRITE); | ||
1945 | return; | ||
1946 | } | ||
1947 | if (-1 == ret) | ||
1948 | { | ||
1949 | if ( (EAGAIN == errno) || | ||
1950 | (EINTR == errno) ) | ||
1951 | { | ||
1952 | /* ignore */ | ||
1953 | ret = 0; | ||
1954 | } | ||
1955 | else | ||
1956 | { | ||
1957 | if (EPIPE != errno) | ||
1958 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, | ||
1959 | "send"); | ||
1960 | GNUNET_MQ_inject_error (client->mq, | ||
1961 | GNUNET_MQ_ERROR_WRITE); | ||
1962 | return; | ||
1963 | } | ||
1964 | } | ||
1965 | if (0 == client->msg_pos) | ||
1966 | { | ||
1967 | GNUNET_MQ_impl_send_in_flight (client->mq); | ||
1968 | } | ||
1969 | client->msg_pos += ret; | ||
1970 | if (left > ret) | ||
1971 | { | ||
1972 | GNUNET_assert (NULL == client->drop_task); | ||
1973 | client->send_task | ||
1974 | = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
1975 | client->sock, | ||
1976 | &do_send, | ||
1977 | client); | ||
1978 | return; | ||
1979 | } | ||
1980 | GNUNET_MQ_impl_send_continue (client->mq); | ||
1981 | } | ||
1982 | |||
1983 | |||
1984 | /** | ||
1985 | * Signature of functions implementing the sending functionality of a | ||
1986 | * message queue. | ||
1987 | * | ||
1988 | * @param mq the message queue | ||
1989 | * @param msg the message to send | ||
1990 | * @param impl_state our `struct GNUNET_SERVICE_Client *` | ||
1991 | */ | ||
1992 | static void | ||
1993 | service_mq_send (struct GNUNET_MQ_Handle *mq, | ||
1994 | const struct GNUNET_MessageHeader *msg, | ||
1995 | void *impl_state) | ||
1996 | { | ||
1997 | struct GNUNET_SERVICE_Client *client = impl_state; | ||
1998 | |||
1999 | if (NULL != client->drop_task) | ||
2000 | return; /* we're going down right now, do not try to send */ | ||
2001 | GNUNET_assert (NULL == client->send_task); | ||
2002 | |||
2003 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
2004 | "Sending message of type %u and size %u to client\n", | ||
2005 | ntohs (msg->type), ntohs (msg->size)); | ||
2006 | |||
2007 | client->msg = msg; | ||
2008 | client->msg_pos = 0; | ||
2009 | client->send_task | ||
2010 | = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
2011 | client->sock, | ||
2012 | &do_send, | ||
2013 | client); | ||
2014 | } | ||
2015 | |||
2016 | |||
2017 | /** | ||
2018 | * Implementation function that cancels the currently sent message. | ||
2019 | * | ||
2020 | * @param mq message queue | ||
2021 | * @param impl_state state specific to the implementation | ||
2022 | */ | ||
2023 | static void | ||
2024 | service_mq_cancel (struct GNUNET_MQ_Handle *mq, | ||
2025 | void *impl_state) | ||
2026 | { | ||
2027 | struct GNUNET_SERVICE_Client *client = impl_state; | ||
2028 | |||
2029 | GNUNET_assert (0 == client->msg_pos); | ||
2030 | client->msg = NULL; | ||
2031 | GNUNET_SCHEDULER_cancel (client->send_task); | ||
2032 | client->send_task = NULL; | ||
2033 | } | ||
2034 | |||
2035 | |||
2036 | /** | ||
2037 | * Generic error handler, called with the appropriate | ||
2038 | * error code and the same closure specified at the creation of | ||
2039 | * the message queue. | ||
2040 | * Not every message queue implementation supports an error handler. | ||
2041 | * | ||
2042 | * @param cls closure with our `struct GNUNET_SERVICE_Client` | ||
2043 | * @param error error code | ||
2044 | */ | ||
2045 | static void | ||
2046 | service_mq_error_handler (void *cls, | ||
2047 | enum GNUNET_MQ_Error error) | ||
2048 | { | ||
2049 | struct GNUNET_SERVICE_Client *client = cls; | ||
2050 | struct GNUNET_SERVICE_Handle *sh = client->sh; | ||
2051 | |||
2052 | if ( (GNUNET_MQ_ERROR_NO_MATCH == error) && | ||
2053 | (GNUNET_NO == sh->require_found) ) | ||
2054 | { | ||
2055 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2056 | "No handler for message of type %u found\n", | ||
2057 | (unsigned int) client->warn_type); | ||
2058 | GNUNET_SERVICE_client_continue (client); | ||
2059 | return; /* ignore error */ | ||
2060 | } | ||
2061 | GNUNET_SERVICE_client_drop (client); | ||
2062 | } | ||
2063 | |||
2064 | |||
2065 | /** | ||
2066 | * Task run to warn about missing calls to #GNUNET_SERVICE_client_continue(). | ||
2067 | * | ||
2068 | * @param cls our `struct GNUNET_SERVICE_Client *` to process more requests from | ||
2069 | */ | ||
2070 | static void | ||
2071 | warn_no_client_continue (void *cls) | ||
2072 | { | ||
2073 | struct GNUNET_SERVICE_Client *client = cls; | ||
2074 | |||
2075 | GNUNET_break (0 != client->warn_type); /* type should never be 0 here, as we don't use 0 */ | ||
2076 | client->warn_task | ||
2077 | = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, | ||
2078 | &warn_no_client_continue, | ||
2079 | client); | ||
2080 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
2081 | _("Processing code for message of type %u did not call `GNUNET_SERVICE_client_continue' after %s\n"), | ||
2082 | (unsigned int) client->warn_type, | ||
2083 | GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (client->warn_start), | ||
2084 | GNUNET_YES)); | ||
2085 | } | ||
2086 | |||
2087 | |||
2088 | /** | ||
2089 | * Functions with this signature are called whenever a | ||
2090 | * complete message is received by the tokenizer for a client. | ||
2091 | * | ||
2092 | * Do not call #GNUNET_MST_destroy() from within | ||
2093 | * the scope of this callback. | ||
2094 | * | ||
2095 | * @param cls closure with the `struct GNUNET_SERVICE_Client *` | ||
2096 | * @param message the actual message | ||
2097 | * @return #GNUNET_OK on success, #GNUNET_SYSERR if the client was dropped | ||
2098 | */ | ||
2099 | static int | ||
2100 | service_client_mst_cb (void *cls, | ||
2101 | const struct GNUNET_MessageHeader *message) | ||
2102 | { | ||
2103 | struct GNUNET_SERVICE_Client *client = cls; | ||
2104 | |||
2105 | LOG (GNUNET_ERROR_TYPE_INFO, | ||
2106 | "Received message of type %u and size %u from client\n", | ||
2107 | ntohs (message->type), ntohs (message->size)); | ||
2108 | |||
2109 | GNUNET_assert (GNUNET_NO == client->needs_continue); | ||
2110 | client->needs_continue = GNUNET_YES; | ||
2111 | client->warn_type = ntohs (message->type); | ||
2112 | client->warn_start = GNUNET_TIME_absolute_get (); | ||
2113 | GNUNET_assert (NULL == client->warn_task); | ||
2114 | client->warn_task | ||
2115 | = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, | ||
2116 | &warn_no_client_continue, | ||
2117 | client); | ||
2118 | GNUNET_MQ_inject_message (client->mq, | ||
2119 | message); | ||
2120 | if (NULL != client->drop_task) | ||
2121 | return GNUNET_SYSERR; | ||
2122 | return GNUNET_OK; | ||
2123 | } | ||
2124 | |||
2125 | |||
2126 | /** | ||
2127 | * A client sent us data. Receive and process it. If we are done, | ||
2128 | * reschedule this task. | ||
2129 | * | ||
2130 | * @param cls the `struct GNUNET_SERVICE_Client` that sent us data. | ||
2131 | */ | ||
2132 | static void | ||
2133 | service_client_recv (void *cls) | ||
2134 | { | ||
2135 | struct GNUNET_SERVICE_Client *client = cls; | ||
2136 | int ret; | ||
2137 | |||
2138 | client->recv_task = NULL; | ||
2139 | ret = GNUNET_MST_read (client->mst, | ||
2140 | client->sock, | ||
2141 | GNUNET_NO, | ||
2142 | GNUNET_YES); | ||
2143 | if (GNUNET_SYSERR == ret) | ||
2144 | { | ||
2145 | /* client closed connection (or IO error) */ | ||
2146 | if (NULL == client->drop_task) | ||
2147 | { | ||
2148 | GNUNET_assert (GNUNET_NO == client->needs_continue); | ||
2149 | GNUNET_SERVICE_client_drop (client); | ||
2150 | } | ||
2151 | return; | ||
2152 | } | ||
2153 | if (GNUNET_NO == ret) | ||
2154 | return; /* more messages in buffer, wait for application | ||
2155 | to be done processing */ | ||
2156 | GNUNET_assert (GNUNET_OK == ret); | ||
2157 | if (GNUNET_YES == client->needs_continue) | ||
2158 | return; | ||
2159 | if (NULL != client->recv_task) | ||
2160 | return; | ||
2161 | /* MST needs more data, re-schedule read job */ | ||
2162 | client->recv_task | ||
2163 | = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
2164 | client->sock, | ||
2165 | &service_client_recv, | ||
2166 | client); | ||
2167 | } | ||
2168 | |||
2169 | |||
2170 | /** | ||
2171 | * We have successfully accepted a connection from a client. Now | ||
2172 | * setup the client (with the scheduler) and tell the application. | ||
2173 | * | ||
2174 | * @param sh service that accepted the client | ||
2175 | * @param sock socket associated with the client | ||
2176 | */ | ||
2177 | static void | ||
2178 | start_client (struct GNUNET_SERVICE_Handle *sh, | ||
2179 | struct GNUNET_NETWORK_Handle *csock) | ||
2180 | { | ||
2181 | struct GNUNET_SERVICE_Client *client; | ||
2182 | |||
2183 | client = GNUNET_new (struct GNUNET_SERVICE_Client); | ||
2184 | GNUNET_CONTAINER_DLL_insert (sh->clients_head, | ||
2185 | sh->clients_tail, | ||
2186 | client); | ||
2187 | client->sh = sh; | ||
2188 | client->sock = csock; | ||
2189 | client->mq = GNUNET_MQ_queue_for_callbacks (&service_mq_send, | ||
2190 | NULL, | ||
2191 | &service_mq_cancel, | ||
2192 | client, | ||
2193 | sh->handlers, | ||
2194 | &service_mq_error_handler, | ||
2195 | client); | ||
2196 | client->mst = GNUNET_MST_create (&service_client_mst_cb, | ||
2197 | client); | ||
2198 | if (NULL != sh->connect_cb) | ||
2199 | client->user_context = sh->connect_cb (sh->cb_cls, | ||
2200 | client, | ||
2201 | client->mq); | ||
2202 | GNUNET_MQ_set_handlers_closure (client->mq, | ||
2203 | client->user_context); | ||
2204 | client->recv_task | ||
2205 | = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
2206 | client->sock, | ||
2207 | &service_client_recv, | ||
2208 | client); | ||
2209 | } | ||
2210 | |||
2211 | |||
2212 | /** | ||
2213 | * Check if the given IP address is in the list of IP addresses. | ||
2214 | * | ||
2215 | * @param list a list of networks | ||
2216 | * @param add the IP to check (in network byte order) | ||
2217 | * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is | ||
2218 | */ | ||
2219 | static int | ||
2220 | check_ipv4_listed (const struct GNUNET_STRINGS_IPv4NetworkPolicy *list, | ||
2221 | const struct in_addr *add) | ||
2222 | { | ||
2223 | unsigned int i; | ||
2224 | |||
2225 | if (NULL == list) | ||
2226 | return GNUNET_NO; | ||
2227 | i = 0; | ||
2228 | while ( (0 != list[i].network.s_addr) || | ||
2229 | (0 != list[i].netmask.s_addr) ) | ||
2230 | { | ||
2231 | if ((add->s_addr & list[i].netmask.s_addr) == | ||
2232 | (list[i].network.s_addr & list[i].netmask.s_addr)) | ||
2233 | return GNUNET_YES; | ||
2234 | i++; | ||
2235 | } | ||
2236 | return GNUNET_NO; | ||
2237 | } | ||
2238 | |||
2239 | |||
2240 | /** | ||
2241 | * Check if the given IP address is in the list of IP addresses. | ||
2242 | * | ||
2243 | * @param list a list of networks | ||
2244 | * @param ip the IP to check (in network byte order) | ||
2245 | * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is | ||
2246 | */ | ||
2247 | static int | ||
2248 | check_ipv6_listed (const struct GNUNET_STRINGS_IPv6NetworkPolicy *list, | ||
2249 | const struct in6_addr *ip) | ||
2250 | { | ||
2251 | unsigned int i; | ||
2252 | unsigned int j; | ||
2253 | struct in6_addr zero; | ||
2254 | |||
2255 | if (NULL == list) | ||
2256 | return GNUNET_NO; | ||
2257 | memset (&zero, | ||
2258 | 0, | ||
2259 | sizeof (struct in6_addr)); | ||
2260 | i = 0; | ||
2261 | NEXT: | ||
2262 | while (0 != memcmp (&zero, | ||
2263 | &list[i].network, | ||
2264 | sizeof (struct in6_addr))) | ||
2265 | { | ||
2266 | for (j = 0; j < sizeof (struct in6_addr) / sizeof (int); j++) | ||
2267 | if (((((int *) ip)[j] & ((int *) &list[i].netmask)[j])) != | ||
2268 | (((int *) &list[i].network)[j] & ((int *) &list[i].netmask)[j])) | ||
2269 | { | ||
2270 | i++; | ||
2271 | goto NEXT; | ||
2272 | } | ||
2273 | return GNUNET_YES; | ||
2274 | } | ||
2275 | return GNUNET_NO; | ||
2276 | } | ||
2277 | |||
2278 | |||
2279 | /** | ||
2280 | * We have a client. Accept the incoming socket(s) (and reschedule | ||
2281 | * the listen task). | ||
2282 | * | ||
2283 | * @param cls the `struct ServiceListenContext` of the ready listen socket | ||
2284 | */ | ||
2285 | static void | ||
2286 | accept_client (void *cls) | ||
2287 | { | ||
2288 | struct ServiceListenContext *slc = cls; | ||
2289 | struct GNUNET_SERVICE_Handle *sh = slc->sh; | ||
2290 | |||
2291 | slc->listen_task = NULL; | ||
2292 | while (1) | ||
2293 | { | ||
2294 | struct GNUNET_NETWORK_Handle *sock; | ||
2295 | const struct sockaddr_in *v4; | ||
2296 | const struct sockaddr_in6 *v6; | ||
2297 | struct sockaddr_storage sa; | ||
2298 | socklen_t addrlen; | ||
2299 | int ok; | ||
2300 | |||
2301 | addrlen = sizeof (sa); | ||
2302 | sock = GNUNET_NETWORK_socket_accept (slc->listen_socket, | ||
2303 | (struct sockaddr *) &sa, | ||
2304 | &addrlen); | ||
2305 | if (NULL == sock) | ||
2306 | break; | ||
2307 | switch (sa.ss_family) | ||
2308 | { | ||
2309 | case AF_INET: | ||
2310 | GNUNET_assert (addrlen == sizeof (struct sockaddr_in)); | ||
2311 | v4 = (const struct sockaddr_in *) &sa; | ||
2312 | ok = ( ( (NULL == sh->v4_allowed) || | ||
2313 | (check_ipv4_listed (sh->v4_allowed, | ||
2314 | &v4->sin_addr))) && | ||
2315 | ( (NULL == sh->v4_denied) || | ||
2316 | (! check_ipv4_listed (sh->v4_denied, | ||
2317 | &v4->sin_addr)) ) ); | ||
2318 | break; | ||
2319 | case AF_INET6: | ||
2320 | GNUNET_assert (addrlen == sizeof (struct sockaddr_in6)); | ||
2321 | v6 = (const struct sockaddr_in6 *) &sa; | ||
2322 | ok = ( ( (NULL == sh->v6_allowed) || | ||
2323 | (check_ipv6_listed (sh->v6_allowed, | ||
2324 | &v6->sin6_addr))) && | ||
2325 | ( (NULL == sh->v6_denied) || | ||
2326 | (! check_ipv6_listed (sh->v6_denied, | ||
2327 | &v6->sin6_addr)) ) ); | ||
2328 | break; | ||
2329 | #ifndef WINDOWS | ||
2330 | case AF_UNIX: | ||
2331 | ok = GNUNET_OK; /* controlled using file-system ACL now */ | ||
2332 | break; | ||
2333 | #endif | ||
2334 | default: | ||
2335 | LOG (GNUNET_ERROR_TYPE_WARNING, | ||
2336 | _("Unknown address family %d\n"), | ||
2337 | sa.ss_family); | ||
2338 | return; | ||
2339 | } | ||
2340 | if (! ok) | ||
2341 | { | ||
2342 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2343 | "Service rejected incoming connection from %s due to policy.\n", | ||
2344 | GNUNET_a2s ((const struct sockaddr *) &sa, | ||
2345 | addrlen)); | ||
2346 | GNUNET_break (GNUNET_OK == | ||
2347 | GNUNET_NETWORK_socket_close (sock)); | ||
2348 | continue; | ||
2349 | } | ||
2350 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
2351 | "Service accepted incoming connection from %s.\n", | ||
2352 | GNUNET_a2s ((const struct sockaddr *) &sa, | ||
2353 | addrlen)); | ||
2354 | start_client (slc->sh, | ||
2355 | sock); | ||
2356 | } | ||
2357 | slc->listen_task | ||
2358 | = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
2359 | slc->listen_socket, | ||
2360 | &accept_client, | ||
2361 | slc); | ||
2362 | } | ||
2363 | |||
2364 | |||
2365 | /** | ||
2366 | * Resume accepting connections from the listen socket. | ||
2367 | * | ||
2368 | * @param sh service to resume accepting connections. | ||
2369 | */ | ||
2370 | void | ||
2371 | GNUNET_SERVICE_resume (struct GNUNET_SERVICE_Handle *sh) | ||
2372 | { | ||
2373 | struct ServiceListenContext *slc; | ||
2374 | |||
2375 | for (slc = sh->slc_head; NULL != slc; slc = slc->next) | ||
2376 | { | ||
2377 | GNUNET_assert (NULL == slc->listen_task); | ||
2378 | slc->listen_task | ||
2379 | = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
2380 | slc->listen_socket, | ||
2381 | &accept_client, | ||
2382 | slc); | ||
2383 | } | ||
2384 | } | ||
2385 | |||
2386 | |||
2387 | /** | ||
2388 | * Task run to resume receiving data from the client after | ||
2389 | * the client called #GNUNET_SERVICE_client_continue(). | ||
2390 | * | ||
2391 | * @param cls our `struct GNUNET_SERVICE_Client` | ||
2392 | */ | ||
2393 | static void | ||
2394 | resume_client_receive (void *cls) | ||
2395 | { | ||
2396 | struct GNUNET_SERVICE_Client *c = cls; | ||
2397 | int ret; | ||
2398 | |||
2399 | c->recv_task = NULL; | ||
2400 | /* first, check if there is still something in the buffer */ | ||
2401 | ret = GNUNET_MST_next (c->mst, | ||
2402 | GNUNET_YES); | ||
2403 | if (GNUNET_SYSERR == ret) | ||
2404 | { | ||
2405 | if (NULL != c->drop_task) | ||
2406 | GNUNET_SERVICE_client_drop (c); | ||
2407 | return; | ||
2408 | } | ||
2409 | if (GNUNET_NO == ret) | ||
2410 | return; /* done processing, wait for more later */ | ||
2411 | GNUNET_assert (GNUNET_OK == ret); | ||
2412 | if (GNUNET_YES == c->needs_continue) | ||
2413 | return; /* #GNUNET_MST_next() did give a message to the client */ | ||
2414 | /* need to receive more data from the network first */ | ||
2415 | if (NULL != c->recv_task) | ||
2416 | return; | ||
2417 | c->recv_task | ||
2418 | = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
2419 | c->sock, | ||
2420 | &service_client_recv, | ||
2421 | c); | ||
2422 | } | ||
2423 | |||
2424 | |||
2425 | /** | ||
2426 | * Continue receiving further messages from the given client. | ||
2427 | * Must be called after each message received. | ||
2428 | * | ||
2429 | * @param c the client to continue receiving from | ||
2430 | */ | ||
2431 | void | ||
2432 | GNUNET_SERVICE_client_continue (struct GNUNET_SERVICE_Client *c) | ||
2433 | { | ||
2434 | GNUNET_assert (GNUNET_YES == c->needs_continue); | ||
2435 | GNUNET_assert (NULL == c->recv_task); | ||
2436 | c->needs_continue = GNUNET_NO; | ||
2437 | if (NULL != c->warn_task) | ||
2438 | { | ||
2439 | GNUNET_SCHEDULER_cancel (c->warn_task); | ||
2440 | c->warn_task = NULL; | ||
2441 | } | ||
2442 | c->recv_task | ||
2443 | = GNUNET_SCHEDULER_add_now (&resume_client_receive, | ||
2444 | c); | ||
2445 | } | ||
2446 | |||
2447 | |||
2448 | /** | ||
2449 | * Disable the warning the server issues if a message is not | ||
2450 | * acknowledged in a timely fashion. Use this call if a client is | ||
2451 | * intentionally delayed for a while. Only applies to the current | ||
2452 | * message. | ||
2453 | * | ||
2454 | * @param c client for which to disable the warning | ||
2455 | */ | ||
2456 | void | ||
2457 | GNUNET_SERVICE_client_disable_continue_warning (struct GNUNET_SERVICE_Client *c) | ||
2458 | { | ||
2459 | GNUNET_break (NULL != c->warn_task); | ||
2460 | if (NULL != c->warn_task) | ||
2461 | { | ||
2462 | GNUNET_SCHEDULER_cancel (c->warn_task); | ||
2463 | c->warn_task = NULL; | ||
2464 | } | ||
2465 | } | ||
2466 | |||
2467 | |||
2468 | /** | ||
2469 | * Asynchronously finish dropping the client. | ||
2470 | * | ||
2471 | * @param cls the `struct GNUNET_SERVICE_Client`. | ||
2472 | */ | ||
2473 | static void | ||
2474 | finish_client_drop (void *cls) | ||
2475 | { | ||
2476 | struct GNUNET_SERVICE_Client *c = cls; | ||
2477 | struct GNUNET_SERVICE_Handle *sh = c->sh; | ||
2478 | |||
2479 | c->drop_task = NULL; | ||
2480 | GNUNET_assert (NULL == c->send_task); | ||
2481 | GNUNET_assert (NULL == c->recv_task); | ||
2482 | GNUNET_assert (NULL == c->warn_task); | ||
2483 | GNUNET_MST_destroy (c->mst); | ||
2484 | GNUNET_MQ_destroy (c->mq); | ||
2485 | if (GNUNET_NO == c->persist) | ||
2486 | { | ||
2487 | GNUNET_break (GNUNET_OK == | ||
2488 | GNUNET_NETWORK_socket_close (c->sock)); | ||
2489 | } | ||
2490 | else | ||
2491 | { | ||
2492 | GNUNET_NETWORK_socket_free_memory_only_ (c->sock); | ||
2493 | } | ||
2494 | GNUNET_free (c); | ||
2495 | if ( (GNUNET_YES == sh->got_shutdown) && | ||
2496 | (GNUNET_NO == have_non_monitor_clients (sh)) ) | ||
2497 | GNUNET_SERVICE_shutdown (sh); | ||
2498 | } | ||
2499 | |||
2500 | |||
2501 | /** | ||
2502 | * Ask the server to disconnect from the given client. This is the | ||
2503 | * same as returning #GNUNET_SYSERR within the check procedure when | ||
2504 | * handling a message, wexcept that it allows dropping of a client even | ||
2505 | * when not handling a message from that client. The `disconnect_cb` | ||
2506 | * will be called on @a c even if the application closes the connection | ||
2507 | * using this function. | ||
2508 | * | ||
2509 | * @param c client to disconnect now | ||
2510 | */ | ||
2511 | void | ||
2512 | GNUNET_SERVICE_client_drop (struct GNUNET_SERVICE_Client *c) | ||
2513 | { | ||
2514 | struct GNUNET_SERVICE_Handle *sh = c->sh; | ||
2515 | |||
2516 | if (NULL != c->drop_task) | ||
2517 | { | ||
2518 | /* asked to drop twice! */ | ||
2519 | GNUNET_assert (0); | ||
2520 | return; | ||
2521 | } | ||
2522 | GNUNET_CONTAINER_DLL_remove (sh->clients_head, | ||
2523 | sh->clients_tail, | ||
2524 | c); | ||
2525 | if (NULL != sh->disconnect_cb) | ||
2526 | sh->disconnect_cb (sh->cb_cls, | ||
2527 | c, | ||
2528 | c->user_context); | ||
2529 | if (NULL != c->warn_task) | ||
2530 | { | ||
2531 | GNUNET_SCHEDULER_cancel (c->warn_task); | ||
2532 | c->warn_task = NULL; | ||
2533 | } | ||
2534 | if (NULL != c->recv_task) | ||
2535 | { | ||
2536 | GNUNET_SCHEDULER_cancel (c->recv_task); | ||
2537 | c->recv_task = NULL; | ||
2538 | } | ||
2539 | if (NULL != c->send_task) | ||
2540 | { | ||
2541 | GNUNET_SCHEDULER_cancel (c->send_task); | ||
2542 | c->send_task = NULL; | ||
2543 | } | ||
2544 | c->drop_task = GNUNET_SCHEDULER_add_now (&finish_client_drop, | ||
2545 | c); | ||
2546 | } | ||
2547 | |||
2548 | |||
2549 | /** | ||
2550 | * Explicitly stops the service. | ||
2551 | * | ||
2552 | * @param sh server to shutdown | ||
2553 | */ | ||
2554 | void | ||
2555 | GNUNET_SERVICE_shutdown (struct GNUNET_SERVICE_Handle *sh) | ||
2556 | { | ||
2557 | struct GNUNET_SERVICE_Client *client; | ||
2558 | |||
2559 | GNUNET_SERVICE_suspend (sh); | ||
2560 | sh->got_shutdown = GNUNET_NO; | ||
2561 | while (NULL != (client = sh->clients_head)) | ||
2562 | GNUNET_SERVICE_client_drop (client); | ||
2563 | } | ||
2564 | |||
2565 | |||
2566 | /** | ||
2567 | * Set the 'monitor' flag on this client. Clients which have been | ||
2568 | * marked as 'monitors' won't prevent the server from shutting down | ||
2569 | * once #GNUNET_SERVICE_stop_listening() has been invoked. The idea is | ||
2570 | * that for "normal" clients we likely want to allow them to process | ||
2571 | * their requests; however, monitor-clients are likely to 'never' | ||
2572 | * disconnect during shutdown and thus will not be considered when | ||
2573 | * determining if the server should continue to exist after | ||
2574 | * shutdown has been triggered. | ||
2575 | * | ||
2576 | * @param c client to mark as a monitor | ||
2577 | */ | ||
2578 | void | ||
2579 | GNUNET_SERVICE_client_mark_monitor (struct GNUNET_SERVICE_Client *c) | ||
2580 | { | ||
2581 | c->is_monitor = GNUNET_YES; | ||
2582 | if ( (GNUNET_YES == c->sh->got_shutdown) && | ||
2583 | (GNUNET_NO == have_non_monitor_clients (c->sh)) ) | ||
2584 | GNUNET_SERVICE_shutdown (c->sh); | ||
2585 | } | ||
2586 | |||
2587 | |||
2588 | /** | ||
2589 | * Set the persist option on this client. Indicates that the | ||
2590 | * underlying socket or fd should never really be closed. Used for | ||
2591 | * indicating process death. | ||
2592 | * | ||
2593 | * @param c client to persist the socket (never to be closed) | ||
2594 | */ | ||
2595 | void | ||
2596 | GNUNET_SERVICE_client_persist (struct GNUNET_SERVICE_Client *c) | ||
2597 | { | ||
2598 | c->persist = GNUNET_YES; | ||
2599 | } | ||
2600 | |||
2601 | |||
2602 | /** | ||
2603 | * Obtain the message queue of @a c. Convenience function. | ||
2604 | * | ||
2605 | * @param c the client to continue receiving from | ||
2606 | * @return the message queue of @a c | ||
2607 | */ | ||
2608 | struct GNUNET_MQ_Handle * | ||
2609 | GNUNET_SERVICE_client_get_mq (struct GNUNET_SERVICE_Client *c) | ||
2610 | { | ||
2611 | return c->mq; | ||
2612 | } | ||
2613 | |||
2614 | |||
2615 | /* end of service_new.c */ | ||
diff --git a/src/util/socks.c b/src/util/socks.c index 37e60e3e4..85548fd79 100644 --- a/src/util/socks.c +++ b/src/util/socks.c | |||
@@ -372,15 +372,18 @@ transmit_ready (void *cls, | |||
372 | return 0; | 372 | return 0; |
373 | } | 373 | } |
374 | 374 | ||
375 | GNUNET_assert (1024 >= size && size > 0); | 375 | GNUNET_assert ( (1024 >= size) && (size > 0) ); |
376 | GNUNET_assert (SOCKS5_step_done > ih->step && ih->step >= 0); | 376 | GNUNET_assert ( (SOCKS5_step_done > ih->step) && (ih->step >= 0) ); |
377 | unsigned char * b = ih->outstep[ih->step]; | 377 | unsigned char * b = ih->outstep[ih->step]; |
378 | unsigned char * e = ih->outstep[ih->step+1]; | 378 | unsigned char * e = ih->outstep[ih->step+1]; |
379 | GNUNET_assert (e <= &ih->outbuf[1024]); | 379 | GNUNET_assert (e <= &ih->outbuf[1024]); |
380 | unsigned l = e - b; | 380 | unsigned int l = e - b; |
381 | GNUNET_assert (size >= l && l >= 0); | 381 | GNUNET_assert (size >= l); |
382 | GNUNET_memcpy(buf, b, l); | 382 | GNUNET_memcpy (buf, |
383 | register_reciever (ih, register_reciever_wants(ih)); | 383 | b, |
384 | l); | ||
385 | register_reciever (ih, | ||
386 | register_reciever_wants (ih)); | ||
384 | return l; | 387 | return l; |
385 | } | 388 | } |
386 | 389 | ||
@@ -566,17 +569,25 @@ GNUNET_SOCKS_check_service (const char *service_name, | |||
566 | */ | 569 | */ |
567 | struct GNUNET_CONNECTION_Handle * | 570 | struct GNUNET_CONNECTION_Handle * |
568 | GNUNET_SOCKS_do_connect (const char *service_name, | 571 | GNUNET_SOCKS_do_connect (const char *service_name, |
569 | const struct GNUNET_CONFIGURATION_Handle *cfg) | 572 | const struct GNUNET_CONFIGURATION_Handle *cfg) |
570 | { | 573 | { |
571 | struct GNUNET_SOCKS_Handshake *ih; | 574 | struct GNUNET_SOCKS_Handshake *ih; |
572 | struct GNUNET_CONNECTION_Handle *socks5; /* *proxied */ | 575 | struct GNUNET_CONNECTION_Handle *socks5; /* *proxied */ |
573 | char *host0,*host1,*user,*pass; | 576 | char *host0; |
574 | unsigned long long port0,port1; | 577 | char *host1; |
575 | 578 | char *user; | |
576 | if (GNUNET_YES != GNUNET_SOCKS_check_service (service_name, cfg)) | 579 | char *pass; |
580 | unsigned long long port0; | ||
581 | unsigned long long port1; | ||
582 | |||
583 | if (GNUNET_YES != | ||
584 | GNUNET_SOCKS_check_service (service_name, cfg)) | ||
577 | return NULL; | 585 | return NULL; |
578 | if (GNUNET_OK != | 586 | if (GNUNET_OK != |
579 | GNUNET_CONFIGURATION_get_value_number (cfg, service_name, "SOCKSPORT", &port0)) | 587 | GNUNET_CONFIGURATION_get_value_number (cfg, |
588 | service_name, | ||
589 | "SOCKSPORT", | ||
590 | &port0)) | ||
580 | port0 = 9050; | 591 | port0 = 9050; |
581 | /* A typical Tor client should usually try port 9150 for the TBB too, but | 592 | /* A typical Tor client should usually try port 9150 for the TBB too, but |
582 | * GNUnet can probably assume a system Tor installation. */ | 593 | * GNUnet can probably assume a system Tor installation. */ |
@@ -588,16 +599,23 @@ GNUNET_SOCKS_do_connect (const char *service_name, | |||
588 | service_name); | 599 | service_name); |
589 | return NULL; | 600 | return NULL; |
590 | } | 601 | } |
591 | if ((GNUNET_OK != | 602 | if ( (GNUNET_OK != |
592 | GNUNET_CONFIGURATION_get_value_number (cfg, service_name, "PORT", &port1)) | 603 | GNUNET_CONFIGURATION_get_value_number (cfg, |
593 | || (port1 > 65535) || (port1 <= 0) || | 604 | service_name, |
605 | "PORT", | ||
606 | &port1)) || | ||
607 | (port1 > 65535) || | ||
608 | (port1 <= 0) || | ||
594 | (GNUNET_OK != | 609 | (GNUNET_OK != |
595 | GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "HOSTNAME", &host1))) | 610 | GNUNET_CONFIGURATION_get_value_string (cfg, |
611 | service_name, | ||
612 | "HOSTNAME", | ||
613 | &host1))) | ||
596 | { | 614 | { |
597 | LOG (GNUNET_ERROR_TYPE_WARNING, | 615 | LOG (GNUNET_ERROR_TYPE_WARNING, |
598 | _ | 616 | _("Attempting to proxy service `%s' to invalid port %d or hostname.\n"), |
599 | ("Attempting to proxy service `%s' to invalid port %d or hostname `%s'.\n"), | 617 | service_name, |
600 | service_name,port1,host1); | 618 | port1); |
601 | return NULL; | 619 | return NULL; |
602 | } | 620 | } |
603 | /* Appeared to still work after host0 corrupted, so either test case is broken, or | 621 | /* Appeared to still work after host0 corrupted, so either test case is broken, or |
@@ -605,20 +623,32 @@ GNUNET_SOCKS_do_connect (const char *service_name, | |||
605 | if (GNUNET_OK != | 623 | if (GNUNET_OK != |
606 | GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "SOCKSHOST", &host0)) | 624 | GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "SOCKSHOST", &host0)) |
607 | host0 = NULL; | 625 | host0 = NULL; |
608 | socks5 = GNUNET_CONNECTION_create_from_connect (cfg, (host0 != NULL)? host0:"127.0.0.1", port0); | 626 | socks5 = GNUNET_CONNECTION_create_from_connect (cfg, |
627 | (host0 != NULL) | ||
628 | ? host0 | ||
629 | :"127.0.0.1", | ||
630 | port0); | ||
609 | GNUNET_free_non_null (host0); | 631 | GNUNET_free_non_null (host0); |
610 | 632 | ||
611 | /* Sets to NULL if they do not exist */ | 633 | /* Sets to NULL if they do not exist */ |
612 | (void) GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "SOCKSUSER", &user); | 634 | (void) GNUNET_CONFIGURATION_get_value_string (cfg, |
613 | (void) GNUNET_CONFIGURATION_get_value_string (cfg, service_name, "SOCKSPASS", &pass); | 635 | service_name, |
636 | "SOCKSUSER", | ||
637 | &user); | ||
638 | (void) GNUNET_CONFIGURATION_get_value_string (cfg, | ||
639 | service_name, | ||
640 | "SOCKSPASS", | ||
641 | &pass); | ||
614 | ih = GNUNET_SOCKS_init_handshake(user,pass); | 642 | ih = GNUNET_SOCKS_init_handshake(user,pass); |
615 | if (NULL != user) GNUNET_free (user); | 643 | GNUNET_free_non_null (user); |
616 | if (NULL != pass) GNUNET_free (pass); | 644 | GNUNET_free_non_null (pass); |
617 | 645 | ||
618 | GNUNET_SOCKS_set_handshake_destination (ih,host1,port1); | 646 | GNUNET_SOCKS_set_handshake_destination (ih, |
647 | host1, | ||
648 | port1); | ||
619 | GNUNET_free (host1); | 649 | GNUNET_free (host1); |
620 | 650 | return GNUNET_SOCKS_run_handshake (ih, | |
621 | return GNUNET_SOCKS_run_handshake(ih,socks5); | 651 | socks5); |
622 | } | 652 | } |
623 | 653 | ||
624 | /* socks.c */ | 654 | /* socks.c */ |
diff --git a/src/util/test_client.c b/src/util/test_client.c index f60e5b7f7..527b400b0 100644 --- a/src/util/test_client.c +++ b/src/util/test_client.c | |||
@@ -179,7 +179,7 @@ main (int argc, | |||
179 | test_argv[2] = "test_client_unix.conf"; | 179 | test_argv[2] = "test_client_unix.conf"; |
180 | global_ret = 1; | 180 | global_ret = 1; |
181 | if (0 != | 181 | if (0 != |
182 | GNUNET_SERVICE_ruN_ (3, | 182 | GNUNET_SERVICE_run_ (3, |
183 | test_argv, | 183 | test_argv, |
184 | "test_client", | 184 | "test_client", |
185 | GNUNET_SERVICE_OPTION_NONE, | 185 | GNUNET_SERVICE_OPTION_NONE, |
diff --git a/src/util/test_common_allocation.c b/src/util/test_common_allocation.c index 4ef98b629..4d1b6fe7d 100644 --- a/src/util/test_common_allocation.c +++ b/src/util/test_common_allocation.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet. | 2 | This file is part of GNUnet. |
3 | Copyright (C) 2001, 2002, 2003, 2005, 2006 GNUnet e.V. | 3 | Copyright (C) 2001, 2002, 2003, 2005, 2006, 2017 GNUnet e.V. |
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 |
@@ -25,6 +25,7 @@ | |||
25 | #include "platform.h" | 25 | #include "platform.h" |
26 | #include "gnunet_util_lib.h" | 26 | #include "gnunet_util_lib.h" |
27 | 27 | ||
28 | |||
28 | static int | 29 | static int |
29 | check () | 30 | check () |
30 | { | 31 | { |
@@ -95,47 +96,57 @@ check () | |||
95 | if (ptrs[0] != NULL) | 96 | if (ptrs[0] != NULL) |
96 | return 9; | 97 | return 9; |
97 | 98 | ||
98 | /* GNUNET_new_array_2d tests */ | 99 | /* GNUNET_new_array_2d tests */ |
99 | a2 = GNUNET_new_array_2d (17, 22, unsigned int); | 100 | a2 = GNUNET_new_array_2d (17, 22, unsigned int); |
100 | for (i = 0; i < 17; i++) | 101 | for (i = 0; i < 17; i++) |
101 | { | 102 | { |
102 | for (j = 0; j < 22; j++) | 103 | for (j = 0; j < 22; j++) |
103 | { | 104 | { |
104 | if (0 != a2[i][j]) | 105 | if (0 != a2[i][j]) |
105 | return 10; | 106 | { |
106 | a2[i][j] = i * 100 + j; | 107 | GNUNET_free (a2); |
107 | } | 108 | return 10; |
108 | } | 109 | } |
109 | free (a2); | 110 | a2[i][j] = i * 100 + j; |
110 | 111 | } | |
111 | /* GNUNET_new_array_3d tests */ | 112 | } |
112 | a3 = GNUNET_new_array_3d (2, 3, 4, char); | 113 | GNUNET_free (a2); |
113 | for (i = 0; i < 2; i++) | ||
114 | { | ||
115 | for (j = 0; j < 3; j++) | ||
116 | { | ||
117 | for (k = 0; k < 4; k++) | ||
118 | { | ||
119 | if (0 != a3[i][j][k]) | ||
120 | return 11; | ||
121 | a3[i][j][k] = i * 100 + j * 10 + k; | ||
122 | } | ||
123 | } | ||
124 | } | ||
125 | free (a3); | ||
126 | 114 | ||
115 | /* GNUNET_new_array_3d tests */ | ||
116 | a3 = GNUNET_new_array_3d (2, 3, 4, char); | ||
117 | for (i = 0; i < 2; i++) | ||
118 | { | ||
119 | for (j = 0; j < 3; j++) | ||
120 | { | ||
121 | for (k = 0; k < 4; k++) | ||
122 | { | ||
123 | if (0 != a3[i][j][k]) | ||
124 | { | ||
125 | GNUNET_free (a3); | ||
126 | return 11; | ||
127 | } | ||
128 | a3[i][j][k] = i * 100 + j * 10 + k; | ||
129 | } | ||
130 | } | ||
131 | } | ||
132 | GNUNET_free (a3); | ||
127 | return 0; | 133 | return 0; |
128 | } | 134 | } |
129 | 135 | ||
136 | |||
130 | int | 137 | int |
131 | main (int argc, char *argv[]) | 138 | main (int argc, char *argv[]) |
132 | { | 139 | { |
133 | int ret; | 140 | int ret; |
134 | 141 | ||
135 | GNUNET_log_setup ("test-common-allocation", "WARNING", NULL); | 142 | GNUNET_log_setup ("test-common-allocation", |
143 | "WARNING", | ||
144 | NULL); | ||
136 | ret = check (); | 145 | ret = check (); |
137 | if (ret != 0) | 146 | if (ret != 0) |
138 | FPRINTF (stderr, "ERROR %d.\n", ret); | 147 | FPRINTF (stderr, |
148 | "ERROR %d.\n", | ||
149 | ret); | ||
139 | return ret; | 150 | return ret; |
140 | } | 151 | } |
141 | 152 | ||
diff --git a/src/util/test_connection.c b/src/util/test_connection.c deleted file mode 100644 index eaca75c2e..000000000 --- a/src/util/test_connection.c +++ /dev/null | |||
@@ -1,167 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009 GNUnet e.V. | ||
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., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | /** | ||
21 | * @file util/test_connection.c | ||
22 | * @brief tests for connection.c | ||
23 | */ | ||
24 | #include "platform.h" | ||
25 | #include "gnunet_util_lib.h" | ||
26 | |||
27 | #define PORT 12435 | ||
28 | |||
29 | |||
30 | static struct GNUNET_CONNECTION_Handle *csock; | ||
31 | |||
32 | static struct GNUNET_CONNECTION_Handle *asock; | ||
33 | |||
34 | static struct GNUNET_CONNECTION_Handle *lsock; | ||
35 | |||
36 | static size_t sofar; | ||
37 | |||
38 | static struct GNUNET_NETWORK_Handle *ls; | ||
39 | |||
40 | static struct GNUNET_CONFIGURATION_Handle *cfg; | ||
41 | |||
42 | /** | ||
43 | * Create and initialize a listen socket for the server. | ||
44 | * | ||
45 | * @return -1 on error, otherwise the listen socket | ||
46 | */ | ||
47 | static struct GNUNET_NETWORK_Handle * | ||
48 | open_listen_socket () | ||
49 | { | ||
50 | const static int on = 1; | ||
51 | struct sockaddr_in sa; | ||
52 | struct GNUNET_NETWORK_Handle *desc; | ||
53 | |||
54 | memset (&sa, 0, sizeof (sa)); | ||
55 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
56 | sa.sin_len = sizeof (sa); | ||
57 | #endif | ||
58 | sa.sin_port = htons (PORT); | ||
59 | sa.sin_family = AF_INET; | ||
60 | desc = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0); | ||
61 | GNUNET_assert (desc != NULL); | ||
62 | if (GNUNET_NETWORK_socket_setsockopt | ||
63 | (desc, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK) | ||
64 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "setsockopt"); | ||
65 | GNUNET_assert (GNUNET_OK == | ||
66 | GNUNET_NETWORK_socket_bind (desc, (const struct sockaddr *) &sa, | ||
67 | sizeof (sa))); | ||
68 | GNUNET_NETWORK_socket_listen (desc, 5); | ||
69 | return desc; | ||
70 | } | ||
71 | |||
72 | static void | ||
73 | receive_check (void *cls, const void *buf, size_t available, | ||
74 | const struct sockaddr *addr, socklen_t addrlen, int errCode) | ||
75 | { | ||
76 | int *ok = cls; | ||
77 | |||
78 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receive validates incoming data\n"); | ||
79 | GNUNET_assert (buf != NULL); /* no timeout */ | ||
80 | if (0 == memcmp (&"Hello World"[sofar], buf, available)) | ||
81 | sofar += available; | ||
82 | if (sofar < 12) | ||
83 | { | ||
84 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receive needs more data\n"); | ||
85 | GNUNET_CONNECTION_receive (asock, 1024, | ||
86 | GNUNET_TIME_relative_multiply | ||
87 | (GNUNET_TIME_UNIT_SECONDS, 5), &receive_check, | ||
88 | cls); | ||
89 | } | ||
90 | else | ||
91 | { | ||
92 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receive closes accepted socket\n"); | ||
93 | *ok = 0; | ||
94 | GNUNET_CONNECTION_destroy (asock); | ||
95 | GNUNET_CONNECTION_destroy (csock); | ||
96 | } | ||
97 | } | ||
98 | |||
99 | |||
100 | static void | ||
101 | run_accept (void *cls) | ||
102 | { | ||
103 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test accepts connection\n"); | ||
104 | asock = GNUNET_CONNECTION_create_from_accept (NULL, NULL, ls); | ||
105 | GNUNET_assert (asock != NULL); | ||
106 | GNUNET_assert (GNUNET_YES == GNUNET_CONNECTION_check (asock)); | ||
107 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test destroys listen socket\n"); | ||
108 | GNUNET_CONNECTION_destroy (lsock); | ||
109 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
110 | "Test asks to receive on accepted socket\n"); | ||
111 | GNUNET_CONNECTION_receive (asock, 1024, | ||
112 | GNUNET_TIME_relative_multiply | ||
113 | (GNUNET_TIME_UNIT_SECONDS, 5), &receive_check, | ||
114 | cls); | ||
115 | } | ||
116 | |||
117 | |||
118 | static size_t | ||
119 | make_hello (void *cls, size_t size, void *buf) | ||
120 | { | ||
121 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
122 | "Test prepares to transmit on connect socket\n"); | ||
123 | GNUNET_assert (size >= 12); | ||
124 | strcpy ((char *) buf, "Hello World"); | ||
125 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test destroys client socket\n"); | ||
126 | return 12; | ||
127 | } | ||
128 | |||
129 | |||
130 | static void | ||
131 | task (void *cls) | ||
132 | { | ||
133 | ls = open_listen_socket (); | ||
134 | lsock = GNUNET_CONNECTION_create_from_existing (ls); | ||
135 | GNUNET_assert (lsock != NULL); | ||
136 | csock = GNUNET_CONNECTION_create_from_connect (cfg, "localhost", PORT); | ||
137 | GNUNET_assert (csock != NULL); | ||
138 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test asks for write notification\n"); | ||
139 | GNUNET_assert (NULL != | ||
140 | GNUNET_CONNECTION_notify_transmit_ready (csock, 12, | ||
141 | GNUNET_TIME_UNIT_SECONDS, | ||
142 | &make_hello, NULL)); | ||
143 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Test prepares to accept\n"); | ||
144 | GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, ls, &run_accept, | ||
145 | cls); | ||
146 | } | ||
147 | |||
148 | |||
149 | int | ||
150 | main (int argc, char *argv[]) | ||
151 | { | ||
152 | int ok; | ||
153 | |||
154 | GNUNET_log_setup ("test_connection", | ||
155 | "WARNING", | ||
156 | NULL); | ||
157 | |||
158 | ok = 1; | ||
159 | cfg = GNUNET_CONFIGURATION_create (); | ||
160 | GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME", | ||
161 | "localhost"); | ||
162 | GNUNET_SCHEDULER_run (&task, &ok); | ||
163 | GNUNET_CONFIGURATION_destroy (cfg); | ||
164 | return ok; | ||
165 | } | ||
166 | |||
167 | /* end of test_connection.c */ | ||
diff --git a/src/util/test_connection_addressing.c b/src/util/test_connection_addressing.c deleted file mode 100644 index a6345b10a..000000000 --- a/src/util/test_connection_addressing.c +++ /dev/null | |||
@@ -1,186 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009 GNUnet e.V. | ||
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., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | /** | ||
21 | * @file util/test_connection_addressing.c | ||
22 | * @brief tests for connection.c | ||
23 | */ | ||
24 | #include "platform.h" | ||
25 | #include "gnunet_util_lib.h" | ||
26 | |||
27 | |||
28 | #define PORT 12435 | ||
29 | |||
30 | |||
31 | static struct GNUNET_CONNECTION_Handle *csock; | ||
32 | |||
33 | static struct GNUNET_CONNECTION_Handle *asock; | ||
34 | |||
35 | static struct GNUNET_CONNECTION_Handle *lsock; | ||
36 | |||
37 | static size_t sofar; | ||
38 | |||
39 | static struct GNUNET_NETWORK_Handle *ls; | ||
40 | |||
41 | |||
42 | |||
43 | /** | ||
44 | * Create and initialize a listen socket for the server. | ||
45 | * | ||
46 | * @return NULL on error, otherwise the listen socket | ||
47 | */ | ||
48 | static struct GNUNET_NETWORK_Handle * | ||
49 | open_listen_socket () | ||
50 | { | ||
51 | const static int on = 1; | ||
52 | struct sockaddr_in sa; | ||
53 | struct GNUNET_NETWORK_Handle *desc; | ||
54 | |||
55 | memset (&sa, 0, sizeof (sa)); | ||
56 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
57 | sa.sin_len = sizeof (sa); | ||
58 | #endif | ||
59 | sa.sin_family = AF_INET; | ||
60 | sa.sin_port = htons (PORT); | ||
61 | desc = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0); | ||
62 | GNUNET_assert (desc != 0); | ||
63 | if (GNUNET_NETWORK_socket_setsockopt | ||
64 | (desc, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK) | ||
65 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "setsockopt"); | ||
66 | if (GNUNET_OK != | ||
67 | GNUNET_NETWORK_socket_bind (desc, (const struct sockaddr *) &sa, | ||
68 | sizeof (sa))) | ||
69 | { | ||
70 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
71 | "bind"); | ||
72 | GNUNET_assert (0); | ||
73 | } | ||
74 | GNUNET_NETWORK_socket_listen (desc, 5); | ||
75 | return desc; | ||
76 | } | ||
77 | |||
78 | |||
79 | static void | ||
80 | receive_check (void *cls, const void *buf, size_t available, | ||
81 | const struct sockaddr *addr, socklen_t addrlen, int errCode) | ||
82 | { | ||
83 | int *ok = cls; | ||
84 | |||
85 | GNUNET_assert (buf != NULL); /* no timeout */ | ||
86 | if (0 == memcmp (&"Hello World"[sofar], buf, available)) | ||
87 | sofar += available; | ||
88 | if (sofar < 12) | ||
89 | { | ||
90 | GNUNET_CONNECTION_receive (asock, 1024, | ||
91 | GNUNET_TIME_relative_multiply | ||
92 | (GNUNET_TIME_UNIT_SECONDS, 5), &receive_check, | ||
93 | cls); | ||
94 | } | ||
95 | else | ||
96 | { | ||
97 | *ok = 0; | ||
98 | GNUNET_CONNECTION_destroy (csock); | ||
99 | GNUNET_CONNECTION_destroy (asock); | ||
100 | } | ||
101 | } | ||
102 | |||
103 | |||
104 | static void | ||
105 | run_accept (void *cls) | ||
106 | { | ||
107 | void *addr; | ||
108 | size_t alen; | ||
109 | struct sockaddr_in *v4; | ||
110 | struct sockaddr_in expect; | ||
111 | |||
112 | asock = GNUNET_CONNECTION_create_from_accept (NULL, NULL, ls); | ||
113 | GNUNET_assert (asock != NULL); | ||
114 | GNUNET_assert (GNUNET_YES == GNUNET_CONNECTION_check (asock)); | ||
115 | GNUNET_assert (GNUNET_OK == | ||
116 | GNUNET_CONNECTION_get_address (asock, &addr, &alen)); | ||
117 | GNUNET_assert (alen == sizeof (struct sockaddr_in)); | ||
118 | v4 = addr; | ||
119 | memset (&expect, 0, sizeof (expect)); | ||
120 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
121 | expect.sin_len = sizeof (expect); | ||
122 | #endif | ||
123 | expect.sin_family = AF_INET; | ||
124 | expect.sin_port = v4->sin_port; | ||
125 | expect.sin_addr.s_addr = htonl (INADDR_LOOPBACK); | ||
126 | GNUNET_assert (0 == memcmp (&expect, v4, alen)); | ||
127 | GNUNET_free (addr); | ||
128 | GNUNET_CONNECTION_destroy (lsock); | ||
129 | GNUNET_CONNECTION_receive (asock, 1024, | ||
130 | GNUNET_TIME_relative_multiply | ||
131 | (GNUNET_TIME_UNIT_SECONDS, 5), &receive_check, | ||
132 | cls); | ||
133 | } | ||
134 | |||
135 | static size_t | ||
136 | make_hello (void *cls, size_t size, void *buf) | ||
137 | { | ||
138 | GNUNET_assert (size >= 12); | ||
139 | strcpy ((char *) buf, "Hello World"); | ||
140 | return 12; | ||
141 | } | ||
142 | |||
143 | |||
144 | static void | ||
145 | task (void *cls) | ||
146 | { | ||
147 | struct sockaddr_in v4; | ||
148 | |||
149 | ls = open_listen_socket (); | ||
150 | lsock = GNUNET_CONNECTION_create_from_existing (ls); | ||
151 | GNUNET_assert (lsock != NULL); | ||
152 | |||
153 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
154 | v4.sin_len = sizeof (v4); | ||
155 | #endif | ||
156 | v4.sin_family = AF_INET; | ||
157 | v4.sin_port = htons (PORT); | ||
158 | v4.sin_addr.s_addr = htonl (INADDR_LOOPBACK); | ||
159 | csock = | ||
160 | GNUNET_CONNECTION_create_from_sockaddr (AF_INET, | ||
161 | (const struct sockaddr *) &v4, | ||
162 | sizeof (v4)); | ||
163 | GNUNET_assert (csock != NULL); | ||
164 | GNUNET_assert (NULL != | ||
165 | GNUNET_CONNECTION_notify_transmit_ready (csock, 12, | ||
166 | GNUNET_TIME_UNIT_SECONDS, | ||
167 | &make_hello, NULL)); | ||
168 | GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, ls, &run_accept, | ||
169 | cls); | ||
170 | } | ||
171 | |||
172 | |||
173 | int | ||
174 | main (int argc, char *argv[]) | ||
175 | { | ||
176 | int ok; | ||
177 | |||
178 | GNUNET_log_setup ("test_connection_addressing", | ||
179 | "WARNING", | ||
180 | NULL); | ||
181 | ok = 1; | ||
182 | GNUNET_SCHEDULER_run (&task, &ok); | ||
183 | return ok; | ||
184 | } | ||
185 | |||
186 | /* end of test_connection_addressing.c */ | ||
diff --git a/src/util/test_connection_receive_cancel.c b/src/util/test_connection_receive_cancel.c deleted file mode 100644 index 9c0ab699e..000000000 --- a/src/util/test_connection_receive_cancel.c +++ /dev/null | |||
@@ -1,160 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009 GNUnet e.V. | ||
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., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | /** | ||
21 | * @file util/test_connection_receive_cancel.c | ||
22 | * @brief tests for connection.c | ||
23 | */ | ||
24 | #include "platform.h" | ||
25 | #include "gnunet_util_lib.h" | ||
26 | |||
27 | #define PORT 12435 | ||
28 | |||
29 | |||
30 | static struct GNUNET_CONNECTION_Handle *csock; | ||
31 | |||
32 | static struct GNUNET_CONNECTION_Handle *asock; | ||
33 | |||
34 | static struct GNUNET_CONNECTION_Handle *lsock; | ||
35 | |||
36 | static struct GNUNET_NETWORK_Handle *ls; | ||
37 | |||
38 | static struct GNUNET_CONFIGURATION_Handle *cfg; | ||
39 | |||
40 | |||
41 | /** | ||
42 | * Create and initialize a listen socket for the server. | ||
43 | * | ||
44 | * @return NULL on error, otherwise the listen socket | ||
45 | */ | ||
46 | static struct GNUNET_NETWORK_Handle * | ||
47 | open_listen_socket () | ||
48 | { | ||
49 | const static int on = 1; | ||
50 | struct sockaddr_in sa; | ||
51 | struct GNUNET_NETWORK_Handle *desc; | ||
52 | |||
53 | memset (&sa, 0, sizeof (sa)); | ||
54 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
55 | sa.sin_len = sizeof (sa); | ||
56 | #endif | ||
57 | sa.sin_family = AF_INET; | ||
58 | sa.sin_port = htons (PORT); | ||
59 | desc = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0); | ||
60 | GNUNET_assert (desc != NULL); | ||
61 | if (GNUNET_NETWORK_socket_setsockopt | ||
62 | (desc, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK) | ||
63 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, | ||
64 | "setsockopt"); | ||
65 | GNUNET_assert (GNUNET_OK == | ||
66 | GNUNET_NETWORK_socket_bind (desc, (const struct sockaddr *) &sa, | ||
67 | sizeof (sa))); | ||
68 | GNUNET_NETWORK_socket_listen (desc, 5); | ||
69 | return desc; | ||
70 | } | ||
71 | |||
72 | |||
73 | static void | ||
74 | dead_receive (void *cls, | ||
75 | const void *buf, | ||
76 | size_t available, | ||
77 | const struct sockaddr *addr, | ||
78 | socklen_t addrlen, | ||
79 | int errCode) | ||
80 | { | ||
81 | GNUNET_assert (0); | ||
82 | } | ||
83 | |||
84 | |||
85 | static void | ||
86 | run_accept_cancel (void *cls) | ||
87 | { | ||
88 | asock = GNUNET_CONNECTION_create_from_accept (NULL, NULL, ls); | ||
89 | GNUNET_assert (asock != NULL); | ||
90 | GNUNET_assert (GNUNET_YES == GNUNET_CONNECTION_check (asock)); | ||
91 | GNUNET_CONNECTION_destroy (lsock); | ||
92 | GNUNET_CONNECTION_receive (asock, 1024, | ||
93 | GNUNET_TIME_relative_multiply | ||
94 | (GNUNET_TIME_UNIT_SECONDS, 5), | ||
95 | &dead_receive, cls); | ||
96 | } | ||
97 | |||
98 | |||
99 | static void | ||
100 | receive_cancel_task (void *cls) | ||
101 | { | ||
102 | int *ok = cls; | ||
103 | |||
104 | GNUNET_CONNECTION_receive_cancel (asock); | ||
105 | GNUNET_CONNECTION_destroy (csock); | ||
106 | GNUNET_CONNECTION_destroy (asock); | ||
107 | *ok = 0; | ||
108 | } | ||
109 | |||
110 | |||
111 | static void | ||
112 | task_receive_cancel (void *cls) | ||
113 | { | ||
114 | ls = open_listen_socket (); | ||
115 | lsock = GNUNET_CONNECTION_create_from_existing (ls); | ||
116 | GNUNET_assert (lsock != NULL); | ||
117 | csock = GNUNET_CONNECTION_create_from_connect (cfg, "localhost", PORT); | ||
118 | GNUNET_assert (csock != NULL); | ||
119 | GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
120 | ls, | ||
121 | &run_accept_cancel, | ||
122 | cls); | ||
123 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, | ||
124 | &receive_cancel_task, | ||
125 | cls); | ||
126 | } | ||
127 | |||
128 | |||
129 | /** | ||
130 | * Main method, starts scheduler with task_timeout. | ||
131 | */ | ||
132 | static int | ||
133 | check_receive_cancel () | ||
134 | { | ||
135 | int ok; | ||
136 | |||
137 | ok = 1; | ||
138 | cfg = GNUNET_CONFIGURATION_create (); | ||
139 | GNUNET_CONFIGURATION_set_value_string (cfg, | ||
140 | "resolver", | ||
141 | "HOSTNAME", | ||
142 | "localhost"); | ||
143 | GNUNET_SCHEDULER_run (&task_receive_cancel, &ok); | ||
144 | GNUNET_CONFIGURATION_destroy (cfg); | ||
145 | return ok; | ||
146 | } | ||
147 | |||
148 | |||
149 | int | ||
150 | main (int argc, char *argv[]) | ||
151 | { | ||
152 | int ret = 0; | ||
153 | |||
154 | GNUNET_log_setup ("test_connection_receive_cancel", "WARNING", NULL); | ||
155 | ret += check_receive_cancel (); | ||
156 | |||
157 | return ret; | ||
158 | } | ||
159 | |||
160 | /* end of test_connection_receive_cancel.c */ | ||
diff --git a/src/util/test_connection_timeout.c b/src/util/test_connection_timeout.c deleted file mode 100644 index e78cec669..000000000 --- a/src/util/test_connection_timeout.c +++ /dev/null | |||
@@ -1,129 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009 GNUnet e.V. | ||
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., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | /** | ||
21 | * @file util/test_connection_timeout.c | ||
22 | * @brief tests for connection.c | ||
23 | */ | ||
24 | #include "platform.h" | ||
25 | #include "gnunet_util_lib.h" | ||
26 | |||
27 | #define PORT 12435 | ||
28 | |||
29 | static struct GNUNET_CONNECTION_Handle *csock; | ||
30 | |||
31 | static struct GNUNET_CONNECTION_Handle *lsock; | ||
32 | |||
33 | static struct GNUNET_NETWORK_Handle *ls; | ||
34 | |||
35 | static struct GNUNET_CONFIGURATION_Handle *cfg; | ||
36 | |||
37 | |||
38 | /** | ||
39 | * Create and initialize a listen socket for the server. | ||
40 | * | ||
41 | * @return NULL on error, otherwise the listen socket | ||
42 | */ | ||
43 | static struct GNUNET_NETWORK_Handle * | ||
44 | open_listen_socket () | ||
45 | { | ||
46 | const static int on = 1; | ||
47 | struct sockaddr_in sa; | ||
48 | struct GNUNET_NETWORK_Handle *desc; | ||
49 | |||
50 | memset (&sa, 0, sizeof (sa)); | ||
51 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
52 | sa.sin_len = sizeof (sa); | ||
53 | #endif | ||
54 | sa.sin_family = AF_INET; | ||
55 | sa.sin_port = htons (PORT); | ||
56 | desc = GNUNET_NETWORK_socket_create (AF_INET, SOCK_STREAM, 0); | ||
57 | GNUNET_assert (desc != NULL); | ||
58 | if (GNUNET_NETWORK_socket_setsockopt | ||
59 | (desc, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) != GNUNET_OK) | ||
60 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, "setsockopt"); | ||
61 | GNUNET_assert (GNUNET_OK == | ||
62 | GNUNET_NETWORK_socket_bind (desc, (const struct sockaddr *) &sa, | ||
63 | sizeof (sa))); | ||
64 | GNUNET_NETWORK_socket_listen (desc, 5); | ||
65 | return desc; | ||
66 | } | ||
67 | |||
68 | |||
69 | static size_t | ||
70 | send_kilo (void *cls, size_t size, void *buf) | ||
71 | { | ||
72 | int *ok = cls; | ||
73 | |||
74 | if (size == 0) | ||
75 | { | ||
76 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got the desired timeout!\n"); | ||
77 | GNUNET_assert (buf == NULL); | ||
78 | *ok = 0; | ||
79 | GNUNET_CONNECTION_destroy (lsock); | ||
80 | GNUNET_CONNECTION_destroy (csock); | ||
81 | return 0; | ||
82 | } | ||
83 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending kilo to fill buffer.\n"); | ||
84 | GNUNET_assert (size >= 1024); | ||
85 | memset (buf, 42, 1024); | ||
86 | |||
87 | GNUNET_assert (NULL != | ||
88 | GNUNET_CONNECTION_notify_transmit_ready (csock, 1024, | ||
89 | GNUNET_TIME_UNIT_SECONDS, | ||
90 | &send_kilo, cls)); | ||
91 | return 1024; | ||
92 | } | ||
93 | |||
94 | |||
95 | static void | ||
96 | task_timeout (void *cls) | ||
97 | { | ||
98 | |||
99 | ls = open_listen_socket (); | ||
100 | lsock = GNUNET_CONNECTION_create_from_existing (ls); | ||
101 | GNUNET_assert (lsock != NULL); | ||
102 | csock = GNUNET_CONNECTION_create_from_connect (cfg, "localhost", PORT); | ||
103 | GNUNET_assert (csock != NULL); | ||
104 | GNUNET_assert (NULL != | ||
105 | GNUNET_CONNECTION_notify_transmit_ready (csock, 1024, | ||
106 | GNUNET_TIME_UNIT_SECONDS, | ||
107 | &send_kilo, cls)); | ||
108 | } | ||
109 | |||
110 | |||
111 | int | ||
112 | main (int argc, char *argv[]) | ||
113 | { | ||
114 | int ok; | ||
115 | |||
116 | GNUNET_log_setup ("test_connection_timeout", | ||
117 | "WARNING", | ||
118 | NULL); | ||
119 | |||
120 | ok = 1; | ||
121 | cfg = GNUNET_CONFIGURATION_create (); | ||
122 | GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME", | ||
123 | "localhost"); | ||
124 | GNUNET_SCHEDULER_run (&task_timeout, &ok); | ||
125 | GNUNET_CONFIGURATION_destroy (cfg); | ||
126 | return ok; | ||
127 | } | ||
128 | |||
129 | /* end of test_connection_timeout.c */ | ||
diff --git a/src/util/test_connection_timeout_no_connect.c b/src/util/test_connection_timeout_no_connect.c deleted file mode 100644 index ebcd4b71e..000000000 --- a/src/util/test_connection_timeout_no_connect.c +++ /dev/null | |||
@@ -1,76 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009 GNUnet e.V. | ||
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., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | /** | ||
21 | * @file util/test_connection_timeout_no_connect.c | ||
22 | * @brief tests for connection.c, doing timeout which connect failure | ||
23 | */ | ||
24 | #include "platform.h" | ||
25 | #include "gnunet_util_lib.h" | ||
26 | |||
27 | #define PORT 13425 | ||
28 | |||
29 | static struct GNUNET_CONNECTION_Handle *csock; | ||
30 | |||
31 | static struct GNUNET_CONFIGURATION_Handle *cfg; | ||
32 | |||
33 | static size_t | ||
34 | handle_timeout (void *cls, size_t size, void *buf) | ||
35 | { | ||
36 | int *ok = cls; | ||
37 | |||
38 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received timeout signal.\n"); | ||
39 | GNUNET_assert (size == 0); | ||
40 | GNUNET_assert (buf == NULL); | ||
41 | *ok = 0; | ||
42 | return 0; | ||
43 | } | ||
44 | |||
45 | |||
46 | static void | ||
47 | task_timeout (void *cls) | ||
48 | { | ||
49 | csock = GNUNET_CONNECTION_create_from_connect (cfg, "localhost", PORT); | ||
50 | GNUNET_assert (csock != NULL); | ||
51 | GNUNET_assert (NULL != | ||
52 | GNUNET_CONNECTION_notify_transmit_ready (csock, 1024, | ||
53 | GNUNET_TIME_UNIT_SECONDS, | ||
54 | &handle_timeout, | ||
55 | cls)); | ||
56 | } | ||
57 | |||
58 | |||
59 | int | ||
60 | main (int argc, char *argv[]) | ||
61 | { | ||
62 | int ok; | ||
63 | |||
64 | GNUNET_log_setup ("test_connection_timeout_no_connect", | ||
65 | "WARNING", | ||
66 | NULL); | ||
67 | ok = 1; | ||
68 | cfg = GNUNET_CONFIGURATION_create (); | ||
69 | GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME", | ||
70 | "localhost"); | ||
71 | GNUNET_SCHEDULER_run (&task_timeout, &ok); | ||
72 | GNUNET_CONFIGURATION_destroy (cfg); | ||
73 | return ok; | ||
74 | } | ||
75 | |||
76 | /* end of test_connection_timeout_no_connect.c */ | ||
diff --git a/src/util/test_connection_transmit_cancel.c b/src/util/test_connection_transmit_cancel.c deleted file mode 100644 index 9ef0720ed..000000000 --- a/src/util/test_connection_transmit_cancel.c +++ /dev/null | |||
@@ -1,76 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009 GNUnet e.V. | ||
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., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | /** | ||
21 | * @file util/test_connection_transmit_cancel.c | ||
22 | * @brief tests for connection.c | ||
23 | */ | ||
24 | #include "platform.h" | ||
25 | #include "gnunet_util_lib.h" | ||
26 | |||
27 | #define PORT 12435 | ||
28 | |||
29 | static struct GNUNET_CONFIGURATION_Handle *cfg; | ||
30 | |||
31 | |||
32 | static size_t | ||
33 | not_run (void *cls, size_t size, void *buf) | ||
34 | { | ||
35 | GNUNET_assert (0); | ||
36 | return 0; | ||
37 | } | ||
38 | |||
39 | |||
40 | static void | ||
41 | task_transmit_cancel (void *cls) | ||
42 | { | ||
43 | int *ok = cls; | ||
44 | struct GNUNET_CONNECTION_TransmitHandle *th; | ||
45 | struct GNUNET_CONNECTION_Handle *csock; | ||
46 | |||
47 | csock = GNUNET_CONNECTION_create_from_connect (cfg, "localhost", PORT); | ||
48 | GNUNET_assert (csock != NULL); | ||
49 | th = GNUNET_CONNECTION_notify_transmit_ready (csock, 12, | ||
50 | GNUNET_TIME_UNIT_MINUTES, | ||
51 | ¬_run, cls); | ||
52 | GNUNET_assert (NULL != th); | ||
53 | GNUNET_CONNECTION_notify_transmit_ready_cancel (th); | ||
54 | GNUNET_CONNECTION_destroy (csock); | ||
55 | *ok = 0; | ||
56 | } | ||
57 | |||
58 | |||
59 | int | ||
60 | main (int argc, char *argv[]) | ||
61 | { | ||
62 | int ok; | ||
63 | |||
64 | GNUNET_log_setup ("test_connection_transmit_cancel", | ||
65 | "WARNING", | ||
66 | NULL); | ||
67 | ok = 1; | ||
68 | cfg = GNUNET_CONFIGURATION_create (); | ||
69 | GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME", | ||
70 | "localhost"); | ||
71 | GNUNET_SCHEDULER_run (&task_transmit_cancel, &ok); | ||
72 | GNUNET_CONFIGURATION_destroy (cfg); | ||
73 | return ok; | ||
74 | } | ||
75 | |||
76 | /* end of test_connection_transmit_cancel.c */ | ||
diff --git a/src/util/test_getopt.c b/src/util/test_getopt.c index 8e578640d..13cedd7f5 100644 --- a/src/util/test_getopt.c +++ b/src/util/test_getopt.c | |||
@@ -136,13 +136,16 @@ testLogOpts () | |||
136 | GNUNET_GETOPT_OPTION_END | 136 | GNUNET_GETOPT_OPTION_END |
137 | }; | 137 | }; |
138 | 138 | ||
139 | if (5 != GNUNET_GETOPT_run ("test_getopt", logoptionlist, 5, myargv)) | 139 | if (5 != GNUNET_GETOPT_run ("test_getopt", |
140 | logoptionlist, | ||
141 | 5, myargv)) | ||
140 | { | 142 | { |
141 | GNUNET_break (0); | 143 | GNUNET_break (0); |
142 | return 1; | 144 | return 1; |
143 | } | 145 | } |
144 | GNUNET_assert (fn != NULL); | 146 | GNUNET_assert (NULL != fn); |
145 | if ((0 != strcmp (level, "WARNING")) || (0 != strcmp (fn, "filename"))) | 147 | if ( (0 != strcmp (level, "WARNING")) || |
148 | (NULL == strstr (fn, "/filename")) ) | ||
146 | { | 149 | { |
147 | GNUNET_break (0); | 150 | GNUNET_break (0); |
148 | GNUNET_free (level); | 151 | GNUNET_free (level); |
@@ -170,21 +173,35 @@ testFlagNum () | |||
170 | unsigned long long lnum = 0; | 173 | unsigned long long lnum = 0; |
171 | 174 | ||
172 | const struct GNUNET_GETOPT_CommandLineOption logoptionlist[] = { | 175 | const struct GNUNET_GETOPT_CommandLineOption logoptionlist[] = { |
173 | {'f', "--flag", NULL, "helptext", 0, &GNUNET_GETOPT_set_one, | 176 | GNUNET_GETOPT_OPTION_SET_ONE ('f', |
174 | (void *) &flag}, | 177 | "--flag", |
175 | {'n', "--num", "ARG", "helptext", 1, &GNUNET_GETOPT_set_uint, | 178 | "helptext", |
176 | (void *) &num}, | 179 | &flag), |
177 | {'N', "--lnum", "ARG", "helptext", 1, &GNUNET_GETOPT_set_ulong, | 180 | GNUNET_GETOPT_OPTION_SET_UINT ('n', |
178 | (void *) &lnum}, | 181 | "--num", |
182 | "ARG", | ||
183 | "helptext", | ||
184 | &num), | ||
185 | GNUNET_GETOPT_OPTION_SET_ULONG ('N', | ||
186 | "--lnum", | ||
187 | "ARG", | ||
188 | "helptext", | ||
189 | &lnum), | ||
179 | GNUNET_GETOPT_OPTION_END | 190 | GNUNET_GETOPT_OPTION_END |
180 | }; | 191 | }; |
181 | 192 | ||
182 | if (6 != GNUNET_GETOPT_run ("test_getopt", logoptionlist, 6, myargv)) | 193 | if (6 != |
194 | GNUNET_GETOPT_run ("test_getopt", | ||
195 | logoptionlist, | ||
196 | 6, | ||
197 | myargv)) | ||
183 | { | 198 | { |
184 | GNUNET_break (0); | 199 | GNUNET_break (0); |
185 | return 1; | 200 | return 1; |
186 | } | 201 | } |
187 | if ((1 != flag) || (42 != num) || (42 != lnum)) | 202 | if ( (1 != flag) || |
203 | (42 != num) || | ||
204 | (42 != lnum)) | ||
188 | { | 205 | { |
189 | GNUNET_break (0); | 206 | GNUNET_break (0); |
190 | return 1; | 207 | return 1; |
@@ -198,7 +215,9 @@ main (int argc, char *argv[]) | |||
198 | { | 215 | { |
199 | int errCnt = 0; | 216 | int errCnt = 0; |
200 | 217 | ||
201 | GNUNET_log_setup ("test_getopt", "WARNING", NULL); | 218 | GNUNET_log_setup ("test_getopt", |
219 | "WARNING", | ||
220 | NULL); | ||
202 | /* suppress output from -h, -v options */ | 221 | /* suppress output from -h, -v options */ |
203 | #ifndef MINGW | 222 | #ifndef MINGW |
204 | GNUNET_break (0 == CLOSE (1)); | 223 | GNUNET_break (0 == CLOSE (1)); |
diff --git a/src/util/test_program.c b/src/util/test_program.c index 669cee7bd..d206952af 100644 --- a/src/util/test_program.c +++ b/src/util/test_program.c | |||
@@ -24,37 +24,19 @@ | |||
24 | #include "platform.h" | 24 | #include "platform.h" |
25 | #include "gnunet_util_lib.h" | 25 | #include "gnunet_util_lib.h" |
26 | 26 | ||
27 | static int setme1, setme2; | 27 | |
28 | 28 | static int setme1; | |
29 | static struct GNUNET_GETOPT_CommandLineOption options1[] = { | 29 | |
30 | {'n', "name", NULL, "description", 0, &GNUNET_GETOPT_set_one, &setme1}, | 30 | static int setme2; |
31 | GNUNET_GETOPT_OPTION_END | 31 | |
32 | }; | ||
33 | |||
34 | static struct GNUNET_GETOPT_CommandLineOption options2[] = { | ||
35 | {'n', "name", NULL, "description", 0, &GNUNET_GETOPT_set_one, &setme1}, | ||
36 | {'N', "number", NULL, "description", 0, &GNUNET_GETOPT_set_one, &setme2}, | ||
37 | GNUNET_GETOPT_OPTION_END | ||
38 | }; | ||
39 | |||
40 | static struct GNUNET_GETOPT_CommandLineOption options3[] = { | ||
41 | {'N', "number", NULL, "description", 0, &GNUNET_GETOPT_set_one, &setme1}, | ||
42 | {'n', "name", NULL, "description", 0, &GNUNET_GETOPT_set_one, &setme2}, | ||
43 | GNUNET_GETOPT_OPTION_END | ||
44 | }; | ||
45 | |||
46 | static struct GNUNET_GETOPT_CommandLineOption options4[] = { | ||
47 | {'n', "name", NULL, "description", 0, &GNUNET_GETOPT_set_one, &setme1}, | ||
48 | {'n', "number", NULL, "description", 0, &GNUNET_GETOPT_set_one, &setme2}, | ||
49 | GNUNET_GETOPT_OPTION_END | ||
50 | }; | ||
51 | 32 | ||
52 | /** | 33 | /** |
53 | * Main function that will be run. | 34 | * Main function that will be run. |
54 | */ | 35 | */ |
55 | |||
56 | static void | 36 | static void |
57 | runner (void *cls, char *const *args, const char *cfgfile, | 37 | runner (void *cls, |
38 | char *const *args, | ||
39 | const char *cfgfile, | ||
58 | const struct GNUNET_CONFIGURATION_Handle *cfg) | 40 | const struct GNUNET_CONFIGURATION_Handle *cfg) |
59 | { | 41 | { |
60 | int *ok = cls; | 42 | int *ok = cls; |
@@ -62,21 +44,16 @@ runner (void *cls, char *const *args, const char *cfgfile, | |||
62 | GNUNET_assert (setme1 == 1); | 44 | GNUNET_assert (setme1 == 1); |
63 | GNUNET_assert (0 == strcmp (args[0], "extra")); | 45 | GNUNET_assert (0 == strcmp (args[0], "extra")); |
64 | GNUNET_assert (args[1] == NULL); | 46 | GNUNET_assert (args[1] == NULL); |
65 | GNUNET_assert (0 == strcmp (cfgfile, "test_program_data.conf")); | 47 | GNUNET_assert (NULL != strstr (cfgfile, "/test_program_data.conf")); |
66 | |||
67 | *ok = 0; | 48 | *ok = 0; |
68 | } | 49 | } |
69 | 50 | ||
70 | /** | 51 | |
71 | * Main method, starts scheduler with task1, | 52 | int |
72 | * checks that "ok" is correct at the end. | 53 | main (int argc, char *argv[]) |
73 | */ | ||
74 | static int | ||
75 | check () | ||
76 | { | 54 | { |
77 | int ok = 1; | 55 | int ok = 1; |
78 | 56 | char *const argvx[] = { | |
79 | char *const argv[] = { | ||
80 | "test_program", | 57 | "test_program", |
81 | "-c", | 58 | "-c", |
82 | "test_program_data.conf", | 59 | "test_program_data.conf", |
@@ -86,33 +63,75 @@ check () | |||
86 | "extra", | 63 | "extra", |
87 | NULL | 64 | NULL |
88 | }; | 65 | }; |
66 | struct GNUNET_GETOPT_CommandLineOption options1[] = { | ||
67 | GNUNET_GETOPT_OPTION_SET_ONE ('n', | ||
68 | "name", | ||
69 | "description", | ||
70 | &setme1), | ||
71 | GNUNET_GETOPT_OPTION_END | ||
72 | }; | ||
73 | struct GNUNET_GETOPT_CommandLineOption options2[] = { | ||
74 | GNUNET_GETOPT_OPTION_SET_ONE ('n', | ||
75 | "name", | ||
76 | "description", | ||
77 | &setme1), | ||
78 | GNUNET_GETOPT_OPTION_SET_ONE ('N', | ||
79 | "number", | ||
80 | "description", | ||
81 | &setme2), | ||
82 | GNUNET_GETOPT_OPTION_END | ||
83 | }; | ||
84 | struct GNUNET_GETOPT_CommandLineOption options3[] = { | ||
85 | GNUNET_GETOPT_OPTION_SET_ONE ('N', | ||
86 | "number", | ||
87 | "description", | ||
88 | &setme1), | ||
89 | GNUNET_GETOPT_OPTION_SET_ONE ('n', | ||
90 | "name", | ||
91 | "description", | ||
92 | &setme2), | ||
93 | GNUNET_GETOPT_OPTION_END | ||
94 | }; | ||
95 | struct GNUNET_GETOPT_CommandLineOption options4[] = { | ||
96 | GNUNET_GETOPT_OPTION_SET_ONE ('n', | ||
97 | "name", | ||
98 | "description", | ||
99 | &setme1), | ||
100 | GNUNET_GETOPT_OPTION_SET_ONE ('n', | ||
101 | "name", | ||
102 | "description", | ||
103 | &setme2), | ||
104 | GNUNET_GETOPT_OPTION_END | ||
105 | }; | ||
89 | 106 | ||
107 | |||
108 | GNUNET_log_setup ("test_program", | ||
109 | "WARNING", | ||
110 | NULL); | ||
90 | GNUNET_assert (GNUNET_OK == | 111 | GNUNET_assert (GNUNET_OK == |
91 | GNUNET_PROGRAM_run (7, argv, "test_program", "A test", | 112 | GNUNET_PROGRAM_run (7, argvx, |
92 | options1, &runner, &ok)); | 113 | "test_program", |
114 | "A test", | ||
115 | options1, | ||
116 | &runner, &ok)); | ||
93 | 117 | ||
94 | GNUNET_assert (GNUNET_OK == | 118 | GNUNET_assert (GNUNET_OK == |
95 | GNUNET_PROGRAM_run (7, argv, "test_program", "A test", | 119 | GNUNET_PROGRAM_run (7, argvx, |
96 | options2, &runner, &ok)); | 120 | "test_program", "A test", |
121 | options2, | ||
122 | &runner, &ok)); | ||
97 | GNUNET_assert (GNUNET_OK == | 123 | GNUNET_assert (GNUNET_OK == |
98 | GNUNET_PROGRAM_run (7, argv, "test_program", "A test", | 124 | GNUNET_PROGRAM_run (7, argvx, |
99 | options3, &runner, &ok)); | 125 | "test_program", "A test", |
126 | options3, | ||
127 | &runner, &ok)); | ||
100 | GNUNET_assert (GNUNET_OK == | 128 | GNUNET_assert (GNUNET_OK == |
101 | GNUNET_PROGRAM_run (7, argv, "test_program", "A test", | 129 | GNUNET_PROGRAM_run (7, argvx, |
102 | options4, &runner, &ok)); | 130 | "test_program", "A test", |
131 | options4, | ||
132 | &runner, &ok)); | ||
103 | 133 | ||
104 | return ok; | 134 | return ok; |
105 | } | 135 | } |
106 | 136 | ||
107 | int | ||
108 | main (int argc, char *argv[]) | ||
109 | { | ||
110 | int ret = 0; | ||
111 | |||
112 | GNUNET_log_setup ("test_program", "WARNING", NULL); | ||
113 | ret += check (); | ||
114 | |||
115 | return ret; | ||
116 | } | ||
117 | |||
118 | /* end of test_program.c */ | 137 | /* end of test_program.c */ |
diff --git a/src/util/test_server.c b/src/util/test_server.c deleted file mode 100644 index 8003adbf4..000000000 --- a/src/util/test_server.c +++ /dev/null | |||
@@ -1,302 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009, 2010, 2014, 2016 GNUnet e.V. | ||
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., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | /** | ||
21 | * @file util/test_server.c | ||
22 | * @brief tests for server.c | ||
23 | */ | ||
24 | #include "platform.h" | ||
25 | #include "gnunet_util_lib.h" | ||
26 | |||
27 | /** | ||
28 | * TCP port to use for the server. | ||
29 | */ | ||
30 | #define PORT 12435 | ||
31 | |||
32 | /** | ||
33 | * Timeout to use for operations. | ||
34 | */ | ||
35 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 2) | ||
36 | |||
37 | /** | ||
38 | * Test message type. | ||
39 | */ | ||
40 | #define MY_TYPE 128 | ||
41 | |||
42 | /** | ||
43 | * Test message type. | ||
44 | */ | ||
45 | #define MY_TYPE2 129 | ||
46 | |||
47 | /** | ||
48 | * Handle for the server. | ||
49 | */ | ||
50 | static struct GNUNET_SERVER_Handle *server; | ||
51 | |||
52 | /** | ||
53 | * Handle for the client. | ||
54 | */ | ||
55 | static struct GNUNET_MQ_Handle *mq; | ||
56 | |||
57 | /** | ||
58 | * Handle of the server for the client. | ||
59 | */ | ||
60 | static struct GNUNET_SERVER_Client *argclient; | ||
61 | |||
62 | /** | ||
63 | * Our configuration. | ||
64 | */ | ||
65 | static struct GNUNET_CONFIGURATION_Handle *cfg; | ||
66 | |||
67 | /** | ||
68 | * Number indiciating in which phase of the test we are. | ||
69 | */ | ||
70 | static int ok; | ||
71 | |||
72 | |||
73 | /** | ||
74 | * Final task invoked to clean up. | ||
75 | * | ||
76 | * @param cls NULL | ||
77 | */ | ||
78 | static void | ||
79 | finish_up (void *cls) | ||
80 | { | ||
81 | GNUNET_assert (7 == ok); | ||
82 | ok = 0; | ||
83 | GNUNET_SERVER_destroy (server); | ||
84 | GNUNET_MQ_destroy (mq); | ||
85 | GNUNET_CONFIGURATION_destroy (cfg); | ||
86 | } | ||
87 | |||
88 | |||
89 | /** | ||
90 | * The server has received the second message, initiate clean up. | ||
91 | * | ||
92 | * @param cls NULL | ||
93 | * @param client client we got the message from | ||
94 | * @param message the message | ||
95 | */ | ||
96 | static void | ||
97 | recv_fin_cb (void *cls, | ||
98 | struct GNUNET_SERVER_Client *client, | ||
99 | const struct GNUNET_MessageHeader *message) | ||
100 | { | ||
101 | GNUNET_assert (6 == ok); | ||
102 | ok = 7; | ||
103 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
104 | GNUNET_SCHEDULER_add_now (&finish_up, NULL); | ||
105 | } | ||
106 | |||
107 | |||
108 | /** | ||
109 | * We have received the reply from the server, check that we are at | ||
110 | * the right stage and queue the next message to the server. Cleans | ||
111 | * up #argclient. | ||
112 | * | ||
113 | * @param cls NULL | ||
114 | * @param msg message we got from the server | ||
115 | */ | ||
116 | static void | ||
117 | handle_reply (void *cls, | ||
118 | const struct GNUNET_MessageHeader *msg) | ||
119 | { | ||
120 | struct GNUNET_MQ_Envelope *env; | ||
121 | struct GNUNET_MessageHeader *m; | ||
122 | |||
123 | GNUNET_assert (4 == ok); | ||
124 | ok = 6; | ||
125 | env = GNUNET_MQ_msg (m, | ||
126 | MY_TYPE2); | ||
127 | GNUNET_MQ_send (mq, | ||
128 | env); | ||
129 | } | ||
130 | |||
131 | |||
132 | /** | ||
133 | * Send a reply of type #MY_TYPE from the server to the client. | ||
134 | * Checks that we are in the right phase and transmits the | ||
135 | * reply. Cleans up #argclient state. | ||
136 | * | ||
137 | * @param cls NULL | ||
138 | * @param size number of bytes we are allowed to send | ||
139 | * @param buf where to copy the reply | ||
140 | * @return number of bytes written to @a buf | ||
141 | */ | ||
142 | static size_t | ||
143 | reply_msg (void *cls, | ||
144 | size_t size, | ||
145 | void *buf) | ||
146 | { | ||
147 | struct GNUNET_MessageHeader msg; | ||
148 | |||
149 | GNUNET_assert (3 == ok); | ||
150 | ok = 4; | ||
151 | GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader)); | ||
152 | msg.type = htons (MY_TYPE); | ||
153 | msg.size = htons (sizeof (struct GNUNET_MessageHeader)); | ||
154 | GNUNET_memcpy (buf, &msg, sizeof (struct GNUNET_MessageHeader)); | ||
155 | GNUNET_assert (NULL != argclient); | ||
156 | GNUNET_SERVER_receive_done (argclient, GNUNET_OK); | ||
157 | GNUNET_SERVER_client_drop (argclient); | ||
158 | argclient = NULL; | ||
159 | return sizeof (struct GNUNET_MessageHeader); | ||
160 | } | ||
161 | |||
162 | |||
163 | /** | ||
164 | * Function called whenever the server receives a message of | ||
165 | * type #MY_TYPE. Checks that we are at the stage where | ||
166 | * we expect the first message, then sends a reply. Stores | ||
167 | * the handle to the client in #argclient. | ||
168 | * | ||
169 | * @param cls NULL | ||
170 | * @param client client that sent the message | ||
171 | * @param message the message we received | ||
172 | */ | ||
173 | static void | ||
174 | recv_cb (void *cls, | ||
175 | struct GNUNET_SERVER_Client *client, | ||
176 | const struct GNUNET_MessageHeader *message) | ||
177 | { | ||
178 | GNUNET_assert (2 == ok); | ||
179 | ok = 3; | ||
180 | argclient = client; | ||
181 | GNUNET_SERVER_client_keep (argclient); | ||
182 | GNUNET_assert (sizeof (struct GNUNET_MessageHeader) == ntohs (message->size)); | ||
183 | GNUNET_assert (MY_TYPE == ntohs (message->type)); | ||
184 | GNUNET_assert (NULL != | ||
185 | GNUNET_SERVER_notify_transmit_ready (client, | ||
186 | ntohs (message->size), | ||
187 | TIMEOUT, | ||
188 | &reply_msg, | ||
189 | NULL)); | ||
190 | } | ||
191 | |||
192 | |||
193 | /** | ||
194 | * Message handlers for the server. | ||
195 | */ | ||
196 | static struct GNUNET_SERVER_MessageHandler handlers[] = { | ||
197 | {&recv_cb, NULL, MY_TYPE, sizeof (struct GNUNET_MessageHeader)}, | ||
198 | {&recv_fin_cb, NULL, MY_TYPE2, sizeof (struct GNUNET_MessageHeader)}, | ||
199 | {NULL, NULL, 0, 0} | ||
200 | }; | ||
201 | |||
202 | |||
203 | /** | ||
204 | * Generic error handler, called with the appropriate error code and | ||
205 | * the same closure specified at the creation of the message queue. | ||
206 | * Not every message queue implementation supports an error handler. | ||
207 | * | ||
208 | * @param cls closure with the `struct GNUNET_STATISTICS_Handle *` | ||
209 | * @param error error code | ||
210 | */ | ||
211 | static void | ||
212 | mq_error_handler (void *cls, | ||
213 | enum GNUNET_MQ_Error error) | ||
214 | { | ||
215 | GNUNET_assert (0); /* should never happen */ | ||
216 | } | ||
217 | |||
218 | |||
219 | /** | ||
220 | * First task run by the scheduler. Initializes the server and | ||
221 | * a client and asks for a transmission from the client to the | ||
222 | * server. | ||
223 | * | ||
224 | * @param cls NULL | ||
225 | */ | ||
226 | static void | ||
227 | task (void *cls) | ||
228 | { | ||
229 | struct sockaddr_in sa; | ||
230 | struct sockaddr *sap[2]; | ||
231 | socklen_t slens[2]; | ||
232 | struct GNUNET_MQ_Envelope *env; | ||
233 | struct GNUNET_MessageHeader *msg; | ||
234 | struct GNUNET_MQ_MessageHandler chandlers[] = { | ||
235 | GNUNET_MQ_hd_fixed_size (reply, | ||
236 | MY_TYPE, | ||
237 | struct GNUNET_MessageHeader, | ||
238 | cls), | ||
239 | GNUNET_MQ_handler_end () | ||
240 | }; | ||
241 | |||
242 | sap[0] = (struct sockaddr *) &sa; | ||
243 | slens[0] = sizeof (sa); | ||
244 | sap[1] = NULL; | ||
245 | slens[1] = 0; | ||
246 | memset (&sa, 0, sizeof (sa)); | ||
247 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
248 | sa.sin_len = sizeof (sa); | ||
249 | #endif | ||
250 | sa.sin_family = AF_INET; | ||
251 | sa.sin_port = htons (PORT); | ||
252 | server = GNUNET_SERVER_create (NULL, NULL, | ||
253 | sap, slens, | ||
254 | TIMEOUT, GNUNET_NO); | ||
255 | GNUNET_assert (server != NULL); | ||
256 | GNUNET_SERVER_add_handlers (server, handlers); | ||
257 | cfg = GNUNET_CONFIGURATION_create (); | ||
258 | GNUNET_CONFIGURATION_set_value_number (cfg, | ||
259 | "test-server", | ||
260 | "PORT", | ||
261 | PORT); | ||
262 | GNUNET_CONFIGURATION_set_value_string (cfg, | ||
263 | "test-server", | ||
264 | "HOSTNAME", | ||
265 | "localhost"); | ||
266 | GNUNET_CONFIGURATION_set_value_string (cfg, | ||
267 | "resolver", | ||
268 | "HOSTNAME", | ||
269 | "localhost"); | ||
270 | mq = GNUNET_CLIENT_connect (cfg, | ||
271 | "test-server", | ||
272 | chandlers, | ||
273 | &mq_error_handler, | ||
274 | NULL); | ||
275 | GNUNET_assert (NULL != mq); | ||
276 | ok = 2; | ||
277 | env = GNUNET_MQ_msg (msg, | ||
278 | MY_TYPE); | ||
279 | GNUNET_MQ_send (mq, | ||
280 | env); | ||
281 | } | ||
282 | |||
283 | |||
284 | /** | ||
285 | * Runs the test. | ||
286 | * | ||
287 | * @param argc length of @a argv | ||
288 | * @param argv command line arguments (ignored) | ||
289 | * @return 0 on success, otherwise phase of failure | ||
290 | */ | ||
291 | int | ||
292 | main (int argc, char *argv[]) | ||
293 | { | ||
294 | GNUNET_log_setup ("test_server", | ||
295 | "WARNING", | ||
296 | NULL); | ||
297 | ok = 1; | ||
298 | GNUNET_SCHEDULER_run (&task, &ok); | ||
299 | return ok; | ||
300 | } | ||
301 | |||
302 | /* end of test_server.c */ | ||
diff --git a/src/util/test_server_disconnect.c b/src/util/test_server_disconnect.c deleted file mode 100644 index c3d003e90..000000000 --- a/src/util/test_server_disconnect.c +++ /dev/null | |||
@@ -1,166 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009, 2010, 2016 GNUnet e.V. | ||
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., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | /** | ||
21 | * @file util/test_server_disconnect.c | ||
22 | * @brief tests for server.c, specifically GNUNET_SERVER_client_disconnect | ||
23 | */ | ||
24 | #include "platform.h" | ||
25 | #include "gnunet_util_lib.h" | ||
26 | |||
27 | |||
28 | #define PORT 12435 | ||
29 | |||
30 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, 250) | ||
31 | |||
32 | #define MY_TYPE 128 | ||
33 | |||
34 | static struct GNUNET_SERVER_Handle *server; | ||
35 | |||
36 | static struct GNUNET_MQ_Handle *mq; | ||
37 | |||
38 | static struct GNUNET_CONFIGURATION_Handle *cfg; | ||
39 | |||
40 | static int ok; | ||
41 | |||
42 | |||
43 | static void | ||
44 | finish_up (void *cls) | ||
45 | { | ||
46 | GNUNET_assert (ok == 5); | ||
47 | ok = 0; | ||
48 | GNUNET_SERVER_destroy (server); | ||
49 | GNUNET_MQ_destroy (mq); | ||
50 | GNUNET_CONFIGURATION_destroy (cfg); | ||
51 | } | ||
52 | |||
53 | |||
54 | static void | ||
55 | notify_disconnect (void *cls, | ||
56 | struct GNUNET_SERVER_Client *clientarg) | ||
57 | { | ||
58 | if (NULL == clientarg) | ||
59 | return; | ||
60 | GNUNET_assert (ok == 4); | ||
61 | ok = 5; | ||
62 | GNUNET_SCHEDULER_add_now (&finish_up, NULL); | ||
63 | } | ||
64 | |||
65 | |||
66 | static void | ||
67 | server_disconnect (void *cls) | ||
68 | { | ||
69 | struct GNUNET_SERVER_Client *argclient = cls; | ||
70 | |||
71 | GNUNET_assert (ok == 3); | ||
72 | ok = 4; | ||
73 | GNUNET_SERVER_client_disconnect (argclient); | ||
74 | GNUNET_SERVER_client_drop (argclient); | ||
75 | } | ||
76 | |||
77 | |||
78 | static void | ||
79 | recv_cb (void *cls, | ||
80 | struct GNUNET_SERVER_Client *client, | ||
81 | const struct GNUNET_MessageHeader *message) | ||
82 | { | ||
83 | GNUNET_assert (ok == 2); | ||
84 | ok = 3; | ||
85 | GNUNET_SERVER_client_keep (client); | ||
86 | GNUNET_SCHEDULER_add_now (&server_disconnect, client); | ||
87 | GNUNET_assert (sizeof (struct GNUNET_MessageHeader) == ntohs (message->size)); | ||
88 | GNUNET_assert (MY_TYPE == ntohs (message->type)); | ||
89 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
90 | } | ||
91 | |||
92 | |||
93 | static struct GNUNET_SERVER_MessageHandler handlers[] = { | ||
94 | {&recv_cb, NULL, MY_TYPE, sizeof (struct GNUNET_MessageHeader)}, | ||
95 | {NULL, NULL, 0, 0} | ||
96 | }; | ||
97 | |||
98 | |||
99 | static void | ||
100 | task (void *cls) | ||
101 | { | ||
102 | struct sockaddr_in sa; | ||
103 | struct sockaddr *sap[2]; | ||
104 | socklen_t slens[2]; | ||
105 | struct GNUNET_MQ_Envelope *env; | ||
106 | struct GNUNET_MessageHeader *msg; | ||
107 | |||
108 | sap[0] = (struct sockaddr *) &sa; | ||
109 | slens[0] = sizeof (sa); | ||
110 | sap[1] = NULL; | ||
111 | slens[1] = 0; | ||
112 | memset (&sa, 0, sizeof (sa)); | ||
113 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
114 | sa.sin_len = sizeof (sa); | ||
115 | #endif | ||
116 | sa.sin_family = AF_INET; | ||
117 | sa.sin_port = htons (PORT); | ||
118 | server = GNUNET_SERVER_create (NULL, NULL, sap, slens, TIMEOUT, GNUNET_NO); | ||
119 | GNUNET_assert (server != NULL); | ||
120 | GNUNET_SERVER_add_handlers (server, handlers); | ||
121 | GNUNET_SERVER_disconnect_notify (server, ¬ify_disconnect, NULL); | ||
122 | cfg = GNUNET_CONFIGURATION_create (); | ||
123 | GNUNET_CONFIGURATION_set_value_number (cfg, "test-server", "PORT", PORT); | ||
124 | GNUNET_CONFIGURATION_set_value_string (cfg, "test-server", "HOSTNAME", | ||
125 | "localhost"); | ||
126 | GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME", | ||
127 | "localhost"); | ||
128 | mq = GNUNET_CLIENT_connect (cfg, | ||
129 | "test-server", | ||
130 | NULL, | ||
131 | NULL, | ||
132 | NULL); | ||
133 | GNUNET_assert (NULL != mq); | ||
134 | ok = 2; | ||
135 | env = GNUNET_MQ_msg (msg, | ||
136 | MY_TYPE); | ||
137 | GNUNET_MQ_send (mq, | ||
138 | env); | ||
139 | } | ||
140 | |||
141 | |||
142 | /** | ||
143 | * Main method, starts scheduler with task1, | ||
144 | * checks that "ok" is correct at the end. | ||
145 | */ | ||
146 | static int | ||
147 | check () | ||
148 | { | ||
149 | ok = 1; | ||
150 | GNUNET_SCHEDULER_run (&task, &ok); | ||
151 | return ok; | ||
152 | } | ||
153 | |||
154 | |||
155 | int | ||
156 | main (int argc, char *argv[]) | ||
157 | { | ||
158 | int ret = 0; | ||
159 | |||
160 | GNUNET_log_setup ("test_server_disconnect", "WARNING", NULL); | ||
161 | ret += check (); | ||
162 | |||
163 | return ret; | ||
164 | } | ||
165 | |||
166 | /* end of test_server_disconnect.c */ | ||
diff --git a/src/util/test_server_mst_interrupt.c b/src/util/test_server_mst_interrupt.c deleted file mode 100644 index 3141a75bd..000000000 --- a/src/util/test_server_mst_interrupt.c +++ /dev/null | |||
@@ -1,60 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009, 2010 GNUnet e.V. | ||
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., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | /** | ||
21 | * @file util/test_server_mst_interrupt.c | ||
22 | * @brief test for interrupt message processing in server_mst.c | ||
23 | */ | ||
24 | #include "platform.h" | ||
25 | #include "gnunet_protocols.h" | ||
26 | #include "gnunet_util_lib.h" | ||
27 | |||
28 | static struct GNUNET_SERVER_MessageStreamTokenizer * mst; | ||
29 | |||
30 | |||
31 | /* Callback destroying mst with data in buffer */ | ||
32 | static int | ||
33 | mst_cb (void *cls, void *client, | ||
34 | const struct GNUNET_MessageHeader * message) | ||
35 | { | ||
36 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "MST gave me message, destroying\n"); | ||
37 | GNUNET_SERVER_mst_destroy (mst); | ||
38 | return GNUNET_SYSERR; | ||
39 | } | ||
40 | |||
41 | |||
42 | int | ||
43 | main (int argc, char *argv[]) | ||
44 | { | ||
45 | struct GNUNET_PeerIdentity id; | ||
46 | struct GNUNET_MessageHeader msg[2]; | ||
47 | |||
48 | GNUNET_log_setup ("test_server_mst_interrupt", "WARNING", NULL); | ||
49 | memset (&id, 0, sizeof (id)); | ||
50 | msg[0].size = htons (sizeof (msg)); | ||
51 | msg[0].type = htons (sizeof (GNUNET_MESSAGE_TYPE_DUMMY)); | ||
52 | mst = GNUNET_SERVER_mst_create(mst_cb, NULL); | ||
53 | GNUNET_SERVER_mst_receive (mst, &id, | ||
54 | (const char *) &msg, 2 * sizeof (msg), | ||
55 | GNUNET_NO, GNUNET_NO); | ||
56 | /* If we reach this line, it did not crash */ | ||
57 | return 0; | ||
58 | } | ||
59 | |||
60 | /* end of test_server_mst_interrupt.c */ | ||
diff --git a/src/util/test_server_with_client.c b/src/util/test_server_with_client.c deleted file mode 100644 index 63bfda00c..000000000 --- a/src/util/test_server_with_client.c +++ /dev/null | |||
@@ -1,198 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009, 2016 GNUnet e.V. | ||
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., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | /** | ||
21 | * @file util/test_server_with_client.c | ||
22 | * @brief tests for server.c and client.c, | ||
23 | * specifically disconnect_notify, | ||
24 | * client_get_address and receive_done (resume processing) | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet_util_lib.h" | ||
28 | |||
29 | #define PORT 22335 | ||
30 | |||
31 | #define MY_TYPE 128 | ||
32 | |||
33 | |||
34 | static struct GNUNET_SERVER_Handle *server; | ||
35 | |||
36 | static struct GNUNET_MQ_Handle *mq; | ||
37 | |||
38 | static struct GNUNET_CONFIGURATION_Handle *cfg; | ||
39 | |||
40 | static int ok; | ||
41 | |||
42 | |||
43 | static void | ||
44 | send_done (void *cls) | ||
45 | { | ||
46 | struct GNUNET_SERVER_Client *argclient = cls; | ||
47 | |||
48 | GNUNET_assert (ok == 3); | ||
49 | ok++; | ||
50 | GNUNET_SERVER_receive_done (argclient, GNUNET_OK); | ||
51 | } | ||
52 | |||
53 | |||
54 | static void | ||
55 | recv_cb (void *cls, | ||
56 | struct GNUNET_SERVER_Client *argclient, | ||
57 | const struct GNUNET_MessageHeader *message) | ||
58 | { | ||
59 | void *addr; | ||
60 | size_t addrlen; | ||
61 | struct sockaddr_in sa; | ||
62 | struct sockaddr_in *have; | ||
63 | |||
64 | GNUNET_assert (GNUNET_OK == | ||
65 | GNUNET_SERVER_client_get_address (argclient, | ||
66 | &addr, | ||
67 | &addrlen)); | ||
68 | |||
69 | GNUNET_assert (addrlen == sizeof (struct sockaddr_in)); | ||
70 | have = addr; | ||
71 | memset (&sa, 0, sizeof (sa)); | ||
72 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
73 | sa.sin_len = sizeof (sa); | ||
74 | #endif | ||
75 | sa.sin_family = AF_INET; | ||
76 | sa.sin_port = have->sin_port; | ||
77 | sa.sin_addr.s_addr = htonl (INADDR_LOOPBACK); | ||
78 | GNUNET_assert (0 == memcmp (&sa, addr, addrlen)); | ||
79 | GNUNET_free (addr); | ||
80 | switch (ok) | ||
81 | { | ||
82 | case 2: | ||
83 | ok++; | ||
84 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply | ||
85 | (GNUNET_TIME_UNIT_MILLISECONDS, 50), | ||
86 | &send_done, | ||
87 | argclient); | ||
88 | break; | ||
89 | case 4: | ||
90 | ok++; | ||
91 | GNUNET_MQ_destroy (mq); | ||
92 | GNUNET_SERVER_receive_done (argclient, | ||
93 | GNUNET_OK); | ||
94 | break; | ||
95 | default: | ||
96 | GNUNET_assert (0); | ||
97 | } | ||
98 | |||
99 | } | ||
100 | |||
101 | |||
102 | static void | ||
103 | clean_up (void *cls) | ||
104 | { | ||
105 | GNUNET_SERVER_destroy (server); | ||
106 | server = NULL; | ||
107 | GNUNET_CONFIGURATION_destroy (cfg); | ||
108 | cfg = NULL; | ||
109 | } | ||
110 | |||
111 | |||
112 | /** | ||
113 | * Functions with this signature are called whenever a client | ||
114 | * is disconnected on the network level. | ||
115 | * | ||
116 | * @param cls closure | ||
117 | * @param client identification of the client | ||
118 | */ | ||
119 | static void | ||
120 | notify_disconnect (void *cls, | ||
121 | struct GNUNET_SERVER_Client *client) | ||
122 | { | ||
123 | if (client == NULL) | ||
124 | return; | ||
125 | GNUNET_assert (ok == 5); | ||
126 | ok = 0; | ||
127 | GNUNET_SCHEDULER_add_now (&clean_up, NULL); | ||
128 | } | ||
129 | |||
130 | |||
131 | static struct GNUNET_SERVER_MessageHandler handlers[] = { | ||
132 | {&recv_cb, NULL, MY_TYPE, sizeof (struct GNUNET_MessageHeader)}, | ||
133 | {NULL, NULL, 0, 0} | ||
134 | }; | ||
135 | |||
136 | |||
137 | static void | ||
138 | task (void *cls) | ||
139 | { | ||
140 | struct sockaddr_in sa; | ||
141 | struct sockaddr *sap[2]; | ||
142 | socklen_t slens[2]; | ||
143 | struct GNUNET_MQ_Envelope *env; | ||
144 | struct GNUNET_MessageHeader *msg; | ||
145 | |||
146 | sap[0] = (struct sockaddr *) &sa; | ||
147 | slens[0] = sizeof (sa); | ||
148 | sap[1] = NULL; | ||
149 | slens[1] = 0; | ||
150 | memset (&sa, 0, sizeof (sa)); | ||
151 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
152 | sa.sin_len = sizeof (sa); | ||
153 | #endif | ||
154 | sa.sin_family = AF_INET; | ||
155 | sa.sin_port = htons (PORT); | ||
156 | server = | ||
157 | GNUNET_SERVER_create (NULL, NULL, sap, slens, | ||
158 | GNUNET_TIME_relative_multiply | ||
159 | (GNUNET_TIME_UNIT_MILLISECONDS, 250), GNUNET_NO); | ||
160 | GNUNET_assert (server != NULL); | ||
161 | handlers[0].callback_cls = cls; | ||
162 | GNUNET_SERVER_add_handlers (server, handlers); | ||
163 | GNUNET_SERVER_disconnect_notify (server, ¬ify_disconnect, cls); | ||
164 | cfg = GNUNET_CONFIGURATION_create (); | ||
165 | GNUNET_CONFIGURATION_set_value_number (cfg, "test", "PORT", PORT); | ||
166 | GNUNET_CONFIGURATION_set_value_string (cfg, "test", "HOSTNAME", "localhost"); | ||
167 | GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME", | ||
168 | "localhost"); | ||
169 | mq = GNUNET_CLIENT_connect (cfg, | ||
170 | "test", | ||
171 | NULL, | ||
172 | NULL, | ||
173 | NULL); | ||
174 | GNUNET_assert (NULL != mq); | ||
175 | ok = 2; | ||
176 | env = GNUNET_MQ_msg (msg, | ||
177 | MY_TYPE); | ||
178 | GNUNET_MQ_send (mq, | ||
179 | env); | ||
180 | env = GNUNET_MQ_msg (msg, | ||
181 | MY_TYPE); | ||
182 | GNUNET_MQ_send (mq, | ||
183 | env); | ||
184 | } | ||
185 | |||
186 | |||
187 | int | ||
188 | main (int argc, char *argv[]) | ||
189 | { | ||
190 | GNUNET_log_setup ("test_server_with_client", | ||
191 | "WARNING", | ||
192 | NULL); | ||
193 | ok = 1; | ||
194 | GNUNET_SCHEDULER_run (&task, NULL); | ||
195 | return ok; | ||
196 | } | ||
197 | |||
198 | /* end of test_server_with_client.c */ | ||
diff --git a/src/util/test_server_with_client_unix.c b/src/util/test_server_with_client_unix.c deleted file mode 100644 index 8fabbe210..000000000 --- a/src/util/test_server_with_client_unix.c +++ /dev/null | |||
@@ -1,176 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009, 2016 GNUnet e.V. | ||
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., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | /** | ||
21 | * @file util/test_server_with_client_unix.c | ||
22 | * @brief tests for server.c and client.c, | ||
23 | * specifically disconnect_notify, | ||
24 | * client_get_address and receive_done (resume processing) | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet_util_lib.h" | ||
28 | |||
29 | #define MY_TYPE 128 | ||
30 | |||
31 | |||
32 | static struct GNUNET_SERVER_Handle *server; | ||
33 | |||
34 | static struct GNUNET_MQ_Handle *mq; | ||
35 | |||
36 | static struct GNUNET_CONFIGURATION_Handle *cfg; | ||
37 | |||
38 | static int ok; | ||
39 | |||
40 | |||
41 | static void | ||
42 | send_done (void *cls) | ||
43 | { | ||
44 | struct GNUNET_SERVER_Client *argclient = cls; | ||
45 | |||
46 | GNUNET_assert (ok == 3); | ||
47 | ok++; | ||
48 | GNUNET_SERVER_receive_done (argclient, GNUNET_OK); | ||
49 | } | ||
50 | |||
51 | |||
52 | static void | ||
53 | recv_cb (void *cls, | ||
54 | struct GNUNET_SERVER_Client *argclient, | ||
55 | const struct GNUNET_MessageHeader *message) | ||
56 | { | ||
57 | switch (ok) | ||
58 | { | ||
59 | case 2: | ||
60 | ok++; | ||
61 | (void) GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply | ||
62 | (GNUNET_TIME_UNIT_MILLISECONDS, 50), | ||
63 | &send_done, | ||
64 | argclient); | ||
65 | break; | ||
66 | case 4: | ||
67 | ok++; | ||
68 | GNUNET_MQ_destroy (mq); | ||
69 | GNUNET_SERVER_receive_done (argclient, GNUNET_OK); | ||
70 | break; | ||
71 | default: | ||
72 | GNUNET_assert (0); | ||
73 | } | ||
74 | |||
75 | } | ||
76 | |||
77 | |||
78 | static void | ||
79 | clean_up (void *cls) | ||
80 | { | ||
81 | GNUNET_SERVER_destroy (server); | ||
82 | server = NULL; | ||
83 | GNUNET_CONFIGURATION_destroy (cfg); | ||
84 | cfg = NULL; | ||
85 | } | ||
86 | |||
87 | |||
88 | /** | ||
89 | * Functions with this signature are called whenever a client | ||
90 | * is disconnected on the network level. | ||
91 | * | ||
92 | * @param cls closure | ||
93 | * @param client identification of the client | ||
94 | */ | ||
95 | static void | ||
96 | notify_disconnect (void *cls, | ||
97 | struct GNUNET_SERVER_Client *client) | ||
98 | { | ||
99 | if (client == NULL) | ||
100 | return; | ||
101 | GNUNET_assert (ok == 5); | ||
102 | ok = 0; | ||
103 | (void) GNUNET_SCHEDULER_add_now (&clean_up, NULL); | ||
104 | } | ||
105 | |||
106 | |||
107 | static struct GNUNET_SERVER_MessageHandler handlers[] = { | ||
108 | {&recv_cb, NULL, MY_TYPE, sizeof (struct GNUNET_MessageHeader)}, | ||
109 | {NULL, NULL, 0, 0} | ||
110 | }; | ||
111 | |||
112 | |||
113 | static void | ||
114 | task (void *cls) | ||
115 | { | ||
116 | struct sockaddr_un un; | ||
117 | const char *unixpath = "/tmp/testsock"; | ||
118 | struct sockaddr *sap[2]; | ||
119 | socklen_t slens[2]; | ||
120 | struct GNUNET_MQ_Envelope *env; | ||
121 | struct GNUNET_MessageHeader *msg; | ||
122 | |||
123 | memset (&un, 0, sizeof (un)); | ||
124 | un.sun_family = AF_UNIX; | ||
125 | strncpy(un.sun_path, unixpath, sizeof (un.sun_path) - 1); | ||
126 | #if HAVE_SOCKADDR_UN_SUN_LEN | ||
127 | un.sun_len = (u_char) sizeof (un); | ||
128 | #endif | ||
129 | |||
130 | sap[0] = (struct sockaddr *) &un; | ||
131 | slens[0] = sizeof (un); | ||
132 | sap[1] = NULL; | ||
133 | slens[1] = 0; | ||
134 | server = | ||
135 | GNUNET_SERVER_create (NULL, NULL, sap, slens, | ||
136 | GNUNET_TIME_relative_multiply | ||
137 | (GNUNET_TIME_UNIT_MILLISECONDS, 250), GNUNET_NO); | ||
138 | GNUNET_assert (server != NULL); | ||
139 | handlers[0].callback_cls = cls; | ||
140 | GNUNET_SERVER_add_handlers (server, handlers); | ||
141 | GNUNET_SERVER_disconnect_notify (server, ¬ify_disconnect, cls); | ||
142 | cfg = GNUNET_CONFIGURATION_create (); | ||
143 | |||
144 | GNUNET_CONFIGURATION_set_value_string (cfg, "test", "UNIXPATH", unixpath); | ||
145 | GNUNET_CONFIGURATION_set_value_string (cfg, "resolver", "HOSTNAME", | ||
146 | "localhost"); | ||
147 | mq = GNUNET_CLIENT_connect (cfg, | ||
148 | "test", | ||
149 | NULL, | ||
150 | NULL, | ||
151 | NULL); | ||
152 | GNUNET_assert (NULL != mq); | ||
153 | ok = 2; | ||
154 | env = GNUNET_MQ_msg (msg, | ||
155 | MY_TYPE); | ||
156 | GNUNET_MQ_send (mq, | ||
157 | env); | ||
158 | env = GNUNET_MQ_msg (msg, | ||
159 | MY_TYPE); | ||
160 | GNUNET_MQ_send (mq, | ||
161 | env); | ||
162 | } | ||
163 | |||
164 | |||
165 | int | ||
166 | main (int argc, char *argv[]) | ||
167 | { | ||
168 | GNUNET_log_setup ("test_server_with_client_unix", | ||
169 | "WARNING", | ||
170 | NULL); | ||
171 | ok = 1; | ||
172 | GNUNET_SCHEDULER_run (&task, NULL); | ||
173 | return ok; | ||
174 | } | ||
175 | |||
176 | /* end of test_server_with_client_unix.c */ | ||
diff --git a/src/util/test_service.c b/src/util/test_service.c index d2136b42f..1567c97ce 100644 --- a/src/util/test_service.c +++ b/src/util/test_service.c | |||
@@ -148,7 +148,7 @@ check (const char *sname) | |||
148 | sname); | 148 | sname); |
149 | global_ret = 1; | 149 | global_ret = 1; |
150 | GNUNET_assert (0 == | 150 | GNUNET_assert (0 == |
151 | GNUNET_SERVICE_ruN_ (3, | 151 | GNUNET_SERVICE_run_ (3, |
152 | argv, | 152 | argv, |
153 | sname, | 153 | sname, |
154 | GNUNET_SERVICE_OPTION_NONE, | 154 | GNUNET_SERVICE_OPTION_NONE, |
diff --git a/src/util/util.conf b/src/util/util.conf index ecc94ead0..ceb5fdcbb 100644 --- a/src/util/util.conf +++ b/src/util/util.conf | |||
@@ -37,9 +37,8 @@ GNUNET_RUNTIME_DIR = ${TMPDIR:-${TMP:-/tmp}}/gnunet-system-runtime/ | |||
37 | GNUNET_USER_RUNTIME_DIR = ${TMPDIR:-${TMP:-/tmp}}/gnunet-${USERHOME:-${USER:-user}}-runtime/ | 37 | GNUNET_USER_RUNTIME_DIR = ${TMPDIR:-${TMP:-/tmp}}/gnunet-${USERHOME:-${USER:-user}}-runtime/ |
38 | 38 | ||
39 | 39 | ||
40 | # Legacy option... | 40 | # Override for GNUNET_HOME used by test cases. |
41 | # GNUNET_TEST_HOME = ~/.gnunet/ | 41 | # GNUNET_TEST_HOME = /tmp/foo/bar |
42 | # GNUNET_TEST_HOME = /var/lib/gnunet/ | ||
43 | 42 | ||
44 | # DEFAULTCONFIG = /etc/gnunet.conf | 43 | # DEFAULTCONFIG = /etc/gnunet.conf |
45 | # If 'DEFAULTCONFIG' is not defined, the current | 44 | # If 'DEFAULTCONFIG' is not defined, the current |