aboutsummaryrefslogtreecommitdiff
path: root/src/service/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/service/core')
-rw-r--r--src/service/core/.gitignore9
-rw-r--r--src/service/core/Makefile.am131
-rw-r--r--src/service/core/core.conf.in23
-rw-r--r--src/service/core/core.h326
-rw-r--r--src/service/core/core_api.c772
-rw-r--r--src/service/core/core_api_cmd_connecting_peers.c277
-rw-r--r--src/service/core/core_api_monitor_peers.c196
-rw-r--r--src/service/core/gnunet-service-core.c988
-rw-r--r--src/service/core/gnunet-service-core.h198
-rw-r--r--src/service/core/gnunet-service-core_kx.c1945
-rw-r--r--src/service/core/gnunet-service-core_kx.h102
-rw-r--r--src/service/core/gnunet-service-core_sessions.c1028
-rw-r--r--src/service/core/gnunet-service-core_sessions.h183
-rw-r--r--src/service/core/gnunet-service-core_typemap.c370
-rw-r--r--src/service/core/gnunet-service-core_typemap.h162
-rw-r--r--src/service/core/meson.build113
-rw-r--r--src/service/core/test_core_api.c348
-rw-r--r--src/service/core/test_core_api_data.conf11
-rw-r--r--src/service/core/test_core_api_peer1.conf38
-rw-r--r--src/service/core/test_core_api_peer2.conf39
-rw-r--r--src/service/core/test_core_api_reliability.c537
-rw-r--r--src/service/core/test_core_api_send_to_self.c195
-rw-r--r--src/service/core/test_core_api_send_to_self.conf19
-rw-r--r--src/service/core/test_core_api_start_only.c258
-rw-r--r--src/service/core/test_core_defaults.conf22
-rw-r--r--src/service/core/test_core_just_run.conf55
-rw-r--r--src/service/core/test_core_just_run_host.conf45
-rw-r--r--src/service/core/test_core_plugin_cmd_just_run.c391
-rw-r--r--src/service/core/test_core_quota_asymmetric_recv_limited_peer1.conf54
-rw-r--r--src/service/core/test_core_quota_asymmetric_recv_limited_peer2.conf57
-rw-r--r--src/service/core/test_core_quota_asymmetric_send_limit_peer1.conf52
-rw-r--r--src/service/core/test_core_quota_asymmetric_send_limit_peer2.conf61
-rw-r--r--src/service/core/test_core_quota_compliance.c788
-rw-r--r--src/service/core/test_core_quota_peer1.conf58
-rw-r--r--src/service/core/test_core_quota_peer2.conf59
-rwxr-xr-xsrc/service/core/test_core_start_testcase.sh15
36 files changed, 9925 insertions, 0 deletions
diff --git a/src/service/core/.gitignore b/src/service/core/.gitignore
new file mode 100644
index 000000000..e985f5ff4
--- /dev/null
+++ b/src/service/core/.gitignore
@@ -0,0 +1,9 @@
1gnunet-service-core
2core.conf
3test_core_api
4test_core_api_reliability
5test_core_api_send_to_self
6test_core_api_start_only
7test_core_quota_compliance_asymmetric_recv_limited
8test_core_quota_compliance_asymmetric_send_limited
9test_core_quota_compliance_symmetric
diff --git a/src/service/core/Makefile.am b/src/service/core/Makefile.am
new file mode 100644
index 000000000..95f22c82c
--- /dev/null
+++ b/src/service/core/Makefile.am
@@ -0,0 +1,131 @@
1# This Makefile.am is in the public domain
2AM_CPPFLAGS = -I$(top_srcdir)/src/include
3
4pkgcfgdir= $(pkgdatadir)/config.d/
5
6plugindir = $(libdir)/gnunet
7
8libexecdir= $(pkglibdir)/libexec/
9
10pkgcfg_DATA = \
11 core.conf
12
13if USE_COVERAGE
14 AM_CFLAGS = --coverage -O0
15 XLIB = -lgcov
16endif
17
18plugin_LTLIBRARIES = \
19 libgnunet_test_core_plugin_cmd_just_run.la
20
21TESTING_LIBS = \
22 libgnunetcoretesting.la
23
24lib_LTLIBRARIES = \
25 libgnunetcore.la \
26 $(TESTING_LIBS)
27
28libgnunetcore_la_SOURCES = \
29 core_api.c core.h \
30 core_api_monitor_peers.c
31libgnunetcore_la_LIBADD = \
32 $(top_builddir)/src/lib/util/libgnunetutil.la \
33 $(GN_LIBINTL) $(XLIB)
34libgnunetcore_la_LDFLAGS = \
35 $(GN_LIB_LDFLAGS) \
36 -version-info 0:1:0
37
38libgnunet_test_core_plugin_cmd_just_run_la_SOURCES = \
39 test_core_plugin_cmd_just_run.c
40libgnunet_test_core_plugin_cmd_just_run_la_LIBADD = \
41 libgnunetcoretesting.la \
42 $(top_builddir)/src/service/transport/libgnunettransportapplication.la \
43 $(top_builddir)/src/service/transport/libgnunettransportcore.la \
44 $(top_builddir)/src/lib/hello/libgnunethello.la \
45 $(top_builddir)/src/service/peerstore/libgnunetpeerstore.la \
46 $(top_builddir)/src/service/transport/libgnunettransporttesting2.la \
47 $(top_builddir)/src/lib/testing/libgnunettesting.la \
48 $(top_builddir)/src/service/statistics/libgnunetstatistics.la \
49 $(top_builddir)/src/service/arm/libgnunetarm.la \
50 $(top_builddir)/src/lib/util/libgnunetutil.la \
51 $(LTLIBINTL)
52libgnunet_test_core_plugin_cmd_just_run_la_LDFLAGS = \
53 $(GN_PLUGIN_LDFLAGS)
54
55libgnunetcoretesting_la_SOURCES = \
56 core_api_cmd_connecting_peers.c
57libgnunetcoretesting_la_LIBADD = \
58 $(top_builddir)/src/lib/testing/libgnunettesting.la \
59 $(top_builddir)/src/service/arm/libgnunetarm.la \
60 $(top_builddir)/src/service/transport/libgnunettransportapplication.la \
61 $(top_builddir)/src/service/transport/libgnunettransporttesting2.la \
62 $(top_builddir)/src/lib/hello/libgnunethello.la \
63 $(top_builddir)/src/service/peerstore/libgnunetpeerstore.la \
64 $(top_builddir)/src/service/transport/libgnunettransportcore.la \
65 $(top_builddir)/src/lib/util/libgnunetutil.la
66libgnunetcoretesting_la_LDFLAGS = \
67 $(GN_LIBINTL) \
68 $(GN_LIB_LDFLAGS) \
69 -version-info 0:0:0
70
71
72libexec_PROGRAMS = \
73 gnunet-service-core
74
75gnunet_service_core_SOURCES = \
76 gnunet-service-core.c gnunet-service-core.h \
77 gnunet-service-core_kx.c gnunet-service-core_kx.h \
78 gnunet-service-core_sessions.c gnunet-service-core_sessions.h \
79 gnunet-service-core_typemap.c gnunet-service-core_typemap.h
80gnunet_service_core_LDADD = \
81 $(top_builddir)/src/service/statistics/libgnunetstatistics.la \
82 $(top_builddir)/src/service/transport/libgnunettransportapplication.la \
83 $(top_builddir)/src/service/transport/libgnunettransportcore.la \
84 $(top_builddir)/src/lib/util/libgnunetutil.la \
85 $(GN_LIBINTL) $(Z_LIBS)
86
87
88TESTING_TESTS = \
89 test_core_api_send_to_self
90
91check_PROGRAMS = \
92 test_core_api_start_only \
93 $(TESTING_TESTS)
94
95# Only test TNG if we run experimental
96#check_SCRIPTS= \
97# test_core_start_testcase.sh
98
99if ENABLE_TEST_RUN
100AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
101TESTS = $(check_PROGRAMS) \
102 $(check_SCRIPTS)
103endif
104
105test_core_api_send_to_self_SOURCES = \
106 test_core_api_send_to_self.c
107test_core_api_send_to_self_LDADD = \
108 libgnunetcore.la \
109 $(top_builddir)/src/lib/testing/libgnunettesting.la \
110 $(top_builddir)/src/lib/util/libgnunetutil.la
111
112test_core_api_start_only_SOURCES = \
113 test_core_api_start_only.c
114test_core_api_start_only_LDADD = \
115 $(top_builddir)/src/lib/testing/libgnunettesting.la \
116 libgnunetcore.la \
117 $(top_builddir)/src/lib/util/libgnunetutil.la
118
119EXTRA_DIST = \
120 test_core_start_testcase.sh \
121 test_core_defaults.conf \
122 test_core_api_data.conf \
123 test_core_api_peer1.conf \
124 test_core_api_peer2.conf \
125 test_core_api_send_to_self.conf \
126 test_core_quota_asymmetric_recv_limited_peer1.conf \
127 test_core_quota_asymmetric_recv_limited_peer2.conf \
128 test_core_quota_asymmetric_send_limit_peer1.conf \
129 test_core_quota_asymmetric_send_limit_peer2.conf \
130 test_core_quota_peer1.conf \
131 test_core_quota_peer2.conf
diff --git a/src/service/core/core.conf.in b/src/service/core/core.conf.in
new file mode 100644
index 000000000..00faf6079
--- /dev/null
+++ b/src/service/core/core.conf.in
@@ -0,0 +1,23 @@
1[core]
2START_ON_DEMAND = @START_ON_DEMAND@
3@JAVAPORT@PORT = 2092
4HOSTNAME = localhost
5BINARY = gnunet-service-core
6ACCEPT_FROM = 127.0.0.1;
7ACCEPT_FROM6 = ::1;
8UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-core.sock
9UNIX_MATCH_UID = NO
10UNIX_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!).
23USE_EPHEMERAL_KEYS = YES
diff --git a/src/service/core/core.h b/src/service/core/core.h
new file mode 100644
index 000000000..d4596f038
--- /dev/null
+++ b/src/service/core/core.h
@@ -0,0 +1,326 @@
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_util_lib.h"
30#include "gnunet_time_lib.h"
31
32/**
33 * General core debugging.
34 */
35#define DEBUG_CORE GNUNET_EXTRA_LOGGING
36
37/**
38 * Definition of bits in the InitMessage's options field that specify
39 * which events this client cares about. Note that inbound messages
40 * for handlers that were specifically registered are always
41 * transmitted to the client.
42 */
43#define GNUNET_CORE_OPTION_NOTHING 0
44
45/**
46 * Client cares about connectivity changes.
47 */
48#define GNUNET_CORE_OPTION_SEND_STATUS_CHANGE 4
49
50/**
51 * Client wants all inbound messages in full.
52 */
53#define GNUNET_CORE_OPTION_SEND_FULL_INBOUND 8
54
55/**
56 * Client just wants the 4-byte message headers of
57 * all inbound messages.
58 */
59#define GNUNET_CORE_OPTION_SEND_HDR_INBOUND 16
60
61/**
62 * Client wants all outbound messages in full.
63 */
64#define GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND 32
65
66/**
67 * Client just wants the 4-byte message headers of
68 * all outbound messages.
69 */
70#define GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND 64
71
72
73GNUNET_NETWORK_STRUCT_BEGIN
74
75/**
76 * Message transmitted core clients to gnunet-service-core
77 * to start the interaction. This header is followed by
78 * uint16_t type values specifying which messages this
79 * client is interested in.
80 */
81struct InitMessage
82{
83 /**
84 * Header with type #GNUNET_MESSAGE_TYPE_CORE_INIT.
85 */
86 struct GNUNET_MessageHeader header;
87
88 /**
89 * Options, see GNUNET_CORE_OPTION_ values.
90 */
91 uint32_t options GNUNET_PACKED;
92};
93
94
95/**
96 * Message transmitted by the gnunet-service-core process
97 * to its clients in response to an INIT message.
98 */
99struct InitReplyMessage
100{
101 /**
102 * Header with type #GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY
103 */
104 struct GNUNET_MessageHeader header;
105
106 /**
107 * Always zero.
108 */
109 uint32_t reserved GNUNET_PACKED;
110
111 /**
112 * Public key of the local peer.
113 */
114 struct GNUNET_PeerIdentity my_identity;
115};
116
117
118/**
119 * Message sent by the service to clients to notify them
120 * about a peer connecting.
121 */
122struct ConnectNotifyMessage
123{
124 /**
125 * Header with type #GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT
126 */
127 struct GNUNET_MessageHeader header;
128
129 /**
130 * Always zero.
131 */
132 uint32_t reserved GNUNET_PACKED;
133
134 /**
135 * Identity of the connecting peer.
136 */
137 struct GNUNET_PeerIdentity peer;
138};
139
140
141/**
142 * Message sent by the service to clients to notify them
143 * about a peer disconnecting.
144 */
145struct DisconnectNotifyMessage
146{
147 /**
148 * Header with type #GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT.
149 */
150 struct GNUNET_MessageHeader header;
151
152 /**
153 * Always zero.
154 */
155 uint32_t reserved GNUNET_PACKED;
156
157 /**
158 * Identity of the connecting peer.
159 */
160 struct GNUNET_PeerIdentity peer;
161};
162
163
164/**
165 * Message sent by the service to clients to notify them about
166 * messages being received or transmitted. This overall message is
167 * followed by the real message, or just the header of the real
168 * message (depending on the client's preferences). The receiver can
169 * tell if it got the full message or only a partial message by
170 * looking at the size field in the header of NotifyTrafficMessage and
171 * checking it with the size field in the message that follows.
172 */
173struct NotifyTrafficMessage
174{
175 /**
176 * Header with type #GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND
177 * or #GNUNET_MESSAGE_TYPE_CORE_NOTIFY_OUTBOUND.
178 */
179 struct GNUNET_MessageHeader header;
180
181 /**
182 * Identity of the receiver or sender.
183 */
184 struct GNUNET_PeerIdentity peer;
185
186 /* Followed by payload (message or just header), variable size */
187};
188
189
190/**
191 * Client notifying core about the maximum-priority
192 * message it has in the queue for a particular target.
193 */
194struct SendMessageRequest
195{
196 /**
197 * Header with type #GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST
198 */
199 struct GNUNET_MessageHeader header;
200
201 /**
202 * How important is this message?
203 */
204 uint32_t priority GNUNET_PACKED;
205
206 /**
207 * By what time would the sender really like to see this
208 * message transmitted?
209 */
210 struct GNUNET_TIME_AbsoluteNBO deadline;
211
212 /**
213 * Identity of the intended target.
214 */
215 struct GNUNET_PeerIdentity peer;
216
217 /**
218 * Always zero.
219 */
220 uint32_t reserved GNUNET_PACKED;
221
222 /**
223 * How large is the message?
224 */
225 uint16_t size GNUNET_PACKED;
226
227 /**
228 * Counter for this peer to match SMRs to replies.
229 */
230 uint16_t smr_id GNUNET_PACKED;
231};
232
233
234/**
235 * Core notifying client that it is allowed to now
236 * transmit a message to the given target
237 * (response to #GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST).
238 */
239struct SendMessageReady
240{
241 /**
242 * Header with type #GNUNET_MESSAGE_TYPE_CORE_SEND_READY
243 */
244 struct GNUNET_MessageHeader header;
245
246 /**
247 * How many bytes are allowed for transmission?
248 * Guaranteed to be at least as big as the requested size,
249 * or ZERO if the request is rejected (will timeout,
250 * peer disconnected, queue full, etc.).
251 */
252 uint16_t size GNUNET_PACKED;
253
254 /**
255 * smr_id from the request.
256 */
257 uint16_t smr_id GNUNET_PACKED;
258
259 /**
260 * Identity of the intended target.
261 */
262 struct GNUNET_PeerIdentity peer;
263};
264
265
266/**
267 * Client asking core to transmit a particular message to a particular
268 * target (response to #GNUNET_MESSAGE_TYPE_CORE_SEND_READY).
269 */
270struct SendMessage
271{
272 /**
273 * Header with type #GNUNET_MESSAGE_TYPE_CORE_SEND
274 */
275 struct GNUNET_MessageHeader header;
276
277 /**
278 * How important is this message? Contains a
279 * `enum GNUNET_MQ_PriorityPreferences` in NBO.
280 */
281 uint32_t priority GNUNET_PACKED;
282
283 /**
284 * By what time would the sender really like to see this
285 * message transmitted?
286 */
287 struct GNUNET_TIME_AbsoluteNBO deadline;
288
289 /**
290 * Identity of the intended receiver.
291 */
292 struct GNUNET_PeerIdentity peer;
293};
294
295
296/**
297 * Message sent by the service to monitor clients to notify them
298 * about a peer changing status.
299 */
300struct MonitorNotifyMessage
301{
302 /**
303 * Header with type #GNUNET_MESSAGE_TYPE_CORE_MONITOR_NOTIFY
304 */
305 struct GNUNET_MessageHeader header;
306
307 /**
308 * New peer state, an `enum GNUNET_CORE_KxState` in NBO.
309 */
310 uint32_t state GNUNET_PACKED;
311
312 /**
313 * Identity of the peer.
314 */
315 struct GNUNET_PeerIdentity peer;
316
317 /**
318 * How long will we stay in this state (if nothing else happens)?
319 */
320 struct GNUNET_TIME_AbsoluteNBO timeout;
321};
322
323
324GNUNET_NETWORK_STRUCT_END
325#endif
326/* end of core.h */
diff --git a/src/service/core/core_api.c b/src/service/core/core_api.c
new file mode 100644
index 000000000..2e0bb1785
--- /dev/null
+++ b/src/service/core/core_api.c
@@ -0,0 +1,772 @@
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 */
38struct 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 */
77struct 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 */
153static void
154reconnect (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 */
162static void
163reconnect_task (void *cls)
164{
165 struct GNUNET_CORE_Handle *h = cls;
166
167 h->reconnect_task = NULL;
168 LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to CORE service after delay\n");
169 reconnect (h);
170}
171
172
173/**
174 * Notify clients about disconnect and free the entry for connected
175 * peer.
176 *
177 * @param cls the `struct GNUNET_CORE_Handle *`
178 * @param key the peer identity (not used)
179 * @param value the `struct PeerRecord` to free.
180 * @return #GNUNET_YES (continue)
181 */
182static int
183disconnect_and_free_peer_entry (void *cls,
184 const struct GNUNET_PeerIdentity *key,
185 void *value)
186{
187 struct GNUNET_CORE_Handle *h = cls;
188 struct PeerRecord *pr = value;
189
190 GNUNET_assert (pr->h == h);
191 if (NULL != h->disconnects)
192 h->disconnects (h->cls, &pr->peer, pr->client_cls);
193 GNUNET_assert (GNUNET_YES ==
194 GNUNET_CONTAINER_multipeermap_remove (h->peers, key, pr));
195 GNUNET_MQ_destroy (pr->mq);
196 GNUNET_assert (NULL == pr->mq);
197 if (NULL != pr->env)
198 {
199 GNUNET_MQ_discard (pr->env);
200 pr->env = NULL;
201 }
202 GNUNET_free (pr);
203 return GNUNET_YES;
204}
205
206
207/**
208 * Close down any existing connection to the CORE service and
209 * try re-establishing it later.
210 *
211 * @param h our handle
212 */
213static void
214reconnect_later (struct GNUNET_CORE_Handle *h)
215{
216 GNUNET_assert (NULL == h->reconnect_task);
217 if (NULL != h->mq)
218 {
219 GNUNET_MQ_destroy (h->mq);
220 h->mq = NULL;
221 }
222 GNUNET_assert (NULL == h->reconnect_task);
223 h->reconnect_task =
224 GNUNET_SCHEDULER_add_delayed (h->retry_backoff, &reconnect_task, h);
225 GNUNET_CONTAINER_multipeermap_iterate (h->peers,
226 &disconnect_and_free_peer_entry,
227 h);
228 h->retry_backoff = GNUNET_TIME_STD_BACKOFF (h->retry_backoff);
229}
230
231
232/**
233 * Error handler for the message queue to the CORE service.
234 * On errors, we reconnect.
235 *
236 * @param cls closure, a `struct GNUNET_CORE_Handle *`
237 * @param error error code
238 */
239static void
240handle_mq_error (void *cls, enum GNUNET_MQ_Error error)
241{
242 struct GNUNET_CORE_Handle *h = cls;
243
244 LOG (GNUNET_ERROR_TYPE_DEBUG, "MQ ERROR: %d\n", error);
245 reconnect_later (h);
246}
247
248
249/**
250 * Implement sending functionality of a message queue for
251 * us sending messages to a peer.
252 *
253 * @param mq the message queue
254 * @param msg the message to send
255 * @param impl_state state of the implementation
256 */
257static void
258core_mq_send_impl (struct GNUNET_MQ_Handle *mq,
259 const struct GNUNET_MessageHeader *msg,
260 void *impl_state)
261{
262 struct PeerRecord *pr = impl_state;
263 struct GNUNET_CORE_Handle *h = pr->h;
264 struct SendMessageRequest *smr;
265 struct SendMessage *sm;
266 struct GNUNET_MQ_Envelope *env;
267 uint16_t msize;
268 enum GNUNET_MQ_PriorityPreferences flags;
269
270 if (NULL == h->mq)
271 {
272 /* We're currently reconnecting, pretend this worked */
273 GNUNET_MQ_impl_send_continue (mq);
274 return;
275 }
276 GNUNET_assert (NULL == pr->env);
277 /* extract options from envelope */
278 env = GNUNET_MQ_get_current_envelope (mq);
279 flags = GNUNET_MQ_env_get_options (env);
280
281 /* check message size for sanity */
282 msize = ntohs (msg->size);
283 if (msize >= GNUNET_MAX_MESSAGE_SIZE - sizeof(struct SendMessage))
284 {
285 GNUNET_break (0);
286 GNUNET_MQ_impl_send_continue (mq);
287 return;
288 }
289
290 /* ask core for transmission */
291 LOG (GNUNET_ERROR_TYPE_DEBUG,
292 "Asking core for transmission of %u bytes to `%s'\n",
293 (unsigned int) msize,
294 GNUNET_i2s (&pr->peer));
295 env = GNUNET_MQ_msg (smr, GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST);
296 smr->priority = htonl ((uint32_t) flags);
297 smr->peer = pr->peer;
298 smr->size = htons (msize);
299 smr->smr_id = htons (++pr->smr_id_gen);
300 GNUNET_MQ_send (h->mq, env);
301
302 /* prepare message with actual transmission data */
303 pr->env = GNUNET_MQ_msg_nested_mh (sm, GNUNET_MESSAGE_TYPE_CORE_SEND, msg);
304 sm->priority = htonl ((uint32_t) flags);
305 sm->peer = pr->peer;
306 LOG (GNUNET_ERROR_TYPE_DEBUG,
307 "Calling get_message with buffer of %u bytes\n",
308 (unsigned int) msize);
309}
310
311
312/**
313 * Handle destruction of a message queue. Implementations must not
314 * free @a mq, but should take care of @a impl_state.
315 *
316 * @param mq the message queue to destroy
317 * @param impl_state state of the implementation
318 */
319static void
320core_mq_destroy_impl (struct GNUNET_MQ_Handle *mq, void *impl_state)
321{
322 struct PeerRecord *pr = impl_state;
323
324 GNUNET_assert (mq == pr->mq);
325 pr->mq = NULL;
326}
327
328
329/**
330 * Implementation function that cancels the currently sent message.
331 * Should basically undo whatever #mq_send_impl() did.
332 *
333 * @param mq message queue
334 * @param impl_state state specific to the implementation
335 */
336static void
337core_mq_cancel_impl (struct GNUNET_MQ_Handle *mq, void *impl_state)
338{
339 struct PeerRecord *pr = impl_state;
340
341 (void) mq;
342 GNUNET_assert (NULL != pr->env);
343 GNUNET_MQ_discard (pr->env);
344 pr->env = NULL;
345}
346
347
348/**
349 * We had an error processing a message we forwarded from a peer to
350 * the CORE service. We should just complain about it but otherwise
351 * continue processing.
352 *
353 * @param cls closure
354 * @param error error code
355 */
356static void
357core_mq_error_handler (void *cls, enum GNUNET_MQ_Error error)
358{
359 /* struct PeerRecord *pr = cls; */
360 (void) cls;
361 (void) error;
362 GNUNET_break_op (0);
363}
364
365
366/**
367 * Add the given peer to the list of our connected peers
368 * and create the respective data structures and notify
369 * the application.
370 *
371 * @param h the core handle
372 * @param peer the peer that is connecting to us
373 */
374static void
375connect_peer (struct GNUNET_CORE_Handle *h,
376 const struct GNUNET_PeerIdentity *peer)
377{
378 struct PeerRecord *pr;
379
380 pr = GNUNET_new (struct PeerRecord);
381 pr->peer = *peer;
382 pr->h = h;
383 GNUNET_assert (GNUNET_YES ==
384 GNUNET_CONTAINER_multipeermap_put (
385 h->peers,
386 &pr->peer,
387 pr,
388 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
389 pr->mq = GNUNET_MQ_queue_for_callbacks (&core_mq_send_impl,
390 &core_mq_destroy_impl,
391 &core_mq_cancel_impl,
392 pr,
393 h->handlers,
394 &core_mq_error_handler,
395 pr);
396 if (NULL != h->connects)
397 {
398 pr->client_cls = h->connects (h->cls, &pr->peer, pr->mq);
399 GNUNET_MQ_set_handlers_closure (pr->mq, pr->client_cls);
400 }
401}
402
403
404/**
405 * Handle init reply message received from CORE service. Notify
406 * application that we are now connected to the CORE. Also fake
407 * loopback connection.
408 *
409 * @param cls the `struct GNUNET_CORE_Handle`
410 * @param m the init reply
411 */
412static void
413handle_init_reply (void *cls, const struct InitReplyMessage *m)
414{
415 struct GNUNET_CORE_Handle *h = cls;
416 GNUNET_CORE_StartupCallback init;
417
418 GNUNET_break (0 == ntohl (m->reserved));
419 h->retry_backoff = GNUNET_TIME_UNIT_MILLISECONDS;
420 if (NULL != (init = h->init))
421 {
422 /* mark so we don't call init on reconnect */
423 h->init = NULL;
424 h->me = m->my_identity;
425 LOG (GNUNET_ERROR_TYPE_DEBUG,
426 "Connected to core service of peer `%s'.\n",
427 GNUNET_i2s (&h->me));
428 h->have_init = GNUNET_YES;
429 init (h->cls, &h->me);
430 }
431 else
432 {
433 LOG (GNUNET_ERROR_TYPE_DEBUG,
434 "Successfully reconnected to core service.\n");
435 if (GNUNET_NO == h->have_init)
436 {
437 h->me = m->my_identity;
438 h->have_init = GNUNET_YES;
439 }
440 else
441 {
442 GNUNET_break (0 == memcmp (&h->me,
443 &m->my_identity,
444 sizeof(struct GNUNET_PeerIdentity)));
445 }
446 }
447 /* fake 'connect to self' */
448 connect_peer (h, &h->me);
449}
450
451
452/**
453 * Handle connect message received from CORE service.
454 * Notify the application about the new connection.
455 *
456 * @param cls the `struct GNUNET_CORE_Handle`
457 * @param cnm the connect message
458 */
459static void
460handle_connect_notify (void *cls, const struct ConnectNotifyMessage *cnm)
461{
462 struct GNUNET_CORE_Handle *h = cls;
463 struct PeerRecord *pr;
464
465 LOG (GNUNET_ERROR_TYPE_DEBUG,
466 "Received notification about connection from `%s'.\n",
467 GNUNET_i2s (&cnm->peer));
468 if (0 == memcmp (&h->me, &cnm->peer, sizeof(struct GNUNET_PeerIdentity)))
469 {
470 /* connect to self!? */
471 GNUNET_break (0);
472 return;
473 }
474 pr = GNUNET_CONTAINER_multipeermap_get (h->peers, &cnm->peer);
475 if (NULL != pr)
476 {
477 GNUNET_break (0);
478 reconnect_later (h);
479 return;
480 }
481 connect_peer (h, &cnm->peer);
482}
483
484
485/**
486 * Handle disconnect message received from CORE service.
487 * Notify the application about the lost connection.
488 *
489 * @param cls the `struct GNUNET_CORE_Handle`
490 * @param dnm message about the disconnect event
491 */
492static void
493handle_disconnect_notify (void *cls, const struct DisconnectNotifyMessage *dnm)
494{
495 struct GNUNET_CORE_Handle *h = cls;
496 struct PeerRecord *pr;
497
498 if (0 == memcmp (&h->me, &dnm->peer, sizeof(struct GNUNET_PeerIdentity)))
499 {
500 /* disconnect from self!? */
501 GNUNET_break (0);
502 return;
503 }
504 GNUNET_break (0 == ntohl (dnm->reserved));
505 LOG (GNUNET_ERROR_TYPE_DEBUG,
506 "Received notification about disconnect from `%s'.\n",
507 GNUNET_i2s (&dnm->peer));
508 pr = GNUNET_CONTAINER_multipeermap_get (h->peers, &dnm->peer);
509 if (NULL == pr)
510 {
511 GNUNET_break (0);
512 reconnect_later (h);
513 return;
514 }
515 disconnect_and_free_peer_entry (h, &pr->peer, pr);
516}
517
518
519/**
520 * Check that message received from CORE service is well-formed.
521 *
522 * @param cls the `struct GNUNET_CORE_Handle`
523 * @param ntm the message we got
524 * @return #GNUNET_OK if the message is well-formed
525 */
526static int
527check_notify_inbound (void *cls, const struct NotifyTrafficMessage *ntm)
528{
529 uint16_t msize;
530 const struct GNUNET_MessageHeader *em;
531
532 (void) cls;
533 msize = ntohs (ntm->header.size) - sizeof(struct NotifyTrafficMessage);
534 if (msize < sizeof(struct GNUNET_MessageHeader))
535 {
536 GNUNET_break (0);
537 return GNUNET_SYSERR;
538 }
539 em = (const struct GNUNET_MessageHeader *) &ntm[1];
540 if (msize != ntohs (em->size))
541 {
542 GNUNET_break (0);
543 return GNUNET_SYSERR;
544 }
545 return GNUNET_OK;
546}
547
548
549/**
550 * Handle inbound message received from CORE service. If applicable,
551 * notify the application.
552 *
553 * @param cls the `struct GNUNET_CORE_Handle`
554 * @param ntm the message we got from CORE.
555 */
556static void
557handle_notify_inbound (void *cls, const struct NotifyTrafficMessage *ntm)
558{
559 struct GNUNET_CORE_Handle *h = cls;
560 const struct GNUNET_MessageHeader *em;
561 struct PeerRecord *pr;
562
563 LOG (GNUNET_ERROR_TYPE_DEBUG,
564 "Received inbound message from `%s'.\n",
565 GNUNET_i2s (&ntm->peer));
566 em = (const struct GNUNET_MessageHeader *) &ntm[1];
567 pr = GNUNET_CONTAINER_multipeermap_get (h->peers, &ntm->peer);
568 if (NULL == pr)
569 {
570 GNUNET_break (0);
571 reconnect_later (h);
572 return;
573 }
574 GNUNET_MQ_inject_message (pr->mq, em);
575}
576
577
578/**
579 * Handle message received from CORE service notifying us that we are
580 * now allowed to send a message to a peer. If that message is still
581 * pending, put it into the queue to be transmitted.
582 *
583 * @param cls the `struct GNUNET_CORE_Handle`
584 * @param smr the message we got
585 */
586static void
587handle_send_ready (void *cls, const struct SendMessageReady *smr)
588{
589 struct GNUNET_CORE_Handle *h = cls;
590 struct PeerRecord *pr;
591
592 pr = GNUNET_CONTAINER_multipeermap_get (h->peers, &smr->peer);
593 if (NULL == pr)
594 {
595 GNUNET_break (0);
596 reconnect_later (h);
597 return;
598 }
599 LOG (GNUNET_ERROR_TYPE_DEBUG,
600 "Received notification about transmission readiness to `%s'.\n",
601 GNUNET_i2s (&smr->peer));
602 if (NULL == pr->env)
603 {
604 /* request must have been cancelled between the original request
605 * and the response from CORE, ignore CORE's readiness */
606 return;
607 }
608 if (ntohs (smr->smr_id) != pr->smr_id_gen)
609 {
610 /* READY message is for expired or cancelled message,
611 * ignore! (we should have already sent another request) */
612 return;
613 }
614
615 /* ok, all good, send message out! */
616 GNUNET_MQ_send (h->mq, pr->env);
617 pr->env = NULL;
618 GNUNET_MQ_impl_send_continue (pr->mq);
619}
620
621
622/**
623 * Our current client connection went down. Clean it up and try to
624 * reconnect!
625 *
626 * @param h our handle to the core service
627 */
628static void
629reconnect (struct GNUNET_CORE_Handle *h)
630{
631 struct GNUNET_MQ_MessageHandler handlers[] =
632 { GNUNET_MQ_hd_fixed_size (init_reply,
633 GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY,
634 struct InitReplyMessage,
635 h),
636 GNUNET_MQ_hd_fixed_size (connect_notify,
637 GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT,
638 struct ConnectNotifyMessage,
639 h),
640 GNUNET_MQ_hd_fixed_size (disconnect_notify,
641 GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT,
642 struct DisconnectNotifyMessage,
643 h),
644 GNUNET_MQ_hd_var_size (notify_inbound,
645 GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND,
646 struct NotifyTrafficMessage,
647 h),
648 GNUNET_MQ_hd_fixed_size (send_ready,
649 GNUNET_MESSAGE_TYPE_CORE_SEND_READY,
650 struct SendMessageReady,
651 h),
652 GNUNET_MQ_handler_end () };
653 struct InitMessage *init;
654 struct GNUNET_MQ_Envelope *env;
655 uint16_t *ts;
656
657 GNUNET_assert (NULL == h->mq);
658 h->mq = GNUNET_CLIENT_connect (h->cfg, "core", handlers, &handle_mq_error, h);
659 if (NULL == h->mq)
660 {
661 reconnect_later (h);
662 return;
663 }
664 env = GNUNET_MQ_msg_extra (init,
665 sizeof(uint16_t) * h->hcnt,
666 GNUNET_MESSAGE_TYPE_CORE_INIT);
667 LOG (GNUNET_ERROR_TYPE_INFO, "(Re)connecting to CORE service\n");
668 init->options = htonl (0);
669 ts = (uint16_t *) &init[1];
670 for (unsigned int hpos = 0; hpos < h->hcnt; hpos++)
671 ts[hpos] = htons (h->handlers[hpos].type);
672 GNUNET_MQ_send (h->mq, env);
673}
674
675
676/**
677 * Connect to the core service. Note that the connection may complete
678 * (or fail) asynchronously.
679 *
680 * @param cfg configuration to use
681 * @param cls closure for the various callbacks that follow (including handlers in the handlers array)
682 * @param init callback to call once we have successfully
683 * connected to the core service
684 * @param connects function to call on peer connect, can be NULL
685 * @param disconnects function to call on peer disconnect / timeout, can be NULL
686 * @param handlers callbacks for messages we care about, NULL-terminated
687 * @return handle to the core service (only useful for disconnect until @a init is called);
688 * NULL on error (in this case, init is never called)
689 */
690struct GNUNET_CORE_Handle *
691GNUNET_CORE_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
692 void *cls,
693 GNUNET_CORE_StartupCallback init,
694 GNUNET_CORE_ConnectEventHandler connects,
695 GNUNET_CORE_DisconnectEventHandler disconnects,
696 const struct GNUNET_MQ_MessageHandler *handlers)
697{
698 struct GNUNET_CORE_Handle *h;
699
700 h = GNUNET_new (struct GNUNET_CORE_Handle);
701 h->cfg = cfg;
702 h->cls = cls;
703 h->init = init;
704 h->connects = connects;
705 h->disconnects = disconnects;
706 h->peers = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_NO);
707 h->handlers = GNUNET_MQ_copy_handlers (handlers);
708 h->hcnt = GNUNET_MQ_count_handlers (handlers);
709 GNUNET_assert (h->hcnt <
710 (GNUNET_MAX_MESSAGE_SIZE - sizeof(struct InitMessage))
711 / sizeof(uint16_t));
712 LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to CORE service\n");
713 reconnect (h);
714 if (NULL == h->mq)
715 {
716 GNUNET_CORE_disconnect (h);
717 return NULL;
718 }
719 return h;
720}
721
722
723/**
724 * Disconnect from the core service.
725 *
726 * @param handle connection to core to disconnect
727 */
728void
729GNUNET_CORE_disconnect (struct GNUNET_CORE_Handle *handle)
730{
731 LOG (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting from CORE service\n");
732 GNUNET_CONTAINER_multipeermap_iterate (handle->peers,
733 &disconnect_and_free_peer_entry,
734 handle);
735 GNUNET_CONTAINER_multipeermap_destroy (handle->peers);
736 handle->peers = NULL;
737 if (NULL != handle->reconnect_task)
738 {
739 GNUNET_SCHEDULER_cancel (handle->reconnect_task);
740 handle->reconnect_task = NULL;
741 }
742 if (NULL != handle->mq)
743 {
744 GNUNET_MQ_destroy (handle->mq);
745 handle->mq = NULL;
746 }
747 GNUNET_free (handle->handlers);
748 GNUNET_free (handle);
749}
750
751
752/**
753 * Obtain the message queue for a connected peer.
754 *
755 * @param h the core handle
756 * @param pid the identity of the peer to check if it has been connected to us
757 * @return NULL if peer is not connected
758 */
759struct GNUNET_MQ_Handle *
760GNUNET_CORE_get_mq (const struct GNUNET_CORE_Handle *h,
761 const struct GNUNET_PeerIdentity *pid)
762{
763 struct PeerRecord *pr;
764
765 pr = GNUNET_CONTAINER_multipeermap_get (h->peers, pid);
766 if (NULL == pr)
767 return NULL;
768 return pr->mq;
769}
770
771
772/* end of core_api.c */
diff --git a/src/service/core/core_api_cmd_connecting_peers.c b/src/service/core/core_api_cmd_connecting_peers.c
new file mode 100644
index 000000000..0d177a8e9
--- /dev/null
+++ b/src/service/core/core_api_cmd_connecting_peers.c
@@ -0,0 +1,277 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2021 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_api_cmd_connecting_peers.c
23 * @brief cmd to start a peer.
24 * @author t3sserakt
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_core_testing_lib.h"
29#include "gnunet_transport_testing_ng_lib.h"
30#include "gnunet_transport_application_service.h"
31#include "gnunet_transport_core_service.h"
32
33/**
34 * Generic logging shortcut
35 */
36#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__)
37
38
39/**
40 * The run method of this cmd will connect to peers.
41 *
42 */
43static void
44connect_peers_run (void *cls,
45 struct GNUNET_TESTING_Interpreter *is)
46{
47 struct GNUNET_TESTING_ConnectPeersState *cps = cls;
48 const struct GNUNET_TESTING_StartPeerState *sps;
49 const struct GNUNET_TESTING_Command *system_cmd;
50 const struct GNUNET_TESTING_System *tl_system;
51 const struct GNUNET_TESTING_Command *peer1_cmd;
52 struct GNUNET_PeerIdentity *peer;
53 enum GNUNET_NetworkType nt = 0;
54 struct GNUNET_TESTING_NodeConnection *pos_connection;
55 struct GNUNET_TESTING_AddressPrefix *pos_prefix;
56 const enum GNUNET_GenericReturnValue *broadcast;
57 unsigned int con_num = 0;
58 uint32_t num;
59 char *addr;
60 char *addr_and_port;
61 char *emsg = NULL;
62
63 cps->is = is;
64 peer1_cmd = GNUNET_TESTING_interpreter_lookup_command (is,
65 cps->start_peer_label);
66 GNUNET_TRANSPORT_TESTING_get_trait_broadcast (peer1_cmd,
67 &broadcast);
68 GNUNET_TRANSPORT_TESTING_get_trait_state (peer1_cmd,
69 &sps);
70
71 system_cmd = GNUNET_TESTING_interpreter_lookup_command (is,
72 cps->create_label);
73 GNUNET_TESTING_get_trait_test_system (system_cmd,
74 &tl_system);
75
76 cps->tl_system = tl_system;
77
78 LOG (GNUNET_ERROR_TYPE_DEBUG,
79 "cps->num: %u \n",
80 cps->num);
81
82
83 cps->ah = GNUNET_TRANSPORT_application_init (sps->cfg);
84 if (NULL == cps->ah)
85 {
86 LOG (GNUNET_ERROR_TYPE_ERROR,
87 "Failed to initialize the TRANSPORT application suggestion client handle for peer `%s': `%s'\n",
88 sps->cfgname,
89 emsg);
90 GNUNET_free (emsg);
91 GNUNET_TESTING_interpreter_fail (is);
92 return;
93 }
94
95 cps->node_connections_head = GNUNET_TESTING_get_connections (cps->num,
96 cps->topology);
97
98 for (pos_connection = cps->node_connections_head; NULL != pos_connection;
99 pos_connection = pos_connection->next)
100 {
101 con_num++;
102 num = GNUNET_TESTING_calculate_num (pos_connection, cps->topology);
103 for (pos_prefix = pos_connection->address_prefixes_head; NULL != pos_prefix;
104 pos_prefix =
105 pos_prefix->next)
106 {
107 addr = GNUNET_TESTING_get_address (pos_connection,
108 pos_prefix->address_prefix);
109 if (NULL != addr)
110 {
111 char *natted_p = strstr (pos_prefix->address_prefix, "_");
112
113 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
114 "0 validating peer number %s %s %s\n",
115 natted_p,
116 pos_prefix->address_prefix,
117 addr);
118 if (0 == GNUNET_memcmp (pos_prefix->address_prefix, "udp"))
119 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
120 "validating memcmp\n");
121 if (GNUNET_YES == *broadcast)
122 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
123 "validating broadcast\n");
124 if ((0 == GNUNET_memcmp (pos_prefix->address_prefix, "udp")) &&
125 (GNUNET_YES == *broadcast) )
126 GNUNET_asprintf (&addr_and_port,
127 "%s:2086",
128 addr);
129 else if (NULL == natted_p)
130 GNUNET_asprintf (&addr_and_port,
131 "%s:60002",
132 addr);
133 else if (NULL != natted_p)
134 {
135 char *prefix;
136 char *rest;
137 char *address;
138
139 prefix = strtok (addr, "_");
140 rest = strtok (NULL, "_");
141 strtok (rest, "-");
142 address = strtok (NULL, "-");
143
144 GNUNET_asprintf (&addr_and_port,
145 "%s-%s:0",
146 prefix,
147 address);
148
149 }
150 peer = GNUNET_TESTING_get_peer (num, tl_system);
151 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
152 "validating peer number %u with identity %s and address %s %u %s and handle %p\n",
153 num,
154 GNUNET_i2s (peer),
155 addr_and_port,
156 *broadcast,
157 pos_prefix->address_prefix,
158 cps->ah);
159 GNUNET_TRANSPORT_application_validate ((struct
160 GNUNET_TRANSPORT_ApplicationHandle
161 *) cps->ah,
162 peer,
163 nt,
164 addr_and_port);
165 GNUNET_free (peer);
166 GNUNET_free (addr);
167 GNUNET_free (addr_and_port);
168 }
169 }
170 }
171 cps->con_num = con_num;
172}
173
174
175/**
176 * The cleanup function of this cmd frees resources the cmd allocated.
177 *
178 */
179static void
180connect_peers_cleanup (void *cls)
181{
182 struct GNUNET_TESTING_ConnectPeersState *cps = cls;
183
184 GNUNET_free (cps->connected_peers_map);
185 GNUNET_free (cps);
186}
187
188
189/**
190 * This function prepares an array with traits.
191 *
192 */
193enum GNUNET_GenericReturnValue
194connect_peers_traits (void *cls,
195 const void **ret,
196 const char *trait,
197 unsigned int index)
198{
199 struct GNUNET_TESTING_ConnectPeersState *cps = cls;
200 struct GNUNET_TESTING_Trait traits[] = {
201 GNUNET_CORE_TESTING_make_trait_connect_peer_state ((const void *) cps),
202 GNUNET_TESTING_trait_end ()
203 };
204 return GNUNET_TESTING_get_trait (traits,
205 ret,
206 trait,
207 index);
208}
209
210
211struct GNUNET_TESTING_Command
212GNUNET_CORE_cmd_connect_peers (
213 const char *label,
214 const char *start_peer_label,
215 const char *create_label,
216 uint32_t num,
217 struct GNUNET_TESTING_NetjailTopology *topology,
218 unsigned int additional_connects,
219 unsigned int wait_for_connect,
220 struct GNUNET_MQ_MessageHandler *handlers)
221{
222 struct GNUNET_TESTING_ConnectPeersState *cps;
223 unsigned int node_additional_connects;
224 struct GNUNET_CONTAINER_MultiShortmap *connected_peers_map =
225 GNUNET_CONTAINER_multishortmap_create (1,GNUNET_NO);
226 unsigned int i;
227
228 node_additional_connects = GNUNET_TESTING_get_additional_connects (num,
229 topology);
230
231 LOG (GNUNET_ERROR_TYPE_DEBUG,
232 "global: %u and local: %u additional_connects\n",
233 additional_connects,
234 node_additional_connects);
235
236 if (0 != node_additional_connects)
237 additional_connects = node_additional_connects;
238
239 cps = GNUNET_new (struct GNUNET_TESTING_ConnectPeersState);
240 cps->start_peer_label = start_peer_label;
241 cps->num = num;
242 cps->create_label = create_label;
243 cps->topology = topology;
244 cps->additional_connects = additional_connects;
245 cps->wait_for_connect = wait_for_connect;
246 cps->connected_peers_map = connected_peers_map;
247
248 if (NULL != handlers)
249 {
250 for (i = 0; NULL != handlers[i].cb; i++)
251 ;
252 cps->handlers = GNUNET_new_array (i + 1,
253 struct GNUNET_MQ_MessageHandler);
254 GNUNET_memcpy (cps->handlers,
255 handlers,
256 i * sizeof(struct GNUNET_MQ_MessageHandler));
257 }
258 // FIXME: wrap with cmd_make_unblocking!
259 if (GNUNET_YES == wait_for_connect)
260 return GNUNET_TESTING_command_new_ac (cps,
261 label,
262 &connect_peers_run,
263 &connect_peers_cleanup,
264 &connect_peers_traits,
265 &cps->ac);
266 else
267 return GNUNET_TESTING_command_new (cps,
268 label,
269 &connect_peers_run,
270 &connect_peers_cleanup,
271 &connect_peers_traits);
272}
273
274
275// FIXME: likely not ideally placed here, move to its own file
276GNUNET_CORE_TESTING_SIMPLE_TRAITS (GNUNET_TESTING_MAKE_IMPL_SIMPLE_TRAIT,
277 GNUNET_CORE_TESTING)
diff --git a/src/service/core/core_api_monitor_peers.c b/src/service/core/core_api_monitor_peers.c
new file mode 100644
index 000000000..3be8e3859
--- /dev/null
+++ b/src/service/core/core_api_monitor_peers.c
@@ -0,0 +1,196 @@
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 */
35struct 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 */
65static void
66reconnect (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 */
77static void
78handle_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 */
93static void
94handle_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 */
111static void
112reconnect (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 */
157struct GNUNET_CORE_MonitorHandle *
158GNUNET_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 */
184void
185GNUNET_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/service/core/gnunet-service-core.c b/src/service/core/gnunet-service-core.c
new file mode 100644
index 000000000..e387fecc9
--- /dev/null
+++ b/src/service/core/gnunet-service-core.c
@@ -0,0 +1,988 @@
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#include "gnunet_constants.h"
34
35/**
36 * How many messages do we queue up at most for any client? This can
37 * cause messages to be dropped if clients do not process them fast
38 * enough! Note that this is a soft limit; we try
39 * to keep a few larger messages above the limit.
40 */
41#define SOFT_MAX_QUEUE 128
42
43/**
44 * How many messages do we queue up at most for any client? This can
45 * cause messages to be dropped if clients do not process them fast
46 * enough! Note that this is the hard limit.
47 */
48#define HARD_MAX_QUEUE 256
49
50
51/**
52 * Data structure for each client connected to the CORE service.
53 */
54struct GSC_Client
55{
56 /**
57 * Clients are kept in a linked list.
58 */
59 struct GSC_Client *next;
60
61 /**
62 * Clients are kept in a linked list.
63 */
64 struct GSC_Client *prev;
65
66 /**
67 * Handle for the client with the server API.
68 */
69 struct GNUNET_SERVICE_Client *client;
70
71 /**
72 * Message queue to talk to @e client.
73 */
74 struct GNUNET_MQ_Handle *mq;
75
76 /**
77 * Array of the types of messages this peer cares
78 * about (with @e tcnt entries). Allocated as part
79 * of this client struct, do not free!
80 */
81 uint16_t *types;
82
83 /**
84 * Map of peer identities to active transmission requests of this
85 * client to the peer (of type `struct GSC_ClientActiveRequest`).
86 */
87 struct GNUNET_CONTAINER_MultiPeerMap *requests;
88
89 /**
90 * Map containing all peers that this client knows we're connected to.
91 */
92 struct GNUNET_CONTAINER_MultiPeerMap *connectmap;
93
94 /**
95 * Options for messages this client cares about,
96 * see GNUNET_CORE_OPTION_ values.
97 */
98 uint32_t options;
99
100 /**
101 * Have we gotten the #GNUNET_MESSAGE_TYPE_CORE_INIT message
102 * from this client already?
103 */
104 int got_init;
105
106 /**
107 * Number of types of incoming messages this client
108 * specifically cares about. Size of the @e types array.
109 */
110 unsigned int tcnt;
111};
112
113
114/**
115 * Our identity.
116 */
117struct GNUNET_PeerIdentity GSC_my_identity;
118
119/**
120 * Our configuration.
121 */
122const struct GNUNET_CONFIGURATION_Handle *GSC_cfg;
123
124/**
125 * For creating statistics.
126 */
127struct GNUNET_STATISTICS_Handle *GSC_stats;
128
129/**
130 * Big "or" of all client options.
131 */
132static uint32_t all_client_options;
133
134/**
135 * Head of linked list of our clients.
136 */
137static struct GSC_Client *client_head;
138
139/**
140 * Tail of linked list of our clients.
141 */
142static struct GSC_Client *client_tail;
143
144
145/**
146 * Test if the client is interested in messages of the given type.
147 *
148 * @param type message type
149 * @param c client to test
150 * @return #GNUNET_YES if @a c is interested, #GNUNET_NO if not.
151 */
152static int
153type_match (uint16_t type, struct GSC_Client *c)
154{
155 if ((0 == c->tcnt) && (0 != c->options))
156 return GNUNET_YES; /* peer without handlers and inbound/outbond
157 callbacks matches ALL */
158 if (NULL == c->types)
159 return GNUNET_NO;
160 for (unsigned int i = 0; i < c->tcnt; i++)
161 if (type == c->types[i])
162 return GNUNET_YES;
163 return GNUNET_NO;
164}
165
166
167/**
168 * Check #GNUNET_MESSAGE_TYPE_CORE_INIT request.
169 *
170 * @param cls client that sent #GNUNET_MESSAGE_TYPE_CORE_INIT
171 * @param im the `struct InitMessage`
172 * @return #GNUNET_OK if @a im is well-formed
173 */
174static int
175check_client_init (void *cls, const struct InitMessage *im)
176{
177 return GNUNET_OK;
178}
179
180
181/**
182 * Handle #GNUNET_MESSAGE_TYPE_CORE_INIT request.
183 *
184 * @param cls client that sent #GNUNET_MESSAGE_TYPE_CORE_INIT
185 * @param im the `struct InitMessage`
186 */
187static void
188handle_client_init (void *cls, const struct InitMessage *im)
189{
190 struct GSC_Client *c = cls;
191 struct GNUNET_MQ_Envelope *env;
192 struct InitReplyMessage *irm;
193 uint16_t msize;
194 const uint16_t *types;
195
196 /* check that we don't have an entry already */
197 msize = ntohs (im->header.size) - sizeof(struct InitMessage);
198 types = (const uint16_t *) &im[1];
199 c->tcnt = msize / sizeof(uint16_t);
200 c->options = ntohl (im->options);
201 c->got_init = GNUNET_YES;
202 all_client_options |= c->options;
203 c->types = GNUNET_malloc (msize);
204 GNUNET_assert (GNUNET_YES ==
205 GNUNET_CONTAINER_multipeermap_put (
206 c->connectmap,
207 &GSC_my_identity,
208 NULL,
209 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
210 for (unsigned int i = 0; i < c->tcnt; i++)
211 c->types[i] = ntohs (types[i]);
212 GSC_TYPEMAP_add (c->types, c->tcnt);
213 GNUNET_log (
214 GNUNET_ERROR_TYPE_DEBUG,
215 "Client connecting to core service is interested in %u message types\n",
216 (unsigned int) c->tcnt);
217 /* send init reply message */
218 env = GNUNET_MQ_msg (irm, GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY);
219 irm->reserved = htonl (0);
220 irm->my_identity = GSC_my_identity;
221 GNUNET_MQ_send (c->mq, env);
222 GSC_SESSIONS_notify_client_about_sessions (c);
223 GNUNET_SERVICE_client_continue (c->client);
224}
225
226
227/**
228 * We will never be ready to transmit the given message in (disconnect
229 * or invalid request). Frees resources associated with @a car. We
230 * don't explicitly tell the client, it'll learn with the disconnect
231 * (or violated the protocol).
232 *
233 * @param car request that now permanently failed; the
234 * responsibility for the handle is now returned
235 * to CLIENTS (SESSIONS is done with it).
236 * @param drop_client #GNUNET_YES if the client violated the protocol
237 * and we should thus drop the connection
238 */
239void
240GSC_CLIENTS_reject_request (struct GSC_ClientActiveRequest *car,
241 int drop_client)
242{
243 GNUNET_assert (
244 GNUNET_YES ==
245 GNUNET_CONTAINER_multipeermap_remove (car->client_handle->requests,
246 &car->target,
247 car));
248 if (GNUNET_YES == drop_client)
249 GNUNET_SERVICE_client_drop (car->client_handle->client);
250 GNUNET_free (car);
251}
252
253
254/**
255 * Tell a client that we are ready to receive the message.
256 *
257 * @param car request that is now ready; the responsibility
258 * for the handle remains shared between CLIENTS
259 * and SESSIONS after this call.
260 */
261void
262GSC_CLIENTS_solicit_request (struct GSC_ClientActiveRequest *car)
263{
264 struct GSC_Client *c;
265 struct GNUNET_MQ_Envelope *env;
266 struct SendMessageReady *smr;
267 struct GNUNET_TIME_Relative delay;
268 struct GNUNET_TIME_Relative left;
269
270 c = car->client_handle;
271 if (GNUNET_YES !=
272 GNUNET_CONTAINER_multipeermap_contains (c->connectmap, &car->target))
273 {
274 /* connection has gone down since, drop request */
275 GNUNET_assert (0 !=
276 GNUNET_memcmp (&car->target,
277 &GSC_my_identity));
278 GSC_SESSIONS_dequeue_request (car);
279 GSC_CLIENTS_reject_request (car, GNUNET_NO);
280 return;
281 }
282 delay = GNUNET_TIME_absolute_get_duration (car->received_time);
283 left = GNUNET_TIME_absolute_get_duration (car->deadline);
284 if (delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
285 GNUNET_log (
286 GNUNET_ERROR_TYPE_WARNING,
287 "Client waited %s for permission to transmit to `%s'%s (priority %u)\n",
288 GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES),
289 GNUNET_i2s (&car->target),
290 (0 == left.rel_value_us) ? " (past deadline)" : "",
291 car->priority);
292 env = GNUNET_MQ_msg (smr, GNUNET_MESSAGE_TYPE_CORE_SEND_READY);
293 smr->size = htons (car->msize);
294 smr->smr_id = car->smr_id;
295 smr->peer = car->target;
296 GNUNET_MQ_send (c->mq, env);
297}
298
299
300/**
301 * Handle #GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST message.
302 *
303 * @param cls client that sent a #GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST
304 * @param req the `struct SendMessageRequest`
305 */
306static void
307handle_client_send_request (void *cls, const struct SendMessageRequest *req)
308{
309 struct GSC_Client *c = cls;
310 struct GSC_ClientActiveRequest *car;
311 int is_loopback;
312
313 if (NULL == c->requests)
314 c->requests = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_NO);
315 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
316 "Client asked for transmission to `%s'\n",
317 GNUNET_i2s (&req->peer));
318 is_loopback = (0 == GNUNET_memcmp (&req->peer,
319 &GSC_my_identity));
320 if ((! is_loopback) &&
321 (GNUNET_YES !=
322 GNUNET_CONTAINER_multipeermap_contains (c->connectmap, &req->peer)))
323 {
324 /* neighbour must have disconnected since request was issued,
325 * ignore (client will realize it once it processes the
326 * disconnect notification) */
327 GNUNET_STATISTICS_update (GSC_stats,
328 gettext_noop (
329 "# send requests dropped (disconnected)"),
330 1,
331 GNUNET_NO);
332 GNUNET_SERVICE_client_continue (c->client);
333 return;
334 }
335
336 car = GNUNET_CONTAINER_multipeermap_get (c->requests, &req->peer);
337 if (NULL == car)
338 {
339 /* create new entry */
340 car = GNUNET_new (struct GSC_ClientActiveRequest);
341 GNUNET_assert (GNUNET_OK ==
342 GNUNET_CONTAINER_multipeermap_put (
343 c->requests,
344 &req->peer,
345 car,
346 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
347 car->client_handle = c;
348 }
349 else
350 {
351 /* dequeue and recycle memory from pending request, there can only
352 be at most one per client and peer */
353 GNUNET_STATISTICS_update (GSC_stats,
354 gettext_noop (
355 "# dequeuing CAR (duplicate request)"),
356 1,
357 GNUNET_NO);
358 GSC_SESSIONS_dequeue_request (car);
359 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
360 "Transmission request to `%s' was a duplicate!\n",
361 GNUNET_i2s (&req->peer));
362 }
363 car->target = req->peer;
364 car->received_time = GNUNET_TIME_absolute_get ();
365 car->deadline = GNUNET_TIME_absolute_ntoh (req->deadline);
366 car->priority = (enum GNUNET_MQ_PriorityPreferences) ntohl (req->priority);
367 car->msize = ntohs (req->size);
368 car->smr_id = req->smr_id;
369 car->was_solicited = GNUNET_NO;
370 GNUNET_SERVICE_client_continue (c->client);
371 if (is_loopback)
372 {
373 /* loopback, satisfy immediately */
374 GSC_CLIENTS_solicit_request (car);
375 return;
376 }
377 GSC_SESSIONS_queue_request (car);
378}
379
380
381/**
382 * Closure for the #client_tokenizer_callback().
383 */
384struct TokenizerContext
385{
386 /**
387 * Active request handle for the message.
388 */
389 struct GSC_ClientActiveRequest *car;
390
391 /**
392 * How important is this message.
393 */
394 enum GNUNET_MQ_PriorityPreferences priority;
395};
396
397
398/**
399 * Functions with this signature are called whenever a complete
400 * message is received by the tokenizer. Used by
401 * #handle_client_send() for dispatching messages from clients to
402 * either the SESSION subsystem or other CLIENT (for loopback).
403 *
404 * @param cls reservation request (`struct TokenizerContext`)
405 * @param message the actual message
406 * @return #GNUNET_OK on success,
407 * #GNUNET_NO to stop further processing (no error)
408 * #GNUNET_SYSERR to stop further processing with error
409 */
410static int
411tokenized_cb (void *cls, const struct GNUNET_MessageHeader *message)
412{
413 struct TokenizerContext *tc = cls;
414 struct GSC_ClientActiveRequest *car = tc->car;
415 char buf[92];
416
417 GNUNET_snprintf (buf,
418 sizeof(buf),
419 gettext_noop ("# bytes of messages of type %u received"),
420 (unsigned int) ntohs (message->type));
421 GNUNET_STATISTICS_update (GSC_stats, buf, ntohs (message->size), GNUNET_NO);
422 if (0 == GNUNET_memcmp (&car->target,
423 &GSC_my_identity))
424 {
425 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
426 "Delivering message of type %u to myself\n",
427 ntohs (message->type));
428 GSC_CLIENTS_deliver_message (&GSC_my_identity,
429 message,
430 ntohs (message->size),
431 GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
432 GSC_CLIENTS_deliver_message (&GSC_my_identity,
433 message,
434 sizeof(struct GNUNET_MessageHeader),
435 GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
436 GSC_CLIENTS_deliver_message (&GSC_my_identity,
437 message,
438 ntohs (message->size),
439 GNUNET_CORE_OPTION_SEND_FULL_INBOUND);
440 GSC_CLIENTS_deliver_message (&GSC_my_identity,
441 message,
442 sizeof(struct GNUNET_MessageHeader),
443 GNUNET_CORE_OPTION_SEND_HDR_INBOUND);
444 }
445 else
446 {
447 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
448 "Delivering message of type %u and size %u to %s\n",
449 ntohs (message->type),
450 ntohs (message->size),
451 GNUNET_i2s (&car->target));
452 GSC_CLIENTS_deliver_message (&car->target,
453 message,
454 ntohs (message->size),
455 GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
456 GSC_CLIENTS_deliver_message (&car->target,
457 message,
458 sizeof(struct GNUNET_MessageHeader),
459 GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
460 GSC_SESSIONS_transmit (car, message, tc->priority);
461 }
462 return GNUNET_OK;
463}
464
465
466/**
467 * Check #GNUNET_MESSAGE_TYPE_CORE_SEND request.
468 *
469 * @param cls the `struct GSC_Client`
470 * @param sm the `struct SendMessage`
471 * @return #GNUNET_OK if @a sm is well-formed
472 */
473static int
474check_client_send (void *cls, const struct SendMessage *sm)
475{
476 return GNUNET_OK;
477}
478
479
480/**
481 * Handle #GNUNET_MESSAGE_TYPE_CORE_SEND request.
482 *
483 * @param cls the `struct GSC_Client`
484 * @param sm the `struct SendMessage`
485 */
486static void
487handle_client_send (void *cls, const struct SendMessage *sm)
488{
489 struct GSC_Client *c = cls;
490 struct TokenizerContext tc;
491 uint16_t msize;
492 struct GNUNET_TIME_Relative delay;
493 struct GNUNET_MessageStreamTokenizer *mst;
494
495 msize = ntohs (sm->header.size) - sizeof(struct SendMessage);
496 tc.car = GNUNET_CONTAINER_multipeermap_get (c->requests, &sm->peer);
497 if (NULL == tc.car)
498 {
499 /* Must have been that we first approved the request, then got disconnected
500 * (which triggered removal of the 'car') and now the client gives us a message
501 * just *before* the client learns about the disconnect. Theoretically, we
502 * might also now be *again* connected. So this can happen (but should be
503 * rare). If it does happen, the message is discarded. */GNUNET_STATISTICS_update (GSC_stats,
504 gettext_noop (
505 "# messages discarded (session disconnected)"),
506 1,
507 GNUNET_NO);
508 GNUNET_SERVICE_client_continue (c->client);
509 return;
510 }
511 delay = GNUNET_TIME_absolute_get_duration (tc.car->received_time);
512 tc.priority = (enum GNUNET_MQ_PriorityPreferences) ntohl (sm->priority);
513 if (delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us)
514 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
515 "Client waited %s for transmission of %u bytes to `%s'\n",
516 GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES),
517 msize,
518 GNUNET_i2s (&sm->peer));
519 else
520 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
521 "Client waited %s for transmission of %u bytes to `%s'\n",
522 GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES),
523 msize,
524 GNUNET_i2s (&sm->peer));
525
526 GNUNET_assert (
527 GNUNET_YES ==
528 GNUNET_CONTAINER_multipeermap_remove (c->requests, &sm->peer, tc.car));
529 mst = GNUNET_MST_create (&tokenized_cb, &tc);
530 GNUNET_MST_from_buffer (mst,
531 (const char *) &sm[1],
532 msize,
533 GNUNET_YES,
534 GNUNET_NO);
535 GNUNET_MST_destroy (mst);
536 GSC_SESSIONS_dequeue_request (tc.car);
537 GNUNET_free (tc.car);
538 GNUNET_SERVICE_client_continue (c->client);
539}
540
541
542/**
543 * Free client request records.
544 *
545 * @param cls NULL
546 * @param key identity of peer for which this is an active request
547 * @param value the `struct GSC_ClientActiveRequest` to free
548 * @return #GNUNET_YES (continue iteration)
549 */
550static int
551destroy_active_client_request (void *cls,
552 const struct GNUNET_PeerIdentity *key,
553 void *value)
554{
555 struct GSC_ClientActiveRequest *car = value;
556
557 GNUNET_assert (
558 GNUNET_YES ==
559 GNUNET_CONTAINER_multipeermap_remove (car->client_handle->requests,
560 &car->target,
561 car));
562 GSC_SESSIONS_dequeue_request (car);
563 GNUNET_free (car);
564 return GNUNET_YES;
565}
566
567
568/**
569 * A client connected, set up.
570 *
571 * @param cls closure
572 * @param client identification of the client
573 * @param mq message queue to talk to @a client
574 * @return our client handle
575 */
576static void *
577client_connect_cb (void *cls,
578 struct GNUNET_SERVICE_Client *client,
579 struct GNUNET_MQ_Handle *mq)
580{
581 struct GSC_Client *c;
582
583 c = GNUNET_new (struct GSC_Client);
584 c->client = client;
585 c->mq = mq;
586 c->connectmap = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_NO);
587 GNUNET_CONTAINER_DLL_insert (client_head, client_tail, c);
588 return c;
589}
590
591
592/**
593 * A client disconnected, clean up.
594 *
595 * @param cls closure
596 * @param client identification of the client
597 * @param app_ctx our `struct GST_Client` for @a client
598 */
599static void
600client_disconnect_cb (void *cls,
601 struct GNUNET_SERVICE_Client *client,
602 void *app_ctx)
603{
604 struct GSC_Client *c = app_ctx;
605
606 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
607 "Client %p has disconnected from core service.\n",
608 client);
609 GNUNET_CONTAINER_DLL_remove (client_head, client_tail, c);
610 if (NULL != c->requests)
611 {
612 GNUNET_CONTAINER_multipeermap_iterate (c->requests,
613 &destroy_active_client_request,
614 NULL);
615 GNUNET_CONTAINER_multipeermap_destroy (c->requests);
616 }
617 GNUNET_CONTAINER_multipeermap_destroy (c->connectmap);
618 c->connectmap = NULL;
619 if (NULL != c->types)
620 {
621 GSC_TYPEMAP_remove (c->types, c->tcnt);
622 GNUNET_free (c->types);
623 }
624 GNUNET_free (c);
625
626 /* recalculate 'all_client_options' */
627 all_client_options = 0;
628 for (c = client_head; NULL != c; c = c->next)
629 all_client_options |= c->options;
630}
631
632
633/**
634 * Notify a particular client about a change to existing connection to
635 * one of our neighbours (check if the client is interested). Called
636 * from #GSC_SESSIONS_notify_client_about_sessions().
637 *
638 * @param client client to notify
639 * @param neighbour identity of the neighbour that changed status
640 * @param tmap_old previous type map for the neighbour, NULL for connect
641 * @param tmap_new updated type map for the neighbour, NULL for disconnect
642 */
643void
644GSC_CLIENTS_notify_client_about_neighbour (
645 struct GSC_Client *client,
646 const struct GNUNET_PeerIdentity *neighbour,
647 const struct GSC_TypeMap *tmap_old,
648 const struct GSC_TypeMap *tmap_new)
649{
650 struct GNUNET_MQ_Envelope *env;
651 int old_match;
652 int new_match;
653
654 if (GNUNET_YES != client->got_init)
655 return;
656 old_match = GSC_TYPEMAP_test_match (tmap_old, client->types, client->tcnt);
657 new_match = GSC_TYPEMAP_test_match (tmap_new, client->types, client->tcnt);
658 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
659 "Notifying client about neighbour %s (%d/%d)\n",
660 GNUNET_i2s (neighbour),
661 old_match,
662 new_match);
663 if (old_match == new_match)
664 {
665 GNUNET_assert (
666 old_match ==
667 GNUNET_CONTAINER_multipeermap_contains (client->connectmap, neighbour));
668 return; /* no change */
669 }
670 if (GNUNET_NO == old_match)
671 {
672 struct ConnectNotifyMessage *cnm;
673
674 /* send connect */
675 GNUNET_assert (
676 GNUNET_NO ==
677 GNUNET_CONTAINER_multipeermap_contains (client->connectmap, neighbour));
678 GNUNET_assert (GNUNET_YES ==
679 GNUNET_CONTAINER_multipeermap_put (
680 client->connectmap,
681 neighbour,
682 NULL,
683 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
684 env = GNUNET_MQ_msg (cnm, GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
685 cnm->reserved = htonl (0);
686 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
687 "Sending NOTIFY_CONNECT message about peer %s to client.\n",
688 GNUNET_i2s (neighbour));
689 cnm->peer = *neighbour;
690 GNUNET_MQ_send (client->mq, env);
691 }
692 else
693 {
694 struct DisconnectNotifyMessage *dcm;
695
696 /* send disconnect */
697 GNUNET_assert (
698 GNUNET_YES ==
699 GNUNET_CONTAINER_multipeermap_contains (client->connectmap, neighbour));
700 GNUNET_assert (GNUNET_YES ==
701 GNUNET_CONTAINER_multipeermap_remove (client->connectmap,
702 neighbour,
703 NULL));
704 env = GNUNET_MQ_msg (dcm, GNUNET_MESSAGE_TYPE_CORE_NOTIFY_DISCONNECT);
705 dcm->reserved = htonl (0);
706 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
707 "Sending NOTIFY_DISCONNECT message about peer %s to client.\n",
708 GNUNET_i2s (neighbour));
709 dcm->peer = *neighbour;
710 GNUNET_MQ_send (client->mq, env);
711 }
712}
713
714
715/**
716 * Notify all clients about a change to existing session.
717 * Called from SESSIONS whenever there is a change in sessions
718 * or types processed by the respective peer.
719 *
720 * @param neighbour identity of the neighbour that changed status
721 * @param tmap_old previous type map for the neighbour, NULL for connect
722 * @param tmap_new updated type map for the neighbour, NULL for disconnect
723 */
724void
725GSC_CLIENTS_notify_clients_about_neighbour (
726 const struct GNUNET_PeerIdentity *neighbour,
727 const struct GSC_TypeMap *tmap_old,
728 const struct GSC_TypeMap *tmap_new)
729{
730 struct GSC_Client *c;
731
732 for (c = client_head; NULL != c; c = c->next)
733 GSC_CLIENTS_notify_client_about_neighbour (c,
734 neighbour,
735 tmap_old,
736 tmap_new);
737}
738
739
740/**
741 * Deliver P2P message to interested clients. Caller must have checked
742 * that the sending peer actually lists the given message type as one
743 * of its types.
744 *
745 * @param sender peer who sent us the message
746 * @param msg the message
747 * @param msize number of bytes to transmit
748 * @param options options for checking which clients should
749 * receive the message
750 */
751void
752GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender,
753 const struct GNUNET_MessageHeader *msg,
754 uint16_t msize,
755 uint32_t options)
756{
757 size_t size = msize + sizeof(struct NotifyTrafficMessage);
758
759 if (size >= GNUNET_MAX_MESSAGE_SIZE)
760 {
761 GNUNET_break (0);
762 return;
763 }
764 if (! ((0 != (all_client_options & options)) ||
765 (0 != (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND))))
766 return; /* no client cares about this message notification */
767 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
768 "Core service passes message from `%s' of type %u to client.\n",
769 GNUNET_i2s (sender),
770 (unsigned int) ntohs (msg->type));
771 GSC_SESSIONS_add_to_typemap (sender, ntohs (msg->type));
772
773 for (struct GSC_Client *c = client_head; NULL != c; c = c->next)
774 {
775 struct GNUNET_MQ_Envelope *env;
776 struct NotifyTrafficMessage *ntm;
777 uint16_t mtype;
778 unsigned int qlen;
779 int tm;
780
781 tm = type_match (ntohs (msg->type), c);
782 if (! ((0 != (c->options & options)) ||
783 ((0 != (options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) &&
784 (GNUNET_YES == tm))))
785 continue; /* neither options nor type match permit the message */
786 if ((0 != (options & GNUNET_CORE_OPTION_SEND_HDR_INBOUND)) &&
787 ((0 != (c->options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ||
788 (GNUNET_YES == tm)))
789 continue;
790 if ((0 != (options & GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND)) &&
791 (0 != (c->options & GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND)))
792 continue;
793
794 /* Drop messages if:
795 1) We are above the hard limit, or
796 2) We are above the soft limit, and a coin toss limited
797 to the message size (giving larger messages a
798 proportionally higher chance of being queued) falls
799 below the threshold. The threshold is based on where
800 we are between the soft and the hard limit, scaled
801 to match the range of message sizes we usually encounter
802 (i.e. up to 32k); so a 64k message has a 50% chance of
803 being kept if we are just barely below the hard max,
804 and a 99% chance of being kept if we are at the soft max.
805 The reason is to make it more likely to drop control traffic
806 (ACK, queries) which may be cumulative or highly redundant,
807 and cheap to drop than data traffic. */qlen = GNUNET_MQ_get_length (c->mq);
808 if ((qlen >= HARD_MAX_QUEUE) ||
809 ((qlen > SOFT_MAX_QUEUE) &&
810 ((GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
811 ntohs (msg->size))) <
812 (qlen - SOFT_MAX_QUEUE) * 0x8000
813 / (HARD_MAX_QUEUE - SOFT_MAX_QUEUE))))
814 {
815 char buf[1024];
816
817 GNUNET_log (
818 GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
819 "Dropping decrypted message of type %u as client is too busy (queue full)\n",
820 (unsigned int) ntohs (msg->type));
821 GNUNET_snprintf (buf,
822 sizeof(buf),
823 gettext_noop (
824 "# messages of type %u discarded (client busy)"),
825 (unsigned int) ntohs (msg->type));
826 GNUNET_STATISTICS_update (GSC_stats, buf, 1, GNUNET_NO);
827 continue;
828 }
829
830 GNUNET_log (
831 GNUNET_ERROR_TYPE_DEBUG,
832 "Sending %u message with %u bytes to client interested in messages of type %u.\n",
833 options,
834 ntohs (msg->size),
835 (unsigned int) ntohs (msg->type));
836
837 if (0 != (options & (GNUNET_CORE_OPTION_SEND_FULL_INBOUND
838 | GNUNET_CORE_OPTION_SEND_HDR_INBOUND)))
839 mtype = GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND;
840 else
841 mtype = GNUNET_MESSAGE_TYPE_CORE_NOTIFY_OUTBOUND;
842 env = GNUNET_MQ_msg_extra (ntm, msize, mtype);
843 ntm->peer = *sender;
844 GNUNET_memcpy (&ntm[1], msg, msize);
845
846 GNUNET_assert (
847 (0 == (c->options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND)) ||
848 (GNUNET_YES != tm) ||
849 (GNUNET_YES ==
850 GNUNET_CONTAINER_multipeermap_contains (c->connectmap, sender)));
851 GNUNET_MQ_send (c->mq, env);
852 }
853}
854
855
856/**
857 * Last task run during shutdown. Disconnects us from
858 * the transport.
859 *
860 * @param cls NULL, unused
861 */
862static void
863shutdown_task (void *cls)
864{
865 struct GSC_Client *c;
866
867 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Core service shutting down.\n");
868 while (NULL != (c = client_head))
869 GNUNET_SERVICE_client_drop (c->client);
870 GSC_SESSIONS_done ();
871 GSC_KX_done ();
872 GSC_TYPEMAP_done ();
873 if (NULL != GSC_stats)
874 {
875 GNUNET_STATISTICS_destroy (GSC_stats, GNUNET_NO);
876 GSC_stats = NULL;
877 }
878 GSC_cfg = NULL;
879}
880
881
882/**
883 * Handle #GNUNET_MESSAGE_TYPE_CORE_MONITOR_PEERS request. For this
884 * request type, the client does not have to have transmitted an INIT
885 * request. All current peers are returned, regardless of which
886 * message types they accept.
887 *
888 * @param cls client sending the iteration request
889 * @param message iteration request message
890 */
891static void
892handle_client_monitor_peers (void *cls,
893 const struct GNUNET_MessageHeader *message)
894{
895 struct GSC_Client *c = cls;
896
897 GNUNET_SERVICE_client_continue (c->client);
898 GSC_KX_handle_client_monitor_peers (c->mq);
899}
900
901
902/**
903 * Initiate core service.
904 *
905 * @param cls closure
906 * @param c configuration to use
907 * @param service the initialized service
908 */
909static void
910run (void *cls,
911 const struct GNUNET_CONFIGURATION_Handle *c,
912 struct GNUNET_SERVICE_Handle *service)
913{
914 struct GNUNET_CRYPTO_EddsaPrivateKey pk;
915 char *keyfile;
916
917 GSC_cfg = c;
918 if (GNUNET_OK !=
919 GNUNET_CONFIGURATION_get_value_filename (GSC_cfg,
920 "PEER",
921 "PRIVATE_KEY",
922 &keyfile))
923 {
924 GNUNET_log (
925 GNUNET_ERROR_TYPE_ERROR,
926 _ ("Core service is lacking HOSTKEY configuration setting. Exiting.\n"));
927 GNUNET_SCHEDULER_shutdown ();
928 return;
929 }
930 GSC_stats = GNUNET_STATISTICS_create ("core", GSC_cfg);
931 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
932 GNUNET_SERVICE_suspend (service);
933 GSC_TYPEMAP_init ();
934 if (GNUNET_SYSERR ==
935 GNUNET_CRYPTO_eddsa_key_from_file (keyfile,
936 GNUNET_YES,
937 &pk))
938 {
939 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
940 "Failed to setup peer's private key\n");
941 GNUNET_SCHEDULER_shutdown ();
942 GNUNET_free (keyfile);
943 return;
944 }
945 GNUNET_free (keyfile);
946 if (GNUNET_OK != GSC_KX_init (&pk))
947 {
948 GNUNET_SCHEDULER_shutdown ();
949 return;
950 }
951 GSC_SESSIONS_init ();
952 GNUNET_SERVICE_resume (service);
953 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
954 _ ("Core service of `%s' ready.\n"),
955 GNUNET_i2s (&GSC_my_identity));
956}
957
958
959/**
960 * Define "main" method using service macro.
961 */
962GNUNET_SERVICE_MAIN (
963 "core",
964 GNUNET_SERVICE_OPTION_NONE,
965 &run,
966 &client_connect_cb,
967 &client_disconnect_cb,
968 NULL,
969 GNUNET_MQ_hd_var_size (client_init,
970 GNUNET_MESSAGE_TYPE_CORE_INIT,
971 struct InitMessage,
972 NULL),
973 GNUNET_MQ_hd_fixed_size (client_monitor_peers,
974 GNUNET_MESSAGE_TYPE_CORE_MONITOR_PEERS,
975 struct GNUNET_MessageHeader,
976 NULL),
977 GNUNET_MQ_hd_fixed_size (client_send_request,
978 GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST,
979 struct SendMessageRequest,
980 NULL),
981 GNUNET_MQ_hd_var_size (client_send,
982 GNUNET_MESSAGE_TYPE_CORE_SEND,
983 struct SendMessage,
984 NULL),
985 GNUNET_MQ_handler_end ());
986
987
988/* end of gnunet-service-core.c */
diff --git a/src/service/core/gnunet-service-core.h b/src/service/core/gnunet-service-core.h
new file mode 100644
index 000000000..0f71f221a
--- /dev/null
+++ b/src/service/core/gnunet-service-core.h
@@ -0,0 +1,198 @@
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 */
38struct 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 */
46struct 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 */
109void
110GSC_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 */
125void
126GSC_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 */
140void
141GSC_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 */
159void
160GSC_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 */
175void
176GSC_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 */
185extern const struct GNUNET_CONFIGURATION_Handle *GSC_cfg;
186
187/**
188 * For creating statistics.
189 */
190extern struct GNUNET_STATISTICS_Handle *GSC_stats;
191
192/**
193 * Our identity.
194 */
195extern struct GNUNET_PeerIdentity GSC_my_identity;
196
197
198#endif
diff --git a/src/service/core/gnunet-service-core_kx.c b/src/service/core/gnunet-service-core_kx.c
new file mode 100644
index 000000000..c5a1de769
--- /dev/null
+++ b/src/service/core/gnunet-service-core_kx.c
@@ -0,0 +1,1945 @@
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_transport_core_service.h"
30#include "gnunet-service-core_sessions.h"
31#include "gnunet-service-core.h"
32#include "gnunet_constants.h"
33#include "gnunet_signatures.h"
34#include "gnunet_protocols.h"
35
36/**
37 * Enable expensive (and possibly problematic for privacy!) logging of KX.
38 */
39#define DEBUG_KX 0
40
41/**
42 * How long do we wait for SET_KEY confirmation initially?
43 */
44#define INITIAL_SET_KEY_RETRY_FREQUENCY \
45 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
46
47/**
48 * What is the minimum frequency for a PING message?
49 */
50#define MIN_PING_FREQUENCY \
51 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
52
53/**
54 * How often do we rekey?
55 */
56#define REKEY_FREQUENCY \
57 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
58
59/**
60 * What time difference do we tolerate?
61 */
62#define REKEY_TOLERANCE \
63 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
64
65/**
66 * What is the maximum age of a message for us to consider processing
67 * it? Note that this looks at the timestamp used by the other peer,
68 * so clock skew between machines does come into play here. So this
69 * should be picked high enough so that a little bit of clock skew
70 * does not prevent peers from connecting to us.
71 */
72#define MAX_MESSAGE_AGE GNUNET_TIME_UNIT_DAYS
73
74
75GNUNET_NETWORK_STRUCT_BEGIN
76
77/**
78 * Encapsulation for encrypted messages exchanged between
79 * peers. Followed by the actual encrypted data.
80 */
81struct EncryptedMessage
82{
83 /**
84 * Message type is #GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE.
85 */
86 struct GNUNET_MessageHeader header;
87
88 /**
89 * Random value used for IV generation.
90 */
91 uint32_t iv_seed GNUNET_PACKED;
92
93 /**
94 * MAC of the encrypted message (starting at @e sequence_number),
95 * used to verify message integrity. Everything after this value
96 * (excluding this value itself) will be encrypted and
97 * authenticated. #ENCRYPTED_HEADER_SIZE must be set to the offset
98 * of the *next* field.
99 */
100 struct GNUNET_HashCode hmac;
101
102 /**
103 * Sequence number, in network byte order. This field
104 * must be the first encrypted/decrypted field
105 */
106 uint32_t sequence_number GNUNET_PACKED;
107
108 /**
109 * Reserved, always zero.
110 */
111 uint32_t reserved GNUNET_PACKED;
112
113 /**
114 * Timestamp. Used to prevent replay of ancient messages
115 * (recent messages are caught with the sequence number).
116 */
117 struct GNUNET_TIME_AbsoluteNBO timestamp;
118};
119GNUNET_NETWORK_STRUCT_END
120
121
122/**
123 * Number of bytes (at the beginning) of `struct EncryptedMessage`
124 * that are NOT encrypted.
125 */
126#define ENCRYPTED_HEADER_SIZE \
127 (offsetof (struct EncryptedMessage, sequence_number))
128
129
130/**
131 * Information about the status of a key exchange with another peer.
132 */
133struct GSC_KeyExchangeInfo
134{
135 /**
136 * DLL.
137 */
138 struct GSC_KeyExchangeInfo *next;
139
140 /**
141 * DLL.
142 */
143 struct GSC_KeyExchangeInfo *prev;
144
145 /**
146 * Identity of the peer.
147 */
148 const struct GNUNET_PeerIdentity *peer;
149
150 /**
151 * Message queue for sending messages to @a peer.
152 */
153 struct GNUNET_MQ_Handle *mq;
154
155 /**
156 * Our message stream tokenizer (for encrypted payload).
157 */
158 struct GNUNET_MessageStreamTokenizer *mst;
159
160 /**
161 * PING message we transmit to the other peer.
162 */
163 struct PingMessage ping;
164
165 /**
166 * Ephemeral public ECC key of the other peer.
167 */
168 struct GNUNET_CRYPTO_EcdhePublicKey other_ephemeral_key;
169
170 /**
171 * Key we use to encrypt our messages for the other peer
172 * (initialized by us when we do the handshake).
173 */
174 struct GNUNET_CRYPTO_SymmetricSessionKey encrypt_key;
175
176 /**
177 * Key we use to decrypt messages from the other peer
178 * (given to us by the other peer during the handshake).
179 */
180 struct GNUNET_CRYPTO_SymmetricSessionKey decrypt_key;
181
182 /**
183 * At what time did the other peer generate the decryption key?
184 */
185 struct GNUNET_TIME_Absolute foreign_key_expires;
186
187 /**
188 * When should the session time out (if there are no PONGs)?
189 */
190 struct GNUNET_TIME_Absolute timeout;
191
192 /**
193 * What was the last timeout we informed our monitors about?
194 */
195 struct GNUNET_TIME_Absolute last_notify_timeout;
196
197 /**
198 * At what frequency are we currently re-trying SET_KEY messages?
199 */
200 struct GNUNET_TIME_Relative set_key_retry_frequency;
201
202 /**
203 * ID of task used for re-trying SET_KEY and PING message.
204 */
205 struct GNUNET_SCHEDULER_Task *retry_set_key_task;
206
207 /**
208 * ID of task used for sending keep-alive pings.
209 */
210 struct GNUNET_SCHEDULER_Task *keep_alive_task;
211
212 /**
213 * Bit map indicating which of the 32 sequence numbers before the
214 * last were received (good for accepting out-of-order packets and
215 * estimating reliability of the connection)
216 */
217 uint32_t last_packets_bitmap;
218
219 /**
220 * last sequence number received on this connection (highest)
221 */
222 uint32_t last_sequence_number_received;
223
224 /**
225 * last sequence number transmitted
226 */
227 uint32_t last_sequence_number_sent;
228
229 /**
230 * What was our PING challenge number (for this peer)?
231 */
232 uint32_t ping_challenge;
233
234 /**
235 * #GNUNET_YES if this peer currently has excess bandwidth.
236 */
237 int has_excess_bandwidth;
238
239 /**
240 * What is our connection status?
241 */
242 enum GNUNET_CORE_KxState status;
243};
244
245
246/**
247 * Transport service.
248 */
249static struct GNUNET_TRANSPORT_CoreHandle *transport;
250
251/**
252 * Our private key.
253 */
254static struct GNUNET_CRYPTO_EddsaPrivateKey my_private_key;
255
256/**
257 * Our ephemeral private key.
258 */
259static struct GNUNET_CRYPTO_EcdhePrivateKey my_ephemeral_key;
260
261/**
262 * Current message we send for a key exchange.
263 */
264static struct EphemeralKeyMessage current_ekm;
265
266/**
267 * DLL head.
268 */
269static struct GSC_KeyExchangeInfo *kx_head;
270
271/**
272 * DLL tail.
273 */
274static struct GSC_KeyExchangeInfo *kx_tail;
275
276/**
277 * Task scheduled for periodic re-generation (and thus rekeying) of our
278 * ephemeral key.
279 */
280static struct GNUNET_SCHEDULER_Task *rekey_task;
281
282/**
283 * Notification context for broadcasting to monitors.
284 */
285static struct GNUNET_NotificationContext *nc;
286
287
288/**
289 * Calculate seed value we should use for a message.
290 *
291 * @param kx key exchange context
292 */
293static uint32_t
294calculate_seed (struct GSC_KeyExchangeInfo *kx)
295{
296 /* Note: may want to make this non-random and instead
297 derive from key material to avoid having an undetectable
298 side-channel */
299 return htonl (
300 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX));
301}
302
303
304/**
305 * Inform all monitors about the KX state of the given peer.
306 *
307 * @param kx key exchange state to inform about
308 */
309static void
310monitor_notify_all (struct GSC_KeyExchangeInfo *kx)
311{
312 struct MonitorNotifyMessage msg;
313
314 msg.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_MONITOR_NOTIFY);
315 msg.header.size = htons (sizeof(msg));
316 msg.state = htonl ((uint32_t) kx->status);
317 msg.peer = *kx->peer;
318 msg.timeout = GNUNET_TIME_absolute_hton (kx->timeout);
319 GNUNET_notification_context_broadcast (nc, &msg.header, GNUNET_NO);
320 kx->last_notify_timeout = kx->timeout;
321}
322
323
324/**
325 * Derive an authentication key from "set key" information
326 *
327 * @param akey authentication key to derive
328 * @param skey session key to use
329 * @param seed seed to use
330 */
331static void
332derive_auth_key (struct GNUNET_CRYPTO_AuthKey *akey,
333 const struct GNUNET_CRYPTO_SymmetricSessionKey *skey,
334 uint32_t seed)
335{
336 static const char ctx[] = "authentication key";
337
338#if DEBUG_KX
339 struct GNUNET_HashCode sh;
340
341 GNUNET_CRYPTO_hash (skey, sizeof(*skey), &sh);
342 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
343 "Deriving Auth key from SKEY %s and seed %u\n",
344 GNUNET_h2s (&sh),
345 (unsigned int) seed);
346#endif
347 GNUNET_CRYPTO_hmac_derive_key (akey,
348 skey,
349 &seed,
350 sizeof(seed),
351 skey,
352 sizeof(
353 struct GNUNET_CRYPTO_SymmetricSessionKey),
354 ctx,
355 sizeof(ctx),
356 NULL);
357}
358
359
360/**
361 * Derive an IV from packet information
362 *
363 * @param iv initialization vector to initialize
364 * @param skey session key to use
365 * @param seed seed to use
366 * @param identity identity of the other peer to use
367 */
368static void
369derive_iv (struct GNUNET_CRYPTO_SymmetricInitializationVector *iv,
370 const struct GNUNET_CRYPTO_SymmetricSessionKey *skey,
371 uint32_t seed,
372 const struct GNUNET_PeerIdentity *identity)
373{
374 static const char ctx[] = "initialization vector";
375
376#if DEBUG_KX
377 struct GNUNET_HashCode sh;
378
379 GNUNET_CRYPTO_hash (skey, sizeof(*skey), &sh);
380 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
381 "Deriving IV from SKEY %s and seed %u for peer %s\n",
382 GNUNET_h2s (&sh),
383 (unsigned int) seed,
384 GNUNET_i2s (identity));
385#endif
386 GNUNET_CRYPTO_symmetric_derive_iv (iv,
387 skey,
388 &seed,
389 sizeof(seed),
390 identity,
391 sizeof(struct GNUNET_PeerIdentity),
392 ctx,
393 sizeof(ctx),
394 NULL);
395}
396
397
398/**
399 * Derive an IV from pong packet information
400 *
401 * @param iv initialization vector to initialize
402 * @param skey session key to use
403 * @param seed seed to use
404 * @param challenge nonce to use
405 * @param identity identity of the other peer to use
406 */
407static void
408derive_pong_iv (struct GNUNET_CRYPTO_SymmetricInitializationVector *iv,
409 const struct GNUNET_CRYPTO_SymmetricSessionKey *skey,
410 uint32_t seed,
411 uint32_t challenge,
412 const struct GNUNET_PeerIdentity *identity)
413{
414 static const char ctx[] = "pong initialization vector";
415
416#if DEBUG_KX
417 struct GNUNET_HashCode sh;
418
419 GNUNET_CRYPTO_hash (skey, sizeof(*skey), &sh);
420 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
421 "Deriving PONG IV from SKEY %s and seed %u/%u for %s\n",
422 GNUNET_h2s (&sh),
423 (unsigned int) seed,
424 (unsigned int) challenge,
425 GNUNET_i2s (identity));
426#endif
427 GNUNET_CRYPTO_symmetric_derive_iv (iv,
428 skey,
429 &seed,
430 sizeof(seed),
431 identity,
432 sizeof(struct GNUNET_PeerIdentity),
433 &challenge,
434 sizeof(challenge),
435 ctx,
436 sizeof(ctx),
437 NULL);
438}
439
440
441/**
442 * Derive an AES key from key material
443 *
444 * @param sender peer identity of the sender
445 * @param receiver peer identity of the sender
446 * @param key_material high entropy key material to use
447 * @param skey set to derived session key
448 */
449static void
450derive_aes_key (const struct GNUNET_PeerIdentity *sender,
451 const struct GNUNET_PeerIdentity *receiver,
452 const struct GNUNET_HashCode *key_material,
453 struct GNUNET_CRYPTO_SymmetricSessionKey *skey)
454{
455 static const char ctx[] = "aes key generation vector";
456
457#if DEBUG_KX
458 struct GNUNET_HashCode sh;
459
460 GNUNET_CRYPTO_hash (skey, sizeof(*skey), &sh);
461 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
462 "Deriving AES Keys for %s to %s from %s\n",
463 GNUNET_i2s (sender),
464 GNUNET_i2s2 (receiver),
465 GNUNET_h2s (key_material));
466#endif
467 GNUNET_CRYPTO_kdf (skey,
468 sizeof(struct GNUNET_CRYPTO_SymmetricSessionKey),
469 ctx,
470 sizeof(ctx),
471 key_material,
472 sizeof(struct GNUNET_HashCode),
473 sender,
474 sizeof(struct GNUNET_PeerIdentity),
475 receiver,
476 sizeof(struct GNUNET_PeerIdentity),
477 NULL);
478}
479
480
481/**
482 * Encrypt size bytes from @a in and write the result to @a out. Use the
483 * @a kx key for outbound traffic of the given neighbour.
484 *
485 * @param kx key information context
486 * @param iv initialization vector to use
487 * @param in ciphertext
488 * @param out plaintext
489 * @param size size of @a in / @a out
490 *
491 * @return #GNUNET_OK on success
492 */
493static int
494do_encrypt (struct GSC_KeyExchangeInfo *kx,
495 const struct GNUNET_CRYPTO_SymmetricInitializationVector *iv,
496 const void *in,
497 void *out,
498 size_t size)
499{
500 if (size != (uint16_t) size)
501 {
502 GNUNET_break (0);
503 return GNUNET_NO;
504 }
505 GNUNET_assert (size == GNUNET_CRYPTO_symmetric_encrypt (in,
506 (uint16_t) size,
507 &kx->encrypt_key,
508 iv,
509 out));
510 GNUNET_STATISTICS_update (GSC_stats,
511 gettext_noop ("# bytes encrypted"),
512 size,
513 GNUNET_NO);
514 /* the following is too sensitive to write to log files by accident,
515 so we require manual intervention to get this one... */
516#if DEBUG_KX
517 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
518 "Encrypted %u bytes for `%s' using key %s, IV %u\n",
519 (unsigned int) size,
520 GNUNET_i2s (kx->peer),
521 kx->encrypt_key.aes_key,
522 GNUNET_CRYPTO_crc32_n (iv, sizeof(iv)));
523#endif
524 return GNUNET_OK;
525}
526
527
528/**
529 * Decrypt size bytes from @a in and write the result to @a out. Use
530 * the @a kx key for inbound traffic of the given neighbour. This
531 * function does NOT do any integrity-checks on the result.
532 *
533 * @param kx key information context
534 * @param iv initialization vector to use
535 * @param in ciphertext
536 * @param out plaintext
537 * @param size size of @a in / @a out
538 * @return #GNUNET_OK on success
539 */
540static int
541do_decrypt (struct GSC_KeyExchangeInfo *kx,
542 const struct GNUNET_CRYPTO_SymmetricInitializationVector *iv,
543 const void *in,
544 void *out,
545 size_t size)
546{
547 if (size != (uint16_t) size)
548 {
549 GNUNET_break (0);
550 return GNUNET_NO;
551 }
552 if ((kx->status != GNUNET_CORE_KX_STATE_KEY_RECEIVED) &&
553 (kx->status != GNUNET_CORE_KX_STATE_UP) &&
554 (kx->status != GNUNET_CORE_KX_STATE_REKEY_SENT))
555 {
556 GNUNET_break_op (0);
557 return GNUNET_SYSERR;
558 }
559 if (size != GNUNET_CRYPTO_symmetric_decrypt (in,
560 (uint16_t) size,
561 &kx->decrypt_key,
562 iv,
563 out))
564 {
565 GNUNET_break (0);
566 return GNUNET_SYSERR;
567 }
568 GNUNET_STATISTICS_update (GSC_stats,
569 gettext_noop ("# bytes decrypted"),
570 size,
571 GNUNET_NO);
572 /* the following is too sensitive to write to log files by accident,
573 so we require manual intervention to get this one... */
574#if DEBUG_KX
575 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
576 "Decrypted %u bytes from `%s' using key %s, IV %u\n",
577 (unsigned int) size,
578 GNUNET_i2s (kx->peer),
579 kx->decrypt_key.aes_key,
580 GNUNET_CRYPTO_crc32_n (iv, sizeof(*iv)));
581#endif
582 return GNUNET_OK;
583}
584
585
586/**
587 * Send our key (and encrypted PING) to the other peer.
588 *
589 * @param kx key exchange context
590 */
591static void
592send_key (struct GSC_KeyExchangeInfo *kx);
593
594
595/**
596 * Task that will retry #send_key() if our previous attempt failed.
597 *
598 * @param cls our `struct GSC_KeyExchangeInfo`
599 */
600static void
601set_key_retry_task (void *cls)
602{
603 struct GSC_KeyExchangeInfo *kx = cls;
604
605 kx->retry_set_key_task = NULL;
606 kx->set_key_retry_frequency =
607 GNUNET_TIME_STD_BACKOFF (kx->set_key_retry_frequency);
608 GNUNET_assert (GNUNET_CORE_KX_STATE_DOWN != kx->status);
609 send_key (kx);
610}
611
612
613/**
614 * Create a fresh PING message for transmission to the other peer.
615 *
616 * @param kx key exchange context to create PING for
617 */
618static void
619setup_fresh_ping (struct GSC_KeyExchangeInfo *kx)
620{
621 struct PingMessage pp;
622 struct PingMessage *pm;
623 struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
624
625 pm = &kx->ping;
626 kx->ping_challenge =
627 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX);
628 pm->header.size = htons (sizeof(struct PingMessage));
629 pm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_PING);
630 pm->iv_seed = calculate_seed (kx);
631 derive_iv (&iv, &kx->encrypt_key, pm->iv_seed, kx->peer);
632 pp.challenge = kx->ping_challenge;
633 pp.target = *kx->peer;
634 do_encrypt (kx,
635 &iv,
636 &pp.target,
637 &pm->target,
638 sizeof(struct PingMessage)
639 - ((void *) &pm->target - (void *) pm));
640}
641
642
643/**
644 * Deliver P2P message to interested clients. Invokes send twice,
645 * once for clients that want the full message, and once for clients
646 * that only want the header
647 *
648 * @param cls the `struct GSC_KeyExchangeInfo`
649 * @param m the message
650 * @return #GNUNET_OK on success,
651 * #GNUNET_NO to stop further processing (no error)
652 * #GNUNET_SYSERR to stop further processing with error
653 */
654static int
655deliver_message (void *cls, const struct GNUNET_MessageHeader *m)
656{
657 struct GSC_KeyExchangeInfo *kx = cls;
658
659 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
660 "Decrypted message of type %d from %s\n",
661 ntohs (m->type),
662 GNUNET_i2s (kx->peer));
663 if (GNUNET_CORE_KX_STATE_UP != kx->status)
664 {
665 GNUNET_STATISTICS_update (GSC_stats,
666 gettext_noop ("# PAYLOAD dropped (out of order)"),
667 1,
668 GNUNET_NO);
669 return GNUNET_OK;
670 }
671 switch (ntohs (m->type))
672 {
673 case GNUNET_MESSAGE_TYPE_CORE_BINARY_TYPE_MAP:
674 case GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP:
675 GSC_SESSIONS_set_typemap (kx->peer, m);
676 return GNUNET_OK;
677
678 case GNUNET_MESSAGE_TYPE_CORE_CONFIRM_TYPE_MAP:
679 GSC_SESSIONS_confirm_typemap (kx->peer, m);
680 return GNUNET_OK;
681
682 default:
683 GSC_CLIENTS_deliver_message (kx->peer,
684 m,
685 ntohs (m->size),
686 GNUNET_CORE_OPTION_SEND_FULL_INBOUND);
687 GSC_CLIENTS_deliver_message (kx->peer,
688 m,
689 sizeof(struct GNUNET_MessageHeader),
690 GNUNET_CORE_OPTION_SEND_HDR_INBOUND);
691 }
692 return GNUNET_OK;
693}
694
695
696/**
697 * Function called by transport to notify us that
698 * a peer connected to us (on the network level).
699 * Starts the key exchange with the given peer.
700 *
701 * @param cls closure (NULL)
702 * @param pid identity of the peer to do a key exchange with
703 * @return key exchange information context
704 */
705static void *
706handle_transport_notify_connect (void *cls,
707 const struct GNUNET_PeerIdentity *pid,
708 struct GNUNET_MQ_Handle *mq)
709{
710 struct GSC_KeyExchangeInfo *kx;
711 struct GNUNET_HashCode h1;
712 struct GNUNET_HashCode h2;
713
714 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
715 "Initiating key exchange with `%s'\n",
716 GNUNET_i2s (pid));
717 GNUNET_STATISTICS_update (GSC_stats,
718 gettext_noop ("# key exchanges initiated"),
719 1,
720 GNUNET_NO);
721
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 */
763static void
764handle_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 */
801static void
802send_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 */
820static void
821derive_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 */
850static void
851handle_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 enum GNUNET_GenericReturnValue do_verify = GNUNET_YES;
859
860 end_t = GNUNET_TIME_absolute_ntoh (m->expiration_time);
861 if (((GNUNET_CORE_KX_STATE_KEY_RECEIVED == kx->status) ||
862 (GNUNET_CORE_KX_STATE_UP == kx->status) ||
863 (GNUNET_CORE_KX_STATE_REKEY_SENT == kx->status)) &&
864 (end_t.abs_value_us < kx->foreign_key_expires.abs_value_us))
865 {
866 GNUNET_STATISTICS_update (GSC_stats,
867 gettext_noop ("# old ephemeral keys ignored"),
868 1,
869 GNUNET_NO);
870 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
871 "Received expired EPHEMERAL_KEY from %s\n",
872 GNUNET_i2s (&m->origin_identity));
873 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
874 return;
875 }
876 if (0 == memcmp (&m->ephemeral_key,
877 &kx->other_ephemeral_key,
878 sizeof(m->ephemeral_key)))
879 {
880 GNUNET_STATISTICS_update (GSC_stats,
881 gettext_noop (
882 "# duplicate ephemeral keys. Not verifying."),
883 1,
884 GNUNET_NO);
885 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
886 "Duplicate EPHEMERAL_KEY from %s, do not verify\n",
887 GNUNET_i2s (&m->origin_identity));
888 do_verify = GNUNET_NO;
889 }
890 if (0 != memcmp (&m->origin_identity,
891 kx->peer,
892 sizeof(struct GNUNET_PeerIdentity)))
893 {
894 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
895 "Received EPHEMERAL_KEY from %s, but expected %s\n",
896 GNUNET_i2s (&m->origin_identity),
897 GNUNET_i2s_full (kx->peer));
898 GNUNET_break_op (0);
899 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
900 return;
901 }
902 if (do_verify && ((ntohl (m->purpose.size) !=
903 sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose)
904 + sizeof(struct GNUNET_TIME_AbsoluteNBO)
905 + sizeof(struct GNUNET_TIME_AbsoluteNBO)
906 + sizeof(struct GNUNET_CRYPTO_EddsaPublicKey)
907 + sizeof(struct GNUNET_CRYPTO_EddsaPublicKey)) ||
908 (GNUNET_OK !=
909 GNUNET_CRYPTO_eddsa_verify_ (GNUNET_SIGNATURE_PURPOSE_SET_ECC_KEY,
910 &m->purpose,
911 &m->signature,
912 &m->origin_identity.public_key))))
913 {
914 /* invalid signature */
915 GNUNET_break_op (0);
916 GNUNET_STATISTICS_update (GSC_stats,
917 gettext_noop (
918 "# EPHEMERAL_KEYs rejected (bad signature)"),
919 1,
920 GNUNET_NO);
921 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
922 "Received EPHEMERAL_KEY from %s with bad signature\n",
923 GNUNET_i2s (&m->origin_identity));
924 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
925 return;
926 }
927 now = GNUNET_TIME_absolute_get ();
928 start_t = GNUNET_TIME_absolute_ntoh (m->creation_time);
929 if ((end_t.abs_value_us <
930 GNUNET_TIME_absolute_subtract (now, REKEY_TOLERANCE).abs_value_us) ||
931 (start_t.abs_value_us >
932 GNUNET_TIME_absolute_add (now, REKEY_TOLERANCE).abs_value_us))
933 {
934 GNUNET_log (
935 GNUNET_ERROR_TYPE_WARNING,
936 _ (
937 "EPHEMERAL_KEY from peer `%s' rejected as its validity range does not match our system time (%llu not in [%llu,%llu]).\n"),
938 GNUNET_i2s (kx->peer),
939 (unsigned long long) now.abs_value_us,
940 (unsigned long long) start_t.abs_value_us,
941 (unsigned long long) end_t.abs_value_us);
942 GNUNET_STATISTICS_update (GSC_stats,
943 gettext_noop (
944 "# EPHEMERAL_KEY messages rejected due to time"),
945 1,
946 GNUNET_NO);
947 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
948 return;
949 }
950#if DEBUG_KX
951 {
952 struct GNUNET_HashCode eh;
953
954 GNUNET_CRYPTO_hash (&m->ephemeral_key, sizeof(m->ephemeral_key), &eh);
955 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
956 "Received valid EPHEMERAL_KEY `%s' from `%s' in state %d.\n",
957 GNUNET_h2s (&eh),
958 GNUNET_i2s (kx->peer),
959 kx->status);
960 }
961#endif
962 GNUNET_STATISTICS_update (GSC_stats,
963 gettext_noop ("# valid ephemeral keys received"),
964 1,
965 GNUNET_NO);
966 kx->other_ephemeral_key = m->ephemeral_key;
967 kx->foreign_key_expires = end_t;
968 derive_session_keys (kx);
969
970 /* check if we still need to send the sender our key */
971 sender_status = (enum GNUNET_CORE_KxState) ntohl (m->sender_status);
972 switch (sender_status)
973 {
974 case GNUNET_CORE_KX_STATE_DOWN:
975 GNUNET_break_op (0);
976 break;
977
978 case GNUNET_CORE_KX_STATE_KEY_SENT:
979 /* fine, need to send our key after updating our status, see below */
980 GSC_SESSIONS_reinit (kx->peer);
981 break;
982
983 case GNUNET_CORE_KX_STATE_KEY_RECEIVED:
984 /* other peer already got our key, but typemap did go down */
985 GSC_SESSIONS_reinit (kx->peer);
986 break;
987
988 case GNUNET_CORE_KX_STATE_UP:
989 /* other peer already got our key, typemap NOT down */
990 break;
991
992 case GNUNET_CORE_KX_STATE_REKEY_SENT:
993 /* other peer already got our key, typemap NOT down */
994 break;
995
996 default:
997 GNUNET_break (0);
998 break;
999 }
1000 /* check if we need to confirm everything is fine via PING + PONG */
1001 switch (kx->status)
1002 {
1003 case GNUNET_CORE_KX_STATE_DOWN:
1004 GNUNET_assert (NULL == kx->keep_alive_task);
1005 kx->status = GNUNET_CORE_KX_STATE_KEY_RECEIVED;
1006 monitor_notify_all (kx);
1007 if (GNUNET_CORE_KX_STATE_KEY_SENT == sender_status)
1008 send_key (kx);
1009 else
1010 send_ping (kx);
1011 break;
1012
1013 case GNUNET_CORE_KX_STATE_KEY_SENT:
1014 GNUNET_assert (NULL == kx->keep_alive_task);
1015 kx->status = GNUNET_CORE_KX_STATE_KEY_RECEIVED;
1016 monitor_notify_all (kx);
1017 if (GNUNET_CORE_KX_STATE_KEY_SENT == sender_status)
1018 send_key (kx);
1019 else
1020 send_ping (kx);
1021 break;
1022
1023 case GNUNET_CORE_KX_STATE_KEY_RECEIVED:
1024 GNUNET_assert (NULL == kx->keep_alive_task);
1025 if (GNUNET_CORE_KX_STATE_KEY_SENT == sender_status)
1026 send_key (kx);
1027 else
1028 send_ping (kx);
1029 break;
1030
1031 case GNUNET_CORE_KX_STATE_UP:
1032 kx->status = GNUNET_CORE_KX_STATE_REKEY_SENT;
1033 monitor_notify_all (kx);
1034 if (GNUNET_CORE_KX_STATE_KEY_SENT == sender_status)
1035 send_key (kx);
1036 else
1037 send_ping (kx);
1038 break;
1039
1040 case GNUNET_CORE_KX_STATE_REKEY_SENT:
1041 if (GNUNET_CORE_KX_STATE_KEY_SENT == sender_status)
1042 send_key (kx);
1043 else
1044 send_ping (kx);
1045 break;
1046
1047 default:
1048 GNUNET_break (0);
1049 break;
1050 }
1051 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
1052}
1053
1054
1055static void
1056send_keep_alive (void *cls);
1057
1058
1059/**
1060 * We received a PING message. Validate and transmit
1061 * a PONG message.
1062 *
1063 * @param cls key exchange status for the corresponding peer
1064 * @param m the encrypted PING message itself
1065 */
1066static void
1067handle_ping (void *cls, const struct PingMessage *m)
1068{
1069 struct GSC_KeyExchangeInfo *kx = cls;
1070 struct PingMessage t;
1071 struct PongMessage tx;
1072 struct PongMessage *tp;
1073 struct GNUNET_MQ_Envelope *env;
1074 struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
1075
1076 GNUNET_STATISTICS_update (GSC_stats,
1077 gettext_noop ("# PING messages received"),
1078 1,
1079 GNUNET_NO);
1080 if ((kx->status != GNUNET_CORE_KX_STATE_KEY_RECEIVED) &&
1081 (kx->status != GNUNET_CORE_KX_STATE_UP) &&
1082 (kx->status != GNUNET_CORE_KX_STATE_REKEY_SENT))
1083 {
1084 /* ignore */
1085 GNUNET_STATISTICS_update (GSC_stats,
1086 gettext_noop (
1087 "# PING messages dropped (out of order)"),
1088 1,
1089 GNUNET_NO);
1090 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
1091 return;
1092 }
1093 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1094 "Core service receives PING request from `%s'.\n",
1095 GNUNET_i2s (kx->peer));
1096 derive_iv (&iv, &kx->decrypt_key, m->iv_seed, &GSC_my_identity);
1097 if (GNUNET_OK != do_decrypt (kx,
1098 &iv,
1099 &m->target,
1100 &t.target,
1101 sizeof(struct PingMessage)
1102 - ((void *) &m->target - (void *) m)))
1103 {
1104 GNUNET_break_op (0);
1105 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
1106 return;
1107 }
1108 if (0 !=
1109 memcmp (&t.target, &GSC_my_identity, sizeof(struct GNUNET_PeerIdentity)))
1110 {
1111 if (GNUNET_CORE_KX_STATE_REKEY_SENT != kx->status)
1112 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1113 "Decryption of PING from peer `%s' failed, PING for `%s'?\n",
1114 GNUNET_i2s (kx->peer),
1115 GNUNET_i2s2 (&t.target));
1116 else
1117 GNUNET_log (
1118 GNUNET_ERROR_TYPE_DEBUG,
1119 "Decryption of PING from peer `%s' failed after rekey (harmless)\n",
1120 GNUNET_i2s (kx->peer));
1121 GNUNET_break_op (0);
1122 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
1123 return;
1124 }
1125 /* construct PONG */
1126 tx.reserved = 0;
1127 tx.challenge = t.challenge;
1128 tx.target = t.target;
1129 env = GNUNET_MQ_msg (tp, GNUNET_MESSAGE_TYPE_CORE_PONG);
1130 tp->iv_seed = calculate_seed (kx);
1131 derive_pong_iv (&iv, &kx->encrypt_key, tp->iv_seed, t.challenge, kx->peer);
1132 do_encrypt (kx,
1133 &iv,
1134 &tx.challenge,
1135 &tp->challenge,
1136 sizeof(struct PongMessage)
1137 - ((void *) &tp->challenge - (void *) tp));
1138 GNUNET_STATISTICS_update (GSC_stats,
1139 gettext_noop ("# PONG messages created"),
1140 1,
1141 GNUNET_NO);
1142 GNUNET_MQ_send (kx->mq, env);
1143 if (NULL != kx->keep_alive_task)
1144 {
1145 GNUNET_SCHEDULER_cancel (kx->keep_alive_task);
1146 kx->keep_alive_task = GNUNET_SCHEDULER_add_delayed (MIN_PING_FREQUENCY, &send_keep_alive, kx);
1147 }
1148 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
1149}
1150
1151
1152/**
1153 * Task triggered when a neighbour entry is about to time out
1154 * (and we should prevent this by sending a PING).
1155 *
1156 * @param cls the `struct GSC_KeyExchangeInfo`
1157 */
1158static void
1159send_keep_alive (void *cls)
1160{
1161 struct GSC_KeyExchangeInfo *kx = cls;
1162 struct GNUNET_TIME_Relative retry;
1163 struct GNUNET_TIME_Relative left;
1164
1165 kx->keep_alive_task = NULL;
1166 left = GNUNET_TIME_absolute_get_remaining (kx->timeout);
1167 if (0 == left.rel_value_us)
1168 {
1169 GNUNET_STATISTICS_update (GSC_stats,
1170 gettext_noop ("# sessions terminated by timeout"),
1171 1,
1172 GNUNET_NO);
1173 GSC_SESSIONS_end (kx->peer);
1174 kx->status = GNUNET_CORE_KX_STATE_KEY_SENT;
1175 monitor_notify_all (kx);
1176 send_key (kx);
1177 return;
1178 }
1179 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1180 "Sending KEEPALIVE to `%s'\n",
1181 GNUNET_i2s (kx->peer));
1182 GNUNET_STATISTICS_update (GSC_stats,
1183 gettext_noop ("# keepalive messages sent"),
1184 1,
1185 GNUNET_NO);
1186 setup_fresh_ping (kx);
1187 send_ping (kx);
1188 retry = GNUNET_TIME_relative_max (GNUNET_TIME_relative_divide (left, 2),
1189 MIN_PING_FREQUENCY);
1190 kx->keep_alive_task =
1191 GNUNET_SCHEDULER_add_delayed (retry, &send_keep_alive, kx);
1192}
1193
1194
1195/**
1196 * We've seen a valid message from the other peer.
1197 * Update the time when the session would time out
1198 * and delay sending our keep alive message further.
1199 *
1200 * @param kx key exchange where we saw activity
1201 */
1202static void
1203update_timeout (struct GSC_KeyExchangeInfo *kx)
1204{
1205 struct GNUNET_TIME_Relative delta;
1206
1207 kx->timeout =
1208 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1209 delta =
1210 GNUNET_TIME_absolute_get_difference (kx->last_notify_timeout, kx->timeout);
1211 if (delta.rel_value_us > 5LL * 1000LL * 1000LL)
1212 {
1213 /* we only notify monitors about timeout changes if those
1214 are bigger than the threshold (5s) */
1215 monitor_notify_all (kx);
1216 }
1217 if (NULL != kx->keep_alive_task)
1218 GNUNET_SCHEDULER_cancel (kx->keep_alive_task);
1219 kx->keep_alive_task = GNUNET_SCHEDULER_add_delayed (
1220 GNUNET_TIME_relative_divide (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, 2),
1221 &send_keep_alive,
1222 kx);
1223}
1224
1225
1226/**
1227 * We received a PONG message. Validate and update our status.
1228 *
1229 * @param kx key exchange context for the the PONG
1230 * @param m the encrypted PONG message itself
1231 */
1232static void
1233handle_pong (void *cls, const struct PongMessage *m)
1234{
1235 struct GSC_KeyExchangeInfo *kx = cls;
1236 struct PongMessage t;
1237 struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
1238
1239 GNUNET_STATISTICS_update (GSC_stats,
1240 gettext_noop ("# PONG messages received"),
1241 1,
1242 GNUNET_NO);
1243 switch (kx->status)
1244 {
1245 case GNUNET_CORE_KX_STATE_DOWN:
1246 GNUNET_STATISTICS_update (GSC_stats,
1247 gettext_noop (
1248 "# PONG messages dropped (connection down)"),
1249 1,
1250 GNUNET_NO);
1251 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
1252 return;
1253
1254 case GNUNET_CORE_KX_STATE_KEY_SENT:
1255 GNUNET_STATISTICS_update (GSC_stats,
1256 gettext_noop (
1257 "# PONG messages dropped (out of order)"),
1258 1,
1259 GNUNET_NO);
1260 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
1261 return;
1262
1263 case GNUNET_CORE_KX_STATE_KEY_RECEIVED:
1264 break;
1265
1266 case GNUNET_CORE_KX_STATE_UP:
1267 break;
1268
1269 case GNUNET_CORE_KX_STATE_REKEY_SENT:
1270 break;
1271
1272 default:
1273 GNUNET_break (0);
1274 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
1275 return;
1276 }
1277 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1278 "Core service receives PONG response from `%s'.\n",
1279 GNUNET_i2s (kx->peer));
1280 /* mark as garbage, just to be sure */
1281 memset (&t, 255, sizeof(t));
1282 derive_pong_iv (&iv,
1283 &kx->decrypt_key,
1284 m->iv_seed,
1285 kx->ping_challenge,
1286 &GSC_my_identity);
1287 if (GNUNET_OK != do_decrypt (kx,
1288 &iv,
1289 &m->challenge,
1290 &t.challenge,
1291 sizeof(struct PongMessage)
1292 - ((void *) &m->challenge - (void *) m)))
1293 {
1294 GNUNET_break_op (0);
1295 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
1296 return;
1297 }
1298 GNUNET_STATISTICS_update (GSC_stats,
1299 gettext_noop ("# PONG messages decrypted"),
1300 1,
1301 GNUNET_NO);
1302 if ((0 !=
1303 memcmp (&t.target, kx->peer, sizeof(struct GNUNET_PeerIdentity))) ||
1304 (kx->ping_challenge != t.challenge))
1305 {
1306 /* PONG malformed */
1307 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1308 "Received malformed PONG wanted sender `%s' with challenge %u\n",
1309 GNUNET_i2s (kx->peer),
1310 (unsigned int) kx->ping_challenge);
1311 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1312 "Received malformed PONG received from `%s' with challenge %u\n",
1313 GNUNET_i2s (&t.target),
1314 (unsigned int) t.challenge);
1315 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
1316 return;
1317 }
1318 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1319 "Received valid PONG from `%s'\n",
1320 GNUNET_i2s (kx->peer));
1321 /* no need to resend key any longer */
1322 if (NULL != kx->retry_set_key_task)
1323 {
1324 GNUNET_SCHEDULER_cancel (kx->retry_set_key_task);
1325 kx->retry_set_key_task = NULL;
1326 }
1327 switch (kx->status)
1328 {
1329 case GNUNET_CORE_KX_STATE_DOWN:
1330 GNUNET_assert (0); /* should be impossible */
1331 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
1332 return;
1333
1334 case GNUNET_CORE_KX_STATE_KEY_SENT:
1335 GNUNET_assert (0); /* should be impossible */
1336 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
1337 return;
1338
1339 case GNUNET_CORE_KX_STATE_KEY_RECEIVED:
1340 GNUNET_STATISTICS_update (GSC_stats,
1341 gettext_noop (
1342 "# session keys confirmed via PONG"),
1343 1,
1344 GNUNET_NO);
1345 kx->status = GNUNET_CORE_KX_STATE_UP;
1346 monitor_notify_all (kx);
1347 GSC_SESSIONS_create (kx->peer, kx);
1348 GNUNET_assert (NULL == kx->keep_alive_task);
1349 update_timeout (kx);
1350 break;
1351
1352 case GNUNET_CORE_KX_STATE_UP:
1353 GNUNET_STATISTICS_update (GSC_stats,
1354 gettext_noop ("# timeouts prevented via PONG"),
1355 1,
1356 GNUNET_NO);
1357 update_timeout (kx);
1358 break;
1359
1360 case GNUNET_CORE_KX_STATE_REKEY_SENT:
1361 GNUNET_STATISTICS_update (GSC_stats,
1362 gettext_noop (
1363 "# rekey operations confirmed via PONG"),
1364 1,
1365 GNUNET_NO);
1366 kx->status = GNUNET_CORE_KX_STATE_UP;
1367 monitor_notify_all (kx);
1368 update_timeout (kx);
1369 break;
1370
1371 default:
1372 GNUNET_break (0);
1373 break;
1374 }
1375 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
1376}
1377
1378
1379/**
1380 * Send our key to the other peer.
1381 *
1382 * @param kx key exchange context
1383 */
1384static void
1385send_key (struct GSC_KeyExchangeInfo *kx)
1386{
1387 struct GNUNET_MQ_Envelope *env;
1388
1389 GNUNET_assert (GNUNET_CORE_KX_STATE_DOWN != kx->status);
1390 if (NULL != kx->retry_set_key_task)
1391 {
1392 GNUNET_SCHEDULER_cancel (kx->retry_set_key_task);
1393 kx->retry_set_key_task = NULL;
1394 }
1395 /* always update sender status in SET KEY message */
1396#if DEBUG_KX
1397 {
1398 struct GNUNET_HashCode hc;
1399
1400 GNUNET_CRYPTO_hash (&current_ekm.ephemeral_key,
1401 sizeof(current_ekm.ephemeral_key),
1402 &hc);
1403 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1404 "Sending EPHEMERAL_KEY %s to `%s' (my status: %d)\n",
1405 GNUNET_h2s (&hc),
1406 GNUNET_i2s (kx->peer),
1407 kx->status);
1408 }
1409#endif
1410 current_ekm.sender_status = htonl ((int32_t) (kx->status));
1411 env = GNUNET_MQ_msg_copy (&current_ekm.header);
1412 GNUNET_MQ_send (kx->mq, env);
1413 if (GNUNET_CORE_KX_STATE_KEY_SENT != kx->status)
1414 send_ping (kx);
1415 kx->retry_set_key_task =
1416 GNUNET_SCHEDULER_add_delayed (kx->set_key_retry_frequency,
1417 &set_key_retry_task,
1418 kx);
1419}
1420
1421
1422void
1423GSC_KX_encrypt_and_transmit (struct GSC_KeyExchangeInfo *kx,
1424 const void *payload,
1425 size_t payload_size)
1426{
1427 size_t used = payload_size + sizeof(struct EncryptedMessage);
1428 char pbuf[used]; /* plaintext */
1429 struct EncryptedMessage *em; /* encrypted message */
1430 struct EncryptedMessage *ph; /* plaintext header */
1431 struct GNUNET_MQ_Envelope *env;
1432 struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
1433 struct GNUNET_CRYPTO_AuthKey auth_key;
1434
1435 ph = (struct EncryptedMessage *) pbuf;
1436 ph->sequence_number = htonl (++kx->last_sequence_number_sent);
1437 ph->iv_seed = calculate_seed (kx);
1438 ph->reserved = 0;
1439 ph->timestamp = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
1440 GNUNET_memcpy (&ph[1], payload, payload_size);
1441 env = GNUNET_MQ_msg_extra (em,
1442 payload_size,
1443 GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE);
1444 em->iv_seed = ph->iv_seed;
1445 derive_iv (&iv, &kx->encrypt_key, ph->iv_seed, kx->peer);
1446 GNUNET_assert (GNUNET_OK == do_encrypt (kx,
1447 &iv,
1448 &ph->sequence_number,
1449 &em->sequence_number,
1450 used - ENCRYPTED_HEADER_SIZE));
1451#if DEBUG_KX
1452 {
1453 struct GNUNET_HashCode hc;
1454
1455 GNUNET_CRYPTO_hash (&ph->sequence_number,
1456 used - ENCRYPTED_HEADER_SIZE,
1457 &hc);
1458 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1459 "Encrypted payload `%s' of %u bytes for %s\n",
1460 GNUNET_h2s (&hc),
1461 (unsigned int) (used - ENCRYPTED_HEADER_SIZE),
1462 GNUNET_i2s (kx->peer));
1463 }
1464#endif
1465 derive_auth_key (&auth_key, &kx->encrypt_key, ph->iv_seed);
1466 GNUNET_CRYPTO_hmac (&auth_key,
1467 &em->sequence_number,
1468 used - ENCRYPTED_HEADER_SIZE,
1469 &em->hmac);
1470#if DEBUG_KX
1471 {
1472 struct GNUNET_HashCode hc;
1473
1474 GNUNET_CRYPTO_hash (&auth_key, sizeof(auth_key), &hc);
1475 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1476 "For peer %s, used AC %s to create hmac %s\n",
1477 GNUNET_i2s (kx->peer),
1478 GNUNET_h2s (&hc),
1479 GNUNET_h2s2 (&em->hmac));
1480 }
1481#endif
1482 kx->has_excess_bandwidth = GNUNET_NO;
1483 GNUNET_MQ_send (kx->mq, env);
1484}
1485
1486
1487/**
1488 * We received an encrypted message. Check that it is
1489 * well-formed (size-wise).
1490 *
1491 * @param cls key exchange context for encrypting the message
1492 * @param m encrypted message
1493 * @return #GNUNET_OK if @a msg is well-formed (size-wise)
1494 */
1495static int
1496check_encrypted (void *cls, const struct EncryptedMessage *m)
1497{
1498 uint16_t size = ntohs (m->header.size) - sizeof(*m);
1499
1500 if (size < sizeof(struct GNUNET_MessageHeader))
1501 {
1502 GNUNET_break_op (0);
1503 return GNUNET_SYSERR;
1504 }
1505 return GNUNET_OK;
1506}
1507
1508
1509/**
1510 * We received an encrypted message. Decrypt, validate and
1511 * pass on to the appropriate clients.
1512 *
1513 * @param cls key exchange context for encrypting the message
1514 * @param m encrypted message
1515 */
1516static void
1517handle_encrypted (void *cls, const struct EncryptedMessage *m)
1518{
1519 struct GSC_KeyExchangeInfo *kx = cls;
1520 struct EncryptedMessage *pt; /* plaintext */
1521 struct GNUNET_HashCode ph;
1522 uint32_t snum;
1523 struct GNUNET_TIME_Absolute t;
1524 struct GNUNET_CRYPTO_SymmetricInitializationVector iv;
1525 struct GNUNET_CRYPTO_AuthKey auth_key;
1526 uint16_t size = ntohs (m->header.size);
1527 char buf[size] GNUNET_ALIGN;
1528
1529 if (GNUNET_CORE_KX_STATE_UP != kx->status)
1530 {
1531 GNUNET_STATISTICS_update (GSC_stats,
1532 gettext_noop (
1533 "# DATA message dropped (out of order)"),
1534 1,
1535 GNUNET_NO);
1536 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
1537 return;
1538 }
1539 if (0 ==
1540 GNUNET_TIME_absolute_get_remaining (kx->foreign_key_expires).rel_value_us)
1541 {
1542 GNUNET_log (
1543 GNUNET_ERROR_TYPE_WARNING,
1544 _ (
1545 "Session to peer `%s' went down due to key expiration (should not happen)\n"),
1546 GNUNET_i2s (kx->peer));
1547 GNUNET_STATISTICS_update (GSC_stats,
1548 gettext_noop (
1549 "# sessions terminated by key expiration"),
1550 1,
1551 GNUNET_NO);
1552 GSC_SESSIONS_end (kx->peer);
1553 if (NULL != kx->keep_alive_task)
1554 {
1555 GNUNET_SCHEDULER_cancel (kx->keep_alive_task);
1556 kx->keep_alive_task = NULL;
1557 }
1558 kx->status = GNUNET_CORE_KX_STATE_KEY_SENT;
1559 monitor_notify_all (kx);
1560 send_key (kx);
1561 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
1562 return;
1563 }
1564
1565 /* validate hash */
1566#if DEBUG_KX
1567 {
1568 struct GNUNET_HashCode hc;
1569
1570 GNUNET_CRYPTO_hash (&m->sequence_number, size - ENCRYPTED_HEADER_SIZE, &hc);
1571 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1572 "Received encrypted payload `%s' of %u bytes from %s\n",
1573 GNUNET_h2s (&hc),
1574 (unsigned int) (size - ENCRYPTED_HEADER_SIZE),
1575 GNUNET_i2s (kx->peer));
1576 }
1577#endif
1578 derive_auth_key (&auth_key, &kx->decrypt_key, m->iv_seed);
1579 GNUNET_CRYPTO_hmac (&auth_key,
1580 &m->sequence_number,
1581 size - ENCRYPTED_HEADER_SIZE,
1582 &ph);
1583#if DEBUG_KX
1584 {
1585 struct GNUNET_HashCode hc;
1586
1587 GNUNET_CRYPTO_hash (&auth_key, sizeof(auth_key), &hc);
1588 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1589 "For peer %s, used AC %s to verify hmac %s\n",
1590 GNUNET_i2s (kx->peer),
1591 GNUNET_h2s (&hc),
1592 GNUNET_h2s2 (&m->hmac));
1593 }
1594#endif
1595 if (0 != memcmp (&ph, &m->hmac, sizeof(struct GNUNET_HashCode)))
1596 {
1597 /* checksum failed */
1598 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1599 "Failed checksum validation for a message from `%s'\n",
1600 GNUNET_i2s (kx->peer));
1601 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
1602 return;
1603 }
1604 derive_iv (&iv, &kx->decrypt_key, m->iv_seed, &GSC_my_identity);
1605 /* decrypt */
1606 if (GNUNET_OK != do_decrypt (kx,
1607 &iv,
1608 &m->sequence_number,
1609 &buf[ENCRYPTED_HEADER_SIZE],
1610 size - ENCRYPTED_HEADER_SIZE))
1611 {
1612 GNUNET_break_op (0);
1613 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
1614 return;
1615 }
1616 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1617 "Decrypted %u bytes from %s\n",
1618 (unsigned int) (size - ENCRYPTED_HEADER_SIZE),
1619 GNUNET_i2s (kx->peer));
1620 pt = (struct EncryptedMessage *) buf;
1621
1622 /* validate sequence number */
1623 snum = ntohl (pt->sequence_number);
1624 if (kx->last_sequence_number_received == snum)
1625 {
1626 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1627 "Received duplicate message, ignoring.\n");
1628 /* duplicate, ignore */
1629 GNUNET_STATISTICS_update (GSC_stats,
1630 gettext_noop ("# bytes dropped (duplicates)"),
1631 size,
1632 GNUNET_NO);
1633 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
1634 return;
1635 }
1636 if ((kx->last_sequence_number_received > snum) &&
1637 (kx->last_sequence_number_received - snum > 32))
1638 {
1639 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1640 "Received ancient out of sequence message, ignoring.\n");
1641 /* ancient out of sequence, ignore */
1642 GNUNET_STATISTICS_update (GSC_stats,
1643 gettext_noop (
1644 "# bytes dropped (out of sequence)"),
1645 size,
1646 GNUNET_NO);
1647 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
1648 return;
1649 }
1650 if (kx->last_sequence_number_received > snum)
1651 {
1652 uint32_t rotbit = 1U << (kx->last_sequence_number_received - snum - 1);
1653
1654 if ((kx->last_packets_bitmap & rotbit) != 0)
1655 {
1656 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1657 "Received duplicate message, ignoring.\n");
1658 GNUNET_STATISTICS_update (GSC_stats,
1659 gettext_noop ("# bytes dropped (duplicates)"),
1660 size,
1661 GNUNET_NO);
1662 /* duplicate, ignore */
1663 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
1664 return;
1665 }
1666 kx->last_packets_bitmap |= rotbit;
1667 }
1668 if (kx->last_sequence_number_received < snum)
1669 {
1670 unsigned int shift = (snum - kx->last_sequence_number_received);
1671
1672 if (shift >= 8 * sizeof(kx->last_packets_bitmap))
1673 kx->last_packets_bitmap = 0;
1674 else
1675 kx->last_packets_bitmap <<= shift;
1676 kx->last_sequence_number_received = snum;
1677 }
1678
1679 /* check timestamp */
1680 t = GNUNET_TIME_absolute_ntoh (pt->timestamp);
1681 if (GNUNET_TIME_absolute_get_duration (t).rel_value_us >
1682 MAX_MESSAGE_AGE.rel_value_us)
1683 {
1684 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1685 "Message received far too old (%s). Content ignored.\n",
1686 GNUNET_STRINGS_relative_time_to_string (
1687 GNUNET_TIME_absolute_get_duration (t),
1688 GNUNET_YES));
1689 GNUNET_STATISTICS_update (GSC_stats,
1690 gettext_noop (
1691 "# bytes dropped (ancient message)"),
1692 size,
1693 GNUNET_NO);
1694 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
1695 return;
1696 }
1697
1698 /* process decrypted message(s) */
1699 update_timeout (kx);
1700 GNUNET_STATISTICS_update (GSC_stats,
1701 gettext_noop ("# bytes of payload decrypted"),
1702 size - sizeof(struct EncryptedMessage),
1703 GNUNET_NO);
1704 if (GNUNET_OK !=
1705 GNUNET_MST_from_buffer (kx->mst,
1706 &buf[sizeof(struct EncryptedMessage)],
1707 size - sizeof(struct EncryptedMessage),
1708 GNUNET_YES,
1709 GNUNET_NO))
1710 GNUNET_break_op (0);
1711
1712 GNUNET_TRANSPORT_core_receive_continue (transport, kx->peer);
1713}
1714
1715
1716/**
1717 * Setup the message that links the ephemeral key to our persistent
1718 * public key and generate the appropriate signature.
1719 */
1720static void
1721sign_ephemeral_key ()
1722{
1723 current_ekm.header.size = htons (sizeof(struct EphemeralKeyMessage));
1724 current_ekm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_EPHEMERAL_KEY);
1725 current_ekm.sender_status = 0; /* to be set later */
1726 current_ekm.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_SET_ECC_KEY);
1727 current_ekm.purpose.size =
1728 htonl (sizeof(struct GNUNET_CRYPTO_EccSignaturePurpose)
1729 + sizeof(struct GNUNET_TIME_AbsoluteNBO)
1730 + sizeof(struct GNUNET_TIME_AbsoluteNBO)
1731 + sizeof(struct GNUNET_CRYPTO_EcdhePublicKey)
1732 + sizeof(struct GNUNET_PeerIdentity));
1733 current_ekm.creation_time =
1734 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
1735 if (GNUNET_YES == GNUNET_CONFIGURATION_get_value_yesno (GSC_cfg,
1736 "core",
1737 "USE_EPHEMERAL_KEYS"))
1738 {
1739 current_ekm.expiration_time =
1740 GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (
1741 GNUNET_TIME_relative_add (REKEY_FREQUENCY,
1742 REKEY_TOLERANCE)));
1743 }
1744 else
1745 {
1746 current_ekm.expiration_time =
1747 GNUNET_TIME_absolute_hton (GNUNET_TIME_UNIT_FOREVER_ABS);
1748 }
1749 GNUNET_CRYPTO_ecdhe_key_get_public (&my_ephemeral_key,
1750 &current_ekm.ephemeral_key);
1751 current_ekm.origin_identity = GSC_my_identity;
1752 GNUNET_assert (GNUNET_OK ==
1753 GNUNET_CRYPTO_eddsa_sign_ (&my_private_key,
1754 &current_ekm.purpose,
1755 &current_ekm.signature));
1756}
1757
1758
1759/**
1760 * Task run to trigger rekeying.
1761 *
1762 * @param cls closure, NULL
1763 */
1764static void
1765do_rekey (void *cls)
1766{
1767 struct GSC_KeyExchangeInfo *pos;
1768
1769 (void) cls;
1770 rekey_task = GNUNET_SCHEDULER_add_delayed (REKEY_FREQUENCY, &do_rekey, NULL);
1771 GNUNET_CRYPTO_ecdhe_key_create (&my_ephemeral_key);
1772 sign_ephemeral_key ();
1773 {
1774 struct GNUNET_HashCode eh;
1775
1776 GNUNET_CRYPTO_hash (&current_ekm.ephemeral_key,
1777 sizeof(current_ekm.ephemeral_key),
1778 &eh);
1779 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Rekeying to %s\n", GNUNET_h2s (&eh));
1780 }
1781 for (pos = kx_head; NULL != pos; pos = pos->next)
1782 {
1783 if (GNUNET_CORE_KX_STATE_UP == pos->status)
1784 {
1785 pos->status = GNUNET_CORE_KX_STATE_REKEY_SENT;
1786 derive_session_keys (pos);
1787 }
1788 else if (GNUNET_CORE_KX_STATE_DOWN == pos->status)
1789 {
1790 pos->status = GNUNET_CORE_KX_STATE_KEY_SENT;
1791 }
1792 monitor_notify_all (pos);
1793 send_key (pos);
1794 }
1795}
1796
1797
1798/**
1799 * Initialize KX subsystem.
1800 *
1801 * @param pk private key to use for the peer
1802 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
1803 */
1804int
1805GSC_KX_init (struct GNUNET_CRYPTO_EddsaPrivateKey *pk)
1806{
1807 struct GNUNET_MQ_MessageHandler handlers[] = {
1808 GNUNET_MQ_hd_fixed_size (ephemeral_key,
1809 GNUNET_MESSAGE_TYPE_CORE_EPHEMERAL_KEY,
1810 struct EphemeralKeyMessage,
1811 NULL),
1812 GNUNET_MQ_hd_fixed_size (ping,
1813 GNUNET_MESSAGE_TYPE_CORE_PING,
1814 struct PingMessage,
1815 NULL),
1816 GNUNET_MQ_hd_fixed_size (pong,
1817 GNUNET_MESSAGE_TYPE_CORE_PONG,
1818 struct PongMessage,
1819 NULL),
1820 GNUNET_MQ_hd_var_size (encrypted,
1821 GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE,
1822 struct EncryptedMessage,
1823 NULL),
1824 GNUNET_MQ_handler_end ()
1825 };
1826
1827 my_private_key = *pk;
1828 GNUNET_CRYPTO_eddsa_key_get_public (&my_private_key,
1829 &GSC_my_identity.public_key);
1830 GNUNET_CRYPTO_ecdhe_key_create (&my_ephemeral_key);
1831 sign_ephemeral_key ();
1832 {
1833 struct GNUNET_HashCode eh;
1834
1835 GNUNET_CRYPTO_hash (&current_ekm.ephemeral_key,
1836 sizeof(current_ekm.ephemeral_key),
1837 &eh);
1838 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1839 "Starting with ephemeral key %s\n",
1840 GNUNET_h2s (&eh));
1841 }
1842
1843 nc = GNUNET_notification_context_create (1);
1844 rekey_task = GNUNET_SCHEDULER_add_delayed (REKEY_FREQUENCY, &do_rekey, NULL);
1845 transport =
1846 GNUNET_TRANSPORT_core_connect (GSC_cfg,
1847 &GSC_my_identity,
1848 handlers,
1849 NULL,
1850 &handle_transport_notify_connect,
1851 &handle_transport_notify_disconnect);
1852 if (NULL == transport)
1853 {
1854 GSC_KX_done ();
1855 return GNUNET_SYSERR;
1856 }
1857 return GNUNET_OK;
1858}
1859
1860
1861/**
1862 * Shutdown KX subsystem.
1863 */
1864void
1865GSC_KX_done ()
1866{
1867 if (NULL != transport)
1868 {
1869 GNUNET_TRANSPORT_core_disconnect (transport);
1870 transport = NULL;
1871 }
1872 if (NULL != rekey_task)
1873 {
1874 GNUNET_SCHEDULER_cancel (rekey_task);
1875 rekey_task = NULL;
1876 }
1877 memset (&my_ephemeral_key,
1878 0,
1879 sizeof (my_ephemeral_key));
1880 memset (&my_private_key,
1881 0,
1882 sizeof (my_private_key));
1883 if (NULL != nc)
1884 {
1885 GNUNET_notification_context_destroy (nc);
1886 nc = NULL;
1887 }
1888}
1889
1890
1891/**
1892 * Check how many messages are queued for the given neighbour.
1893 *
1894 * @param kxinfo data about neighbour to check
1895 * @return number of items in the message queue
1896 */
1897unsigned int
1898GSC_NEIGHBOURS_get_queue_length (const struct GSC_KeyExchangeInfo *kxinfo)
1899{
1900 return GNUNET_MQ_get_length (kxinfo->mq);
1901}
1902
1903
1904int
1905GSC_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 */
1919void
1920GSC_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/service/core/gnunet-service-core_kx.h b/src/service/core/gnunet-service-core_kx.h
new file mode 100644
index 000000000..8bcac3f68
--- /dev/null
+++ b/src/service/core/gnunet-service-core_kx.h
@@ -0,0 +1,102 @@
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
31
32/**
33 * Information about the status of a key exchange with another peer.
34 */
35struct GSC_KeyExchangeInfo;
36
37
38/**
39 * Encrypt and transmit a message with the given payload.
40 *
41 * @param kx key exchange context
42 * @param payload payload of the message
43 * @param payload_size number of bytes in 'payload'
44 */
45void
46GSC_KX_encrypt_and_transmit (struct GSC_KeyExchangeInfo *kx,
47 const void *payload,
48 size_t payload_size);
49
50
51/**
52 * Initialize KX subsystem.
53 *
54 * @param pk private key to use for the peer
55 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
56 */
57int
58GSC_KX_init (struct GNUNET_CRYPTO_EddsaPrivateKey *pk);
59
60
61/**
62 * Shutdown KX subsystem.
63 */
64void
65GSC_KX_done (void);
66
67
68/**
69 * Check if the given neighbour has excess bandwidth available.
70 *
71 * @param target neighbour to check
72 * @return #GNUNET_YES if excess bandwidth is available, #GNUNET_NO if not
73 */
74int
75GSC_NEIGHBOURS_check_excess_bandwidth (const struct
76 GSC_KeyExchangeInfo *target);
77
78
79/**
80 * Check how many messages are queued for the given neighbour.
81 *
82 * @param target neighbour to check
83 * @return number of items in the message queue
84 */
85unsigned int
86GSC_NEIGHBOURS_get_queue_length (const struct GSC_KeyExchangeInfo *target);
87
88
89/**
90 * Handle #GNUNET_MESSAGE_TYPE_CORE_MONITOR_PEERS request. For this
91 * request type, the client does not have to have transmitted an INIT
92 * request. All current peers are returned, regardless of which
93 * message types they accept.
94 *
95 * @param mq message queue to add for monitoring
96 */
97void
98GSC_KX_handle_client_monitor_peers (struct GNUNET_MQ_Handle *mq);
99
100
101#endif
102/* end of gnunet-service-core_kx.h */
diff --git a/src/service/core/gnunet-service-core_sessions.c b/src/service/core/gnunet-service-core_sessions.c
new file mode 100644
index 000000000..e103c89f5
--- /dev/null
+++ b/src/service/core/gnunet-service-core_sessions.c
@@ -0,0 +1,1028 @@
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 */
46struct 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 */
92struct 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
156GNUNET_NETWORK_STRUCT_BEGIN
157
158/**
159 * Message sent to confirm that a typemap was received.
160 */
161struct 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
179GNUNET_NETWORK_STRUCT_END
180
181
182/**
183 * Map of peer identities to `struct Session`.
184 */
185static 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 */
195static struct Session *
196find_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 */
210void
211GSC_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 */
267static void
268transmit_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 */
299static void
300start_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 */
317void
318GSC_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 */
352void
353GSC_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 */
375void
376GSC_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 */
432static int
433notify_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 */
453void
454GSC_SESSIONS_notify_client_about_sessions (struct GSC_Client *client)
455{
456 /* notify new client about existing sessions */
457 GNUNET_CONTAINER_multipeermap_iterate (sessions,
458 &notify_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 */
469static void
470try_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 */
482void
483GSC_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 */
517void
518GSC_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 */
545static void
546solicit_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 */
592static void
593pop_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 */
609static void
610try_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 */
784static int
785do_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 */
825void
826GSC_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 */
843void
844GSC_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
858void
859GSC_SESSIONS_transmit (struct GSC_ClientActiveRequest *car,
860 const struct GNUNET_MessageHeader *msg,
861 enum GNUNET_MQ_PriorityPreferences priority)
862{
863 struct Session *session;
864 struct SessionMessageEntry *sme;
865 struct SessionMessageEntry *pos;
866 size_t msize;
867
868 session = find_session (&car->target);
869 if (NULL == session)
870 return;
871 msize = ntohs (msg->size);
872 sme = GNUNET_malloc (sizeof(struct SessionMessageEntry) + msize);
873 GNUNET_memcpy (&sme[1], msg, msize);
874 sme->size = msize;
875 sme->priority = priority;
876 if (0 != (GNUNET_MQ_PREF_CORK_ALLOWED & priority))
877 {
878 sme->deadline =
879 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_MAX_CORK_DELAY);
880 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
881 "Message corked, delaying transmission\n");
882 }
883 pos = session->sme_head;
884 while ((NULL != pos) && (pos->priority >= sme->priority))
885 pos = pos->next;
886 if (NULL == pos)
887 GNUNET_CONTAINER_DLL_insert_tail (session->sme_head,
888 session->sme_tail,
889 sme);
890 else
891 GNUNET_CONTAINER_DLL_insert_after (session->sme_head,
892 session->sme_tail,
893 pos->prev,
894 sme);
895 try_transmission (session);
896}
897
898
899void
900GSC_SESSIONS_set_typemap (const struct GNUNET_PeerIdentity *peer,
901 const struct GNUNET_MessageHeader *msg)
902{
903 struct Session *session;
904 struct GSC_TypeMap *nmap;
905 struct SessionMessageEntry *sme;
906 struct TypeMapConfirmationMessage *tmc;
907
908 nmap = GSC_TYPEMAP_get_from_message (msg);
909 if (NULL == nmap)
910 {
911 GNUNET_break_op (0);
912 return; /* malformed */
913 }
914 session = find_session (peer);
915 if (NULL == session)
916 {
917 GSC_TYPEMAP_destroy (nmap);
918 GNUNET_break (0);
919 return;
920 }
921 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
922 "Received TYPEMAP from %s\n",
923 GNUNET_i2s (session->peer));
924 for (sme = session->sme_head; NULL != sme; sme = sme->next)
925 {
926 if (GNUNET_YES == sme->is_typemap_confirm)
927 {
928 GNUNET_CONTAINER_DLL_remove (session->sme_head, session->sme_tail, sme);
929 GNUNET_free (sme);
930 break;
931 }
932 }
933 sme = GNUNET_malloc (sizeof(struct SessionMessageEntry)
934 + sizeof(struct TypeMapConfirmationMessage));
935 sme->deadline = GNUNET_TIME_absolute_get ();
936 sme->size = sizeof(struct TypeMapConfirmationMessage);
937 sme->priority = GNUNET_MQ_PRIO_CRITICAL_CONTROL;
938 sme->is_typemap_confirm = GNUNET_YES;
939 tmc = (struct TypeMapConfirmationMessage *) &sme[1];
940 tmc->header.size = htons (sizeof(struct TypeMapConfirmationMessage));
941 tmc->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_CONFIRM_TYPE_MAP);
942 tmc->reserved = htonl (0);
943 GSC_TYPEMAP_hash (nmap, &tmc->tm_hash);
944 GNUNET_CONTAINER_DLL_insert (session->sme_head, session->sme_tail, sme);
945 try_transmission (session);
946 GSC_CLIENTS_notify_clients_about_neighbour (peer, session->tmap, nmap);
947 GSC_TYPEMAP_destroy (session->tmap);
948 session->tmap = nmap;
949}
950
951
952/**
953 * The given peer send a message of the specified type. Make sure the
954 * respective bit is set in its type-map and that clients are notified
955 * about the session.
956 *
957 * @param peer peer this is about
958 * @param type type of the message
959 */
960void
961GSC_SESSIONS_add_to_typemap (const struct GNUNET_PeerIdentity *peer,
962 uint16_t type)
963{
964 struct Session *session;
965 struct GSC_TypeMap *nmap;
966
967 if (0 == memcmp (peer, &GSC_my_identity, sizeof(struct GNUNET_PeerIdentity)))
968 return;
969 session = find_session (peer);
970 GNUNET_assert (NULL != session);
971 if (GNUNET_YES == GSC_TYPEMAP_test_match (session->tmap, &type, 1))
972 return; /* already in it */
973 nmap = GSC_TYPEMAP_extend (session->tmap, &type, 1);
974 GSC_CLIENTS_notify_clients_about_neighbour (peer, session->tmap, nmap);
975 GSC_TYPEMAP_destroy (session->tmap);
976 session->tmap = nmap;
977}
978
979
980/**
981 * Initialize sessions subsystem.
982 */
983void
984GSC_SESSIONS_init ()
985{
986 sessions = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_YES);
987}
988
989
990/**
991 * Helper function for #GSC_SESSIONS_done() to free all
992 * active sessions.
993 *
994 * @param cls NULL
995 * @param key identity of the connected peer
996 * @param value the `struct Session` for the peer
997 * @return #GNUNET_OK (continue to iterate)
998 */
999static int
1000free_session_helper (void *cls,
1001 const struct GNUNET_PeerIdentity *key,
1002 void *value)
1003{
1004 /* struct Session *session = value; */
1005
1006 GSC_SESSIONS_end (key);
1007 return GNUNET_OK;
1008}
1009
1010
1011/**
1012 * Shutdown sessions subsystem.
1013 */
1014void
1015GSC_SESSIONS_done ()
1016{
1017 if (NULL != sessions)
1018 {
1019 GNUNET_CONTAINER_multipeermap_iterate (sessions,
1020 &free_session_helper,
1021 NULL);
1022 GNUNET_CONTAINER_multipeermap_destroy (sessions);
1023 sessions = NULL;
1024 }
1025}
1026
1027
1028/* end of gnunet-service-core_sessions.c */
diff --git a/src/service/core/gnunet-service-core_sessions.h b/src/service/core/gnunet-service-core_sessions.h
new file mode 100644
index 000000000..fda2cc32c
--- /dev/null
+++ b/src/service/core/gnunet-service-core_sessions.h
@@ -0,0 +1,183 @@
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 */
39void
40GSC_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 */
51void
52GSC_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 */
62void
63GSC_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 */
73void
74GSC_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 */
84void
85GSC_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 */
97void
98GSC_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 */
107void
108GSC_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 */
119void
120GSC_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 */
131void
132GSC_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 */
140void
141GSC_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 */
151void
152GSC_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 */
164void
165GSC_SESSIONS_add_to_typemap (const struct GNUNET_PeerIdentity *peer,
166 uint16_t type);
167
168
169/**
170 * Initialize sessions subsystem.
171 */
172void
173GSC_SESSIONS_init (void);
174
175
176/**
177 * Shutdown sessions subsystem.
178 */
179void
180GSC_SESSIONS_done (void);
181
182
183#endif
diff --git a/src/service/core/gnunet-service-core_typemap.c b/src/service/core/gnunet-service-core_typemap.c
new file mode 100644
index 000000000..200a84b23
--- /dev/null
+++ b/src/service/core/gnunet-service-core_typemap.c
@@ -0,0 +1,370 @@
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-service-core.h"
29#include "gnunet-service-core_sessions.h"
30#include "gnunet-service-core_typemap.h"
31#include <zlib.h>
32
33
34/**
35 * A type map describing which messages a given neighbour is able
36 * to process.
37 */
38struct GSC_TypeMap
39{
40 uint32_t bits[(UINT16_MAX + 1) / 32];
41};
42
43/**
44 * Bitmap of message types this peer is able to handle.
45 */
46static struct GSC_TypeMap my_type_map;
47
48/**
49 * Counters for message types this peer is able to handle.
50 */
51static uint8_t map_counters[UINT16_MAX + 1];
52
53/**
54 * Current hash of our (uncompressed) type map.
55 * Lazily computed when needed.
56 */
57static struct GNUNET_HashCode my_tm_hash;
58
59/**
60 * Is #my_tm_hash() current with respect to our type map?
61 */
62static int hash_current;
63
64
65/**
66 * Our type map changed, recompute its hash.
67 */
68static void
69rehash_typemap ()
70{
71 hash_current = GNUNET_NO;
72}
73
74
75/**
76 * Hash the contents of a type map.
77 *
78 * @param tm map to hash
79 * @param hc where to store the hash code
80 */
81void
82GSC_TYPEMAP_hash (const struct GSC_TypeMap *tm, struct GNUNET_HashCode *hc)
83{
84 GNUNET_CRYPTO_hash (tm, sizeof(struct GSC_TypeMap), hc);
85}
86
87
88/**
89 * Check if the given hash matches our current type map.
90 *
91 * @param hc hash code to check if it matches our type map
92 * @return #GNUNET_YES if the hash matches, #GNUNET_NO if not
93 */
94int
95GSC_TYPEMAP_check_hash (const struct GNUNET_HashCode *hc)
96{
97 if (GNUNET_NO == hash_current)
98 {
99 GSC_TYPEMAP_hash (&my_type_map, &my_tm_hash);
100 hash_current = GNUNET_YES;
101 }
102 return (0 == memcmp (hc, &my_tm_hash, sizeof(struct GNUNET_HashCode)))
103 ? GNUNET_YES
104 : GNUNET_NO;
105}
106
107
108/**
109 * Compute a type map message for this peer.
110 *
111 * @return this peers current type map message.
112 */
113struct GNUNET_MessageHeader *
114GSC_TYPEMAP_compute_type_map_message ()
115{
116 char *tmp;
117 uLongf dlen;
118 struct GNUNET_MessageHeader *hdr;
119
120#ifdef compressBound
121 dlen = compressBound (sizeof(my_type_map));
122#else
123 dlen = sizeof(my_type_map) + (sizeof(my_type_map) / 100) + 20;
124 /* documentation says 100.1% oldSize + 12 bytes, but we
125 * should be able to overshoot by more to be safe */
126#endif
127 hdr = GNUNET_malloc (dlen + sizeof(struct GNUNET_MessageHeader));
128 tmp = (char *) &hdr[1];
129 if ((Z_OK != compress2 ((Bytef *) tmp,
130 &dlen,
131 (const Bytef *) &my_type_map,
132 sizeof(my_type_map),
133 9)) ||
134 (dlen >= sizeof(my_type_map)))
135 {
136 /* compression failed, use uncompressed map */
137 dlen = sizeof(my_type_map);
138 GNUNET_memcpy (tmp, &my_type_map, sizeof(my_type_map));
139 hdr->type = htons (GNUNET_MESSAGE_TYPE_CORE_BINARY_TYPE_MAP);
140 }
141 else
142 {
143 /* compression worked, use compressed map */
144 hdr->type = htons (GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP);
145 }
146 hdr->size = htons ((uint16_t) dlen + sizeof(struct GNUNET_MessageHeader));
147 return hdr;
148}
149
150
151/**
152 * Extract a type map from a TYPE_MAP message.
153 *
154 * @param msg a type map message
155 * @return NULL on error
156 */
157struct GSC_TypeMap *
158GSC_TYPEMAP_get_from_message (const struct GNUNET_MessageHeader *msg)
159{
160 struct GSC_TypeMap *ret;
161 uint16_t size;
162 uLongf dlen;
163
164 size = ntohs (msg->size);
165 switch (ntohs (msg->type))
166 {
167 case GNUNET_MESSAGE_TYPE_CORE_BINARY_TYPE_MAP:
168 GNUNET_STATISTICS_update (GSC_stats,
169 gettext_noop ("# type maps received"),
170 1,
171 GNUNET_NO);
172 if (size != sizeof(struct GSC_TypeMap))
173 {
174 GNUNET_break_op (0);
175 return NULL;
176 }
177 ret = GNUNET_new (struct GSC_TypeMap);
178 GNUNET_memcpy (ret, &msg[1], sizeof(struct GSC_TypeMap));
179 return ret;
180
181 case GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP:
182 GNUNET_STATISTICS_update (GSC_stats,
183 gettext_noop ("# type maps received"),
184 1,
185 GNUNET_NO);
186 ret = GNUNET_new (struct GSC_TypeMap);
187 dlen = sizeof(struct GSC_TypeMap);
188 if ((Z_OK != uncompress ((Bytef *) ret,
189 &dlen,
190 (const Bytef *) &msg[1],
191 (uLong) size)) ||
192 (dlen != sizeof(struct GSC_TypeMap)))
193 {
194 GNUNET_break_op (0);
195 GNUNET_free (ret);
196 return NULL;
197 }
198 return ret;
199
200 default:
201 GNUNET_break (0);
202 return NULL;
203 }
204}
205
206
207/**
208 * Send my type map to all connected peers (it got changed).
209 */
210static void
211broadcast_my_type_map ()
212{
213 struct GNUNET_MessageHeader *hdr;
214
215 hdr = GSC_TYPEMAP_compute_type_map_message ();
216 GNUNET_STATISTICS_update (GSC_stats,
217 gettext_noop ("# updates to my type map"),
218 1,
219 GNUNET_NO);
220 GSC_SESSIONS_broadcast_typemap (hdr);
221 GNUNET_free (hdr);
222}
223
224
225/**
226 * Add a set of types to our type map.
227 *
228 * @param types array of message types supported by this peer
229 * @param tlen number of entries in @a types
230 */
231void
232GSC_TYPEMAP_add (const uint16_t *types, unsigned int tlen)
233{
234 unsigned int i;
235 int changed;
236
237 changed = GNUNET_NO;
238 for (i = 0; i < tlen; i++)
239 {
240 if (0 == map_counters[types[i]]++)
241 {
242 my_type_map.bits[types[i] / 32] |= (1 << (types[i] % 32));
243 changed = GNUNET_YES;
244 }
245 }
246 if (GNUNET_YES == changed)
247 {
248 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Typemap changed, broadcasting!\n");
249 rehash_typemap ();
250 broadcast_my_type_map ();
251 }
252}
253
254
255void
256GSC_TYPEMAP_remove (const uint16_t *types, unsigned int tlen)
257{
258 int changed;
259
260 changed = GNUNET_NO;
261 for (unsigned int i = 0; i < tlen; i++)
262 {
263 if (0 == --map_counters[types[i]])
264 {
265 my_type_map.bits[types[i] / 32] &= ~(1 << (types[i] % 32));
266 changed = GNUNET_YES;
267 }
268 }
269 if (GNUNET_YES == changed)
270 {
271 rehash_typemap ();
272 broadcast_my_type_map ();
273 }
274}
275
276
277/**
278 * Test if any of the types from the types array is in the
279 * given type map.
280 *
281 * @param tmap map to test
282 * @param types array of types
283 * @param tcnt number of entries in @a types
284 * @return #GNUNET_YES if a type is in the map, #GNUNET_NO if not
285 */
286int
287GSC_TYPEMAP_test_match (const struct GSC_TypeMap *tmap,
288 const uint16_t *types,
289 unsigned int tcnt)
290{
291 if (NULL == tmap)
292 return GNUNET_NO;
293 if (0 == tcnt)
294 return GNUNET_YES; /* matches all */
295 for (unsigned int i = 0; i < tcnt; i++)
296 if (0 != (tmap->bits[types[i] / 32] & (1 << (types[i] % 32))))
297 return GNUNET_YES;
298 return GNUNET_NO;
299}
300
301
302/**
303 * Add additional types to a given typemap.
304 *
305 * @param tmap map to extend (not changed)
306 * @param types array of types to add
307 * @param tcnt number of entries in @a types
308 * @return updated type map (fresh copy)
309 */
310struct GSC_TypeMap *
311GSC_TYPEMAP_extend (const struct GSC_TypeMap *tmap,
312 const uint16_t *types,
313 unsigned int tcnt)
314{
315 struct GSC_TypeMap *ret;
316
317 ret = GNUNET_new (struct GSC_TypeMap);
318 if (NULL != tmap)
319 GNUNET_memcpy (ret, tmap, sizeof(struct GSC_TypeMap));
320 for (unsigned int i = 0; i < tcnt; i++)
321 ret->bits[types[i] / 32] |= (1 << (types[i] % 32));
322 return ret;
323}
324
325
326/**
327 * Create an empty type map.
328 *
329 * @return an empty type map
330 */
331struct GSC_TypeMap *
332GSC_TYPEMAP_create ()
333{
334 return GNUNET_new (struct GSC_TypeMap);
335}
336
337
338/**
339 * Free the given type map.
340 *
341 * @param tmap a type map
342 */
343void
344GSC_TYPEMAP_destroy (struct GSC_TypeMap *tmap)
345{
346 GNUNET_free (tmap);
347}
348
349
350/**
351 * Initialize typemap subsystem.
352 */
353void
354GSC_TYPEMAP_init ()
355{
356 /* nothing to do */
357}
358
359
360/**
361 * Shutdown typemap subsystem.
362 */
363void
364GSC_TYPEMAP_done ()
365{
366 /* nothing to do */
367}
368
369
370/* end of gnunet-service-core_typemap.c */
diff --git a/src/service/core/gnunet-service-core_typemap.h b/src/service/core/gnunet-service-core_typemap.h
new file mode 100644
index 000000000..de41f4220
--- /dev/null
+++ b/src/service/core/gnunet-service-core_typemap.h
@@ -0,0 +1,162 @@
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
31/**
32 * Map specifying which message types a peer supports.
33 */
34struct GSC_TypeMap;
35
36
37/**
38 * Add a set of types to our type map.
39 *
40 * @param types array of message types supported by this peer
41 * @param tlen number of entries in @a types
42 */
43void
44GSC_TYPEMAP_add (const uint16_t *types,
45 unsigned int tlen);
46
47
48/**
49 * Remove a set of message types from our type map.
50 *
51 * @param types array of message types no longer supported by this peer
52 * @param tlen number of entries in @a types
53 */
54void
55GSC_TYPEMAP_remove (const uint16_t *types,
56 unsigned int tlen);
57
58
59/**
60 * Compute a type map message for this peer.
61 *
62 * @return this peers current type map message.
63 */
64struct GNUNET_MessageHeader *
65GSC_TYPEMAP_compute_type_map_message (void);
66
67
68/**
69 * Check if the given hash matches our current type map.
70 *
71 * @param hc hash code to check if it matches our type map
72 * @return #GNUNET_YES if the hash matches, #GNUNET_NO if not
73 */
74int
75GSC_TYPEMAP_check_hash (const struct GNUNET_HashCode *hc);
76
77
78/**
79 * Hash the contents of a type map.
80 *
81 * @param tm map to hash
82 * @param hc where to store the hash code
83 */
84void
85GSC_TYPEMAP_hash (const struct GSC_TypeMap *tm,
86 struct GNUNET_HashCode *hc);
87
88
89/**
90 * Extract a type map from a
91 * #GNUNET_MESSAGE_TYPE_CORE_COMRESSED_TYPE_MAP or
92 * #GNUNET_MESSAGE_TYPE_CORE_BINARY_TYPE_MAP message.
93 *
94 * @param msg a type map message
95 * @return NULL on error
96 */
97struct GSC_TypeMap *
98GSC_TYPEMAP_get_from_message (const struct GNUNET_MessageHeader *msg);
99
100
101/**
102 * Test if any of the types from the types array is in the
103 * given type map.
104 *
105 * @param tmap map to test
106 * @param types array of types
107 * @param tcnt number of entries in @a types
108 * @return #GNUNET_YES if a type is in the map, #GNUNET_NO if not
109 */
110int
111GSC_TYPEMAP_test_match (const struct GSC_TypeMap *tmap,
112 const uint16_t *types,
113 unsigned int tcnt);
114
115
116/**
117 * Add additional types to a given typemap.
118 *
119 * @param tmap map to extend (not changed)
120 * @param types array of types to add
121 * @param tcnt number of entries in @a types
122 * @return updated type map (fresh copy)
123 */
124struct GSC_TypeMap *
125GSC_TYPEMAP_extend (const struct GSC_TypeMap *tmap,
126 const uint16_t *types,
127 unsigned int tcnt);
128
129
130/**
131 * Create an empty type map.
132 *
133 * @return an empty type map
134 */
135struct GSC_TypeMap *
136GSC_TYPEMAP_create (void);
137
138
139/**
140 * Free the given type map.
141 *
142 * @param tmap a type map
143 */
144void
145GSC_TYPEMAP_destroy (struct GSC_TypeMap *tmap);
146
147
148/**
149 * Initialize typemap subsystem.
150 */
151void
152GSC_TYPEMAP_init (void);
153
154
155/**
156 * Shutdown typemap subsystem.
157 */
158void
159GSC_TYPEMAP_done (void);
160
161#endif
162/* end of gnunet-service-core_typemap.h */
diff --git a/src/service/core/meson.build b/src/service/core/meson.build
new file mode 100644
index 000000000..09fdc8dab
--- /dev/null
+++ b/src/service/core/meson.build
@@ -0,0 +1,113 @@
1libgnunetcore_src = ['core_api.c',
2 'core_api_monitor_peers.c']
3
4gnunetservicecore_src = ['gnunet-service-core.c',
5 'gnunet-service-core_kx.c',
6 'gnunet-service-core_sessions.c',
7 'gnunet-service-core_typemap.c']
8
9configure_file(input : 'core.conf.in',
10 output : 'core.conf',
11 configuration : cdata,
12 install: true,
13 install_dir: pkgcfgdir)
14
15
16if get_option('monolith')
17 foreach p : libgnunetcore_src + gnunetservicecore_src
18 gnunet_src += 'core/' + p
19 endforeach
20endif
21
22libgnunetcore = library('gnunetcore',
23 libgnunetcore_src,
24 dependencies: libgnunetutil_dep,
25 include_directories: [incdir, configuration_inc],
26 install: true,
27 soversion: '0',
28 version: '0.0.1',
29 install_dir: get_option('libdir'))
30libgnunetcore_dep = declare_dependency(link_with : libgnunetcore)
31pkg.generate(libgnunetcore, url: 'https://www.gnunet.org',
32 description : 'Provides API for (encrypted) P2P communication')
33
34libgnunetcoretesting = library('gnunetcoretesting',
35 ['core_api_cmd_connecting_peers.c'],
36 dependencies: [
37 libgnunetutil_dep,
38 libgnunettransporttesting2_dep,
39 libgnunettesting_dep,
40 libgnunetarm_dep,
41 libgnunettransportapplication_dep,
42 libgnunettransportcore_dep,
43 ],
44 include_directories: [incdir, configuration_inc],
45 install: true,
46 soversion: '0',
47 version: '0.0.0',
48 install_dir: get_option('libdir'))
49libgnunetcoretesting_dep = declare_dependency(link_with : libgnunetcoretesting)
50
51shared_module('gnunet_test_core_plugin_cmd_just_run',
52 ['test_core_plugin_cmd_just_run.c'],
53 dependencies: [libgnunetutil_dep,
54 libgnunettesting_dep,
55 libgnunetcoretesting_dep,
56 libgnunettransporttesting2_dep,
57 libgnunettransportcore_dep,
58 libgnunettransportapplication_dep,
59 libgnunettesting_dep,
60 libgnunetpeerstore_dep,
61 libgnunetstatistics_dep,
62 libgnunethello_dep,
63 libgnunetarm_dep
64 ],
65 include_directories: [incdir, configuration_inc],
66 install: false)
67
68executable ('gnunet-service-core',
69 gnunetservicecore_src,
70 dependencies: [libgnunetcore_dep, libgnunetutil_dep,
71 libgnunetstatistics_dep,
72 libgnunettransportcore_dep,
73 zlib_dep],
74 include_directories: [incdir, configuration_inc],
75 install: true,
76 install_dir: get_option('libdir') / 'gnunet' / 'libexec')
77
78configure_file(input : 'test_core_defaults.conf',
79 output : 'test_core_defaults.conf',
80 copy: true)
81
82configure_file(input : 'test_core_api_send_to_self.conf',
83 output : 'test_core_api_send_to_self.conf',
84 copy: true)
85
86configure_file(input : 'test_core_api_peer1.conf',
87 output : 'test_core_api_peer1.conf',
88 copy: true)
89
90testcore_api_send_self = executable ('test_core_api_send_to_self',
91 ['test_core_api_send_to_self.c'],
92 dependencies: [
93 libgnunetcore_dep,
94 libgnunetutil_dep,
95 libgnunettesting_dep
96 ],
97 include_directories: [incdir, configuration_inc],
98 install: false)
99
100testcore_api_start = executable ('test_core_api_start_only',
101 ['test_core_api_send_to_self.c'],
102 dependencies: [
103 libgnunetcore_dep,
104 libgnunetutil_dep,
105 libgnunettesting_dep
106 ],
107 include_directories: [incdir, configuration_inc],
108 install: false)
109
110test('test_core_api_send_to_self', testcore_api_send_self,
111 suite: 'core', workdir: meson.current_build_dir())
112test('test_core_api_start_only', testcore_api_start,
113 suite: 'core', workdir: meson.current_build_dir())
diff --git a/src/service/core/test_core_api.c b/src/service/core/test_core_api.c
new file mode 100644
index 000000000..653ce1aa0
--- /dev/null
+++ b/src/service/core/test_core_api.c
@@ -0,0 +1,348 @@
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
35struct 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
49static struct PeerContext p1;
50
51static struct PeerContext p2;
52
53static struct GNUNET_SCHEDULER_Task *err_task;
54
55static 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
69static void
70offer_hello_done (void *cls)
71{
72 struct PeerContext *p = cls;
73
74 p->oh = NULL;
75}
76
77
78static void
79process_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
95static void
96terminate_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
126static void
127terminate_task (void *cls)
128{
129 GNUNET_assert (ok == 6);
130 terminate_peer (&p1);
131 terminate_peer (&p2);
132 ok = 0;
133}
134
135
136static void
137terminate_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
147static void *
148connect_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
182static void
183disconnect_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
198static void
199handle_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
213static void
214init_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
247static void
248setup_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
275static void
276run (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
302static void
303stop_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
318int
319main (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_purge_cfg_dir
338 ("test_core_api_peer1.conf",
339 "GNUNET_TEST_HOME");
340 GNUNET_DISK_purge_cfg_dir
341 ("test_core_api_peer2.conf",
342 "GNUNET_TEST_HOME");
343
344 return ok;
345}
346
347
348/* end of test_core_api.c */
diff --git a/src/service/core/test_core_api_data.conf b/src/service/core/test_core_api_data.conf
new file mode 100644
index 000000000..420849ba9
--- /dev/null
+++ b/src/service/core/test_core_api_data.conf
@@ -0,0 +1,11 @@
1@INLINE@ test_core_defaults.conf
2[PATHS]
3
4[ats]
5WAN_QUOTA_IN = 64 kiB
6WAN_QUOTA_OUT = 64 kiB
7
8[core]
9PORT = 52092
10UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-core.sock
11
diff --git a/src/service/core/test_core_api_peer1.conf b/src/service/core/test_core_api_peer1.conf
new file mode 100644
index 000000000..c3e8fb86c
--- /dev/null
+++ b/src/service/core/test_core_api_peer1.conf
@@ -0,0 +1,38 @@
1@INLINE@ test_core_defaults.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-core-peer-1/
4
5[arm]
6PORT = 12460
7UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
8
9[statistics]
10PORT = 12461
11
12[resolver]
13PORT = 12462
14UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
15
16[peerstore]
17PORT = 12463
18UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerstore.sock
19
20[transport]
21PORT = 12464
22UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
23
24[core]
25PORT = 12475
26UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-core.sock
27
28[communicator-tcp]
29PORT = 12467
30
31[communicator-udp]
32PORT = 12468
33
34[transport-unix]
35PORT = 12469
36
37[transport-http]
38PORT = 12470
diff --git a/src/service/core/test_core_api_peer2.conf b/src/service/core/test_core_api_peer2.conf
new file mode 100644
index 000000000..7cea78ae4
--- /dev/null
+++ b/src/service/core/test_core_api_peer2.conf
@@ -0,0 +1,39 @@
1@INLINE@ test_core_defaults.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-core-peer-2/
4
5[arm]
6PORT = 22460
7UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
8
9[statistics]
10PORT = 22461
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
12
13[resolver]
14PORT = 22462
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
16
17[peerstore]
18PORT = 22463
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerstore.sock
20
21[transport]
22PORT = 22464
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
24
25[core]
26PORT = 22475
27UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-core.sock
28
29[communicator-tcp]
30PORT = 22467
31
32[communicator-udp]
33PORT = 22468
34
35[transport-unix]
36PORT = 22469
37
38[transport-http]
39PORT = 22470
diff --git a/src/service/core/test_core_api_reliability.c b/src/service/core/test_core_api_reliability.c
new file mode 100644
index 000000000..d4b55a6b8
--- /dev/null
+++ b/src/service/core/test_core_api_reliability.c
@@ -0,0 +1,537 @@
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
49static unsigned long long total_bytes;
50
51static struct GNUNET_TIME_Absolute start_time;
52
53static struct GNUNET_SCHEDULER_Task *err_task;
54
55
56struct 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
71static struct PeerContext p1;
72
73static struct PeerContext p2;
74
75static int ok;
76
77static 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
84struct TestMessage
85{
86 struct GNUNET_MessageHeader header;
87 uint32_t num GNUNET_PACKED;
88};
89
90
91static unsigned int
92get_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
103static void
104terminate_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
134static void
135terminate_task_error (void *cls)
136{
137 err_task = NULL;
138 GNUNET_break (0);
139 GNUNET_SCHEDULER_shutdown ();
140 ok = 42;
141}
142
143
144static void
145do_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
169static void
170send_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
203static void *
204connect_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
238static void
239disconnect_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
257static int
258check_test (void *cls,
259 const struct TestMessage *hdr)
260{
261 return GNUNET_OK; /* accept all */
262}
263
264
265static void
266handle_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
324static void
325init_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
369static void
370offer_hello_done (void *cls)
371{
372 struct PeerContext *p = cls;
373
374 p->oh = NULL;
375}
376
377
378static void
379process_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
413static void
414setup_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
443static void
444run (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
480static void
481stop_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
499int
500main (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_purge_cfg_dir ("test_core_api_peer1.conf",
529 "GNUNET_TEST_HOME");
530 GNUNET_DISK_purge_cfg_dir ("test_core_api_peer2.conf",
531 "GNUNET_TEST_HOME");
532
533 return ok;
534}
535
536
537/* end of test_core_api_reliability.c */
diff --git a/src/service/core/test_core_api_send_to_self.c b/src/service/core/test_core_api_send_to_self.c
new file mode 100644
index 000000000..c2e39cd26
--- /dev/null
+++ b/src/service/core/test_core_api_send_to_self.c
@@ -0,0 +1,195 @@
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 */
37static int ret;
38
39/**
40 * Handle to the cleanup task.
41 */
42static struct GNUNET_SCHEDULER_Task *die_task;
43
44/**
45 * Identity of this peer.
46 */
47static struct GNUNET_PeerIdentity myself;
48
49/**
50 * The handle to core
51 */
52static struct GNUNET_CORE_Handle *core;
53
54
55/**
56 * Function scheduled as very last function, cleans up after us
57 */
58static void
59cleanup (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 */
79static void
80do_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
89static void
90handle_test (void *cls,
91 const struct GNUNET_MessageHeader *message)
92{
93 GNUNET_SCHEDULER_shutdown ();
94 ret = 0;
95}
96
97
98static void
99init (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
116static void *
117connect_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 */
148static void
149run (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 */
183int
184main (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/service/core/test_core_api_send_to_self.conf b/src/service/core/test_core_api_send_to_self.conf
new file mode 100644
index 000000000..fe8e69999
--- /dev/null
+++ b/src/service/core/test_core_api_send_to_self.conf
@@ -0,0 +1,19 @@
1@INLINE@ test_core_defaults.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-core-api-send-to-self/
4
5[ats]
6WAN_QUOTA_IN = 104857600
7WAN_QUOTA_OUT = 104757600
8
9[test-sts]
10IMMEDIATE_START = YES
11PORT = 59252
12HOSTNAME = localhost
13BINARY = test_core_api_send_to_self
14ACCEPT_FROM = 127.0.0.1;
15ACCEPT_FROM6 = ::1;
16TOTAL_QUOTA_IN = 65536
17TOTAL_QUOTA_OUT = 65536
18UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-sts.sock
19
diff --git a/src/service/core/test_core_api_start_only.c b/src/service/core/test_core_api_start_only.c
new file mode 100644
index 000000000..e50d3b2ec
--- /dev/null
+++ b/src/service/core/test_core_api_start_only.c
@@ -0,0 +1,258 @@
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
35struct 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
43static struct PeerContext p1;
44
45static struct PeerContext p2;
46
47static struct GNUNET_SCHEDULER_Task *timeout_task_id;
48
49static int ok;
50
51
52static void *
53connect_notify (void *cls,
54 const struct GNUNET_PeerIdentity *peer,
55 struct GNUNET_MQ_Handle *mq)
56{
57 return NULL;
58}
59
60
61static void
62disconnect_notify (void *cls,
63 const struct GNUNET_PeerIdentity *peer,
64 void *internal_cls)
65{
66}
67
68
69static struct GNUNET_MQ_MessageHandler handlers[] = {
70 GNUNET_MQ_handler_end ()
71};
72
73
74static void
75shutdown_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
85static void
86init_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
112static void
113setup_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
135static void
136timeout_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
155static void
156run (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
180static void
181stop_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
202static int
203check ()
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_purge_cfg_dir
216 ("test_core_api_peer1.conf",
217 "GNUNET_TEST_HOME");
218 GNUNET_DISK_purge_cfg_dir
219 ("test_core_api_peer2.conf",
220 "GNUNET_TEST_HOME");
221
222 ok = 1;
223 GNUNET_PROGRAM_run ((sizeof(argv) / sizeof(char *)) - 1,
224 argv,
225 "test-core-api-start-only",
226 "nohelp",
227 options,
228 &run,
229 &ok);
230 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
231 "Test finished\n");
232 stop_arm (&p1);
233 stop_arm (&p2);
234 return ok;
235}
236
237
238int
239main (int argc,
240 char *argv[])
241{
242 int ret;
243
244 GNUNET_log_setup ("test-core-api-start-only",
245 "WARNING",
246 NULL);
247 ret = check ();
248 GNUNET_DISK_purge_cfg_dir
249 ("test_core_api_peer1.conf",
250 "GNUNET_TEST_HOME");
251 GNUNET_DISK_purge_cfg_dir
252 ("test_core_api_peer2.conf",
253 "GNUNET_TEST_HOME");
254 return ret;
255}
256
257
258/* end of test_core_api_start_only.c */
diff --git a/src/service/core/test_core_defaults.conf b/src/service/core/test_core_defaults.conf
new file mode 100644
index 000000000..b098b7d63
--- /dev/null
+++ b/src/service/core/test_core_defaults.conf
@@ -0,0 +1,22 @@
1@INLINE@ ../../../contrib/conf/gnunet/no_forcestart.conf
2@INLINE@ ../../../contrib/conf/gnunet/no_autostart_above_core.conf
3
4[PATHS]
5GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-core/
6
7[nat]
8ENABLE_UPNP = NO
9
10[ats]
11WAN_QUOTA_IN = 1 GB
12WAN_QUOTA_OUT = 1 GB
13
14[communicator-tcp]
15BINDTO = 127.0.0.1
16
17[communicator-udp]
18BROADCAST = NO
19
20[peerinfo]
21NO_IO = YES
22
diff --git a/src/service/core/test_core_just_run.conf b/src/service/core/test_core_just_run.conf
new file mode 100644
index 000000000..b7d22f102
--- /dev/null
+++ b/src/service/core/test_core_just_run.conf
@@ -0,0 +1,55 @@
1@INLINE@ ../transport/template_tng_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[transport]
6BINARY = gnunet-service-transport
7#PREFIX = valgrind --leak-check=full --track-origins=yes --trace-children=yes --log-file=$GNUNET_TEST_HOME/vg_peer1-%p
8UNIXPATH = $GNUNET_RUNTIME_DIR/tng-p1.sock
9
10[PEER]
11PRIVATE_KEY = $GNUNET_RUNTIME_DIR/private.key
12
13[communicator-tcp]
14BINARY = gnunet-communicator-tcp
15BINDTO = 192.168.15.1:60002
16DISABLE_V6 = YES
17IMMEDIATE_START = YES
18UNIXPATH = $GNUNET_RUNTIME_DIR/tcp-comm-p1.sock
19#PREFIX = valgrind --leak-check=full --track-origins=yes --trace-children=yes --log-file=$GNUNET_TEST_HOME/vg_ctpeer1-%p
20#PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args
21
22[communicator-udp]
23#PREFIX = valgrind --leak-check=full --track-origins=yes --trace-children=yes --log-file=$GNUNET_TEST_HOME/vg_cupeer1-%p
24BINARY = gnunet-communicator-udp
25BINDTO = 192.168.15.1:60002
26DISABLE_V6 = YES
27IMMEDIATE_START = YES
28UNIXPATH = $GNUNET_RUNTIME_DIR/udp-comm-p1.sock
29
30[peerstore]
31IMMEDIATE_START = YES
32USE_INCLUDED_HELLOS = YES
33PREFIX = valgrind --leak-check=full --track-origins=yes --trace-children=yes --log-file=$GNUNET_TEST_HOME/vg_peer1-%p
34
35[topology]
36IMMEDIATE_START = YES
37PREFIX = valgrind --leak-check=full --track-origins=yes --trace-children=yes --log-file=$GNUNET_TEST_HOME/vg_peer1-transport-%p
38
39[dht]
40IMMEDIATE_START = YES
41PREFIX = valgrind --leak-check=full --track-origins=yes --trace-children=yes --log-file=$GNUNET_TEST_HOME/vg_peer1-%p
42
43[fs]
44IMMEDIATE_START = YES
45
46[hostlist]
47IMMEDIATE_START = YES
48SERVERS = http://192.168.15.1:8080/
49PREFIX = valgrind --leak-check=full --track-origins=yes --trace-children=yes --log-file=$GNUNET_TEST_HOME/vg_peer1-%p
50
51[core]
52PREFIX = valgrind --leak-check=full --track-origins=yes --trace-children=yes --log-file=$GNUNET_TEST_HOME/vg_peer1-transport-%p
53
54[cadet]
55PREFIX = valgrind --leak-check=full --track-origins=yes --trace-children=yes --log-file=$GNUNET_TEST_HOME/vg_peer1-transport-%p
diff --git a/src/service/core/test_core_just_run_host.conf b/src/service/core/test_core_just_run_host.conf
new file mode 100644
index 000000000..406b8dcc9
--- /dev/null
+++ b/src/service/core/test_core_just_run_host.conf
@@ -0,0 +1,45 @@
1@INLINE@ ../transport/template_tng_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[transport]
6BINARY = gnunet-service-transport
7#PREFIX = valgrind --leak-check=full --track-origins=yes --trace-children=yes --log-file=$GNUNET_TEST_HOME/vg_peer1-%p
8UNIXPATH = $GNUNET_RUNTIME_DIR/tng-p1.sock
9
10[PEER]
11PRIVATE_KEY = $GNUNET_RUNTIME_DIR/private.key
12
13[communicator-tcp]
14BINARY = gnunet-communicator-tcp
15BINDTO = 192.168.15.1:60002
16DISABLE_V6 = YES
17IMMEDIATE_START = YES
18UNIXPATH = $GNUNET_RUNTIME_DIR/tcp-comm-p1.sock
19#PREFIX = valgrind --leak-check=full --track-origins=yes --trace-children=yes --log-file=$GNUNET_TEST_HOME/vg_ctpeer1-%p
20#PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args
21
22[communicator-udp]
23#PREFIX = valgrind --leak-check=full --track-origins=yes --trace-children=yes --log-file=$GNUNET_TEST_HOME/vg_cupeer1-%p
24BINARY = gnunet-communicator-udp
25BINDTO = 192.168.15.1:60002
26DISABLE_V6 = YES
27IMMEDIATE_START = YES
28UNIXPATH = $GNUNET_RUNTIME_DIR/udp-comm-p1.sock
29
30[peerstore]
31IMMEDIATE_START = YES
32USE_INCLUDED_HELLOS = YES
33
34[topology]
35IMMEDIATE_START = YES
36
37[dht]
38IMMEDIATE_START = YES
39
40[fs]
41IMMEDIATE_START = YES
42
43[hostlist]
44IMMEDIATE_START = YES
45OPTIONS = -p \ No newline at end of file
diff --git a/src/service/core/test_core_plugin_cmd_just_run.c b/src/service/core/test_core_plugin_cmd_just_run.c
new file mode 100644
index 000000000..3c77c370d
--- /dev/null
+++ b/src/service/core/test_core_plugin_cmd_just_run.c
@@ -0,0 +1,391 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2021 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 testbed/plugin_cmd_simple_send.c
23 * @brief a plugin to provide the API for running test cases.
24 * @author t3sserakt
25 */
26#include "platform.h"
27#include "gnunet_testing_barrier.h"
28#include "gnunet_testing_netjail_lib.h"
29#include "gnunet_util_lib.h"
30#include "gnunet_transport_application_service.h"
31#include "gnunet_transport_core_service.h"
32#include "gnunet_testing_barrier.h"
33#include "gnunet_core_service.h"
34#include "gnunet_transport_testing_ng_lib.h"
35#include "gnunet_core_testing_lib.h"
36
37/**
38 * Generic logging shortcut
39 */
40#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__)
41
42#define BASE_DIR "testdir"
43
44#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 600)
45
46#define MAX_RECEIVED 1000
47
48#define MESSAGE_SIZE 65000
49
50static struct GNUNET_TESTING_Command block_script;
51
52static struct GNUNET_TESTING_Command connect_peers;
53
54static struct GNUNET_TESTING_Command local_prepared;
55
56static struct GNUNET_TESTING_Command start_peer;
57
58static struct GNUNET_TESTING_Interpreter *is;
59
60struct TestState
61{
62 /**
63 * Callback to write messages to the master loop.
64 *
65 */
66 GNUNET_TESTING_cmd_helper_write_cb write_message;
67
68 /**
69 * Callback to notify the helper test case has finished.
70 */
71 GNUNET_TESTING_cmd_helper_finish_cb finished_cb;
72
73 /**
74 * The name for a specific test environment directory.
75 *
76 */
77 char *testdir;
78
79 /**
80 * The name for the configuration file of the specific node.
81 *
82 */
83 char *cfgname;
84
85 /**
86 * The complete topology information.
87 */
88 struct GNUNET_TESTING_NetjailTopology *topology;
89};
90
91struct Sender
92{
93 /**
94 * Number of received messages from sender.
95 */
96 unsigned long long num_received;
97
98 /**
99 * Sample mean time the message traveled.
100 */
101 struct GNUNET_TIME_Relative mean_time;
102
103 /**
104 * Time the first message was send.
105 */
106 struct GNUNET_TIME_Absolute time_first;
107};
108
109
110struct GNUNET_TESTING_BarrierList*
111get_waiting_for_barriers ()
112{
113 struct GNUNET_TESTING_BarrierList*barriers;
114 struct GNUNET_TESTING_BarrierListEntry *ble;
115
116 barriers = GNUNET_new (struct GNUNET_TESTING_BarrierList);
117 ble = GNUNET_new (struct GNUNET_TESTING_BarrierListEntry);
118 ble->barrier_name = "ready-to-connect";
119 ble->expected_reaches = 1;
120 GNUNET_CONTAINER_DLL_insert (barriers->head,
121 barriers->tail,
122 ble);
123
124 ble = GNUNET_new (struct GNUNET_TESTING_BarrierListEntry);
125 ble->barrier_name = "test-case-finished";
126 ble->expected_reaches = 1;
127 GNUNET_CONTAINER_DLL_insert (barriers->head,
128 barriers->tail,
129 ble);
130 return barriers;
131}
132
133
134/**
135 * Function called with the final result of the test.
136 *
137 * @param cls the `struct MainParams`
138 * @param rv #GNUNET_OK if the test passed
139 */
140static void
141handle_result (void *cls,
142 enum GNUNET_GenericReturnValue rv)
143{
144 struct TestState *ts = cls;
145
146 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
147 "Local test exits with status %d\n",
148 rv);
149
150 ts->finished_cb (rv);
151 GNUNET_free (ts->testdir);
152 GNUNET_free (ts->cfgname);
153 GNUNET_TESTING_free_topology (ts->topology);
154 GNUNET_free (ts);
155}
156
157
158static void
159child_completed_callback (void *cls,
160 enum GNUNET_OS_ProcessStatusType type,
161 long unsigned int exit_code)
162{
163
164}
165
166
167/**
168 * Function to start a local test case.
169 *
170 * @param write_message Callback to send a message to the master loop.
171 * @param router_ip Global address of the network namespace.
172 * @param node_ip The IP address of the node.
173 * @param m The number of the node in a network namespace.
174 * @param n The number of the network namespace.
175 * @param local_m The number of nodes in a network namespace.
176 * @param topology_data A file name for the file containing the topology configuration, or a string containing
177 * the topology configuration.
178 * @param read_file If read_file is GNUNET_YES this string is the filename for the topology configuration,
179 * if read_file is GNUNET_NO the string contains the topology configuration.
180 * @param finish_cb Callback function which writes a message from the helper process running on a netjail
181 * node to the master process * signaling that the test case running on the netjail node finished.
182 * @return Returns the struct GNUNET_TESTING_Interpreter of the command loop running on this netjail node.
183 */
184static struct GNUNET_TESTING_Interpreter *
185start_testcase (GNUNET_TESTING_cmd_helper_write_cb write_message,
186 const char *router_ip,
187 const char *node_ip,
188 const char *m,
189 const char *n,
190 const char *local_m,
191 const char *topology_data,
192 unsigned int *read_file,
193 GNUNET_TESTING_cmd_helper_finish_cb finished_cb)
194{
195
196 unsigned int n_int;
197 unsigned int m_int;
198 unsigned int local_m_int;
199 unsigned int num;
200 struct TestState *ts = GNUNET_new (struct TestState);
201 struct GNUNET_TESTING_NetjailTopology *topology;
202 unsigned int sscanf_ret = 0;
203 char **argv = NULL;
204 int argc = 0;
205
206 ts->finished_cb = finished_cb;
207 LOG (GNUNET_ERROR_TYPE_ERROR,
208 "n %s m %s\n",
209 n,
210 m);
211
212 if (GNUNET_YES == *read_file)
213 {
214 LOG (GNUNET_ERROR_TYPE_DEBUG,
215 "read from file\n");
216 topology = GNUNET_TESTING_get_topo_from_file (topology_data);
217 }
218 else
219 topology = GNUNET_TESTING_get_topo_from_string (topology_data);
220
221 ts->topology = topology;
222
223 errno = 0;
224 sscanf_ret = sscanf (m, "%u", &m_int);
225 if (errno != 0)
226 {
227 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sscanf");
228 }
229 GNUNET_assert (0 < sscanf_ret);
230 errno = 0;
231 sscanf_ret = sscanf (n, "%u", &n_int);
232 if (errno != 0)
233 {
234 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sscanf");
235 }
236 GNUNET_assert (0 < sscanf_ret);
237 errno = 0;
238 sscanf_ret = sscanf (local_m, "%u", &local_m_int);
239 if (errno != 0)
240 {
241 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sscanf");
242 }
243 GNUNET_assert (0 < sscanf_ret);
244
245 if (0 == n_int)
246 num = m_int;
247 else
248 num = (n_int - 1) * local_m_int + m_int + topology->nodes_x;
249
250 block_script = GNUNET_TESTING_cmd_block_until_external_trigger (
251 "block-script");
252 connect_peers = GNUNET_CORE_cmd_connect_peers ("connect-peers",
253 "start-peer",
254 "system-create",
255 num,
256 topology,
257 0,
258 GNUNET_NO,
259 NULL);
260 local_prepared = GNUNET_TESTING_cmd_local_test_prepared (
261 "local-test-prepared",
262 write_message);
263
264
265 if (1 == m_int)
266 {
267 GNUNET_asprintf (&ts->cfgname,
268 "test_core_just_run_host.conf");
269 }
270 else
271 {
272 GNUNET_asprintf (&ts->cfgname,
273 "test_core_just_run.conf");
274 }
275
276 LOG (GNUNET_ERROR_TYPE_DEBUG,
277 "plugin cfgname: %s\n",
278 ts->cfgname);
279
280 LOG (GNUNET_ERROR_TYPE_DEBUG,
281 "node ip: %s\n",
282 node_ip);
283
284 GNUNET_asprintf (&ts->testdir,
285 "%s%s%s",
286 BASE_DIR,
287 m,
288 n);
289
290 /*struct GNUNET_MQ_MessageHandler handlers[] = {
291 GNUNET_MQ_hd_fixed_size (ephemeral_key,
292 GNUNET_MESSAGE_TYPE_CORE_EPHEMERAL_KEY,
293 struct EphemeralKeyMessage,
294 NULL),
295 GNUNET_MQ_hd_fixed_size (ping,
296 GNUNET_MESSAGE_TYPE_CORE_PING,
297 struct PingMessage,
298 NULL),
299 GNUNET_MQ_hd_fixed_size (pong,
300 GNUNET_MESSAGE_TYPE_CORE_PONG,
301 struct PongMessage,
302 NULL),
303 GNUNET_MQ_handler_end ()
304 };*/
305
306 start_peer = GNUNET_TESTING_cmd_start_peer ("start-peer",
307 "system-create",
308 num,
309 node_ip,
310 ts->cfgname,
311 GNUNET_NO);
312
313 struct GNUNET_TESTING_Command commands[] = {
314 GNUNET_TESTING_cmd_system_create ("system-create",
315 ts->testdir),
316 start_peer,
317 GNUNET_TESTING_cmd_barrier_reached ("ready-to-connect-reached",
318 "ready-to-connect",
319 GNUNET_NO,
320 num,
321 GNUNET_NO,
322 write_message),
323 connect_peers,
324 GNUNET_TESTING_cmd_exec_bash_script ("script",
325 "block.sh",
326 argv,
327 argc,
328 &child_completed_callback),
329 block_script,
330 GNUNET_TESTING_cmd_barrier_reached ("test-case-finished-reached",
331 "test-case-finished",
332 GNUNET_NO,
333 num,
334 GNUNET_NO,
335 write_message),
336 GNUNET_TESTING_cmd_stop_peer ("stop-peer",
337 "start-peer"),
338 GNUNET_TESTING_cmd_system_destroy ("system-destroy",
339 "system-create"),
340 GNUNET_TESTING_cmd_end ()
341 };
342
343 ts->write_message = write_message;
344
345 is = GNUNET_TESTING_run (commands,
346 TIMEOUT,
347 &handle_result,
348 ts);
349 return is;
350}
351
352
353/**
354 * Entry point for the plugin.
355 *
356 * @param cls NULL
357 * @return the exported block API
358 */
359void *
360libgnunet_test_core_plugin_cmd_just_run_init (void *cls)
361{
362 struct GNUNET_TESTING_PluginFunctions *api;
363
364 GNUNET_log_setup ("simple-send",
365 "DEBUG",
366 NULL);
367
368 api = GNUNET_new (struct GNUNET_TESTING_PluginFunctions);
369 api->start_testcase = &start_testcase;
370 api->get_waiting_for_barriers = get_waiting_for_barriers;
371 return api;
372}
373
374
375/**
376 * Exit point from the plugin.
377 *
378 * @param cls the return value from #libgnunet_test_transport_plugin_just_run_init
379 * @return NULL
380 */
381void *
382libgnunet_test_core_plugin_cmd_just_run_done (void *cls)
383{
384 struct GNUNET_TESTING_PluginFunctions *api = cls;
385
386 GNUNET_free (api);
387 return NULL;
388}
389
390
391/* end of plugin_cmd_simple_send.c */
diff --git a/src/service/core/test_core_quota_asymmetric_recv_limited_peer1.conf b/src/service/core/test_core_quota_asymmetric_recv_limited_peer1.conf
new file mode 100644
index 000000000..766a2e73b
--- /dev/null
+++ b/src/service/core/test_core_quota_asymmetric_recv_limited_peer1.conf
@@ -0,0 +1,54 @@
1@INLINE@ test_core_defaults.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-core-quota-asym-recv-lim-peer-1/
4
5[transport-tcp]
6PORT = 12488
7
8[arm]
9PORT = 12486
10UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-recv-p1-service-arm.sock
11
12[statistics]
13PORT = 12487
14UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-recv-p1-service-statistics.sock
15
16[resolver]
17PORT = 12484
18UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-recv-1-service-resolver.sock
19
20[peerinfo]
21PORT = 12489
22UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-recv-p1-service-peerinfo.sock
23
24[transport]
25PORT = 12485
26UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-recv-p1-service-transport.sock
27
28[transport-udp]
29PORT = 12489
30
31[ats]
32PORT = 12491
33UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-recv-p1-service-ats.sock
34# UNSPECIFIED
35UNSPECIFIED_QUOTA_IN = 100 MiB
36UNSPECIFIED_QUOTA_OUT = 100 MiB
37# LOOPBACK
38LOOPBACK_QUOTA_IN = 100 MiB
39LOOPBACK_QUOTA_OUT = 100 MiB
40# LAN
41LAN_QUOTA_IN = 100 MiB
42LAN_QUOTA_OUT = 100 MiB
43# WAN
44WAN_QUOTA_IN = 100 MiB
45WAN_QUOTA_OUT = 100 MiB
46# WLAN
47WLAN_QUOTA_IN = 100 MiB
48WLAN_QUOTA_OUT = 100 MiB
49
50
51[core]
52PORT = 12490
53UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-recv-p1-service-core.sock
54
diff --git a/src/service/core/test_core_quota_asymmetric_recv_limited_peer2.conf b/src/service/core/test_core_quota_asymmetric_recv_limited_peer2.conf
new file mode 100644
index 000000000..30c0bb81f
--- /dev/null
+++ b/src/service/core/test_core_quota_asymmetric_recv_limited_peer2.conf
@@ -0,0 +1,57 @@
1@INLINE@ test_core_defaults.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-core-quota-asym-recv-lim-peer-2/
4
5
6[arm]
7PORT = 22486
8UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-recv-p2-service-arm.sock
9
10[statistics]
11PORT = 22487
12UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-recv-p2-service-statistics.sock
13
14[resolver]
15PORT = 22484
16UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-recv-p2-service-resolver.sock
17
18[peerinfo]
19PORT = 22489
20UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-recv-p2-service-peerinfo.sock
21
22[transport]
23PORT = 22485
24UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-recv-p2-service-transport.sock
25
26[core]
27PORT = 22490
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-recv-p2-service-core.sock
29
30[ats]
31PORT = 22491
32UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-recv-p2-service-ats.sock
33# UNSPECIFIED
34UNSPECIFIED_QUOTA_IN = 10 MiB
35UNSPECIFIED_QUOTA_OUT = 10 MiB
36# LOOPBACK
37LOOPBACK_QUOTA_IN = 10 MiB
38LOOPBACK_QUOTA_OUT = 10 MiB
39# LAN
40LAN_QUOTA_IN = 10 MiB
41LAN_QUOTA_OUT = 10 MiB
42# WAN
43WAN_QUOTA_IN = 10 MiB
44WAN_QUOTA_OUT = 10 MiB
45# WLAN
46WLAN_QUOTA_IN = 10 MiB
47WLAN_QUOTA_OUT = 10 MiB
48
49[transport-tcp]
50PORT = 22467
51
52[transport-http]
53PORT = 22469
54
55[transport-tcp]
56PORT = 22468
57
diff --git a/src/service/core/test_core_quota_asymmetric_send_limit_peer1.conf b/src/service/core/test_core_quota_asymmetric_send_limit_peer1.conf
new file mode 100644
index 000000000..4a9f483d6
--- /dev/null
+++ b/src/service/core/test_core_quota_asymmetric_send_limit_peer1.conf
@@ -0,0 +1,52 @@
1@INLINE@ test_core_defaults.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-core-quota-asym-send-lim-peer-1/
4
5[transport-tcp]
6PORT = 12488
7
8[transport-udp]
9PORT = 12492
10
11[arm]
12PORT = 12486
13UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-send-p1-service-arm.sock
14
15[statistics]
16PORT = 12487
17UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-send-p1-service-statistics.sock
18
19[resolver]
20PORT = 12484
21UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-send-1-service-resolver.sock
22
23[peerinfo]
24PORT = 12489
25UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-send-p1-service-peerinfo.sock
26
27[transport]
28PORT = 12485
29UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-send-p1-service-transport.sock
30
31[ats]
32PORT = 12491
33UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-send-p1-service-ats.sock
34# UNSPECIFIED
35UNSPECIFIED_QUOTA_IN = 10 MiB
36UNSPECIFIED_QUOTA_OUT = 10 MiB
37# LOOPBACK
38LOOPBACK_QUOTA_IN = 10 MiB
39LOOPBACK_QUOTA_OUT = 10 MiB
40# LAN
41LAN_QUOTA_IN = 10 MiB
42LAN_QUOTA_OUT = 10 MiB
43# WAN
44WAN_QUOTA_IN = 10 MiB
45WAN_QUOTA_OUT = 10 MiB
46# WLAN
47WLAN_QUOTA_IN = 10 MiB
48WLAN_QUOTA_OUT = 10 MiB
49
50[core]
51PORT = 12490
52UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-send-p1-service-core.sock
diff --git a/src/service/core/test_core_quota_asymmetric_send_limit_peer2.conf b/src/service/core/test_core_quota_asymmetric_send_limit_peer2.conf
new file mode 100644
index 000000000..36434461c
--- /dev/null
+++ b/src/service/core/test_core_quota_asymmetric_send_limit_peer2.conf
@@ -0,0 +1,61 @@
1@INLINE@ test_core_defaults.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-core-quota-asym-send-lim-peer-2/
4
5[arm]
6PORT = 22486
7UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-send-p2-service-arm.sock
8
9[statistics]
10PORT = 22487
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-send-p2-service-statistics.sock
12
13[resolver]
14PORT = 22484
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-send-p2-service-resolver.sock
16
17[peerinfo]
18PORT = 22489
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-send-p2-service-peerinfo.sock
20
21[transport]
22PORT = 22485
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-send-p2-service-transport.sock
24
25[core]
26PORT = 22490
27UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-send-p2-service-core.sock
28
29[ats]
30PORT = 22491
31UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-asym-send-p2-service-ats.sock
32WAN_QUOTA_IN = 100 MiB
33WAN_QUOTA_OUT = 100 MiB
34
35[ats]
36PORT = 12471
37UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-core-sym-p1-service-ats.sock
38# UNSPECIFIED
39UNSPECIFIED_QUOTA_IN = 100 MiB
40UNSPECIFIED_QUOTA_OUT = 100 MiB
41# LOOPBACK
42LOOPBACK_QUOTA_IN = 100 MiB
43LOOPBACK_QUOTA_OUT = 100 MiB
44# LAN
45LAN_QUOTA_IN = 100 MiB
46LAN_QUOTA_OUT = 100 MiB
47# WAN
48WAN_QUOTA_IN = 100 MiB
49WAN_QUOTA_OUT = 100 MiB
50# WLAN
51WLAN_QUOTA_IN = 100 MiB
52WLAN_QUOTA_OUT = 100 MiB
53
54[transport-tcp]
55PORT = 22467
56
57[transport-udp]
58PORT = 22468
59
60[transport-http]
61PORT = 22469
diff --git a/src/service/core/test_core_quota_compliance.c b/src/service/core/test_core_quota_compliance.c
new file mode 100644
index 000000000..099c6fa3b
--- /dev/null
+++ b/src/service/core/test_core_quota_compliance.c
@@ -0,0 +1,788 @@
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
62static unsigned long long total_bytes_sent;
63static unsigned long long total_bytes_recv;
64
65static struct GNUNET_TIME_Absolute start_time;
66
67static struct GNUNET_SCHEDULER_Task *err_task;
68
69static struct GNUNET_SCHEDULER_Task *measure_task;
70
71
72struct 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
88static struct PeerContext p1;
89static struct PeerContext p2;
90
91static unsigned long long current_quota_p1_in;
92static unsigned long long current_quota_p1_out;
93static unsigned long long current_quota_p2_in;
94static unsigned long long current_quota_p2_out;
95
96static int ok;
97static int test;
98static int32_t tr_n;
99
100static 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
111struct TestMessage
112{
113 struct GNUNET_MessageHeader header;
114 uint32_t num GNUNET_PACKED;
115 uint8_t pad[MESSAGESIZE];
116};
117
118
119static void
120terminate_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
160static void
161shutdown_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
178static void
179terminate_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 */
199static int
200print_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
220static void
221measurement_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
350static void
351do_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
374static void *
375connect_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
413static void
414disconnect_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
437static void
438handle_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
467static void
468init_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
515static void
516offer_hello_done (void *cls)
517{
518 struct PeerContext *p = cls;
519
520 p->oh = NULL;
521}
522
523
524static void
525process_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 if (NULL != p->hello) GNUNET_free (p->hello);
534 p->hello = GNUNET_malloc (ntohs (message->size));
535 GNUNET_memcpy (p->hello, message, ntohs (message->size));
536 if ((p == &p1) &&
537 (NULL == p2.oh))
538 p2.oh = GNUNET_TRANSPORT_offer_hello (p2.cfg,
539 message,
540 &offer_hello_done,
541 &p2);
542 if ((p == &p2) &&
543 (NULL == p1.oh))
544 p1.oh = GNUNET_TRANSPORT_offer_hello (p1.cfg, message,
545 &offer_hello_done,
546 &p1);
547
548 if ((p == &p1) &&
549 (NULL != p2.hello) &&
550 (NULL == p1.oh))
551 p1.oh = GNUNET_TRANSPORT_offer_hello (p1.cfg,
552 p2.hello,
553 &offer_hello_done,
554 &p1);
555 if ((p == &p2) &&
556 (NULL != p1.hello) &&
557 (NULL == p2.oh))
558 p2.oh = GNUNET_TRANSPORT_offer_hello (p2.cfg,
559 p1.hello,
560 &offer_hello_done,
561 &p2);
562}
563
564
565static void
566setup_peer (struct PeerContext *p,
567 const char *cfgname)
568{
569 char *binary;
570
571 binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-arm");
572 p->cfg = GNUNET_CONFIGURATION_create ();
573 p->arm_proc =
574 GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_OUT_AND_ERR
575 | GNUNET_OS_USE_PIPE_CONTROL,
576 NULL, NULL, NULL,
577 binary,
578 "gnunet-service-arm",
579 "-c",
580 cfgname,
581 NULL);
582 GNUNET_assert (GNUNET_OK ==
583 GNUNET_CONFIGURATION_load (p->cfg,
584 cfgname));
585 p->stats = GNUNET_STATISTICS_create ("core",
586 p->cfg);
587 GNUNET_assert (NULL != p->stats);
588 p->ats = GNUNET_ATS_connectivity_init (p->cfg);
589 GNUNET_assert (NULL != p->ats);
590 p->ghh = GNUNET_TRANSPORT_hello_get (p->cfg,
591 GNUNET_TRANSPORT_AC_ANY,
592 &process_hello,
593 p);
594 GNUNET_free (binary);
595}
596
597
598static void
599run (void *cls,
600 char *const *args,
601 const char *cfgfile,
602 const struct GNUNET_CONFIGURATION_Handle *cfg)
603{
604 struct GNUNET_MQ_MessageHandler handlers[] = {
605 GNUNET_MQ_hd_fixed_size (test,
606 MTYPE,
607 struct TestMessage,
608 NULL),
609 GNUNET_MQ_handler_end ()
610 };
611
612 GNUNET_assert (ok == 1);
613 OKPP;
614 err_task =
615 GNUNET_SCHEDULER_add_delayed (TIMEOUT,
616 &terminate_task_error,
617 NULL);
618 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
619 NULL);
620 if (test == SYMMETRIC)
621 {
622 setup_peer (&p1,
623 "test_core_quota_peer1.conf");
624 setup_peer (&p2,
625 "test_core_quota_peer2.conf");
626 }
627 else if (test == ASYMMETRIC_SEND_LIMITED)
628 {
629 setup_peer (&p1,
630 "test_core_quota_asymmetric_send_limit_peer1.conf");
631 setup_peer (&p2,
632 "test_core_quota_asymmetric_send_limit_peer2.conf");
633 }
634 else if (test == ASYMMETRIC_RECV_LIMITED)
635 {
636 setup_peer (&p1,
637 "test_core_quota_asymmetric_recv_limited_peer1.conf");
638 setup_peer (&p2,
639 "test_core_quota_asymmetric_recv_limited_peer2.conf");
640 }
641
642 GNUNET_assert (test != -1);
643 GNUNET_assert (GNUNET_SYSERR !=
644 GNUNET_CONFIGURATION_get_value_size (p1.cfg,
645 "ATS",
646 "WAN_QUOTA_IN",
647 &current_quota_p1_in));
648 GNUNET_assert (GNUNET_SYSERR !=
649 GNUNET_CONFIGURATION_get_value_size (p2.cfg,
650 "ATS",
651 "WAN_QUOTA_IN",
652 &current_quota_p2_in));
653 GNUNET_assert (GNUNET_SYSERR !=
654 GNUNET_CONFIGURATION_get_value_size (p1.cfg,
655 "ATS",
656 "WAN_QUOTA_OUT",
657 &current_quota_p1_out));
658 GNUNET_assert (GNUNET_SYSERR !=
659 GNUNET_CONFIGURATION_get_value_size (p2.cfg,
660 "ATS",
661 "WAN_QUOTA_OUT",
662 &current_quota_p2_out));
663
664 p1.ch = GNUNET_CORE_connect (p1.cfg,
665 &p1,
666 &init_notify,
667 &connect_notify,
668 &disconnect_notify,
669 handlers);
670}
671
672
673static void
674stop_arm (struct PeerContext *p)
675{
676 if (0 != GNUNET_OS_process_kill (p->arm_proc,
677 GNUNET_TERM_SIG))
678 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
679 "kill");
680 if (GNUNET_OK !=
681 GNUNET_OS_process_wait (p->arm_proc))
682 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
683 "waitpid");
684 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
685 "ARM process %u stopped\n",
686 GNUNET_OS_process_get_pid (p->arm_proc));
687 GNUNET_OS_process_destroy (p->arm_proc);
688 p->arm_proc = NULL;
689 GNUNET_CONFIGURATION_destroy (p->cfg);
690}
691
692
693static int
694check ()
695{
696 char *const argv[] = {
697 "test-core-quota-compliance",
698 "-c",
699 "test_core_api_data.conf",
700 NULL
701 };
702 struct GNUNET_GETOPT_CommandLineOption options[] = {
703 GNUNET_GETOPT_OPTION_END
704 };
705
706 ok = 1;
707 GNUNET_PROGRAM_run ((sizeof(argv) / sizeof(char *)) - 1,
708 argv,
709 "test-core-quota-compliance",
710 "nohelp",
711 options,
712 &run,
713 &ok);
714 stop_arm (&p1);
715 stop_arm (&p2);
716 return ok;
717}
718
719
720static void
721cleanup_directory (int test)
722{
723 switch (test)
724 {
725 case SYMMETRIC:
726 GNUNET_DISK_purge_cfg_dir
727 ("test_core_quota_peer1.conf",
728 "GNUNET_TEST_HOME");
729 GNUNET_DISK_purge_cfg_dir
730 ("test_core_quota_peer2.conf",
731 "GNUNET_TEST_HOME");
732 break;
733
734 case ASYMMETRIC_SEND_LIMITED:
735 GNUNET_DISK_purge_cfg_dir
736 ("test_core_quota_asymmetric_send_limit_peer1.conf",
737 "GNUNET_TEST_HOME");
738 GNUNET_DISK_purge_cfg_dir
739 ("test_core_quota_asymmetric_send_limit_peer2.conf",
740 "GNUNET_TEST_HOME");
741 break;
742
743 case ASYMMETRIC_RECV_LIMITED:
744 GNUNET_DISK_purge_cfg_dir
745 ("test_core_quota_asymmetric_recv_limited_peer1.conf",
746 "GNUNET_TEST_HOME");
747 GNUNET_DISK_purge_cfg_dir
748 ("test_core_quota_asymmetric_recv_limited_peer2.conf",
749 "GNUNET_TEST_HOME");
750 break;
751 }
752}
753
754
755int
756main (int argc,
757 char *argv[])
758{
759 int ret;
760
761 test = -1;
762 if (NULL != strstr (argv[0],
763 "_symmetric"))
764 {
765 test = SYMMETRIC;
766 }
767 else if (NULL != strstr (argv[0],
768 "_asymmetric_send"))
769 {
770 test = ASYMMETRIC_SEND_LIMITED;
771 }
772 else if (NULL != strstr (argv[0],
773 "_asymmetric_recv"))
774 {
775 test = ASYMMETRIC_RECV_LIMITED;
776 }
777 GNUNET_assert (test != -1);
778 cleanup_directory (test);
779 GNUNET_log_setup ("test-core-quota-compliance",
780 "WARNING",
781 NULL);
782 ret = check ();
783 cleanup_directory (test);
784 return ret;
785}
786
787
788/* end of test_core_quota_compliance.c */
diff --git a/src/service/core/test_core_quota_peer1.conf b/src/service/core/test_core_quota_peer1.conf
new file mode 100644
index 000000000..ec592f778
--- /dev/null
+++ b/src/service/core/test_core_quota_peer1.conf
@@ -0,0 +1,58 @@
1@INLINE@ test_core_defaults.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-core-peer-1/
4
5[arm]
6PORT = 12460
7UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
8
9[statistics]
10PORT = 12461
11
12[resolver]
13PORT = 12462
14UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
15
16[peerinfo]
17PORT = 12463
18UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
19
20[transport]
21PORT = 12464
22UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
23
24[core]
25PORT = 12475
26UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-core.sock
27
28[ats]
29PORT = 12476
30UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-ats.sock
31# UNSPECIFIED
32UNSPECIFIED_QUOTA_IN = 10 MiB
33UNSPECIFIED_QUOTA_OUT = 10 MiB
34# LOOPBACK
35LOOPBACK_QUOTA_IN = 10 MiB
36LOOPBACK_QUOTA_OUT = 10 MiB
37# LAN
38LAN_QUOTA_IN = 10 MiB
39LAN_QUOTA_OUT = 10 MiB
40# WAN
41WAN_QUOTA_IN = 10 MiB
42WAN_QUOTA_OUT = 10 MiB
43# WLAN
44WLAN_QUOTA_IN = 10 MiB
45WLAN_QUOTA_OUT = 10 MiB
46
47
48[transport-tcp]
49PORT = 12467
50
51[transport-udp]
52PORT = 12468
53
54[transport-unix]
55PORT = 12469
56
57[transport-http]
58PORT = 12470
diff --git a/src/service/core/test_core_quota_peer2.conf b/src/service/core/test_core_quota_peer2.conf
new file mode 100644
index 000000000..65d0710bb
--- /dev/null
+++ b/src/service/core/test_core_quota_peer2.conf
@@ -0,0 +1,59 @@
1@INLINE@ test_core_defaults.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunet-core-peer-2/
4
5[arm]
6PORT = 22460
7UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
8
9[statistics]
10PORT = 22461
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
12
13[resolver]
14PORT = 22462
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
16
17[peerinfo]
18PORT = 22463
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
20
21[transport]
22PORT = 22464
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
24
25[core]
26PORT = 22475
27UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-core.sock
28
29[ats]
30PORT = 22476
31UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-ats.sock
32# UNSPECIFIED
33UNSPECIFIED_QUOTA_IN = 10 MiB
34UNSPECIFIED_QUOTA_OUT = 10 MiB
35# LOOPBACK
36LOOPBACK_QUOTA_IN = 10 MiB
37LOOPBACK_QUOTA_OUT = 10 MiB
38# LAN
39LAN_QUOTA_IN = 10 MiB
40LAN_QUOTA_OUT = 10 MiB
41# WAN
42WAN_QUOTA_IN = 10 MiB
43WAN_QUOTA_OUT = 10 MiB
44# WLAN
45WLAN_QUOTA_IN = 10 MiB
46WLAN_QUOTA_OUT = 10 MiB
47
48
49[transport-tcp]
50PORT = 22467
51
52[transport-udp]
53PORT = 22468
54
55[transport-unix]
56PORT = 22469
57
58[transport-http]
59PORT = 22470
diff --git a/src/service/core/test_core_start_testcase.sh b/src/service/core/test_core_start_testcase.sh
new file mode 100755
index 000000000..78e67dbf5
--- /dev/null
+++ b/src/service/core/test_core_start_testcase.sh
@@ -0,0 +1,15 @@
1#!/bin/bash
2echo gaga1 > gaga.txt
3read -p "Test case configuration to use:" conf
4if ! [ -d "/run/netns" ]; then
5 echo You have to create the directory /run/netns.
6fi
7if [ -f /proc/sys/kernel/unprivileged_userns_clone ]; then
8 if [ "$(cat /proc/sys/kernel/unprivileged_userns_clone)" != 1 ]; then
9 echo -e "Error during test setup: The kernel parameter kernel.unprivileged_userns_clone has to be set to 1! One has to execute\n\n sysctl kernel.unprivileged_userns_clone=1\n"
10 exit 78
11 fi
12fi
13echo gaga2 >> gaga.txt
14exec unshare -r -nmU bash -c "mount -t tmpfs --make-rshared tmpfs /run/netns; /usr/local/lib/gnunet/libexec/test_testing_start_with_config $conf"
15echo gaga3 >> gaga.txt