diff options
Diffstat (limited to 'src/core')
31 files changed, 0 insertions, 9260 deletions
diff --git a/src/core/.gitignore b/src/core/.gitignore deleted file mode 100644 index cdd1f93c2..000000000 --- a/src/core/.gitignore +++ /dev/null | |||
@@ -1,9 +0,0 @@ | |||
1 | gnunet-service-core | ||
2 | gnunet-core | ||
3 | test_core_api | ||
4 | test_core_api_reliability | ||
5 | test_core_api_send_to_self | ||
6 | test_core_api_start_only | ||
7 | test_core_quota_compliance_asymmetric_recv_limited | ||
8 | test_core_quota_compliance_asymmetric_send_limited | ||
9 | test_core_quota_compliance_symmetric | ||
diff --git a/src/core/Makefile.am b/src/core/Makefile.am deleted file mode 100644 index e51247e18..000000000 --- a/src/core/Makefile.am +++ /dev/null | |||
@@ -1,143 +0,0 @@ | |||
1 | # This Makefile.am is in the public domain | ||
2 | AM_CPPFLAGS = -I$(top_srcdir)/src/include | ||
3 | |||
4 | pkgcfgdir= $(pkgdatadir)/config.d/ | ||
5 | |||
6 | libexecdir= $(pkglibdir)/libexec/ | ||
7 | |||
8 | pkgcfg_DATA = \ | ||
9 | core.conf | ||
10 | |||
11 | if USE_COVERAGE | ||
12 | AM_CFLAGS = --coverage -O0 | ||
13 | XLIB = -lgcov | ||
14 | endif | ||
15 | |||
16 | |||
17 | lib_LTLIBRARIES = \ | ||
18 | libgnunetcore.la | ||
19 | |||
20 | libgnunetcore_la_SOURCES = \ | ||
21 | core_api.c core.h \ | ||
22 | core_api_monitor_peers.c | ||
23 | libgnunetcore_la_LIBADD = \ | ||
24 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
25 | $(GN_LIBINTL) $(XLIB) | ||
26 | libgnunetcore_la_LDFLAGS = \ | ||
27 | $(GN_LIB_LDFLAGS) \ | ||
28 | -version-info 0:1:0 | ||
29 | |||
30 | |||
31 | libexec_PROGRAMS = \ | ||
32 | gnunet-service-core | ||
33 | |||
34 | bin_PROGRAMS = \ | ||
35 | gnunet-core | ||
36 | |||
37 | gnunet_service_core_SOURCES = \ | ||
38 | gnunet-service-core.c gnunet-service-core.h \ | ||
39 | gnunet-service-core_kx.c gnunet-service-core_kx.h \ | ||
40 | gnunet-service-core_sessions.c gnunet-service-core_sessions.h \ | ||
41 | gnunet-service-core_typemap.c gnunet-service-core_typemap.h | ||
42 | gnunet_service_core_LDADD = \ | ||
43 | $(top_builddir)/src/statistics/libgnunetstatistics.la \ | ||
44 | $(top_builddir)/src/transport/libgnunettransport.la \ | ||
45 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
46 | $(GN_LIBINTL) $(Z_LIBS) | ||
47 | |||
48 | |||
49 | gnunet_core_SOURCES = \ | ||
50 | gnunet-core.c | ||
51 | gnunet_core_LDADD = \ | ||
52 | libgnunetcore.la \ | ||
53 | $(top_builddir)/src/util/libgnunetutil.la | ||
54 | gnunet_core_LDFLAGS = \ | ||
55 | $(GN_LIBINTL) | ||
56 | |||
57 | TESTING_TESTS = \ | ||
58 | test_core_api_send_to_self | ||
59 | |||
60 | check_PROGRAMS = \ | ||
61 | test_core_api_start_only \ | ||
62 | test_core_api \ | ||
63 | test_core_api_reliability \ | ||
64 | test_core_quota_compliance_symmetric \ | ||
65 | test_core_quota_compliance_asymmetric_send_limited \ | ||
66 | test_core_quota_compliance_asymmetric_recv_limited \ | ||
67 | $(TESTING_TESTS) | ||
68 | |||
69 | if ENABLE_TEST_RUN | ||
70 | AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME; | ||
71 | TESTS = $(check_PROGRAMS) | ||
72 | endif | ||
73 | |||
74 | test_core_api_SOURCES = \ | ||
75 | test_core_api.c | ||
76 | test_core_api_LDADD = \ | ||
77 | libgnunetcore.la \ | ||
78 | $(top_builddir)/src/transport/libgnunettransport.la \ | ||
79 | $(top_builddir)/src/ats/libgnunetats.la \ | ||
80 | $(top_builddir)/src/util/libgnunetutil.la | ||
81 | |||
82 | test_core_api_reliability_SOURCES = \ | ||
83 | test_core_api_reliability.c | ||
84 | test_core_api_reliability_LDADD = \ | ||
85 | libgnunetcore.la \ | ||
86 | $(top_builddir)/src/transport/libgnunettransport.la \ | ||
87 | $(top_builddir)/src/ats/libgnunetats.la \ | ||
88 | $(top_builddir)/src/util/libgnunetutil.la | ||
89 | |||
90 | test_core_api_send_to_self_SOURCES = \ | ||
91 | test_core_api_send_to_self.c | ||
92 | test_core_api_send_to_self_LDADD = \ | ||
93 | libgnunetcore.la \ | ||
94 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
95 | $(top_builddir)/src/transport/libgnunettransport.la \ | ||
96 | $(top_builddir)/src/util/libgnunetutil.la | ||
97 | |||
98 | test_core_api_start_only_SOURCES = \ | ||
99 | test_core_api_start_only.c | ||
100 | test_core_api_start_only_LDADD = \ | ||
101 | $(top_builddir)/src/testing/libgnunettesting.la \ | ||
102 | libgnunetcore.la \ | ||
103 | $(top_builddir)/src/util/libgnunetutil.la | ||
104 | |||
105 | test_core_quota_compliance_symmetric_SOURCES = \ | ||
106 | test_core_quota_compliance.c | ||
107 | test_core_quota_compliance_symmetric_LDADD = \ | ||
108 | libgnunetcore.la \ | ||
109 | $(top_builddir)/src/transport/libgnunettransport.la \ | ||
110 | $(top_builddir)/src/ats/libgnunetats.la \ | ||
111 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
112 | $(top_builddir)/src/statistics/libgnunetstatistics.la | ||
113 | |||
114 | test_core_quota_compliance_asymmetric_send_limited_SOURCES = \ | ||
115 | test_core_quota_compliance.c | ||
116 | test_core_quota_compliance_asymmetric_send_limited_LDADD = \ | ||
117 | libgnunetcore.la \ | ||
118 | $(top_builddir)/src/transport/libgnunettransport.la \ | ||
119 | $(top_builddir)/src/ats/libgnunetats.la \ | ||
120 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
121 | $(top_builddir)/src/statistics/libgnunetstatistics.la | ||
122 | |||
123 | test_core_quota_compliance_asymmetric_recv_limited_SOURCES = \ | ||
124 | test_core_quota_compliance.c | ||
125 | test_core_quota_compliance_asymmetric_recv_limited_LDADD = \ | ||
126 | libgnunetcore.la \ | ||
127 | $(top_builddir)/src/transport/libgnunettransport.la \ | ||
128 | $(top_builddir)/src/ats/libgnunetats.la \ | ||
129 | $(top_builddir)/src/util/libgnunetutil.la \ | ||
130 | $(top_builddir)/src/statistics/libgnunetstatistics.la | ||
131 | |||
132 | EXTRA_DIST = \ | ||
133 | test_core_defaults.conf \ | ||
134 | test_core_api_data.conf \ | ||
135 | test_core_api_peer1.conf \ | ||
136 | test_core_api_peer2.conf \ | ||
137 | test_core_api_send_to_self.conf \ | ||
138 | test_core_quota_asymmetric_recv_limited_peer1.conf \ | ||
139 | test_core_quota_asymmetric_recv_limited_peer2.conf \ | ||
140 | test_core_quota_asymmetric_send_limit_peer1.conf \ | ||
141 | test_core_quota_asymmetric_send_limit_peer2.conf \ | ||
142 | test_core_quota_peer1.conf \ | ||
143 | test_core_quota_peer2.conf | ||
diff --git a/src/core/core.conf.in b/src/core/core.conf.in deleted file mode 100644 index 00faf6079..000000000 --- a/src/core/core.conf.in +++ /dev/null | |||
@@ -1,23 +0,0 @@ | |||
1 | [core] | ||
2 | START_ON_DEMAND = @START_ON_DEMAND@ | ||
3 | @JAVAPORT@PORT = 2092 | ||
4 | HOSTNAME = localhost | ||
5 | BINARY = gnunet-service-core | ||
6 | ACCEPT_FROM = 127.0.0.1; | ||
7 | ACCEPT_FROM6 = ::1; | ||
8 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-core.sock | ||
9 | UNIX_MATCH_UID = NO | ||
10 | UNIX_MATCH_GID = YES | ||
11 | # DISABLE_SOCKET_FORWARDING = NO | ||
12 | # USERNAME = | ||
13 | # MAXBUF = | ||
14 | # TIMEOUT = | ||
15 | # DISABLEV6 = | ||
16 | # BINDTO = | ||
17 | # REJECT_FROM = | ||
18 | # REJECT_FROM6 = | ||
19 | # PREFIX = | ||
20 | |||
21 | # Note: this MUST be set to YES in production, only set to NO for testing | ||
22 | # for performance (testbed/cluster-scale use!). | ||
23 | USE_EPHEMERAL_KEYS = YES | ||
diff --git a/src/core/core.h b/src/core/core.h deleted file mode 100644 index 4d8619a29..000000000 --- a/src/core/core.h +++ /dev/null | |||
@@ -1,328 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009-2014 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file core/core.h | ||
23 | * @brief common internal definitions for core service | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #ifndef CORE_H | ||
27 | #define CORE_H | ||
28 | |||
29 | #include "gnunet_bandwidth_lib.h" | ||
30 | #include "gnunet_transport_service.h" | ||
31 | #include "gnunet_crypto_lib.h" | ||
32 | #include "gnunet_time_lib.h" | ||
33 | |||
34 | /** | ||
35 | * General core debugging. | ||
36 | */ | ||
37 | #define DEBUG_CORE GNUNET_EXTRA_LOGGING | ||
38 | |||
39 | /** | ||
40 | * Definition of bits in the InitMessage's options field that specify | ||
41 | * which events this client cares about. Note that inbound messages | ||
42 | * for handlers that were specifically registered are always | ||
43 | * transmitted to the client. | ||
44 | */ | ||
45 | #define GNUNET_CORE_OPTION_NOTHING 0 | ||
46 | |||
47 | /** | ||
48 | * Client cares about connectivity changes. | ||
49 | */ | ||
50 | #define GNUNET_CORE_OPTION_SEND_STATUS_CHANGE 4 | ||
51 | |||
52 | /** | ||
53 | * Client wants all inbound messages in full. | ||
54 | */ | ||
55 | #define GNUNET_CORE_OPTION_SEND_FULL_INBOUND 8 | ||
56 | |||
57 | /** | ||
58 | * Client just wants the 4-byte message headers of | ||
59 | * all inbound messages. | ||
60 | */ | ||
61 | #define GNUNET_CORE_OPTION_SEND_HDR_INBOUND 16 | ||
62 | |||
63 | /** | ||
64 | * Client wants all outbound messages in full. | ||
65 | */ | ||
66 | #define GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND 32 | ||
67 | |||
68 | /** | ||
69 | * Client just wants the 4-byte message headers of | ||
70 | * all outbound messages. | ||
71 | */ | ||
72 | #define GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND 64 | ||
73 | |||
74 | |||
75 | GNUNET_NETWORK_STRUCT_BEGIN | ||
76 | |||
77 | /** | ||
78 | * Message transmitted core clients to gnunet-service-core | ||
79 | * to start the interaction. This header is followed by | ||
80 | * uint16_t type values specifying which messages this | ||
81 | * client is interested in. | ||
82 | */ | ||
83 | struct InitMessage | ||
84 | { | ||
85 | /** | ||
86 | * Header with type #GNUNET_MESSAGE_TYPE_CORE_INIT. | ||
87 | */ | ||
88 | struct GNUNET_MessageHeader header; | ||
89 | |||
90 | /** | ||
91 | * Options, see GNUNET_CORE_OPTION_ values. | ||
92 | */ | ||
93 | uint32_t options GNUNET_PACKED; | ||
94 | }; | ||
95 | |||
96 | |||
97 | /** | ||
98 | * Message transmitted by the gnunet-service-core process | ||
99 | * to its clients in response to an INIT message. | ||
100 | */ | ||
101 | struct InitReplyMessage | ||
102 | { | ||
103 | /** | ||
104 | * Header with type #GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY | ||
105 | */ | ||
106 | struct GNUNET_MessageHeader header; | ||
107 | |||
108 | /** | ||
109 | * Always zero. | ||
110 | */ | ||
111 | uint32_t reserved GNUNET_PACKED; | ||
112 | |||
113 | /** | ||
114 | * Public key of the local peer. | ||
115 | */ | ||
116 | struct GNUNET_PeerIdentity my_identity; | ||
117 | }; | ||
118 | |||
119 | |||
120 | /** | ||
121 | * Message sent by the service to clients to notify them | ||
122 | * about a peer connecting. | ||
123 | */ | ||
124 | struct ConnectNotifyMessage | ||
125 | { | ||
126 | /** | ||
127 | * Header with type #GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT | ||
128 | */ | ||
129 | struct GNUNET_MessageHeader header; | ||
130 | |||
131 | /** | ||
132 | * Always zero. | ||
133 | */ | ||
134 | uint32_t reserved GNUNET_PACKED; | ||
135 | |||
136 | /** | ||
137 | * Identity of the connecting peer. | ||
138 | */ | ||
139 | struct GNUNET_PeerIdentity peer; | ||
140 | }; | ||
141 | |||
142 | |||
143 | /** | ||
144 | * Message sent by the service to clients to notify them | ||
145 | * about a peer disconnecting. | ||
146 | */ | ||
147 | struct DisconnectNotifyMessage | ||
148 | { | ||
149 | /** | ||
150 | * Header with type #GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT. | ||
151 | */ | ||
152 | struct GNUNET_MessageHeader header; | ||
153 | |||
154 | /** | ||
155 | * Always zero. | ||
156 | */ | ||
157 | uint32_t reserved GNUNET_PACKED; | ||
158 | |||
159 | /** | ||
160 | * Identity of the connecting peer. | ||
161 | */ | ||
162 | struct GNUNET_PeerIdentity peer; | ||
163 | }; | ||
164 | |||
165 | |||
166 | /** | ||
167 | * Message sent by the service to clients to notify them about | ||
168 | * messages being received or transmitted. This overall message is | ||
169 | * followed by the real message, or just the header of the real | ||
170 | * message (depending on the client's preferences). The receiver can | ||
171 | * tell if it got the full message or only a partial message by | ||
172 | * looking at the size field in the header of NotifyTrafficMessage and | ||
173 | * checking it with the size field in the message that follows. | ||
174 | */ | ||
175 | struct NotifyTrafficMessage | ||
176 | { | ||
177 | /** | ||
178 | * Header with type #GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND | ||
179 | * or #GNUNET_MESSAGE_TYPE_CORE_NOTIFY_OUTBOUND. | ||
180 | */ | ||
181 | struct GNUNET_MessageHeader header; | ||
182 | |||
183 | /** | ||
184 | * Identity of the receiver or sender. | ||
185 | */ | ||
186 | struct GNUNET_PeerIdentity peer; | ||
187 | |||
188 | /* Followed by payload (message or just header), variable size */ | ||
189 | }; | ||
190 | |||
191 | |||
192 | /** | ||
193 | * Client notifying core about the maximum-priority | ||
194 | * message it has in the queue for a particular target. | ||
195 | */ | ||
196 | struct SendMessageRequest | ||
197 | { | ||
198 | /** | ||
199 | * Header with type #GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST | ||
200 | */ | ||
201 | struct GNUNET_MessageHeader header; | ||
202 | |||
203 | /** | ||
204 | * How important is this message? | ||
205 | */ | ||
206 | uint32_t priority GNUNET_PACKED; | ||
207 | |||
208 | /** | ||
209 | * By what time would the sender really like to see this | ||
210 | * message transmitted? | ||
211 | */ | ||
212 | struct GNUNET_TIME_AbsoluteNBO deadline; | ||
213 | |||
214 | /** | ||
215 | * Identity of the intended target. | ||
216 | */ | ||
217 | struct GNUNET_PeerIdentity peer; | ||
218 | |||
219 | /** | ||
220 | * Always zero. | ||
221 | */ | ||
222 | uint32_t reserved GNUNET_PACKED; | ||
223 | |||
224 | /** | ||
225 | * How large is the message? | ||
226 | */ | ||
227 | uint16_t size GNUNET_PACKED; | ||
228 | |||
229 | /** | ||
230 | * Counter for this peer to match SMRs to replies. | ||
231 | */ | ||
232 | uint16_t smr_id GNUNET_PACKED; | ||
233 | }; | ||
234 | |||
235 | |||
236 | /** | ||
237 | * Core notifying client that it is allowed to now | ||
238 | * transmit a message to the given target | ||
239 | * (response to #GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST). | ||
240 | */ | ||
241 | struct SendMessageReady | ||
242 | { | ||
243 | /** | ||
244 | * Header with type #GNUNET_MESSAGE_TYPE_CORE_SEND_READY | ||
245 | */ | ||
246 | struct GNUNET_MessageHeader header; | ||
247 | |||
248 | /** | ||
249 | * How many bytes are allowed for transmission? | ||
250 | * Guaranteed to be at least as big as the requested size, | ||
251 | * or ZERO if the request is rejected (will timeout, | ||
252 | * peer disconnected, queue full, etc.). | ||
253 | */ | ||
254 | uint16_t size GNUNET_PACKED; | ||
255 | |||
256 | /** | ||
257 | * smr_id from the request. | ||
258 | */ | ||
259 | uint16_t smr_id GNUNET_PACKED; | ||
260 | |||
261 | /** | ||
262 | * Identity of the intended target. | ||
263 | */ | ||
264 | struct GNUNET_PeerIdentity peer; | ||
265 | }; | ||
266 | |||
267 | |||
268 | /** | ||
269 | * Client asking core to transmit a particular message to a particular | ||
270 | * target (response to #GNUNET_MESSAGE_TYPE_CORE_SEND_READY). | ||
271 | */ | ||
272 | struct SendMessage | ||
273 | { | ||
274 | /** | ||
275 | * Header with type #GNUNET_MESSAGE_TYPE_CORE_SEND | ||
276 | */ | ||
277 | struct GNUNET_MessageHeader header; | ||
278 | |||
279 | /** | ||
280 | * How important is this message? Contains a | ||
281 | * `enum GNUNET_MQ_PriorityPreferences` in NBO. | ||
282 | */ | ||
283 | uint32_t priority GNUNET_PACKED; | ||
284 | |||
285 | /** | ||
286 | * By what time would the sender really like to see this | ||
287 | * message transmitted? | ||
288 | */ | ||
289 | struct GNUNET_TIME_AbsoluteNBO deadline; | ||
290 | |||
291 | /** | ||
292 | * Identity of the intended receiver. | ||
293 | */ | ||
294 | struct GNUNET_PeerIdentity peer; | ||
295 | }; | ||
296 | |||
297 | |||
298 | /** | ||
299 | * Message sent by the service to monitor clients to notify them | ||
300 | * about a peer changing status. | ||
301 | */ | ||
302 | struct MonitorNotifyMessage | ||
303 | { | ||
304 | /** | ||
305 | * Header with type #GNUNET_MESSAGE_TYPE_CORE_MONITOR_NOTIFY | ||
306 | */ | ||
307 | struct GNUNET_MessageHeader header; | ||
308 | |||
309 | /** | ||
310 | * New peer state, an `enum GNUNET_CORE_KxState` in NBO. | ||
311 | */ | ||
312 | uint32_t state GNUNET_PACKED; | ||
313 | |||
314 | /** | ||
315 | * Identity of the peer. | ||
316 | */ | ||
317 | struct GNUNET_PeerIdentity peer; | ||
318 | |||
319 | /** | ||
320 | * How long will we stay in this state (if nothing else happens)? | ||
321 | */ | ||
322 | struct GNUNET_TIME_AbsoluteNBO timeout; | ||
323 | }; | ||
324 | |||
325 | |||
326 | GNUNET_NETWORK_STRUCT_END | ||
327 | #endif | ||
328 | /* end of core.h */ | ||
diff --git a/src/core/core_api.c b/src/core/core_api.c deleted file mode 100644 index 81118693d..000000000 --- a/src/core/core_api.c +++ /dev/null | |||
@@ -1,773 +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 it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @file core/core_api.c | ||
22 | * @brief core service; this is the main API for encrypted P2P | ||
23 | * communications | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet_util_lib.h" | ||
28 | #include "gnunet_constants.h" | ||
29 | #include "gnunet_core_service.h" | ||
30 | #include "core.h" | ||
31 | |||
32 | #define LOG(kind, ...) GNUNET_log_from (kind, "core-api", __VA_ARGS__) | ||
33 | |||
34 | |||
35 | /** | ||
36 | * Information we track for each peer. | ||
37 | */ | ||
38 | struct PeerRecord | ||
39 | { | ||
40 | /** | ||
41 | * Corresponding CORE handle. | ||
42 | */ | ||
43 | struct GNUNET_CORE_Handle *h; | ||
44 | |||
45 | /** | ||
46 | * Message queue for the peer. | ||
47 | */ | ||
48 | struct GNUNET_MQ_Handle *mq; | ||
49 | |||
50 | /** | ||
51 | * Message we are currently trying to pass to the CORE service | ||
52 | * for this peer (from @e mq). | ||
53 | */ | ||
54 | struct GNUNET_MQ_Envelope *env; | ||
55 | |||
56 | /** | ||
57 | * Value the client returned when we connected, used | ||
58 | * as the closure in various places. | ||
59 | */ | ||
60 | void *client_cls; | ||
61 | |||
62 | /** | ||
63 | * Peer the record is about. | ||
64 | */ | ||
65 | struct GNUNET_PeerIdentity peer; | ||
66 | |||
67 | /** | ||
68 | * SendMessageRequest ID generator for this peer. | ||
69 | */ | ||
70 | uint16_t smr_id_gen; | ||
71 | }; | ||
72 | |||
73 | |||
74 | /** | ||
75 | * Context for the core service connection. | ||
76 | */ | ||
77 | struct GNUNET_CORE_Handle | ||
78 | { | ||
79 | /** | ||
80 | * Configuration we're using. | ||
81 | */ | ||
82 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
83 | |||
84 | /** | ||
85 | * Closure for the various callbacks. | ||
86 | */ | ||
87 | void *cls; | ||
88 | |||
89 | /** | ||
90 | * Function to call once we've handshaked with the core service. | ||
91 | */ | ||
92 | GNUNET_CORE_StartupCallback init; | ||
93 | |||
94 | /** | ||
95 | * Function to call whenever we're notified about a peer connecting. | ||
96 | */ | ||
97 | GNUNET_CORE_ConnectEventHandler connects; | ||
98 | |||
99 | /** | ||
100 | * Function to call whenever we're notified about a peer disconnecting. | ||
101 | */ | ||
102 | GNUNET_CORE_DisconnectEventHandler disconnects; | ||
103 | |||
104 | /** | ||
105 | * Function handlers for messages of particular type. | ||
106 | */ | ||
107 | struct GNUNET_MQ_MessageHandler *handlers; | ||
108 | |||
109 | /** | ||
110 | * Our message queue for transmissions to the service. | ||
111 | */ | ||
112 | struct GNUNET_MQ_Handle *mq; | ||
113 | |||
114 | /** | ||
115 | * Hash map listing all of the peers that we are currently | ||
116 | * connected to. | ||
117 | */ | ||
118 | struct GNUNET_CONTAINER_MultiPeerMap *peers; | ||
119 | |||
120 | /** | ||
121 | * Identity of this peer. | ||
122 | */ | ||
123 | struct GNUNET_PeerIdentity me; | ||
124 | |||
125 | /** | ||
126 | * ID of reconnect task (if any). | ||
127 | */ | ||
128 | struct GNUNET_SCHEDULER_Task *reconnect_task; | ||
129 | |||
130 | /** | ||
131 | * Current delay we use for re-trying to connect to core. | ||
132 | */ | ||
133 | struct GNUNET_TIME_Relative retry_backoff; | ||
134 | |||
135 | /** | ||
136 | * Number of entries in the handlers array. | ||
137 | */ | ||
138 | unsigned int hcnt; | ||
139 | |||
140 | /** | ||
141 | * Did we ever get INIT? | ||
142 | */ | ||
143 | int have_init; | ||
144 | }; | ||
145 | |||
146 | |||
147 | /** | ||
148 | * Our current client connection went down. Clean it up | ||
149 | * and try to reconnect! | ||
150 | * | ||
151 | * @param h our handle to the core service | ||
152 | */ | ||
153 | static void | ||
154 | reconnect (struct GNUNET_CORE_Handle *h); | ||
155 | |||
156 | |||
157 | /** | ||
158 | * Task schedule to try to re-connect to core. | ||
159 | * | ||
160 | * @param cls the `struct GNUNET_CORE_Handle` | ||
161 | * @param tc task context | ||
162 | */ | ||
163 | static void | ||
164 | reconnect_task (void *cls) | ||
165 | { | ||
166 | struct GNUNET_CORE_Handle *h = cls; | ||
167 | |||
168 | h->reconnect_task = NULL; | ||
169 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to CORE service after delay\n"); | ||
170 | reconnect (h); | ||
171 | } | ||
172 | |||
173 | |||
174 | /** | ||
175 | * Notify clients about disconnect and free the entry for connected | ||
176 | * peer. | ||
177 | * | ||
178 | * @param cls the `struct GNUNET_CORE_Handle *` | ||
179 | * @param key the peer identity (not used) | ||
180 | * @param value the `struct PeerRecord` to free. | ||
181 | * @return #GNUNET_YES (continue) | ||
182 | */ | ||
183 | static int | ||
184 | disconnect_and_free_peer_entry (void *cls, | ||
185 | const struct GNUNET_PeerIdentity *key, | ||
186 | void *value) | ||
187 | { | ||
188 | struct GNUNET_CORE_Handle *h = cls; | ||
189 | struct PeerRecord *pr = value; | ||
190 | |||
191 | GNUNET_assert (pr->h == h); | ||
192 | if (NULL != h->disconnects) | ||
193 | h->disconnects (h->cls, &pr->peer, pr->client_cls); | ||
194 | GNUNET_assert (GNUNET_YES == | ||
195 | GNUNET_CONTAINER_multipeermap_remove (h->peers, key, pr)); | ||
196 | GNUNET_MQ_destroy (pr->mq); | ||
197 | GNUNET_assert (NULL == pr->mq); | ||
198 | if (NULL != pr->env) | ||
199 | { | ||
200 | GNUNET_MQ_discard (pr->env); | ||
201 | pr->env = NULL; | ||
202 | } | ||
203 | GNUNET_free (pr); | ||
204 | return GNUNET_YES; | ||
205 | } | ||
206 | |||
207 | |||
208 | /** | ||
209 | * Close down any existing connection to the CORE service and | ||
210 | * try re-establishing it later. | ||
211 | * | ||
212 | * @param h our handle | ||
213 | */ | ||
214 | static void | ||
215 | reconnect_later (struct GNUNET_CORE_Handle *h) | ||
216 | { | ||
217 | GNUNET_assert (NULL == h->reconnect_task); | ||
218 | if (NULL != h->mq) | ||
219 | { | ||
220 | GNUNET_MQ_destroy (h->mq); | ||
221 | h->mq = NULL; | ||
222 | } | ||
223 | GNUNET_assert (NULL == h->reconnect_task); | ||
224 | h->reconnect_task = | ||
225 | GNUNET_SCHEDULER_add_delayed (h->retry_backoff, &reconnect_task, h); | ||
226 | GNUNET_CONTAINER_multipeermap_iterate (h->peers, | ||
227 | &disconnect_and_free_peer_entry, | ||
228 | h); | ||
229 | h->retry_backoff = GNUNET_TIME_STD_BACKOFF (h->retry_backoff); | ||
230 | } | ||
231 | |||
232 | |||
233 | /** | ||
234 | * Error handler for the message queue to the CORE service. | ||
235 | * On errors, we reconnect. | ||
236 | * | ||
237 | * @param cls closure, a `struct GNUNET_CORE_Handle *` | ||
238 | * @param error error code | ||
239 | */ | ||
240 | static void | ||
241 | handle_mq_error (void *cls, enum GNUNET_MQ_Error error) | ||
242 | { | ||
243 | struct GNUNET_CORE_Handle *h = cls; | ||
244 | |||
245 | LOG (GNUNET_ERROR_TYPE_DEBUG, "MQ ERROR: %d\n", error); | ||
246 | reconnect_later (h); | ||
247 | } | ||
248 | |||
249 | |||
250 | /** | ||
251 | * Implement sending functionality of a message queue for | ||
252 | * us sending messages to a peer. | ||
253 | * | ||
254 | * @param mq the message queue | ||
255 | * @param msg the message to send | ||
256 | * @param impl_state state of the implementation | ||
257 | */ | ||
258 | static void | ||
259 | core_mq_send_impl (struct GNUNET_MQ_Handle *mq, | ||
260 | const struct GNUNET_MessageHeader *msg, | ||
261 | void *impl_state) | ||
262 | { | ||
263 | struct PeerRecord *pr = impl_state; | ||
264 | struct GNUNET_CORE_Handle *h = pr->h; | ||
265 | struct SendMessageRequest *smr; | ||
266 | struct SendMessage *sm; | ||
267 | struct GNUNET_MQ_Envelope *env; | ||
268 | uint16_t msize; | ||
269 | enum GNUNET_MQ_PriorityPreferences flags; | ||
270 | |||
271 | if (NULL == h->mq) | ||
272 | { | ||
273 | /* We're currently reconnecting, pretend this worked */ | ||
274 | GNUNET_MQ_impl_send_continue (mq); | ||
275 | return; | ||
276 | } | ||
277 | GNUNET_assert (NULL == pr->env); | ||
278 | /* extract options from envelope */ | ||
279 | env = GNUNET_MQ_get_current_envelope (mq); | ||
280 | flags = GNUNET_MQ_env_get_options (env); | ||
281 | |||
282 | /* check message size for sanity */ | ||
283 | msize = ntohs (msg->size); | ||
284 | if (msize >= GNUNET_MAX_MESSAGE_SIZE - sizeof(struct SendMessage)) | ||
285 | { | ||
286 | GNUNET_break (0); | ||
287 | GNUNET_MQ_impl_send_continue (mq); | ||
288 | return; | ||
289 | } | ||
290 | |||
291 | /* ask core for transmission */ | ||
292 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
293 | "Asking core for transmission of %u bytes to `%s'\n", | ||
294 | (unsigned int) msize, | ||
295 | GNUNET_i2s (&pr->peer)); | ||
296 | env = GNUNET_MQ_msg (smr, GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST); | ||
297 | smr->priority = htonl ((uint32_t) flags); | ||
298 | smr->peer = pr->peer; | ||
299 | smr->size = htons (msize); | ||
300 | smr->smr_id = htons (++pr->smr_id_gen); | ||
301 | GNUNET_MQ_send (h->mq, env); | ||
302 | |||
303 | /* prepare message with actual transmission data */ | ||
304 | pr->env = GNUNET_MQ_msg_nested_mh (sm, GNUNET_MESSAGE_TYPE_CORE_SEND, msg); | ||
305 | sm->priority = htonl ((uint32_t) flags); | ||
306 | sm->peer = pr->peer; | ||
307 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
308 | "Calling get_message with buffer of %u bytes\n", | ||
309 | (unsigned int) msize); | ||
310 | } | ||
311 | |||
312 | |||
313 | /** | ||
314 | * Handle destruction of a message queue. Implementations must not | ||
315 | * free @a mq, but should take care of @a impl_state. | ||
316 | * | ||
317 | * @param mq the message queue to destroy | ||
318 | * @param impl_state state of the implementation | ||
319 | */ | ||
320 | static void | ||
321 | core_mq_destroy_impl (struct GNUNET_MQ_Handle *mq, void *impl_state) | ||
322 | { | ||
323 | struct PeerRecord *pr = impl_state; | ||
324 | |||
325 | GNUNET_assert (mq == pr->mq); | ||
326 | pr->mq = NULL; | ||
327 | } | ||
328 | |||
329 | |||
330 | /** | ||
331 | * Implementation function that cancels the currently sent message. | ||
332 | * Should basically undo whatever #mq_send_impl() did. | ||
333 | * | ||
334 | * @param mq message queue | ||
335 | * @param impl_state state specific to the implementation | ||
336 | */ | ||
337 | static void | ||
338 | core_mq_cancel_impl (struct GNUNET_MQ_Handle *mq, void *impl_state) | ||
339 | { | ||
340 | struct PeerRecord *pr = impl_state; | ||
341 | |||
342 | (void) mq; | ||
343 | GNUNET_assert (NULL != pr->env); | ||
344 | GNUNET_MQ_discard (pr->env); | ||
345 | pr->env = NULL; | ||
346 | } | ||
347 | |||
348 | |||
349 | /** | ||
350 | * We had an error processing a message we forwarded from a peer to | ||
351 | * the CORE service. We should just complain about it but otherwise | ||
352 | * continue processing. | ||
353 | * | ||
354 | * @param cls closure | ||
355 | * @param error error code | ||
356 | */ | ||
357 | static void | ||
358 | core_mq_error_handler (void *cls, enum GNUNET_MQ_Error error) | ||
359 | { | ||
360 | /* struct PeerRecord *pr = cls; */ | ||
361 | (void) cls; | ||
362 | (void) error; | ||
363 | GNUNET_break_op (0); | ||
364 | } | ||
365 | |||
366 | |||
367 | /** | ||
368 | * Add the given peer to the list of our connected peers | ||
369 | * and create the respective data structures and notify | ||
370 | * the application. | ||
371 | * | ||
372 | * @param h the core handle | ||
373 | * @param peer the peer that is connecting to us | ||
374 | */ | ||
375 | static void | ||
376 | connect_peer (struct GNUNET_CORE_Handle *h, | ||
377 | const struct GNUNET_PeerIdentity *peer) | ||
378 | { | ||
379 | struct PeerRecord *pr; | ||
380 | |||
381 | pr = GNUNET_new (struct PeerRecord); | ||
382 | pr->peer = *peer; | ||
383 | pr->h = h; | ||
384 | GNUNET_assert (GNUNET_YES == | ||
385 | GNUNET_CONTAINER_multipeermap_put ( | ||
386 | h->peers, | ||
387 | &pr->peer, | ||
388 | pr, | ||
389 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
390 | pr->mq = GNUNET_MQ_queue_for_callbacks (&core_mq_send_impl, | ||
391 | &core_mq_destroy_impl, | ||
392 | &core_mq_cancel_impl, | ||
393 | pr, | ||
394 | h->handlers, | ||
395 | &core_mq_error_handler, | ||
396 | pr); | ||
397 | if (NULL != h->connects) | ||
398 | { | ||
399 | pr->client_cls = h->connects (h->cls, &pr->peer, pr->mq); | ||
400 | GNUNET_MQ_set_handlers_closure (pr->mq, pr->client_cls); | ||
401 | } | ||
402 | } | ||
403 | |||
404 | |||
405 | /** | ||
406 | * Handle init reply message received from CORE service. Notify | ||
407 | * application that we are now connected to the CORE. Also fake | ||
408 | * loopback connection. | ||
409 | * | ||
410 | * @param cls the `struct GNUNET_CORE_Handle` | ||
411 | * @param m the init reply | ||
412 | */ | ||
413 | static void | ||
414 | handle_init_reply (void *cls, const struct InitReplyMessage *m) | ||
415 | { | ||
416 | struct GNUNET_CORE_Handle *h = cls; | ||
417 | GNUNET_CORE_StartupCallback init; | ||
418 | |||
419 | GNUNET_break (0 == ntohl (m->reserved)); | ||
420 | h->retry_backoff = GNUNET_TIME_UNIT_MILLISECONDS; | ||
421 | if (NULL != (init = h->init)) | ||
422 | { | ||
423 | /* mark so we don't call init on reconnect */ | ||
424 | h->init = NULL; | ||
425 | h->me = m->my_identity; | ||
426 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
427 | "Connected to core service of peer `%s'.\n", | ||
428 | GNUNET_i2s (&h->me)); | ||
429 | h->have_init = GNUNET_YES; | ||
430 | init (h->cls, &h->me); | ||
431 | } | ||
432 | else | ||
433 | { | ||
434 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
435 | "Successfully reconnected to core service.\n"); | ||
436 | if (GNUNET_NO == h->have_init) | ||
437 | { | ||
438 | h->me = m->my_identity; | ||
439 | h->have_init = GNUNET_YES; | ||
440 | } | ||
441 | else | ||
442 | { | ||
443 | GNUNET_break (0 == memcmp (&h->me, | ||
444 | &m->my_identity, | ||
445 | sizeof(struct GNUNET_PeerIdentity))); | ||
446 | } | ||
447 | } | ||
448 | /* fake 'connect to self' */ | ||
449 | connect_peer (h, &h->me); | ||
450 | } | ||
451 | |||
452 | |||
453 | /** | ||
454 | * Handle connect message received from CORE service. | ||
455 | * Notify the application about the new connection. | ||
456 | * | ||
457 | * @param cls the `struct GNUNET_CORE_Handle` | ||
458 | * @param cnm the connect message | ||
459 | */ | ||
460 | static void | ||
461 | handle_connect_notify (void *cls, const struct ConnectNotifyMessage *cnm) | ||
462 | { | ||
463 | struct GNUNET_CORE_Handle *h = cls; | ||
464 | struct PeerRecord *pr; | ||
465 | |||
466 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
467 | "Received notification about connection from `%s'.\n", | ||
468 | GNUNET_i2s (&cnm->peer)); | ||
469 | if (0 == memcmp (&h->me, &cnm->peer, sizeof(struct GNUNET_PeerIdentity))) | ||
470 | { | ||
471 | /* connect to self!? */ | ||
472 | GNUNET_break (0); | ||
473 | return; | ||
474 | } | ||
475 | pr = GNUNET_CONTAINER_multipeermap_get (h->peers, &cnm->peer); | ||
476 | if (NULL != pr) | ||
477 | { | ||
478 | GNUNET_break (0); | ||
479 | reconnect_later (h); | ||
480 | return; | ||
481 | } | ||
482 | connect_peer (h, &cnm->peer); | ||
483 | } | ||
484 | |||
485 | |||
486 | /** | ||
487 | * Handle disconnect message received from CORE service. | ||
488 | * Notify the application about the lost connection. | ||
489 | * | ||
490 | * @param cls the `struct GNUNET_CORE_Handle` | ||
491 | * @param dnm message about the disconnect event | ||
492 | */ | ||
493 | static void | ||
494 | handle_disconnect_notify (void *cls, const struct DisconnectNotifyMessage *dnm) | ||
495 | { | ||
496 | struct GNUNET_CORE_Handle *h = cls; | ||
497 | struct PeerRecord *pr; | ||
498 | |||
499 | if (0 == memcmp (&h->me, &dnm->peer, sizeof(struct GNUNET_PeerIdentity))) | ||
500 | { | ||
501 | /* disconnect from self!? */ | ||
502 | GNUNET_break (0); | ||
503 | return; | ||
504 | } | ||
505 | GNUNET_break (0 == ntohl (dnm->reserved)); | ||
506 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
507 | "Received notification about disconnect from `%s'.\n", | ||
508 | GNUNET_i2s (&dnm->peer)); | ||
509 | pr = GNUNET_CONTAINER_multipeermap_get (h->peers, &dnm->peer); | ||
510 | if (NULL == pr) | ||
511 | { | ||
512 | GNUNET_break (0); | ||
513 | reconnect_later (h); | ||
514 | return; | ||
515 | } | ||
516 | disconnect_and_free_peer_entry (h, &pr->peer, pr); | ||
517 | } | ||
518 | |||
519 | |||
520 | /** | ||
521 | * Check that message received from CORE service is well-formed. | ||
522 | * | ||
523 | * @param cls the `struct GNUNET_CORE_Handle` | ||
524 | * @param ntm the message we got | ||
525 | * @return #GNUNET_OK if the message is well-formed | ||
526 | */ | ||
527 | static int | ||
528 | check_notify_inbound (void *cls, const struct NotifyTrafficMessage *ntm) | ||
529 | { | ||
530 | uint16_t msize; | ||
531 | const struct GNUNET_MessageHeader *em; | ||
532 | |||
533 | (void) cls; | ||
534 | msize = ntohs (ntm->header.size) - sizeof(struct NotifyTrafficMessage); | ||
535 | if (msize < sizeof(struct GNUNET_MessageHeader)) | ||
536 | { | ||
537 | GNUNET_break (0); | ||
538 | return GNUNET_SYSERR; | ||
539 | } | ||
540 | em = (const struct GNUNET_MessageHeader *) &ntm[1]; | ||
541 | if (msize != ntohs (em->size)) | ||
542 | { | ||
543 | GNUNET_break (0); | ||
544 | return GNUNET_SYSERR; | ||
545 | } | ||
546 | return GNUNET_OK; | ||
547 | } | ||
548 | |||
549 | |||
550 | /** | ||
551 | * Handle inbound message received from CORE service. If applicable, | ||
552 | * notify the application. | ||
553 | * | ||
554 | * @param cls the `struct GNUNET_CORE_Handle` | ||
555 | * @param ntm the message we got from CORE. | ||
556 | */ | ||
557 | static void | ||
558 | handle_notify_inbound (void *cls, const struct NotifyTrafficMessage *ntm) | ||
559 | { | ||
560 | struct GNUNET_CORE_Handle *h = cls; | ||
561 | const struct GNUNET_MessageHeader *em; | ||
562 | struct PeerRecord *pr; | ||
563 | |||
564 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
565 | "Received inbound message from `%s'.\n", | ||
566 | GNUNET_i2s (&ntm->peer)); | ||
567 | em = (const struct GNUNET_MessageHeader *) &ntm[1]; | ||
568 | pr = GNUNET_CONTAINER_multipeermap_get (h->peers, &ntm->peer); | ||
569 | if (NULL == pr) | ||
570 | { | ||
571 | GNUNET_break (0); | ||
572 | reconnect_later (h); | ||
573 | return; | ||
574 | } | ||
575 | GNUNET_MQ_inject_message (pr->mq, em); | ||
576 | } | ||
577 | |||
578 | |||
579 | /** | ||
580 | * Handle message received from CORE service notifying us that we are | ||
581 | * now allowed to send a message to a peer. If that message is still | ||
582 | * pending, put it into the queue to be transmitted. | ||
583 | * | ||
584 | * @param cls the `struct GNUNET_CORE_Handle` | ||
585 | * @param smr the message we got | ||
586 | */ | ||
587 | static void | ||
588 | handle_send_ready (void *cls, const struct SendMessageReady *smr) | ||
589 | { | ||
590 | struct GNUNET_CORE_Handle *h = cls; | ||
591 | struct PeerRecord *pr; | ||
592 | |||
593 | pr = GNUNET_CONTAINER_multipeermap_get (h->peers, &smr->peer); | ||
594 | if (NULL == pr) | ||
595 | { | ||
596 | GNUNET_break (0); | ||
597 | reconnect_later (h); | ||
598 | return; | ||
599 | } | ||
600 | LOG (GNUNET_ERROR_TYPE_DEBUG, | ||
601 | "Received notification about transmission readiness to `%s'.\n", | ||
602 | GNUNET_i2s (&smr->peer)); | ||
603 | if (NULL == pr->env) | ||
604 | { | ||
605 | /* request must have been cancelled between the original request | ||
606 | * and the response from CORE, ignore CORE's readiness */ | ||
607 | return; | ||
608 | } | ||
609 | if (ntohs (smr->smr_id) != pr->smr_id_gen) | ||
610 | { | ||
611 | /* READY message is for expired or cancelled message, | ||
612 | * ignore! (we should have already sent another request) */ | ||
613 | return; | ||
614 | } | ||
615 | |||
616 | /* ok, all good, send message out! */ | ||
617 | GNUNET_MQ_send (h->mq, pr->env); | ||
618 | pr->env = NULL; | ||
619 | GNUNET_MQ_impl_send_continue (pr->mq); | ||
620 | } | ||
621 | |||
622 | |||
623 | /** | ||
624 | * Our current client connection went down. Clean it up and try to | ||
625 | * reconnect! | ||
626 | * | ||
627 | * @param h our handle to the core service | ||
628 | */ | ||
629 | static void | ||
630 | reconnect (struct GNUNET_CORE_Handle *h) | ||
631 | { | ||
632 | struct GNUNET_MQ_MessageHandler handlers[] = | ||
633 | { GNUNET_MQ_hd_fixed_size (init_reply, | ||
634 | GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY, | ||
635 | struct InitReplyMessage, | ||
636 | h), | ||
637 | GNUNET_MQ_hd_fixed_size (connect_notify, | ||
638 | GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT, | ||
639 | struct ConnectNotifyMessage, | ||
640 | h), | ||
641 | GNUNET_MQ_hd_fixed_size (disconnect_notify, | ||
642 | GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT, | ||
643 | struct DisconnectNotifyMessage, | ||
644 | h), | ||
645 | GNUNET_MQ_hd_var_size (notify_inbound, | ||
646 | GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND, | ||
647 | struct NotifyTrafficMessage, | ||
648 | h), | ||
649 | GNUNET_MQ_hd_fixed_size (send_ready, | ||
650 | GNUNET_MESSAGE_TYPE_CORE_SEND_READY, | ||
651 | struct SendMessageReady, | ||
652 | h), | ||
653 | GNUNET_MQ_handler_end () }; | ||
654 | struct InitMessage *init; | ||
655 | struct GNUNET_MQ_Envelope *env; | ||
656 | uint16_t *ts; | ||
657 | |||
658 | GNUNET_assert (NULL == h->mq); | ||
659 | h->mq = GNUNET_CLIENT_connect (h->cfg, "core", handlers, &handle_mq_error, h); | ||
660 | if (NULL == h->mq) | ||
661 | { | ||
662 | reconnect_later (h); | ||
663 | return; | ||
664 | } | ||
665 | env = GNUNET_MQ_msg_extra (init, | ||
666 | sizeof(uint16_t) * h->hcnt, | ||
667 | GNUNET_MESSAGE_TYPE_CORE_INIT); | ||
668 | LOG (GNUNET_ERROR_TYPE_INFO, "(Re)connecting to CORE service\n"); | ||
669 | init->options = htonl (0); | ||
670 | ts = (uint16_t *) &init[1]; | ||
671 | for (unsigned int hpos = 0; hpos < h->hcnt; hpos++) | ||
672 | ts[hpos] = htons (h->handlers[hpos].type); | ||
673 | GNUNET_MQ_send (h->mq, env); | ||
674 | } | ||
675 | |||
676 | |||
677 | /** | ||
678 | * Connect to the core service. Note that the connection may complete | ||
679 | * (or fail) asynchronously. | ||
680 | * | ||
681 | * @param cfg configuration to use | ||
682 | * @param cls closure for the various callbacks that follow (including handlers in the handlers array) | ||
683 | * @param init callback to call once we have successfully | ||
684 | * connected to the core service | ||
685 | * @param connects function to call on peer connect, can be NULL | ||
686 | * @param disconnects function to call on peer disconnect / timeout, can be NULL | ||
687 | * @param handlers callbacks for messages we care about, NULL-terminated | ||
688 | * @return handle to the core service (only useful for disconnect until @a init is called); | ||
689 | * NULL on error (in this case, init is never called) | ||
690 | */ | ||
691 | struct GNUNET_CORE_Handle * | ||
692 | GNUNET_CORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
693 | void *cls, | ||
694 | GNUNET_CORE_StartupCallback init, | ||
695 | GNUNET_CORE_ConnectEventHandler connects, | ||
696 | GNUNET_CORE_DisconnectEventHandler disconnects, | ||
697 | const struct GNUNET_MQ_MessageHandler *handlers) | ||
698 | { | ||
699 | struct GNUNET_CORE_Handle *h; | ||
700 | |||
701 | h = GNUNET_new (struct GNUNET_CORE_Handle); | ||
702 | h->cfg = cfg; | ||
703 | h->cls = cls; | ||
704 | h->init = init; | ||
705 | h->connects = connects; | ||
706 | h->disconnects = disconnects; | ||
707 | h->peers = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_NO); | ||
708 | h->handlers = GNUNET_MQ_copy_handlers (handlers); | ||
709 | h->hcnt = GNUNET_MQ_count_handlers (handlers); | ||
710 | GNUNET_assert (h->hcnt < | ||
711 | (GNUNET_MAX_MESSAGE_SIZE - sizeof(struct InitMessage)) | ||
712 | / sizeof(uint16_t)); | ||
713 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to CORE service\n"); | ||
714 | reconnect (h); | ||
715 | if (NULL == h->mq) | ||
716 | { | ||
717 | GNUNET_CORE_disconnect (h); | ||
718 | return NULL; | ||
719 | } | ||
720 | return h; | ||
721 | } | ||
722 | |||
723 | |||
724 | /** | ||
725 | * Disconnect from the core service. | ||
726 | * | ||
727 | * @param handle connection to core to disconnect | ||
728 | */ | ||
729 | void | ||
730 | GNUNET_CORE_disconnect (struct GNUNET_CORE_Handle *handle) | ||
731 | { | ||
732 | LOG (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from CORE service\n"); | ||
733 | GNUNET_CONTAINER_multipeermap_iterate (handle->peers, | ||
734 | &disconnect_and_free_peer_entry, | ||
735 | handle); | ||
736 | GNUNET_CONTAINER_multipeermap_destroy (handle->peers); | ||
737 | handle->peers = NULL; | ||
738 | if (NULL != handle->reconnect_task) | ||
739 | { | ||
740 | GNUNET_SCHEDULER_cancel (handle->reconnect_task); | ||
741 | handle->reconnect_task = NULL; | ||
742 | } | ||
743 | if (NULL != handle->mq) | ||
744 | { | ||
745 | GNUNET_MQ_destroy (handle->mq); | ||
746 | handle->mq = NULL; | ||
747 | } | ||
748 | GNUNET_free (handle->handlers); | ||
749 | GNUNET_free (handle); | ||
750 | } | ||
751 | |||
752 | |||
753 | /** | ||
754 | * Obtain the message queue for a connected peer. | ||
755 | * | ||
756 | * @param h the core handle | ||
757 | * @param pid the identity of the peer to check if it has been connected to us | ||
758 | * @return NULL if peer is not connected | ||
759 | */ | ||
760 | struct GNUNET_MQ_Handle * | ||
761 | GNUNET_CORE_get_mq (const struct GNUNET_CORE_Handle *h, | ||
762 | const struct GNUNET_PeerIdentity *pid) | ||
763 | { | ||
764 | struct PeerRecord *pr; | ||
765 | |||
766 | pr = GNUNET_CONTAINER_multipeermap_get (h->peers, pid); | ||
767 | if (NULL == pr) | ||
768 | return NULL; | ||
769 | return pr->mq; | ||
770 | } | ||
771 | |||
772 | |||
773 | /* end of core_api.c */ | ||
diff --git a/src/core/core_api_monitor_peers.c b/src/core/core_api_monitor_peers.c deleted file mode 100644 index 3be8e3859..000000000 --- a/src/core/core_api_monitor_peers.c +++ /dev/null | |||
@@ -1,196 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009-2014, 2016 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file core/core_api_monitor_peers.c | ||
23 | * @brief implementation of the peer_iterate function | ||
24 | * @author Christian Grothoff | ||
25 | * @author Nathan Evans | ||
26 | */ | ||
27 | #include "platform.h" | ||
28 | #include "gnunet_core_service.h" | ||
29 | #include "core.h" | ||
30 | |||
31 | |||
32 | /** | ||
33 | * Handle to a CORE monitoring operation. | ||
34 | */ | ||
35 | struct GNUNET_CORE_MonitorHandle | ||
36 | { | ||
37 | /** | ||
38 | * Our configuration. | ||
39 | */ | ||
40 | const struct GNUNET_CONFIGURATION_Handle *cfg; | ||
41 | |||
42 | /** | ||
43 | * Our connection to the service. | ||
44 | */ | ||
45 | struct GNUNET_MQ_Handle *mq; | ||
46 | |||
47 | /** | ||
48 | * Function called with the peer. | ||
49 | */ | ||
50 | GNUNET_CORE_MonitorCallback peer_cb; | ||
51 | |||
52 | /** | ||
53 | * Closure for @e peer_cb. | ||
54 | */ | ||
55 | void *peer_cb_cls; | ||
56 | }; | ||
57 | |||
58 | |||
59 | /** | ||
60 | * Protocol error, reconnect to CORE service and notify | ||
61 | * client. | ||
62 | * | ||
63 | * @param mh monitoring session to reconnect to CORE | ||
64 | */ | ||
65 | static void | ||
66 | reconnect (struct GNUNET_CORE_MonitorHandle *mh); | ||
67 | |||
68 | |||
69 | /** | ||
70 | * Generic error handler, called with the appropriate error code and | ||
71 | * the same closure specified at the creation of the message queue. | ||
72 | * Not every message queue implementation supports an error handler. | ||
73 | * | ||
74 | * @param cls closure, a `struct GNUNET_CORE_MonitorHandle *` | ||
75 | * @param error error code | ||
76 | */ | ||
77 | static void | ||
78 | handle_mq_error (void *cls, enum GNUNET_MQ_Error error) | ||
79 | { | ||
80 | struct GNUNET_CORE_MonitorHandle *mh = cls; | ||
81 | |||
82 | (void) error; | ||
83 | reconnect (mh); | ||
84 | } | ||
85 | |||
86 | |||
87 | /** | ||
88 | * Receive reply from CORE service with information about a peer. | ||
89 | * | ||
90 | * @param cls our `struct GNUNET_CORE_MonitorHandle *` | ||
91 | * @param mon_message monitor message | ||
92 | */ | ||
93 | static void | ||
94 | handle_receive_info (void *cls, const struct MonitorNotifyMessage *mon_message) | ||
95 | { | ||
96 | struct GNUNET_CORE_MonitorHandle *mh = cls; | ||
97 | |||
98 | mh->peer_cb (mh->peer_cb_cls, | ||
99 | &mon_message->peer, | ||
100 | (enum GNUNET_CORE_KxState) ntohl (mon_message->state), | ||
101 | GNUNET_TIME_absolute_ntoh (mon_message->timeout)); | ||
102 | } | ||
103 | |||
104 | |||
105 | /** | ||
106 | * Protocol error, reconnect to CORE service and notify | ||
107 | * client. | ||
108 | * | ||
109 | * @param mh monitoring session to reconnect to CORE | ||
110 | */ | ||
111 | static void | ||
112 | reconnect (struct GNUNET_CORE_MonitorHandle *mh) | ||
113 | { | ||
114 | struct GNUNET_MQ_MessageHandler handlers[] = | ||
115 | { GNUNET_MQ_hd_fixed_size (receive_info, | ||
116 | GNUNET_MESSAGE_TYPE_CORE_MONITOR_NOTIFY, | ||
117 | struct MonitorNotifyMessage, | ||
118 | mh), | ||
119 | GNUNET_MQ_handler_end () }; | ||
120 | struct GNUNET_MQ_Envelope *env; | ||
121 | struct GNUNET_MessageHeader *msg; | ||
122 | |||
123 | if (NULL != mh->mq) | ||
124 | GNUNET_MQ_destroy (mh->mq); | ||
125 | /* FIXME: use backoff? */ | ||
126 | mh->mq = | ||
127 | GNUNET_CLIENT_connect (mh->cfg, "core", handlers, &handle_mq_error, mh); | ||
128 | if (NULL == mh->mq) | ||
129 | return; | ||
130 | /* notify callback about reconnect */ | ||
131 | if (NULL != mh->peer_cb) | ||
132 | mh->peer_cb (mh->peer_cb_cls, | ||
133 | NULL, | ||
134 | GNUNET_CORE_KX_CORE_DISCONNECT, | ||
135 | GNUNET_TIME_UNIT_FOREVER_ABS); | ||
136 | env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_CORE_MONITOR_PEERS); | ||
137 | GNUNET_MQ_send (mh->mq, env); | ||
138 | } | ||
139 | |||
140 | |||
141 | /** | ||
142 | * Monitor connectivity and KX status of all peers known to CORE. | ||
143 | * Calls @a peer_cb with the current status for each connected peer, | ||
144 | * and then once with NULL to indicate that all peers that are | ||
145 | * currently active have been handled. After that, the iteration | ||
146 | * continues until it is cancelled. Normal users of the CORE API are | ||
147 | * not expected to use this function. It is different in that it | ||
148 | * truly lists all connections (including those where the KX is in | ||
149 | * progress), not just those relevant to the application. This | ||
150 | * function is used by special applications for diagnostics. | ||
151 | * | ||
152 | * @param cfg configuration handle | ||
153 | * @param peer_cb function to call with the peer information | ||
154 | * @param peer_cb_cls closure for @a peer_cb | ||
155 | * @return NULL on error | ||
156 | */ | ||
157 | struct GNUNET_CORE_MonitorHandle * | ||
158 | GNUNET_CORE_monitor_start (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
159 | GNUNET_CORE_MonitorCallback peer_cb, | ||
160 | void *peer_cb_cls) | ||
161 | { | ||
162 | struct GNUNET_CORE_MonitorHandle *mh; | ||
163 | |||
164 | GNUNET_assert (NULL != peer_cb); | ||
165 | mh = GNUNET_new (struct GNUNET_CORE_MonitorHandle); | ||
166 | mh->cfg = cfg; | ||
167 | reconnect (mh); | ||
168 | mh->peer_cb = peer_cb; | ||
169 | mh->peer_cb_cls = peer_cb_cls; | ||
170 | if (NULL == mh->mq) | ||
171 | { | ||
172 | GNUNET_free (mh); | ||
173 | return NULL; | ||
174 | } | ||
175 | return mh; | ||
176 | } | ||
177 | |||
178 | |||
179 | /** | ||
180 | * Stop monitoring CORE activity. | ||
181 | * | ||
182 | * @param mh monitor to stop | ||
183 | */ | ||
184 | void | ||
185 | GNUNET_CORE_monitor_stop (struct GNUNET_CORE_MonitorHandle *mh) | ||
186 | { | ||
187 | if (NULL != mh->mq) | ||
188 | { | ||
189 | GNUNET_MQ_destroy (mh->mq); | ||
190 | mh->mq = NULL; | ||
191 | } | ||
192 | GNUNET_free (mh); | ||
193 | } | ||
194 | |||
195 | |||
196 | /* end of core_api_monitor_peers.c */ | ||
diff --git a/src/core/gnunet-core.c b/src/core/gnunet-core.c deleted file mode 100644 index d90c8e1f5..000000000 --- a/src/core/gnunet-core.c +++ /dev/null | |||
@@ -1,208 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2011, 2012, 2014 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file core/gnunet-core.c | ||
23 | * @brief Print information about other peers known to CORE. | ||
24 | * @author Nathan Evans | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet_util_lib.h" | ||
28 | #include "gnunet_core_service.h" | ||
29 | |||
30 | |||
31 | /** | ||
32 | * Option -m. | ||
33 | */ | ||
34 | static int monitor_connections; | ||
35 | |||
36 | /** | ||
37 | * Handle to the CORE monitor. | ||
38 | */ | ||
39 | static struct GNUNET_CORE_MonitorHandle *mh; | ||
40 | |||
41 | |||
42 | /** | ||
43 | * Task run in monitor mode when the user presses CTRL-C to abort. | ||
44 | * Stops monitoring activity. | ||
45 | * | ||
46 | * @param cls NULL | ||
47 | */ | ||
48 | static void | ||
49 | shutdown_task (void *cls) | ||
50 | { | ||
51 | (void) cls; | ||
52 | if (NULL != mh) | ||
53 | { | ||
54 | GNUNET_CORE_monitor_stop (mh); | ||
55 | mh = NULL; | ||
56 | } | ||
57 | } | ||
58 | |||
59 | |||
60 | /** | ||
61 | * Function called to notify core users that another | ||
62 | * peer changed its state with us. | ||
63 | * | ||
64 | * @param cls closure | ||
65 | * @param peer the peer that changed state | ||
66 | * @param state new state of the peer | ||
67 | * @param timeout timeout for the new state | ||
68 | */ | ||
69 | static void | ||
70 | monitor_cb (void *cls, | ||
71 | const struct GNUNET_PeerIdentity *peer, | ||
72 | enum GNUNET_CORE_KxState state, | ||
73 | struct GNUNET_TIME_Absolute timeout) | ||
74 | { | ||
75 | struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get (); | ||
76 | const char *now_str; | ||
77 | const char *state_str; | ||
78 | |||
79 | (void) cls; | ||
80 | if (((NULL == peer) || (GNUNET_CORE_KX_ITERATION_FINISHED == state)) && | ||
81 | (GNUNET_NO == monitor_connections)) | ||
82 | { | ||
83 | GNUNET_SCHEDULER_shutdown (); | ||
84 | return; | ||
85 | } | ||
86 | |||
87 | switch (state) | ||
88 | { | ||
89 | case GNUNET_CORE_KX_STATE_DOWN: | ||
90 | /* should never happen, as we immediately send the key */ | ||
91 | state_str = _ ("fresh connection"); | ||
92 | break; | ||
93 | |||
94 | case GNUNET_CORE_KX_STATE_KEY_SENT: | ||
95 | state_str = _ ("key sent"); | ||
96 | break; | ||
97 | |||
98 | case GNUNET_CORE_KX_STATE_KEY_RECEIVED: | ||
99 | state_str = _ ("key received"); | ||
100 | break; | ||
101 | |||
102 | case GNUNET_CORE_KX_STATE_UP: | ||
103 | state_str = _ ("connection established"); | ||
104 | break; | ||
105 | |||
106 | case GNUNET_CORE_KX_STATE_REKEY_SENT: | ||
107 | state_str = _ ("rekeying"); | ||
108 | break; | ||
109 | |||
110 | case GNUNET_CORE_KX_PEER_DISCONNECT: | ||
111 | state_str = _ ("disconnected"); | ||
112 | break; | ||
113 | |||
114 | case GNUNET_CORE_KX_ITERATION_FINISHED: | ||
115 | return; | ||
116 | |||
117 | case GNUNET_CORE_KX_CORE_DISCONNECT: | ||
118 | fprintf (stderr, | ||
119 | "%s\n", | ||
120 | _ ("Connection to CORE service lost (reconnecting)")); | ||
121 | return; | ||
122 | |||
123 | default: | ||
124 | state_str = _ ("unknown state"); | ||
125 | break; | ||
126 | } | ||
127 | now_str = GNUNET_STRINGS_absolute_time_to_string (now); | ||
128 | fprintf (stdout, | ||
129 | _ ("%24s: %-30s %4s (timeout in %6s)\n"), | ||
130 | now_str, | ||
131 | state_str, | ||
132 | GNUNET_i2s (peer), | ||
133 | GNUNET_STRINGS_relative_time_to_string ( | ||
134 | GNUNET_TIME_absolute_get_remaining (timeout), | ||
135 | GNUNET_YES)); | ||
136 | } | ||
137 | |||
138 | |||
139 | /** | ||
140 | * Main function that will be run by the scheduler. | ||
141 | * | ||
142 | * @param cls closure | ||
143 | * @param args remaining command-line arguments | ||
144 | * @param cfgfile name of the configuration file used (for saving, can be NULL!) | ||
145 | * @param cfg configuration | ||
146 | */ | ||
147 | static void | ||
148 | run (void *cls, | ||
149 | char *const *args, | ||
150 | const char *cfgfile, | ||
151 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
152 | { | ||
153 | (void) cls; | ||
154 | (void) cfgfile; | ||
155 | if (NULL != args[0]) | ||
156 | { | ||
157 | fprintf (stderr, _ ("Invalid command line argument `%s'\n"), args[0]); | ||
158 | return; | ||
159 | } | ||
160 | mh = GNUNET_CORE_monitor_start (cfg, &monitor_cb, NULL); | ||
161 | if (NULL == mh) | ||
162 | { | ||
163 | fprintf (stderr, "%s", _ ("Failed to connect to CORE service!\n")); | ||
164 | return; | ||
165 | } | ||
166 | GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); | ||
167 | } | ||
168 | |||
169 | |||
170 | /** | ||
171 | * The main function to obtain peer information from CORE. | ||
172 | * | ||
173 | * @param argc number of arguments from the command line | ||
174 | * @param argv command line arguments | ||
175 | * @return 0 ok, 1 on error | ||
176 | */ | ||
177 | int | ||
178 | main (int argc, char *const *argv) | ||
179 | { | ||
180 | int res; | ||
181 | struct GNUNET_GETOPT_CommandLineOption options[] = | ||
182 | { GNUNET_GETOPT_option_flag ( | ||
183 | 'm', | ||
184 | "monitor", | ||
185 | gettext_noop ( | ||
186 | "provide information about all current connections (continuously)"), | ||
187 | &monitor_connections), | ||
188 | GNUNET_GETOPT_OPTION_END }; | ||
189 | |||
190 | if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv)) | ||
191 | return 2; | ||
192 | res = GNUNET_PROGRAM_run (argc, | ||
193 | argv, | ||
194 | "gnunet-core", | ||
195 | gettext_noop ( | ||
196 | "Print information about connected peers."), | ||
197 | options, | ||
198 | &run, | ||
199 | NULL); | ||
200 | |||
201 | GNUNET_free_nz ((void *) argv); | ||
202 | if (GNUNET_OK == res) | ||
203 | return 0; | ||
204 | return 1; | ||
205 | } | ||
206 | |||
207 | |||
208 | /* end of gnunet-core.c */ | ||
diff --git a/src/core/gnunet-service-core.c b/src/core/gnunet-service-core.c deleted file mode 100644 index c9c3e3ff5..000000000 --- a/src/core/gnunet-service-core.c +++ /dev/null | |||
@@ -1,987 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009, 2010, 2011, 2016 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file core/gnunet-service-core.c | ||
23 | * @brief high-level P2P messaging | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include <gcrypt.h> | ||
28 | #include "gnunet_util_lib.h" | ||
29 | #include "gnunet-service-core.h" | ||
30 | #include "gnunet-service-core_kx.h" | ||
31 | #include "gnunet-service-core_sessions.h" | ||
32 | #include "gnunet-service-core_typemap.h" | ||
33 | |||
34 | /** | ||
35 | * How many messages do we queue up at most for any client? This can | ||
36 | * cause messages to be dropped if clients do not process them fast | ||
37 | * enough! Note that this is a soft limit; we try | ||
38 | * to keep a few larger messages above the limit. | ||
39 | */ | ||
40 | #define SOFT_MAX_QUEUE 128 | ||
41 | |||
42 | /** | ||
43 | * How many messages do we queue up at most for any client? This can | ||
44 | * cause messages to be dropped if clients do not process them fast | ||
45 | * enough! Note that this is the hard limit. | ||
46 | */ | ||
47 | #define HARD_MAX_QUEUE 256 | ||
48 | |||
49 | |||
50 | /** | ||
51 | * Data structure for each client connected to the CORE service. | ||
52 | */ | ||
53 | struct GSC_Client | ||
54 | { | ||
55 | /** | ||
56 | * Clients are kept in a linked list. | ||
57 | */ | ||
58 | struct GSC_Client *next; | ||
59 | |||
60 | /** | ||
61 | * Clients are kept in a linked list. | ||
62 | */ | ||
63 | struct GSC_Client *prev; | ||
64 | |||
65 | /** | ||
66 | * Handle for the client with the server API. | ||
67 | */ | ||
68 | struct GNUNET_SERVICE_Client *client; | ||
69 | |||
70 | /** | ||
71 | * Message queue to talk to @e client. | ||
72 | */ | ||
73 | struct GNUNET_MQ_Handle *mq; | ||
74 | |||
75 | /** | ||
76 | * Array of the types of messages this peer cares | ||
77 | * about (with @e tcnt entries). Allocated as part | ||
78 | * of this client struct, do not free! | ||
79 | */ | ||
80 | uint16_t *types; | ||
81 | |||
82 | /** | ||
83 | * Map of peer identities to active transmission requests of this | ||
84 | * client to the peer (of type `struct GSC_ClientActiveRequest`). | ||
85 | */ | ||
86 | struct GNUNET_CONTAINER_MultiPeerMap *requests; | ||
87 | |||
88 | /** | ||
89 | * Map containing all peers that this client knows we're connected to. | ||
90 | */ | ||
91 | struct GNUNET_CONTAINER_MultiPeerMap *connectmap; | ||
92 | |||
93 | /** | ||
94 | * Options for messages this client cares about, | ||
95 | * see GNUNET_CORE_OPTION_ values. | ||
96 | */ | ||
97 | uint32_t options; | ||
98 | |||
99 | /** | ||
100 | * Have we gotten the #GNUNET_MESSAGE_TYPE_CORE_INIT message | ||
101 | * from this client already? | ||
102 | */ | ||
103 | int got_init; | ||
104 | |||
105 | /** | ||
106 | * Number of types of incoming messages this client | ||
107 | * specifically cares about. Size of the @e types array. | ||
108 | */ | ||
109 | unsigned int tcnt; | ||
110 | }; | ||
111 | |||
112 | |||
113 | /** | ||
114 | * Our identity. | ||
115 | */ | ||
116 | struct GNUNET_PeerIdentity GSC_my_identity; | ||
117 | |||
118 | /** | ||
119 | * Our configuration. | ||
120 | */ | ||
121 | const struct GNUNET_CONFIGURATION_Handle *GSC_cfg; | ||
122 | |||
123 | /** | ||
124 | * For creating statistics. | ||
125 | */ | ||
126 | struct GNUNET_STATISTICS_Handle *GSC_stats; | ||
127 | |||
128 | /** | ||
129 | * Big "or" of all client options. | ||
130 | */ | ||
131 | static uint32_t all_client_options; | ||
132 | |||
133 | /** | ||
134 | * Head of linked list of our clients. | ||
135 | */ | ||
136 | static struct GSC_Client *client_head; | ||
137 | |||
138 | /** | ||
139 | * Tail of linked list of our clients. | ||
140 | */ | ||
141 | static struct GSC_Client *client_tail; | ||
142 | |||
143 | |||
144 | /** | ||
145 | * Test if the client is interested in messages of the given type. | ||
146 | * | ||
147 | * @param type message type | ||
148 | * @param c client to test | ||
149 | * @return #GNUNET_YES if @a c is interested, #GNUNET_NO if not. | ||
150 | */ | ||
151 | static int | ||
152 | type_match (uint16_t type, struct GSC_Client *c) | ||
153 | { | ||
154 | if ((0 == c->tcnt) && (0 != c->options)) | ||
155 | return GNUNET_YES; /* peer without handlers and inbound/outbond | ||
156 | callbacks matches ALL */ | ||
157 | if (NULL == c->types) | ||
158 | return GNUNET_NO; | ||
159 | for (unsigned int i = 0; i < c->tcnt; i++) | ||
160 | if (type == c->types[i]) | ||
161 | return GNUNET_YES; | ||
162 | return GNUNET_NO; | ||
163 | } | ||
164 | |||
165 | |||
166 | /** | ||
167 | * Check #GNUNET_MESSAGE_TYPE_CORE_INIT request. | ||
168 | * | ||
169 | * @param cls client that sent #GNUNET_MESSAGE_TYPE_CORE_INIT | ||
170 | * @param im the `struct InitMessage` | ||
171 | * @return #GNUNET_OK if @a im is well-formed | ||
172 | */ | ||
173 | static int | ||
174 | check_client_init (void *cls, const struct InitMessage *im) | ||
175 | { | ||
176 | return GNUNET_OK; | ||
177 | } | ||
178 | |||
179 | |||
180 | /** | ||
181 | * Handle #GNUNET_MESSAGE_TYPE_CORE_INIT request. | ||
182 | * | ||
183 | * @param cls client that sent #GNUNET_MESSAGE_TYPE_CORE_INIT | ||
184 | * @param im the `struct InitMessage` | ||
185 | */ | ||
186 | static void | ||
187 | handle_client_init (void *cls, const struct InitMessage *im) | ||
188 | { | ||
189 | struct GSC_Client *c = cls; | ||
190 | struct GNUNET_MQ_Envelope *env; | ||
191 | struct InitReplyMessage *irm; | ||
192 | uint16_t msize; | ||
193 | const uint16_t *types; | ||
194 | |||
195 | /* check that we don't have an entry already */ | ||
196 | msize = ntohs (im->header.size) - sizeof(struct InitMessage); | ||
197 | types = (const uint16_t *) &im[1]; | ||
198 | c->tcnt = msize / sizeof(uint16_t); | ||
199 | c->options = ntohl (im->options); | ||
200 | c->got_init = GNUNET_YES; | ||
201 | all_client_options |= c->options; | ||
202 | c->types = GNUNET_malloc (msize); | ||
203 | GNUNET_assert (GNUNET_YES == | ||
204 | GNUNET_CONTAINER_multipeermap_put ( | ||
205 | c->connectmap, | ||
206 | &GSC_my_identity, | ||
207 | NULL, | ||
208 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
209 | for (unsigned int i = 0; i < c->tcnt; i++) | ||
210 | c->types[i] = ntohs (types[i]); | ||
211 | GSC_TYPEMAP_add (c->types, c->tcnt); | ||
212 | GNUNET_log ( | ||
213 | GNUNET_ERROR_TYPE_DEBUG, | ||
214 | "Client connecting to core service is interested in %u message types\n", | ||
215 | (unsigned int) c->tcnt); | ||
216 | /* send init reply message */ | ||
217 | env = GNUNET_MQ_msg (irm, GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY); | ||
218 | irm->reserved = htonl (0); | ||
219 | irm->my_identity = GSC_my_identity; | ||
220 | GNUNET_MQ_send (c->mq, env); | ||
221 | GSC_SESSIONS_notify_client_about_sessions (c); | ||
222 | GNUNET_SERVICE_client_continue (c->client); | ||
223 | } | ||
224 | |||
225 | |||
226 | /** | ||
227 | * We will never be ready to transmit the given message in (disconnect | ||
228 | * or invalid request). Frees resources associated with @a car. We | ||
229 | * don't explicitly tell the client, it'll learn with the disconnect | ||
230 | * (or violated the protocol). | ||
231 | * | ||
232 | * @param car request that now permanently failed; the | ||
233 | * responsibility for the handle is now returned | ||
234 | * to CLIENTS (SESSIONS is done with it). | ||
235 | * @param drop_client #GNUNET_YES if the client violated the protocol | ||
236 | * and we should thus drop the connection | ||
237 | */ | ||
238 | void | ||
239 | GSC_CLIENTS_reject_request (struct GSC_ClientActiveRequest *car, | ||
240 | int drop_client) | ||
241 | { | ||
242 | GNUNET_assert ( | ||
243 | GNUNET_YES == | ||
244 | GNUNET_CONTAINER_multipeermap_remove (car->client_handle->requests, | ||
245 | &car->target, | ||
246 | car)); | ||
247 | if (GNUNET_YES == drop_client) | ||
248 | GNUNET_SERVICE_client_drop (car->client_handle->client); | ||
249 | GNUNET_free (car); | ||
250 | } | ||
251 | |||
252 | |||
253 | /** | ||
254 | * Tell a client that we are ready to receive the message. | ||
255 | * | ||
256 | * @param car request that is now ready; the responsibility | ||
257 | * for the handle remains shared between CLIENTS | ||
258 | * and SESSIONS after this call. | ||
259 | */ | ||
260 | void | ||
261 | GSC_CLIENTS_solicit_request (struct GSC_ClientActiveRequest *car) | ||
262 | { | ||
263 | struct GSC_Client *c; | ||
264 | struct GNUNET_MQ_Envelope *env; | ||
265 | struct SendMessageReady *smr; | ||
266 | struct GNUNET_TIME_Relative delay; | ||
267 | struct GNUNET_TIME_Relative left; | ||
268 | |||
269 | c = car->client_handle; | ||
270 | if (GNUNET_YES != | ||
271 | GNUNET_CONTAINER_multipeermap_contains (c->connectmap, &car->target)) | ||
272 | { | ||
273 | /* connection has gone down since, drop request */ | ||
274 | GNUNET_assert (0 != | ||
275 | GNUNET_memcmp (&car->target, | ||
276 | &GSC_my_identity)); | ||
277 | GSC_SESSIONS_dequeue_request (car); | ||
278 | GSC_CLIENTS_reject_request (car, GNUNET_NO); | ||
279 | return; | ||
280 | } | ||
281 | delay = GNUNET_TIME_absolute_get_duration (car->received_time); | ||
282 | left = GNUNET_TIME_absolute_get_duration (car->deadline); | ||
283 | if (delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us) | ||
284 | GNUNET_log ( | ||
285 | GNUNET_ERROR_TYPE_WARNING, | ||
286 | "Client waited %s for permission to transmit to `%s'%s (priority %u)\n", | ||
287 | GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES), | ||
288 | GNUNET_i2s (&car->target), | ||
289 | (0 == left.rel_value_us) ? " (past deadline)" : "", | ||
290 | car->priority); | ||
291 | env = GNUNET_MQ_msg (smr, GNUNET_MESSAGE_TYPE_CORE_SEND_READY); | ||
292 | smr->size = htons (car->msize); | ||
293 | smr->smr_id = car->smr_id; | ||
294 | smr->peer = car->target; | ||
295 | GNUNET_MQ_send (c->mq, env); | ||
296 | } | ||
297 | |||
298 | |||
299 | /** | ||
300 | * Handle #GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST message. | ||
301 | * | ||
302 | * @param cls client that sent a #GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST | ||
303 | * @param req the `struct SendMessageRequest` | ||
304 | */ | ||
305 | static void | ||
306 | handle_client_send_request (void *cls, const struct SendMessageRequest *req) | ||
307 | { | ||
308 | struct GSC_Client *c = cls; | ||
309 | struct GSC_ClientActiveRequest *car; | ||
310 | int is_loopback; | ||
311 | |||
312 | if (NULL == c->requests) | ||
313 | c->requests = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_NO); | ||
314 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
315 | "Client asked for transmission to `%s'\n", | ||
316 | GNUNET_i2s (&req->peer)); | ||
317 | is_loopback = (0 == GNUNET_memcmp (&req->peer, | ||
318 | &GSC_my_identity)); | ||
319 | if ((! is_loopback) && | ||
320 | (GNUNET_YES != | ||
321 | GNUNET_CONTAINER_multipeermap_contains (c->connectmap, &req->peer))) | ||
322 | { | ||
323 | /* neighbour must have disconnected since request was issued, | ||
324 | * ignore (client will realize it once it processes the | ||
325 | * disconnect notification) */ | ||
326 | GNUNET_STATISTICS_update (GSC_stats, | ||
327 | gettext_noop ( | ||
328 | "# send requests dropped (disconnected)"), | ||
329 | 1, | ||
330 | GNUNET_NO); | ||
331 | GNUNET_SERVICE_client_continue (c->client); | ||
332 | return; | ||
333 | } | ||
334 | |||
335 | car = GNUNET_CONTAINER_multipeermap_get (c->requests, &req->peer); | ||
336 | if (NULL == car) | ||
337 | { | ||
338 | /* create new entry */ | ||
339 | car = GNUNET_new (struct GSC_ClientActiveRequest); | ||
340 | GNUNET_assert (GNUNET_OK == | ||
341 | GNUNET_CONTAINER_multipeermap_put ( | ||
342 | c->requests, | ||
343 | &req->peer, | ||
344 | car, | ||
345 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)); | ||
346 | car->client_handle = c; | ||
347 | } | ||
348 | else | ||
349 | { | ||
350 | /* dequeue and recycle memory from pending request, there can only | ||
351 | be at most one per client and peer */ | ||
352 | GNUNET_STATISTICS_update (GSC_stats, | ||
353 | gettext_noop ( | ||
354 | "# dequeuing CAR (duplicate request)"), | ||
355 | 1, | ||
356 | GNUNET_NO); | ||
357 | GSC_SESSIONS_dequeue_request (car); | ||
358 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
359 | "Transmission request to `%s' was a duplicate!\n", | ||
360 | GNUNET_i2s (&req->peer)); | ||
361 | } | ||
362 | car->target = req->peer; | ||
363 | car->received_time = GNUNET_TIME_absolute_get (); | ||
364 | car->deadline = GNUNET_TIME_absolute_ntoh (req->deadline); | ||
365 | car->priority = (enum GNUNET_MQ_PriorityPreferences) ntohl (req->priority); | ||
366 | car->msize = ntohs (req->size); | ||
367 | car->smr_id = req->smr_id; | ||
368 | car->was_solicited = GNUNET_NO; | ||
369 | GNUNET_SERVICE_client_continue (c->client); | ||
370 | if (is_loopback) | ||
371 | { | ||
372 | /* loopback, satisfy immediately */ | ||
373 | GSC_CLIENTS_solicit_request (car); | ||
374 | return; | ||
375 | } | ||
376 | GSC_SESSIONS_queue_request (car); | ||
377 | } | ||
378 | |||
379 | |||
380 | /** | ||
381 | * Closure for the #client_tokenizer_callback(). | ||
382 | */ | ||
383 | struct TokenizerContext | ||
384 | { | ||
385 | /** | ||
386 | * Active request handle for the message. | ||
387 | */ | ||
388 | struct GSC_ClientActiveRequest *car; | ||
389 | |||
390 | /** | ||
391 | * How important is this message. | ||
392 | */ | ||
393 | enum GNUNET_MQ_PriorityPreferences priority; | ||
394 | }; | ||
395 | |||
396 | |||
397 | /** | ||
398 | * Functions with this signature are called whenever a complete | ||
399 | * message is received by the tokenizer. Used by | ||
400 | * #handle_client_send() for dispatching messages from clients to | ||
401 | * either the SESSION subsystem or other CLIENT (for loopback). | ||
402 | * | ||
403 | * @param cls reservation request (`struct TokenizerContext`) | ||
404 | * @param message the actual message | ||
405 | * @return #GNUNET_OK on success, | ||
406 | * #GNUNET_NO to stop further processing (no error) | ||
407 | * #GNUNET_SYSERR to stop further processing with error | ||
408 | */ | ||
409 | static int | ||
410 | tokenized_cb (void *cls, const struct GNUNET_MessageHeader *message) | ||
411 | { | ||
412 | struct TokenizerContext *tc = cls; | ||
413 | struct GSC_ClientActiveRequest *car = tc->car; | ||
414 | char buf[92]; | ||
415 | |||
416 | GNUNET_snprintf (buf, | ||
417 | sizeof(buf), | ||
418 | gettext_noop ("# bytes of messages of type %u received"), | ||
419 | (unsigned int) ntohs (message->type)); | ||
420 | GNUNET_STATISTICS_update (GSC_stats, buf, ntohs (message->size), GNUNET_NO); | ||
421 | if (0 == GNUNET_memcmp (&car->target, | ||
422 | &GSC_my_identity)) | ||
423 | { | ||
424 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
425 | "Delivering message of type %u to myself\n", | ||
426 | ntohs (message->type)); | ||
427 | GSC_CLIENTS_deliver_message (&GSC_my_identity, | ||
428 | message, | ||
429 | ntohs (message->size), | ||
430 | GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND); | ||
431 | GSC_CLIENTS_deliver_message (&GSC_my_identity, | ||
432 | message, | ||
433 | sizeof(struct GNUNET_MessageHeader), | ||
434 | GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND); | ||
435 | GSC_CLIENTS_deliver_message (&GSC_my_identity, | ||
436 | message, | ||
437 | ntohs (message->size), | ||
438 | GNUNET_CORE_OPTION_SEND_FULL_INBOUND); | ||
439 | GSC_CLIENTS_deliver_message (&GSC_my_identity, | ||
440 | message, | ||
441 | sizeof(struct GNUNET_MessageHeader), | ||
442 | GNUNET_CORE_OPTION_SEND_HDR_INBOUND); | ||
443 | } | ||
444 | else | ||
445 | { | ||
446 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
447 | "Delivering message of type %u and size %u to %s\n", | ||
448 | ntohs (message->type), | ||
449 | ntohs (message->size), | ||
450 | GNUNET_i2s (&car->target)); | ||
451 | GSC_CLIENTS_deliver_message (&car->target, | ||
452 | message, | ||
453 | ntohs (message->size), | ||
454 | GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND); | ||
455 | GSC_CLIENTS_deliver_message (&car->target, | ||
456 | message, | ||
457 | sizeof(struct GNUNET_MessageHeader), | ||
458 | GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND); | ||
459 | GSC_SESSIONS_transmit (car, message, tc->priority); | ||
460 | } | ||
461 | return GNUNET_OK; | ||
462 | } | ||
463 | |||
464 | |||
465 | /** | ||
466 | * Check #GNUNET_MESSAGE_TYPE_CORE_SEND request. | ||
467 | * | ||
468 | * @param cls the `struct GSC_Client` | ||
469 | * @param sm the `struct SendMessage` | ||
470 | * @return #GNUNET_OK if @a sm is well-formed | ||
471 | */ | ||
472 | static int | ||
473 | check_client_send (void *cls, const struct SendMessage *sm) | ||
474 | { | ||
475 | return GNUNET_OK; | ||
476 | } | ||
477 | |||
478 | |||
479 | /** | ||
480 | * Handle #GNUNET_MESSAGE_TYPE_CORE_SEND request. | ||
481 | * | ||
482 | * @param cls the `struct GSC_Client` | ||
483 | * @param sm the `struct SendMessage` | ||
484 | */ | ||
485 | static void | ||
486 | handle_client_send (void *cls, const struct SendMessage *sm) | ||
487 | { | ||
488 | struct GSC_Client *c = cls; | ||
489 | struct TokenizerContext tc; | ||
490 | uint16_t msize; | ||
491 | struct GNUNET_TIME_Relative delay; | ||
492 | struct GNUNET_MessageStreamTokenizer *mst; | ||
493 | |||
494 | msize = ntohs (sm->header.size) - sizeof(struct SendMessage); | ||
495 | tc.car = GNUNET_CONTAINER_multipeermap_get (c->requests, &sm->peer); | ||
496 | if (NULL == tc.car) | ||
497 | { | ||
498 | /* Must have been that we first approved the request, then got disconnected | ||
499 | * (which triggered removal of the 'car') and now the client gives us a message | ||
500 | * just *before* the client learns about the disconnect. Theoretically, we | ||
501 | * might also now be *again* connected. So this can happen (but should be | ||
502 | * rare). If it does happen, the message is discarded. */GNUNET_STATISTICS_update (GSC_stats, | ||
503 | gettext_noop ( | ||
504 | "# messages discarded (session disconnected)"), | ||
505 | 1, | ||
506 | GNUNET_NO); | ||
507 | GNUNET_SERVICE_client_continue (c->client); | ||
508 | return; | ||
509 | } | ||
510 | delay = GNUNET_TIME_absolute_get_duration (tc.car->received_time); | ||
511 | tc.priority = (enum GNUNET_MQ_PriorityPreferences) ntohl (sm->priority); | ||
512 | if (delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us) | ||
513 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
514 | "Client waited %s for transmission of %u bytes to `%s'\n", | ||
515 | GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES), | ||
516 | msize, | ||
517 | GNUNET_i2s (&sm->peer)); | ||
518 | else | ||
519 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
520 | "Client waited %s for transmission of %u bytes to `%s'\n", | ||
521 | GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES), | ||
522 | msize, | ||
523 | GNUNET_i2s (&sm->peer)); | ||
524 | |||
525 | GNUNET_assert ( | ||
526 | GNUNET_YES == | ||
527 | GNUNET_CONTAINER_multipeermap_remove (c->requests, &sm->peer, tc.car)); | ||
528 | mst = GNUNET_MST_create (&tokenized_cb, &tc); | ||
529 | GNUNET_MST_from_buffer (mst, | ||
530 | (const char *) &sm[1], | ||
531 | msize, | ||
532 | GNUNET_YES, | ||
533 | GNUNET_NO); | ||
534 | GNUNET_MST_destroy (mst); | ||
535 | GSC_SESSIONS_dequeue_request (tc.car); | ||
536 | GNUNET_free (tc.car); | ||
537 | GNUNET_SERVICE_client_continue (c->client); | ||
538 | } | ||
539 | |||
540 | |||
541 | /** | ||
542 | * Free client request records. | ||
543 | * | ||
544 | * @param cls NULL | ||
545 | * @param key identity of peer for which this is an active request | ||
546 | * @param value the `struct GSC_ClientActiveRequest` to free | ||
547 | * @return #GNUNET_YES (continue iteration) | ||
548 | */ | ||
549 | static int | ||
550 | destroy_active_client_request (void *cls, | ||
551 | const struct GNUNET_PeerIdentity *key, | ||
552 | void *value) | ||
553 | { | ||
554 | struct GSC_ClientActiveRequest *car = value; | ||
555 | |||
556 | GNUNET_assert ( | ||
557 | GNUNET_YES == | ||
558 | GNUNET_CONTAINER_multipeermap_remove (car->client_handle->requests, | ||
559 | &car->target, | ||
560 | car)); | ||
561 | GSC_SESSIONS_dequeue_request (car); | ||
562 | GNUNET_free (car); | ||
563 | return GNUNET_YES; | ||
564 | } | ||
565 | |||
566 | |||
567 | /** | ||
568 | * A client connected, set up. | ||
569 | * | ||
570 | * @param cls closure | ||
571 | * @param client identification of the client | ||
572 | * @param mq message queue to talk to @a client | ||
573 | * @return our client handle | ||
574 | */ | ||
575 | static void * | ||
576 | client_connect_cb (void *cls, | ||
577 | struct GNUNET_SERVICE_Client *client, | ||
578 | struct GNUNET_MQ_Handle *mq) | ||
579 | { | ||
580 | struct GSC_Client *c; | ||
581 | |||
582 | c = GNUNET_new (struct GSC_Client); | ||
583 | c->client = client; | ||
584 | c->mq = mq; | ||
585 | c->connectmap = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_NO); | ||
586 | GNUNET_CONTAINER_DLL_insert (client_head, client_tail, c); | ||
587 | return c; | ||
588 | } | ||
589 | |||
590 | |||
591 | /** | ||
592 | * A client disconnected, clean up. | ||
593 | * | ||
594 | * @param cls closure | ||
595 | * @param client identification of the client | ||
596 | * @param app_ctx our `struct GST_Client` for @a client | ||
597 | */ | ||
598 | static void | ||
599 | client_disconnect_cb (void *cls, | ||
600 | struct GNUNET_SERVICE_Client *client, | ||
601 | void *app_ctx) | ||
602 | { | ||
603 | struct GSC_Client *c = app_ctx; | ||
604 | |||
605 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
606 | "Client %p has disconnected from core service.\n", | ||
607 | client); | ||
608 | GNUNET_CONTAINER_DLL_remove (client_head, client_tail, c); | ||
609 | if (NULL != c->requests) | ||
610 | { | ||
611 | GNUNET_CONTAINER_multipeermap_iterate (c->requests, | ||
612 | &destroy_active_client_request, | ||
613 | NULL); | ||
614 | GNUNET_CONTAINER_multipeermap_destroy (c->requests); | ||
615 | } | ||
616 | GNUNET_CONTAINER_multipeermap_destroy (c->connectmap); | ||
617 | c->connectmap = NULL; | ||
618 | if (NULL != c->types) | ||
619 | { | ||
620 | GSC_TYPEMAP_remove (c->types, c->tcnt); | ||
621 | GNUNET_free (c->types); | ||
622 | } | ||
623 | GNUNET_free (c); | ||
624 | |||
625 | /* recalculate 'all_client_options' */ | ||
626 | all_client_options = 0; | ||
627 | for (c = client_head; NULL != c; c = c->next) | ||
628 | all_client_options |= c->options; | ||
629 | } | ||
630 | |||
631 | |||
632 | /** | ||
633 | * Notify a particular client about a change to existing connection to | ||
634 | * one of our neighbours (check if the client is interested). Called | ||
635 | * from #GSC_SESSIONS_notify_client_about_sessions(). | ||
636 | * | ||
637 | * @param client client to notify | ||
638 | * @param neighbour identity of the neighbour that changed status | ||
639 | * @param tmap_old previous type map for the neighbour, NULL for connect | ||
640 | * @param tmap_new updated type map for the neighbour, NULL for disconnect | ||
641 | */ | ||
642 | void | ||
643 | GSC_CLIENTS_notify_client_about_neighbour ( | ||
644 | struct GSC_Client *client, | ||
645 | const struct GNUNET_PeerIdentity *neighbour, | ||
646 | const struct GSC_TypeMap *tmap_old, | ||
647 | const struct GSC_TypeMap *tmap_new) | ||
648 | { | ||
649 | struct GNUNET_MQ_Envelope *env; | ||
650 | int old_match; | ||
651 | int new_match; | ||
652 | |||
653 | if (GNUNET_YES != client->got_init) | ||
654 | return; | ||
655 | old_match = GSC_TYPEMAP_test_match (tmap_old, client->types, client->tcnt); | ||
656 | new_match = GSC_TYPEMAP_test_match (tmap_new, client->types, client->tcnt); | ||
657 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
658 | "Notifying client about neighbour %s (%d/%d)\n", | ||
659 | GNUNET_i2s (neighbour), | ||
660 | old_match, | ||
661 | new_match); | ||
662 | if (old_match == new_match) | ||
663 | { | ||
664 | GNUNET_assert ( | ||
665 | old_match == | ||
666 | GNUNET_CONTAINER_multipeermap_contains (client->connectmap, neighbour)); | ||
667 | return; /* no change */ | ||
668 | } | ||
669 | if (GNUNET_NO == old_match) | ||
670 | { | ||
671 | struct ConnectNotifyMessage *cnm; | ||
672 | |||
673 | /* send connect */ | ||
674 | GNUNET_assert ( | ||
675 | GNUNET_NO == | ||
676 | GNUNET_CONTAINER_multipeermap_contains (client->connectmap, neighbour)); | ||
677 | GNUNET_assert (GNUNET_YES == | ||
678 | GNUNET_CONTAINER_multipeermap_put ( | ||
679 | client->connectmap, | ||
680 | neighbour, | ||
681 | NULL, | ||
682 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
683 | env = GNUNET_MQ_msg (cnm, GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT); | ||
684 | cnm->reserved = htonl (0); | ||
685 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
686 | "Sending NOTIFY_CONNECT message about peer %s to client.\n", | ||
687 | GNUNET_i2s (neighbour)); | ||
688 | cnm->peer = *neighbour; | ||
689 | GNUNET_MQ_send (client->mq, env); | ||
690 | } | ||
691 | else | ||
692 | { | ||
693 | struct DisconnectNotifyMessage *dcm; | ||
694 | |||
695 | /* send disconnect */ | ||
696 | GNUNET_assert ( | ||
697 | GNUNET_YES == | ||
698 | GNUNET_CONTAINER_multipeermap_contains (client->connectmap, neighbour)); | ||
699 | GNUNET_assert (GNUNET_YES == | ||
700 | GNUNET_CONTAINER_multipeermap_remove (client->connectmap, | ||
701 | neighbour, | ||
702 | NULL)); | ||
703 | env = GNUNET_MQ_msg (dcm, GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT); | ||
704 | dcm->reserved = htonl (0); | ||
705 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
706 | "Sending NOTIFY_DISCONNECT message about peer %s to client.\n", | ||
707 | GNUNET_i2s (neighbour)); | ||
708 | dcm->peer = *neighbour; | ||
709 | GNUNET_MQ_send (client->mq, env); | ||
710 | } | ||
711 | } | ||
712 | |||
713 | |||
714 | /** | ||
715 | * Notify all clients about a change to existing session. | ||
716 | * Called from SESSIONS whenever there is a change in sessions | ||
717 | * or types processed by the respective peer. | ||
718 | * | ||
719 | * @param neighbour identity of the neighbour that changed status | ||
720 | * @param tmap_old previous type map for the neighbour, NULL for connect | ||
721 | * @param tmap_new updated type map for the neighbour, NULL for disconnect | ||
722 | */ | ||
723 | void | ||
724 | GSC_CLIENTS_notify_clients_about_neighbour ( | ||
725 | const struct GNUNET_PeerIdentity *neighbour, | ||
726 | const struct GSC_TypeMap *tmap_old, | ||
727 | const struct GSC_TypeMap *tmap_new) | ||
728 | { | ||
729 | struct GSC_Client *c; | ||
730 | |||
731 | for (c = client_head; NULL != c; c = c->next) | ||
732 | GSC_CLIENTS_notify_client_about_neighbour (c, | ||
733 | neighbour, | ||
734 | tmap_old, | ||
735 | tmap_new); | ||
736 | } | ||
737 | |||
738 | |||
739 | /** | ||
740 | * Deliver P2P message to interested clients. Caller must have checked | ||
741 | * that the sending peer actually lists the given message type as one | ||
742 | * of its types. | ||
743 | * | ||
744 | * @param sender peer who sent us the message | ||
745 | * @param msg the message | ||
746 | * @param msize number of bytes to transmit | ||
747 | * @param options options for checking which clients should | ||
748 | * receive the message | ||
749 | */ | ||
750 | void | ||
751 | GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender, | ||
752 | const struct GNUNET_MessageHeader *msg, | ||
753 | uint16_t msize, | ||
754 | uint32_t options) | ||
755 | { | ||
756 | size_t size = msize + sizeof(struct NotifyTrafficMessage); | ||
757 | |||
758 | if (size >= GNUNET_MAX_MESSAGE_SIZE) | ||
759 | { | ||
760 | GNUNET_break (0); | ||
761 | return; | ||
762 | } | ||
763 | if (! ((0 != (all_client_options & options)) || | ||
764 | (0 != (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)))) | ||
765 | return; /* no client cares about this message notification */ | ||
766 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
767 | "Core service passes message from `%s' of type %u to client.\n", | ||
768 | GNUNET_i2s (sender), | ||
769 | (unsigned int) ntohs (msg->type)); | ||
770 | GSC_SESSIONS_add_to_typemap (sender, ntohs (msg->type)); | ||
771 | |||
772 | for (struct GSC_Client *c = client_head; NULL != c; c = c->next) | ||
773 | { | ||
774 | struct GNUNET_MQ_Envelope *env; | ||
775 | struct NotifyTrafficMessage *ntm; | ||
776 | uint16_t mtype; | ||
777 | unsigned int qlen; | ||
778 | int tm; | ||
779 | |||
780 | tm = type_match (ntohs (msg->type), c); | ||
781 | if (! ((0 != (c->options & options)) || | ||
782 | ((0 != (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) && | ||
783 | (GNUNET_YES == tm)))) | ||
784 | continue; /* neither options nor type match permit the message */ | ||
785 | if ((0 != (options & GNUNET_CORE_OPTION_SEND_HDR_INBOUND)) && | ||
786 | ((0 != (c->options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) || | ||
787 | (GNUNET_YES == tm))) | ||
788 | continue; | ||
789 | if ((0 != (options & GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND)) && | ||
790 | (0 != (c->options & GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND))) | ||
791 | continue; | ||
792 | |||
793 | /* Drop messages if: | ||
794 | 1) We are above the hard limit, or | ||
795 | 2) We are above the soft limit, and a coin toss limited | ||
796 | to the message size (giving larger messages a | ||
797 | proportionally higher chance of being queued) falls | ||
798 | below the threshold. The threshold is based on where | ||
799 | we are between the soft and the hard limit, scaled | ||
800 | to match the range of message sizes we usually encounter | ||
801 | (i.e. up to 32k); so a 64k message has a 50% chance of | ||
802 | being kept if we are just barely below the hard max, | ||
803 | and a 99% chance of being kept if we are at the soft max. | ||
804 | The reason is to make it more likely to drop control traffic | ||
805 | (ACK, queries) which may be cumulative or highly redundant, | ||
806 | and cheap to drop than data traffic. */qlen = GNUNET_MQ_get_length (c->mq); | ||
807 | if ((qlen >= HARD_MAX_QUEUE) || | ||
808 | ((qlen > SOFT_MAX_QUEUE) && | ||
809 | ((GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, | ||
810 | ntohs (msg->size))) < | ||
811 | (qlen - SOFT_MAX_QUEUE) * 0x8000 | ||
812 | / (HARD_MAX_QUEUE - SOFT_MAX_QUEUE)))) | ||
813 | { | ||
814 | char buf[1024]; | ||
815 | |||
816 | GNUNET_log ( | ||
817 | GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK, | ||
818 | "Dropping decrypted message of type %u as client is too busy (queue full)\n", | ||
819 | (unsigned int) ntohs (msg->type)); | ||
820 | GNUNET_snprintf (buf, | ||
821 | sizeof(buf), | ||
822 | gettext_noop ( | ||
823 | "# messages of type %u discarded (client busy)"), | ||
824 | (unsigned int) ntohs (msg->type)); | ||
825 | GNUNET_STATISTICS_update (GSC_stats, buf, 1, GNUNET_NO); | ||
826 | continue; | ||
827 | } | ||
828 | |||
829 | GNUNET_log ( | ||
830 | GNUNET_ERROR_TYPE_DEBUG, | ||
831 | "Sending %u message with %u bytes to client interested in messages of type %u.\n", | ||
832 | options, | ||
833 | ntohs (msg->size), | ||
834 | (unsigned int) ntohs (msg->type)); | ||
835 | |||
836 | if (0 != (options & (GNUNET_CORE_OPTION_SEND_FULL_INBOUND | ||
837 | | GNUNET_CORE_OPTION_SEND_HDR_INBOUND))) | ||
838 | mtype = GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND; | ||
839 | else | ||
840 | mtype = GNUNET_MESSAGE_TYPE_CORE_NOTIFY_OUTBOUND; | ||
841 | env = GNUNET_MQ_msg_extra (ntm, msize, mtype); | ||
842 | ntm->peer = *sender; | ||
843 | GNUNET_memcpy (&ntm[1], msg, msize); | ||
844 | |||
845 | GNUNET_assert ( | ||
846 | (0 == (c->options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) || | ||
847 | (GNUNET_YES != tm) || | ||
848 | (GNUNET_YES == | ||
849 | GNUNET_CONTAINER_multipeermap_contains (c->connectmap, sender))); | ||
850 | GNUNET_MQ_send (c->mq, env); | ||
851 | } | ||
852 | } | ||
853 | |||
854 | |||
855 | /** | ||
856 | * Last task run during shutdown. Disconnects us from | ||
857 | * the transport. | ||
858 | * | ||
859 | * @param cls NULL, unused | ||
860 | */ | ||
861 | static void | ||
862 | shutdown_task (void *cls) | ||
863 | { | ||
864 | struct GSC_Client *c; | ||
865 | |||
866 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Core service shutting down.\n"); | ||
867 | while (NULL != (c = client_head)) | ||
868 | GNUNET_SERVICE_client_drop (c->client); | ||
869 | GSC_SESSIONS_done (); | ||
870 | GSC_KX_done (); | ||
871 | GSC_TYPEMAP_done (); | ||
872 | if (NULL != GSC_stats) | ||
873 | { | ||
874 | GNUNET_STATISTICS_destroy (GSC_stats, GNUNET_NO); | ||
875 | GSC_stats = NULL; | ||
876 | } | ||
877 | GSC_cfg = NULL; | ||
878 | } | ||
879 | |||
880 | |||
881 | /** | ||
882 | * Handle #GNUNET_MESSAGE_TYPE_CORE_MONITOR_PEERS request. For this | ||
883 | * request type, the client does not have to have transmitted an INIT | ||
884 | * request. All current peers are returned, regardless of which | ||
885 | * message types they accept. | ||
886 | * | ||
887 | * @param cls client sending the iteration request | ||
888 | * @param message iteration request message | ||
889 | */ | ||
890 | static void | ||
891 | handle_client_monitor_peers (void *cls, | ||
892 | const struct GNUNET_MessageHeader *message) | ||
893 | { | ||
894 | struct GSC_Client *c = cls; | ||
895 | |||
896 | GNUNET_SERVICE_client_continue (c->client); | ||
897 | GSC_KX_handle_client_monitor_peers (c->mq); | ||
898 | } | ||
899 | |||
900 | |||
901 | /** | ||
902 | * Initiate core service. | ||
903 | * | ||
904 | * @param cls closure | ||
905 | * @param c configuration to use | ||
906 | * @param service the initialized service | ||
907 | */ | ||
908 | static void | ||
909 | run (void *cls, | ||
910 | const struct GNUNET_CONFIGURATION_Handle *c, | ||
911 | struct GNUNET_SERVICE_Handle *service) | ||
912 | { | ||
913 | struct GNUNET_CRYPTO_EddsaPrivateKey pk; | ||
914 | char *keyfile; | ||
915 | |||
916 | GSC_cfg = c; | ||
917 | if (GNUNET_OK != | ||
918 | GNUNET_CONFIGURATION_get_value_filename (GSC_cfg, | ||
919 | "PEER", | ||
920 | "PRIVATE_KEY", | ||
921 | &keyfile)) | ||
922 | { | ||
923 | GNUNET_log ( | ||
924 | GNUNET_ERROR_TYPE_ERROR, | ||
925 | _ ("Core service is lacking HOSTKEY configuration setting. Exiting.\n")); | ||
926 | GNUNET_SCHEDULER_shutdown (); | ||
927 | return; | ||
928 | } | ||
929 | GSC_stats = GNUNET_STATISTICS_create ("core", GSC_cfg); | ||
930 | GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL); | ||
931 | GNUNET_SERVICE_suspend (service); | ||
932 | GSC_TYPEMAP_init (); | ||
933 | if (GNUNET_SYSERR == | ||
934 | GNUNET_CRYPTO_eddsa_key_from_file (keyfile, | ||
935 | GNUNET_YES, | ||
936 | &pk)) | ||
937 | { | ||
938 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
939 | "Failed to setup peer's private key\n"); | ||
940 | GNUNET_SCHEDULER_shutdown (); | ||
941 | GNUNET_free (keyfile); | ||
942 | return; | ||
943 | } | ||
944 | GNUNET_free (keyfile); | ||
945 | if (GNUNET_OK != GSC_KX_init (&pk)) | ||
946 | { | ||
947 | GNUNET_SCHEDULER_shutdown (); | ||
948 | return; | ||
949 | } | ||
950 | GSC_SESSIONS_init (); | ||
951 | GNUNET_SERVICE_resume (service); | ||
952 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
953 | _ ("Core service of `%s' ready.\n"), | ||
954 | GNUNET_i2s (&GSC_my_identity)); | ||
955 | } | ||
956 | |||
957 | |||
958 | /** | ||
959 | * Define "main" method using service macro. | ||
960 | */ | ||
961 | GNUNET_SERVICE_MAIN ( | ||
962 | "core", | ||
963 | GNUNET_SERVICE_OPTION_NONE, | ||
964 | &run, | ||
965 | &client_connect_cb, | ||
966 | &client_disconnect_cb, | ||
967 | NULL, | ||
968 | GNUNET_MQ_hd_var_size (client_init, | ||
969 | GNUNET_MESSAGE_TYPE_CORE_INIT, | ||
970 | struct InitMessage, | ||
971 | NULL), | ||
972 | GNUNET_MQ_hd_fixed_size (client_monitor_peers, | ||
973 | GNUNET_MESSAGE_TYPE_CORE_MONITOR_PEERS, | ||
974 | struct GNUNET_MessageHeader, | ||
975 | NULL), | ||
976 | GNUNET_MQ_hd_fixed_size (client_send_request, | ||
977 | GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST, | ||
978 | struct SendMessageRequest, | ||
979 | NULL), | ||
980 | GNUNET_MQ_hd_var_size (client_send, | ||
981 | GNUNET_MESSAGE_TYPE_CORE_SEND, | ||
982 | struct SendMessage, | ||
983 | NULL), | ||
984 | GNUNET_MQ_handler_end ()); | ||
985 | |||
986 | |||
987 | /* end of gnunet-service-core.c */ | ||
diff --git a/src/core/gnunet-service-core.h b/src/core/gnunet-service-core.h deleted file mode 100644 index 0f71f221a..000000000 --- a/src/core/gnunet-service-core.h +++ /dev/null | |||
@@ -1,198 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009, 2010, 2011 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file core/gnunet-service-core.h | ||
23 | * @brief Globals for gnunet-service-core | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #ifndef GNUNET_SERVICE_CORE_H | ||
27 | #define GNUNET_SERVICE_CORE_H | ||
28 | |||
29 | #include "gnunet_statistics_service.h" | ||
30 | #include "gnunet_core_service.h" | ||
31 | #include "core.h" | ||
32 | #include "gnunet-service-core_typemap.h" | ||
33 | |||
34 | |||
35 | /** | ||
36 | * Opaque handle to a client. | ||
37 | */ | ||
38 | struct GSC_Client; | ||
39 | |||
40 | |||
41 | /** | ||
42 | * Record kept for each request for transmission issued by a | ||
43 | * client that is still pending. (This struct is used by | ||
44 | * both the 'CLIENTS' and 'SESSIONS' subsystems.) | ||
45 | */ | ||
46 | struct GSC_ClientActiveRequest | ||
47 | { | ||
48 | /** | ||
49 | * Active requests are kept in a doubly-linked list of | ||
50 | * the respective target peer. | ||
51 | */ | ||
52 | struct GSC_ClientActiveRequest *next; | ||
53 | |||
54 | /** | ||
55 | * Active requests are kept in a doubly-linked list of | ||
56 | * the respective target peer. | ||
57 | */ | ||
58 | struct GSC_ClientActiveRequest *prev; | ||
59 | |||
60 | /** | ||
61 | * Handle to the client. | ||
62 | */ | ||
63 | struct GSC_Client *client_handle; | ||
64 | |||
65 | /** | ||
66 | * Which peer is the message going to be for? | ||
67 | */ | ||
68 | struct GNUNET_PeerIdentity target; | ||
69 | |||
70 | /** | ||
71 | * At what time did we first see this request? | ||
72 | */ | ||
73 | struct GNUNET_TIME_Absolute received_time; | ||
74 | |||
75 | /** | ||
76 | * By what time would the client want to see this message out? | ||
77 | */ | ||
78 | struct GNUNET_TIME_Absolute deadline; | ||
79 | |||
80 | /** | ||
81 | * How important is this request. | ||
82 | */ | ||
83 | enum GNUNET_MQ_PriorityPreferences priority; | ||
84 | |||
85 | /** | ||
86 | * Has this request been solicited yet? | ||
87 | */ | ||
88 | int was_solicited; | ||
89 | |||
90 | /** | ||
91 | * How many bytes does the client intend to send? | ||
92 | */ | ||
93 | uint16_t msize; | ||
94 | |||
95 | /** | ||
96 | * Unique request ID (in big endian). | ||
97 | */ | ||
98 | uint16_t smr_id; | ||
99 | }; | ||
100 | |||
101 | |||
102 | /** | ||
103 | * Tell a client that we are ready to receive the message. | ||
104 | * | ||
105 | * @param car request that is now ready; the responsibility | ||
106 | * for the handle remains shared between CLIENTS | ||
107 | * and SESSIONS after this call. | ||
108 | */ | ||
109 | void | ||
110 | GSC_CLIENTS_solicit_request (struct GSC_ClientActiveRequest *car); | ||
111 | |||
112 | |||
113 | /** | ||
114 | * We will never be ready to transmit the given message in (disconnect | ||
115 | * or invalid request). Frees resources associated with @a car. We | ||
116 | * don't explicitly tell the client, it'll learn with the disconnect | ||
117 | * (or violated the protocol). | ||
118 | * | ||
119 | * @param car request that now permanently failed; the | ||
120 | * responsibility for the handle is now returned | ||
121 | * to CLIENTS (SESSIONS is done with it). | ||
122 | * @param drop_client #GNUNET_YES if the client violated the protocol | ||
123 | * and we should thus drop the connection | ||
124 | */ | ||
125 | void | ||
126 | GSC_CLIENTS_reject_request (struct GSC_ClientActiveRequest *car, | ||
127 | int drop_client); | ||
128 | |||
129 | |||
130 | /** | ||
131 | * Notify a particular client about a change to existing connection to | ||
132 | * one of our neighbours (check if the client is interested). Called | ||
133 | * from #GSC_SESSIONS_notify_client_about_sessions(). | ||
134 | * | ||
135 | * @param client client to notify | ||
136 | * @param neighbour identity of the neighbour that changed status | ||
137 | * @param tmap_old previous type map for the neighbour, NULL for connect | ||
138 | * @param tmap_new updated type map for the neighbour, NULL for disconnect | ||
139 | */ | ||
140 | void | ||
141 | GSC_CLIENTS_notify_client_about_neighbour ( | ||
142 | struct GSC_Client *client, | ||
143 | const struct GNUNET_PeerIdentity *neighbour, | ||
144 | const struct GSC_TypeMap *tmap_old, | ||
145 | const struct GSC_TypeMap *tmap_new); | ||
146 | |||
147 | |||
148 | /** | ||
149 | * Deliver P2P message to interested clients. Caller must have checked | ||
150 | * that the sending peer actually lists the given message type as one | ||
151 | * of its types. | ||
152 | * | ||
153 | * @param sender peer who sent us the message | ||
154 | * @param msg the message | ||
155 | * @param msize number of bytes to transmit | ||
156 | * @param options options for checking which clients should | ||
157 | * receive the message | ||
158 | */ | ||
159 | void | ||
160 | GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender, | ||
161 | const struct GNUNET_MessageHeader *msg, | ||
162 | uint16_t msize, | ||
163 | uint32_t options); | ||
164 | |||
165 | |||
166 | /** | ||
167 | * Notify all clients about a change to existing session. | ||
168 | * Called from SESSIONS whenever there is a change in sessions | ||
169 | * or types processed by the respective peer. | ||
170 | * | ||
171 | * @param neighbour identity of the neighbour that changed status | ||
172 | * @param tmap_old previous type map for the neighbour, NULL for connect | ||
173 | * @param tmap_new updated type map for the neighbour, NULL for disconnect | ||
174 | */ | ||
175 | void | ||
176 | GSC_CLIENTS_notify_clients_about_neighbour ( | ||
177 | const struct GNUNET_PeerIdentity *neighbour, | ||
178 | const struct GSC_TypeMap *tmap_old, | ||
179 | const struct GSC_TypeMap *tmap_new); | ||
180 | |||
181 | |||
182 | /** | ||
183 | * Our configuration. | ||
184 | */ | ||
185 | extern const struct GNUNET_CONFIGURATION_Handle *GSC_cfg; | ||
186 | |||
187 | /** | ||
188 | * For creating statistics. | ||
189 | */ | ||
190 | extern struct GNUNET_STATISTICS_Handle *GSC_stats; | ||
191 | |||
192 | /** | ||
193 | * Our identity. | ||
194 | */ | ||
195 | extern struct GNUNET_PeerIdentity GSC_my_identity; | ||
196 | |||
197 | |||
198 | #endif | ||
diff --git a/src/core/gnunet-service-core_kx.c b/src/core/gnunet-service-core_kx.c deleted file mode 100644 index 07c346485..000000000 --- a/src/core/gnunet-service-core_kx.c +++ /dev/null | |||
@@ -1,1945 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009-2013, 2016 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file core/gnunet-service-core_kx.c | ||
23 | * @brief code for managing the key exchange (SET_KEY, PING, PONG) with other | ||
24 | * peers | ||
25 | * @author Christian Grothoff | ||
26 | */ | ||
27 | #include "platform.h" | ||
28 | #include "gnunet-service-core_kx.h" | ||
29 | #include "gnunet-service-core.h" | ||
30 | #include "gnunet-service-core_sessions.h" | ||
31 | #include "gnunet_statistics_service.h" | ||
32 | #include "gnunet_transport_service.h" | ||
33 | #include "gnunet_constants.h" | ||
34 | #include "gnunet_signatures.h" | ||
35 | #include "gnunet_protocols.h" | ||
36 | #include "core.h" | ||
37 | |||
38 | /** | ||
39 | * Enable expensive (and possibly problematic for privacy!) logging of KX. | ||
40 | */ | ||
41 | #define DEBUG_KX 0 | ||
42 | |||
43 | /** | ||
44 | * How long do we wait for SET_KEY confirmation initially? | ||
45 | */ | ||
46 | #define INITIAL_SET_KEY_RETRY_FREQUENCY \ | ||
47 | GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10) | ||
48 | |||
49 | /** | ||
50 | * What is the minimum frequency for a PING message? | ||
51 | */ | ||
52 | #define MIN_PING_FREQUENCY \ | ||
53 | GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5) | ||
54 | |||
55 | /** | ||
56 | * How often do we rekey? | ||
57 | */ | ||
58 | #define REKEY_FREQUENCY \ | ||
59 | GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12) | ||
60 | |||
61 | /** | ||
62 | * What time difference do we tolerate? | ||
63 | */ | ||
64 | #define REKEY_TOLERANCE \ | ||
65 | GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5) | ||
66 | |||
67 | /** | ||
68 | * What is the maximum age of a message for us to consider processing | ||
69 | * it? Note that this looks at the timestamp used by the other peer, | ||
70 | * so clock skew between machines does come into play here. So this | ||
71 | * should be picked high enough so that a little bit of clock skew | ||
72 | * does not prevent peers from connecting to us. | ||
73 | */ | ||
74 | #define MAX_MESSAGE_AGE GNUNET_TIME_UNIT_DAYS | ||
75 | |||
76 | |||
77 | GNUNET_NETWORK_STRUCT_BEGIN | ||
78 | |||
79 | /** | ||
80 | * Encapsulation for encrypted messages exchanged between | ||
81 | * peers. Followed by the actual encrypted data. | ||
82 | */ | ||
83 | struct EncryptedMessage | ||
84 | { | ||
85 | /** | ||
86 | * Message type is #GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE. | ||
87 | */ | ||
88 | struct GNUNET_MessageHeader header; | ||
89 | |||
90 | /** | ||
91 | * Random value used for IV generation. | ||
92 | */ | ||
93 | uint32_t iv_seed GNUNET_PACKED; | ||
94 | |||
95 | /** | ||
96 | * MAC of the encrypted message (starting at @e sequence_number), | ||
97 | * used to verify message integrity. Everything after this value | ||
98 | * (excluding this value itself) will be encrypted and | ||
99 | * authenticated. #ENCRYPTED_HEADER_SIZE must be set to the offset | ||
100 | * of the *next* field. | ||
101 | */ | ||
102 | struct GNUNET_HashCode hmac; | ||
103 | |||
104 | /** | ||
105 | * Sequence number, in network byte order. This field | ||
106 | * must be the first encrypted/decrypted field | ||
107 | */ | ||
108 | uint32_t sequence_number GNUNET_PACKED; | ||
109 | |||
110 | /** | ||
111 | * Reserved, always zero. | ||
112 | */ | ||
113 | uint32_t reserved GNUNET_PACKED; | ||
114 | |||
115 | /** | ||
116 | * Timestamp. Used to prevent replay of ancient messages | ||
117 | * (recent messages are caught with the sequence number). | ||
118 | */ | ||
119 | struct GNUNET_TIME_AbsoluteNBO timestamp; | ||
120 | }; | ||
121 | GNUNET_NETWORK_STRUCT_END | ||
122 | |||
123 | |||
124 | /** | ||
125 | * Number of bytes (at the beginning) of `struct EncryptedMessage` | ||
126 | * that are NOT encrypted. | ||
127 | */ | ||
128 | #define ENCRYPTED_HEADER_SIZE \ | ||
129 | (offsetof (struct EncryptedMessage, sequence_number)) | ||
130 | |||
131 | |||
132 | /** | ||
133 | * Information about the status of a key exchange with another peer. | ||
134 | */ | ||
135 | struct GSC_KeyExchangeInfo | ||
136 | { | ||
137 | /** | ||
138 | * DLL. | ||
139 | */ | ||
140 | struct GSC_KeyExchangeInfo *next; | ||
141 | |||
142 | /** | ||
143 | * DLL. | ||
144 | */ | ||
145 | struct GSC_KeyExchangeInfo *prev; | ||
146 | |||
147 | /** | ||
148 | * Identity of the peer. | ||
149 | */ | ||
150 | const struct GNUNET_PeerIdentity *peer; | ||
151 | |||
152 | /** | ||
153 | * Message queue for sending messages to @a peer. | ||
154 | */ | ||
155 | struct GNUNET_MQ_Handle *mq; | ||
156 | |||
157 | /** | ||
158 | * Our message stream tokenizer (for encrypted payload). | ||
159 | */ | ||
160 | struct GNUNET_MessageStreamTokenizer *mst; | ||
161 | |||
162 | /** | ||
163 | * PING message we transmit to the other peer. | ||
164 | */ | ||
165 | struct PingMessage ping; | ||
166 | |||
167 | /** | ||
168 | * Ephemeral public ECC key of the other peer. | ||
169 | */ | ||
170 | struct GNUNET_CRYPTO_EcdhePublicKey other_ephemeral_key; | ||
171 | |||
172 | /** | ||
173 | * Key we use to encrypt our messages for the other peer | ||
174 | * (initialized by us when we do the handshake). | ||
175 | */ | ||
176 | struct GNUNET_CRYPTO_SymmetricSessionKey encrypt_key; | ||
177 | |||
178 | /** | ||
179 | * Key we use to decrypt messages from the other peer | ||
180 | * (given to us by the other peer during the handshake). | ||
181 | */ | ||
182 | struct GNUNET_CRYPTO_SymmetricSessionKey decrypt_key; | ||
183 | |||
184 | /** | ||
185 | * At what time did the other peer generate the decryption key? | ||
186 | */ | ||
187 | struct GNUNET_TIME_Absolute foreign_key_expires; | ||
188 | |||
189 | /** | ||
190 | * When should the session time out (if there are no PONGs)? | ||
191 | */ | ||
192 | struct GNUNET_TIME_Absolute timeout; | ||
193 | |||
194 | /** | ||
195 | * What was the last timeout we informed our monitors about? | ||
196 | */ | ||
197 | struct GNUNET_TIME_Absolute last_notify_timeout; | ||
198 | |||
199 | /** | ||
200 | * At what frequency are we currently re-trying SET_KEY messages? | ||
201 | */ | ||
202 | struct GNUNET_TIME_Relative set_key_retry_frequency; | ||
203 | |||
204 | /** | ||
205 | * ID of task used for re-trying SET_KEY and PING message. | ||
206 | */ | ||
207 | struct GNUNET_SCHEDULER_Task *retry_set_key_task; | ||
208 | |||
209 | /** | ||
210 | * ID of task used for sending keep-alive pings. | ||
211 | */ | ||
212 | struct GNUNET_SCHEDULER_Task *keep_alive_task; | ||
213 | |||
214 | /** | ||
215 | * Bit map indicating which of the 32 sequence numbers before the | ||
216 | * last were received (good for accepting out-of-order packets and | ||
217 | * estimating reliability of the connection) | ||
218 | */ | ||
219 | uint32_t last_packets_bitmap; | ||
220 | |||
221 | /** | ||
222 | * last sequence number received on this connection (highest) | ||
223 | */ | ||
224 | uint32_t last_sequence_number_received; | ||
225 | |||
226 | /** | ||
227 | * last sequence number transmitted | ||
228 | */ | ||
229 | uint32_t last_sequence_number_sent; | ||
230 | |||
231 | /** | ||
232 | * What was our PING challenge number (for this peer)? | ||
233 | */ | ||
234 | uint32_t ping_challenge; | ||
235 | |||
236 | /** | ||
237 | * #GNUNET_YES if this peer currently has excess bandwidth. | ||
238 | */ | ||
239 | int has_excess_bandwidth; | ||
240 | |||
241 | /** | ||
242 | * What is our connection status? | ||
243 | */ | ||
244 | enum GNUNET_CORE_KxState status; | ||
245 | }; | ||
246 | |||
247 | |||
248 | /** | ||
249 | * Transport service. | ||
250 | */ | ||
251 | static struct GNUNET_TRANSPORT_CoreHandle *transport; | ||
252 | |||
253 | /** | ||
254 | * Our private key. | ||
255 | */ | ||
256 | static struct GNUNET_CRYPTO_EddsaPrivateKey my_private_key; | ||
257 | |||
258 | /** | ||
259 | * Our ephemeral private key. | ||
260 | */ | ||
261 | static struct GNUNET_CRYPTO_EcdhePrivateKey my_ephemeral_key; | ||
262 | |||
263 | /** | ||
264 | * Current message we send for a key exchange. | ||
265 | */ | ||
266 | static struct EphemeralKeyMessage current_ekm; | ||
267 | |||
268 | /** | ||
269 | * DLL head. | ||
270 | */ | ||
271 | static struct GSC_KeyExchangeInfo *kx_head; | ||
272 | |||
273 | /** | ||
274 | * DLL tail. | ||
275 | */ | ||
276 | static struct GSC_KeyExchangeInfo *kx_tail; | ||
277 | |||
278 | /** | ||
279 | * Task scheduled for periodic re-generation (and thus rekeying) of our | ||
280 | * ephemeral key. | ||
281 | */ | ||
282 | static struct GNUNET_SCHEDULER_Task *rekey_task; | ||
283 | |||
284 | /** | ||
285 | * Notification context for broadcasting to monitors. | ||
286 | */ | ||
287 | static struct GNUNET_NotificationContext *nc; | ||
288 | |||
289 | |||
290 | /** | ||
291 | * Calculate seed value we should use for a message. | ||
292 | * | ||
293 | * @param kx key exchange context | ||
294 | */ | ||
295 | static uint32_t | ||
296 | calculate_seed (struct GSC_KeyExchangeInfo *kx) | ||
297 | { | ||
298 | /* Note: may want to make this non-random and instead | ||
299 | derive from key material to avoid having an undetectable | ||
300 | side-channel */ | ||
301 | return htonl ( | ||
302 | GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX)); | ||
303 | } | ||
304 | |||
305 | |||
306 | /** | ||
307 | * Inform all monitors about the KX state of the given peer. | ||
308 | * | ||
309 | * @param kx key exchange state to inform about | ||
310 | */ | ||
311 | static void | ||
312 | monitor_notify_all (struct GSC_KeyExchangeInfo *kx) | ||
313 | { | ||
314 | struct MonitorNotifyMessage msg; | ||
315 | |||
316 | msg.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_MONITOR_NOTIFY); | ||
317 | msg.header.size = htons (sizeof(msg)); | ||
318 | msg.state = htonl ((uint32_t) kx->status); | ||
319 | msg.peer = *kx->peer; | ||
320 | msg.timeout = GNUNET_TIME_absolute_hton (kx->timeout); | ||
321 | GNUNET_notification_context_broadcast (nc, &msg.header, GNUNET_NO); | ||
322 | kx->last_notify_timeout = kx->timeout; | ||
323 | } | ||
324 | |||
325 | |||
326 | /** | ||
327 | * Derive an authentication key from "set key" information | ||
328 | * | ||
329 | * @param akey authentication key to derive | ||
330 | * @param skey session key to use | ||
331 | * @param seed seed to use | ||
332 | */ | ||
333 | static void | ||
334 | derive_auth_key (struct GNUNET_CRYPTO_AuthKey *akey, | ||
335 | const struct GNUNET_CRYPTO_SymmetricSessionKey *skey, | ||
336 | uint32_t seed) | ||
337 | { | ||
338 | static const char ctx[] = "authentication key"; | ||
339 | |||
340 | #if DEBUG_KX | ||
341 | struct GNUNET_HashCode sh; | ||
342 | |||
343 | GNUNET_CRYPTO_hash (skey, sizeof(*skey), &sh); | ||
344 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
345 | "Deriving Auth key from SKEY %s and seed %u\n", | ||
346 | GNUNET_h2s (&sh), | ||
347 | (unsigned int) seed); | ||
348 | #endif | ||
349 | GNUNET_CRYPTO_hmac_derive_key (akey, | ||
350 | skey, | ||
351 | &seed, | ||
352 | sizeof(seed), | ||
353 | skey, | ||
354 | sizeof( | ||
355 | struct GNUNET_CRYPTO_SymmetricSessionKey), | ||
356 | ctx, | ||
357 | sizeof(ctx), | ||
358 | NULL); | ||
359 | } | ||
360 | |||
361 | |||
362 | /** | ||
363 | * Derive an IV from packet information | ||
364 | * | ||
365 | * @param iv initialization vector to initialize | ||
366 | * @param skey session key to use | ||
367 | * @param seed seed to use | ||
368 | * @param identity identity of the other peer to use | ||
369 | */ | ||
370 | static void | ||
371 | derive_iv (struct GNUNET_CRYPTO_SymmetricInitializationVector *iv, | ||
372 | const struct GNUNET_CRYPTO_SymmetricSessionKey *skey, | ||
373 | uint32_t seed, | ||
374 | const struct GNUNET_PeerIdentity *identity) | ||
375 | { | ||
376 | static const char ctx[] = "initialization vector"; | ||
377 | |||
378 | #if DEBUG_KX | ||
379 | struct GNUNET_HashCode sh; | ||
380 | |||
381 | GNUNET_CRYPTO_hash (skey, sizeof(*skey), &sh); | ||
382 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
383 | "Deriving IV from SKEY %s and seed %u for peer %s\n", | ||
384 | GNUNET_h2s (&sh), | ||
385 | (unsigned int) seed, | ||
386 | GNUNET_i2s (identity)); | ||
387 | #endif | ||
388 | GNUNET_CRYPTO_symmetric_derive_iv (iv, | ||
389 | skey, | ||
390 | &seed, | ||
391 | sizeof(seed), | ||
392 | identity, | ||
393 | sizeof(struct GNUNET_PeerIdentity), | ||
394 | ctx, | ||
395 | sizeof(ctx), | ||
396 | NULL); | ||
397 | } | ||
398 | |||
399 | |||
400 | /** | ||
401 | * Derive an IV from pong packet information | ||
402 | * | ||
403 | * @param iv initialization vector to initialize | ||
404 | * @param skey session key to use | ||
405 | * @param seed seed to use | ||
406 | * @param challenge nonce to use | ||
407 | * @param identity identity of the other peer to use | ||
408 | */ | ||
409 | static void | ||
410 | derive_pong_iv (struct GNUNET_CRYPTO_SymmetricInitializationVector *iv, | ||
411 | const struct GNUNET_CRYPTO_SymmetricSessionKey *skey, | ||
412 | uint32_t seed, | ||
413 | uint32_t challenge, | ||
414 | const struct GNUNET_PeerIdentity *identity) | ||
415 | { | ||
416 | static const char ctx[] = "pong initialization vector"; | ||
417 | |||
418 | #if DEBUG_KX | ||
419 | struct GNUNET_HashCode sh; | ||
420 | |||
421 | GNUNET_CRYPTO_hash (skey, sizeof(*skey), &sh); | ||
422 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
423 | "Deriving PONG IV from SKEY %s and seed %u/%u for %s\n", | ||
424 | GNUNET_h2s (&sh), | ||
425 | (unsigned int) seed, | ||
426 | (unsigned int) challenge, | ||
427 | GNUNET_i2s (identity)); | ||
428 | #endif | ||
429 | GNUNET_CRYPTO_symmetric_derive_iv (iv, | ||
430 | skey, | ||
431 | &seed, | ||
432 | sizeof(seed), | ||
433 | identity, | ||
434 | sizeof(struct GNUNET_PeerIdentity), | ||
435 | &challenge, | ||
436 | sizeof(challenge), | ||
437 | ctx, | ||
438 | sizeof(ctx), | ||
439 | NULL); | ||
440 | } | ||
441 | |||
442 | |||
443 | /** | ||
444 | * Derive an AES key from key material | ||
445 | * | ||
446 | * @param sender peer identity of the sender | ||
447 | * @param receiver peer identity of the sender | ||
448 | * @param key_material high entropy key material to use | ||
449 | * @param skey set to derived session key | ||
450 | */ | ||
451 | static void | ||
452 | derive_aes_key (const struct GNUNET_PeerIdentity *sender, | ||
453 | const struct GNUNET_PeerIdentity *receiver, | ||
454 | const struct GNUNET_HashCode *key_material, | ||
455 | struct GNUNET_CRYPTO_SymmetricSessionKey *skey) | ||
456 | { | ||
457 | static const char ctx[] = "aes key generation vector"; | ||
458 | |||
459 | #if DEBUG_KX | ||
460 | struct GNUNET_HashCode sh; | ||
461 | |||
462 | GNUNET_CRYPTO_hash (skey, sizeof(*skey), &sh); | ||
463 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
464 | "Deriving AES Keys for %s to %s from %s\n", | ||
465 | GNUNET_i2s (sender), | ||
466 | GNUNET_i2s2 (receiver), | ||
467 | GNUNET_h2s (key_material)); | ||
468 | #endif | ||
469 | GNUNET_CRYPTO_kdf (skey, | ||
470 | sizeof(struct GNUNET_CRYPTO_SymmetricSessionKey), | ||
471 | ctx, | ||
472 | sizeof(ctx), | ||
473 | key_material, | ||
474 | sizeof(struct GNUNET_HashCode), | ||
475 | sender, | ||
476 | sizeof(struct GNUNET_PeerIdentity), | ||
477 | receiver, | ||
478 | sizeof(struct GNUNET_PeerIdentity), | ||
479 | NULL); | ||
480 | } | ||
481 | |||
482 | |||
483 | /** | ||
484 | * Encrypt size bytes from @a in and write the result to @a out. Use the | ||
485 | * @a kx key for outbound traffic of the given neighbour. | ||
486 | * | ||
487 | * @param kx key information context | ||
488 | * @param iv initialization vector to use | ||
489 | * @param in ciphertext | ||
490 | * @param out plaintext | ||
491 | * @param size size of @a in/@a out | ||
492 | * @return #GNUNET_OK on success | ||
493 | */ | ||
494 | static int | ||
495 | do_encrypt (struct GSC_KeyExchangeInfo *kx, | ||
496 | const struct GNUNET_CRYPTO_SymmetricInitializationVector *iv, | ||
497 | const void *in, | ||
498 | void *out, | ||
499 | size_t size) | ||
500 | { | ||
501 | if (size != (uint16_t) size) | ||
502 | { | ||
503 | GNUNET_break (0); | ||
504 | return GNUNET_NO; | ||
505 | } | ||
506 | GNUNET_assert (size == GNUNET_CRYPTO_symmetric_encrypt (in, | ||
507 | (uint16_t) size, | ||
508 | &kx->encrypt_key, | ||
509 | iv, | ||
510 | out)); | ||
511 | GNUNET_STATISTICS_update (GSC_stats, | ||
512 | gettext_noop ("# bytes encrypted"), | ||
513 | size, | ||
514 | GNUNET_NO); | ||
515 | /* the following is too sensitive to write to log files by accident, | ||
516 | so we require manual intervention to get this one... */ | ||
517 | #if DEBUG_KX | ||
518 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
519 | "Encrypted %u bytes for `%s' using key %u, IV %u\n", | ||
520 | (unsigned int) size, | ||
521 | GNUNET_i2s (kx->peer), | ||
522 | (unsigned int) kx->encrypt_key.crc32, | ||
523 | GNUNET_CRYPTO_crc32_n (iv, sizeof(iv))); | ||
524 | #endif | ||
525 | return GNUNET_OK; | ||
526 | } | ||
527 | |||
528 | |||
529 | /** | ||
530 | * Decrypt size bytes from @a in and write the result to @a out. Use | ||
531 | * the @a kx key for inbound traffic of the given neighbour. This | ||
532 | * function does NOT do any integrity-checks on the result. | ||
533 | * | ||
534 | * @param kx key information context | ||
535 | * @param iv initialization vector to use | ||
536 | * @param in ciphertext | ||
537 | * @param out plaintext | ||
538 | * @param size size of @a in / @a out | ||
539 | * @return #GNUNET_OK on success | ||
540 | */ | ||
541 | static int | ||
542 | do_decrypt (struct GSC_KeyExchangeInfo *kx, | ||
543 | const struct GNUNET_CRYPTO_SymmetricInitializationVector *iv, | ||
544 | const void *in, | ||
545 | void *out, | ||
546 | size_t size) | ||
547 | { | ||
548 | if (size != (uint16_t) size) | ||
549 | { | ||
550 | GNUNET_break (0); | ||
551 | return GNUNET_NO; | ||
552 | } | ||
553 | if ((kx->status != GNUNET_CORE_KX_STATE_KEY_RECEIVED) && | ||
554 | (kx->status != GNUNET_CORE_KX_STATE_UP) && | ||
555 | (kx->status != GNUNET_CORE_KX_STATE_REKEY_SENT)) | ||
556 | { | ||
557 | GNUNET_break_op (0); | ||
558 | return GNUNET_SYSERR; | ||
559 | } | ||
560 | if (size != GNUNET_CRYPTO_symmetric_decrypt (in, | ||
561 | (uint16_t) size, | ||
562 | &kx->decrypt_key, | ||
563 | iv, | ||
564 | out)) | ||
565 | { | ||
566 | GNUNET_break (0); | ||
567 | return GNUNET_SYSERR; | ||
568 | } | ||
569 | GNUNET_STATISTICS_update (GSC_stats, | ||
570 | gettext_noop ("# bytes decrypted"), | ||
571 | size, | ||
572 | GNUNET_NO); | ||
573 | /* the following is too sensitive to write to log files by accident, | ||
574 | so we require manual intervention to get this one... */ | ||
575 | #if DEBUG_KX | ||
576 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
577 | "Decrypted %u bytes from `%s' using key %u, IV %u\n", | ||
578 | (unsigned int) size, | ||
579 | GNUNET_i2s (kx->peer), | ||
580 | (unsigned int) kx->decrypt_key.crc32, | ||
581 | GNUNET_CRYPTO_crc32_n (iv, sizeof(*iv))); | ||
582 | #endif | ||
583 | return GNUNET_OK; | ||
584 | } | ||
585 | |||
586 | |||
587 | /** | ||
588 | * Send our key (and encrypted PING) to the other peer. | ||
589 | * | ||
590 | * @param kx key exchange context | ||
591 | */ | ||
592 | static void | ||
593 | send_key (struct GSC_KeyExchangeInfo *kx); | ||
594 | |||
595 | |||
596 | /** | ||
597 | * Task that will retry #send_key() if our previous attempt failed. | ||
598 | * | ||
599 | * @param cls our `struct GSC_KeyExchangeInfo` | ||
600 | */ | ||
601 | static void | ||
602 | set_key_retry_task (void *cls) | ||
603 | { | ||
604 | struct GSC_KeyExchangeInfo *kx = cls; | ||
605 | |||
606 | kx->retry_set_key_task = NULL; | ||
607 | kx->set_key_retry_frequency = | ||
608 | GNUNET_TIME_STD_BACKOFF (kx->set_key_retry_frequency); | ||
609 | GNUNET_assert (GNUNET_CORE_KX_STATE_DOWN != kx->status); | ||
610 | send_key (kx); | ||
611 | } | ||
612 | |||
613 | |||
614 | /** | ||
615 | * Create a fresh PING message for transmission to the other peer. | ||
616 | * | ||
617 | * @param kx key exchange context to create PING for | ||
618 | */ | ||
619 | static void | ||
620 | setup_fresh_ping (struct GSC_KeyExchangeInfo *kx) | ||
621 | { | ||
622 | struct PingMessage pp; | ||
623 | struct PingMessage *pm; | ||
624 | struct GNUNET_CRYPTO_SymmetricInitializationVector iv; | ||
625 | |||
626 | pm = &kx->ping; | ||
627 | kx->ping_challenge = | ||
628 | GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX); | ||
629 | pm->header.size = htons (sizeof(struct PingMessage)); | ||
630 | pm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_PING); | ||
631 | pm->iv_seed = calculate_seed (kx); | ||
632 | derive_iv (&iv, &kx->encrypt_key, pm->iv_seed, kx->peer); | ||
633 | pp.challenge = kx->ping_challenge; | ||
634 | pp.target = *kx->peer; | ||
635 | do_encrypt (kx, | ||
636 | &iv, | ||
637 | &pp.target, | ||
638 | &pm->target, | ||
639 | sizeof(struct PingMessage) | ||
640 | - ((void *) &pm->target - (void *) pm)); | ||
641 | } | ||
642 | |||
643 | |||
644 | /** | ||
645 | * Deliver P2P message to interested clients. Invokes send twice, | ||
646 | * once for clients that want the full message, and once for clients | ||
647 | * that only want the header | ||
648 | * | ||
649 | * @param cls the `struct GSC_KeyExchangeInfo` | ||
650 | * @param m the message | ||
651 | * @return #GNUNET_OK on success, | ||
652 | * #GNUNET_NO to stop further processing (no error) | ||
653 | * #GNUNET_SYSERR to stop further processing with error | ||
654 | */ | ||
655 | static int | ||
656 | deliver_message (void *cls, const struct GNUNET_MessageHeader *m) | ||
657 | { | ||
658 | struct GSC_KeyExchangeInfo *kx = cls; | ||
659 | |||
660 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
661 | "Decrypted message of type %d from %s\n", | ||
662 | ntohs (m->type), | ||
663 | GNUNET_i2s (kx->peer)); | ||
664 | if (GNUNET_CORE_KX_STATE_UP != kx->status) | ||
665 | { | ||
666 | GNUNET_STATISTICS_update (GSC_stats, | ||
667 | gettext_noop ("# PAYLOAD dropped (out of order)"), | ||
668 | 1, | ||
669 | GNUNET_NO); | ||
670 | return GNUNET_OK; | ||
671 | } | ||
672 | switch (ntohs (m->type)) | ||
673 | { | ||
674 | case GNUNET_MESSAGE_TYPE_CORE_BINARY_TYPE_MAP: | ||
675 | case GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP: | ||
676 | GSC_SESSIONS_set_typemap (kx->peer, m); | ||
677 | return GNUNET_OK; | ||
678 | |||
679 | case GNUNET_MESSAGE_TYPE_CORE_CONFIRM_TYPE_MAP: | ||
680 | GSC_SESSIONS_confirm_typemap (kx->peer, m); | ||
681 | return GNUNET_OK; | ||
682 | |||
683 | default: | ||
684 | GSC_CLIENTS_deliver_message (kx->peer, | ||
685 | m, | ||
686 | ntohs (m->size), | ||
687 | GNUNET_CORE_OPTION_SEND_FULL_INBOUND); | ||
688 | GSC_CLIENTS_deliver_message (kx->peer, | ||
689 | m, | ||
690 | sizeof(struct GNUNET_MessageHeader), | ||
691 | GNUNET_CORE_OPTION_SEND_HDR_INBOUND); | ||
692 | } | ||
693 | return GNUNET_OK; | ||
694 | } | ||
695 | |||
696 | |||
697 | /** | ||
698 | * Function called by transport to notify us that | ||
699 | * a peer connected to us (on the network level). | ||
700 | * Starts the key exchange with the given peer. | ||
701 | * | ||
702 | * @param cls closure (NULL) | ||
703 | * @param pid identity of the peer to do a key exchange with | ||
704 | * @return key exchange information context | ||
705 | */ | ||
706 | static void * | ||
707 | handle_transport_notify_connect (void *cls, | ||
708 | const struct GNUNET_PeerIdentity *pid, | ||
709 | struct GNUNET_MQ_Handle *mq) | ||
710 | { | ||
711 | struct GSC_KeyExchangeInfo *kx; | ||
712 | struct GNUNET_HashCode h1; | ||
713 | struct GNUNET_HashCode h2; | ||
714 | |||
715 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
716 | "Initiating key exchange with `%s'\n", | ||
717 | GNUNET_i2s (pid)); | ||
718 | GNUNET_STATISTICS_update (GSC_stats, | ||
719 | gettext_noop ("# key exchanges initiated"), | ||
720 | 1, | ||
721 | GNUNET_NO); | ||
722 | kx = GNUNET_new (struct GSC_KeyExchangeInfo); | ||
723 | kx->mst = GNUNET_MST_create (&deliver_message, kx); | ||
724 | kx->mq = mq; | ||
725 | kx->peer = pid; | ||
726 | kx->set_key_retry_frequency = INITIAL_SET_KEY_RETRY_FREQUENCY; | ||
727 | GNUNET_CONTAINER_DLL_insert (kx_head, kx_tail, kx); | ||
728 | kx->status = GNUNET_CORE_KX_STATE_KEY_SENT; | ||
729 | monitor_notify_all (kx); | ||
730 | GNUNET_CRYPTO_hash (pid, sizeof(struct GNUNET_PeerIdentity), &h1); | ||
731 | GNUNET_CRYPTO_hash (&GSC_my_identity, | ||
732 | sizeof(struct GNUNET_PeerIdentity), | ||
733 | &h2); | ||
734 | if (0 < GNUNET_CRYPTO_hash_cmp (&h1, &h2)) | ||
735 | { | ||
736 | /* peer with "lower" identity starts KX, otherwise we typically end up | ||
737 | with both peers starting the exchange and transmit the 'set key' | ||
738 | message twice */ | ||
739 | send_key (kx); | ||
740 | } | ||
741 | else | ||
742 | { | ||
743 | /* peer with "higher" identity starts a delayed KX, if the "lower" peer | ||
744 | * does not start a KX since it sees no reasons to do so */ | ||
745 | kx->retry_set_key_task = | ||
746 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, | ||
747 | &set_key_retry_task, | ||
748 | kx); | ||
749 | } | ||
750 | return kx; | ||
751 | } | ||
752 | |||
753 | |||
754 | /** | ||
755 | * Function called by transport telling us that a peer | ||
756 | * disconnected. | ||
757 | * Stop key exchange with the given peer. Clean up key material. | ||
758 | * | ||
759 | * @param cls closure | ||
760 | * @param peer the peer that disconnected | ||
761 | * @param handler_cls the `struct GSC_KeyExchangeInfo` of the peer | ||
762 | */ | ||
763 | static void | ||
764 | handle_transport_notify_disconnect (void *cls, | ||
765 | const struct GNUNET_PeerIdentity *peer, | ||
766 | void *handler_cls) | ||
767 | { | ||
768 | struct GSC_KeyExchangeInfo *kx = handler_cls; | ||
769 | |||
770 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
771 | "Peer `%s' disconnected from us.\n", | ||
772 | GNUNET_i2s (peer)); | ||
773 | GSC_SESSIONS_end (kx->peer); | ||
774 | GNUNET_STATISTICS_update (GSC_stats, | ||
775 | gettext_noop ("# key exchanges stopped"), | ||
776 | 1, | ||
777 | GNUNET_NO); | ||
778 | if (NULL != kx->retry_set_key_task) | ||
779 | { | ||
780 | GNUNET_SCHEDULER_cancel (kx->retry_set_key_task); | ||
781 | kx->retry_set_key_task = NULL; | ||
782 | } | ||
783 | if (NULL != kx->keep_alive_task) | ||
784 | { | ||
785 | GNUNET_SCHEDULER_cancel (kx->keep_alive_task); | ||
786 | kx->keep_alive_task = NULL; | ||
787 | } | ||
788 | kx->status = GNUNET_CORE_KX_PEER_DISCONNECT; | ||
789 | monitor_notify_all (kx); | ||
790 | GNUNET_CONTAINER_DLL_remove (kx_head, kx_tail, kx); | ||
791 | GNUNET_MST_destroy (kx->mst); | ||
792 | GNUNET_free (kx); | ||
793 | } | ||
794 | |||
795 | |||
796 | /** | ||
797 | * Send our PING to the other peer. | ||
798 | * | ||
799 | * @param kx key exchange context | ||
800 | */ | ||
801 | static void | ||
802 | send_ping (struct GSC_KeyExchangeInfo *kx) | ||
803 | { | ||
804 | struct GNUNET_MQ_Envelope *env; | ||
805 | |||
806 | GNUNET_STATISTICS_update (GSC_stats, | ||
807 | gettext_noop ("# PING messages transmitted"), | ||
808 | 1, | ||
809 | GNUNET_NO); | ||
810 | env = GNUNET_MQ_msg_copy (&kx->ping.header); | ||
811 | GNUNET_MQ_send (kx->mq, env); | ||
812 | } | ||
813 | |||
814 | |||
815 | /** | ||
816 | * Derive fresh session keys from the current ephemeral keys. | ||
817 | * | ||
818 | * @param kx session to derive keys for | ||
819 | */ | ||
820 | static void | ||
821 | derive_session_keys (struct GSC_KeyExchangeInfo *kx) | ||
822 | { | ||
823 | struct GNUNET_HashCode key_material; | ||
824 | |||
825 | if (GNUNET_OK != | ||
826 | GNUNET_CRYPTO_ecc_ecdh (&my_ephemeral_key, | ||
827 | &kx->other_ephemeral_key, | ||
828 | &key_material)) | ||
829 | { | ||
830 | GNUNET_break (0); | ||
831 | return; | ||
832 | } | ||
833 | derive_aes_key (&GSC_my_identity, kx->peer, &key_material, &kx->encrypt_key); | ||
834 | derive_aes_key (kx->peer, &GSC_my_identity, &key_material, &kx->decrypt_key); | ||
835 | memset (&key_material, 0, sizeof(key_material)); | ||
836 | /* fresh key, reset sequence numbers */ | ||
837 | kx->last_sequence_number_received = 0; | ||
838 | kx->last_packets_bitmap = 0; | ||
839 | setup_fresh_ping (kx); | ||
840 | } | ||
841 | |||
842 | |||
843 | /** | ||
844 | * We received a #GNUNET_MESSAGE_TYPE_CORE_EPHEMERAL_KEY message. | ||
845 | * Validate and update our key material and status. | ||
846 | * | ||
847 | * @param cls key exchange status for the corresponding peer | ||
848 | * @param m the set key message we received | ||
849 | */ | ||
850 | static void | ||
851 | handle_ephemeral_key (void *cls, const struct EphemeralKeyMessage *m) | ||
852 | { | ||
853 | struct GSC_KeyExchangeInfo *kx = cls; | ||
854 | struct GNUNET_TIME_Absolute start_t; | ||
855 | struct GNUNET_TIME_Absolute end_t; | ||
856 | struct GNUNET_TIME_Absolute now; | ||
857 | enum GNUNET_CORE_KxState sender_status; | ||
858 | |||
859 | end_t = GNUNET_TIME_absolute_ntoh (m->expiration_time); | ||
860 | if (((GNUNET_CORE_KX_STATE_KEY_RECEIVED == kx->status) || | ||
861 | (GNUNET_CORE_KX_STATE_UP == kx->status) || | ||
862 | (GNUNET_CORE_KX_STATE_REKEY_SENT == kx->status)) && | ||
863 | (end_t.abs_value_us < kx->foreign_key_expires.abs_value_us)) | ||
864 | { | ||
865 | GNUNET_STATISTICS_update (GSC_stats, | ||
866 | gettext_noop ("# old ephemeral keys ignored"), | ||
867 | 1, | ||
868 | GNUNET_NO); | ||
869 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
870 | "Received expired EPHEMERAL_KEY from %s\n", | ||
871 | GNUNET_i2s (&m->origin_identity)); | ||
872 | return; | ||
873 | } | ||
874 | if (0 == memcmp (&m->ephemeral_key, | ||
875 | &kx->other_ephemeral_key, | ||
876 | sizeof(m->ephemeral_key))) | ||
877 | { | ||
878 | GNUNET_STATISTICS_update (GSC_stats, | ||
879 | gettext_noop ( | ||
880 | "# duplicate ephemeral keys ignored"), | ||
881 | 1, | ||
882 | GNUNET_NO); | ||
883 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
884 | "Ignoring duplicate EPHEMERAL_KEY from %s\n", | ||
885 | GNUNET_i2s (&m->origin_identity)); | ||
886 | return; | ||
887 | } | ||
888 | if (0 != memcmp (&m->origin_identity, | ||
889 | kx->peer, | ||
890 | sizeof(struct GNUNET_PeerIdentity))) | ||
891 | { | ||
892 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
893 | "Received EPHEMERAL_KEY from %s, but expected %s\n", | ||
894 | GNUNET_i2s (&m->origin_identity), | ||
895 | GNUNET_i2s_full (kx->peer)); | ||
896 | GNUNET_break_op (0); | ||
897 | return; | ||
898 | } | ||
899 | if ((ntohl (m->purpose.size) != | ||
900 | sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose) | ||
901 | + sizeof(struct GNUNET_TIME_AbsoluteNBO) | ||
902 | + sizeof(struct GNUNET_TIME_AbsoluteNBO) | ||
903 | + sizeof(struct GNUNET_CRYPTO_EddsaPublicKey) | ||
904 | + sizeof(struct GNUNET_CRYPTO_EddsaPublicKey)) || | ||
905 | (GNUNET_OK != | ||
906 | GNUNET_CRYPTO_eddsa_verify_ (GNUNET_SIGNATURE_PURPOSE_SET_ECC_KEY, | ||
907 | &m->purpose, | ||
908 | &m->signature, | ||
909 | &m->origin_identity.public_key))) | ||
910 | { | ||
911 | /* invalid signature */ | ||
912 | GNUNET_break_op (0); | ||
913 | GNUNET_STATISTICS_update (GSC_stats, | ||
914 | gettext_noop ( | ||
915 | "# EPHEMERAL_KEYs rejected (bad signature)"), | ||
916 | 1, | ||
917 | GNUNET_NO); | ||
918 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
919 | "Received EPHEMERAL_KEY from %s with bad signature\n", | ||
920 | GNUNET_i2s (&m->origin_identity)); | ||
921 | return; | ||
922 | } | ||
923 | now = GNUNET_TIME_absolute_get (); | ||
924 | start_t = GNUNET_TIME_absolute_ntoh (m->creation_time); | ||
925 | if ((end_t.abs_value_us < | ||
926 | GNUNET_TIME_absolute_subtract (now, REKEY_TOLERANCE).abs_value_us) || | ||
927 | (start_t.abs_value_us > | ||
928 | GNUNET_TIME_absolute_add (now, REKEY_TOLERANCE).abs_value_us)) | ||
929 | { | ||
930 | GNUNET_log ( | ||
931 | GNUNET_ERROR_TYPE_WARNING, | ||
932 | _ ( | ||
933 | "EPHEMERAL_KEY from peer `%s' rejected as its validity range does not match our system time (%llu not in [%llu,%llu]).\n"), | ||
934 | GNUNET_i2s (kx->peer), | ||
935 | (unsigned long long) now.abs_value_us, | ||
936 | (unsigned long long) start_t.abs_value_us, | ||
937 | (unsigned long long) end_t.abs_value_us); | ||
938 | GNUNET_STATISTICS_update (GSC_stats, | ||
939 | gettext_noop ( | ||
940 | "# EPHEMERAL_KEY messages rejected due to time"), | ||
941 | 1, | ||
942 | GNUNET_NO); | ||
943 | return; | ||
944 | } | ||
945 | #if DEBUG_KX | ||
946 | { | ||
947 | struct GNUNET_HashCode eh; | ||
948 | |||
949 | GNUNET_CRYPTO_hash (&m->ephemeral_key, sizeof(m->ephemeral_key), &eh); | ||
950 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
951 | "Received valid EPHEMERAL_KEY `%s' from `%s' in state %d.\n", | ||
952 | GNUNET_h2s (&eh), | ||
953 | GNUNET_i2s (kx->peer), | ||
954 | kx->status); | ||
955 | } | ||
956 | #endif | ||
957 | GNUNET_STATISTICS_update (GSC_stats, | ||
958 | gettext_noop ("# valid ephemeral keys received"), | ||
959 | 1, | ||
960 | GNUNET_NO); | ||
961 | kx->other_ephemeral_key = m->ephemeral_key; | ||
962 | kx->foreign_key_expires = end_t; | ||
963 | derive_session_keys (kx); | ||
964 | |||
965 | /* check if we still need to send the sender our key */ | ||
966 | sender_status = (enum GNUNET_CORE_KxState) ntohl (m->sender_status); | ||
967 | switch (sender_status) | ||
968 | { | ||
969 | case GNUNET_CORE_KX_STATE_DOWN: | ||
970 | GNUNET_break_op (0); | ||
971 | break; | ||
972 | |||
973 | case GNUNET_CORE_KX_STATE_KEY_SENT: | ||
974 | /* fine, need to send our key after updating our status, see below */ | ||
975 | GSC_SESSIONS_reinit (kx->peer); | ||
976 | break; | ||
977 | |||
978 | case GNUNET_CORE_KX_STATE_KEY_RECEIVED: | ||
979 | /* other peer already got our key, but typemap did go down */ | ||
980 | GSC_SESSIONS_reinit (kx->peer); | ||
981 | break; | ||
982 | |||
983 | case GNUNET_CORE_KX_STATE_UP: | ||
984 | /* other peer already got our key, typemap NOT down */ | ||
985 | break; | ||
986 | |||
987 | case GNUNET_CORE_KX_STATE_REKEY_SENT: | ||
988 | /* other peer already got our key, typemap NOT down */ | ||
989 | break; | ||
990 | |||
991 | default: | ||
992 | GNUNET_break (0); | ||
993 | break; | ||
994 | } | ||
995 | /* check if we need to confirm everything is fine via PING + PONG */ | ||
996 | switch (kx->status) | ||
997 | { | ||
998 | case GNUNET_CORE_KX_STATE_DOWN: | ||
999 | GNUNET_assert (NULL == kx->keep_alive_task); | ||
1000 | kx->status = GNUNET_CORE_KX_STATE_KEY_RECEIVED; | ||
1001 | monitor_notify_all (kx); | ||
1002 | if (GNUNET_CORE_KX_STATE_KEY_SENT == sender_status) | ||
1003 | send_key (kx); | ||
1004 | else | ||
1005 | send_ping (kx); | ||
1006 | break; | ||
1007 | |||
1008 | case GNUNET_CORE_KX_STATE_KEY_SENT: | ||
1009 | GNUNET_assert (NULL == kx->keep_alive_task); | ||
1010 | kx->status = GNUNET_CORE_KX_STATE_KEY_RECEIVED; | ||
1011 | monitor_notify_all (kx); | ||
1012 | if (GNUNET_CORE_KX_STATE_KEY_SENT == sender_status) | ||
1013 | send_key (kx); | ||
1014 | else | ||
1015 | send_ping (kx); | ||
1016 | break; | ||
1017 | |||
1018 | case GNUNET_CORE_KX_STATE_KEY_RECEIVED: | ||
1019 | GNUNET_assert (NULL == kx->keep_alive_task); | ||
1020 | if (GNUNET_CORE_KX_STATE_KEY_SENT == sender_status) | ||
1021 | send_key (kx); | ||
1022 | else | ||
1023 | send_ping (kx); | ||
1024 | break; | ||
1025 | |||
1026 | case GNUNET_CORE_KX_STATE_UP: | ||
1027 | kx->status = GNUNET_CORE_KX_STATE_REKEY_SENT; | ||
1028 | monitor_notify_all (kx); | ||
1029 | if (GNUNET_CORE_KX_STATE_KEY_SENT == sender_status) | ||
1030 | send_key (kx); | ||
1031 | else | ||
1032 | send_ping (kx); | ||
1033 | break; | ||
1034 | |||
1035 | case GNUNET_CORE_KX_STATE_REKEY_SENT: | ||
1036 | if (GNUNET_CORE_KX_STATE_KEY_SENT == sender_status) | ||
1037 | send_key (kx); | ||
1038 | else | ||
1039 | send_ping (kx); | ||
1040 | break; | ||
1041 | |||
1042 | default: | ||
1043 | GNUNET_break (0); | ||
1044 | break; | ||
1045 | } | ||
1046 | } | ||
1047 | |||
1048 | |||
1049 | /** | ||
1050 | * We received a PING message. Validate and transmit | ||
1051 | * a PONG message. | ||
1052 | * | ||
1053 | * @param cls key exchange status for the corresponding peer | ||
1054 | * @param m the encrypted PING message itself | ||
1055 | */ | ||
1056 | static void | ||
1057 | handle_ping (void *cls, const struct PingMessage *m) | ||
1058 | { | ||
1059 | struct GSC_KeyExchangeInfo *kx = cls; | ||
1060 | struct PingMessage t; | ||
1061 | struct PongMessage tx; | ||
1062 | struct PongMessage *tp; | ||
1063 | struct GNUNET_MQ_Envelope *env; | ||
1064 | struct GNUNET_CRYPTO_SymmetricInitializationVector iv; | ||
1065 | |||
1066 | GNUNET_STATISTICS_update (GSC_stats, | ||
1067 | gettext_noop ("# PING messages received"), | ||
1068 | 1, | ||
1069 | GNUNET_NO); | ||
1070 | if ((kx->status != GNUNET_CORE_KX_STATE_KEY_RECEIVED) && | ||
1071 | (kx->status != GNUNET_CORE_KX_STATE_UP) && | ||
1072 | (kx->status != GNUNET_CORE_KX_STATE_REKEY_SENT)) | ||
1073 | { | ||
1074 | /* ignore */ | ||
1075 | GNUNET_STATISTICS_update (GSC_stats, | ||
1076 | gettext_noop ( | ||
1077 | "# PING messages dropped (out of order)"), | ||
1078 | 1, | ||
1079 | GNUNET_NO); | ||
1080 | return; | ||
1081 | } | ||
1082 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1083 | "Core service receives PING request from `%s'.\n", | ||
1084 | GNUNET_i2s (kx->peer)); | ||
1085 | derive_iv (&iv, &kx->decrypt_key, m->iv_seed, &GSC_my_identity); | ||
1086 | if (GNUNET_OK != do_decrypt (kx, | ||
1087 | &iv, | ||
1088 | &m->target, | ||
1089 | &t.target, | ||
1090 | sizeof(struct PingMessage) | ||
1091 | - ((void *) &m->target - (void *) m))) | ||
1092 | { | ||
1093 | GNUNET_break_op (0); | ||
1094 | return; | ||
1095 | } | ||
1096 | if (0 != | ||
1097 | memcmp (&t.target, &GSC_my_identity, sizeof(struct GNUNET_PeerIdentity))) | ||
1098 | { | ||
1099 | if (GNUNET_CORE_KX_STATE_REKEY_SENT != kx->status) | ||
1100 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1101 | "Decryption of PING from peer `%s' failed, PING for `%s'?\n", | ||
1102 | GNUNET_i2s (kx->peer), | ||
1103 | GNUNET_i2s2 (&t.target)); | ||
1104 | else | ||
1105 | GNUNET_log ( | ||
1106 | GNUNET_ERROR_TYPE_DEBUG, | ||
1107 | "Decryption of PING from peer `%s' failed after rekey (harmless)\n", | ||
1108 | GNUNET_i2s (kx->peer)); | ||
1109 | GNUNET_break_op (0); | ||
1110 | return; | ||
1111 | } | ||
1112 | /* construct PONG */ | ||
1113 | tx.reserved = 0; | ||
1114 | tx.challenge = t.challenge; | ||
1115 | tx.target = t.target; | ||
1116 | env = GNUNET_MQ_msg (tp, GNUNET_MESSAGE_TYPE_CORE_PONG); | ||
1117 | tp->iv_seed = calculate_seed (kx); | ||
1118 | derive_pong_iv (&iv, &kx->encrypt_key, tp->iv_seed, t.challenge, kx->peer); | ||
1119 | do_encrypt (kx, | ||
1120 | &iv, | ||
1121 | &tx.challenge, | ||
1122 | &tp->challenge, | ||
1123 | sizeof(struct PongMessage) | ||
1124 | - ((void *) &tp->challenge - (void *) tp)); | ||
1125 | GNUNET_STATISTICS_update (GSC_stats, | ||
1126 | gettext_noop ("# PONG messages created"), | ||
1127 | 1, | ||
1128 | GNUNET_NO); | ||
1129 | GNUNET_MQ_send (kx->mq, env); | ||
1130 | } | ||
1131 | |||
1132 | |||
1133 | /** | ||
1134 | * Task triggered when a neighbour entry is about to time out | ||
1135 | * (and we should prevent this by sending a PING). | ||
1136 | * | ||
1137 | * @param cls the `struct GSC_KeyExchangeInfo` | ||
1138 | */ | ||
1139 | static void | ||
1140 | send_keep_alive (void *cls) | ||
1141 | { | ||
1142 | struct GSC_KeyExchangeInfo *kx = cls; | ||
1143 | struct GNUNET_TIME_Relative retry; | ||
1144 | struct GNUNET_TIME_Relative left; | ||
1145 | |||
1146 | kx->keep_alive_task = NULL; | ||
1147 | left = GNUNET_TIME_absolute_get_remaining (kx->timeout); | ||
1148 | if (0 == left.rel_value_us) | ||
1149 | { | ||
1150 | GNUNET_STATISTICS_update (GSC_stats, | ||
1151 | gettext_noop ("# sessions terminated by timeout"), | ||
1152 | 1, | ||
1153 | GNUNET_NO); | ||
1154 | GSC_SESSIONS_end (kx->peer); | ||
1155 | kx->status = GNUNET_CORE_KX_STATE_KEY_SENT; | ||
1156 | monitor_notify_all (kx); | ||
1157 | send_key (kx); | ||
1158 | return; | ||
1159 | } | ||
1160 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1161 | "Sending KEEPALIVE to `%s'\n", | ||
1162 | GNUNET_i2s (kx->peer)); | ||
1163 | GNUNET_STATISTICS_update (GSC_stats, | ||
1164 | gettext_noop ("# keepalive messages sent"), | ||
1165 | 1, | ||
1166 | GNUNET_NO); | ||
1167 | setup_fresh_ping (kx); | ||
1168 | send_ping (kx); | ||
1169 | retry = GNUNET_TIME_relative_max (GNUNET_TIME_relative_divide (left, 2), | ||
1170 | MIN_PING_FREQUENCY); | ||
1171 | kx->keep_alive_task = | ||
1172 | GNUNET_SCHEDULER_add_delayed (retry, &send_keep_alive, kx); | ||
1173 | } | ||
1174 | |||
1175 | |||
1176 | /** | ||
1177 | * We've seen a valid message from the other peer. | ||
1178 | * Update the time when the session would time out | ||
1179 | * and delay sending our keep alive message further. | ||
1180 | * | ||
1181 | * @param kx key exchange where we saw activity | ||
1182 | */ | ||
1183 | static void | ||
1184 | update_timeout (struct GSC_KeyExchangeInfo *kx) | ||
1185 | { | ||
1186 | struct GNUNET_TIME_Relative delta; | ||
1187 | |||
1188 | kx->timeout = | ||
1189 | GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); | ||
1190 | delta = | ||
1191 | GNUNET_TIME_absolute_get_difference (kx->last_notify_timeout, kx->timeout); | ||
1192 | if (delta.rel_value_us > 5LL * 1000LL * 1000LL) | ||
1193 | { | ||
1194 | /* we only notify monitors about timeout changes if those | ||
1195 | are bigger than the threshold (5s) */ | ||
1196 | monitor_notify_all (kx); | ||
1197 | } | ||
1198 | if (NULL != kx->keep_alive_task) | ||
1199 | GNUNET_SCHEDULER_cancel (kx->keep_alive_task); | ||
1200 | kx->keep_alive_task = GNUNET_SCHEDULER_add_delayed ( | ||
1201 | GNUNET_TIME_relative_divide (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, 2), | ||
1202 | &send_keep_alive, | ||
1203 | kx); | ||
1204 | } | ||
1205 | |||
1206 | |||
1207 | /** | ||
1208 | * We received a PONG message. Validate and update our status. | ||
1209 | * | ||
1210 | * @param kx key exchange context for the the PONG | ||
1211 | * @param m the encrypted PONG message itself | ||
1212 | */ | ||
1213 | static void | ||
1214 | handle_pong (void *cls, const struct PongMessage *m) | ||
1215 | { | ||
1216 | struct GSC_KeyExchangeInfo *kx = cls; | ||
1217 | struct PongMessage t; | ||
1218 | struct GNUNET_CRYPTO_SymmetricInitializationVector iv; | ||
1219 | |||
1220 | GNUNET_STATISTICS_update (GSC_stats, | ||
1221 | gettext_noop ("# PONG messages received"), | ||
1222 | 1, | ||
1223 | GNUNET_NO); | ||
1224 | switch (kx->status) | ||
1225 | { | ||
1226 | case GNUNET_CORE_KX_STATE_DOWN: | ||
1227 | GNUNET_STATISTICS_update (GSC_stats, | ||
1228 | gettext_noop ( | ||
1229 | "# PONG messages dropped (connection down)"), | ||
1230 | 1, | ||
1231 | GNUNET_NO); | ||
1232 | return; | ||
1233 | |||
1234 | case GNUNET_CORE_KX_STATE_KEY_SENT: | ||
1235 | GNUNET_STATISTICS_update (GSC_stats, | ||
1236 | gettext_noop ( | ||
1237 | "# PONG messages dropped (out of order)"), | ||
1238 | 1, | ||
1239 | GNUNET_NO); | ||
1240 | return; | ||
1241 | |||
1242 | case GNUNET_CORE_KX_STATE_KEY_RECEIVED: | ||
1243 | break; | ||
1244 | |||
1245 | case GNUNET_CORE_KX_STATE_UP: | ||
1246 | break; | ||
1247 | |||
1248 | case GNUNET_CORE_KX_STATE_REKEY_SENT: | ||
1249 | break; | ||
1250 | |||
1251 | default: | ||
1252 | GNUNET_break (0); | ||
1253 | return; | ||
1254 | } | ||
1255 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1256 | "Core service receives PONG response from `%s'.\n", | ||
1257 | GNUNET_i2s (kx->peer)); | ||
1258 | /* mark as garbage, just to be sure */ | ||
1259 | memset (&t, 255, sizeof(t)); | ||
1260 | derive_pong_iv (&iv, | ||
1261 | &kx->decrypt_key, | ||
1262 | m->iv_seed, | ||
1263 | kx->ping_challenge, | ||
1264 | &GSC_my_identity); | ||
1265 | if (GNUNET_OK != do_decrypt (kx, | ||
1266 | &iv, | ||
1267 | &m->challenge, | ||
1268 | &t.challenge, | ||
1269 | sizeof(struct PongMessage) | ||
1270 | - ((void *) &m->challenge - (void *) m))) | ||
1271 | { | ||
1272 | GNUNET_break_op (0); | ||
1273 | return; | ||
1274 | } | ||
1275 | GNUNET_STATISTICS_update (GSC_stats, | ||
1276 | gettext_noop ("# PONG messages decrypted"), | ||
1277 | 1, | ||
1278 | GNUNET_NO); | ||
1279 | if ((0 != | ||
1280 | memcmp (&t.target, kx->peer, sizeof(struct GNUNET_PeerIdentity))) || | ||
1281 | (kx->ping_challenge != t.challenge)) | ||
1282 | { | ||
1283 | /* PONG malformed */ | ||
1284 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1285 | "Received malformed PONG wanted sender `%s' with challenge %u\n", | ||
1286 | GNUNET_i2s (kx->peer), | ||
1287 | (unsigned int) kx->ping_challenge); | ||
1288 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1289 | "Received malformed PONG received from `%s' with challenge %u\n", | ||
1290 | GNUNET_i2s (&t.target), | ||
1291 | (unsigned int) t.challenge); | ||
1292 | return; | ||
1293 | } | ||
1294 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1295 | "Received valid PONG from `%s'\n", | ||
1296 | GNUNET_i2s (kx->peer)); | ||
1297 | /* no need to resend key any longer */ | ||
1298 | if (NULL != kx->retry_set_key_task) | ||
1299 | { | ||
1300 | GNUNET_SCHEDULER_cancel (kx->retry_set_key_task); | ||
1301 | kx->retry_set_key_task = NULL; | ||
1302 | } | ||
1303 | switch (kx->status) | ||
1304 | { | ||
1305 | case GNUNET_CORE_KX_STATE_DOWN: | ||
1306 | GNUNET_assert (0); /* should be impossible */ | ||
1307 | return; | ||
1308 | |||
1309 | case GNUNET_CORE_KX_STATE_KEY_SENT: | ||
1310 | GNUNET_assert (0); /* should be impossible */ | ||
1311 | return; | ||
1312 | |||
1313 | case GNUNET_CORE_KX_STATE_KEY_RECEIVED: | ||
1314 | GNUNET_STATISTICS_update (GSC_stats, | ||
1315 | gettext_noop ( | ||
1316 | "# session keys confirmed via PONG"), | ||
1317 | 1, | ||
1318 | GNUNET_NO); | ||
1319 | kx->status = GNUNET_CORE_KX_STATE_UP; | ||
1320 | monitor_notify_all (kx); | ||
1321 | GSC_SESSIONS_create (kx->peer, kx); | ||
1322 | GNUNET_assert (NULL == kx->keep_alive_task); | ||
1323 | update_timeout (kx); | ||
1324 | break; | ||
1325 | |||
1326 | case GNUNET_CORE_KX_STATE_UP: | ||
1327 | GNUNET_STATISTICS_update (GSC_stats, | ||
1328 | gettext_noop ("# timeouts prevented via PONG"), | ||
1329 | 1, | ||
1330 | GNUNET_NO); | ||
1331 | update_timeout (kx); | ||
1332 | break; | ||
1333 | |||
1334 | case GNUNET_CORE_KX_STATE_REKEY_SENT: | ||
1335 | GNUNET_STATISTICS_update (GSC_stats, | ||
1336 | gettext_noop ( | ||
1337 | "# rekey operations confirmed via PONG"), | ||
1338 | 1, | ||
1339 | GNUNET_NO); | ||
1340 | kx->status = GNUNET_CORE_KX_STATE_UP; | ||
1341 | monitor_notify_all (kx); | ||
1342 | update_timeout (kx); | ||
1343 | break; | ||
1344 | |||
1345 | default: | ||
1346 | GNUNET_break (0); | ||
1347 | break; | ||
1348 | } | ||
1349 | } | ||
1350 | |||
1351 | |||
1352 | /** | ||
1353 | * Send our key to the other peer. | ||
1354 | * | ||
1355 | * @param kx key exchange context | ||
1356 | */ | ||
1357 | static void | ||
1358 | send_key (struct GSC_KeyExchangeInfo *kx) | ||
1359 | { | ||
1360 | struct GNUNET_MQ_Envelope *env; | ||
1361 | |||
1362 | GNUNET_assert (GNUNET_CORE_KX_STATE_DOWN != kx->status); | ||
1363 | if (NULL != kx->retry_set_key_task) | ||
1364 | { | ||
1365 | GNUNET_SCHEDULER_cancel (kx->retry_set_key_task); | ||
1366 | kx->retry_set_key_task = NULL; | ||
1367 | } | ||
1368 | /* always update sender status in SET KEY message */ | ||
1369 | #if DEBUG_KX | ||
1370 | { | ||
1371 | struct GNUNET_HashCode hc; | ||
1372 | |||
1373 | GNUNET_CRYPTO_hash (¤t_ekm.ephemeral_key, | ||
1374 | sizeof(current_ekm.ephemeral_key), | ||
1375 | &hc); | ||
1376 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1377 | "Sending EPHEMERAL_KEY %s to `%s' (my status: %d)\n", | ||
1378 | GNUNET_h2s (&hc), | ||
1379 | GNUNET_i2s (kx->peer), | ||
1380 | kx->status); | ||
1381 | } | ||
1382 | #endif | ||
1383 | current_ekm.sender_status = htonl ((int32_t) (kx->status)); | ||
1384 | env = GNUNET_MQ_msg_copy (¤t_ekm.header); | ||
1385 | GNUNET_MQ_send (kx->mq, env); | ||
1386 | if (GNUNET_CORE_KX_STATE_KEY_SENT != kx->status) | ||
1387 | send_ping (kx); | ||
1388 | kx->retry_set_key_task = | ||
1389 | GNUNET_SCHEDULER_add_delayed (kx->set_key_retry_frequency, | ||
1390 | &set_key_retry_task, | ||
1391 | kx); | ||
1392 | } | ||
1393 | |||
1394 | |||
1395 | /** | ||
1396 | * Encrypt and transmit a message with the given payload. | ||
1397 | * | ||
1398 | * @param kx key exchange context | ||
1399 | * @param payload payload of the message | ||
1400 | * @param payload_size number of bytes in @a payload | ||
1401 | */ | ||
1402 | void | ||
1403 | GSC_KX_encrypt_and_transmit (struct GSC_KeyExchangeInfo *kx, | ||
1404 | const void *payload, | ||
1405 | size_t payload_size) | ||
1406 | { | ||
1407 | size_t used = payload_size + sizeof(struct EncryptedMessage); | ||
1408 | char pbuf[used]; /* plaintext */ | ||
1409 | struct EncryptedMessage *em; /* encrypted message */ | ||
1410 | struct EncryptedMessage *ph; /* plaintext header */ | ||
1411 | struct GNUNET_MQ_Envelope *env; | ||
1412 | struct GNUNET_CRYPTO_SymmetricInitializationVector iv; | ||
1413 | struct GNUNET_CRYPTO_AuthKey auth_key; | ||
1414 | |||
1415 | ph = (struct EncryptedMessage *) pbuf; | ||
1416 | ph->sequence_number = htonl (++kx->last_sequence_number_sent); | ||
1417 | ph->iv_seed = calculate_seed (kx); | ||
1418 | ph->reserved = 0; | ||
1419 | ph->timestamp = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ()); | ||
1420 | GNUNET_memcpy (&ph[1], payload, payload_size); | ||
1421 | env = GNUNET_MQ_msg_extra (em, | ||
1422 | payload_size, | ||
1423 | GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE); | ||
1424 | em->iv_seed = ph->iv_seed; | ||
1425 | derive_iv (&iv, &kx->encrypt_key, ph->iv_seed, kx->peer); | ||
1426 | GNUNET_assert (GNUNET_OK == do_encrypt (kx, | ||
1427 | &iv, | ||
1428 | &ph->sequence_number, | ||
1429 | &em->sequence_number, | ||
1430 | used - ENCRYPTED_HEADER_SIZE)); | ||
1431 | #if DEBUG_KX | ||
1432 | { | ||
1433 | struct GNUNET_HashCode hc; | ||
1434 | |||
1435 | GNUNET_CRYPTO_hash (&ph->sequence_number, | ||
1436 | used - ENCRYPTED_HEADER_SIZE, | ||
1437 | &hc); | ||
1438 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1439 | "Encrypted payload `%s' of %u bytes for %s\n", | ||
1440 | GNUNET_h2s (&hc), | ||
1441 | (unsigned int) (used - ENCRYPTED_HEADER_SIZE), | ||
1442 | GNUNET_i2s (kx->peer)); | ||
1443 | } | ||
1444 | #endif | ||
1445 | derive_auth_key (&auth_key, &kx->encrypt_key, ph->iv_seed); | ||
1446 | GNUNET_CRYPTO_hmac (&auth_key, | ||
1447 | &em->sequence_number, | ||
1448 | used - ENCRYPTED_HEADER_SIZE, | ||
1449 | &em->hmac); | ||
1450 | #if DEBUG_KX | ||
1451 | { | ||
1452 | struct GNUNET_HashCode hc; | ||
1453 | |||
1454 | GNUNET_CRYPTO_hash (&auth_key, sizeof(auth_key), &hc); | ||
1455 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1456 | "For peer %s, used AC %s to create hmac %s\n", | ||
1457 | GNUNET_i2s (kx->peer), | ||
1458 | GNUNET_h2s (&hc), | ||
1459 | GNUNET_h2s2 (&em->hmac)); | ||
1460 | } | ||
1461 | #endif | ||
1462 | kx->has_excess_bandwidth = GNUNET_NO; | ||
1463 | GNUNET_MQ_send (kx->mq, env); | ||
1464 | } | ||
1465 | |||
1466 | |||
1467 | /** | ||
1468 | * We received an encrypted message. Check that it is | ||
1469 | * well-formed (size-wise). | ||
1470 | * | ||
1471 | * @param cls key exchange context for encrypting the message | ||
1472 | * @param m encrypted message | ||
1473 | * @return #GNUNET_OK if @a msg is well-formed (size-wise) | ||
1474 | */ | ||
1475 | static int | ||
1476 | check_encrypted (void *cls, const struct EncryptedMessage *m) | ||
1477 | { | ||
1478 | uint16_t size = ntohs (m->header.size) - sizeof(*m); | ||
1479 | |||
1480 | if (size < sizeof(struct GNUNET_MessageHeader)) | ||
1481 | { | ||
1482 | GNUNET_break_op (0); | ||
1483 | return GNUNET_SYSERR; | ||
1484 | } | ||
1485 | return GNUNET_OK; | ||
1486 | } | ||
1487 | |||
1488 | |||
1489 | /** | ||
1490 | * We received an encrypted message. Decrypt, validate and | ||
1491 | * pass on to the appropriate clients. | ||
1492 | * | ||
1493 | * @param cls key exchange context for encrypting the message | ||
1494 | * @param m encrypted message | ||
1495 | */ | ||
1496 | static void | ||
1497 | handle_encrypted (void *cls, const struct EncryptedMessage *m) | ||
1498 | { | ||
1499 | struct GSC_KeyExchangeInfo *kx = cls; | ||
1500 | struct EncryptedMessage *pt; /* plaintext */ | ||
1501 | struct GNUNET_HashCode ph; | ||
1502 | uint32_t snum; | ||
1503 | struct GNUNET_TIME_Absolute t; | ||
1504 | struct GNUNET_CRYPTO_SymmetricInitializationVector iv; | ||
1505 | struct GNUNET_CRYPTO_AuthKey auth_key; | ||
1506 | uint16_t size = ntohs (m->header.size); | ||
1507 | char buf[size] GNUNET_ALIGN; | ||
1508 | |||
1509 | if (GNUNET_CORE_KX_STATE_UP != kx->status) | ||
1510 | { | ||
1511 | GNUNET_STATISTICS_update (GSC_stats, | ||
1512 | gettext_noop ( | ||
1513 | "# DATA message dropped (out of order)"), | ||
1514 | 1, | ||
1515 | GNUNET_NO); | ||
1516 | return; | ||
1517 | } | ||
1518 | if (0 == | ||
1519 | GNUNET_TIME_absolute_get_remaining (kx->foreign_key_expires).rel_value_us) | ||
1520 | { | ||
1521 | GNUNET_log ( | ||
1522 | GNUNET_ERROR_TYPE_WARNING, | ||
1523 | _ ( | ||
1524 | "Session to peer `%s' went down due to key expiration (should not happen)\n"), | ||
1525 | GNUNET_i2s (kx->peer)); | ||
1526 | GNUNET_STATISTICS_update (GSC_stats, | ||
1527 | gettext_noop ( | ||
1528 | "# sessions terminated by key expiration"), | ||
1529 | 1, | ||
1530 | GNUNET_NO); | ||
1531 | GSC_SESSIONS_end (kx->peer); | ||
1532 | if (NULL != kx->keep_alive_task) | ||
1533 | { | ||
1534 | GNUNET_SCHEDULER_cancel (kx->keep_alive_task); | ||
1535 | kx->keep_alive_task = NULL; | ||
1536 | } | ||
1537 | kx->status = GNUNET_CORE_KX_STATE_KEY_SENT; | ||
1538 | monitor_notify_all (kx); | ||
1539 | send_key (kx); | ||
1540 | return; | ||
1541 | } | ||
1542 | |||
1543 | /* validate hash */ | ||
1544 | #if DEBUG_KX | ||
1545 | { | ||
1546 | struct GNUNET_HashCode hc; | ||
1547 | |||
1548 | GNUNET_CRYPTO_hash (&m->sequence_number, size - ENCRYPTED_HEADER_SIZE, &hc); | ||
1549 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1550 | "Received encrypted payload `%s' of %u bytes from %s\n", | ||
1551 | GNUNET_h2s (&hc), | ||
1552 | (unsigned int) (size - ENCRYPTED_HEADER_SIZE), | ||
1553 | GNUNET_i2s (kx->peer)); | ||
1554 | } | ||
1555 | #endif | ||
1556 | derive_auth_key (&auth_key, &kx->decrypt_key, m->iv_seed); | ||
1557 | GNUNET_CRYPTO_hmac (&auth_key, | ||
1558 | &m->sequence_number, | ||
1559 | size - ENCRYPTED_HEADER_SIZE, | ||
1560 | &ph); | ||
1561 | #if DEBUG_KX | ||
1562 | { | ||
1563 | struct GNUNET_HashCode hc; | ||
1564 | |||
1565 | GNUNET_CRYPTO_hash (&auth_key, sizeof(auth_key), &hc); | ||
1566 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1567 | "For peer %s, used AC %s to verify hmac %s\n", | ||
1568 | GNUNET_i2s (kx->peer), | ||
1569 | GNUNET_h2s (&hc), | ||
1570 | GNUNET_h2s2 (&m->hmac)); | ||
1571 | } | ||
1572 | #endif | ||
1573 | if (0 != memcmp (&ph, &m->hmac, sizeof(struct GNUNET_HashCode))) | ||
1574 | { | ||
1575 | /* checksum failed */ | ||
1576 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
1577 | "Failed checksum validation for a message from `%s'\n", | ||
1578 | GNUNET_i2s (kx->peer)); | ||
1579 | return; | ||
1580 | } | ||
1581 | derive_iv (&iv, &kx->decrypt_key, m->iv_seed, &GSC_my_identity); | ||
1582 | /* decrypt */ | ||
1583 | if (GNUNET_OK != do_decrypt (kx, | ||
1584 | &iv, | ||
1585 | &m->sequence_number, | ||
1586 | &buf[ENCRYPTED_HEADER_SIZE], | ||
1587 | size - ENCRYPTED_HEADER_SIZE)) | ||
1588 | { | ||
1589 | GNUNET_break_op (0); | ||
1590 | return; | ||
1591 | } | ||
1592 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1593 | "Decrypted %u bytes from %s\n", | ||
1594 | (unsigned int) (size - ENCRYPTED_HEADER_SIZE), | ||
1595 | GNUNET_i2s (kx->peer)); | ||
1596 | pt = (struct EncryptedMessage *) buf; | ||
1597 | |||
1598 | /* validate sequence number */ | ||
1599 | snum = ntohl (pt->sequence_number); | ||
1600 | if (kx->last_sequence_number_received == snum) | ||
1601 | { | ||
1602 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1603 | "Received duplicate message, ignoring.\n"); | ||
1604 | /* duplicate, ignore */ | ||
1605 | GNUNET_STATISTICS_update (GSC_stats, | ||
1606 | gettext_noop ("# bytes dropped (duplicates)"), | ||
1607 | size, | ||
1608 | GNUNET_NO); | ||
1609 | return; | ||
1610 | } | ||
1611 | if ((kx->last_sequence_number_received > snum) && | ||
1612 | (kx->last_sequence_number_received - snum > 32)) | ||
1613 | { | ||
1614 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1615 | "Received ancient out of sequence message, ignoring.\n"); | ||
1616 | /* ancient out of sequence, ignore */ | ||
1617 | GNUNET_STATISTICS_update (GSC_stats, | ||
1618 | gettext_noop ( | ||
1619 | "# bytes dropped (out of sequence)"), | ||
1620 | size, | ||
1621 | GNUNET_NO); | ||
1622 | return; | ||
1623 | } | ||
1624 | if (kx->last_sequence_number_received > snum) | ||
1625 | { | ||
1626 | uint32_t rotbit = 1U << (kx->last_sequence_number_received - snum - 1); | ||
1627 | |||
1628 | if ((kx->last_packets_bitmap & rotbit) != 0) | ||
1629 | { | ||
1630 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1631 | "Received duplicate message, ignoring.\n"); | ||
1632 | GNUNET_STATISTICS_update (GSC_stats, | ||
1633 | gettext_noop ("# bytes dropped (duplicates)"), | ||
1634 | size, | ||
1635 | GNUNET_NO); | ||
1636 | /* duplicate, ignore */ | ||
1637 | return; | ||
1638 | } | ||
1639 | kx->last_packets_bitmap |= rotbit; | ||
1640 | } | ||
1641 | if (kx->last_sequence_number_received < snum) | ||
1642 | { | ||
1643 | unsigned int shift = (snum - kx->last_sequence_number_received); | ||
1644 | |||
1645 | if (shift >= 8 * sizeof(kx->last_packets_bitmap)) | ||
1646 | kx->last_packets_bitmap = 0; | ||
1647 | else | ||
1648 | kx->last_packets_bitmap <<= shift; | ||
1649 | kx->last_sequence_number_received = snum; | ||
1650 | } | ||
1651 | |||
1652 | /* check timestamp */ | ||
1653 | t = GNUNET_TIME_absolute_ntoh (pt->timestamp); | ||
1654 | if (GNUNET_TIME_absolute_get_duration (t).rel_value_us > | ||
1655 | MAX_MESSAGE_AGE.rel_value_us) | ||
1656 | { | ||
1657 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1658 | "Message received far too old (%s). Content ignored.\n", | ||
1659 | GNUNET_STRINGS_relative_time_to_string ( | ||
1660 | GNUNET_TIME_absolute_get_duration (t), | ||
1661 | GNUNET_YES)); | ||
1662 | GNUNET_STATISTICS_update (GSC_stats, | ||
1663 | gettext_noop ( | ||
1664 | "# bytes dropped (ancient message)"), | ||
1665 | size, | ||
1666 | GNUNET_NO); | ||
1667 | return; | ||
1668 | } | ||
1669 | |||
1670 | /* process decrypted message(s) */ | ||
1671 | update_timeout (kx); | ||
1672 | GNUNET_STATISTICS_update (GSC_stats, | ||
1673 | gettext_noop ("# bytes of payload decrypted"), | ||
1674 | size - sizeof(struct EncryptedMessage), | ||
1675 | GNUNET_NO); | ||
1676 | if (GNUNET_OK != | ||
1677 | GNUNET_MST_from_buffer (kx->mst, | ||
1678 | &buf[sizeof(struct EncryptedMessage)], | ||
1679 | size - sizeof(struct EncryptedMessage), | ||
1680 | GNUNET_YES, | ||
1681 | GNUNET_NO)) | ||
1682 | GNUNET_break_op (0); | ||
1683 | } | ||
1684 | |||
1685 | |||
1686 | /** | ||
1687 | * One of our neighbours has excess bandwidth, remember this. | ||
1688 | * | ||
1689 | * @param cls NULL | ||
1690 | * @param pid identity of the peer with excess bandwidth | ||
1691 | * @param connect_cls the `struct Neighbour` | ||
1692 | */ | ||
1693 | static void | ||
1694 | handle_transport_notify_excess_bw (void *cls, | ||
1695 | const struct GNUNET_PeerIdentity *pid, | ||
1696 | void *connect_cls) | ||
1697 | { | ||
1698 | struct GSC_KeyExchangeInfo *kx = connect_cls; | ||
1699 | |||
1700 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1701 | "Peer %s has excess bandwidth available\n", | ||
1702 | GNUNET_i2s (pid)); | ||
1703 | kx->has_excess_bandwidth = GNUNET_YES; | ||
1704 | GSC_SESSIONS_solicit (pid); | ||
1705 | } | ||
1706 | |||
1707 | |||
1708 | /** | ||
1709 | * Setup the message that links the ephemeral key to our persistent | ||
1710 | * public key and generate the appropriate signature. | ||
1711 | */ | ||
1712 | static void | ||
1713 | sign_ephemeral_key () | ||
1714 | { | ||
1715 | current_ekm.header.size = htons (sizeof(struct EphemeralKeyMessage)); | ||
1716 | current_ekm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_EPHEMERAL_KEY); | ||
1717 | current_ekm.sender_status = 0; /* to be set later */ | ||
1718 | current_ekm.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_SET_ECC_KEY); | ||
1719 | current_ekm.purpose.size = | ||
1720 | htonl (sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose) | ||
1721 | + sizeof(struct GNUNET_TIME_AbsoluteNBO) | ||
1722 | + sizeof(struct GNUNET_TIME_AbsoluteNBO) | ||
1723 | + sizeof(struct GNUNET_CRYPTO_EcdhePublicKey) | ||
1724 | + sizeof(struct GNUNET_PeerIdentity)); | ||
1725 | current_ekm.creation_time = | ||
1726 | GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ()); | ||
1727 | if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (GSC_cfg, | ||
1728 | "core", | ||
1729 | "USE_EPHEMERAL_KEYS")) | ||
1730 | { | ||
1731 | current_ekm.expiration_time = | ||
1732 | GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute ( | ||
1733 | GNUNET_TIME_relative_add (REKEY_FREQUENCY, | ||
1734 | REKEY_TOLERANCE))); | ||
1735 | } | ||
1736 | else | ||
1737 | { | ||
1738 | current_ekm.expiration_time = | ||
1739 | GNUNET_TIME_absolute_hton (GNUNET_TIME_UNIT_FOREVER_ABS); | ||
1740 | } | ||
1741 | GNUNET_CRYPTO_ecdhe_key_get_public (&my_ephemeral_key, | ||
1742 | ¤t_ekm.ephemeral_key); | ||
1743 | current_ekm.origin_identity = GSC_my_identity; | ||
1744 | GNUNET_assert (GNUNET_OK == | ||
1745 | GNUNET_CRYPTO_eddsa_sign_ (&my_private_key, | ||
1746 | ¤t_ekm.purpose, | ||
1747 | ¤t_ekm.signature)); | ||
1748 | } | ||
1749 | |||
1750 | |||
1751 | /** | ||
1752 | * Task run to trigger rekeying. | ||
1753 | * | ||
1754 | * @param cls closure, NULL | ||
1755 | */ | ||
1756 | static void | ||
1757 | do_rekey (void *cls) | ||
1758 | { | ||
1759 | struct GSC_KeyExchangeInfo *pos; | ||
1760 | |||
1761 | rekey_task = GNUNET_SCHEDULER_add_delayed (REKEY_FREQUENCY, &do_rekey, NULL); | ||
1762 | GNUNET_CRYPTO_ecdhe_key_create (&my_ephemeral_key); | ||
1763 | sign_ephemeral_key (); | ||
1764 | { | ||
1765 | struct GNUNET_HashCode eh; | ||
1766 | |||
1767 | GNUNET_CRYPTO_hash (¤t_ekm.ephemeral_key, | ||
1768 | sizeof(current_ekm.ephemeral_key), | ||
1769 | &eh); | ||
1770 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Rekeying to %s\n", GNUNET_h2s (&eh)); | ||
1771 | } | ||
1772 | for (pos = kx_head; NULL != pos; pos = pos->next) | ||
1773 | { | ||
1774 | if (GNUNET_CORE_KX_STATE_UP == pos->status) | ||
1775 | { | ||
1776 | pos->status = GNUNET_CORE_KX_STATE_REKEY_SENT; | ||
1777 | monitor_notify_all (pos); | ||
1778 | derive_session_keys (pos); | ||
1779 | } | ||
1780 | if (GNUNET_CORE_KX_STATE_DOWN == pos->status) | ||
1781 | { | ||
1782 | pos->status = GNUNET_CORE_KX_STATE_KEY_SENT; | ||
1783 | monitor_notify_all (pos); | ||
1784 | } | ||
1785 | monitor_notify_all (pos); | ||
1786 | send_key (pos); | ||
1787 | } | ||
1788 | } | ||
1789 | |||
1790 | |||
1791 | /** | ||
1792 | * Initialize KX subsystem. | ||
1793 | * | ||
1794 | * @param pk private key to use for the peer | ||
1795 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure | ||
1796 | */ | ||
1797 | int | ||
1798 | GSC_KX_init (struct GNUNET_CRYPTO_EddsaPrivateKey *pk) | ||
1799 | { | ||
1800 | struct GNUNET_MQ_MessageHandler handlers[] = { | ||
1801 | GNUNET_MQ_hd_fixed_size (ephemeral_key, | ||
1802 | GNUNET_MESSAGE_TYPE_CORE_EPHEMERAL_KEY, | ||
1803 | struct EphemeralKeyMessage, | ||
1804 | NULL), | ||
1805 | GNUNET_MQ_hd_fixed_size (ping, | ||
1806 | GNUNET_MESSAGE_TYPE_CORE_PING, | ||
1807 | struct PingMessage, | ||
1808 | NULL), | ||
1809 | GNUNET_MQ_hd_fixed_size (pong, | ||
1810 | GNUNET_MESSAGE_TYPE_CORE_PONG, | ||
1811 | struct PongMessage, | ||
1812 | NULL), | ||
1813 | GNUNET_MQ_hd_var_size (encrypted, | ||
1814 | GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE, | ||
1815 | struct EncryptedMessage, | ||
1816 | NULL), | ||
1817 | GNUNET_MQ_handler_end () | ||
1818 | }; | ||
1819 | |||
1820 | my_private_key = *pk; | ||
1821 | GNUNET_CRYPTO_eddsa_key_get_public (&my_private_key, | ||
1822 | &GSC_my_identity.public_key); | ||
1823 | GNUNET_CRYPTO_ecdhe_key_create (&my_ephemeral_key); | ||
1824 | sign_ephemeral_key (); | ||
1825 | { | ||
1826 | struct GNUNET_HashCode eh; | ||
1827 | |||
1828 | GNUNET_CRYPTO_hash (¤t_ekm.ephemeral_key, | ||
1829 | sizeof(current_ekm.ephemeral_key), | ||
1830 | &eh); | ||
1831 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
1832 | "Starting with ephemeral key %s\n", | ||
1833 | GNUNET_h2s (&eh)); | ||
1834 | } | ||
1835 | |||
1836 | nc = GNUNET_notification_context_create (1); | ||
1837 | rekey_task = GNUNET_SCHEDULER_add_delayed (REKEY_FREQUENCY, &do_rekey, NULL); | ||
1838 | transport = | ||
1839 | GNUNET_TRANSPORT_core_connect (GSC_cfg, | ||
1840 | &GSC_my_identity, | ||
1841 | handlers, | ||
1842 | NULL, | ||
1843 | &handle_transport_notify_connect, | ||
1844 | &handle_transport_notify_disconnect, | ||
1845 | &handle_transport_notify_excess_bw); | ||
1846 | if (NULL == transport) | ||
1847 | { | ||
1848 | GSC_KX_done (); | ||
1849 | return GNUNET_SYSERR; | ||
1850 | } | ||
1851 | return GNUNET_OK; | ||
1852 | } | ||
1853 | |||
1854 | |||
1855 | /** | ||
1856 | * Shutdown KX subsystem. | ||
1857 | */ | ||
1858 | void | ||
1859 | GSC_KX_done () | ||
1860 | { | ||
1861 | if (NULL != transport) | ||
1862 | { | ||
1863 | GNUNET_TRANSPORT_core_disconnect (transport); | ||
1864 | transport = NULL; | ||
1865 | } | ||
1866 | if (NULL != rekey_task) | ||
1867 | { | ||
1868 | GNUNET_SCHEDULER_cancel (rekey_task); | ||
1869 | rekey_task = NULL; | ||
1870 | } | ||
1871 | memset (&my_ephemeral_key, | ||
1872 | 0, | ||
1873 | sizeof (my_ephemeral_key)); | ||
1874 | memset (&my_private_key, | ||
1875 | 0, | ||
1876 | sizeof (my_private_key)); | ||
1877 | if (NULL != nc) | ||
1878 | { | ||
1879 | GNUNET_notification_context_destroy (nc); | ||
1880 | nc = NULL; | ||
1881 | } | ||
1882 | } | ||
1883 | |||
1884 | |||
1885 | /** | ||
1886 | * Check how many messages are queued for the given neighbour. | ||
1887 | * | ||
1888 | * @param kxinfo data about neighbour to check | ||
1889 | * @return number of items in the message queue | ||
1890 | */ | ||
1891 | unsigned int | ||
1892 | GSC_NEIGHBOURS_get_queue_length (const struct GSC_KeyExchangeInfo *kxinfo) | ||
1893 | { | ||
1894 | return GNUNET_MQ_get_length (kxinfo->mq); | ||
1895 | } | ||
1896 | |||
1897 | |||
1898 | /** | ||
1899 | * Check if the given neighbour has excess bandwidth available. | ||
1900 | * | ||
1901 | * @param target neighbour to check | ||
1902 | * @return #GNUNET_YES if excess bandwidth is available, #GNUNET_NO if not | ||
1903 | */ | ||
1904 | int | ||
1905 | GSC_NEIGHBOURS_check_excess_bandwidth (const struct GSC_KeyExchangeInfo *kxinfo) | ||
1906 | { | ||
1907 | return kxinfo->has_excess_bandwidth; | ||
1908 | } | ||
1909 | |||
1910 | |||
1911 | /** | ||
1912 | * Handle #GNUNET_MESSAGE_TYPE_CORE_MONITOR_PEERS request. For this | ||
1913 | * request type, the client does not have to have transmitted an INIT | ||
1914 | * request. All current peers are returned, regardless of which | ||
1915 | * message types they accept. | ||
1916 | * | ||
1917 | * @param mq message queue to add for monitoring | ||
1918 | */ | ||
1919 | void | ||
1920 | GSC_KX_handle_client_monitor_peers (struct GNUNET_MQ_Handle *mq) | ||
1921 | { | ||
1922 | struct GNUNET_MQ_Envelope *env; | ||
1923 | struct MonitorNotifyMessage *done_msg; | ||
1924 | struct GSC_KeyExchangeInfo *kx; | ||
1925 | |||
1926 | GNUNET_notification_context_add (nc, mq); | ||
1927 | for (kx = kx_head; NULL != kx; kx = kx->next) | ||
1928 | { | ||
1929 | struct GNUNET_MQ_Envelope *env; | ||
1930 | struct MonitorNotifyMessage *msg; | ||
1931 | |||
1932 | env = GNUNET_MQ_msg (msg, GNUNET_MESSAGE_TYPE_CORE_MONITOR_NOTIFY); | ||
1933 | msg->state = htonl ((uint32_t) kx->status); | ||
1934 | msg->peer = *kx->peer; | ||
1935 | msg->timeout = GNUNET_TIME_absolute_hton (kx->timeout); | ||
1936 | GNUNET_MQ_send (mq, env); | ||
1937 | } | ||
1938 | env = GNUNET_MQ_msg (done_msg, GNUNET_MESSAGE_TYPE_CORE_MONITOR_NOTIFY); | ||
1939 | done_msg->state = htonl ((uint32_t) GNUNET_CORE_KX_ITERATION_FINISHED); | ||
1940 | done_msg->timeout = GNUNET_TIME_absolute_hton (GNUNET_TIME_UNIT_FOREVER_ABS); | ||
1941 | GNUNET_MQ_send (mq, env); | ||
1942 | } | ||
1943 | |||
1944 | |||
1945 | /* end of gnunet-service-core_kx.c */ | ||
diff --git a/src/core/gnunet-service-core_kx.h b/src/core/gnunet-service-core_kx.h deleted file mode 100644 index 77f3e43b6..000000000 --- a/src/core/gnunet-service-core_kx.h +++ /dev/null | |||
@@ -1,103 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009, 2010, 2011 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file core/gnunet-service-core_kx.h | ||
23 | * @brief code for managing the key exchange (SET_KEY, PING, PONG) with other peers | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #ifndef GNUNET_SERVICE_CORE_KX_H | ||
27 | #define GNUNET_SERVICE_CORE_KX_H | ||
28 | |||
29 | #include "gnunet_util_lib.h" | ||
30 | #include "gnunet_transport_service.h" | ||
31 | |||
32 | |||
33 | /** | ||
34 | * Information about the status of a key exchange with another peer. | ||
35 | */ | ||
36 | struct GSC_KeyExchangeInfo; | ||
37 | |||
38 | |||
39 | /** | ||
40 | * Encrypt and transmit a message with the given payload. | ||
41 | * | ||
42 | * @param kx key exchange context | ||
43 | * @param payload payload of the message | ||
44 | * @param payload_size number of bytes in 'payload' | ||
45 | */ | ||
46 | void | ||
47 | GSC_KX_encrypt_and_transmit (struct GSC_KeyExchangeInfo *kx, | ||
48 | const void *payload, | ||
49 | size_t payload_size); | ||
50 | |||
51 | |||
52 | /** | ||
53 | * Initialize KX subsystem. | ||
54 | * | ||
55 | * @param pk private key to use for the peer | ||
56 | * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure | ||
57 | */ | ||
58 | int | ||
59 | GSC_KX_init (struct GNUNET_CRYPTO_EddsaPrivateKey *pk); | ||
60 | |||
61 | |||
62 | /** | ||
63 | * Shutdown KX subsystem. | ||
64 | */ | ||
65 | void | ||
66 | GSC_KX_done (void); | ||
67 | |||
68 | |||
69 | /** | ||
70 | * Check if the given neighbour has excess bandwidth available. | ||
71 | * | ||
72 | * @param target neighbour to check | ||
73 | * @return #GNUNET_YES if excess bandwidth is available, #GNUNET_NO if not | ||
74 | */ | ||
75 | int | ||
76 | GSC_NEIGHBOURS_check_excess_bandwidth (const struct | ||
77 | GSC_KeyExchangeInfo *target); | ||
78 | |||
79 | |||
80 | /** | ||
81 | * Check how many messages are queued for the given neighbour. | ||
82 | * | ||
83 | * @param target neighbour to check | ||
84 | * @return number of items in the message queue | ||
85 | */ | ||
86 | unsigned int | ||
87 | GSC_NEIGHBOURS_get_queue_length (const struct GSC_KeyExchangeInfo *target); | ||
88 | |||
89 | |||
90 | /** | ||
91 | * Handle #GNUNET_MESSAGE_TYPE_CORE_MONITOR_PEERS request. For this | ||
92 | * request type, the client does not have to have transmitted an INIT | ||
93 | * request. All current peers are returned, regardless of which | ||
94 | * message types they accept. | ||
95 | * | ||
96 | * @param mq message queue to add for monitoring | ||
97 | */ | ||
98 | void | ||
99 | GSC_KX_handle_client_monitor_peers (struct GNUNET_MQ_Handle *mq); | ||
100 | |||
101 | |||
102 | #endif | ||
103 | /* end of gnunet-service-core_kx.h */ | ||
diff --git a/src/core/gnunet-service-core_sessions.c b/src/core/gnunet-service-core_sessions.c deleted file mode 100644 index d40b3bfad..000000000 --- a/src/core/gnunet-service-core_sessions.c +++ /dev/null | |||
@@ -1,1043 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009-2014, 2016 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file core/gnunet-service-core_sessions.c | ||
23 | * @brief code for managing of 'encrypted' sessions (key exchange done) | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet-service-core.h" | ||
28 | #include "gnunet-service-core_kx.h" | ||
29 | #include "gnunet-service-core_typemap.h" | ||
30 | #include "gnunet-service-core_sessions.h" | ||
31 | #include "gnunet_constants.h" | ||
32 | #include "core.h" | ||
33 | |||
34 | |||
35 | /** | ||
36 | * How many encrypted messages do we queue at most? | ||
37 | * Needed to bound memory consumption. | ||
38 | */ | ||
39 | #define MAX_ENCRYPTED_MESSAGE_QUEUE_SIZE 4 | ||
40 | |||
41 | |||
42 | /** | ||
43 | * Message ready for encryption. This struct is followed by the | ||
44 | * actual content of the message. | ||
45 | */ | ||
46 | struct SessionMessageEntry | ||
47 | { | ||
48 | /** | ||
49 | * We keep messages in a doubly linked list. | ||
50 | */ | ||
51 | struct SessionMessageEntry *next; | ||
52 | |||
53 | /** | ||
54 | * We keep messages in a doubly linked list. | ||
55 | */ | ||
56 | struct SessionMessageEntry *prev; | ||
57 | |||
58 | /** | ||
59 | * How important is this message. | ||
60 | */ | ||
61 | enum GNUNET_MQ_PriorityPreferences priority; | ||
62 | |||
63 | /** | ||
64 | * Flag set to #GNUNET_YES if this is a typemap message. | ||
65 | */ | ||
66 | int is_typemap; | ||
67 | |||
68 | /** | ||
69 | * Flag set to #GNUNET_YES if this is a typemap confirmation message. | ||
70 | */ | ||
71 | int is_typemap_confirm; | ||
72 | |||
73 | /** | ||
74 | * Deadline for transmission, 1s after we received it (if we | ||
75 | * are not corking), otherwise "now". Note that this message | ||
76 | * does NOT expire past its deadline. | ||
77 | */ | ||
78 | struct GNUNET_TIME_Absolute deadline; | ||
79 | |||
80 | /** | ||
81 | * How long is the message? (number of bytes following the `struct | ||
82 | * MessageEntry`, but not including the size of `struct | ||
83 | * MessageEntry` itself!) | ||
84 | */ | ||
85 | size_t size; | ||
86 | }; | ||
87 | |||
88 | |||
89 | /** | ||
90 | * Data kept per session. | ||
91 | */ | ||
92 | struct Session | ||
93 | { | ||
94 | /** | ||
95 | * Identity of the other peer. | ||
96 | */ | ||
97 | const struct GNUNET_PeerIdentity *peer; | ||
98 | |||
99 | /** | ||
100 | * Key exchange state for this peer. | ||
101 | */ | ||
102 | struct GSC_KeyExchangeInfo *kx; | ||
103 | |||
104 | /** | ||
105 | * Head of list of requests from clients for transmission to | ||
106 | * this peer. | ||
107 | */ | ||
108 | struct GSC_ClientActiveRequest *active_client_request_head; | ||
109 | |||
110 | /** | ||
111 | * Tail of list of requests from clients for transmission to | ||
112 | * this peer. | ||
113 | */ | ||
114 | struct GSC_ClientActiveRequest *active_client_request_tail; | ||
115 | |||
116 | /** | ||
117 | * Head of list of messages ready for encryption. | ||
118 | */ | ||
119 | struct SessionMessageEntry *sme_head; | ||
120 | |||
121 | /** | ||
122 | * Tail of list of messages ready for encryption. | ||
123 | */ | ||
124 | struct SessionMessageEntry *sme_tail; | ||
125 | |||
126 | /** | ||
127 | * Current type map for this peer. | ||
128 | */ | ||
129 | struct GSC_TypeMap *tmap; | ||
130 | |||
131 | /** | ||
132 | * Task to transmit corked messages with a delay. | ||
133 | */ | ||
134 | struct GNUNET_SCHEDULER_Task *cork_task; | ||
135 | |||
136 | /** | ||
137 | * Task to transmit our type map. | ||
138 | */ | ||
139 | struct GNUNET_SCHEDULER_Task *typemap_task; | ||
140 | |||
141 | /** | ||
142 | * Retransmission delay we currently use for the typemap | ||
143 | * transmissions (if not confirmed). | ||
144 | */ | ||
145 | struct GNUNET_TIME_Relative typemap_delay; | ||
146 | |||
147 | /** | ||
148 | * Is this the first time we're sending the typemap? If so, | ||
149 | * we want to send it a bit faster the second time. 0 if | ||
150 | * we are sending for the first time, 1 if not. | ||
151 | */ | ||
152 | int first_typemap; | ||
153 | }; | ||
154 | |||
155 | |||
156 | GNUNET_NETWORK_STRUCT_BEGIN | ||
157 | |||
158 | /** | ||
159 | * Message sent to confirm that a typemap was received. | ||
160 | */ | ||
161 | struct TypeMapConfirmationMessage | ||
162 | { | ||
163 | /** | ||
164 | * Header with type #GNUNET_MESSAGE_TYPE_CORE_CONFIRM_TYPE_MAP. | ||
165 | */ | ||
166 | struct GNUNET_MessageHeader header; | ||
167 | |||
168 | /** | ||
169 | * Reserved, always zero. | ||
170 | */ | ||
171 | uint32_t reserved GNUNET_PACKED; | ||
172 | |||
173 | /** | ||
174 | * Hash of the (decompressed) type map that was received. | ||
175 | */ | ||
176 | struct GNUNET_HashCode tm_hash; | ||
177 | }; | ||
178 | |||
179 | GNUNET_NETWORK_STRUCT_END | ||
180 | |||
181 | |||
182 | /** | ||
183 | * Map of peer identities to `struct Session`. | ||
184 | */ | ||
185 | static struct GNUNET_CONTAINER_MultiPeerMap *sessions; | ||
186 | |||
187 | |||
188 | /** | ||
189 | * Find the session for the given peer. | ||
190 | * | ||
191 | * @param peer identity of the peer | ||
192 | * @return NULL if we are not connected, otherwise the | ||
193 | * session handle | ||
194 | */ | ||
195 | static struct Session * | ||
196 | find_session (const struct GNUNET_PeerIdentity *peer) | ||
197 | { | ||
198 | if (NULL == sessions) | ||
199 | return NULL; | ||
200 | return GNUNET_CONTAINER_multipeermap_get (sessions, peer); | ||
201 | } | ||
202 | |||
203 | |||
204 | /** | ||
205 | * End the session with the given peer (we are no longer | ||
206 | * connected). | ||
207 | * | ||
208 | * @param pid identity of peer to kill session with | ||
209 | */ | ||
210 | void | ||
211 | GSC_SESSIONS_end (const struct GNUNET_PeerIdentity *pid) | ||
212 | { | ||
213 | struct Session *session; | ||
214 | struct GSC_ClientActiveRequest *car; | ||
215 | struct SessionMessageEntry *sme; | ||
216 | |||
217 | session = find_session (pid); | ||
218 | if (NULL == session) | ||
219 | return; | ||
220 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
221 | "Destroying session for peer `%s'\n", | ||
222 | GNUNET_i2s (session->peer)); | ||
223 | if (NULL != session->cork_task) | ||
224 | { | ||
225 | GNUNET_SCHEDULER_cancel (session->cork_task); | ||
226 | session->cork_task = NULL; | ||
227 | } | ||
228 | while (NULL != (car = session->active_client_request_head)) | ||
229 | { | ||
230 | GNUNET_CONTAINER_DLL_remove (session->active_client_request_head, | ||
231 | session->active_client_request_tail, | ||
232 | car); | ||
233 | GSC_CLIENTS_reject_request (car, GNUNET_NO); | ||
234 | } | ||
235 | while (NULL != (sme = session->sme_head)) | ||
236 | { | ||
237 | GNUNET_CONTAINER_DLL_remove (session->sme_head, session->sme_tail, sme); | ||
238 | GNUNET_free (sme); | ||
239 | } | ||
240 | if (NULL != session->typemap_task) | ||
241 | { | ||
242 | GNUNET_SCHEDULER_cancel (session->typemap_task); | ||
243 | session->typemap_task = NULL; | ||
244 | } | ||
245 | GSC_CLIENTS_notify_clients_about_neighbour (session->peer, | ||
246 | session->tmap, | ||
247 | NULL); | ||
248 | GNUNET_assert ( | ||
249 | GNUNET_YES == | ||
250 | GNUNET_CONTAINER_multipeermap_remove (sessions, session->peer, session)); | ||
251 | GNUNET_STATISTICS_set (GSC_stats, | ||
252 | gettext_noop ("# peers connected"), | ||
253 | GNUNET_CONTAINER_multipeermap_size (sessions), | ||
254 | GNUNET_NO); | ||
255 | GSC_TYPEMAP_destroy (session->tmap); | ||
256 | session->tmap = NULL; | ||
257 | GNUNET_free (session); | ||
258 | } | ||
259 | |||
260 | |||
261 | /** | ||
262 | * Transmit our current typemap message to the other peer. | ||
263 | * (Done periodically until the typemap is confirmed). | ||
264 | * | ||
265 | * @param cls the `struct Session *` | ||
266 | */ | ||
267 | static void | ||
268 | transmit_typemap_task (void *cls) | ||
269 | { | ||
270 | struct Session *session = cls; | ||
271 | struct GNUNET_MessageHeader *hdr; | ||
272 | struct GNUNET_TIME_Relative delay; | ||
273 | |||
274 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
275 | "Sending TYPEMAP to %s\n", | ||
276 | GNUNET_i2s (session->peer)); | ||
277 | session->typemap_delay = GNUNET_TIME_STD_BACKOFF (session->typemap_delay); | ||
278 | delay = session->typemap_delay; | ||
279 | /* randomize a bit to avoid spont. sync */ | ||
280 | delay.rel_value_us += | ||
281 | GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000 * 1000); | ||
282 | session->typemap_task = | ||
283 | GNUNET_SCHEDULER_add_delayed (delay, &transmit_typemap_task, session); | ||
284 | GNUNET_STATISTICS_update (GSC_stats, | ||
285 | gettext_noop ("# type map refreshes sent"), | ||
286 | 1, | ||
287 | GNUNET_NO); | ||
288 | hdr = GSC_TYPEMAP_compute_type_map_message (); | ||
289 | GSC_KX_encrypt_and_transmit (session->kx, hdr, ntohs (hdr->size)); | ||
290 | GNUNET_free (hdr); | ||
291 | } | ||
292 | |||
293 | |||
294 | /** | ||
295 | * Restart the typemap task for the given session. | ||
296 | * | ||
297 | * @param session session to restart typemap transmission for | ||
298 | */ | ||
299 | static void | ||
300 | start_typemap_task (struct Session *session) | ||
301 | { | ||
302 | if (NULL != session->typemap_task) | ||
303 | GNUNET_SCHEDULER_cancel (session->typemap_task); | ||
304 | session->typemap_delay = GNUNET_TIME_UNIT_SECONDS; | ||
305 | session->typemap_task = GNUNET_SCHEDULER_add_delayed (session->typemap_delay, | ||
306 | &transmit_typemap_task, | ||
307 | session); | ||
308 | } | ||
309 | |||
310 | |||
311 | /** | ||
312 | * Create a session, a key exchange was just completed. | ||
313 | * | ||
314 | * @param peer peer that is now connected | ||
315 | * @param kx key exchange that completed | ||
316 | */ | ||
317 | void | ||
318 | GSC_SESSIONS_create (const struct GNUNET_PeerIdentity *peer, | ||
319 | struct GSC_KeyExchangeInfo *kx) | ||
320 | { | ||
321 | struct Session *session; | ||
322 | |||
323 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
324 | "Creating session for peer `%s'\n", | ||
325 | GNUNET_i2s (peer)); | ||
326 | session = GNUNET_new (struct Session); | ||
327 | session->tmap = GSC_TYPEMAP_create (); | ||
328 | session->peer = peer; | ||
329 | session->kx = kx; | ||
330 | GNUNET_assert (GNUNET_OK == | ||
331 | GNUNET_CONTAINER_multipeermap_put ( | ||
332 | sessions, | ||
333 | session->peer, | ||
334 | session, | ||
335 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY)); | ||
336 | GNUNET_STATISTICS_set (GSC_stats, | ||
337 | gettext_noop ("# peers connected"), | ||
338 | GNUNET_CONTAINER_multipeermap_size (sessions), | ||
339 | GNUNET_NO); | ||
340 | GSC_CLIENTS_notify_clients_about_neighbour (peer, NULL, session->tmap); | ||
341 | start_typemap_task (session); | ||
342 | } | ||
343 | |||
344 | |||
345 | /** | ||
346 | * The other peer has indicated that it 'lost' the session | ||
347 | * (KX down), reinitialize the session on our end, in particular | ||
348 | * this means to restart the typemap transmission. | ||
349 | * | ||
350 | * @param peer peer that is now connected | ||
351 | */ | ||
352 | void | ||
353 | GSC_SESSIONS_reinit (const struct GNUNET_PeerIdentity *peer) | ||
354 | { | ||
355 | struct Session *session; | ||
356 | |||
357 | session = find_session (peer); | ||
358 | if (NULL == session) | ||
359 | { | ||
360 | /* KX/session is new for both sides; thus no need to restart what | ||
361 | has not yet begun */ | ||
362 | return; | ||
363 | } | ||
364 | start_typemap_task (session); | ||
365 | } | ||
366 | |||
367 | |||
368 | /** | ||
369 | * The other peer has confirmed receiving our type map, | ||
370 | * check if it is current and if so, stop retransmitting it. | ||
371 | * | ||
372 | * @param peer peer that confirmed the type map | ||
373 | * @param msg confirmation message we received | ||
374 | */ | ||
375 | void | ||
376 | GSC_SESSIONS_confirm_typemap (const struct GNUNET_PeerIdentity *peer, | ||
377 | const struct GNUNET_MessageHeader *msg) | ||
378 | { | ||
379 | const struct TypeMapConfirmationMessage *cmsg; | ||
380 | struct Session *session; | ||
381 | |||
382 | session = find_session (peer); | ||
383 | if (NULL == session) | ||
384 | { | ||
385 | GNUNET_break (0); | ||
386 | return; | ||
387 | } | ||
388 | if (ntohs (msg->size) != sizeof(struct TypeMapConfirmationMessage)) | ||
389 | { | ||
390 | GNUNET_break_op (0); | ||
391 | return; | ||
392 | } | ||
393 | cmsg = (const struct TypeMapConfirmationMessage *) msg; | ||
394 | if (GNUNET_YES != GSC_TYPEMAP_check_hash (&cmsg->tm_hash)) | ||
395 | { | ||
396 | /* our typemap has changed in the meantime, do not | ||
397 | accept confirmation */ | ||
398 | GNUNET_STATISTICS_update (GSC_stats, | ||
399 | gettext_noop ( | ||
400 | "# outdated typemap confirmations received"), | ||
401 | 1, | ||
402 | GNUNET_NO); | ||
403 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
404 | "Got outdated typemap confirmated from peer `%s'\n", | ||
405 | GNUNET_i2s (session->peer)); | ||
406 | return; | ||
407 | } | ||
408 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
409 | "Got typemap confirmation from peer `%s'\n", | ||
410 | GNUNET_i2s (session->peer)); | ||
411 | if (NULL != session->typemap_task) | ||
412 | { | ||
413 | GNUNET_SCHEDULER_cancel (session->typemap_task); | ||
414 | session->typemap_task = NULL; | ||
415 | } | ||
416 | GNUNET_STATISTICS_update (GSC_stats, | ||
417 | gettext_noop ( | ||
418 | "# valid typemap confirmations received"), | ||
419 | 1, | ||
420 | GNUNET_NO); | ||
421 | } | ||
422 | |||
423 | |||
424 | /** | ||
425 | * Notify the given client about the session (client is new). | ||
426 | * | ||
427 | * @param cls the `struct GSC_Client` | ||
428 | * @param key peer identity | ||
429 | * @param value the `struct Session` | ||
430 | * @return #GNUNET_OK (continue to iterate) | ||
431 | */ | ||
432 | static int | ||
433 | notify_client_about_session (void *cls, | ||
434 | const struct GNUNET_PeerIdentity *key, | ||
435 | void *value) | ||
436 | { | ||
437 | struct GSC_Client *client = cls; | ||
438 | struct Session *session = value; | ||
439 | |||
440 | GSC_CLIENTS_notify_client_about_neighbour (client, | ||
441 | session->peer, | ||
442 | NULL, /* old TMAP: none */ | ||
443 | session->tmap); | ||
444 | return GNUNET_OK; | ||
445 | } | ||
446 | |||
447 | |||
448 | /** | ||
449 | * We have a new client, notify it about all current sessions. | ||
450 | * | ||
451 | * @param client the new client | ||
452 | */ | ||
453 | void | ||
454 | GSC_SESSIONS_notify_client_about_sessions (struct GSC_Client *client) | ||
455 | { | ||
456 | /* notify new client about existing sessions */ | ||
457 | GNUNET_CONTAINER_multipeermap_iterate (sessions, | ||
458 | ¬ify_client_about_session, | ||
459 | client); | ||
460 | } | ||
461 | |||
462 | |||
463 | /** | ||
464 | * Try to perform a transmission on the given session. Will solicit | ||
465 | * additional messages if the 'sme' queue is not full enough. | ||
466 | * | ||
467 | * @param session session to transmit messages from | ||
468 | */ | ||
469 | static void | ||
470 | try_transmission (struct Session *session); | ||
471 | |||
472 | |||
473 | /** | ||
474 | * Queue a request from a client for transmission to a particular peer. | ||
475 | * | ||
476 | * @param car request to queue; this handle is then shared between | ||
477 | * the caller (CLIENTS subsystem) and SESSIONS and must not | ||
478 | * be released by either until either #GSC_SESSIONS_dequeue(), | ||
479 | * #GSC_SESSIONS_transmit() or #GSC_CLIENTS_failed() | ||
480 | * have been invoked on it | ||
481 | */ | ||
482 | void | ||
483 | GSC_SESSIONS_queue_request (struct GSC_ClientActiveRequest *car) | ||
484 | { | ||
485 | struct Session *session; | ||
486 | |||
487 | session = find_session (&car->target); | ||
488 | if (NULL == session) | ||
489 | { | ||
490 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
491 | "Dropped client request for transmission (am disconnected)\n"); | ||
492 | GNUNET_break (0); /* should have been rejected earlier */ | ||
493 | GSC_CLIENTS_reject_request (car, GNUNET_NO); | ||
494 | return; | ||
495 | } | ||
496 | if (car->msize > GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE) | ||
497 | { | ||
498 | GNUNET_break (0); | ||
499 | GSC_CLIENTS_reject_request (car, GNUNET_YES); | ||
500 | return; | ||
501 | } | ||
502 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
503 | "Received client transmission request. queueing\n"); | ||
504 | GNUNET_CONTAINER_DLL_insert_tail (session->active_client_request_head, | ||
505 | session->active_client_request_tail, | ||
506 | car); | ||
507 | try_transmission (session); | ||
508 | } | ||
509 | |||
510 | |||
511 | /** | ||
512 | * Dequeue a request from a client from transmission to a particular peer. | ||
513 | * | ||
514 | * @param car request to dequeue; this handle will then be 'owned' by | ||
515 | * the caller (CLIENTS sysbsystem) | ||
516 | */ | ||
517 | void | ||
518 | GSC_SESSIONS_dequeue_request (struct GSC_ClientActiveRequest *car) | ||
519 | { | ||
520 | struct Session *session; | ||
521 | |||
522 | if (0 == memcmp (&car->target, | ||
523 | &GSC_my_identity, | ||
524 | sizeof(struct GNUNET_PeerIdentity))) | ||
525 | return; | ||
526 | session = find_session (&car->target); | ||
527 | GNUNET_assert (NULL != session); | ||
528 | GNUNET_CONTAINER_DLL_remove (session->active_client_request_head, | ||
529 | session->active_client_request_tail, | ||
530 | car); | ||
531 | /* dequeueing of 'high' priority messages may unblock | ||
532 | transmission for lower-priority messages, so we also | ||
533 | need to try in this case. */ | ||
534 | try_transmission (session); | ||
535 | } | ||
536 | |||
537 | |||
538 | /** | ||
539 | * Solicit messages for transmission, starting with those of the highest | ||
540 | * priority. | ||
541 | * | ||
542 | * @param session session to solict messages for | ||
543 | * @param msize how many bytes do we have already | ||
544 | */ | ||
545 | static void | ||
546 | solicit_messages (struct Session *session, size_t msize) | ||
547 | { | ||
548 | struct GSC_ClientActiveRequest *car; | ||
549 | struct GSC_ClientActiveRequest *nxt; | ||
550 | size_t so_size; | ||
551 | enum GNUNET_MQ_PriorityPreferences pmax; | ||
552 | |||
553 | so_size = msize; | ||
554 | pmax = GNUNET_MQ_PRIO_BACKGROUND; | ||
555 | for (car = session->active_client_request_head; NULL != car; car = car->next) | ||
556 | { | ||
557 | if (GNUNET_YES == car->was_solicited) | ||
558 | continue; | ||
559 | pmax = GNUNET_MAX (pmax, car->priority & GNUNET_MQ_PRIORITY_MASK); | ||
560 | } | ||
561 | nxt = session->active_client_request_head; | ||
562 | while (NULL != (car = nxt)) | ||
563 | { | ||
564 | nxt = car->next; | ||
565 | if (car->priority < pmax) | ||
566 | continue; | ||
567 | if (so_size + car->msize > GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE) | ||
568 | break; | ||
569 | so_size += car->msize; | ||
570 | if (GNUNET_YES == car->was_solicited) | ||
571 | continue; | ||
572 | car->was_solicited = GNUNET_YES; | ||
573 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
574 | "Soliciting message with priority %u\n", | ||
575 | car->priority); | ||
576 | GSC_CLIENTS_solicit_request (car); | ||
577 | /* The above call may *dequeue* requests and thereby | ||
578 | clobber 'nxt'. Hence we need to restart from the | ||
579 | head of the list. */ | ||
580 | nxt = session->active_client_request_head; | ||
581 | so_size = msize; | ||
582 | } | ||
583 | } | ||
584 | |||
585 | |||
586 | /** | ||
587 | * Some messages were delayed (corked), but the timeout has now expired. | ||
588 | * Send them now. | ||
589 | * | ||
590 | * @param cls `struct Session` with the messages to transmit now | ||
591 | */ | ||
592 | static void | ||
593 | pop_cork_task (void *cls) | ||
594 | { | ||
595 | struct Session *session = cls; | ||
596 | |||
597 | session->cork_task = NULL; | ||
598 | try_transmission (session); | ||
599 | } | ||
600 | |||
601 | |||
602 | /** | ||
603 | * Try to perform a transmission on the given session. Will solicit | ||
604 | * additional messages if the 'sme' queue is not full enough or has | ||
605 | * only low-priority messages. | ||
606 | * | ||
607 | * @param session session to transmit messages from | ||
608 | */ | ||
609 | static void | ||
610 | try_transmission (struct Session *session) | ||
611 | { | ||
612 | struct SessionMessageEntry *pos; | ||
613 | size_t msize; | ||
614 | struct GNUNET_TIME_Absolute now; | ||
615 | struct GNUNET_TIME_Absolute min_deadline; | ||
616 | enum GNUNET_MQ_PriorityPreferences maxp; | ||
617 | enum GNUNET_MQ_PriorityPreferences maxpc; | ||
618 | struct GSC_ClientActiveRequest *car; | ||
619 | int excess; | ||
620 | |||
621 | msize = 0; | ||
622 | min_deadline = GNUNET_TIME_UNIT_FOREVER_ABS; | ||
623 | /* if the peer has excess bandwidth, background traffic is allowed, | ||
624 | otherwise not */ | ||
625 | if (MAX_ENCRYPTED_MESSAGE_QUEUE_SIZE <= | ||
626 | GSC_NEIGHBOURS_get_queue_length (session->kx)) | ||
627 | { | ||
628 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
629 | "Transmission queue already very long, waiting...\n"); | ||
630 | return; /* queue already too long */ | ||
631 | } | ||
632 | excess = GSC_NEIGHBOURS_check_excess_bandwidth (session->kx); | ||
633 | if (GNUNET_YES == excess) | ||
634 | maxp = GNUNET_MQ_PRIO_BACKGROUND; | ||
635 | else | ||
636 | maxp = GNUNET_MQ_PRIO_BEST_EFFORT; | ||
637 | /* determine highest priority of 'ready' messages we already solicited from clients */ | ||
638 | pos = session->sme_head; | ||
639 | while ((NULL != pos) && | ||
640 | (msize + pos->size <= GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE)) | ||
641 | { | ||
642 | GNUNET_assert (pos->size < GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE); | ||
643 | msize += pos->size; | ||
644 | maxp = GNUNET_MAX (maxp, pos->priority & GNUNET_MQ_PRIORITY_MASK); | ||
645 | min_deadline = GNUNET_TIME_absolute_min (min_deadline, pos->deadline); | ||
646 | pos = pos->next; | ||
647 | } | ||
648 | GNUNET_log ( | ||
649 | GNUNET_ERROR_TYPE_DEBUG, | ||
650 | "Calculating transmission set with %u priority (%s) and %s earliest deadline\n", | ||
651 | maxp, | ||
652 | (GNUNET_YES == excess) ? "excess bandwidth" : "limited bandwidth", | ||
653 | GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_remaining ( | ||
654 | min_deadline), | ||
655 | GNUNET_YES)); | ||
656 | |||
657 | if (maxp < GNUNET_MQ_PRIO_CRITICAL_CONTROL) | ||
658 | { | ||
659 | /* if highest already solicited priority from clients is not critical, | ||
660 | check if there are higher-priority messages to be solicited from clients */ | ||
661 | if (GNUNET_YES == excess) | ||
662 | maxpc = GNUNET_MQ_PRIO_BACKGROUND; | ||
663 | else | ||
664 | maxpc = GNUNET_MQ_PRIO_BEST_EFFORT; | ||
665 | for (car = session->active_client_request_head; NULL != car; | ||
666 | car = car->next) | ||
667 | { | ||
668 | if (GNUNET_YES == car->was_solicited) | ||
669 | continue; | ||
670 | maxpc = GNUNET_MAX (maxpc, car->priority & GNUNET_MQ_PRIORITY_MASK); | ||
671 | } | ||
672 | if (maxpc > maxp) | ||
673 | { | ||
674 | /* we have messages waiting for solicitation that have a higher | ||
675 | priority than those that we already accepted; solicit the | ||
676 | high-priority messages first */ | ||
677 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
678 | "Soliciting messages based on priority (%u > %u)\n", | ||
679 | maxpc, | ||
680 | maxp); | ||
681 | solicit_messages (session, 0); | ||
682 | return; | ||
683 | } | ||
684 | } | ||
685 | else | ||
686 | { | ||
687 | /* never solicit more, we have critical messages to process */ | ||
688 | excess = GNUNET_NO; | ||
689 | maxpc = GNUNET_MQ_PRIO_BACKGROUND; | ||
690 | } | ||
691 | now = GNUNET_TIME_absolute_get (); | ||
692 | if (((GNUNET_YES == excess) || (maxpc >= GNUNET_MQ_PRIO_BEST_EFFORT)) && | ||
693 | ((0 == msize) || | ||
694 | ((msize < GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE / 2) && | ||
695 | (min_deadline.abs_value_us > now.abs_value_us)))) | ||
696 | { | ||
697 | /* not enough ready yet (tiny message & cork possible), or no messages at all, | ||
698 | and either excess bandwidth or best-effort or higher message waiting at | ||
699 | client; in this case, we try to solicit more */ | ||
700 | GNUNET_log ( | ||
701 | GNUNET_ERROR_TYPE_DEBUG, | ||
702 | "Soliciting messages (excess %d, maxpc %d, message size %u, deadline %s)\n", | ||
703 | excess, | ||
704 | maxpc, | ||
705 | (unsigned int) msize, | ||
706 | GNUNET_STRINGS_relative_time_to_string ( | ||
707 | GNUNET_TIME_absolute_get_remaining ( | ||
708 | min_deadline), | ||
709 | GNUNET_YES)); | ||
710 | solicit_messages (session, msize); | ||
711 | if (msize > 0) | ||
712 | { | ||
713 | /* if there is data to send, just not yet, make sure we do transmit | ||
714 | * it once the deadline is reached */ | ||
715 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
716 | "Corking until %s\n", | ||
717 | GNUNET_STRINGS_relative_time_to_string ( | ||
718 | GNUNET_TIME_absolute_get_remaining (min_deadline), | ||
719 | GNUNET_YES)); | ||
720 | if (NULL != session->cork_task) | ||
721 | GNUNET_SCHEDULER_cancel (session->cork_task); | ||
722 | session->cork_task = | ||
723 | GNUNET_SCHEDULER_add_at (min_deadline, &pop_cork_task, session); | ||
724 | } | ||
725 | else | ||
726 | { | ||
727 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
728 | "Queue empty, waiting for solicitations\n"); | ||
729 | } | ||
730 | return; | ||
731 | } | ||
732 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
733 | "Building combined plaintext buffer to transmit message!\n"); | ||
734 | /* create plaintext buffer of all messages (that fit), encrypt and | ||
735 | transmit */ | ||
736 | { | ||
737 | static unsigned long long total_bytes; | ||
738 | static unsigned int total_msgs; | ||
739 | char pbuf[msize]; /* plaintext */ | ||
740 | size_t used; | ||
741 | |||
742 | used = 0; | ||
743 | while ((NULL != (pos = session->sme_head)) && (used + pos->size <= msize)) | ||
744 | { | ||
745 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
746 | "Adding message of type %d (%d/%d) to payload for %s\n", | ||
747 | ntohs (((const struct GNUNET_MessageHeader *) &pos[1])->type), | ||
748 | pos->is_typemap, | ||
749 | pos->is_typemap_confirm, | ||
750 | GNUNET_i2s (session->peer)); | ||
751 | GNUNET_memcpy (&pbuf[used], &pos[1], pos->size); | ||
752 | used += pos->size; | ||
753 | GNUNET_CONTAINER_DLL_remove (session->sme_head, session->sme_tail, pos); | ||
754 | GNUNET_free (pos); | ||
755 | } | ||
756 | /* compute average payload size */ | ||
757 | total_bytes += used; | ||
758 | total_msgs++; | ||
759 | if (0 == total_msgs) | ||
760 | { | ||
761 | /* 2^32 messages, wrap around... */ | ||
762 | total_msgs = 1; | ||
763 | total_bytes = used; | ||
764 | } | ||
765 | GNUNET_STATISTICS_set (GSC_stats, | ||
766 | "# avg payload per encrypted message", | ||
767 | total_bytes / total_msgs, | ||
768 | GNUNET_NO); | ||
769 | /* now actually transmit... */ | ||
770 | GSC_KX_encrypt_and_transmit (session->kx, pbuf, used); | ||
771 | } | ||
772 | } | ||
773 | |||
774 | |||
775 | /** | ||
776 | * Send an updated typemap message to the neighbour now, | ||
777 | * and restart typemap transmissions. | ||
778 | * | ||
779 | * @param cls the message | ||
780 | * @param key neighbour's identity | ||
781 | * @param value `struct Neighbour` of the target | ||
782 | * @return always #GNUNET_OK | ||
783 | */ | ||
784 | static int | ||
785 | do_restart_typemap_message (void *cls, | ||
786 | const struct GNUNET_PeerIdentity *key, | ||
787 | void *value) | ||
788 | { | ||
789 | const struct GNUNET_MessageHeader *hdr = cls; | ||
790 | struct Session *session = value; | ||
791 | struct SessionMessageEntry *sme; | ||
792 | uint16_t size; | ||
793 | |||
794 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
795 | "Restarting sending TYPEMAP to %s\n", | ||
796 | GNUNET_i2s (session->peer)); | ||
797 | size = ntohs (hdr->size); | ||
798 | for (sme = session->sme_head; NULL != sme; sme = sme->next) | ||
799 | { | ||
800 | if (GNUNET_YES == sme->is_typemap) | ||
801 | { | ||
802 | GNUNET_CONTAINER_DLL_remove (session->sme_head, session->sme_tail, sme); | ||
803 | GNUNET_free (sme); | ||
804 | break; | ||
805 | } | ||
806 | } | ||
807 | sme = GNUNET_malloc (sizeof(struct SessionMessageEntry) + size); | ||
808 | sme->is_typemap = GNUNET_YES; | ||
809 | GNUNET_memcpy (&sme[1], hdr, size); | ||
810 | sme->size = size; | ||
811 | sme->priority = GNUNET_MQ_PRIO_CRITICAL_CONTROL; | ||
812 | GNUNET_CONTAINER_DLL_insert (session->sme_head, session->sme_tail, sme); | ||
813 | try_transmission (session); | ||
814 | start_typemap_task (session); | ||
815 | return GNUNET_OK; | ||
816 | } | ||
817 | |||
818 | |||
819 | /** | ||
820 | * Broadcast an updated typemap message to all neighbours. | ||
821 | * Restarts the retransmissions until the typemaps are confirmed. | ||
822 | * | ||
823 | * @param msg message to transmit | ||
824 | */ | ||
825 | void | ||
826 | GSC_SESSIONS_broadcast_typemap (const struct GNUNET_MessageHeader *msg) | ||
827 | { | ||
828 | if (NULL == sessions) | ||
829 | return; | ||
830 | GNUNET_CONTAINER_multipeermap_iterate (sessions, | ||
831 | &do_restart_typemap_message, | ||
832 | (void *) msg); | ||
833 | } | ||
834 | |||
835 | |||
836 | /** | ||
837 | * Traffic is being solicited for the given peer. This means that the | ||
838 | * message queue on the transport-level (NEIGHBOURS subsystem) is now | ||
839 | * empty and it is now OK to transmit another (non-control) message. | ||
840 | * | ||
841 | * @param pid identity of peer ready to receive data | ||
842 | */ | ||
843 | void | ||
844 | GSC_SESSIONS_solicit (const struct GNUNET_PeerIdentity *pid) | ||
845 | { | ||
846 | struct Session *session; | ||
847 | |||
848 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
849 | "Transport solicits for %s\n", | ||
850 | GNUNET_i2s (pid)); | ||
851 | session = find_session (pid); | ||
852 | if (NULL == session) | ||
853 | return; | ||
854 | try_transmission (session); | ||
855 | } | ||
856 | |||
857 | |||
858 | /** | ||
859 | * Transmit a message to a particular peer. | ||
860 | * | ||
861 | * @param car original request that was queued and then solicited; | ||
862 | * this handle will now be 'owned' by the SESSIONS subsystem | ||
863 | * @param msg message to transmit | ||
864 | * @param priority how important is this message | ||
865 | */ | ||
866 | void | ||
867 | GSC_SESSIONS_transmit (struct GSC_ClientActiveRequest *car, | ||
868 | const struct GNUNET_MessageHeader *msg, | ||
869 | enum GNUNET_MQ_PriorityPreferences priority) | ||
870 | { | ||
871 | struct Session *session; | ||
872 | struct SessionMessageEntry *sme; | ||
873 | struct SessionMessageEntry *pos; | ||
874 | size_t msize; | ||
875 | |||
876 | session = find_session (&car->target); | ||
877 | if (NULL == session) | ||
878 | return; | ||
879 | msize = ntohs (msg->size); | ||
880 | sme = GNUNET_malloc (sizeof(struct SessionMessageEntry) + msize); | ||
881 | GNUNET_memcpy (&sme[1], msg, msize); | ||
882 | sme->size = msize; | ||
883 | sme->priority = priority; | ||
884 | if (0 != (GNUNET_MQ_PREF_CORK_ALLOWED & priority)) | ||
885 | { | ||
886 | sme->deadline = | ||
887 | GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_MAX_CORK_DELAY); | ||
888 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
889 | "Message corked, delaying transmission\n"); | ||
890 | } | ||
891 | pos = session->sme_head; | ||
892 | while ((NULL != pos) && (pos->priority >= sme->priority)) | ||
893 | pos = pos->next; | ||
894 | if (NULL == pos) | ||
895 | GNUNET_CONTAINER_DLL_insert_tail (session->sme_head, | ||
896 | session->sme_tail, | ||
897 | sme); | ||
898 | else | ||
899 | GNUNET_CONTAINER_DLL_insert_after (session->sme_head, | ||
900 | session->sme_tail, | ||
901 | pos->prev, | ||
902 | sme); | ||
903 | try_transmission (session); | ||
904 | } | ||
905 | |||
906 | |||
907 | /** | ||
908 | * We have received a typemap message from a peer, update ours. | ||
909 | * Notifies clients about the session. | ||
910 | * | ||
911 | * @param peer peer this is about | ||
912 | * @param msg typemap update message | ||
913 | */ | ||
914 | void | ||
915 | GSC_SESSIONS_set_typemap (const struct GNUNET_PeerIdentity *peer, | ||
916 | const struct GNUNET_MessageHeader *msg) | ||
917 | { | ||
918 | struct Session *session; | ||
919 | struct GSC_TypeMap *nmap; | ||
920 | struct SessionMessageEntry *sme; | ||
921 | struct TypeMapConfirmationMessage *tmc; | ||
922 | |||
923 | nmap = GSC_TYPEMAP_get_from_message (msg); | ||
924 | if (NULL == nmap) | ||
925 | { | ||
926 | GNUNET_break_op (0); | ||
927 | return; /* malformed */ | ||
928 | } | ||
929 | session = find_session (peer); | ||
930 | if (NULL == session) | ||
931 | { | ||
932 | GSC_TYPEMAP_destroy (nmap); | ||
933 | GNUNET_break (0); | ||
934 | return; | ||
935 | } | ||
936 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
937 | "Received TYPEMAP from %s\n", | ||
938 | GNUNET_i2s (session->peer)); | ||
939 | for (sme = session->sme_head; NULL != sme; sme = sme->next) | ||
940 | { | ||
941 | if (GNUNET_YES == sme->is_typemap_confirm) | ||
942 | { | ||
943 | GNUNET_CONTAINER_DLL_remove (session->sme_head, session->sme_tail, sme); | ||
944 | GNUNET_free (sme); | ||
945 | break; | ||
946 | } | ||
947 | } | ||
948 | sme = GNUNET_malloc (sizeof(struct SessionMessageEntry) | ||
949 | + sizeof(struct TypeMapConfirmationMessage)); | ||
950 | sme->deadline = GNUNET_TIME_absolute_get (); | ||
951 | sme->size = sizeof(struct TypeMapConfirmationMessage); | ||
952 | sme->priority = GNUNET_MQ_PRIO_CRITICAL_CONTROL; | ||
953 | sme->is_typemap_confirm = GNUNET_YES; | ||
954 | tmc = (struct TypeMapConfirmationMessage *) &sme[1]; | ||
955 | tmc->header.size = htons (sizeof(struct TypeMapConfirmationMessage)); | ||
956 | tmc->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_CONFIRM_TYPE_MAP); | ||
957 | tmc->reserved = htonl (0); | ||
958 | GSC_TYPEMAP_hash (nmap, &tmc->tm_hash); | ||
959 | GNUNET_CONTAINER_DLL_insert (session->sme_head, session->sme_tail, sme); | ||
960 | try_transmission (session); | ||
961 | GSC_CLIENTS_notify_clients_about_neighbour (peer, session->tmap, nmap); | ||
962 | GSC_TYPEMAP_destroy (session->tmap); | ||
963 | session->tmap = nmap; | ||
964 | } | ||
965 | |||
966 | |||
967 | /** | ||
968 | * The given peer send a message of the specified type. Make sure the | ||
969 | * respective bit is set in its type-map and that clients are notified | ||
970 | * about the session. | ||
971 | * | ||
972 | * @param peer peer this is about | ||
973 | * @param type type of the message | ||
974 | */ | ||
975 | void | ||
976 | GSC_SESSIONS_add_to_typemap (const struct GNUNET_PeerIdentity *peer, | ||
977 | uint16_t type) | ||
978 | { | ||
979 | struct Session *session; | ||
980 | struct GSC_TypeMap *nmap; | ||
981 | |||
982 | if (0 == memcmp (peer, &GSC_my_identity, sizeof(struct GNUNET_PeerIdentity))) | ||
983 | return; | ||
984 | session = find_session (peer); | ||
985 | GNUNET_assert (NULL != session); | ||
986 | if (GNUNET_YES == GSC_TYPEMAP_test_match (session->tmap, &type, 1)) | ||
987 | return; /* already in it */ | ||
988 | nmap = GSC_TYPEMAP_extend (session->tmap, &type, 1); | ||
989 | GSC_CLIENTS_notify_clients_about_neighbour (peer, session->tmap, nmap); | ||
990 | GSC_TYPEMAP_destroy (session->tmap); | ||
991 | session->tmap = nmap; | ||
992 | } | ||
993 | |||
994 | |||
995 | /** | ||
996 | * Initialize sessions subsystem. | ||
997 | */ | ||
998 | void | ||
999 | GSC_SESSIONS_init () | ||
1000 | { | ||
1001 | sessions = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_YES); | ||
1002 | } | ||
1003 | |||
1004 | |||
1005 | /** | ||
1006 | * Helper function for #GSC_SESSIONS_done() to free all | ||
1007 | * active sessions. | ||
1008 | * | ||
1009 | * @param cls NULL | ||
1010 | * @param key identity of the connected peer | ||
1011 | * @param value the `struct Session` for the peer | ||
1012 | * @return #GNUNET_OK (continue to iterate) | ||
1013 | */ | ||
1014 | static int | ||
1015 | free_session_helper (void *cls, | ||
1016 | const struct GNUNET_PeerIdentity *key, | ||
1017 | void *value) | ||
1018 | { | ||
1019 | /* struct Session *session = value; */ | ||
1020 | |||
1021 | GSC_SESSIONS_end (key); | ||
1022 | return GNUNET_OK; | ||
1023 | } | ||
1024 | |||
1025 | |||
1026 | /** | ||
1027 | * Shutdown sessions subsystem. | ||
1028 | */ | ||
1029 | void | ||
1030 | GSC_SESSIONS_done () | ||
1031 | { | ||
1032 | if (NULL != sessions) | ||
1033 | { | ||
1034 | GNUNET_CONTAINER_multipeermap_iterate (sessions, | ||
1035 | &free_session_helper, | ||
1036 | NULL); | ||
1037 | GNUNET_CONTAINER_multipeermap_destroy (sessions); | ||
1038 | sessions = NULL; | ||
1039 | } | ||
1040 | } | ||
1041 | |||
1042 | |||
1043 | /* end of gnunet-service-core_sessions.c */ | ||
diff --git a/src/core/gnunet-service-core_sessions.h b/src/core/gnunet-service-core_sessions.h deleted file mode 100644 index fda2cc32c..000000000 --- a/src/core/gnunet-service-core_sessions.h +++ /dev/null | |||
@@ -1,183 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009-2014 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file core/gnunet-service-core_neighbours.h | ||
23 | * @brief code for managing of 'encrypted' sessions (key exchange done) | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #ifndef GNUNET_SERVICE_CORE_SESSIONS_H | ||
27 | #define GNUNET_SERVICE_CORE_SESSIONS_H | ||
28 | |||
29 | #include "gnunet-service-core.h" | ||
30 | #include "gnunet-service-core_kx.h" | ||
31 | |||
32 | |||
33 | /** | ||
34 | * Create a session, a key exchange was just completed. | ||
35 | * | ||
36 | * @param peer peer that is now connected | ||
37 | * @param kx key exchange that completed | ||
38 | */ | ||
39 | void | ||
40 | GSC_SESSIONS_create (const struct GNUNET_PeerIdentity *peer, | ||
41 | struct GSC_KeyExchangeInfo *kx); | ||
42 | |||
43 | |||
44 | /** | ||
45 | * The other peer has indicated that it 'lost' the session | ||
46 | * (KX down), reinitialize the session on our end, in particular | ||
47 | * this means to restart the typemap transmission. | ||
48 | * | ||
49 | * @param peer peer that is now connected | ||
50 | */ | ||
51 | void | ||
52 | GSC_SESSIONS_reinit (const struct GNUNET_PeerIdentity *peer); | ||
53 | |||
54 | |||
55 | /** | ||
56 | * The other peer has confirmed receiving our type map, | ||
57 | * check if it is current and if so, stop retransmitting it. | ||
58 | * | ||
59 | * @param peer peer that confirmed the type map | ||
60 | * @param msg confirmation message we received | ||
61 | */ | ||
62 | void | ||
63 | GSC_SESSIONS_confirm_typemap (const struct GNUNET_PeerIdentity *peer, | ||
64 | const struct GNUNET_MessageHeader *msg); | ||
65 | |||
66 | |||
67 | /** | ||
68 | * End the session with the given peer (we are no longer | ||
69 | * connected). | ||
70 | * | ||
71 | * @param pid identity of peer to kill session with | ||
72 | */ | ||
73 | void | ||
74 | GSC_SESSIONS_end (const struct GNUNET_PeerIdentity *pid); | ||
75 | |||
76 | |||
77 | /** | ||
78 | * Traffic is being solicited for the given peer. This means that the | ||
79 | * message queue on the transport-level (NEIGHBOURS subsystem) is now | ||
80 | * empty and it is now OK to transmit another (non-control) message. | ||
81 | * | ||
82 | * @param pid identity of peer ready to receive data | ||
83 | */ | ||
84 | void | ||
85 | GSC_SESSIONS_solicit (const struct GNUNET_PeerIdentity *pid); | ||
86 | |||
87 | |||
88 | /** | ||
89 | * Queue a request from a client for transmission to a particular peer. | ||
90 | * | ||
91 | * @param car request to queue; this handle is then shared between | ||
92 | * the caller (CLIENTS subsystem) and SESSIONS and must not | ||
93 | * be released by either until either 'GNUNET_SESSIONS_dequeue', | ||
94 | * or 'GNUNET_CLIENTS_failed' | ||
95 | * have been invoked on it | ||
96 | */ | ||
97 | void | ||
98 | GSC_SESSIONS_queue_request (struct GSC_ClientActiveRequest *car); | ||
99 | |||
100 | |||
101 | /** | ||
102 | * Dequeue a request from a client from transmission to a particular peer. | ||
103 | * | ||
104 | * @param car request to dequeue; this handle will then be 'owned' by | ||
105 | * the caller (CLIENTS sysbsystem) | ||
106 | */ | ||
107 | void | ||
108 | GSC_SESSIONS_dequeue_request (struct GSC_ClientActiveRequest *car); | ||
109 | |||
110 | |||
111 | /** | ||
112 | * Transmit a message to a particular peer. | ||
113 | * | ||
114 | * @param car original request that was queued and then solicited, | ||
115 | * ownership does not change (dequeue will be called soon). | ||
116 | * @param msg message to transmit | ||
117 | * @param priority how important is this message | ||
118 | */ | ||
119 | void | ||
120 | GSC_SESSIONS_transmit (struct GSC_ClientActiveRequest *car, | ||
121 | const struct GNUNET_MessageHeader *msg, | ||
122 | enum GNUNET_MQ_PriorityPreferences priority); | ||
123 | |||
124 | |||
125 | /** | ||
126 | * Broadcast an updated typemap message to all neighbours. | ||
127 | * Restarts the retransmissions until the typemaps are confirmed. | ||
128 | * | ||
129 | * @param msg message to transmit | ||
130 | */ | ||
131 | void | ||
132 | GSC_SESSIONS_broadcast_typemap (const struct GNUNET_MessageHeader *msg); | ||
133 | |||
134 | |||
135 | /** | ||
136 | * We have a new client, notify it about all current sessions. | ||
137 | * | ||
138 | * @param client the new client | ||
139 | */ | ||
140 | void | ||
141 | GSC_SESSIONS_notify_client_about_sessions (struct GSC_Client *client); | ||
142 | |||
143 | |||
144 | /** | ||
145 | * We've received a typemap message from a peer, update ours. | ||
146 | * Notifies clients about the session. | ||
147 | * | ||
148 | * @param peer peer this is about | ||
149 | * @param msg typemap update message | ||
150 | */ | ||
151 | void | ||
152 | GSC_SESSIONS_set_typemap (const struct GNUNET_PeerIdentity *peer, | ||
153 | const struct GNUNET_MessageHeader *msg); | ||
154 | |||
155 | |||
156 | /** | ||
157 | * The given peer send a message of the specified type. Make sure the | ||
158 | * respective bit is set in its type-map and that clients are notified | ||
159 | * about the session. | ||
160 | * | ||
161 | * @param peer peer this is about | ||
162 | * @param type type of the message | ||
163 | */ | ||
164 | void | ||
165 | GSC_SESSIONS_add_to_typemap (const struct GNUNET_PeerIdentity *peer, | ||
166 | uint16_t type); | ||
167 | |||
168 | |||
169 | /** | ||
170 | * Initialize sessions subsystem. | ||
171 | */ | ||
172 | void | ||
173 | GSC_SESSIONS_init (void); | ||
174 | |||
175 | |||
176 | /** | ||
177 | * Shutdown sessions subsystem. | ||
178 | */ | ||
179 | void | ||
180 | GSC_SESSIONS_done (void); | ||
181 | |||
182 | |||
183 | #endif | ||
diff --git a/src/core/gnunet-service-core_typemap.c b/src/core/gnunet-service-core_typemap.c deleted file mode 100644 index 47235501c..000000000 --- a/src/core/gnunet-service-core_typemap.c +++ /dev/null | |||
@@ -1,377 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2011-2014 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file core/gnunet-service-core_typemap.c | ||
23 | * @brief management of map that specifies which message types this peer supports | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet_util_lib.h" | ||
28 | #include "gnunet_transport_service.h" | ||
29 | #include "gnunet-service-core.h" | ||
30 | #include "gnunet-service-core_sessions.h" | ||
31 | #include "gnunet-service-core_typemap.h" | ||
32 | #include <zlib.h> | ||
33 | |||
34 | |||
35 | /** | ||
36 | * A type map describing which messages a given neighbour is able | ||
37 | * to process. | ||
38 | */ | ||
39 | struct GSC_TypeMap | ||
40 | { | ||
41 | uint32_t bits[(UINT16_MAX + 1) / 32]; | ||
42 | }; | ||
43 | |||
44 | /** | ||
45 | * Bitmap of message types this peer is able to handle. | ||
46 | */ | ||
47 | static struct GSC_TypeMap my_type_map; | ||
48 | |||
49 | /** | ||
50 | * Counters for message types this peer is able to handle. | ||
51 | */ | ||
52 | static uint8_t map_counters[UINT16_MAX + 1]; | ||
53 | |||
54 | /** | ||
55 | * Current hash of our (uncompressed) type map. | ||
56 | * Lazily computed when needed. | ||
57 | */ | ||
58 | static struct GNUNET_HashCode my_tm_hash; | ||
59 | |||
60 | /** | ||
61 | * Is #my_tm_hash() current with respect to our type map? | ||
62 | */ | ||
63 | static int hash_current; | ||
64 | |||
65 | |||
66 | /** | ||
67 | * Our type map changed, recompute its hash. | ||
68 | */ | ||
69 | static void | ||
70 | rehash_typemap () | ||
71 | { | ||
72 | hash_current = GNUNET_NO; | ||
73 | } | ||
74 | |||
75 | |||
76 | /** | ||
77 | * Hash the contents of a type map. | ||
78 | * | ||
79 | * @param tm map to hash | ||
80 | * @param hc where to store the hash code | ||
81 | */ | ||
82 | void | ||
83 | GSC_TYPEMAP_hash (const struct GSC_TypeMap *tm, struct GNUNET_HashCode *hc) | ||
84 | { | ||
85 | GNUNET_CRYPTO_hash (tm, sizeof(struct GSC_TypeMap), hc); | ||
86 | } | ||
87 | |||
88 | |||
89 | /** | ||
90 | * Check if the given hash matches our current type map. | ||
91 | * | ||
92 | * @param hc hash code to check if it matches our type map | ||
93 | * @return #GNUNET_YES if the hash matches, #GNUNET_NO if not | ||
94 | */ | ||
95 | int | ||
96 | GSC_TYPEMAP_check_hash (const struct GNUNET_HashCode *hc) | ||
97 | { | ||
98 | if (GNUNET_NO == hash_current) | ||
99 | { | ||
100 | GSC_TYPEMAP_hash (&my_type_map, &my_tm_hash); | ||
101 | hash_current = GNUNET_YES; | ||
102 | } | ||
103 | return (0 == memcmp (hc, &my_tm_hash, sizeof(struct GNUNET_HashCode))) | ||
104 | ? GNUNET_YES | ||
105 | : GNUNET_NO; | ||
106 | } | ||
107 | |||
108 | |||
109 | /** | ||
110 | * Compute a type map message for this peer. | ||
111 | * | ||
112 | * @return this peers current type map message. | ||
113 | */ | ||
114 | struct GNUNET_MessageHeader * | ||
115 | GSC_TYPEMAP_compute_type_map_message () | ||
116 | { | ||
117 | char *tmp; | ||
118 | uLongf dlen; | ||
119 | struct GNUNET_MessageHeader *hdr; | ||
120 | |||
121 | #ifdef compressBound | ||
122 | dlen = compressBound (sizeof(my_type_map)); | ||
123 | #else | ||
124 | dlen = sizeof(my_type_map) + (sizeof(my_type_map) / 100) + 20; | ||
125 | /* documentation says 100.1% oldSize + 12 bytes, but we | ||
126 | * should be able to overshoot by more to be safe */ | ||
127 | #endif | ||
128 | hdr = GNUNET_malloc (dlen + sizeof(struct GNUNET_MessageHeader)); | ||
129 | tmp = (char *) &hdr[1]; | ||
130 | if ((Z_OK != compress2 ((Bytef *) tmp, | ||
131 | &dlen, | ||
132 | (const Bytef *) &my_type_map, | ||
133 | sizeof(my_type_map), | ||
134 | 9)) || | ||
135 | (dlen >= sizeof(my_type_map))) | ||
136 | { | ||
137 | /* compression failed, use uncompressed map */ | ||
138 | dlen = sizeof(my_type_map); | ||
139 | GNUNET_memcpy (tmp, &my_type_map, sizeof(my_type_map)); | ||
140 | hdr->type = htons (GNUNET_MESSAGE_TYPE_CORE_BINARY_TYPE_MAP); | ||
141 | } | ||
142 | else | ||
143 | { | ||
144 | /* compression worked, use compressed map */ | ||
145 | hdr->type = htons (GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP); | ||
146 | } | ||
147 | hdr->size = htons ((uint16_t) dlen + sizeof(struct GNUNET_MessageHeader)); | ||
148 | return hdr; | ||
149 | } | ||
150 | |||
151 | |||
152 | /** | ||
153 | * Extract a type map from a TYPE_MAP message. | ||
154 | * | ||
155 | * @param msg a type map message | ||
156 | * @return NULL on error | ||
157 | */ | ||
158 | struct GSC_TypeMap * | ||
159 | GSC_TYPEMAP_get_from_message (const struct GNUNET_MessageHeader *msg) | ||
160 | { | ||
161 | struct GSC_TypeMap *ret; | ||
162 | uint16_t size; | ||
163 | uLongf dlen; | ||
164 | |||
165 | size = ntohs (msg->size); | ||
166 | switch (ntohs (msg->type)) | ||
167 | { | ||
168 | case GNUNET_MESSAGE_TYPE_CORE_BINARY_TYPE_MAP: | ||
169 | GNUNET_STATISTICS_update (GSC_stats, | ||
170 | gettext_noop ("# type maps received"), | ||
171 | 1, | ||
172 | GNUNET_NO); | ||
173 | if (size != sizeof(struct GSC_TypeMap)) | ||
174 | { | ||
175 | GNUNET_break_op (0); | ||
176 | return NULL; | ||
177 | } | ||
178 | ret = GNUNET_new (struct GSC_TypeMap); | ||
179 | GNUNET_memcpy (ret, &msg[1], sizeof(struct GSC_TypeMap)); | ||
180 | return ret; | ||
181 | |||
182 | case GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP: | ||
183 | GNUNET_STATISTICS_update (GSC_stats, | ||
184 | gettext_noop ("# type maps received"), | ||
185 | 1, | ||
186 | GNUNET_NO); | ||
187 | ret = GNUNET_new (struct GSC_TypeMap); | ||
188 | dlen = sizeof(struct GSC_TypeMap); | ||
189 | if ((Z_OK != uncompress ((Bytef *) ret, | ||
190 | &dlen, | ||
191 | (const Bytef *) &msg[1], | ||
192 | (uLong) size)) || | ||
193 | (dlen != sizeof(struct GSC_TypeMap))) | ||
194 | { | ||
195 | GNUNET_break_op (0); | ||
196 | GNUNET_free (ret); | ||
197 | return NULL; | ||
198 | } | ||
199 | return ret; | ||
200 | |||
201 | default: | ||
202 | GNUNET_break (0); | ||
203 | return NULL; | ||
204 | } | ||
205 | } | ||
206 | |||
207 | |||
208 | /** | ||
209 | * Send my type map to all connected peers (it got changed). | ||
210 | */ | ||
211 | static void | ||
212 | broadcast_my_type_map () | ||
213 | { | ||
214 | struct GNUNET_MessageHeader *hdr; | ||
215 | |||
216 | hdr = GSC_TYPEMAP_compute_type_map_message (); | ||
217 | GNUNET_STATISTICS_update (GSC_stats, | ||
218 | gettext_noop ("# updates to my type map"), | ||
219 | 1, | ||
220 | GNUNET_NO); | ||
221 | GSC_SESSIONS_broadcast_typemap (hdr); | ||
222 | GNUNET_free (hdr); | ||
223 | } | ||
224 | |||
225 | |||
226 | /** | ||
227 | * Add a set of types to our type map. | ||
228 | * | ||
229 | * @param types array of message types supported by this peer | ||
230 | * @param tlen number of entries in @a types | ||
231 | */ | ||
232 | void | ||
233 | GSC_TYPEMAP_add (const uint16_t *types, unsigned int tlen) | ||
234 | { | ||
235 | unsigned int i; | ||
236 | int changed; | ||
237 | |||
238 | changed = GNUNET_NO; | ||
239 | for (i = 0; i < tlen; i++) | ||
240 | { | ||
241 | if (0 == map_counters[types[i]]++) | ||
242 | { | ||
243 | my_type_map.bits[types[i] / 32] |= (1 << (types[i] % 32)); | ||
244 | changed = GNUNET_YES; | ||
245 | } | ||
246 | } | ||
247 | if (GNUNET_YES == changed) | ||
248 | { | ||
249 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Typemap changed, broadcasting!\n"); | ||
250 | rehash_typemap (); | ||
251 | broadcast_my_type_map (); | ||
252 | } | ||
253 | } | ||
254 | |||
255 | |||
256 | /** | ||
257 | * Remove a set of types from our type map. | ||
258 | * | ||
259 | * @param types array of types to remove | ||
260 | * @param tlen length of the @a types array | ||
261 | */ | ||
262 | void | ||
263 | GSC_TYPEMAP_remove (const uint16_t *types, unsigned int tlen) | ||
264 | { | ||
265 | int changed; | ||
266 | |||
267 | changed = GNUNET_NO; | ||
268 | for (unsigned int i = 0; i < tlen; i++) | ||
269 | { | ||
270 | if (0 == --map_counters[types[i]]) | ||
271 | { | ||
272 | my_type_map.bits[types[i] / 32] &= ~(1 << (types[i] % 32)); | ||
273 | changed = GNUNET_YES; | ||
274 | } | ||
275 | } | ||
276 | if (GNUNET_YES == changed) | ||
277 | { | ||
278 | rehash_typemap (); | ||
279 | broadcast_my_type_map (); | ||
280 | } | ||
281 | } | ||
282 | |||
283 | |||
284 | /** | ||
285 | * Test if any of the types from the types array is in the | ||
286 | * given type map. | ||
287 | * | ||
288 | * @param tmap map to test | ||
289 | * @param types array of types | ||
290 | * @param tcnt number of entries in @a types | ||
291 | * @return #GNUNET_YES if a type is in the map, #GNUNET_NO if not | ||
292 | */ | ||
293 | int | ||
294 | GSC_TYPEMAP_test_match (const struct GSC_TypeMap *tmap, | ||
295 | const uint16_t *types, | ||
296 | unsigned int tcnt) | ||
297 | { | ||
298 | if (NULL == tmap) | ||
299 | return GNUNET_NO; | ||
300 | if (0 == tcnt) | ||
301 | return GNUNET_YES; /* matches all */ | ||
302 | for (unsigned int i = 0; i < tcnt; i++) | ||
303 | if (0 != (tmap->bits[types[i] / 32] & (1 << (types[i] % 32)))) | ||
304 | return GNUNET_YES; | ||
305 | return GNUNET_NO; | ||
306 | } | ||
307 | |||
308 | |||
309 | /** | ||
310 | * Add additional types to a given typemap. | ||
311 | * | ||
312 | * @param tmap map to extend (not changed) | ||
313 | * @param types array of types to add | ||
314 | * @param tcnt number of entries in @a types | ||
315 | * @return updated type map (fresh copy) | ||
316 | */ | ||
317 | struct GSC_TypeMap * | ||
318 | GSC_TYPEMAP_extend (const struct GSC_TypeMap *tmap, | ||
319 | const uint16_t *types, | ||
320 | unsigned int tcnt) | ||
321 | { | ||
322 | struct GSC_TypeMap *ret; | ||
323 | |||
324 | ret = GNUNET_new (struct GSC_TypeMap); | ||
325 | if (NULL != tmap) | ||
326 | GNUNET_memcpy (ret, tmap, sizeof(struct GSC_TypeMap)); | ||
327 | for (unsigned int i = 0; i < tcnt; i++) | ||
328 | ret->bits[types[i] / 32] |= (1 << (types[i] % 32)); | ||
329 | return ret; | ||
330 | } | ||
331 | |||
332 | |||
333 | /** | ||
334 | * Create an empty type map. | ||
335 | * | ||
336 | * @return an empty type map | ||
337 | */ | ||
338 | struct GSC_TypeMap * | ||
339 | GSC_TYPEMAP_create () | ||
340 | { | ||
341 | return GNUNET_new (struct GSC_TypeMap); | ||
342 | } | ||
343 | |||
344 | |||
345 | /** | ||
346 | * Free the given type map. | ||
347 | * | ||
348 | * @param tmap a type map | ||
349 | */ | ||
350 | void | ||
351 | GSC_TYPEMAP_destroy (struct GSC_TypeMap *tmap) | ||
352 | { | ||
353 | GNUNET_free (tmap); | ||
354 | } | ||
355 | |||
356 | |||
357 | /** | ||
358 | * Initialize typemap subsystem. | ||
359 | */ | ||
360 | void | ||
361 | GSC_TYPEMAP_init () | ||
362 | { | ||
363 | /* nothing to do */ | ||
364 | } | ||
365 | |||
366 | |||
367 | /** | ||
368 | * Shutdown typemap subsystem. | ||
369 | */ | ||
370 | void | ||
371 | GSC_TYPEMAP_done () | ||
372 | { | ||
373 | /* nothing to do */ | ||
374 | } | ||
375 | |||
376 | |||
377 | /* end of gnunet-service-core_typemap.c */ | ||
diff --git a/src/core/gnunet-service-core_typemap.h b/src/core/gnunet-service-core_typemap.h deleted file mode 100644 index 7acdec53b..000000000 --- a/src/core/gnunet-service-core_typemap.h +++ /dev/null | |||
@@ -1,163 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2011 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file core/gnunet-service-core_typemap.h | ||
23 | * @brief management of map that specifies which message types this peer supports | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #ifndef GNUNET_SERVICE_CORE_TYPEMAP_H | ||
27 | #define GNUNET_SERVICE_CORE_TYPEMAP_H | ||
28 | |||
29 | #include "gnunet_util_lib.h" | ||
30 | #include "gnunet_transport_service.h" | ||
31 | |||
32 | /** | ||
33 | * Map specifying which message types a peer supports. | ||
34 | */ | ||
35 | struct GSC_TypeMap; | ||
36 | |||
37 | |||
38 | /** | ||
39 | * Add a set of types to our type map. | ||
40 | * | ||
41 | * @param types array of message types supported by this peer | ||
42 | * @param tlen number of entries in @a types | ||
43 | */ | ||
44 | void | ||
45 | GSC_TYPEMAP_add (const uint16_t *types, | ||
46 | unsigned int tlen); | ||
47 | |||
48 | |||
49 | /** | ||
50 | * Remove a set of message types from our type map. | ||
51 | * | ||
52 | * @param types array of message types no longer supported by this peer | ||
53 | * @param tlen number of entries in @a types | ||
54 | */ | ||
55 | void | ||
56 | GSC_TYPEMAP_remove (const uint16_t *types, | ||
57 | unsigned int tlen); | ||
58 | |||
59 | |||
60 | /** | ||
61 | * Compute a type map message for this peer. | ||
62 | * | ||
63 | * @return this peers current type map message. | ||
64 | */ | ||
65 | struct GNUNET_MessageHeader * | ||
66 | GSC_TYPEMAP_compute_type_map_message (void); | ||
67 | |||
68 | |||
69 | /** | ||
70 | * Check if the given hash matches our current type map. | ||
71 | * | ||
72 | * @param hc hash code to check if it matches our type map | ||
73 | * @return #GNUNET_YES if the hash matches, #GNUNET_NO if not | ||
74 | */ | ||
75 | int | ||
76 | GSC_TYPEMAP_check_hash (const struct GNUNET_HashCode *hc); | ||
77 | |||
78 | |||
79 | /** | ||
80 | * Hash the contents of a type map. | ||
81 | * | ||
82 | * @param tm map to hash | ||
83 | * @param hc where to store the hash code | ||
84 | */ | ||
85 | void | ||
86 | GSC_TYPEMAP_hash (const struct GSC_TypeMap *tm, | ||
87 | struct GNUNET_HashCode *hc); | ||
88 | |||
89 | |||
90 | /** | ||
91 | * Extract a type map from a | ||
92 | * #GNUNET_MESSAGE_TYPE_CORE_COMRESSED_TYPE_MAP or | ||
93 | * #GNUNET_MESSAGE_TYPE_CORE_BINARY_TYPE_MAP message. | ||
94 | * | ||
95 | * @param msg a type map message | ||
96 | * @return NULL on error | ||
97 | */ | ||
98 | struct GSC_TypeMap * | ||
99 | GSC_TYPEMAP_get_from_message (const struct GNUNET_MessageHeader *msg); | ||
100 | |||
101 | |||
102 | /** | ||
103 | * Test if any of the types from the types array is in the | ||
104 | * given type map. | ||
105 | * | ||
106 | * @param tmap map to test | ||
107 | * @param types array of types | ||
108 | * @param tcnt number of entries in @a types | ||
109 | * @return #GNUNET_YES if a type is in the map, #GNUNET_NO if not | ||
110 | */ | ||
111 | int | ||
112 | GSC_TYPEMAP_test_match (const struct GSC_TypeMap *tmap, | ||
113 | const uint16_t *types, | ||
114 | unsigned int tcnt); | ||
115 | |||
116 | |||
117 | /** | ||
118 | * Add additional types to a given typemap. | ||
119 | * | ||
120 | * @param tmap map to extend (not changed) | ||
121 | * @param types array of types to add | ||
122 | * @param tcnt number of entries in @a types | ||
123 | * @return updated type map (fresh copy) | ||
124 | */ | ||
125 | struct GSC_TypeMap * | ||
126 | GSC_TYPEMAP_extend (const struct GSC_TypeMap *tmap, | ||
127 | const uint16_t *types, | ||
128 | unsigned int tcnt); | ||
129 | |||
130 | |||
131 | /** | ||
132 | * Create an empty type map. | ||
133 | * | ||
134 | * @return an empty type map | ||
135 | */ | ||
136 | struct GSC_TypeMap * | ||
137 | GSC_TYPEMAP_create (void); | ||
138 | |||
139 | |||
140 | /** | ||
141 | * Free the given type map. | ||
142 | * | ||
143 | * @param tmap a type map | ||
144 | */ | ||
145 | void | ||
146 | GSC_TYPEMAP_destroy (struct GSC_TypeMap *tmap); | ||
147 | |||
148 | |||
149 | /** | ||
150 | * Initialize typemap subsystem. | ||
151 | */ | ||
152 | void | ||
153 | GSC_TYPEMAP_init (void); | ||
154 | |||
155 | |||
156 | /** | ||
157 | * Shutdown typemap subsystem. | ||
158 | */ | ||
159 | void | ||
160 | GSC_TYPEMAP_done (void); | ||
161 | |||
162 | #endif | ||
163 | /* end of gnunet-service-core_typemap.h */ | ||
diff --git a/src/core/test_core_api.c b/src/core/test_core_api.c deleted file mode 100644 index 064964292..000000000 --- a/src/core/test_core_api.c +++ /dev/null | |||
@@ -1,344 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009, 2010, 2015, 2016 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @file core/test_core_api.c | ||
22 | * @brief testcase for core_api.c | ||
23 | * @author Christian Grothoff | ||
24 | */ | ||
25 | #include "platform.h" | ||
26 | #include "gnunet_arm_service.h" | ||
27 | #include "gnunet_core_service.h" | ||
28 | #include "gnunet_util_lib.h" | ||
29 | #include "gnunet_transport_service.h" | ||
30 | #include "gnunet_transport_hello_service.h" | ||
31 | #include "gnunet_ats_service.h" | ||
32 | |||
33 | #define MTYPE 12345 | ||
34 | |||
35 | struct PeerContext | ||
36 | { | ||
37 | struct GNUNET_CONFIGURATION_Handle *cfg; | ||
38 | struct GNUNET_CORE_Handle *ch; | ||
39 | struct GNUNET_PeerIdentity id; | ||
40 | struct GNUNET_TRANSPORT_OfferHelloHandle *oh; | ||
41 | struct GNUNET_TRANSPORT_HelloGetHandle *ghh; | ||
42 | struct GNUNET_ATS_ConnectivityHandle *ats; | ||
43 | struct GNUNET_ATS_ConnectivitySuggestHandle *ats_sh; | ||
44 | struct GNUNET_MessageHeader *hello; | ||
45 | int connect_status; | ||
46 | struct GNUNET_OS_Process *arm_proc; | ||
47 | }; | ||
48 | |||
49 | static struct PeerContext p1; | ||
50 | |||
51 | static struct PeerContext p2; | ||
52 | |||
53 | static struct GNUNET_SCHEDULER_Task *err_task; | ||
54 | |||
55 | static int ok; | ||
56 | |||
57 | #define OKPP \ | ||
58 | do \ | ||
59 | { \ | ||
60 | ok++; \ | ||
61 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, \ | ||
62 | "Now at stage %u at %s:%u\n", \ | ||
63 | ok, \ | ||
64 | __FILE__, \ | ||
65 | __LINE__); \ | ||
66 | } while (0) | ||
67 | |||
68 | |||
69 | static void | ||
70 | offer_hello_done (void *cls) | ||
71 | { | ||
72 | struct PeerContext *p = cls; | ||
73 | |||
74 | p->oh = NULL; | ||
75 | } | ||
76 | |||
77 | |||
78 | static void | ||
79 | process_hello (void *cls, const struct GNUNET_MessageHeader *message) | ||
80 | { | ||
81 | struct PeerContext *p = cls; | ||
82 | |||
83 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
84 | "Received (my) HELLO from transport service\n"); | ||
85 | GNUNET_assert (message != NULL); | ||
86 | if ((p == &p1) && (NULL == p2.oh)) | ||
87 | p2.oh = | ||
88 | GNUNET_TRANSPORT_offer_hello (p2.cfg, message, &offer_hello_done, &p2); | ||
89 | if ((p == &p2) && (NULL == p1.oh)) | ||
90 | p1.oh = | ||
91 | GNUNET_TRANSPORT_offer_hello (p1.cfg, message, &offer_hello_done, &p1); | ||
92 | } | ||
93 | |||
94 | |||
95 | static void | ||
96 | terminate_peer (struct PeerContext *p) | ||
97 | { | ||
98 | if (NULL != p->ch) | ||
99 | { | ||
100 | GNUNET_CORE_disconnect (p->ch); | ||
101 | p->ch = NULL; | ||
102 | } | ||
103 | if (NULL != p->ghh) | ||
104 | { | ||
105 | GNUNET_TRANSPORT_hello_get_cancel (p->ghh); | ||
106 | p->ghh = NULL; | ||
107 | } | ||
108 | if (NULL != p->oh) | ||
109 | { | ||
110 | GNUNET_TRANSPORT_offer_hello_cancel (p->oh); | ||
111 | p->oh = NULL; | ||
112 | } | ||
113 | if (NULL != p->ats_sh) | ||
114 | { | ||
115 | GNUNET_ATS_connectivity_suggest_cancel (p->ats_sh); | ||
116 | p->ats_sh = NULL; | ||
117 | } | ||
118 | if (NULL != p->ats) | ||
119 | { | ||
120 | GNUNET_ATS_connectivity_done (p->ats); | ||
121 | p->ats = NULL; | ||
122 | } | ||
123 | } | ||
124 | |||
125 | |||
126 | static void | ||
127 | terminate_task (void *cls) | ||
128 | { | ||
129 | GNUNET_assert (ok == 6); | ||
130 | terminate_peer (&p1); | ||
131 | terminate_peer (&p2); | ||
132 | ok = 0; | ||
133 | } | ||
134 | |||
135 | |||
136 | static void | ||
137 | terminate_task_error (void *cls) | ||
138 | { | ||
139 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "ENDING ANGRILY %u\n", ok); | ||
140 | GNUNET_break (0); | ||
141 | terminate_peer (&p1); | ||
142 | terminate_peer (&p2); | ||
143 | ok = 42; | ||
144 | } | ||
145 | |||
146 | |||
147 | static void * | ||
148 | connect_notify (void *cls, | ||
149 | const struct GNUNET_PeerIdentity *peer, | ||
150 | struct GNUNET_MQ_Handle *mq) | ||
151 | { | ||
152 | struct PeerContext *pc = cls; | ||
153 | struct GNUNET_MQ_Envelope *env; | ||
154 | struct GNUNET_MessageHeader *msg; | ||
155 | |||
156 | if (0 == memcmp (&pc->id, peer, sizeof(struct GNUNET_PeerIdentity))) | ||
157 | return (void *) peer; | ||
158 | GNUNET_assert (pc->connect_status == 0); | ||
159 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
160 | "Encrypted connection established to peer `%s'\n", | ||
161 | GNUNET_i2s (peer)); | ||
162 | pc->connect_status = 1; | ||
163 | if (pc == &p1) | ||
164 | { | ||
165 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
166 | "Asking core (1) for transmission to peer `%s'\n", | ||
167 | GNUNET_i2s (&p2.id)); | ||
168 | env = GNUNET_MQ_msg (msg, MTYPE); | ||
169 | /* enable corking for this test */ | ||
170 | GNUNET_MQ_env_set_options (env, | ||
171 | GNUNET_MQ_PRIO_BEST_EFFORT | ||
172 | | GNUNET_MQ_PREF_CORK_ALLOWED); | ||
173 | /* now actually transmit message */ | ||
174 | GNUNET_assert (ok == 4); | ||
175 | OKPP; | ||
176 | GNUNET_MQ_send (mq, env); | ||
177 | } | ||
178 | return (void *) peer; | ||
179 | } | ||
180 | |||
181 | |||
182 | static void | ||
183 | disconnect_notify (void *cls, | ||
184 | const struct GNUNET_PeerIdentity *peer, | ||
185 | void *internal_cls) | ||
186 | { | ||
187 | struct PeerContext *pc = cls; | ||
188 | |||
189 | if (0 == memcmp (&pc->id, peer, sizeof(struct GNUNET_PeerIdentity))) | ||
190 | return; | ||
191 | pc->connect_status = 0; | ||
192 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
193 | "Encrypted connection to `%s' cut\n", | ||
194 | GNUNET_i2s (peer)); | ||
195 | } | ||
196 | |||
197 | |||
198 | static void | ||
199 | handle_test (void *cls, const struct GNUNET_MessageHeader *message) | ||
200 | { | ||
201 | const struct GNUNET_PeerIdentity *peer = cls; | ||
202 | |||
203 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
204 | "Receiving message from `%s'.\n", | ||
205 | GNUNET_i2s (peer)); | ||
206 | GNUNET_assert (ok == 5); | ||
207 | OKPP; | ||
208 | GNUNET_SCHEDULER_cancel (err_task); | ||
209 | err_task = GNUNET_SCHEDULER_add_now (&terminate_task, NULL); | ||
210 | } | ||
211 | |||
212 | |||
213 | static void | ||
214 | init_notify (void *cls, const struct GNUNET_PeerIdentity *my_identity) | ||
215 | { | ||
216 | struct PeerContext *p = cls; | ||
217 | struct GNUNET_MQ_MessageHandler handlers[] = | ||
218 | { GNUNET_MQ_hd_fixed_size (test, MTYPE, struct GNUNET_MessageHeader, NULL), | ||
219 | GNUNET_MQ_handler_end () }; | ||
220 | |||
221 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
222 | "Core connection to `%s' established\n", | ||
223 | GNUNET_i2s (my_identity)); | ||
224 | p->id = *my_identity; | ||
225 | if (cls == &p1) | ||
226 | { | ||
227 | GNUNET_assert (ok == 2); | ||
228 | OKPP; | ||
229 | /* connect p2 */ | ||
230 | p2.ch = GNUNET_CORE_connect (p2.cfg, | ||
231 | &p2, | ||
232 | &init_notify, | ||
233 | &connect_notify, | ||
234 | &disconnect_notify, | ||
235 | handlers); | ||
236 | } | ||
237 | else | ||
238 | { | ||
239 | GNUNET_assert (ok == 3); | ||
240 | OKPP; | ||
241 | GNUNET_assert (cls == &p2); | ||
242 | p1.ats_sh = GNUNET_ATS_connectivity_suggest (p1.ats, &p2.id, 1); | ||
243 | } | ||
244 | } | ||
245 | |||
246 | |||
247 | static void | ||
248 | setup_peer (struct PeerContext *p, const char *cfgname) | ||
249 | { | ||
250 | char *binary; | ||
251 | |||
252 | binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-arm"); | ||
253 | p->cfg = GNUNET_CONFIGURATION_create (); | ||
254 | p->arm_proc = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_OUT_AND_ERR | ||
255 | | GNUNET_OS_USE_PIPE_CONTROL, | ||
256 | NULL, | ||
257 | NULL, | ||
258 | NULL, | ||
259 | binary, | ||
260 | "gnunet-service-arm", | ||
261 | "-c", | ||
262 | cfgname, | ||
263 | NULL); | ||
264 | GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname)); | ||
265 | p->ats = GNUNET_ATS_connectivity_init (p->cfg); | ||
266 | GNUNET_assert (NULL != p->ats); | ||
267 | p->ghh = GNUNET_TRANSPORT_hello_get (p->cfg, | ||
268 | GNUNET_TRANSPORT_AC_ANY, | ||
269 | &process_hello, | ||
270 | p); | ||
271 | GNUNET_free (binary); | ||
272 | } | ||
273 | |||
274 | |||
275 | static void | ||
276 | run (void *cls, | ||
277 | char *const *args, | ||
278 | const char *cfgfile, | ||
279 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
280 | { | ||
281 | struct GNUNET_MQ_MessageHandler handlers[] = | ||
282 | { GNUNET_MQ_hd_fixed_size (test, MTYPE, struct GNUNET_MessageHeader, NULL), | ||
283 | GNUNET_MQ_handler_end () }; | ||
284 | |||
285 | GNUNET_assert (ok == 1); | ||
286 | OKPP; | ||
287 | setup_peer (&p1, "test_core_api_peer1.conf"); | ||
288 | setup_peer (&p2, "test_core_api_peer2.conf"); | ||
289 | err_task = GNUNET_SCHEDULER_add_delayed ( | ||
290 | GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300), | ||
291 | &terminate_task_error, | ||
292 | NULL); | ||
293 | p1.ch = GNUNET_CORE_connect (p1.cfg, | ||
294 | &p1, | ||
295 | &init_notify, | ||
296 | &connect_notify, | ||
297 | &disconnect_notify, | ||
298 | handlers); | ||
299 | } | ||
300 | |||
301 | |||
302 | static void | ||
303 | stop_arm (struct PeerContext *p) | ||
304 | { | ||
305 | if (0 != GNUNET_OS_process_kill (p->arm_proc, GNUNET_TERM_SIG)) | ||
306 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill"); | ||
307 | if (GNUNET_OK != GNUNET_OS_process_wait (p->arm_proc)) | ||
308 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "waitpid"); | ||
309 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
310 | "ARM process %u stopped\n", | ||
311 | GNUNET_OS_process_get_pid (p->arm_proc)); | ||
312 | GNUNET_OS_process_destroy (p->arm_proc); | ||
313 | p->arm_proc = NULL; | ||
314 | GNUNET_CONFIGURATION_destroy (p->cfg); | ||
315 | } | ||
316 | |||
317 | |||
318 | int | ||
319 | main (int argc, char *argv1[]) | ||
320 | { | ||
321 | char *const argv[] = { "test-core-api", "-c", "test_core_api_data.conf", | ||
322 | NULL }; | ||
323 | struct GNUNET_GETOPT_CommandLineOption options[] = | ||
324 | { GNUNET_GETOPT_OPTION_END }; | ||
325 | |||
326 | ok = 1; | ||
327 | GNUNET_log_setup ("test-core-api", "WARNING", NULL); | ||
328 | GNUNET_PROGRAM_run ((sizeof(argv) / sizeof(char *)) - 1, | ||
329 | argv, | ||
330 | "test-core-api", | ||
331 | "nohelp", | ||
332 | options, | ||
333 | &run, | ||
334 | &ok); | ||
335 | stop_arm (&p1); | ||
336 | stop_arm (&p2); | ||
337 | GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-peer-1"); | ||
338 | GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-peer-2"); | ||
339 | |||
340 | return ok; | ||
341 | } | ||
342 | |||
343 | |||
344 | /* end of test_core_api.c */ | ||
diff --git a/src/core/test_core_api_data.conf b/src/core/test_core_api_data.conf deleted file mode 100644 index 420849ba9..000000000 --- a/src/core/test_core_api_data.conf +++ /dev/null | |||
@@ -1,11 +0,0 @@ | |||
1 | @INLINE@ test_core_defaults.conf | ||
2 | [PATHS] | ||
3 | |||
4 | [ats] | ||
5 | WAN_QUOTA_IN = 64 kiB | ||
6 | WAN_QUOTA_OUT = 64 kiB | ||
7 | |||
8 | [core] | ||
9 | PORT = 52092 | ||
10 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-core.sock | ||
11 | |||
diff --git a/src/core/test_core_api_peer1.conf b/src/core/test_core_api_peer1.conf deleted file mode 100644 index 28463effe..000000000 --- a/src/core/test_core_api_peer1.conf +++ /dev/null | |||
@@ -1,42 +0,0 @@ | |||
1 | @INLINE@ test_core_defaults.conf | ||
2 | [PATHS] | ||
3 | GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-core-peer-1/ | ||
4 | |||
5 | [arm] | ||
6 | PORT = 12460 | ||
7 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock | ||
8 | |||
9 | [statistics] | ||
10 | PORT = 12461 | ||
11 | |||
12 | [resolver] | ||
13 | PORT = 12462 | ||
14 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock | ||
15 | |||
16 | [peerinfo] | ||
17 | PORT = 12463 | ||
18 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock | ||
19 | |||
20 | [transport] | ||
21 | PORT = 12464 | ||
22 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock | ||
23 | |||
24 | [core] | ||
25 | PORT = 12475 | ||
26 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-core.sock | ||
27 | |||
28 | [ats] | ||
29 | PORT = 12476 | ||
30 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-ats.sock | ||
31 | |||
32 | [transport-tcp] | ||
33 | PORT = 12467 | ||
34 | |||
35 | [transport-udp] | ||
36 | PORT = 12468 | ||
37 | |||
38 | [transport-unix] | ||
39 | PORT = 12469 | ||
40 | |||
41 | [transport-http] | ||
42 | PORT = 12470 | ||
diff --git a/src/core/test_core_api_peer2.conf b/src/core/test_core_api_peer2.conf deleted file mode 100644 index 819d58d17..000000000 --- a/src/core/test_core_api_peer2.conf +++ /dev/null | |||
@@ -1,43 +0,0 @@ | |||
1 | @INLINE@ test_core_defaults.conf | ||
2 | [PATHS] | ||
3 | GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-core-peer-2/ | ||
4 | |||
5 | [arm] | ||
6 | PORT = 22460 | ||
7 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock | ||
8 | |||
9 | [statistics] | ||
10 | PORT = 22461 | ||
11 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock | ||
12 | |||
13 | [resolver] | ||
14 | PORT = 22462 | ||
15 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock | ||
16 | |||
17 | [peerinfo] | ||
18 | PORT = 22463 | ||
19 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock | ||
20 | |||
21 | [transport] | ||
22 | PORT = 22464 | ||
23 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock | ||
24 | |||
25 | [core] | ||
26 | PORT = 22475 | ||
27 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-core.sock | ||
28 | |||
29 | [ats] | ||
30 | PORT = 22476 | ||
31 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-ats.sock | ||
32 | |||
33 | [transport-tcp] | ||
34 | PORT = 22467 | ||
35 | |||
36 | [transport-udp] | ||
37 | PORT = 22468 | ||
38 | |||
39 | [transport-unix] | ||
40 | PORT = 22469 | ||
41 | |||
42 | [transport-http] | ||
43 | PORT = 22470 | ||
diff --git a/src/core/test_core_api_reliability.c b/src/core/test_core_api_reliability.c deleted file mode 100644 index debf808ca..000000000 --- a/src/core/test_core_api_reliability.c +++ /dev/null | |||
@@ -1,535 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009, 2010, 2015, 2016 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @file core/test_core_api_reliability.c | ||
22 | * @brief testcase for core_api.c focusing on reliable transmission (with TCP) | ||
23 | * @author Christian Grothoff | ||
24 | */ | ||
25 | #include "platform.h" | ||
26 | #include "gnunet_arm_service.h" | ||
27 | #include "gnunet_core_service.h" | ||
28 | #include "gnunet_util_lib.h" | ||
29 | #include "gnunet_ats_service.h" | ||
30 | #include "gnunet_transport_service.h" | ||
31 | #include "gnunet_transport_hello_service.h" | ||
32 | #include <gauger.h> | ||
33 | |||
34 | /** | ||
35 | * Note that this value must not significantly exceed | ||
36 | * 'MAX_PENDING' in 'gnunet-service-transport.c', otherwise | ||
37 | * messages may be dropped even for a reliable transport. | ||
38 | */ | ||
39 | #define TOTAL_MSGS (600 * 10) | ||
40 | |||
41 | /** | ||
42 | * How long until we give up on transmitting the message? | ||
43 | */ | ||
44 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 600) | ||
45 | |||
46 | #define MTYPE 12345 | ||
47 | |||
48 | |||
49 | static unsigned long long total_bytes; | ||
50 | |||
51 | static struct GNUNET_TIME_Absolute start_time; | ||
52 | |||
53 | static struct GNUNET_SCHEDULER_Task *err_task; | ||
54 | |||
55 | |||
56 | struct PeerContext | ||
57 | { | ||
58 | struct GNUNET_CONFIGURATION_Handle *cfg; | ||
59 | struct GNUNET_CORE_Handle *ch; | ||
60 | struct GNUNET_MQ_Handle *mq; | ||
61 | struct GNUNET_PeerIdentity id; | ||
62 | struct GNUNET_TRANSPORT_OfferHelloHandle *oh; | ||
63 | struct GNUNET_MessageHeader *hello; | ||
64 | struct GNUNET_TRANSPORT_HelloGetHandle *ghh; | ||
65 | struct GNUNET_ATS_ConnectivityHandle *ats; | ||
66 | struct GNUNET_ATS_ConnectivitySuggestHandle *ats_sh; | ||
67 | int connect_status; | ||
68 | struct GNUNET_OS_Process *arm_proc; | ||
69 | }; | ||
70 | |||
71 | static struct PeerContext p1; | ||
72 | |||
73 | static struct PeerContext p2; | ||
74 | |||
75 | static int ok; | ||
76 | |||
77 | static int32_t tr_n; | ||
78 | |||
79 | |||
80 | #define OKPP do { ok++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, \ | ||
81 | "Now at stage %u at %s:%u\n", ok, __FILE__, \ | ||
82 | __LINE__); } while (0) | ||
83 | |||
84 | struct TestMessage | ||
85 | { | ||
86 | struct GNUNET_MessageHeader header; | ||
87 | uint32_t num GNUNET_PACKED; | ||
88 | }; | ||
89 | |||
90 | |||
91 | static unsigned int | ||
92 | get_size (unsigned int iter) | ||
93 | { | ||
94 | unsigned int ret; | ||
95 | |||
96 | if (iter < 60000) | ||
97 | return iter + sizeof(struct TestMessage); | ||
98 | ret = (iter * iter * iter); | ||
99 | return sizeof(struct TestMessage) + (ret % 60000); | ||
100 | } | ||
101 | |||
102 | |||
103 | static void | ||
104 | terminate_peer (struct PeerContext *p) | ||
105 | { | ||
106 | if (NULL != p->ch) | ||
107 | { | ||
108 | GNUNET_CORE_disconnect (p->ch); | ||
109 | p->ch = NULL; | ||
110 | } | ||
111 | if (NULL != p->ghh) | ||
112 | { | ||
113 | GNUNET_TRANSPORT_hello_get_cancel (p->ghh); | ||
114 | p->ghh = NULL; | ||
115 | } | ||
116 | if (NULL != p->oh) | ||
117 | { | ||
118 | GNUNET_TRANSPORT_offer_hello_cancel (p->oh); | ||
119 | p->oh = NULL; | ||
120 | } | ||
121 | if (NULL != p->ats_sh) | ||
122 | { | ||
123 | GNUNET_ATS_connectivity_suggest_cancel (p->ats_sh); | ||
124 | p->ats_sh = NULL; | ||
125 | } | ||
126 | if (NULL != p->ats) | ||
127 | { | ||
128 | GNUNET_ATS_connectivity_done (p->ats); | ||
129 | p->ats = NULL; | ||
130 | } | ||
131 | } | ||
132 | |||
133 | |||
134 | static void | ||
135 | terminate_task_error (void *cls) | ||
136 | { | ||
137 | err_task = NULL; | ||
138 | GNUNET_break (0); | ||
139 | GNUNET_SCHEDULER_shutdown (); | ||
140 | ok = 42; | ||
141 | } | ||
142 | |||
143 | |||
144 | static void | ||
145 | do_shutdown (void *cls) | ||
146 | { | ||
147 | unsigned long long delta; | ||
148 | |||
149 | delta = GNUNET_TIME_absolute_get_duration (start_time).rel_value_us; | ||
150 | if (0 == delta) | ||
151 | delta = 1; | ||
152 | fprintf (stderr, | ||
153 | "\nThroughput was %llu kb/s\n", | ||
154 | total_bytes * 1000000LL / 1024 / delta); | ||
155 | GAUGER ("CORE", | ||
156 | "Core throughput/s", | ||
157 | total_bytes * 1000000LL / 1024 / delta, | ||
158 | "kb/s"); | ||
159 | if (NULL != err_task) | ||
160 | { | ||
161 | GNUNET_SCHEDULER_cancel (err_task); | ||
162 | err_task = NULL; | ||
163 | } | ||
164 | terminate_peer (&p1); | ||
165 | terminate_peer (&p2); | ||
166 | } | ||
167 | |||
168 | |||
169 | static void | ||
170 | send_message (struct GNUNET_MQ_Handle *mq, | ||
171 | int32_t num) | ||
172 | { | ||
173 | struct GNUNET_MQ_Envelope *env; | ||
174 | struct TestMessage *hdr; | ||
175 | unsigned int s; | ||
176 | |||
177 | GNUNET_assert (NULL != mq); | ||
178 | GNUNET_assert (tr_n < TOTAL_MSGS); | ||
179 | s = get_size (tr_n); | ||
180 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
181 | "Sending message %u of size %u\n", | ||
182 | tr_n, | ||
183 | s); | ||
184 | env = GNUNET_MQ_msg_extra (hdr, | ||
185 | s - sizeof(struct TestMessage), | ||
186 | MTYPE); | ||
187 | hdr->num = htonl (tr_n); | ||
188 | memset (&hdr[1], | ||
189 | tr_n, | ||
190 | s - sizeof(struct TestMessage)); | ||
191 | tr_n++; | ||
192 | GNUNET_SCHEDULER_cancel (err_task); | ||
193 | err_task = | ||
194 | GNUNET_SCHEDULER_add_delayed (TIMEOUT, | ||
195 | &terminate_task_error, | ||
196 | NULL); | ||
197 | total_bytes += s; | ||
198 | GNUNET_MQ_send (mq, | ||
199 | env); | ||
200 | } | ||
201 | |||
202 | |||
203 | static void * | ||
204 | connect_notify (void *cls, | ||
205 | const struct GNUNET_PeerIdentity *peer, | ||
206 | struct GNUNET_MQ_Handle *mq) | ||
207 | { | ||
208 | struct PeerContext *pc = cls; | ||
209 | |||
210 | if (0 == memcmp (&pc->id, | ||
211 | peer, | ||
212 | sizeof(struct GNUNET_PeerIdentity))) | ||
213 | return (void *) peer; | ||
214 | pc->mq = mq; | ||
215 | GNUNET_assert (0 == pc->connect_status); | ||
216 | pc->connect_status = 1; | ||
217 | if (pc == &p1) | ||
218 | { | ||
219 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
220 | "Encrypted connection established to peer `%s'\n", | ||
221 | GNUNET_i2s (peer)); | ||
222 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
223 | "Asking core (1) for transmission to peer `%s'\n", | ||
224 | GNUNET_i2s (&p2.id)); | ||
225 | GNUNET_SCHEDULER_cancel (err_task); | ||
226 | err_task = | ||
227 | GNUNET_SCHEDULER_add_delayed (TIMEOUT, | ||
228 | &terminate_task_error, | ||
229 | NULL); | ||
230 | start_time = GNUNET_TIME_absolute_get (); | ||
231 | send_message (mq, | ||
232 | 0); | ||
233 | } | ||
234 | return (void *) peer; | ||
235 | } | ||
236 | |||
237 | |||
238 | static void | ||
239 | disconnect_notify (void *cls, | ||
240 | const struct GNUNET_PeerIdentity *peer, | ||
241 | void *internal_cls) | ||
242 | { | ||
243 | struct PeerContext *pc = cls; | ||
244 | |||
245 | if (0 == memcmp (&pc->id, | ||
246 | peer, | ||
247 | sizeof(struct GNUNET_PeerIdentity))) | ||
248 | return; | ||
249 | pc->mq = NULL; | ||
250 | pc->connect_status = 0; | ||
251 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
252 | "Encrypted connection to `%s' cut\n", | ||
253 | GNUNET_i2s (peer)); | ||
254 | } | ||
255 | |||
256 | |||
257 | static int | ||
258 | check_test (void *cls, | ||
259 | const struct TestMessage *hdr) | ||
260 | { | ||
261 | return GNUNET_OK; /* accept all */ | ||
262 | } | ||
263 | |||
264 | |||
265 | static void | ||
266 | handle_test (void *cls, | ||
267 | const struct TestMessage *hdr) | ||
268 | { | ||
269 | static int n; | ||
270 | unsigned int s; | ||
271 | |||
272 | s = get_size (n); | ||
273 | if (ntohs (hdr->header.size) != s) | ||
274 | { | ||
275 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
276 | "Expected message %u of size %u, got %u bytes of message %u\n", | ||
277 | n, | ||
278 | s, | ||
279 | ntohs (hdr->header.size), | ||
280 | ntohl (hdr->num)); | ||
281 | GNUNET_SCHEDULER_cancel (err_task); | ||
282 | err_task = GNUNET_SCHEDULER_add_now (&terminate_task_error, | ||
283 | NULL); | ||
284 | return; | ||
285 | } | ||
286 | if (ntohl (hdr->num) != n) | ||
287 | { | ||
288 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
289 | "Expected message %u of size %u, got %u bytes of message %u\n", | ||
290 | n, | ||
291 | s, | ||
292 | (unsigned int) ntohs (hdr->header.size), | ||
293 | (unsigned int) ntohl (hdr->num)); | ||
294 | GNUNET_SCHEDULER_cancel (err_task); | ||
295 | err_task = GNUNET_SCHEDULER_add_now (&terminate_task_error, | ||
296 | NULL); | ||
297 | return; | ||
298 | } | ||
299 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
300 | "Got message %u of size %u\n", | ||
301 | (unsigned int) ntohl (hdr->num), | ||
302 | (unsigned int) ntohs (hdr->header.size)); | ||
303 | n++; | ||
304 | if (0 == (n % (TOTAL_MSGS / 100))) | ||
305 | fprintf (stderr, | ||
306 | "%s", | ||
307 | "."); | ||
308 | if (n == TOTAL_MSGS) | ||
309 | { | ||
310 | ok = 0; | ||
311 | GNUNET_SCHEDULER_shutdown (); | ||
312 | } | ||
313 | else | ||
314 | { | ||
315 | if (n == tr_n) | ||
316 | { | ||
317 | send_message (p1.mq, | ||
318 | tr_n); | ||
319 | } | ||
320 | } | ||
321 | } | ||
322 | |||
323 | |||
324 | static void | ||
325 | init_notify (void *cls, | ||
326 | const struct GNUNET_PeerIdentity *my_identity) | ||
327 | { | ||
328 | struct PeerContext *p = cls; | ||
329 | struct GNUNET_MQ_MessageHandler handlers[] = { | ||
330 | GNUNET_MQ_hd_var_size (test, | ||
331 | MTYPE, | ||
332 | struct TestMessage, | ||
333 | NULL), | ||
334 | GNUNET_MQ_handler_end () | ||
335 | }; | ||
336 | |||
337 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
338 | "Connection to CORE service of `%s' established\n", | ||
339 | GNUNET_i2s (my_identity)); | ||
340 | p->id = *my_identity; | ||
341 | if (cls == &p1) | ||
342 | { | ||
343 | GNUNET_assert (ok == 2); | ||
344 | OKPP; | ||
345 | /* connect p2 */ | ||
346 | GNUNET_assert (NULL != | ||
347 | (p2.ch = GNUNET_CORE_connect (p2.cfg, | ||
348 | &p2, | ||
349 | &init_notify, | ||
350 | &connect_notify, | ||
351 | &disconnect_notify, | ||
352 | handlers))); | ||
353 | } | ||
354 | else | ||
355 | { | ||
356 | GNUNET_assert (ok == 3); | ||
357 | OKPP; | ||
358 | GNUNET_assert (cls == &p2); | ||
359 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
360 | "Asking transport (1) to connect to peer `%s'\n", | ||
361 | GNUNET_i2s (&p2.id)); | ||
362 | p1.ats_sh = GNUNET_ATS_connectivity_suggest (p1.ats, | ||
363 | &p2.id, | ||
364 | 1); | ||
365 | } | ||
366 | } | ||
367 | |||
368 | |||
369 | static void | ||
370 | offer_hello_done (void *cls) | ||
371 | { | ||
372 | struct PeerContext *p = cls; | ||
373 | |||
374 | p->oh = NULL; | ||
375 | } | ||
376 | |||
377 | |||
378 | static void | ||
379 | process_hello (void *cls, | ||
380 | const struct GNUNET_MessageHeader *message) | ||
381 | { | ||
382 | struct PeerContext *p = cls; | ||
383 | |||
384 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
385 | "Received (my) `%s' from transport service\n", "HELLO"); | ||
386 | GNUNET_assert (message != NULL); | ||
387 | GNUNET_free (p->hello); | ||
388 | p->hello = GNUNET_copy_message (message); | ||
389 | if ((p == &p1) && (NULL == p2.oh)) | ||
390 | p2.oh = GNUNET_TRANSPORT_offer_hello (p2.cfg, | ||
391 | message, | ||
392 | &offer_hello_done, | ||
393 | &p2); | ||
394 | if ((p == &p2) && (NULL == p1.oh)) | ||
395 | p1.oh = GNUNET_TRANSPORT_offer_hello (p1.cfg, | ||
396 | message, | ||
397 | &offer_hello_done, | ||
398 | &p1); | ||
399 | |||
400 | if ((p == &p1) && (p2.hello != NULL) && (NULL == p1.oh)) | ||
401 | p1.oh = GNUNET_TRANSPORT_offer_hello (p1.cfg, | ||
402 | p2.hello, | ||
403 | &offer_hello_done, | ||
404 | &p1); | ||
405 | if ((p == &p2) && (p1.hello != NULL) && (NULL == p2.oh)) | ||
406 | p2.oh = GNUNET_TRANSPORT_offer_hello (p2.cfg, | ||
407 | p1.hello, | ||
408 | &offer_hello_done, | ||
409 | &p2); | ||
410 | } | ||
411 | |||
412 | |||
413 | static void | ||
414 | setup_peer (struct PeerContext *p, | ||
415 | const char *cfgname) | ||
416 | { | ||
417 | char *binary; | ||
418 | |||
419 | binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-arm"); | ||
420 | p->cfg = GNUNET_CONFIGURATION_create (); | ||
421 | p->arm_proc | ||
422 | = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_OUT_AND_ERR | ||
423 | | GNUNET_OS_USE_PIPE_CONTROL, | ||
424 | NULL, NULL, NULL, | ||
425 | binary, | ||
426 | "gnunet-service-arm", | ||
427 | "-c", | ||
428 | cfgname, | ||
429 | NULL); | ||
430 | GNUNET_assert (GNUNET_OK == | ||
431 | GNUNET_CONFIGURATION_load (p->cfg, | ||
432 | cfgname)); | ||
433 | p->ats = GNUNET_ATS_connectivity_init (p->cfg); | ||
434 | GNUNET_assert (NULL != p->ats); | ||
435 | p->ghh = GNUNET_TRANSPORT_hello_get (p->cfg, | ||
436 | GNUNET_TRANSPORT_AC_ANY, | ||
437 | &process_hello, | ||
438 | p); | ||
439 | GNUNET_free (binary); | ||
440 | } | ||
441 | |||
442 | |||
443 | static void | ||
444 | run (void *cls, | ||
445 | char *const *args, | ||
446 | const char *cfgfile, | ||
447 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
448 | { | ||
449 | struct GNUNET_MQ_MessageHandler handlers[] = { | ||
450 | GNUNET_MQ_hd_fixed_size (test, | ||
451 | MTYPE, | ||
452 | struct TestMessage, | ||
453 | NULL), | ||
454 | GNUNET_MQ_handler_end () | ||
455 | }; | ||
456 | |||
457 | GNUNET_assert (ok == 1); | ||
458 | OKPP; | ||
459 | setup_peer (&p1, | ||
460 | "test_core_api_peer1.conf"); | ||
461 | setup_peer (&p2, | ||
462 | "test_core_api_peer2.conf"); | ||
463 | err_task = | ||
464 | GNUNET_SCHEDULER_add_delayed (TIMEOUT, | ||
465 | &terminate_task_error, | ||
466 | NULL); | ||
467 | GNUNET_SCHEDULER_add_shutdown (&do_shutdown, | ||
468 | NULL); | ||
469 | |||
470 | GNUNET_assert (NULL != | ||
471 | (p1.ch = GNUNET_CORE_connect (p1.cfg, | ||
472 | &p1, | ||
473 | &init_notify, | ||
474 | &connect_notify, | ||
475 | &disconnect_notify, | ||
476 | handlers))); | ||
477 | } | ||
478 | |||
479 | |||
480 | static void | ||
481 | stop_arm (struct PeerContext *p) | ||
482 | { | ||
483 | if (0 != GNUNET_OS_process_kill (p->arm_proc, | ||
484 | GNUNET_TERM_SIG)) | ||
485 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, | ||
486 | "kill"); | ||
487 | if (GNUNET_OK != GNUNET_OS_process_wait (p->arm_proc)) | ||
488 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, | ||
489 | "waitpid"); | ||
490 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
491 | "ARM process %u stopped\n", | ||
492 | GNUNET_OS_process_get_pid (p->arm_proc)); | ||
493 | GNUNET_OS_process_destroy (p->arm_proc); | ||
494 | p->arm_proc = NULL; | ||
495 | GNUNET_CONFIGURATION_destroy (p->cfg); | ||
496 | } | ||
497 | |||
498 | |||
499 | int | ||
500 | main (int argc, | ||
501 | char *argv1[]) | ||
502 | { | ||
503 | char *const argv[] = { | ||
504 | "test-core-api-reliability", | ||
505 | "-c", | ||
506 | "test_core_api_data.conf", | ||
507 | NULL | ||
508 | }; | ||
509 | struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
510 | GNUNET_GETOPT_OPTION_END | ||
511 | }; | ||
512 | |||
513 | ok = 1; | ||
514 | GNUNET_log_setup ("test-core-api-reliability", | ||
515 | "WARNING", | ||
516 | NULL); | ||
517 | GNUNET_PROGRAM_run ((sizeof(argv) / sizeof(char *)) - 1, | ||
518 | argv, | ||
519 | "test-core-api-reliability", | ||
520 | "nohelp", | ||
521 | options, | ||
522 | &run, | ||
523 | &ok); | ||
524 | stop_arm (&p1); | ||
525 | stop_arm (&p2); | ||
526 | GNUNET_free (p1.hello); | ||
527 | GNUNET_free (p2.hello); | ||
528 | GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-peer-1"); | ||
529 | GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-peer-2"); | ||
530 | |||
531 | return ok; | ||
532 | } | ||
533 | |||
534 | |||
535 | /* end of test_core_api_reliability.c */ | ||
diff --git a/src/core/test_core_api_send_to_self.c b/src/core/test_core_api_send_to_self.c deleted file mode 100644 index c2e39cd26..000000000 --- a/src/core/test_core_api_send_to_self.c +++ /dev/null | |||
@@ -1,195 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2010, 2016 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file core/test_core_api_send_to_self.c | ||
23 | * @brief test that sending a message to ourselves via CORE works | ||
24 | * @author Philipp Toelke | ||
25 | * @author Christian Grothoff | ||
26 | */ | ||
27 | #include "platform.h" | ||
28 | #include "gnunet_util_lib.h" | ||
29 | #include "gnunet_testing_lib.h" | ||
30 | #include "gnunet_protocols.h" | ||
31 | #include "gnunet_core_service.h" | ||
32 | #include "gnunet_constants.h" | ||
33 | |||
34 | /** | ||
35 | * Final status code. | ||
36 | */ | ||
37 | static int ret; | ||
38 | |||
39 | /** | ||
40 | * Handle to the cleanup task. | ||
41 | */ | ||
42 | static struct GNUNET_SCHEDULER_Task *die_task; | ||
43 | |||
44 | /** | ||
45 | * Identity of this peer. | ||
46 | */ | ||
47 | static struct GNUNET_PeerIdentity myself; | ||
48 | |||
49 | /** | ||
50 | * The handle to core | ||
51 | */ | ||
52 | static struct GNUNET_CORE_Handle *core; | ||
53 | |||
54 | |||
55 | /** | ||
56 | * Function scheduled as very last function, cleans up after us | ||
57 | */ | ||
58 | static void | ||
59 | cleanup (void *cls) | ||
60 | { | ||
61 | if (NULL != die_task) | ||
62 | { | ||
63 | GNUNET_SCHEDULER_cancel (die_task); | ||
64 | die_task = NULL; | ||
65 | } | ||
66 | if (NULL != core) | ||
67 | { | ||
68 | GNUNET_CORE_disconnect (core); | ||
69 | core = NULL; | ||
70 | } | ||
71 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
72 | "Ending test.\n"); | ||
73 | } | ||
74 | |||
75 | |||
76 | /** | ||
77 | * Function scheduled as very last function, cleans up after us | ||
78 | */ | ||
79 | static void | ||
80 | do_timeout (void *cls) | ||
81 | { | ||
82 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
83 | "Test timeout.\n"); | ||
84 | die_task = NULL; | ||
85 | GNUNET_SCHEDULER_shutdown (); | ||
86 | } | ||
87 | |||
88 | |||
89 | static void | ||
90 | handle_test (void *cls, | ||
91 | const struct GNUNET_MessageHeader *message) | ||
92 | { | ||
93 | GNUNET_SCHEDULER_shutdown (); | ||
94 | ret = 0; | ||
95 | } | ||
96 | |||
97 | |||
98 | static void | ||
99 | init (void *cls, | ||
100 | const struct GNUNET_PeerIdentity *my_identity) | ||
101 | { | ||
102 | if (NULL == my_identity) | ||
103 | { | ||
104 | GNUNET_break (0); | ||
105 | return; | ||
106 | } | ||
107 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
108 | "Correctly connected to CORE; we are the peer %s.\n", | ||
109 | GNUNET_i2s (my_identity)); | ||
110 | GNUNET_memcpy (&myself, | ||
111 | my_identity, | ||
112 | sizeof(struct GNUNET_PeerIdentity)); | ||
113 | } | ||
114 | |||
115 | |||
116 | static void * | ||
117 | connect_cb (void *cls, | ||
118 | const struct GNUNET_PeerIdentity *peer, | ||
119 | struct GNUNET_MQ_Handle *mq) | ||
120 | { | ||
121 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
122 | "Connected to peer %s.\n", | ||
123 | GNUNET_i2s (peer)); | ||
124 | if (0 == memcmp (peer, | ||
125 | &myself, | ||
126 | sizeof(struct GNUNET_PeerIdentity))) | ||
127 | { | ||
128 | struct GNUNET_MQ_Envelope *env; | ||
129 | struct GNUNET_MessageHeader *msg; | ||
130 | |||
131 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
132 | "Connected to myself; sending message!\n"); | ||
133 | env = GNUNET_MQ_msg (msg, | ||
134 | GNUNET_MESSAGE_TYPE_DUMMY); | ||
135 | GNUNET_MQ_send (mq, | ||
136 | env); | ||
137 | } | ||
138 | return NULL; | ||
139 | } | ||
140 | |||
141 | |||
142 | /** | ||
143 | * Main function that will be run by the scheduler. | ||
144 | * | ||
145 | * @param cls closure | ||
146 | * @param cfg configuration | ||
147 | */ | ||
148 | static void | ||
149 | run (void *cls, | ||
150 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
151 | struct GNUNET_TESTING_Peer *peer) | ||
152 | { | ||
153 | struct GNUNET_MQ_MessageHandler handlers[] = { | ||
154 | GNUNET_MQ_hd_fixed_size (test, | ||
155 | GNUNET_MESSAGE_TYPE_DUMMY, | ||
156 | struct GNUNET_MessageHeader, | ||
157 | NULL), | ||
158 | GNUNET_MQ_handler_end () | ||
159 | }; | ||
160 | |||
161 | core = | ||
162 | GNUNET_CORE_connect (cfg, | ||
163 | NULL, | ||
164 | &init, | ||
165 | &connect_cb, | ||
166 | NULL, | ||
167 | handlers); | ||
168 | GNUNET_SCHEDULER_add_shutdown (&cleanup, | ||
169 | NULL); | ||
170 | die_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, | ||
171 | &do_timeout, | ||
172 | NULL); | ||
173 | } | ||
174 | |||
175 | |||
176 | /** | ||
177 | * The main function to test sending a message to the local peer via core | ||
178 | * | ||
179 | * @param argc number of arguments from the command line | ||
180 | * @param argv command line arguments | ||
181 | * @return 0 ok, 1 on error | ||
182 | */ | ||
183 | int | ||
184 | main (int argc, char *argv[]) | ||
185 | { | ||
186 | ret = 1; | ||
187 | if (0 != GNUNET_TESTING_peer_run ("test-core-api-send-to-self", | ||
188 | "test_core_api_peer1.conf", | ||
189 | &run, NULL)) | ||
190 | return 1; | ||
191 | return ret; | ||
192 | } | ||
193 | |||
194 | |||
195 | /* end of test_core_api_send_to_self.c */ | ||
diff --git a/src/core/test_core_api_send_to_self.conf b/src/core/test_core_api_send_to_self.conf deleted file mode 100644 index c2a459bb9..000000000 --- a/src/core/test_core_api_send_to_self.conf +++ /dev/null | |||
@@ -1,19 +0,0 @@ | |||
1 | @INLINE@ test_core_defaults.conf | ||
2 | [PATHS] | ||
3 | GNUNET_TEST_HOME = ~/.gnunet/ | ||
4 | |||
5 | [ats] | ||
6 | WAN_QUOTA_IN = 104857600 | ||
7 | WAN_QUOTA_OUT = 104757600 | ||
8 | |||
9 | [test-sts] | ||
10 | IMMEDIATE_START = YES | ||
11 | PORT = 59252 | ||
12 | HOSTNAME = localhost | ||
13 | BINARY = test_core_api_send_to_self | ||
14 | ACCEPT_FROM = 127.0.0.1; | ||
15 | ACCEPT_FROM6 = ::1; | ||
16 | TOTAL_QUOTA_IN = 65536 | ||
17 | TOTAL_QUOTA_OUT = 65536 | ||
18 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-sts.sock | ||
19 | |||
diff --git a/src/core/test_core_api_start_only.c b/src/core/test_core_api_start_only.c deleted file mode 100644 index 007131134..000000000 --- a/src/core/test_core_api_start_only.c +++ /dev/null | |||
@@ -1,250 +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 it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @file transport/test_core_api_start_only.c | ||
22 | * @brief testcase for core_api.c that only starts two peers, | ||
23 | * connects to the core service and shuts down again | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet_arm_service.h" | ||
28 | #include "gnunet_core_service.h" | ||
29 | #include "gnunet_util_lib.h" | ||
30 | |||
31 | #define TIMEOUT 5 | ||
32 | |||
33 | #define MTYPE 12345 | ||
34 | |||
35 | struct PeerContext | ||
36 | { | ||
37 | struct GNUNET_CONFIGURATION_Handle *cfg; | ||
38 | struct GNUNET_CORE_Handle *ch; | ||
39 | struct GNUNET_PeerIdentity id; | ||
40 | struct GNUNET_OS_Process *arm_proc; | ||
41 | }; | ||
42 | |||
43 | static struct PeerContext p1; | ||
44 | |||
45 | static struct PeerContext p2; | ||
46 | |||
47 | static struct GNUNET_SCHEDULER_Task *timeout_task_id; | ||
48 | |||
49 | static int ok; | ||
50 | |||
51 | |||
52 | static void * | ||
53 | connect_notify (void *cls, | ||
54 | const struct GNUNET_PeerIdentity *peer, | ||
55 | struct GNUNET_MQ_Handle *mq) | ||
56 | { | ||
57 | return NULL; | ||
58 | } | ||
59 | |||
60 | |||
61 | static void | ||
62 | disconnect_notify (void *cls, | ||
63 | const struct GNUNET_PeerIdentity *peer, | ||
64 | void *internal_cls) | ||
65 | { | ||
66 | } | ||
67 | |||
68 | |||
69 | static struct GNUNET_MQ_MessageHandler handlers[] = { | ||
70 | GNUNET_MQ_handler_end () | ||
71 | }; | ||
72 | |||
73 | |||
74 | static void | ||
75 | shutdown_task (void *cls) | ||
76 | { | ||
77 | GNUNET_CORE_disconnect (p1.ch); | ||
78 | p1.ch = NULL; | ||
79 | GNUNET_CORE_disconnect (p2.ch); | ||
80 | p2.ch = NULL; | ||
81 | ok = 0; | ||
82 | } | ||
83 | |||
84 | |||
85 | static void | ||
86 | init_notify (void *cls, | ||
87 | const struct GNUNET_PeerIdentity *my_identity) | ||
88 | { | ||
89 | struct PeerContext *p = cls; | ||
90 | |||
91 | if (p == &p1) | ||
92 | { | ||
93 | /* connect p2 */ | ||
94 | p2.ch = GNUNET_CORE_connect (p2.cfg, | ||
95 | &p2, | ||
96 | &init_notify, | ||
97 | &connect_notify, | ||
98 | &disconnect_notify, | ||
99 | handlers); | ||
100 | } | ||
101 | else | ||
102 | { | ||
103 | GNUNET_assert (p == &p2); | ||
104 | GNUNET_SCHEDULER_cancel (timeout_task_id); | ||
105 | timeout_task_id = NULL; | ||
106 | GNUNET_SCHEDULER_add_now (&shutdown_task, | ||
107 | NULL); | ||
108 | } | ||
109 | } | ||
110 | |||
111 | |||
112 | static void | ||
113 | setup_peer (struct PeerContext *p, | ||
114 | const char *cfgname) | ||
115 | { | ||
116 | char *binary; | ||
117 | |||
118 | binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-arm"); | ||
119 | p->cfg = GNUNET_CONFIGURATION_create (); | ||
120 | p->arm_proc = | ||
121 | GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_OUT_AND_ERR | ||
122 | | GNUNET_OS_USE_PIPE_CONTROL, | ||
123 | NULL, NULL, NULL, | ||
124 | binary, | ||
125 | "gnunet-service-arm", | ||
126 | "-c", cfgname, | ||
127 | NULL); | ||
128 | GNUNET_assert (GNUNET_OK == | ||
129 | GNUNET_CONFIGURATION_load (p->cfg, | ||
130 | cfgname)); | ||
131 | GNUNET_free (binary); | ||
132 | } | ||
133 | |||
134 | |||
135 | static void | ||
136 | timeout_task (void *cls) | ||
137 | { | ||
138 | fprintf (stderr, | ||
139 | "%s", | ||
140 | "Timeout.\n"); | ||
141 | if (NULL != p1.ch) | ||
142 | { | ||
143 | GNUNET_CORE_disconnect (p1.ch); | ||
144 | p1.ch = NULL; | ||
145 | } | ||
146 | if (NULL != p2.ch) | ||
147 | { | ||
148 | GNUNET_CORE_disconnect (p2.ch); | ||
149 | p2.ch = NULL; | ||
150 | } | ||
151 | ok = 42; | ||
152 | } | ||
153 | |||
154 | |||
155 | static void | ||
156 | run (void *cls, | ||
157 | char *const *args, | ||
158 | const char *cfgfile, | ||
159 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
160 | { | ||
161 | GNUNET_assert (ok == 1); | ||
162 | ok++; | ||
163 | setup_peer (&p1, "test_core_api_peer1.conf"); | ||
164 | setup_peer (&p2, "test_core_api_peer2.conf"); | ||
165 | timeout_task_id = | ||
166 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply | ||
167 | (GNUNET_TIME_UNIT_MINUTES, | ||
168 | TIMEOUT), | ||
169 | &timeout_task, | ||
170 | NULL); | ||
171 | p1.ch = GNUNET_CORE_connect (p1.cfg, | ||
172 | &p1, | ||
173 | &init_notify, | ||
174 | &connect_notify, | ||
175 | &disconnect_notify, | ||
176 | handlers); | ||
177 | } | ||
178 | |||
179 | |||
180 | static void | ||
181 | stop_arm (struct PeerContext *p) | ||
182 | { | ||
183 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
184 | "Stopping peer\n"); | ||
185 | if (0 != GNUNET_OS_process_kill (p->arm_proc, | ||
186 | GNUNET_TERM_SIG)) | ||
187 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, | ||
188 | "kill"); | ||
189 | if (GNUNET_OK != | ||
190 | GNUNET_OS_process_wait (p->arm_proc)) | ||
191 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, | ||
192 | "waitpid"); | ||
193 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
194 | "ARM process %u stopped\n", | ||
195 | (unsigned int) GNUNET_OS_process_get_pid (p->arm_proc)); | ||
196 | GNUNET_OS_process_destroy (p->arm_proc); | ||
197 | p->arm_proc = NULL; | ||
198 | GNUNET_CONFIGURATION_destroy (p->cfg); | ||
199 | } | ||
200 | |||
201 | |||
202 | static int | ||
203 | check () | ||
204 | { | ||
205 | char *const argv[] = { | ||
206 | "test-core-api-start-only", | ||
207 | "-c", | ||
208 | "test_core_api_data.conf", | ||
209 | NULL | ||
210 | }; | ||
211 | struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
212 | GNUNET_GETOPT_OPTION_END | ||
213 | }; | ||
214 | |||
215 | GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-peer-1"); | ||
216 | GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-peer-2"); | ||
217 | |||
218 | ok = 1; | ||
219 | GNUNET_PROGRAM_run ((sizeof(argv) / sizeof(char *)) - 1, | ||
220 | argv, | ||
221 | "test-core-api-start-only", | ||
222 | "nohelp", | ||
223 | options, | ||
224 | &run, | ||
225 | &ok); | ||
226 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
227 | "Test finished\n"); | ||
228 | stop_arm (&p1); | ||
229 | stop_arm (&p2); | ||
230 | return ok; | ||
231 | } | ||
232 | |||
233 | |||
234 | int | ||
235 | main (int argc, | ||
236 | char *argv[]) | ||
237 | { | ||
238 | int ret; | ||
239 | |||
240 | GNUNET_log_setup ("test-core-api-start-only", | ||
241 | "WARNING", | ||
242 | NULL); | ||
243 | ret = check (); | ||
244 | GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-peer-1"); | ||
245 | GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-peer-2"); | ||
246 | return ret; | ||
247 | } | ||
248 | |||
249 | |||
250 | /* end of test_core_api_start_only.c */ | ||
diff --git a/src/core/test_core_defaults.conf b/src/core/test_core_defaults.conf deleted file mode 100644 index 7c7dad99e..000000000 --- a/src/core/test_core_defaults.conf +++ /dev/null | |||
@@ -1,22 +0,0 @@ | |||
1 | @INLINE@ ../../contrib/conf/gnunet/no_forcestart.conf | ||
2 | @INLINE@ ../../contrib/conf/gnunet/no_autostart_above_core.conf | ||
3 | |||
4 | [PATHS] | ||
5 | GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-core/ | ||
6 | |||
7 | [nat] | ||
8 | ENABLE_UPNP = NO | ||
9 | |||
10 | [ats] | ||
11 | WAN_QUOTA_IN = 1 GB | ||
12 | WAN_QUOTA_OUT = 1 GB | ||
13 | |||
14 | [transport-tcp] | ||
15 | BINDTO = 127.0.0.1 | ||
16 | |||
17 | [transport-udp] | ||
18 | BROADCAST = NO | ||
19 | |||
20 | [peerinfo] | ||
21 | NO_IO = YES | ||
22 | |||
diff --git a/src/core/test_core_quota_asymmetric_recv_limited_peer1.conf b/src/core/test_core_quota_asymmetric_recv_limited_peer1.conf deleted file mode 100644 index 766a2e73b..000000000 --- a/src/core/test_core_quota_asymmetric_recv_limited_peer1.conf +++ /dev/null | |||
@@ -1,54 +0,0 @@ | |||
1 | @INLINE@ test_core_defaults.conf | ||
2 | [PATHS] | ||
3 | GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-core-quota-asym-recv-lim-peer-1/ | ||
4 | |||
5 | [transport-tcp] | ||
6 | PORT = 12488 | ||
7 | |||
8 | [arm] | ||
9 | PORT = 12486 | ||
10 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-recv-p1-service-arm.sock | ||
11 | |||
12 | [statistics] | ||
13 | PORT = 12487 | ||
14 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-recv-p1-service-statistics.sock | ||
15 | |||
16 | [resolver] | ||
17 | PORT = 12484 | ||
18 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-recv-1-service-resolver.sock | ||
19 | |||
20 | [peerinfo] | ||
21 | PORT = 12489 | ||
22 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-recv-p1-service-peerinfo.sock | ||
23 | |||
24 | [transport] | ||
25 | PORT = 12485 | ||
26 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-recv-p1-service-transport.sock | ||
27 | |||
28 | [transport-udp] | ||
29 | PORT = 12489 | ||
30 | |||
31 | [ats] | ||
32 | PORT = 12491 | ||
33 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-recv-p1-service-ats.sock | ||
34 | # UNSPECIFIED | ||
35 | UNSPECIFIED_QUOTA_IN = 100 MiB | ||
36 | UNSPECIFIED_QUOTA_OUT = 100 MiB | ||
37 | # LOOPBACK | ||
38 | LOOPBACK_QUOTA_IN = 100 MiB | ||
39 | LOOPBACK_QUOTA_OUT = 100 MiB | ||
40 | # LAN | ||
41 | LAN_QUOTA_IN = 100 MiB | ||
42 | LAN_QUOTA_OUT = 100 MiB | ||
43 | # WAN | ||
44 | WAN_QUOTA_IN = 100 MiB | ||
45 | WAN_QUOTA_OUT = 100 MiB | ||
46 | # WLAN | ||
47 | WLAN_QUOTA_IN = 100 MiB | ||
48 | WLAN_QUOTA_OUT = 100 MiB | ||
49 | |||
50 | |||
51 | [core] | ||
52 | PORT = 12490 | ||
53 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-recv-p1-service-core.sock | ||
54 | |||
diff --git a/src/core/test_core_quota_asymmetric_recv_limited_peer2.conf b/src/core/test_core_quota_asymmetric_recv_limited_peer2.conf deleted file mode 100644 index 30c0bb81f..000000000 --- a/src/core/test_core_quota_asymmetric_recv_limited_peer2.conf +++ /dev/null | |||
@@ -1,57 +0,0 @@ | |||
1 | @INLINE@ test_core_defaults.conf | ||
2 | [PATHS] | ||
3 | GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-core-quota-asym-recv-lim-peer-2/ | ||
4 | |||
5 | |||
6 | [arm] | ||
7 | PORT = 22486 | ||
8 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-recv-p2-service-arm.sock | ||
9 | |||
10 | [statistics] | ||
11 | PORT = 22487 | ||
12 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-recv-p2-service-statistics.sock | ||
13 | |||
14 | [resolver] | ||
15 | PORT = 22484 | ||
16 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-recv-p2-service-resolver.sock | ||
17 | |||
18 | [peerinfo] | ||
19 | PORT = 22489 | ||
20 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-recv-p2-service-peerinfo.sock | ||
21 | |||
22 | [transport] | ||
23 | PORT = 22485 | ||
24 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-recv-p2-service-transport.sock | ||
25 | |||
26 | [core] | ||
27 | PORT = 22490 | ||
28 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-recv-p2-service-core.sock | ||
29 | |||
30 | [ats] | ||
31 | PORT = 22491 | ||
32 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-recv-p2-service-ats.sock | ||
33 | # UNSPECIFIED | ||
34 | UNSPECIFIED_QUOTA_IN = 10 MiB | ||
35 | UNSPECIFIED_QUOTA_OUT = 10 MiB | ||
36 | # LOOPBACK | ||
37 | LOOPBACK_QUOTA_IN = 10 MiB | ||
38 | LOOPBACK_QUOTA_OUT = 10 MiB | ||
39 | # LAN | ||
40 | LAN_QUOTA_IN = 10 MiB | ||
41 | LAN_QUOTA_OUT = 10 MiB | ||
42 | # WAN | ||
43 | WAN_QUOTA_IN = 10 MiB | ||
44 | WAN_QUOTA_OUT = 10 MiB | ||
45 | # WLAN | ||
46 | WLAN_QUOTA_IN = 10 MiB | ||
47 | WLAN_QUOTA_OUT = 10 MiB | ||
48 | |||
49 | [transport-tcp] | ||
50 | PORT = 22467 | ||
51 | |||
52 | [transport-http] | ||
53 | PORT = 22469 | ||
54 | |||
55 | [transport-tcp] | ||
56 | PORT = 22468 | ||
57 | |||
diff --git a/src/core/test_core_quota_asymmetric_send_limit_peer1.conf b/src/core/test_core_quota_asymmetric_send_limit_peer1.conf deleted file mode 100644 index 4a9f483d6..000000000 --- a/src/core/test_core_quota_asymmetric_send_limit_peer1.conf +++ /dev/null | |||
@@ -1,52 +0,0 @@ | |||
1 | @INLINE@ test_core_defaults.conf | ||
2 | [PATHS] | ||
3 | GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-core-quota-asym-send-lim-peer-1/ | ||
4 | |||
5 | [transport-tcp] | ||
6 | PORT = 12488 | ||
7 | |||
8 | [transport-udp] | ||
9 | PORT = 12492 | ||
10 | |||
11 | [arm] | ||
12 | PORT = 12486 | ||
13 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-send-p1-service-arm.sock | ||
14 | |||
15 | [statistics] | ||
16 | PORT = 12487 | ||
17 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-send-p1-service-statistics.sock | ||
18 | |||
19 | [resolver] | ||
20 | PORT = 12484 | ||
21 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-send-1-service-resolver.sock | ||
22 | |||
23 | [peerinfo] | ||
24 | PORT = 12489 | ||
25 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-send-p1-service-peerinfo.sock | ||
26 | |||
27 | [transport] | ||
28 | PORT = 12485 | ||
29 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-send-p1-service-transport.sock | ||
30 | |||
31 | [ats] | ||
32 | PORT = 12491 | ||
33 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-send-p1-service-ats.sock | ||
34 | # UNSPECIFIED | ||
35 | UNSPECIFIED_QUOTA_IN = 10 MiB | ||
36 | UNSPECIFIED_QUOTA_OUT = 10 MiB | ||
37 | # LOOPBACK | ||
38 | LOOPBACK_QUOTA_IN = 10 MiB | ||
39 | LOOPBACK_QUOTA_OUT = 10 MiB | ||
40 | # LAN | ||
41 | LAN_QUOTA_IN = 10 MiB | ||
42 | LAN_QUOTA_OUT = 10 MiB | ||
43 | # WAN | ||
44 | WAN_QUOTA_IN = 10 MiB | ||
45 | WAN_QUOTA_OUT = 10 MiB | ||
46 | # WLAN | ||
47 | WLAN_QUOTA_IN = 10 MiB | ||
48 | WLAN_QUOTA_OUT = 10 MiB | ||
49 | |||
50 | [core] | ||
51 | PORT = 12490 | ||
52 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-send-p1-service-core.sock | ||
diff --git a/src/core/test_core_quota_asymmetric_send_limit_peer2.conf b/src/core/test_core_quota_asymmetric_send_limit_peer2.conf deleted file mode 100644 index 36434461c..000000000 --- a/src/core/test_core_quota_asymmetric_send_limit_peer2.conf +++ /dev/null | |||
@@ -1,61 +0,0 @@ | |||
1 | @INLINE@ test_core_defaults.conf | ||
2 | [PATHS] | ||
3 | GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-core-quota-asym-send-lim-peer-2/ | ||
4 | |||
5 | [arm] | ||
6 | PORT = 22486 | ||
7 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-send-p2-service-arm.sock | ||
8 | |||
9 | [statistics] | ||
10 | PORT = 22487 | ||
11 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-send-p2-service-statistics.sock | ||
12 | |||
13 | [resolver] | ||
14 | PORT = 22484 | ||
15 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-send-p2-service-resolver.sock | ||
16 | |||
17 | [peerinfo] | ||
18 | PORT = 22489 | ||
19 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-send-p2-service-peerinfo.sock | ||
20 | |||
21 | [transport] | ||
22 | PORT = 22485 | ||
23 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-send-p2-service-transport.sock | ||
24 | |||
25 | [core] | ||
26 | PORT = 22490 | ||
27 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-send-p2-service-core.sock | ||
28 | |||
29 | [ats] | ||
30 | PORT = 22491 | ||
31 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-send-p2-service-ats.sock | ||
32 | WAN_QUOTA_IN = 100 MiB | ||
33 | WAN_QUOTA_OUT = 100 MiB | ||
34 | |||
35 | [ats] | ||
36 | PORT = 12471 | ||
37 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-sym-p1-service-ats.sock | ||
38 | # UNSPECIFIED | ||
39 | UNSPECIFIED_QUOTA_IN = 100 MiB | ||
40 | UNSPECIFIED_QUOTA_OUT = 100 MiB | ||
41 | # LOOPBACK | ||
42 | LOOPBACK_QUOTA_IN = 100 MiB | ||
43 | LOOPBACK_QUOTA_OUT = 100 MiB | ||
44 | # LAN | ||
45 | LAN_QUOTA_IN = 100 MiB | ||
46 | LAN_QUOTA_OUT = 100 MiB | ||
47 | # WAN | ||
48 | WAN_QUOTA_IN = 100 MiB | ||
49 | WAN_QUOTA_OUT = 100 MiB | ||
50 | # WLAN | ||
51 | WLAN_QUOTA_IN = 100 MiB | ||
52 | WLAN_QUOTA_OUT = 100 MiB | ||
53 | |||
54 | [transport-tcp] | ||
55 | PORT = 22467 | ||
56 | |||
57 | [transport-udp] | ||
58 | PORT = 22468 | ||
59 | |||
60 | [transport-http] | ||
61 | PORT = 22469 | ||
diff --git a/src/core/test_core_quota_compliance.c b/src/core/test_core_quota_compliance.c deleted file mode 100644 index cf2da3d97..000000000 --- a/src/core/test_core_quota_compliance.c +++ /dev/null | |||
@@ -1,779 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2009, 2010, 2015, 2016 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | */ | ||
20 | /** | ||
21 | * @file core/test_core_quota_compliance.c | ||
22 | * @brief testcase for core_api.c focusing quota compliance on core level | ||
23 | * @author Christian Grothoff | ||
24 | */ | ||
25 | #include "platform.h" | ||
26 | #include "gnunet_arm_service.h" | ||
27 | #include "gnunet_core_service.h" | ||
28 | #include "gnunet_util_lib.h" | ||
29 | #include "gnunet_ats_service.h" | ||
30 | #include "gnunet_transport_service.h" | ||
31 | #include "gnunet_transport_hello_service.h" | ||
32 | #include "gnunet_statistics_service.h" | ||
33 | |||
34 | |||
35 | #define SYMMETRIC 0 | ||
36 | #define ASYMMETRIC_SEND_LIMITED 1 | ||
37 | #define ASYMMETRIC_RECV_LIMITED 2 | ||
38 | |||
39 | /** | ||
40 | * Note that this value must not significantly exceed | ||
41 | * 'MAX_PENDING' in 'gnunet-service-transport.c', otherwise | ||
42 | * messages may be dropped even for a reliable transport. | ||
43 | */ | ||
44 | #define TOTAL_MSGS (60000 * 10) | ||
45 | |||
46 | /** | ||
47 | * How long until we give up on transmitting the message? | ||
48 | */ | ||
49 | #define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300) | ||
50 | |||
51 | /** | ||
52 | * What delay do we request from the core service for transmission? | ||
53 | */ | ||
54 | #define FAST_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, \ | ||
55 | 150) | ||
56 | |||
57 | #define MTYPE 12345 | ||
58 | #define MESSAGESIZE (1024 - 8) | ||
59 | #define MEASUREMENT_LENGTH GNUNET_TIME_relative_multiply ( \ | ||
60 | GNUNET_TIME_UNIT_SECONDS, 30) | ||
61 | |||
62 | static unsigned long long total_bytes_sent; | ||
63 | static unsigned long long total_bytes_recv; | ||
64 | |||
65 | static struct GNUNET_TIME_Absolute start_time; | ||
66 | |||
67 | static struct GNUNET_SCHEDULER_Task *err_task; | ||
68 | |||
69 | static struct GNUNET_SCHEDULER_Task *measure_task; | ||
70 | |||
71 | |||
72 | struct PeerContext | ||
73 | { | ||
74 | struct GNUNET_CONFIGURATION_Handle *cfg; | ||
75 | struct GNUNET_CORE_Handle *ch; | ||
76 | struct GNUNET_MQ_Handle *mq; | ||
77 | struct GNUNET_TRANSPORT_OfferHelloHandle *oh; | ||
78 | struct GNUNET_PeerIdentity id; | ||
79 | struct GNUNET_MessageHeader *hello; | ||
80 | struct GNUNET_STATISTICS_Handle *stats; | ||
81 | struct GNUNET_TRANSPORT_HelloGetHandle *ghh; | ||
82 | struct GNUNET_ATS_ConnectivityHandle *ats; | ||
83 | struct GNUNET_ATS_ConnectivitySuggestHandle *ats_sh; | ||
84 | int connect_status; | ||
85 | struct GNUNET_OS_Process *arm_proc; | ||
86 | }; | ||
87 | |||
88 | static struct PeerContext p1; | ||
89 | static struct PeerContext p2; | ||
90 | |||
91 | static unsigned long long current_quota_p1_in; | ||
92 | static unsigned long long current_quota_p1_out; | ||
93 | static unsigned long long current_quota_p2_in; | ||
94 | static unsigned long long current_quota_p2_out; | ||
95 | |||
96 | static int ok; | ||
97 | static int test; | ||
98 | static int32_t tr_n; | ||
99 | |||
100 | static int running; | ||
101 | |||
102 | |||
103 | #if VERBOSE | ||
104 | #define OKPP do { ok++; GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, \ | ||
105 | "Now at stage %u at %s:%u\n", ok, __FILE__, \ | ||
106 | __LINE__); } while (0) | ||
107 | #else | ||
108 | #define OKPP do { ok++; } while (0) | ||
109 | #endif | ||
110 | |||
111 | struct TestMessage | ||
112 | { | ||
113 | struct GNUNET_MessageHeader header; | ||
114 | uint32_t num GNUNET_PACKED; | ||
115 | uint8_t pad[MESSAGESIZE]; | ||
116 | }; | ||
117 | |||
118 | |||
119 | static void | ||
120 | terminate_peer (struct PeerContext *p) | ||
121 | { | ||
122 | if (NULL != p->ch) | ||
123 | { | ||
124 | GNUNET_CORE_disconnect (p->ch); | ||
125 | p->ch = NULL; | ||
126 | } | ||
127 | if (NULL != p->ghh) | ||
128 | { | ||
129 | GNUNET_TRANSPORT_hello_get_cancel (p->ghh); | ||
130 | p->ghh = NULL; | ||
131 | } | ||
132 | if (NULL != p->oh) | ||
133 | { | ||
134 | GNUNET_TRANSPORT_offer_hello_cancel (p->oh); | ||
135 | p->oh = NULL; | ||
136 | } | ||
137 | if (NULL != p->ats_sh) | ||
138 | { | ||
139 | GNUNET_ATS_connectivity_suggest_cancel (p->ats_sh); | ||
140 | p->ats_sh = NULL; | ||
141 | } | ||
142 | if (NULL != p->ats) | ||
143 | { | ||
144 | GNUNET_ATS_connectivity_done (p->ats); | ||
145 | p->ats = NULL; | ||
146 | } | ||
147 | if (NULL != p->stats) | ||
148 | { | ||
149 | GNUNET_STATISTICS_destroy (p->stats, GNUNET_NO); | ||
150 | p->stats = NULL; | ||
151 | } | ||
152 | if (NULL != p->hello) | ||
153 | { | ||
154 | GNUNET_free (p->hello); | ||
155 | p->hello = NULL; | ||
156 | } | ||
157 | } | ||
158 | |||
159 | |||
160 | static void | ||
161 | shutdown_task (void *cls) | ||
162 | { | ||
163 | if (NULL != err_task) | ||
164 | { | ||
165 | GNUNET_SCHEDULER_cancel (err_task); | ||
166 | err_task = NULL; | ||
167 | } | ||
168 | if (NULL != measure_task) | ||
169 | { | ||
170 | GNUNET_SCHEDULER_cancel (measure_task); | ||
171 | measure_task = NULL; | ||
172 | } | ||
173 | terminate_peer (&p1); | ||
174 | terminate_peer (&p2); | ||
175 | } | ||
176 | |||
177 | |||
178 | static void | ||
179 | terminate_task_error (void *cls) | ||
180 | { | ||
181 | err_task = NULL; | ||
182 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
183 | "Testcase failed (timeout)!\n"); | ||
184 | GNUNET_SCHEDULER_shutdown (); | ||
185 | ok = 42; | ||
186 | } | ||
187 | |||
188 | |||
189 | /** | ||
190 | * Callback function to process statistic values. | ||
191 | * | ||
192 | * @param cls closure | ||
193 | * @param subsystem name of subsystem that created the statistic | ||
194 | * @param name the name of the datum | ||
195 | * @param value the current value | ||
196 | * @param is_persistent #GNUNET_YES if the value is persistent, #GNUNET_NO if not | ||
197 | * @return #GNUNET_OK to continue, #GNUNET_SYSERR to abort iteration | ||
198 | */ | ||
199 | static int | ||
200 | print_stat (void *cls, | ||
201 | const char *subsystem, | ||
202 | const char *name, | ||
203 | uint64_t value, | ||
204 | int is_persistent) | ||
205 | { | ||
206 | if (cls == &p1) | ||
207 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
208 | "Peer1 %50s = %12llu\n", | ||
209 | name, | ||
210 | (unsigned long long) value); | ||
211 | if (cls == &p2) | ||
212 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
213 | "Peer2 %50s = %12llu\n", | ||
214 | name, | ||
215 | (unsigned long long) value); | ||
216 | return GNUNET_OK; | ||
217 | } | ||
218 | |||
219 | |||
220 | static void | ||
221 | measurement_stop (void *cls) | ||
222 | { | ||
223 | unsigned long long delta; | ||
224 | unsigned long long throughput_out; | ||
225 | unsigned long long throughput_in; | ||
226 | unsigned long long max_quota_in; | ||
227 | unsigned long long max_quota_out; | ||
228 | unsigned long long quota_delta; | ||
229 | enum GNUNET_ErrorType kind = GNUNET_ERROR_TYPE_DEBUG; | ||
230 | |||
231 | measure_task = NULL; | ||
232 | fprintf (stdout, "%s", "\n"); | ||
233 | running = GNUNET_NO; | ||
234 | |||
235 | delta = GNUNET_TIME_absolute_get_duration (start_time).rel_value_us; | ||
236 | if (0 == delta) | ||
237 | delta = 1; | ||
238 | throughput_out = total_bytes_sent * 1000000LL / delta; /* convert to bytes/s */ | ||
239 | throughput_in = total_bytes_recv * 1000000LL / delta; /* convert to bytes/s */ | ||
240 | |||
241 | max_quota_in = GNUNET_MIN (current_quota_p1_in, current_quota_p2_in); | ||
242 | max_quota_out = GNUNET_MIN (current_quota_p1_out, current_quota_p2_out); | ||
243 | if (max_quota_out < max_quota_in) | ||
244 | quota_delta = max_quota_in / 3; | ||
245 | else | ||
246 | quota_delta = max_quota_out / 3; | ||
247 | |||
248 | if ((throughput_out > (max_quota_out + quota_delta)) || | ||
249 | (throughput_in > (max_quota_in + quota_delta))) | ||
250 | ok = 1; /* fail */ | ||
251 | else | ||
252 | ok = 0; /* pass */ | ||
253 | GNUNET_STATISTICS_get (p1.stats, | ||
254 | "core", | ||
255 | "# discarded CORE_SEND requests", | ||
256 | NULL, | ||
257 | &print_stat, | ||
258 | &p1); | ||
259 | GNUNET_STATISTICS_get (p1.stats, | ||
260 | "core", | ||
261 | "# discarded CORE_SEND request bytes", | ||
262 | NULL, | ||
263 | &print_stat, | ||
264 | &p1); | ||
265 | GNUNET_STATISTICS_get (p1.stats, | ||
266 | "core", | ||
267 | "# discarded lower priority CORE_SEND requests", | ||
268 | NULL, | ||
269 | &print_stat, | ||
270 | NULL); | ||
271 | GNUNET_STATISTICS_get (p1.stats, | ||
272 | "core", | ||
273 | "# discarded lower priority CORE_SEND request bytes", | ||
274 | NULL, | ||
275 | &print_stat, | ||
276 | &p1); | ||
277 | GNUNET_STATISTICS_get (p2.stats, | ||
278 | "core", | ||
279 | "# discarded CORE_SEND requests", | ||
280 | NULL, | ||
281 | &print_stat, | ||
282 | &p2); | ||
283 | |||
284 | GNUNET_STATISTICS_get (p2.stats, | ||
285 | "core", | ||
286 | "# discarded CORE_SEND request bytes", | ||
287 | NULL, | ||
288 | &print_stat, | ||
289 | &p2); | ||
290 | GNUNET_STATISTICS_get (p2.stats, | ||
291 | "core", | ||
292 | "# discarded lower priority CORE_SEND requests", | ||
293 | NULL, | ||
294 | &print_stat, | ||
295 | &p2); | ||
296 | GNUNET_STATISTICS_get (p2.stats, | ||
297 | "core", | ||
298 | "# discarded lower priority CORE_SEND request bytes", | ||
299 | NULL, | ||
300 | &print_stat, | ||
301 | &p2); | ||
302 | |||
303 | if (ok != 0) | ||
304 | kind = GNUNET_ERROR_TYPE_ERROR; | ||
305 | switch (test) | ||
306 | { | ||
307 | case SYMMETRIC: | ||
308 | GNUNET_log (kind, | ||
309 | "Core quota compliance test with symmetric quotas: %s\n", | ||
310 | (0 == ok) ? "PASSED" : "FAILED"); | ||
311 | break; | ||
312 | |||
313 | case ASYMMETRIC_SEND_LIMITED: | ||
314 | GNUNET_log (kind, | ||
315 | "Core quota compliance test with limited sender quota: %s\n", | ||
316 | (0 == ok) ? "PASSED" : "FAILED"); | ||
317 | break; | ||
318 | |||
319 | case ASYMMETRIC_RECV_LIMITED: | ||
320 | GNUNET_log (kind, | ||
321 | "Core quota compliance test with limited receiver quota: %s\n", | ||
322 | (0 == ok) ? "PASSED" : "FAILED"); | ||
323 | break; | ||
324 | } | ||
325 | ; | ||
326 | GNUNET_log (kind, | ||
327 | "Peer 1 send rate: %llu b/s (%llu bytes in %llu ms)\n", | ||
328 | throughput_out, | ||
329 | total_bytes_sent, | ||
330 | delta); | ||
331 | GNUNET_log (kind, | ||
332 | "Peer 1 send quota: %llu b/s\n", | ||
333 | current_quota_p1_out); | ||
334 | GNUNET_log (kind, | ||
335 | "Peer 2 receive rate: %llu b/s (%llu bytes in %llu ms)\n", | ||
336 | throughput_in, | ||
337 | total_bytes_recv, | ||
338 | delta); | ||
339 | GNUNET_log (kind, | ||
340 | "Peer 2 receive quota: %llu b/s\n", | ||
341 | current_quota_p2_in); | ||
342 | /* | ||
343 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Max. inbound quota allowed: %llu b/s\n",max_quota_in ); | ||
344 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,"Max. outbound quota allowed: %llu b/s\n",max_quota_out); | ||
345 | */ | ||
346 | GNUNET_SCHEDULER_shutdown (); | ||
347 | } | ||
348 | |||
349 | |||
350 | static void | ||
351 | do_transmit (void *cls) | ||
352 | { | ||
353 | struct TestMessage *hdr; | ||
354 | struct GNUNET_MQ_Envelope *env; | ||
355 | |||
356 | env = GNUNET_MQ_msg (hdr, | ||
357 | MTYPE); | ||
358 | hdr->num = htonl (tr_n); | ||
359 | memset (&hdr->pad, | ||
360 | tr_n, | ||
361 | MESSAGESIZE); | ||
362 | tr_n++; | ||
363 | GNUNET_SCHEDULER_cancel (err_task); | ||
364 | err_task = | ||
365 | GNUNET_SCHEDULER_add_delayed (TIMEOUT, | ||
366 | &terminate_task_error, | ||
367 | NULL); | ||
368 | total_bytes_sent += sizeof(struct TestMessage); | ||
369 | GNUNET_MQ_send (p1.mq, | ||
370 | env); | ||
371 | } | ||
372 | |||
373 | |||
374 | static void * | ||
375 | connect_notify (void *cls, | ||
376 | const struct GNUNET_PeerIdentity *peer, | ||
377 | struct GNUNET_MQ_Handle *mq) | ||
378 | { | ||
379 | struct PeerContext *pc = cls; | ||
380 | |||
381 | if (0 == memcmp (&pc->id, | ||
382 | peer, | ||
383 | sizeof(struct GNUNET_PeerIdentity))) | ||
384 | return NULL; /* loopback */ | ||
385 | GNUNET_assert (0 == pc->connect_status); | ||
386 | pc->connect_status = 1; | ||
387 | pc->mq = mq; | ||
388 | if (pc == &p1) | ||
389 | { | ||
390 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
391 | "Encrypted connection established to peer `%s'\n", | ||
392 | GNUNET_i2s (peer)); | ||
393 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
394 | "Asking core (1) for transmission to peer `%s'\n", | ||
395 | GNUNET_i2s (&p2.id)); | ||
396 | GNUNET_SCHEDULER_cancel (err_task); | ||
397 | err_task = | ||
398 | GNUNET_SCHEDULER_add_delayed (TIMEOUT, | ||
399 | &terminate_task_error, | ||
400 | NULL); | ||
401 | start_time = GNUNET_TIME_absolute_get (); | ||
402 | running = GNUNET_YES; | ||
403 | measure_task = | ||
404 | GNUNET_SCHEDULER_add_delayed (MEASUREMENT_LENGTH, | ||
405 | &measurement_stop, | ||
406 | NULL); | ||
407 | do_transmit (NULL); | ||
408 | } | ||
409 | return pc; | ||
410 | } | ||
411 | |||
412 | |||
413 | static void | ||
414 | disconnect_notify (void *cls, | ||
415 | const struct GNUNET_PeerIdentity *peer, | ||
416 | void *internal_cls) | ||
417 | { | ||
418 | struct PeerContext *pc = cls; | ||
419 | |||
420 | if (NULL == internal_cls) | ||
421 | return; /* loopback */ | ||
422 | pc->connect_status = 0; | ||
423 | pc->mq = NULL; | ||
424 | if (NULL != measure_task) | ||
425 | { | ||
426 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
427 | "Measurement aborted due to disconnect!\n"); | ||
428 | GNUNET_SCHEDULER_cancel (measure_task); | ||
429 | measure_task = NULL; | ||
430 | } | ||
431 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
432 | "Encrypted connection to `%s' cut\n", | ||
433 | GNUNET_i2s (peer)); | ||
434 | } | ||
435 | |||
436 | |||
437 | static void | ||
438 | handle_test (void *cls, | ||
439 | const struct TestMessage *hdr) | ||
440 | { | ||
441 | static int n; | ||
442 | |||
443 | total_bytes_recv += sizeof(struct TestMessage); | ||
444 | if (ntohl (hdr->num) != n) | ||
445 | { | ||
446 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
447 | "Expected message %u, got message %u\n", | ||
448 | n, | ||
449 | ntohl (hdr->num)); | ||
450 | GNUNET_SCHEDULER_cancel (err_task); | ||
451 | err_task = GNUNET_SCHEDULER_add_now (&terminate_task_error, | ||
452 | NULL); | ||
453 | return; | ||
454 | } | ||
455 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
456 | "Got message %u\n", | ||
457 | ntohl (hdr->num)); | ||
458 | n++; | ||
459 | if (0 == (n % 10)) | ||
460 | fprintf (stderr, "%s", "."); | ||
461 | |||
462 | if (GNUNET_YES == running) | ||
463 | do_transmit (NULL); | ||
464 | } | ||
465 | |||
466 | |||
467 | static void | ||
468 | init_notify (void *cls, | ||
469 | const struct GNUNET_PeerIdentity *my_identity) | ||
470 | { | ||
471 | struct PeerContext *p = cls; | ||
472 | struct GNUNET_MQ_MessageHandler handlers[] = { | ||
473 | GNUNET_MQ_hd_fixed_size (test, | ||
474 | MTYPE, | ||
475 | struct TestMessage, | ||
476 | NULL), | ||
477 | GNUNET_MQ_handler_end () | ||
478 | }; | ||
479 | |||
480 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
481 | "Connection to CORE service of `%s' established\n", | ||
482 | GNUNET_i2s (my_identity)); | ||
483 | GNUNET_assert (NULL != my_identity); | ||
484 | p->id = *my_identity; | ||
485 | if (cls == &p1) | ||
486 | { | ||
487 | GNUNET_assert (ok == 2); | ||
488 | OKPP; | ||
489 | /* connect p2 */ | ||
490 | p2.ch = GNUNET_CORE_connect (p2.cfg, | ||
491 | &p2, | ||
492 | &init_notify, | ||
493 | &connect_notify, | ||
494 | &disconnect_notify, | ||
495 | handlers); | ||
496 | } | ||
497 | else | ||
498 | { | ||
499 | GNUNET_assert (ok == 3); | ||
500 | OKPP; | ||
501 | GNUNET_assert (cls == &p2); | ||
502 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
503 | "Asking core (1) to connect to peer `%s' and vice-versa\n", | ||
504 | GNUNET_i2s (&p2.id)); | ||
505 | p1.ats_sh = GNUNET_ATS_connectivity_suggest (p1.ats, | ||
506 | &p2.id, | ||
507 | 1); | ||
508 | p2.ats_sh = GNUNET_ATS_connectivity_suggest (p2.ats, | ||
509 | &p1.id, | ||
510 | 1); | ||
511 | } | ||
512 | } | ||
513 | |||
514 | |||
515 | static void | ||
516 | offer_hello_done (void *cls) | ||
517 | { | ||
518 | struct PeerContext *p = cls; | ||
519 | |||
520 | p->oh = NULL; | ||
521 | } | ||
522 | |||
523 | |||
524 | static void | ||
525 | process_hello (void *cls, | ||
526 | const struct GNUNET_MessageHeader *message) | ||
527 | { | ||
528 | struct PeerContext *p = cls; | ||
529 | |||
530 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
531 | "Received (my) HELLO from transport service\n"); | ||
532 | GNUNET_assert (message != NULL); | ||
533 | p->hello = GNUNET_malloc (ntohs (message->size)); | ||
534 | GNUNET_memcpy (p->hello, message, ntohs (message->size)); | ||
535 | if ((p == &p1) && | ||
536 | (NULL == p2.oh)) | ||
537 | p2.oh = GNUNET_TRANSPORT_offer_hello (p2.cfg, | ||
538 | message, | ||
539 | &offer_hello_done, | ||
540 | &p2); | ||
541 | if ((p == &p2) && | ||
542 | (NULL == p1.oh)) | ||
543 | p1.oh = GNUNET_TRANSPORT_offer_hello (p1.cfg, message, | ||
544 | &offer_hello_done, | ||
545 | &p1); | ||
546 | |||
547 | if ((p == &p1) && | ||
548 | (NULL != p2.hello) && | ||
549 | (NULL == p1.oh)) | ||
550 | p1.oh = GNUNET_TRANSPORT_offer_hello (p1.cfg, | ||
551 | p2.hello, | ||
552 | &offer_hello_done, | ||
553 | &p1); | ||
554 | if ((p == &p2) && | ||
555 | (NULL != p1.hello) && | ||
556 | (NULL == p2.oh)) | ||
557 | p2.oh = GNUNET_TRANSPORT_offer_hello (p2.cfg, | ||
558 | p1.hello, | ||
559 | &offer_hello_done, | ||
560 | &p2); | ||
561 | } | ||
562 | |||
563 | |||
564 | static void | ||
565 | setup_peer (struct PeerContext *p, | ||
566 | const char *cfgname) | ||
567 | { | ||
568 | char *binary; | ||
569 | |||
570 | binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-arm"); | ||
571 | p->cfg = GNUNET_CONFIGURATION_create (); | ||
572 | p->arm_proc = | ||
573 | GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_OUT_AND_ERR | ||
574 | | GNUNET_OS_USE_PIPE_CONTROL, | ||
575 | NULL, NULL, NULL, | ||
576 | binary, | ||
577 | "gnunet-service-arm", | ||
578 | "-c", | ||
579 | cfgname, | ||
580 | NULL); | ||
581 | GNUNET_assert (GNUNET_OK == | ||
582 | GNUNET_CONFIGURATION_load (p->cfg, | ||
583 | cfgname)); | ||
584 | p->stats = GNUNET_STATISTICS_create ("core", | ||
585 | p->cfg); | ||
586 | GNUNET_assert (NULL != p->stats); | ||
587 | p->ats = GNUNET_ATS_connectivity_init (p->cfg); | ||
588 | GNUNET_assert (NULL != p->ats); | ||
589 | p->ghh = GNUNET_TRANSPORT_hello_get (p->cfg, | ||
590 | GNUNET_TRANSPORT_AC_ANY, | ||
591 | &process_hello, | ||
592 | p); | ||
593 | GNUNET_free (binary); | ||
594 | } | ||
595 | |||
596 | |||
597 | static void | ||
598 | run (void *cls, | ||
599 | char *const *args, | ||
600 | const char *cfgfile, | ||
601 | const struct GNUNET_CONFIGURATION_Handle *cfg) | ||
602 | { | ||
603 | struct GNUNET_MQ_MessageHandler handlers[] = { | ||
604 | GNUNET_MQ_hd_fixed_size (test, | ||
605 | MTYPE, | ||
606 | struct TestMessage, | ||
607 | NULL), | ||
608 | GNUNET_MQ_handler_end () | ||
609 | }; | ||
610 | |||
611 | GNUNET_assert (ok == 1); | ||
612 | OKPP; | ||
613 | err_task = | ||
614 | GNUNET_SCHEDULER_add_delayed (TIMEOUT, | ||
615 | &terminate_task_error, | ||
616 | NULL); | ||
617 | GNUNET_SCHEDULER_add_shutdown (&shutdown_task, | ||
618 | NULL); | ||
619 | if (test == SYMMETRIC) | ||
620 | { | ||
621 | setup_peer (&p1, | ||
622 | "test_core_quota_peer1.conf"); | ||
623 | setup_peer (&p2, | ||
624 | "test_core_quota_peer2.conf"); | ||
625 | } | ||
626 | else if (test == ASYMMETRIC_SEND_LIMITED) | ||
627 | { | ||
628 | setup_peer (&p1, | ||
629 | "test_core_quota_asymmetric_send_limit_peer1.conf"); | ||
630 | setup_peer (&p2, | ||
631 | "test_core_quota_asymmetric_send_limit_peer2.conf"); | ||
632 | } | ||
633 | else if (test == ASYMMETRIC_RECV_LIMITED) | ||
634 | { | ||
635 | setup_peer (&p1, | ||
636 | "test_core_quota_asymmetric_recv_limited_peer1.conf"); | ||
637 | setup_peer (&p2, | ||
638 | "test_core_quota_asymmetric_recv_limited_peer2.conf"); | ||
639 | } | ||
640 | |||
641 | GNUNET_assert (test != -1); | ||
642 | GNUNET_assert (GNUNET_SYSERR != | ||
643 | GNUNET_CONFIGURATION_get_value_size (p1.cfg, | ||
644 | "ATS", | ||
645 | "WAN_QUOTA_IN", | ||
646 | ¤t_quota_p1_in)); | ||
647 | GNUNET_assert (GNUNET_SYSERR != | ||
648 | GNUNET_CONFIGURATION_get_value_size (p2.cfg, | ||
649 | "ATS", | ||
650 | "WAN_QUOTA_IN", | ||
651 | ¤t_quota_p2_in)); | ||
652 | GNUNET_assert (GNUNET_SYSERR != | ||
653 | GNUNET_CONFIGURATION_get_value_size (p1.cfg, | ||
654 | "ATS", | ||
655 | "WAN_QUOTA_OUT", | ||
656 | ¤t_quota_p1_out)); | ||
657 | GNUNET_assert (GNUNET_SYSERR != | ||
658 | GNUNET_CONFIGURATION_get_value_size (p2.cfg, | ||
659 | "ATS", | ||
660 | "WAN_QUOTA_OUT", | ||
661 | ¤t_quota_p2_out)); | ||
662 | |||
663 | p1.ch = GNUNET_CORE_connect (p1.cfg, | ||
664 | &p1, | ||
665 | &init_notify, | ||
666 | &connect_notify, | ||
667 | &disconnect_notify, | ||
668 | handlers); | ||
669 | } | ||
670 | |||
671 | |||
672 | static void | ||
673 | stop_arm (struct PeerContext *p) | ||
674 | { | ||
675 | if (0 != GNUNET_OS_process_kill (p->arm_proc, | ||
676 | GNUNET_TERM_SIG)) | ||
677 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, | ||
678 | "kill"); | ||
679 | if (GNUNET_OK != | ||
680 | GNUNET_OS_process_wait (p->arm_proc)) | ||
681 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, | ||
682 | "waitpid"); | ||
683 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
684 | "ARM process %u stopped\n", | ||
685 | GNUNET_OS_process_get_pid (p->arm_proc)); | ||
686 | GNUNET_OS_process_destroy (p->arm_proc); | ||
687 | p->arm_proc = NULL; | ||
688 | GNUNET_CONFIGURATION_destroy (p->cfg); | ||
689 | } | ||
690 | |||
691 | |||
692 | static int | ||
693 | check () | ||
694 | { | ||
695 | char *const argv[] = { | ||
696 | "test-core-quota-compliance", | ||
697 | "-c", | ||
698 | "test_core_api_data.conf", | ||
699 | NULL | ||
700 | }; | ||
701 | struct GNUNET_GETOPT_CommandLineOption options[] = { | ||
702 | GNUNET_GETOPT_OPTION_END | ||
703 | }; | ||
704 | |||
705 | ok = 1; | ||
706 | GNUNET_PROGRAM_run ((sizeof(argv) / sizeof(char *)) - 1, | ||
707 | argv, | ||
708 | "test-core-quota-compliance", | ||
709 | "nohelp", | ||
710 | options, | ||
711 | &run, | ||
712 | &ok); | ||
713 | stop_arm (&p1); | ||
714 | stop_arm (&p2); | ||
715 | return ok; | ||
716 | } | ||
717 | |||
718 | |||
719 | static void | ||
720 | cleanup_directory (int test) | ||
721 | { | ||
722 | switch (test) | ||
723 | { | ||
724 | case SYMMETRIC: | ||
725 | GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-quota-sym-peer-1/"); | ||
726 | GNUNET_DISK_directory_remove ("/tmp/test-gnunet-core-quota-sym-peer-2/"); | ||
727 | break; | ||
728 | |||
729 | case ASYMMETRIC_SEND_LIMITED: | ||
730 | GNUNET_DISK_directory_remove | ||
731 | ("/tmp/test-gnunet-core-quota-asym-send-lim-peer-1/"); | ||
732 | GNUNET_DISK_directory_remove | ||
733 | ("/tmp/test-gnunet-core-quota-asym-send-lim-peer-2/"); | ||
734 | break; | ||
735 | |||
736 | case ASYMMETRIC_RECV_LIMITED: | ||
737 | GNUNET_DISK_directory_remove | ||
738 | ("/tmp/test-gnunet-core-quota-asym-recv-lim-peer-1/"); | ||
739 | GNUNET_DISK_directory_remove | ||
740 | ("/tmp/test-gnunet-core-quota-asym-recv-lim-peer-2/"); | ||
741 | break; | ||
742 | } | ||
743 | } | ||
744 | |||
745 | |||
746 | int | ||
747 | main (int argc, | ||
748 | char *argv[]) | ||
749 | { | ||
750 | int ret; | ||
751 | |||
752 | test = -1; | ||
753 | if (NULL != strstr (argv[0], | ||
754 | "_symmetric")) | ||
755 | { | ||
756 | test = SYMMETRIC; | ||
757 | } | ||
758 | else if (NULL != strstr (argv[0], | ||
759 | "_asymmetric_send")) | ||
760 | { | ||
761 | test = ASYMMETRIC_SEND_LIMITED; | ||
762 | } | ||
763 | else if (NULL != strstr (argv[0], | ||
764 | "_asymmetric_recv")) | ||
765 | { | ||
766 | test = ASYMMETRIC_RECV_LIMITED; | ||
767 | } | ||
768 | GNUNET_assert (test != -1); | ||
769 | cleanup_directory (test); | ||
770 | GNUNET_log_setup ("test-core-quota-compliance", | ||
771 | "WARNING", | ||
772 | NULL); | ||
773 | ret = check (); | ||
774 | cleanup_directory (test); | ||
775 | return ret; | ||
776 | } | ||
777 | |||
778 | |||
779 | /* end of test_core_quota_compliance.c */ | ||
diff --git a/src/core/test_core_quota_peer1.conf b/src/core/test_core_quota_peer1.conf deleted file mode 100644 index ec592f778..000000000 --- a/src/core/test_core_quota_peer1.conf +++ /dev/null | |||
@@ -1,58 +0,0 @@ | |||
1 | @INLINE@ test_core_defaults.conf | ||
2 | [PATHS] | ||
3 | GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-core-peer-1/ | ||
4 | |||
5 | [arm] | ||
6 | PORT = 12460 | ||
7 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock | ||
8 | |||
9 | [statistics] | ||
10 | PORT = 12461 | ||
11 | |||
12 | [resolver] | ||
13 | PORT = 12462 | ||
14 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock | ||
15 | |||
16 | [peerinfo] | ||
17 | PORT = 12463 | ||
18 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock | ||
19 | |||
20 | [transport] | ||
21 | PORT = 12464 | ||
22 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock | ||
23 | |||
24 | [core] | ||
25 | PORT = 12475 | ||
26 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-core.sock | ||
27 | |||
28 | [ats] | ||
29 | PORT = 12476 | ||
30 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-ats.sock | ||
31 | # UNSPECIFIED | ||
32 | UNSPECIFIED_QUOTA_IN = 10 MiB | ||
33 | UNSPECIFIED_QUOTA_OUT = 10 MiB | ||
34 | # LOOPBACK | ||
35 | LOOPBACK_QUOTA_IN = 10 MiB | ||
36 | LOOPBACK_QUOTA_OUT = 10 MiB | ||
37 | # LAN | ||
38 | LAN_QUOTA_IN = 10 MiB | ||
39 | LAN_QUOTA_OUT = 10 MiB | ||
40 | # WAN | ||
41 | WAN_QUOTA_IN = 10 MiB | ||
42 | WAN_QUOTA_OUT = 10 MiB | ||
43 | # WLAN | ||
44 | WLAN_QUOTA_IN = 10 MiB | ||
45 | WLAN_QUOTA_OUT = 10 MiB | ||
46 | |||
47 | |||
48 | [transport-tcp] | ||
49 | PORT = 12467 | ||
50 | |||
51 | [transport-udp] | ||
52 | PORT = 12468 | ||
53 | |||
54 | [transport-unix] | ||
55 | PORT = 12469 | ||
56 | |||
57 | [transport-http] | ||
58 | PORT = 12470 | ||
diff --git a/src/core/test_core_quota_peer2.conf b/src/core/test_core_quota_peer2.conf deleted file mode 100644 index 65d0710bb..000000000 --- a/src/core/test_core_quota_peer2.conf +++ /dev/null | |||
@@ -1,59 +0,0 @@ | |||
1 | @INLINE@ test_core_defaults.conf | ||
2 | [PATHS] | ||
3 | GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-core-peer-2/ | ||
4 | |||
5 | [arm] | ||
6 | PORT = 22460 | ||
7 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock | ||
8 | |||
9 | [statistics] | ||
10 | PORT = 22461 | ||
11 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock | ||
12 | |||
13 | [resolver] | ||
14 | PORT = 22462 | ||
15 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock | ||
16 | |||
17 | [peerinfo] | ||
18 | PORT = 22463 | ||
19 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock | ||
20 | |||
21 | [transport] | ||
22 | PORT = 22464 | ||
23 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock | ||
24 | |||
25 | [core] | ||
26 | PORT = 22475 | ||
27 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-core.sock | ||
28 | |||
29 | [ats] | ||
30 | PORT = 22476 | ||
31 | UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-ats.sock | ||
32 | # UNSPECIFIED | ||
33 | UNSPECIFIED_QUOTA_IN = 10 MiB | ||
34 | UNSPECIFIED_QUOTA_OUT = 10 MiB | ||
35 | # LOOPBACK | ||
36 | LOOPBACK_QUOTA_IN = 10 MiB | ||
37 | LOOPBACK_QUOTA_OUT = 10 MiB | ||
38 | # LAN | ||
39 | LAN_QUOTA_IN = 10 MiB | ||
40 | LAN_QUOTA_OUT = 10 MiB | ||
41 | # WAN | ||
42 | WAN_QUOTA_IN = 10 MiB | ||
43 | WAN_QUOTA_OUT = 10 MiB | ||
44 | # WLAN | ||
45 | WLAN_QUOTA_IN = 10 MiB | ||
46 | WLAN_QUOTA_OUT = 10 MiB | ||
47 | |||
48 | |||
49 | [transport-tcp] | ||
50 | PORT = 22467 | ||
51 | |||
52 | [transport-udp] | ||
53 | PORT = 22468 | ||
54 | |||
55 | [transport-unix] | ||
56 | PORT = 22469 | ||
57 | |||
58 | [transport-http] | ||
59 | PORT = 22470 | ||