aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2011-10-05 13:26:24 +0000
committerChristian Grothoff <christian@grothoff.org>2011-10-05 13:26:24 +0000
commit0f29195adbd56ae10dea70c2951333c13e765f88 (patch)
tree83247d0f38a2cba50209af2325bad3d74890eb71
parentf39c4e7141b1fbb4830cb24ff630a879337f98d4 (diff)
downloadgnunet-0f29195adbd56ae10dea70c2951333c13e765f88.tar.gz
gnunet-0f29195adbd56ae10dea70c2951333c13e765f88.zip
towards new core service implementation -- breaking core up into smaller modules
-rw-r--r--src/core/gnunet-service-core-new.c305
-rw-r--r--src/core/gnunet-service-core.h15
-rw-r--r--src/core/gnunet-service-core_ats.c159
-rw-r--r--src/core/gnunet-service-core_clients.c1102
-rw-r--r--src/core/gnunet-service-core_crypto.c361
-rw-r--r--src/core/gnunet-service-core_extern.c39
-rw-r--r--src/core/gnunet-service-core_kx.c958
-rw-r--r--src/core/gnunet-service-core_kx.h77
-rw-r--r--src/core/gnunet-service-core_neighbours.c617
-rw-r--r--src/core/gnunet-service-core_plan.c563
-rw-r--r--src/core/gnunet-service-core_sessions.c713
-rw-r--r--src/core/gnunet-service-core_typemap.c96
12 files changed, 5005 insertions, 0 deletions
diff --git a/src/core/gnunet-service-core-new.c b/src/core/gnunet-service-core-new.c
new file mode 100644
index 000000000..cebc5237b
--- /dev/null
+++ b/src/core/gnunet-service-core-new.c
@@ -0,0 +1,305 @@
1/*
2 This file is part of GNUnet.
3 (C) 2009, 2010 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file core/gnunet-service-core.c
23 * @brief high-level P2P messaging
24 * @author Christian Grothoff
25 *
26 * Type map implementation:
27 * - track type maps for neighbours (can wait)
28 * - only notify clients about peers with matching type maps (can wait)
29 *
30 * Considerations for later:
31 * - check that hostkey used by transport (for HELLOs) is the
32 * same as the hostkey that we are using!
33 */
34#include "platform.h"
35#include <zlib.h>
36#include "gnunet_constants.h"
37#include "gnunet_util_lib.h"
38#include "gnunet_hello_lib.h"
39#include "gnunet_peerinfo_service.h"
40#include "gnunet_protocols.h"
41#include "gnunet_signatures.h"
42#include "gnunet_statistics_service.h"
43#include "gnunet_transport_service.h"
44#include "core.h"
45
46
47#define DEBUG_HANDSHAKE GNUNET_EXTRA_LOGGING
48
49#define DEBUG_CORE_QUOTA GNUNET_EXTRA_LOGGING
50
51/**
52 * Receive and send buffer windows grow over time. For
53 * how long can 'unused' bandwidth accumulate before we
54 * need to cap it? (specified in seconds).
55 */
56#define MAX_WINDOW_TIME_S (5 * 60)
57
58/**
59 * How many messages do we queue up at most for optional
60 * notifications to a client? (this can cause notifications
61 * about outgoing messages to be dropped).
62 */
63#define MAX_NOTIFY_QUEUE 1024
64
65/**
66 * Minimum bandwidth (out) to assign to any connected peer.
67 * Should be rather low; values larger than DEFAULT_BW_IN_OUT make no
68 * sense.
69 */
70#define MIN_BANDWIDTH_PER_PEER GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT
71
72/**
73 * After how much time past the "official" expiration time do
74 * we discard messages? Should not be zero since we may
75 * intentionally defer transmission until close to the deadline
76 * and then may be slightly past the deadline due to inaccuracy
77 * in sleep and our own CPU consumption.
78 */
79#define PAST_EXPIRATION_DISCARD_TIME GNUNET_TIME_UNIT_SECONDS
80
81/**
82 * What is the maximum delay for a SET_KEY message?
83 */
84#define MAX_SET_KEY_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
85
86/**
87 * How long do we wait for SET_KEY confirmation initially?
88 */
89#define INITIAL_SET_KEY_RETRY_FREQUENCY GNUNET_TIME_relative_multiply (MAX_SET_KEY_DELAY, 1)
90
91/**
92 * What is the maximum delay for a PING message?
93 */
94#define MAX_PING_DELAY GNUNET_TIME_relative_multiply (MAX_SET_KEY_DELAY, 2)
95
96/**
97 * What is the maximum delay for a PONG message?
98 */
99#define MAX_PONG_DELAY GNUNET_TIME_relative_multiply (MAX_PING_DELAY, 2)
100
101/**
102 * What is the minimum frequency for a PING message?
103 */
104#define MIN_PING_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
105
106/**
107 * How often do we recalculate bandwidth quotas?
108 */
109#define QUOTA_UPDATE_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
110
111/**
112 * What is the priority for a SET_KEY message?
113 */
114#define SET_KEY_PRIORITY 0xFFFFFF
115
116/**
117 * What is the priority for a PING message?
118 */
119#define PING_PRIORITY 0xFFFFFF
120
121/**
122 * What is the priority for a PONG message?
123 */
124#define PONG_PRIORITY 0xFFFFFF
125
126/**
127 * How many messages do we queue per peer at most? Must be at
128 * least two.
129 */
130#define MAX_PEER_QUEUE_SIZE 16
131
132/**
133 * How many non-mandatory messages do we queue per client at most?
134 */
135#define MAX_CLIENT_QUEUE_SIZE 32
136
137/**
138 * What is the maximum age of a message for us to consider
139 * processing it? Note that this looks at the timestamp used
140 * by the other peer, so clock skew between machines does
141 * come into play here. So this should be picked high enough
142 * so that a little bit of clock skew does not prevent peers
143 * from connecting to us.
144 */
145#define MAX_MESSAGE_AGE GNUNET_TIME_UNIT_DAYS
146
147
148/**
149 * State machine for our P2P encryption handshake. Everyone starts in
150 * "DOWN", if we receive the other peer's key (other peer initiated)
151 * we start in state RECEIVED (since we will immediately send our
152 * own); otherwise we start in SENT. If we get back a PONG from
153 * within either state, we move up to CONFIRMED (the PONG will always
154 * be sent back encrypted with the key we sent to the other peer).
155 */
156enum PeerStateMachine
157{
158 /**
159 * No handshake yet.
160 */
161 PEER_STATE_DOWN,
162
163 /**
164 * We've sent our session key.
165 */
166 PEER_STATE_KEY_SENT,
167
168 /**
169 * We've received the other peers session key.
170 */
171 PEER_STATE_KEY_RECEIVED,
172
173 /**
174 * The other peer has confirmed our session key with a message
175 * encrypted with his session key (which we got). Session is now fully up.
176 */
177 PEER_STATE_KEY_CONFIRMED
178};
179
180
181/**
182 * Encapsulation for encrypted messages exchanged between
183 * peers. Followed by the actual encrypted data.
184 */
185struct EncryptedMessage
186{
187 /**
188 * Message type is either CORE_ENCRYPTED_MESSAGE.
189 */
190 struct GNUNET_MessageHeader header;
191
192 /**
193 * Random value used for IV generation.
194 */
195 uint32_t iv_seed GNUNET_PACKED;
196
197 /**
198 * MAC of the encrypted message (starting at 'sequence_number'),
199 * used to verify message integrity. Everything after this value
200 * (excluding this value itself) will be encrypted and authenticated.
201 * ENCRYPTED_HEADER_SIZE must be set to the offset of the *next* field.
202 */
203 GNUNET_HashCode hmac;
204
205 /**
206 * Sequence number, in network byte order. This field
207 * must be the first encrypted/decrypted field
208 */
209 uint32_t sequence_number GNUNET_PACKED;
210
211 /**
212 * Desired bandwidth (how much we should send to this peer / how
213 * much is the sender willing to receive)?
214 */
215 struct GNUNET_BANDWIDTH_Value32NBO inbound_bw_limit;
216
217 /**
218 * Timestamp. Used to prevent reply of ancient messages
219 * (recent messages are caught with the sequence number).
220 */
221 struct GNUNET_TIME_AbsoluteNBO timestamp;
222
223};
224
225
226/**
227 * Number of bytes (at the beginning) of "struct EncryptedMessage"
228 * that are NOT encrypted.
229 */
230#define ENCRYPTED_HEADER_SIZE (offsetof(struct EncryptedMessage, sequence_number))
231
232
233/**
234 * Our identity.
235 */
236struct GNUNET_PeerIdentity GSC_my_identity;
237
238/**
239 * Our configuration.
240 */
241const struct GNUNET_CONFIGURATION_Handle *GSC_cfg;
242
243/**
244 * For creating statistics.
245 */
246struct GNUNET_STATISTICS_Handle *GSC_stats;
247
248
249
250
251
252/**
253 * Last task run during shutdown. Disconnects us from
254 * the transport.
255 */
256static void
257cleaning_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
258{
259#if DEBUG_CORE
260 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Core service shutting down.\n");
261#endif
262 if (stats != NULL)
263 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
264}
265
266
267/**
268 * Initiate core service.
269 *
270 * @param cls closure
271 * @param server the initialized server
272 * @param c configuration to use
273 */
274static void
275run (void *cls, struct GNUNET_SERVER_Handle *server,
276 const struct GNUNET_CONFIGURATION_Handle *c)
277{
278 cfg = c;
279 /* setup transport connection */
280 stats = GNUNET_STATISTICS_create ("core", cfg);
281 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleaning_task,
282 NULL);
283 /* process client requests */
284 GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Core service of `%4s' ready.\n"),
285 GNUNET_i2s (&my_identity));
286}
287
288
289
290/**
291 * The main function for the transport service.
292 *
293 * @param argc number of arguments from the command line
294 * @param argv command line arguments
295 * @return 0 ok, 1 on error
296 */
297int
298main (int argc, char *const *argv)
299{
300 return (GNUNET_OK ==
301 GNUNET_SERVICE_run (argc, argv, "core", GNUNET_SERVICE_OPTION_NONE,
302 &run, NULL)) ? 0 : 1;
303}
304
305/* end of gnunet-service-core.c */
diff --git a/src/core/gnunet-service-core.h b/src/core/gnunet-service-core.h
new file mode 100644
index 000000000..d98b318e5
--- /dev/null
+++ b/src/core/gnunet-service-core.h
@@ -0,0 +1,15 @@
1
2/**
3 * Our configuration.
4 */
5extern const struct GNUNET_CONFIGURATION_Handle *GSC_cfg;
6
7/**
8 * For creating statistics.
9 */
10extern struct GNUNET_STATISTICS_Handle *GSC_stats;
11
12/**
13 * Our identity.
14 */
15extern struct GNUNET_PeerIdentity GSC_my_identity;
diff --git a/src/core/gnunet-service-core_ats.c b/src/core/gnunet-service-core_ats.c
new file mode 100644
index 000000000..3be2da205
--- /dev/null
+++ b/src/core/gnunet-service-core_ats.c
@@ -0,0 +1,159 @@
1
2/**
3 * How much inbound bandwidth are we supposed to be using per second?
4 */
5static unsigned long long bandwidth_target_in_bps;
6
7/**
8 * How much outbound bandwidth are we supposed to be using per second?
9 */
10static unsigned long long bandwidth_target_out_bps;
11
12
13
14/**
15 * Schedule the task that will recalculate the bandwidth
16 * quota for this peer (and possibly force a disconnect of
17 * idle peers by calculating a bandwidth of zero).
18 */
19static void
20schedule_quota_update (struct Neighbour *n)
21{
22 GNUNET_assert (n->quota_update_task == GNUNET_SCHEDULER_NO_TASK);
23 n->quota_update_task =
24 GNUNET_SCHEDULER_add_delayed (QUOTA_UPDATE_FREQUENCY,
25 &neighbour_quota_update, n);
26}
27
28
29/**
30 * Function that recalculates the bandwidth quota for the
31 * given neighbour and transmits it to the transport service.
32 *
33 * @param cls neighbour for the quota update
34 * @param tc context
35 */
36static void
37neighbour_quota_update (void *cls,
38 const struct GNUNET_SCHEDULER_TaskContext *tc)
39{
40 struct Neighbour *n = cls;
41 struct GNUNET_BANDWIDTH_Value32NBO q_in;
42 struct GNUNET_BANDWIDTH_Value32NBO q_out;
43 struct GNUNET_BANDWIDTH_Value32NBO q_out_min;
44 double pref_rel;
45 double share;
46 unsigned long long distributable;
47 uint64_t need_per_peer;
48 uint64_t need_per_second;
49 unsigned int neighbour_count;
50
51#if DEBUG_CORE > 1
52 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
53 "Neighbour quota update calculation running for peer `%4s'\n",
54 GNUNET_i2s (&n->peer));
55#endif
56 n->quota_update_task = GNUNET_SCHEDULER_NO_TASK;
57 /* calculate relative preference among all neighbours;
58 * divides by a bit more to avoid division by zero AND to
59 * account for possibility of new neighbours joining any time
60 * AND to convert to double... */
61 neighbour_count = GNUNET_CONTAINER_multihashmap_size (neighbours);
62 if (neighbour_count == 0)
63 return;
64 if (preference_sum == 0)
65 {
66 pref_rel = 1.0 / (double) neighbour_count;
67 }
68 else
69 {
70 pref_rel = (double) n->current_preference / preference_sum;
71 }
72 need_per_peer =
73 GNUNET_BANDWIDTH_value_get_available_until (MIN_BANDWIDTH_PER_PEER,
74 GNUNET_TIME_UNIT_SECONDS);
75 need_per_second = need_per_peer * neighbour_count;
76
77 /* calculate inbound bandwidth per peer */
78 distributable = 0;
79 if (bandwidth_target_in_bps > need_per_second)
80 distributable = bandwidth_target_in_bps - need_per_second;
81 share = distributable * pref_rel;
82 if (share + need_per_peer > UINT32_MAX)
83 q_in = GNUNET_BANDWIDTH_value_init (UINT32_MAX);
84 else
85 q_in = GNUNET_BANDWIDTH_value_init (need_per_peer + (uint32_t) share);
86
87 /* calculate outbound bandwidth per peer */
88 distributable = 0;
89 if (bandwidth_target_out_bps > need_per_second)
90 distributable = bandwidth_target_out_bps - need_per_second;
91 share = distributable * pref_rel;
92 if (share + need_per_peer > UINT32_MAX)
93 q_out = GNUNET_BANDWIDTH_value_init (UINT32_MAX);
94 else
95 q_out = GNUNET_BANDWIDTH_value_init (need_per_peer + (uint32_t) share);
96 n->bw_out_internal_limit = q_out;
97
98 q_out_min =
99 GNUNET_BANDWIDTH_value_min (n->bw_out_external_limit,
100 n->bw_out_internal_limit);
101 GNUNET_BANDWIDTH_tracker_update_quota (&n->available_send_window, n->bw_out);
102
103 /* check if we want to disconnect for good due to inactivity */
104 if ((GNUNET_TIME_absolute_get_duration (get_neighbour_timeout (n)).rel_value >
105 0) &&
106 (GNUNET_TIME_absolute_get_duration (n->time_established).rel_value >
107 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value))
108 {
109#if DEBUG_CORE
110 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
111 "Forcing disconnect of `%4s' due to inactivity\n",
112 GNUNET_i2s (&n->peer));
113#endif
114 GNUNET_STATISTICS_update (stats,
115 gettext_noop ("# peers disconnected due to inactivity"), 1,
116 GNUNET_NO);
117 q_in = GNUNET_BANDWIDTH_value_init (0); /* force disconnect */
118 }
119#if DEBUG_CORE_QUOTA
120 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
121 "Current quota for `%4s' is %u/%llu b/s in (old: %u b/s) / %u out (%u internal)\n",
122 GNUNET_i2s (&n->peer), (unsigned int) ntohl (q_in.value__),
123 bandwidth_target_out_bps, (unsigned int) ntohl (n->bw_in.value__),
124 (unsigned int) ntohl (n->bw_out.value__),
125 (unsigned int) ntohl (n->bw_out_internal_limit.value__));
126#endif
127 if ((n->bw_in.value__ != q_in.value__) ||
128 (n->bw_out.value__ != q_out_min.value__))
129 {
130 if (n->bw_in.value__ != q_in.value__)
131 n->bw_in = q_in;
132 if (n->bw_out.value__ != q_out_min.value__)
133 n->bw_out = q_out_min;
134 if (GNUNET_YES == n->is_connected)
135 GNUNET_TRANSPORT_set_quota (transport, &n->peer, n->bw_in, n->bw_out);
136 handle_peer_status_change (n);
137 }
138 schedule_quota_update (n);
139}
140
141
142
143void
144GSC_ATS_init ()
145{
146 if ((GNUNET_OK !=
147 GNUNET_CONFIGURATION_get_value_number (c, "CORE", "TOTAL_QUOTA_IN",
148 &bandwidth_target_in_bps)) ||
149 (GNUNET_OK !=
150 GNUNET_CONFIGURATION_get_value_number (c, "CORE", "TOTAL_QUOTA_OUT",
151 &bandwidth_target_out_bps)) )
152 {
153 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
154 _
155 ("Core service is lacking key configuration settings. Exiting.\n"));
156 GNUNET_SCHEDULER_shutdown ();
157 return;
158 }
159}
diff --git a/src/core/gnunet-service-core_clients.c b/src/core/gnunet-service-core_clients.c
new file mode 100644
index 000000000..ffd6d294f
--- /dev/null
+++ b/src/core/gnunet-service-core_clients.c
@@ -0,0 +1,1102 @@
1
2/**
3 * Data structure for each client connected to the core service.
4 */
5struct Client
6{
7 /**
8 * Clients are kept in a linked list.
9 */
10 struct Client *next;
11
12 /**
13 * Handle for the client with the server API.
14 */
15 struct GNUNET_SERVER_Client *client_handle;
16
17 /**
18 * Array of the types of messages this peer cares
19 * about (with "tcnt" entries). Allocated as part
20 * of this client struct, do not free!
21 */
22 const uint16_t *types;
23
24 /**
25 * Map of peer identities to active transmission requests of this
26 * client to the peer (of type 'struct ClientActiveRequest').
27 */
28 struct GNUNET_CONTAINER_MultiHashMap *requests;
29
30 /**
31 * Options for messages this client cares about,
32 * see GNUNET_CORE_OPTION_ values.
33 */
34 uint32_t options;
35
36 /**
37 * Number of types of incoming messages this client
38 * specifically cares about. Size of the "types" array.
39 */
40 unsigned int tcnt;
41
42};
43
44
45/**
46 * Record kept for each request for transmission issued by a
47 * client that is still pending.
48 */
49struct ClientActiveRequest
50{
51
52 /**
53 * Active requests are kept in a doubly-linked list of
54 * the respective target peer.
55 */
56 struct ClientActiveRequest *next;
57
58 /**
59 * Active requests are kept in a doubly-linked list of
60 * the respective target peer.
61 */
62 struct ClientActiveRequest *prev;
63
64 /**
65 * Handle to the client.
66 */
67 struct Client *client;
68
69 /**
70 * By what time would the client want to see this message out?
71 */
72 struct GNUNET_TIME_Absolute deadline;
73
74 /**
75 * How important is this request.
76 */
77 uint32_t priority;
78
79 /**
80 * How many more requests does this client have?
81 */
82 uint32_t queue_size;
83
84 /**
85 * How many bytes does the client intend to send?
86 */
87 uint16_t msize;
88
89 /**
90 * Unique request ID (in big endian).
91 */
92 uint16_t smr_id;
93
94};
95
96
97
98/**
99 * Linked list of our clients.
100 */
101static struct Client *clients;
102
103/**
104 * Context for notifications we need to send to our clients.
105 */
106static struct GNUNET_SERVER_NotificationContext *notifier;
107
108
109/**
110 * Our message stream tokenizer (for encrypted payload).
111 */
112static struct GNUNET_SERVER_MessageStreamTokenizer *mst;
113
114
115
116/**
117 * Send a message to one of our clients.
118 *
119 * @param client target for the message
120 * @param msg message to transmit
121 * @param can_drop could this message be dropped if the
122 * client's queue is getting too large?
123 */
124static void
125send_to_client (struct Client *client, const struct GNUNET_MessageHeader *msg,
126 int can_drop)
127{
128#if DEBUG_CORE_CLIENT
129 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
130 "Preparing to send %u bytes of message of type %u to client.\n",
131 (unsigned int) ntohs (msg->size),
132 (unsigned int) ntohs (msg->type));
133#endif
134 GNUNET_SERVER_notification_context_unicast (notifier, client->client_handle,
135 msg, can_drop);
136}
137
138
139
140
141
142/**
143 * Send a message to all of our current clients that have
144 * the right options set.
145 *
146 * @param msg message to multicast
147 * @param can_drop can this message be discarded if the queue is too long
148 * @param options mask to use
149 */
150static void
151send_to_all_clients (const struct GNUNET_MessageHeader *msg, int can_drop,
152 int options)
153{
154 struct Client *c;
155
156 c = clients;
157 while (c != NULL)
158 {
159 if (0 != (c->options & options))
160 {
161#if DEBUG_CORE_CLIENT > 1
162 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
163 "Sending message of type %u to client.\n",
164 (unsigned int) ntohs (msg->type));
165#endif
166 send_to_client (c, msg, can_drop);
167 }
168 c = c->next;
169 }
170}
171
172
173
174/**
175 * Handle CORE_SEND_REQUEST message.
176 */
177static void
178handle_client_send_request (void *cls, struct GNUNET_SERVER_Client *client,
179 const struct GNUNET_MessageHeader *message)
180{
181 const struct SendMessageRequest *req;
182 struct Neighbour *n;
183 struct Client *c;
184 struct ClientActiveRequest *car;
185
186 req = (const struct SendMessageRequest *) message;
187 if (0 ==
188 memcmp (&req->peer, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
189 n = &self;
190 else
191 n = find_neighbour (&req->peer);
192 if ((n == NULL) || (GNUNET_YES != n->is_connected) ||
193 (n->status != PEER_STATE_KEY_CONFIRMED))
194 {
195 /* neighbour must have disconnected since request was issued,
196 * ignore (client will realize it once it processes the
197 * disconnect notification) */
198#if DEBUG_CORE_CLIENT
199 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
200 "Dropped client request for transmission (am disconnected)\n");
201#endif
202 GNUNET_STATISTICS_update (stats,
203 gettext_noop
204 ("# send requests dropped (disconnected)"), 1,
205 GNUNET_NO);
206 GNUNET_SERVER_receive_done (client, GNUNET_OK);
207 return;
208 }
209 c = clients;
210 while ((c != NULL) && (c->client_handle != client))
211 c = c->next;
212 if (c == NULL)
213 {
214 /* client did not send INIT first! */
215 GNUNET_break (0);
216 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
217 return;
218 }
219 if (c->requests == NULL)
220 c->requests = GNUNET_CONTAINER_multihashmap_create (16);
221#if DEBUG_CORE_CLIENT
222 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
223 "Received client transmission request. queueing\n");
224#endif
225 car = GNUNET_CONTAINER_multihashmap_get (c->requests, &req->peer.hashPubKey);
226 if (car == NULL)
227 {
228 /* create new entry */
229 car = GNUNET_malloc (sizeof (struct ClientActiveRequest));
230 GNUNET_assert (GNUNET_OK ==
231 GNUNET_CONTAINER_multihashmap_put (c->requests,
232 &req->peer.hashPubKey,
233 car,
234 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST));
235 GNUNET_CONTAINER_DLL_insert (n->active_client_request_head,
236 n->active_client_request_tail, car);
237 car->client = c;
238 }
239 car->deadline = GNUNET_TIME_absolute_ntoh (req->deadline);
240 car->priority = ntohl (req->priority);
241 car->queue_size = ntohl (req->queue_size);
242 car->msize = ntohs (req->size);
243 car->smr_id = req->smr_id;
244 schedule_peer_messages (n);
245 GNUNET_SERVER_receive_done (client, GNUNET_OK);
246}
247
248
249/**
250 * Notify client about an existing connection to one of our neighbours.
251 */
252static int
253notify_client_about_neighbour (void *cls, const GNUNET_HashCode * key,
254 void *value)
255{
256 struct Client *c = cls;
257 struct Neighbour *n = value;
258 size_t size;
259 char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
260 struct GNUNET_TRANSPORT_ATS_Information *ats;
261 struct ConnectNotifyMessage *cnm;
262
263 size =
264 sizeof (struct ConnectNotifyMessage) +
265 (n->ats_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
266 if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
267 {
268 GNUNET_break (0);
269 /* recovery strategy: throw away performance data */
270 GNUNET_array_grow (n->ats, n->ats_count, 0);
271 size =
272 sizeof (struct ConnectNotifyMessage) +
273 (n->ats_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
274 }
275 cnm = (struct ConnectNotifyMessage *) buf;
276 cnm->header.size = htons (size);
277 cnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
278 cnm->ats_count = htonl (n->ats_count);
279 ats = &cnm->ats;
280 memcpy (ats, n->ats,
281 sizeof (struct GNUNET_TRANSPORT_ATS_Information) * n->ats_count);
282 ats[n->ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
283 ats[n->ats_count].value = htonl (0);
284 if (n->status == PEER_STATE_KEY_CONFIRMED)
285 {
286#if DEBUG_CORE_CLIENT
287 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message to client.\n",
288 "NOTIFY_CONNECT");
289#endif
290 cnm->peer = n->peer;
291 send_to_client (c, &cnm->header, GNUNET_NO);
292 }
293 return GNUNET_OK;
294}
295
296
297
298/**
299 * Handle CORE_INIT request.
300 */
301static void
302handle_client_init (void *cls, struct GNUNET_SERVER_Client *client,
303 const struct GNUNET_MessageHeader *message)
304{
305 const struct InitMessage *im;
306 struct InitReplyMessage irm;
307 struct Client *c;
308 uint16_t msize;
309 const uint16_t *types;
310 uint16_t *wtypes;
311 unsigned int i;
312
313#if DEBUG_CORE_CLIENT
314 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
315 "Client connecting to core service with `%s' message\n", "INIT");
316#endif
317 /* check that we don't have an entry already */
318 c = clients;
319 while (c != NULL)
320 {
321 if (client == c->client_handle)
322 {
323 GNUNET_break (0);
324 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
325 return;
326 }
327 c = c->next;
328 }
329 msize = ntohs (message->size);
330 if (msize < sizeof (struct InitMessage))
331 {
332 GNUNET_break (0);
333 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
334 return;
335 }
336 GNUNET_SERVER_notification_context_add (notifier, client);
337 im = (const struct InitMessage *) message;
338 types = (const uint16_t *) &im[1];
339 msize -= sizeof (struct InitMessage);
340 c = GNUNET_malloc (sizeof (struct Client) + msize);
341 c->client_handle = client;
342 c->next = clients;
343 clients = c;
344 c->tcnt = msize / sizeof (uint16_t);
345 c->types = (const uint16_t *) &c[1];
346 wtypes = (uint16_t *) & c[1];
347 for (i = 0; i < c->tcnt; i++)
348 {
349 wtypes[i] = ntohs (types[i]);
350 my_type_map[wtypes[i] / 32] |= (1 << (wtypes[i] % 32));
351 }
352 if (c->tcnt > 0)
353 broadcast_my_type_map ();
354 c->options = ntohl (im->options);
355#if DEBUG_CORE_CLIENT
356 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
357 "Client %p is interested in %u message types\n", c,
358 (unsigned int) c->tcnt);
359#endif
360 /* send init reply message */
361 irm.header.size = htons (sizeof (struct InitReplyMessage));
362 irm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY);
363 irm.reserved = htonl (0);
364 memcpy (&irm.publicKey, &my_public_key,
365 sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
366#if DEBUG_CORE_CLIENT
367 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message to client.\n",
368 "INIT_REPLY");
369#endif
370 send_to_client (c, &irm.header, GNUNET_NO);
371 if (0 != (c->options & GNUNET_CORE_OPTION_SEND_CONNECT))
372 {
373 /* notify new client about existing neighbours */
374 GNUNET_CONTAINER_multihashmap_iterate (neighbours,
375 &notify_client_about_neighbour, c);
376 }
377 GNUNET_SERVER_receive_done (client, GNUNET_OK);
378}
379
380
381/**
382 * Free client request records.
383 *
384 * @param cls NULL
385 * @param key identity of peer for which this is an active request
386 * @param value the 'struct ClientActiveRequest' to free
387 * @return GNUNET_YES (continue iteration)
388 */
389static int
390destroy_active_client_request (void *cls, const GNUNET_HashCode * key,
391 void *value)
392{
393 struct ClientActiveRequest *car = value;
394 struct Neighbour *n;
395 struct GNUNET_PeerIdentity peer;
396
397 peer.hashPubKey = *key;
398 n = find_neighbour (&peer);
399 GNUNET_assert (NULL != n);
400 GNUNET_CONTAINER_DLL_remove (n->active_client_request_head,
401 n->active_client_request_tail, car);
402 GNUNET_free (car);
403 return GNUNET_YES;
404}
405
406
407/**
408 * A client disconnected, clean up.
409 *
410 * @param cls closure
411 * @param client identification of the client
412 */
413static void
414handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client)
415{
416 struct Client *pos;
417 struct Client *prev;
418 unsigned int i;
419 const uint16_t *wtypes;
420
421 if (client == NULL)
422 return;
423#if DEBUG_CORE_CLIENT
424 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
425 "Client %p has disconnected from core service.\n", client);
426#endif
427 prev = NULL;
428 pos = clients;
429 while (pos != NULL)
430 {
431 if (client == pos->client_handle)
432 break;
433 prev = pos;
434 pos = pos->next;
435 }
436 if (pos == NULL)
437 {
438 /* client never sent INIT */
439 return;
440 }
441 if (prev == NULL)
442 clients = pos->next;
443 else
444 prev->next = pos->next;
445 if (pos->requests != NULL)
446 {
447 GNUNET_CONTAINER_multihashmap_iterate (pos->requests,
448 &destroy_active_client_request,
449 NULL);
450 GNUNET_CONTAINER_multihashmap_destroy (pos->requests);
451 }
452 GNUNET_free (pos);
453
454 /* rebuild my_type_map */
455 memset (my_type_map, 0, sizeof (my_type_map));
456 for (pos = clients; NULL != pos; pos = pos->next)
457 {
458 wtypes = (const uint16_t *) &pos[1];
459 for (i = 0; i < pos->tcnt; i++)
460 my_type_map[wtypes[i] / 32] |= (1 << (wtypes[i] % 32));
461 }
462 broadcast_my_type_map ();
463}
464
465
466
467
468
469/**
470 * Handle CORE_SEND request.
471 *
472 * @param cls unused
473 * @param client the client issuing the request
474 * @param message the "struct SendMessage"
475 */
476static void
477handle_client_send (void *cls, struct GNUNET_SERVER_Client *client,
478 const struct GNUNET_MessageHeader *message)
479{
480 const struct SendMessage *sm;
481 struct Neighbour *n;
482 struct MessageEntry *prev;
483 struct MessageEntry *pos;
484 struct MessageEntry *e;
485 struct MessageEntry *min_prio_entry;
486 struct MessageEntry *min_prio_prev;
487 unsigned int min_prio;
488 unsigned int queue_size;
489 uint16_t msize;
490
491 msize = ntohs (message->size);
492 if (msize <
493 sizeof (struct SendMessage) + sizeof (struct GNUNET_MessageHeader))
494 {
495 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
496 "msize is %u, should be at least %u (in %s:%d)\n", msize,
497 sizeof (struct SendMessage) +
498 sizeof (struct GNUNET_MessageHeader), __FILE__, __LINE__);
499 GNUNET_break (0);
500 if (client != NULL)
501 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
502 return;
503 }
504 sm = (const struct SendMessage *) message;
505 msize -= sizeof (struct SendMessage);
506 if (0 ==
507 memcmp (&sm->peer, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
508 {
509 /* loopback */
510 GNUNET_SERVER_mst_receive (mst, &self, (const char *) &sm[1], msize,
511 GNUNET_YES, GNUNET_NO);
512 if (client != NULL)
513 GNUNET_SERVER_receive_done (client, GNUNET_OK);
514 return;
515 }
516 n = find_neighbour (&sm->peer);
517 if ((n == NULL) || (GNUNET_YES != n->is_connected) ||
518 (n->status != PEER_STATE_KEY_CONFIRMED))
519 {
520 /* attempt to send message to peer that is not connected anymore
521 * (can happen due to asynchrony) */
522 GNUNET_STATISTICS_update (stats,
523 gettext_noop
524 ("# messages discarded (disconnected)"), 1,
525 GNUNET_NO);
526 if (client != NULL)
527 GNUNET_SERVER_receive_done (client, GNUNET_OK);
528 return;
529 }
530#if DEBUG_CORE
531 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
532 "Core received `%s' request, queueing %u bytes of plaintext data for transmission to `%4s'.\n",
533 "SEND", (unsigned int) msize, GNUNET_i2s (&sm->peer));
534#endif
535 discard_expired_messages (n);
536 /* bound queue size */
537 /* NOTE: this entire block to bound the queue size should be
538 * obsolete with the new client-request code and the
539 * 'schedule_peer_messages' mechanism; we still have this code in
540 * here for now as a sanity check for the new mechanmism;
541 * ultimately, we should probably simply reject SEND messages that
542 * are not 'approved' (or provide a new core API for very unreliable
543 * delivery that always sends with priority 0). Food for thought. */
544 min_prio = UINT32_MAX;
545 min_prio_entry = NULL;
546 min_prio_prev = NULL;
547 queue_size = 0;
548 prev = NULL;
549 pos = n->messages;
550 while (pos != NULL)
551 {
552 if (pos->priority <= min_prio)
553 {
554 min_prio_entry = pos;
555 min_prio_prev = prev;
556 min_prio = pos->priority;
557 }
558 queue_size++;
559 prev = pos;
560 pos = pos->next;
561 }
562 if (queue_size >= MAX_PEER_QUEUE_SIZE)
563 {
564 /* queue full */
565 if (ntohl (sm->priority) <= min_prio)
566 {
567 /* discard new entry; this should no longer happen! */
568 GNUNET_break (0);
569#if DEBUG_CORE
570 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
571 "Queue full (%u/%u), discarding new request (%u bytes of type %u)\n",
572 queue_size, (unsigned int) MAX_PEER_QUEUE_SIZE,
573 (unsigned int) msize, (unsigned int) ntohs (message->type));
574#endif
575 GNUNET_STATISTICS_update (stats,
576 gettext_noop ("# discarded CORE_SEND requests"),
577 1, GNUNET_NO);
578
579 if (client != NULL)
580 GNUNET_SERVER_receive_done (client, GNUNET_OK);
581 return;
582 }
583 GNUNET_assert (min_prio_entry != NULL);
584 /* discard "min_prio_entry" */
585#if DEBUG_CORE
586 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
587 "Queue full, discarding existing older request\n");
588#endif
589 GNUNET_STATISTICS_update (stats,
590 gettext_noop
591 ("# discarded lower priority CORE_SEND requests"),
592 1, GNUNET_NO);
593 if (min_prio_prev == NULL)
594 n->messages = min_prio_entry->next;
595 else
596 min_prio_prev->next = min_prio_entry->next;
597 GNUNET_free (min_prio_entry);
598 }
599
600#if DEBUG_CORE
601 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
602 "Adding transmission request for `%4s' of size %u to queue\n",
603 GNUNET_i2s (&sm->peer), (unsigned int) msize);
604#endif
605 GNUNET_break (0 == ntohl (sm->reserved));
606 e = GNUNET_malloc (sizeof (struct MessageEntry) + msize);
607 e->deadline = GNUNET_TIME_absolute_ntoh (sm->deadline);
608 e->priority = ntohl (sm->priority);
609 e->size = msize;
610 if (GNUNET_YES != (int) ntohl (sm->cork))
611 e->got_slack = GNUNET_YES;
612 memcpy (&e[1], &sm[1], msize);
613
614 /* insert, keep list sorted by deadline */
615 prev = NULL;
616 pos = n->messages;
617 while ((pos != NULL) && (pos->deadline.abs_value < e->deadline.abs_value))
618 {
619 prev = pos;
620 pos = pos->next;
621 }
622 if (prev == NULL)
623 n->messages = e;
624 else
625 prev->next = e;
626 e->next = pos;
627
628 /* consider scheduling now */
629 process_plaintext_neighbour_queue (n);
630 if (client != NULL)
631 GNUNET_SERVER_receive_done (client, GNUNET_OK);
632}
633
634
635/**
636 * Handle CORE_REQUEST_CONNECT request.
637 *
638 * @param cls unused
639 * @param client the client issuing the request
640 * @param message the "struct ConnectMessage"
641 */
642static void
643handle_client_request_connect (void *cls, struct GNUNET_SERVER_Client *client,
644 const struct GNUNET_MessageHeader *message)
645{
646 const struct ConnectMessage *cm = (const struct ConnectMessage *) message;
647 struct Neighbour *n;
648
649 if (0 ==
650 memcmp (&cm->peer, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
651 {
652 /* In this case a client has asked us to connect to ourselves, not really an error! */
653 GNUNET_SERVER_receive_done (client, GNUNET_OK);
654 return;
655 }
656 GNUNET_break (ntohl (cm->reserved) == 0);
657#if DEBUG_CORE
658 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
659 "Core received `%s' request for `%4s', will try to establish connection\n",
660 "REQUEST_CONNECT", GNUNET_i2s (&cm->peer));
661#endif
662 GNUNET_STATISTICS_update (stats,
663 gettext_noop ("# connection requests received"), 1,
664 GNUNET_NO);
665 GNUNET_SERVER_receive_done (client, GNUNET_OK);
666 n = find_neighbour (&cm->peer);
667 if ((n == NULL) || (GNUNET_YES != n->is_connected))
668 {
669 GNUNET_TRANSPORT_try_connect (transport, &cm->peer);
670 }
671 else
672 {
673 GNUNET_STATISTICS_update (stats,
674 gettext_noop
675 ("# connection requests ignored (already connected)"),
676 1, GNUNET_NO);
677 }
678}
679
680
681
682/**
683 * Helper function for handle_client_iterate_peers.
684 *
685 * @param cls the 'struct GNUNET_SERVER_TransmitContext' to queue replies
686 * @param key identity of the connected peer
687 * @param value the 'struct Neighbour' for the peer
688 * @return GNUNET_OK (continue to iterate)
689 */
690static int
691queue_connect_message (void *cls, const GNUNET_HashCode * key, void *value)
692{
693 struct GNUNET_SERVER_TransmitContext *tc = cls;
694 struct Neighbour *n = value;
695 char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
696 struct GNUNET_TRANSPORT_ATS_Information *ats;
697 size_t size;
698 struct ConnectNotifyMessage *cnm;
699
700 cnm = (struct ConnectNotifyMessage *) buf;
701 if (n->status != PEER_STATE_KEY_CONFIRMED)
702 return GNUNET_OK;
703 size =
704 sizeof (struct ConnectNotifyMessage) +
705 (n->ats_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
706 if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
707 {
708 GNUNET_break (0);
709 /* recovery strategy: throw away performance data */
710 GNUNET_array_grow (n->ats, n->ats_count, 0);
711 size =
712 sizeof (struct PeerStatusNotifyMessage) +
713 n->ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
714 }
715 cnm = (struct ConnectNotifyMessage *) buf;
716 cnm->header.size = htons (size);
717 cnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
718 cnm->ats_count = htonl (n->ats_count);
719 ats = &cnm->ats;
720 memcpy (ats, n->ats,
721 n->ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information));
722 ats[n->ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
723 ats[n->ats_count].value = htonl (0);
724#if DEBUG_CORE_CLIENT
725 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message to client.\n",
726 "NOTIFY_CONNECT");
727#endif
728 cnm->peer = n->peer;
729 GNUNET_SERVER_transmit_context_append_message (tc, &cnm->header);
730 return GNUNET_OK;
731}
732
733
734/**
735 * Handle CORE_ITERATE_PEERS request.
736 *
737 * @param cls unused
738 * @param client client sending the iteration request
739 * @param message iteration request message
740 */
741static void
742handle_client_iterate_peers (void *cls, struct GNUNET_SERVER_Client *client,
743 const struct GNUNET_MessageHeader *message)
744{
745 struct GNUNET_MessageHeader done_msg;
746 struct GNUNET_SERVER_TransmitContext *tc;
747 int msize;
748
749 /* notify new client about existing neighbours */
750
751 msize = ntohs (message->size);
752 tc = GNUNET_SERVER_transmit_context_create (client);
753 if (msize == sizeof (struct GNUNET_MessageHeader))
754 GNUNET_CONTAINER_multihashmap_iterate (neighbours, &queue_connect_message,
755 tc);
756 else
757 GNUNET_break (0);
758
759 done_msg.size = htons (sizeof (struct GNUNET_MessageHeader));
760 done_msg.type = htons (GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS_END);
761 GNUNET_SERVER_transmit_context_append_message (tc, &done_msg);
762 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
763}
764
765
766/**
767 * Handle CORE_PEER_CONNECTED request. Notify client about existing neighbours.
768 *
769 * @param cls unused
770 * @param client client sending the iteration request
771 * @param message iteration request message
772 */
773static void
774handle_client_have_peer (void *cls, struct GNUNET_SERVER_Client *client,
775 const struct GNUNET_MessageHeader *message)
776{
777 struct GNUNET_MessageHeader done_msg;
778 struct GNUNET_SERVER_TransmitContext *tc;
779 struct GNUNET_PeerIdentity *peer;
780
781 tc = GNUNET_SERVER_transmit_context_create (client);
782 peer = (struct GNUNET_PeerIdentity *) &message[1];
783 GNUNET_CONTAINER_multihashmap_get_multiple (neighbours, &peer->hashPubKey,
784 &queue_connect_message, tc);
785 done_msg.size = htons (sizeof (struct GNUNET_MessageHeader));
786 done_msg.type = htons (GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS_END);
787 GNUNET_SERVER_transmit_context_append_message (tc, &done_msg);
788 GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
789}
790
791
792/**
793 * Handle REQUEST_INFO request.
794 *
795 * @param cls unused
796 * @param client client sending the request
797 * @param message iteration request message
798 */
799static void
800handle_client_request_info (void *cls, struct GNUNET_SERVER_Client *client,
801 const struct GNUNET_MessageHeader *message)
802{
803 const struct RequestInfoMessage *rcm;
804 struct Client *pos;
805 struct Neighbour *n;
806 struct ConfigurationInfoMessage cim;
807 int32_t want_reserv;
808 int32_t got_reserv;
809 unsigned long long old_preference;
810 struct GNUNET_TIME_Relative rdelay;
811
812 rdelay = GNUNET_TIME_relative_get_zero ();
813#if DEBUG_CORE_CLIENT
814 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Core service receives `%s' request.\n",
815 "REQUEST_INFO");
816#endif
817 pos = clients;
818 while (pos != NULL)
819 {
820 if (client == pos->client_handle)
821 break;
822 pos = pos->next;
823 }
824 if (pos == NULL)
825 {
826 GNUNET_break (0);
827 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
828 return;
829 }
830
831 rcm = (const struct RequestInfoMessage *) message;
832 n = find_neighbour (&rcm->peer);
833 memset (&cim, 0, sizeof (cim));
834 if ((n != NULL) && (GNUNET_YES == n->is_connected))
835 {
836 want_reserv = ntohl (rcm->reserve_inbound);
837 if (n->bw_out_internal_limit.value__ != rcm->limit_outbound.value__)
838 {
839 n->bw_out_internal_limit = rcm->limit_outbound;
840 if (n->bw_out.value__ !=
841 GNUNET_BANDWIDTH_value_min (n->bw_out_internal_limit,
842 n->bw_out_external_limit).value__)
843 {
844 n->bw_out =
845 GNUNET_BANDWIDTH_value_min (n->bw_out_internal_limit,
846 n->bw_out_external_limit);
847 GNUNET_BANDWIDTH_tracker_update_quota (&n->available_recv_window,
848 n->bw_out);
849 GNUNET_TRANSPORT_set_quota (transport, &n->peer, n->bw_in, n->bw_out);
850 handle_peer_status_change (n);
851 }
852 }
853 if (want_reserv < 0)
854 {
855 got_reserv = want_reserv;
856 }
857 else if (want_reserv > 0)
858 {
859 rdelay =
860 GNUNET_BANDWIDTH_tracker_get_delay (&n->available_recv_window,
861 want_reserv);
862 if (rdelay.rel_value == 0)
863 got_reserv = want_reserv;
864 else
865 got_reserv = 0; /* all or nothing */
866 }
867 else
868 got_reserv = 0;
869 GNUNET_BANDWIDTH_tracker_consume (&n->available_recv_window, got_reserv);
870 old_preference = n->current_preference;
871 n->current_preference += GNUNET_ntohll (rcm->preference_change);
872 if (old_preference > n->current_preference)
873 {
874 /* overflow; cap at maximum value */
875 n->current_preference = ULLONG_MAX;
876 }
877 update_preference_sum (n->current_preference - old_preference);
878#if DEBUG_CORE_QUOTA
879 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
880 "Received reservation request for %d bytes for peer `%4s', reserved %d bytes, suggesting delay of %llu ms\n",
881 (int) want_reserv, GNUNET_i2s (&rcm->peer), (int) got_reserv,
882 (unsigned long long) rdelay.rel_value);
883#endif
884 cim.reserved_amount = htonl (got_reserv);
885 cim.reserve_delay = GNUNET_TIME_relative_hton (rdelay);
886 cim.bw_out = n->bw_out;
887 cim.preference = n->current_preference;
888 }
889 else
890 {
891 /* Technically, this COULD happen (due to asynchronous behavior),
892 * but it should be rare, so we should generate an info event
893 * to help diagnosis of serious errors that might be masked by this */
894 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
895 _
896 ("Client asked for preference change with peer `%s', which is not connected!\n"),
897 GNUNET_i2s (&rcm->peer));
898 GNUNET_SERVER_receive_done (client, GNUNET_OK);
899 return;
900 }
901 cim.header.size = htons (sizeof (struct ConfigurationInfoMessage));
902 cim.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_CONFIGURATION_INFO);
903 cim.peer = rcm->peer;
904 cim.rim_id = rcm->rim_id;
905#if DEBUG_CORE_CLIENT
906 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message to client.\n",
907 "CONFIGURATION_INFO");
908#endif
909 send_to_client (pos, &cim.header, GNUNET_NO);
910 GNUNET_SERVER_receive_done (client, GNUNET_OK);
911}
912
913
914
915
916/**
917 * Send a P2P message to a client.
918 *
919 * @param sender who sent us the message?
920 * @param client who should we give the message to?
921 * @param m contains the message to transmit
922 * @param msize number of bytes in buf to transmit
923 */
924static void
925send_p2p_message_to_client (struct Neighbour *sender, struct Client *client,
926 const void *m, size_t msize)
927{
928 size_t size =
929 msize + sizeof (struct NotifyTrafficMessage) +
930 (sender->ats_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
931 char buf[size];
932 struct NotifyTrafficMessage *ntm;
933 struct GNUNET_TRANSPORT_ATS_Information *ats;
934
935 GNUNET_assert (GNUNET_YES == sender->is_connected);
936 GNUNET_break (sender->status == PEER_STATE_KEY_CONFIRMED);
937 if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
938 {
939 GNUNET_break (0);
940 /* recovery strategy: throw performance data away... */
941 GNUNET_array_grow (sender->ats, sender->ats_count, 0);
942 size =
943 msize + sizeof (struct NotifyTrafficMessage) +
944 (sender->ats_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
945 }
946#if DEBUG_CORE
947 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
948 "Core service passes message from `%4s' of type %u to client.\n",
949 GNUNET_i2s (&sender->peer),
950 (unsigned int)
951 ntohs (((const struct GNUNET_MessageHeader *) m)->type));
952#endif
953 ntm = (struct NotifyTrafficMessage *) buf;
954 ntm->header.size = htons (size);
955 ntm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_INBOUND);
956 ntm->ats_count = htonl (sender->ats_count);
957 ntm->peer = sender->peer;
958 ats = &ntm->ats;
959 memcpy (ats, sender->ats,
960 sizeof (struct GNUNET_TRANSPORT_ATS_Information) * sender->ats_count);
961 ats[sender->ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
962 ats[sender->ats_count].value = htonl (0);
963 memcpy (&ats[sender->ats_count + 1], m, msize);
964 send_to_client (client, &ntm->header, GNUNET_YES);
965}
966
967
968
969
970/**
971 * Deliver P2P message to interested clients.
972 *
973 * @param cls always NULL
974 * @param client who sent us the message (struct Neighbour)
975 * @param m the message
976 */
977static void
978deliver_message (void *cls, void *client, const struct GNUNET_MessageHeader *m)
979{
980 struct Neighbour *sender = client;
981 size_t msize = ntohs (m->size);
982 char buf[256];
983 struct Client *cpos;
984 uint16_t type;
985 unsigned int tpos;
986 int deliver_full;
987 int dropped;
988
989 GNUNET_break (sender->status == PEER_STATE_KEY_CONFIRMED);
990 type = ntohs (m->type);
991#if DEBUG_CORE > 1
992 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
993 "Received encapsulated message of type %u and size %u from `%4s'\n",
994 (unsigned int) type, ntohs (m->size), GNUNET_i2s (&sender->peer));
995#endif
996 GNUNET_snprintf (buf, sizeof (buf),
997 gettext_noop ("# bytes of messages of type %u received"),
998 (unsigned int) type);
999 GNUNET_STATISTICS_update (stats, buf, msize, GNUNET_NO);
1000 if ((GNUNET_MESSAGE_TYPE_CORE_BINARY_TYPE_MAP == type) ||
1001 (GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP == type))
1002 {
1003 /* FIXME: update message type map for 'Neighbour' */
1004 return;
1005 }
1006 dropped = GNUNET_YES;
1007 cpos = clients;
1008 while (cpos != NULL)
1009 {
1010 deliver_full = GNUNET_NO;
1011 if (0 != (cpos->options & GNUNET_CORE_OPTION_SEND_FULL_INBOUND))
1012 deliver_full = GNUNET_YES;
1013 else
1014 {
1015 for (tpos = 0; tpos < cpos->tcnt; tpos++)
1016 {
1017 if (type != cpos->types[tpos])
1018 continue;
1019 deliver_full = GNUNET_YES;
1020 break;
1021 }
1022 }
1023 if (GNUNET_YES == deliver_full)
1024 {
1025 send_p2p_message_to_client (sender, cpos, m, msize);
1026 dropped = GNUNET_NO;
1027 }
1028 else if (cpos->options & GNUNET_CORE_OPTION_SEND_HDR_INBOUND)
1029 {
1030 send_p2p_message_to_client (sender, cpos, m,
1031 sizeof (struct GNUNET_MessageHeader));
1032 }
1033 cpos = cpos->next;
1034 }
1035 if (dropped == GNUNET_YES)
1036 {
1037#if DEBUG_CORE
1038 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1039 "Message of type %u from `%4s' not delivered to any client.\n",
1040 (unsigned int) type, GNUNET_i2s (&sender->peer));
1041#endif
1042 GNUNET_STATISTICS_update (stats,
1043 gettext_noop
1044 ("# messages not delivered to any client"), 1,
1045 GNUNET_NO);
1046 }
1047}
1048
1049
1050
1051void
1052GSC_CLIENTS_init (struct GNUNET_SERVER_Handle *server)
1053{
1054 static const struct GNUNET_SERVER_MessageHandler handlers[] = {
1055 {&handle_client_init, NULL,
1056 GNUNET_MESSAGE_TYPE_CORE_INIT, 0},
1057 {&handle_client_iterate_peers, NULL,
1058 GNUNET_MESSAGE_TYPE_CORE_ITERATE_PEERS,
1059 sizeof (struct GNUNET_MessageHeader)},
1060 {&handle_client_have_peer, NULL,
1061 GNUNET_MESSAGE_TYPE_CORE_PEER_CONNECTED,
1062 sizeof (struct GNUNET_MessageHeader) +
1063 sizeof (struct GNUNET_PeerIdentity)},
1064 {&handle_client_request_info, NULL,
1065 GNUNET_MESSAGE_TYPE_CORE_REQUEST_INFO,
1066 sizeof (struct RequestInfoMessage)},
1067 {&handle_client_send_request, NULL,
1068 GNUNET_MESSAGE_TYPE_CORE_SEND_REQUEST,
1069 sizeof (struct SendMessageRequest)},
1070 {&handle_client_send, NULL,
1071 GNUNET_MESSAGE_TYPE_CORE_SEND, 0},
1072 {&handle_client_request_connect, NULL,
1073 GNUNET_MESSAGE_TYPE_CORE_REQUEST_CONNECT,
1074 sizeof (struct ConnectMessage)},
1075 {NULL, NULL, 0, 0}
1076 };
1077
1078 /* setup notification */
1079 notifier =
1080 GNUNET_SERVER_notification_context_create (server, MAX_NOTIFY_QUEUE);
1081 GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL);
1082 GNUNET_SERVER_add_handlers (server, handlers);
1083 mst = GNUNET_SERVER_mst_create (&deliver_message, NULL);
1084}
1085
1086
1087void
1088GSC_CLIENTS_done ()
1089{
1090 struct Client *c;
1091
1092 while (NULL != (c = clients))
1093 handle_client_disconnect (NULL, c->client_handle);
1094 GNUNET_SERVER_notification_context_destroy (notifier);
1095 notifier = NULL;
1096 if (mst != NULL)
1097 {
1098 GNUNET_SERVER_mst_destroy (mst);
1099 mst = NULL;
1100 }
1101
1102}
diff --git a/src/core/gnunet-service-core_crypto.c b/src/core/gnunet-service-core_crypto.c
new file mode 100644
index 000000000..0df6dabc1
--- /dev/null
+++ b/src/core/gnunet-service-core_crypto.c
@@ -0,0 +1,361 @@
1
2/**
3 * Our private key.
4 */
5static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
6
7/**
8 * Our public key.
9 */
10static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
11
12
13/**
14 * Derive an authentication key from "set key" information
15 */
16static void
17derive_auth_key (struct GNUNET_CRYPTO_AuthKey *akey,
18 const struct GNUNET_CRYPTO_AesSessionKey *skey, uint32_t seed,
19 struct GNUNET_TIME_Absolute creation_time)
20{
21 static const char ctx[] = "authentication key";
22 struct GNUNET_TIME_AbsoluteNBO ctbe;
23
24
25 ctbe = GNUNET_TIME_absolute_hton (creation_time);
26 GNUNET_CRYPTO_hmac_derive_key (akey, skey, &seed, sizeof (seed), &skey->key,
27 sizeof (skey->key), &ctbe, sizeof (ctbe), ctx,
28 sizeof (ctx), NULL);
29}
30
31
32/**
33 * Derive an IV from packet information
34 */
35static void
36derive_iv (struct GNUNET_CRYPTO_AesInitializationVector *iv,
37 const struct GNUNET_CRYPTO_AesSessionKey *skey, uint32_t seed,
38 const struct GNUNET_PeerIdentity *identity)
39{
40 static const char ctx[] = "initialization vector";
41
42 GNUNET_CRYPTO_aes_derive_iv (iv, skey, &seed, sizeof (seed),
43 &identity->hashPubKey.bits,
44 sizeof (identity->hashPubKey.bits), ctx,
45 sizeof (ctx), NULL);
46}
47
48/**
49 * Derive an IV from pong packet information
50 */
51static void
52derive_pong_iv (struct GNUNET_CRYPTO_AesInitializationVector *iv,
53 const struct GNUNET_CRYPTO_AesSessionKey *skey, uint32_t seed,
54 uint32_t challenge, const struct GNUNET_PeerIdentity *identity)
55{
56 static const char ctx[] = "pong initialization vector";
57
58 GNUNET_CRYPTO_aes_derive_iv (iv, skey, &seed, sizeof (seed),
59 &identity->hashPubKey.bits,
60 sizeof (identity->hashPubKey.bits), &challenge,
61 sizeof (challenge), ctx, sizeof (ctx), NULL);
62}
63
64
65/**
66 * Encrypt size bytes from in and write the result to out. Use the
67 * key for outbound traffic of the given neighbour.
68 *
69 * @param n neighbour we are sending to
70 * @param iv initialization vector to use
71 * @param in ciphertext
72 * @param out plaintext
73 * @param size size of in/out
74 * @return GNUNET_OK on success
75 */
76static int
77do_encrypt (struct Neighbour *n,
78 const struct GNUNET_CRYPTO_AesInitializationVector *iv,
79 const void *in, void *out, size_t size)
80{
81 if (size != (uint16_t) size)
82 {
83 GNUNET_break (0);
84 return GNUNET_NO;
85 }
86 GNUNET_assert (size ==
87 GNUNET_CRYPTO_aes_encrypt (in, (uint16_t) size,
88 &n->encrypt_key, iv, out));
89 GNUNET_STATISTICS_update (stats, gettext_noop ("# bytes encrypted"), size,
90 GNUNET_NO);
91#if DEBUG_CORE > 2
92 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
93 "Encrypted %u bytes for `%4s' using key %u, IV %u\n",
94 (unsigned int) size, GNUNET_i2s (&n->peer),
95 (unsigned int) n->encrypt_key.crc32, GNUNET_CRYPTO_crc32_n (iv,
96 sizeof
97 (iv)));
98#endif
99 return GNUNET_OK;
100}
101
102
103
104
105/**
106 * Decrypt size bytes from in and write the result to out. Use the
107 * key for inbound traffic of the given neighbour. This function does
108 * NOT do any integrity-checks on the result.
109 *
110 * @param n neighbour we are receiving from
111 * @param iv initialization vector to use
112 * @param in ciphertext
113 * @param out plaintext
114 * @param size size of in/out
115 * @return GNUNET_OK on success
116 */
117static int
118do_decrypt (struct Neighbour *n,
119 const struct GNUNET_CRYPTO_AesInitializationVector *iv,
120 const void *in, void *out, size_t size)
121{
122 if (size != (uint16_t) size)
123 {
124 GNUNET_break (0);
125 return GNUNET_NO;
126 }
127 if ((n->status != PEER_STATE_KEY_RECEIVED) &&
128 (n->status != PEER_STATE_KEY_CONFIRMED))
129 {
130 GNUNET_break_op (0);
131 return GNUNET_SYSERR;
132 }
133 if (size !=
134 GNUNET_CRYPTO_aes_decrypt (in, (uint16_t) size, &n->decrypt_key, iv, out))
135 {
136 GNUNET_break (0);
137 return GNUNET_SYSERR;
138 }
139 GNUNET_STATISTICS_update (stats, gettext_noop ("# bytes decrypted"), size,
140 GNUNET_NO);
141#if DEBUG_CORE > 1
142 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
143 "Decrypted %u bytes from `%4s' using key %u, IV %u\n",
144 (unsigned int) size, GNUNET_i2s (&n->peer),
145 (unsigned int) n->decrypt_key.crc32, GNUNET_CRYPTO_crc32_n (iv,
146 sizeof
147 (*iv)));
148#endif
149 return GNUNET_OK;
150}
151
152
153
154/**
155 * We received an encrypted message. Decrypt, validate and
156 * pass on to the appropriate clients.
157 *
158 * @param n target of the message
159 * @param m encrypted message
160 * @param ats performance data
161 * @param ats_count number of entries in ats (excluding 0-termination)
162 */
163static void
164handle_encrypted_message (struct Neighbour *n, const struct EncryptedMessage *m,
165 const struct GNUNET_TRANSPORT_ATS_Information *ats,
166 uint32_t ats_count)
167{
168 size_t size = ntohs (m->header.size);
169 char buf[size];
170 struct EncryptedMessage *pt; /* plaintext */
171 GNUNET_HashCode ph;
172 uint32_t snum;
173 struct GNUNET_TIME_Absolute t;
174 struct GNUNET_CRYPTO_AesInitializationVector iv;
175 struct GNUNET_CRYPTO_AuthKey auth_key;
176
177#if DEBUG_CORE
178 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
179 "Core service receives `%s' request from `%4s'.\n",
180 "ENCRYPTED_MESSAGE", GNUNET_i2s (&n->peer));
181#endif
182 /* validate hash */
183 derive_auth_key (&auth_key, &n->decrypt_key, m->iv_seed,
184 n->decrypt_key_created);
185 GNUNET_CRYPTO_hmac (&auth_key, &m->sequence_number,
186 size - ENCRYPTED_HEADER_SIZE, &ph);
187#if DEBUG_HANDSHAKE
188 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
189 "Re-Authenticated %u bytes of ciphertext (`%u'): `%s'\n",
190 (unsigned int) size - ENCRYPTED_HEADER_SIZE,
191 GNUNET_CRYPTO_crc32_n (&m->sequence_number,
192 size - ENCRYPTED_HEADER_SIZE),
193 GNUNET_h2s (&ph));
194#endif
195
196 if (0 != memcmp (&ph, &m->hmac, sizeof (GNUNET_HashCode)))
197 {
198 /* checksum failed */
199 GNUNET_break_op (0);
200 return;
201 }
202 derive_iv (&iv, &n->decrypt_key, m->iv_seed, &my_identity);
203 /* decrypt */
204 if (GNUNET_OK !=
205 do_decrypt (n, &iv, &m->sequence_number, &buf[ENCRYPTED_HEADER_SIZE],
206 size - ENCRYPTED_HEADER_SIZE))
207 return;
208 pt = (struct EncryptedMessage *) buf;
209
210 /* validate sequence number */
211 snum = ntohl (pt->sequence_number);
212 if (n->last_sequence_number_received == snum)
213 {
214 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
215 "Received duplicate message, ignoring.\n");
216 /* duplicate, ignore */
217 GNUNET_STATISTICS_update (stats,
218 gettext_noop ("# bytes dropped (duplicates)"),
219 size, GNUNET_NO);
220 return;
221 }
222 if ((n->last_sequence_number_received > snum) &&
223 (n->last_sequence_number_received - snum > 32))
224 {
225 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
226 "Received ancient out of sequence message, ignoring.\n");
227 /* ancient out of sequence, ignore */
228 GNUNET_STATISTICS_update (stats,
229 gettext_noop
230 ("# bytes dropped (out of sequence)"), size,
231 GNUNET_NO);
232 return;
233 }
234 if (n->last_sequence_number_received > snum)
235 {
236 unsigned int rotbit = 1 << (n->last_sequence_number_received - snum - 1);
237
238 if ((n->last_packets_bitmap & rotbit) != 0)
239 {
240 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
241 "Received duplicate message, ignoring.\n");
242 GNUNET_STATISTICS_update (stats,
243 gettext_noop ("# bytes dropped (duplicates)"),
244 size, GNUNET_NO);
245 /* duplicate, ignore */
246 return;
247 }
248 n->last_packets_bitmap |= rotbit;
249 }
250 if (n->last_sequence_number_received < snum)
251 {
252 int shift = (snum - n->last_sequence_number_received);
253
254 if (shift >= 8 * sizeof (n->last_packets_bitmap))
255 n->last_packets_bitmap = 0;
256 else
257 n->last_packets_bitmap <<= shift;
258 n->last_sequence_number_received = snum;
259 }
260
261 /* check timestamp */
262 t = GNUNET_TIME_absolute_ntoh (pt->timestamp);
263 if (GNUNET_TIME_absolute_get_duration (t).rel_value >
264 MAX_MESSAGE_AGE.rel_value)
265 {
266 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
267 _("Message received far too old (%llu ms). Content ignored.\n"),
268 GNUNET_TIME_absolute_get_duration (t).rel_value);
269 GNUNET_STATISTICS_update (stats,
270 gettext_noop
271 ("# bytes dropped (ancient message)"), size,
272 GNUNET_NO);
273 return;
274 }
275
276 /* process decrypted message(s) */
277 if (n->bw_out_external_limit.value__ != pt->inbound_bw_limit.value__)
278 {
279#if DEBUG_CORE_SET_QUOTA
280 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
281 "Received %u b/s as new inbound limit for peer `%4s'\n",
282 (unsigned int) ntohl (pt->inbound_bw_limit.value__),
283 GNUNET_i2s (&n->peer));
284#endif
285 n->bw_out_external_limit = pt->inbound_bw_limit;
286 n->bw_out =
287 GNUNET_BANDWIDTH_value_min (n->bw_out_external_limit,
288 n->bw_out_internal_limit);
289 GNUNET_BANDWIDTH_tracker_update_quota (&n->available_send_window,
290 n->bw_out);
291 GNUNET_TRANSPORT_set_quota (transport, &n->peer, n->bw_in, n->bw_out);
292 }
293 n->last_activity = GNUNET_TIME_absolute_get ();
294 if (n->keep_alive_task != GNUNET_SCHEDULER_NO_TASK)
295 GNUNET_SCHEDULER_cancel (n->keep_alive_task);
296 n->keep_alive_task =
297 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide
298 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
299 2), &send_keep_alive, n);
300 GNUNET_STATISTICS_update (stats,
301 gettext_noop ("# bytes of payload decrypted"),
302 size - sizeof (struct EncryptedMessage), GNUNET_NO);
303 handle_peer_status_change (n);
304 update_neighbour_performance (n, ats, ats_count);
305 if (GNUNET_OK !=
306 GNUNET_SERVER_mst_receive (mst, n, &buf[sizeof (struct EncryptedMessage)],
307 size - sizeof (struct EncryptedMessage),
308 GNUNET_YES, GNUNET_NO))
309 GNUNET_break_op (0);
310}
311
312
313/**
314 * Wrapper around 'free_neighbour'; helper for 'cleaning_task'.
315 */
316static int
317free_neighbour_helper (void *cls, const GNUNET_HashCode * key, void *value)
318{
319 struct Neighbour *n = value;
320
321 free_neighbour (n);
322 return GNUNET_OK;
323}
324
325
326int
327GSC_CRYPTO_init ()
328{
329 char *keyfile;
330
331 if (GNUNET_OK !=
332 GNUNET_CONFIGURATION_get_value_filename (GSC_cfg, "GNUNETD", "HOSTKEY",
333 &keyfile))
334 {
335 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
336 _
337 ("Core service is lacking HOSTKEY configuration setting. Exiting.\n"));
338 return GNUNET_SYSERR;
339 }
340 my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
341 GNUNET_free (keyfile);
342 if (my_private_key == NULL)
343 {
344 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
345 _("Core service could not access hostkey. Exiting.\n"));
346 return GNUNET_SYSERR;
347 }
348 GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
349 GNUNET_CRYPTO_hash (&my_public_key, sizeof (my_public_key),
350 &my_identity.hashPubKey);
351
352 return GNUNET_OK;
353}
354
355
356void
357GSC_CRYPTO_done ()
358{
359 if (my_private_key != NULL)
360 GNUNET_CRYPTO_rsa_key_free (my_private_key);
361}
diff --git a/src/core/gnunet-service-core_extern.c b/src/core/gnunet-service-core_extern.c
new file mode 100644
index 000000000..0d2a3172b
--- /dev/null
+++ b/src/core/gnunet-service-core_extern.c
@@ -0,0 +1,39 @@
1/* code that should be moved outside of core/ entirely */
2
3/**
4 * Merge the given performance data with the data we currently
5 * track for the given neighbour.
6 *
7 * @param n neighbour
8 * @param ats new performance data
9 * @param ats_count number of records in ats
10 */
11static void
12update_neighbour_performance (struct Neighbour *n,
13 const struct GNUNET_TRANSPORT_ATS_Information
14 *ats, uint32_t ats_count)
15{
16 uint32_t i;
17 unsigned int j;
18
19 if (ats_count == 0)
20 return;
21 for (i = 0; i < ats_count; i++)
22 {
23 for (j = 0; j < n->ats_count; j++)
24 {
25 if (n->ats[j].type == ats[i].type)
26 {
27 n->ats[j].value = ats[i].value;
28 break;
29 }
30 }
31 if (j == n->ats_count)
32 {
33 GNUNET_array_append (n->ats, n->ats_count, ats[i]);
34 }
35 }
36}
37
38
39
diff --git a/src/core/gnunet-service-core_kx.c b/src/core/gnunet-service-core_kx.c
new file mode 100644
index 000000000..ac5b08d79
--- /dev/null
+++ b/src/core/gnunet-service-core_kx.c
@@ -0,0 +1,958 @@
1
2/**
3 * We're sending an (encrypted) PING to the other peer to check if he
4 * can decrypt. The other peer should respond with a PONG with the
5 * same content, except this time encrypted with the receiver's key.
6 */
7struct PingMessage
8{
9 /**
10 * Message type is CORE_PING.
11 */
12 struct GNUNET_MessageHeader header;
13
14 /**
15 * Seed for the IV
16 */
17 uint32_t iv_seed GNUNET_PACKED;
18
19 /**
20 * Intended target of the PING, used primarily to check
21 * that decryption actually worked.
22 */
23 struct GNUNET_PeerIdentity target;
24
25 /**
26 * Random number chosen to make reply harder.
27 */
28 uint32_t challenge GNUNET_PACKED;
29};
30
31
32
33/**
34 * Response to a PING. Includes data from the original PING
35 * plus initial bandwidth quota information.
36 */
37struct PongMessage
38{
39 /**
40 * Message type is CORE_PONG.
41 */
42 struct GNUNET_MessageHeader header;
43
44 /**
45 * Seed for the IV
46 */
47 uint32_t iv_seed GNUNET_PACKED;
48
49 /**
50 * Random number to make faking the reply harder. Must be
51 * first field after header (this is where we start to encrypt!).
52 */
53 uint32_t challenge GNUNET_PACKED;
54
55 /**
56 * Desired bandwidth (how much we should send to this
57 * peer / how much is the sender willing to receive).
58 */
59 struct GNUNET_BANDWIDTH_Value32NBO inbound_bw_limit;
60
61 /**
62 * Intended target of the PING, used primarily to check
63 * that decryption actually worked.
64 */
65 struct GNUNET_PeerIdentity target;
66};
67
68
69/**
70 * Message transmitted to set (or update) a session key.
71 */
72struct SetKeyMessage
73{
74
75 /**
76 * Message type is either CORE_SET_KEY.
77 */
78 struct GNUNET_MessageHeader header;
79
80 /**
81 * Status of the sender (should be in "enum PeerStateMachine"), nbo.
82 */
83 int32_t sender_status GNUNET_PACKED;
84
85 /**
86 * Purpose of the signature, will be
87 * GNUNET_SIGNATURE_PURPOSE_SET_KEY.
88 */
89 struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
90
91 /**
92 * At what time was this key created?
93 */
94 struct GNUNET_TIME_AbsoluteNBO creation_time;
95
96 /**
97 * The encrypted session key.
98 */
99 struct GNUNET_CRYPTO_RsaEncryptedData encrypted_key;
100
101 /**
102 * Who is the intended recipient?
103 */
104 struct GNUNET_PeerIdentity target;
105
106 /**
107 * Signature of the stuff above (starting at purpose).
108 */
109 struct GNUNET_CRYPTO_RsaSignature signature;
110
111};
112
113
114/**
115 * Handle to peerinfo service.
116 */
117static struct GNUNET_PEERINFO_Handle *peerinfo;
118
119
120
121/**
122 * We received a PING message. Validate and transmit
123 * PONG.
124 *
125 * @param n sender of the PING
126 * @param m the encrypted PING message itself
127 * @param ats performance data
128 * @param ats_count number of entries in ats (excluding 0-termination)
129 */
130static void
131handle_ping (struct Neighbour *n, const struct PingMessage *m,
132 const struct GNUNET_TRANSPORT_ATS_Information *ats,
133 uint32_t ats_count)
134{
135 struct PingMessage t;
136 struct PongMessage tx;
137 struct PongMessage *tp;
138 struct MessageEntry *me;
139 struct GNUNET_CRYPTO_AesInitializationVector iv;
140
141#if DEBUG_CORE
142 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
143 "Core service receives `%s' request from `%4s'.\n", "PING",
144 GNUNET_i2s (&n->peer));
145#endif
146 derive_iv (&iv, &n->decrypt_key, m->iv_seed, &my_identity);
147 if (GNUNET_OK !=
148 do_decrypt (n, &iv, &m->target, &t.target,
149 sizeof (struct PingMessage) - ((void *) &m->target -
150 (void *) m)))
151 return;
152#if DEBUG_HANDSHAKE
153 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
154 "Decrypted `%s' to `%4s' with challenge %u decrypted using key %u, IV %u (salt %u)\n",
155 "PING", GNUNET_i2s (&t.target), (unsigned int) t.challenge,
156 (unsigned int) n->decrypt_key.crc32, GNUNET_CRYPTO_crc32_n (&iv,
157 sizeof
158 (iv)),
159 m->iv_seed);
160#endif
161 GNUNET_STATISTICS_update (stats, gettext_noop ("# PING messages decrypted"),
162 1, GNUNET_NO);
163 if (0 !=
164 memcmp (&t.target, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
165 {
166 char sender[9];
167 char peer[9];
168
169 GNUNET_snprintf (sender, sizeof (sender), "%8s", GNUNET_i2s (&n->peer));
170 GNUNET_snprintf (peer, sizeof (peer), "%8s", GNUNET_i2s (&t.target));
171 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
172 _
173 ("Received PING from `%s' for different identity: I am `%s', PONG identity: `%s'\n"),
174 sender, GNUNET_i2s (&my_identity), peer);
175 GNUNET_break_op (0);
176 return;
177 }
178 update_neighbour_performance (n, ats, ats_count);
179 me = GNUNET_malloc (sizeof (struct MessageEntry) +
180 sizeof (struct PongMessage));
181 GNUNET_CONTAINER_DLL_insert_after (n->encrypted_head, n->encrypted_tail,
182 n->encrypted_tail, me);
183 me->deadline = GNUNET_TIME_relative_to_absolute (MAX_PONG_DELAY);
184 me->priority = PONG_PRIORITY;
185 me->size = sizeof (struct PongMessage);
186 tx.inbound_bw_limit = n->bw_in;
187 tx.challenge = t.challenge;
188 tx.target = t.target;
189 tp = (struct PongMessage *) &me[1];
190 tp->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_PONG);
191 tp->header.size = htons (sizeof (struct PongMessage));
192 tp->iv_seed =
193 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX);
194 derive_pong_iv (&iv, &n->encrypt_key, tp->iv_seed, t.challenge, &n->peer);
195 do_encrypt (n, &iv, &tx.challenge, &tp->challenge,
196 sizeof (struct PongMessage) - ((void *) &tp->challenge -
197 (void *) tp));
198 GNUNET_STATISTICS_update (stats, gettext_noop ("# PONG messages created"), 1,
199 GNUNET_NO);
200#if DEBUG_HANDSHAKE
201 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
202 "Encrypting `%s' with challenge %u using key %u, IV %u (salt %u)\n",
203 "PONG", (unsigned int) t.challenge,
204 (unsigned int) n->encrypt_key.crc32, GNUNET_CRYPTO_crc32_n (&iv,
205 sizeof
206 (iv)),
207 tp->iv_seed);
208#endif
209 /* trigger queue processing */
210 process_encrypted_neighbour_queue (n);
211}
212
213
214/**
215 * We received a PONG message. Validate and update our status.
216 *
217 * @param n sender of the PONG
218 * @param m the encrypted PONG message itself
219 * @param ats performance data
220 * @param ats_count number of entries in ats (excluding 0-termination)
221 */
222static void
223handle_pong (struct Neighbour *n, const struct PongMessage *m,
224 const struct GNUNET_TRANSPORT_ATS_Information *ats,
225 uint32_t ats_count)
226{
227 struct PongMessage t;
228 struct ConnectNotifyMessage *cnm;
229 struct GNUNET_CRYPTO_AesInitializationVector iv;
230 char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
231 struct GNUNET_TRANSPORT_ATS_Information *mats;
232 size_t size;
233
234#if DEBUG_HANDSHAKE
235 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
236 "Core service receives `%s' response from `%4s'.\n", "PONG",
237 GNUNET_i2s (&n->peer));
238#endif
239 /* mark as garbage, just to be sure */
240 memset (&t, 255, sizeof (t));
241 derive_pong_iv (&iv, &n->decrypt_key, m->iv_seed, n->ping_challenge,
242 &my_identity);
243 if (GNUNET_OK !=
244 do_decrypt (n, &iv, &m->challenge, &t.challenge,
245 sizeof (struct PongMessage) - ((void *) &m->challenge -
246 (void *) m)))
247 {
248 GNUNET_break_op (0);
249 return;
250 }
251 GNUNET_STATISTICS_update (stats, gettext_noop ("# PONG messages decrypted"),
252 1, GNUNET_NO);
253#if DEBUG_HANDSHAKE
254 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
255 "Decrypted `%s' from `%4s' with challenge %u using key %u, IV %u (salt %u)\n",
256 "PONG", GNUNET_i2s (&t.target), (unsigned int) t.challenge,
257 (unsigned int) n->decrypt_key.crc32, GNUNET_CRYPTO_crc32_n (&iv,
258 sizeof
259 (iv)),
260 m->iv_seed);
261#endif
262 if ((0 != memcmp (&t.target, &n->peer, sizeof (struct GNUNET_PeerIdentity)))
263 || (n->ping_challenge != t.challenge))
264 {
265 /* PONG malformed */
266#if DEBUG_CORE
267 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
268 "Received malformed `%s' wanted sender `%4s' with challenge %u\n",
269 "PONG", GNUNET_i2s (&n->peer),
270 (unsigned int) n->ping_challenge);
271 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
272 "Received malformed `%s' received from `%4s' with challenge %u\n",
273 "PONG", GNUNET_i2s (&t.target), (unsigned int) t.challenge);
274#endif
275 GNUNET_break_op (n->ping_challenge != t.challenge);
276 return;
277 }
278 switch (n->status)
279 {
280 case PEER_STATE_DOWN:
281 GNUNET_break (0); /* should be impossible */
282 return;
283 case PEER_STATE_KEY_SENT:
284 GNUNET_break (0); /* should be impossible, how did we decrypt? */
285 return;
286 case PEER_STATE_KEY_RECEIVED:
287 GNUNET_STATISTICS_update (stats,
288 gettext_noop
289 ("# Session keys confirmed via PONG"), 1,
290 GNUNET_NO);
291 n->status = PEER_STATE_KEY_CONFIRMED;
292 {
293 struct GNUNET_MessageHeader *hdr;
294
295 hdr = compute_type_map_message ();
296 send_type_map_to_neighbour (hdr, &n->peer.hashPubKey, n);
297 GNUNET_free (hdr);
298 }
299 if (n->bw_out_external_limit.value__ != t.inbound_bw_limit.value__)
300 {
301 n->bw_out_external_limit = t.inbound_bw_limit;
302 n->bw_out =
303 GNUNET_BANDWIDTH_value_min (n->bw_out_external_limit,
304 n->bw_out_internal_limit);
305 GNUNET_BANDWIDTH_tracker_update_quota (&n->available_send_window,
306 n->bw_out);
307 GNUNET_TRANSPORT_set_quota (transport, &n->peer, n->bw_in, n->bw_out);
308 }
309#if DEBUG_CORE
310 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
311 "Confirmed key via `%s' message for peer `%4s'\n", "PONG",
312 GNUNET_i2s (&n->peer));
313#endif
314 if (n->retry_set_key_task != GNUNET_SCHEDULER_NO_TASK)
315 {
316 GNUNET_SCHEDULER_cancel (n->retry_set_key_task);
317 n->retry_set_key_task = GNUNET_SCHEDULER_NO_TASK;
318 }
319 update_neighbour_performance (n, ats, ats_count);
320 size =
321 sizeof (struct ConnectNotifyMessage) +
322 (n->ats_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
323 if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
324 {
325 GNUNET_break (0);
326 /* recovery strategy: throw away performance data */
327 GNUNET_array_grow (n->ats, n->ats_count, 0);
328 size =
329 sizeof (struct PeerStatusNotifyMessage) +
330 n->ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
331 }
332 cnm = (struct ConnectNotifyMessage *) buf;
333 cnm->header.size = htons (size);
334 cnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT);
335 cnm->ats_count = htonl (n->ats_count);
336 cnm->peer = n->peer;
337 mats = &cnm->ats;
338 memcpy (mats, n->ats,
339 n->ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information));
340 mats[n->ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
341 mats[n->ats_count].value = htonl (0);
342 send_to_all_clients (&cnm->header, GNUNET_NO,
343 GNUNET_CORE_OPTION_SEND_CONNECT);
344 process_encrypted_neighbour_queue (n);
345 /* fall-through! */
346 case PEER_STATE_KEY_CONFIRMED:
347 n->last_activity = GNUNET_TIME_absolute_get ();
348 if (n->keep_alive_task != GNUNET_SCHEDULER_NO_TASK)
349 GNUNET_SCHEDULER_cancel (n->keep_alive_task);
350 n->keep_alive_task =
351 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide
352 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
353 2), &send_keep_alive, n);
354 handle_peer_status_change (n);
355 break;
356 default:
357 GNUNET_break (0);
358 break;
359 }
360}
361
362
363/**
364 * We received a SET_KEY message. Validate and update
365 * our key material and status.
366 *
367 * @param n the neighbour from which we received message m
368 * @param m the set key message we received
369 * @param ats performance data
370 * @param ats_count number of entries in ats (excluding 0-termination)
371 */
372static void
373handle_set_key (struct Neighbour *n, const struct SetKeyMessage *m,
374 const struct GNUNET_TRANSPORT_ATS_Information *ats,
375 uint32_t ats_count)
376{
377 struct SetKeyMessage *m_cpy;
378 struct GNUNET_TIME_Absolute t;
379 struct GNUNET_CRYPTO_AesSessionKey k;
380 struct PingMessage *ping;
381 struct PongMessage *pong;
382 enum PeerStateMachine sender_status;
383
384#if DEBUG_CORE
385 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
386 "Core service receives `%s' request from `%4s'.\n", "SET_KEY",
387 GNUNET_i2s (&n->peer));
388#endif
389 if (n->public_key == NULL)
390 {
391 if (n->pitr != NULL)
392 {
393#if DEBUG_CORE
394 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
395 "Ignoring `%s' message due to lack of public key for peer (still trying to obtain one).\n",
396 "SET_KEY");
397#endif
398 return;
399 }
400#if DEBUG_CORE
401 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
402 "Lacking public key for peer, trying to obtain one (handle_set_key).\n");
403#endif
404 m_cpy = GNUNET_malloc (sizeof (struct SetKeyMessage));
405 memcpy (m_cpy, m, sizeof (struct SetKeyMessage));
406 /* lookup n's public key, then try again */
407 GNUNET_assert (n->skm == NULL);
408 n->skm = m_cpy;
409 n->pitr =
410 GNUNET_PEERINFO_iterate (peerinfo, &n->peer, GNUNET_TIME_UNIT_MINUTES,
411 &process_hello_retry_handle_set_key, n);
412 GNUNET_STATISTICS_update (stats,
413 gettext_noop
414 ("# SET_KEY messages deferred (need public key)"),
415 1, GNUNET_NO);
416 return;
417 }
418 if (0 !=
419 memcmp (&m->target, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
420 {
421 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
422 _
423 ("Received `%s' message that was for `%s', not for me. Ignoring.\n"),
424 "SET_KEY", GNUNET_i2s (&m->target));
425 return;
426 }
427 if ((ntohl (m->purpose.size) !=
428 sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
429 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
430 sizeof (struct GNUNET_CRYPTO_RsaEncryptedData) +
431 sizeof (struct GNUNET_PeerIdentity)) ||
432 (GNUNET_OK !=
433 GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_SET_KEY, &m->purpose,
434 &m->signature, n->public_key)))
435 {
436 /* invalid signature */
437 GNUNET_break_op (0);
438 return;
439 }
440 t = GNUNET_TIME_absolute_ntoh (m->creation_time);
441 if (((n->status == PEER_STATE_KEY_RECEIVED) ||
442 (n->status == PEER_STATE_KEY_CONFIRMED)) &&
443 (t.abs_value < n->decrypt_key_created.abs_value))
444 {
445 /* this could rarely happen due to massive re-ordering of
446 * messages on the network level, but is most likely either
447 * a bug or some adversary messing with us. Report. */
448 GNUNET_break_op (0);
449 return;
450 }
451#if DEBUG_CORE
452 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Decrypting key material.\n");
453#endif
454 if ((GNUNET_CRYPTO_rsa_decrypt
455 (my_private_key, &m->encrypted_key, &k,
456 sizeof (struct GNUNET_CRYPTO_AesSessionKey)) !=
457 sizeof (struct GNUNET_CRYPTO_AesSessionKey)) ||
458 (GNUNET_OK != GNUNET_CRYPTO_aes_check_session_key (&k)))
459 {
460 /* failed to decrypt !? */
461 GNUNET_break_op (0);
462 return;
463 }
464 GNUNET_STATISTICS_update (stats,
465 gettext_noop ("# SET_KEY messages decrypted"), 1,
466 GNUNET_NO);
467 n->decrypt_key = k;
468 if (n->decrypt_key_created.abs_value != t.abs_value)
469 {
470 /* fresh key, reset sequence numbers */
471 n->last_sequence_number_received = 0;
472 n->last_packets_bitmap = 0;
473 n->decrypt_key_created = t;
474 }
475 update_neighbour_performance (n, ats, ats_count);
476 sender_status = (enum PeerStateMachine) ntohl (m->sender_status);
477 switch (n->status)
478 {
479 case PEER_STATE_DOWN:
480 n->status = PEER_STATE_KEY_RECEIVED;
481#if DEBUG_CORE
482 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
483 "Responding to `%s' with my own key.\n", "SET_KEY");
484#endif
485 send_key (n);
486 break;
487 case PEER_STATE_KEY_SENT:
488 case PEER_STATE_KEY_RECEIVED:
489 n->status = PEER_STATE_KEY_RECEIVED;
490 if ((sender_status != PEER_STATE_KEY_RECEIVED) &&
491 (sender_status != PEER_STATE_KEY_CONFIRMED))
492 {
493#if DEBUG_CORE
494 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
495 "Responding to `%s' with my own key (other peer has status %u).\n",
496 "SET_KEY", (unsigned int) sender_status);
497#endif
498 send_key (n);
499 }
500 break;
501 case PEER_STATE_KEY_CONFIRMED:
502 if ((sender_status != PEER_STATE_KEY_RECEIVED) &&
503 (sender_status != PEER_STATE_KEY_CONFIRMED))
504 {
505#if DEBUG_CORE
506 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
507 "Responding to `%s' with my own key (other peer has status %u), I was already fully up.\n",
508 "SET_KEY", (unsigned int) sender_status);
509#endif
510 send_key (n);
511 }
512 break;
513 default:
514 GNUNET_break (0);
515 break;
516 }
517 if (n->pending_ping != NULL)
518 {
519 ping = n->pending_ping;
520 n->pending_ping = NULL;
521 handle_ping (n, ping, NULL, 0);
522 GNUNET_free (ping);
523 }
524 if (n->pending_pong != NULL)
525 {
526 pong = n->pending_pong;
527 n->pending_pong = NULL;
528 handle_pong (n, pong, NULL, 0);
529 GNUNET_free (pong);
530 }
531}
532
533
534
535/**
536 * PEERINFO is giving us a HELLO for a peer. Add the public key to
537 * the neighbour's struct and retry send_key. Or, if we did not get a
538 * HELLO, just do nothing.
539 *
540 * @param cls the 'struct Neighbour' to retry sending the key for
541 * @param peer the peer for which this is the HELLO
542 * @param hello HELLO message of that peer
543 * @param err_msg NULL if successful, otherwise contains error message
544 */
545static void
546process_hello_retry_send_key (void *cls, const struct GNUNET_PeerIdentity *peer,
547 const struct GNUNET_HELLO_Message *hello,
548 const char *err_msg)
549{
550 struct Neighbour *n = cls;
551
552 if (err_msg != NULL)
553 {
554 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
555 _("Error in communication with PEERINFO service\n"));
556 /* return; */
557 }
558
559 if (peer == NULL)
560 {
561#if DEBUG_CORE
562 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Entered `%s' and `%s' is NULL!\n",
563 "process_hello_retry_send_key", "peer");
564#endif
565 n->pitr = NULL;
566 if (n->public_key != NULL)
567 {
568 if (n->retry_set_key_task != GNUNET_SCHEDULER_NO_TASK)
569 {
570 GNUNET_SCHEDULER_cancel (n->retry_set_key_task);
571 n->retry_set_key_task = GNUNET_SCHEDULER_NO_TASK;
572 }
573 GNUNET_STATISTICS_update (stats,
574 gettext_noop
575 ("# SET_KEY messages deferred (need public key)"),
576 -1, GNUNET_NO);
577 send_key (n);
578 }
579 else
580 {
581#if DEBUG_CORE
582 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
583 "Failed to obtain public key for peer `%4s', delaying processing of SET_KEY\n",
584 GNUNET_i2s (&n->peer));
585#endif
586 GNUNET_STATISTICS_update (stats,
587 gettext_noop
588 ("# Delayed connecting due to lack of public key"),
589 1, GNUNET_NO);
590 if (GNUNET_SCHEDULER_NO_TASK == n->retry_set_key_task)
591 n->retry_set_key_task =
592 GNUNET_SCHEDULER_add_delayed (n->set_key_retry_frequency,
593 &set_key_retry_task, n);
594 }
595 return;
596 }
597
598#if DEBUG_CORE
599 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Entered `%s' for peer `%4s'\n",
600 "process_hello_retry_send_key", GNUNET_i2s (peer));
601#endif
602 if (n->public_key != NULL)
603 {
604 /* already have public key, why are we here? */
605 GNUNET_break (0);
606 return;
607 }
608
609#if DEBUG_CORE
610 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
611 "Received new `%s' message for `%4s', initiating key exchange.\n",
612 "HELLO", GNUNET_i2s (peer));
613#endif
614 n->public_key =
615 GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
616 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, n->public_key))
617 {
618 GNUNET_STATISTICS_update (stats,
619 gettext_noop
620 ("# Error extracting public key from HELLO"), 1,
621 GNUNET_NO);
622 GNUNET_free (n->public_key);
623 n->public_key = NULL;
624#if DEBUG_CORE
625 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
626 "GNUNET_HELLO_get_key returned awfully\n");
627#endif
628 return;
629 }
630}
631
632
633/**
634 * Send our key (and encrypted PING) to the other peer.
635 *
636 * @param n the other peer
637 */
638static void
639send_key (struct Neighbour *n)
640{
641 struct MessageEntry *pos;
642 struct SetKeyMessage *sm;
643 struct MessageEntry *me;
644 struct PingMessage pp;
645 struct PingMessage *pm;
646 struct GNUNET_CRYPTO_AesInitializationVector iv;
647
648 if (n->retry_set_key_task != GNUNET_SCHEDULER_NO_TASK)
649 {
650 GNUNET_SCHEDULER_cancel (n->retry_set_key_task);
651 n->retry_set_key_task = GNUNET_SCHEDULER_NO_TASK;
652 }
653 if (n->pitr != NULL)
654 {
655#if DEBUG_CORE
656 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
657 "Key exchange in progress with `%4s'.\n",
658 GNUNET_i2s (&n->peer));
659#endif
660 return; /* already in progress */
661 }
662 if (GNUNET_YES != n->is_connected)
663 {
664 GNUNET_STATISTICS_update (stats,
665 gettext_noop
666 ("# Asking transport to connect (for SET_KEY)"),
667 1, GNUNET_NO);
668 GNUNET_TRANSPORT_try_connect (transport, &n->peer);
669 return;
670 }
671#if DEBUG_CORE
672 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
673 "Asked to perform key exchange with `%4s'.\n",
674 GNUNET_i2s (&n->peer));
675#endif
676 if (n->public_key == NULL)
677 {
678 /* lookup n's public key, then try again */
679#if DEBUG_CORE
680 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
681 "Lacking public key for `%4s', trying to obtain one (send_key).\n",
682 GNUNET_i2s (&n->peer));
683#endif
684 GNUNET_assert (n->pitr == NULL);
685 n->pitr =
686 GNUNET_PEERINFO_iterate (peerinfo, &n->peer,
687 GNUNET_TIME_relative_multiply
688 (GNUNET_TIME_UNIT_SECONDS, 20),
689 &process_hello_retry_send_key, n);
690 return;
691 }
692 pos = n->encrypted_head;
693 while (pos != NULL)
694 {
695 if (GNUNET_YES == pos->is_setkey)
696 {
697 if (pos->sender_status == n->status)
698 {
699#if DEBUG_CORE
700 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
701 "`%s' message for `%4s' queued already\n", "SET_KEY",
702 GNUNET_i2s (&n->peer));
703#endif
704 goto trigger_processing;
705 }
706 GNUNET_CONTAINER_DLL_remove (n->encrypted_head, n->encrypted_tail, pos);
707 GNUNET_free (pos);
708#if DEBUG_CORE
709 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
710 "Removing queued `%s' message for `%4s', will create a new one\n",
711 "SET_KEY", GNUNET_i2s (&n->peer));
712#endif
713 break;
714 }
715 pos = pos->next;
716 }
717
718 /* update status */
719 switch (n->status)
720 {
721 case PEER_STATE_DOWN:
722 n->status = PEER_STATE_KEY_SENT;
723 break;
724 case PEER_STATE_KEY_SENT:
725 break;
726 case PEER_STATE_KEY_RECEIVED:
727 break;
728 case PEER_STATE_KEY_CONFIRMED:
729 break;
730 default:
731 GNUNET_break (0);
732 break;
733 }
734
735
736 /* first, set key message */
737 me = GNUNET_malloc (sizeof (struct MessageEntry) +
738 sizeof (struct SetKeyMessage) +
739 sizeof (struct PingMessage));
740 me->deadline = GNUNET_TIME_relative_to_absolute (MAX_SET_KEY_DELAY);
741 me->priority = SET_KEY_PRIORITY;
742 me->size = sizeof (struct SetKeyMessage) + sizeof (struct PingMessage);
743 me->is_setkey = GNUNET_YES;
744 me->got_slack = GNUNET_YES; /* do not defer this one! */
745 me->sender_status = n->status;
746 GNUNET_CONTAINER_DLL_insert_after (n->encrypted_head, n->encrypted_tail,
747 n->encrypted_tail, me);
748 sm = (struct SetKeyMessage *) &me[1];
749 sm->header.size = htons (sizeof (struct SetKeyMessage));
750 sm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_SET_KEY);
751 sm->sender_status =
752 htonl ((int32_t)
753 ((n->status ==
754 PEER_STATE_DOWN) ? PEER_STATE_KEY_SENT : n->status));
755 sm->purpose.size =
756 htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
757 sizeof (struct GNUNET_TIME_AbsoluteNBO) +
758 sizeof (struct GNUNET_CRYPTO_RsaEncryptedData) +
759 sizeof (struct GNUNET_PeerIdentity));
760 sm->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_SET_KEY);
761 sm->creation_time = GNUNET_TIME_absolute_hton (n->encrypt_key_created);
762 sm->target = n->peer;
763 GNUNET_assert (GNUNET_OK ==
764 GNUNET_CRYPTO_rsa_encrypt (&n->encrypt_key,
765 sizeof (struct
766 GNUNET_CRYPTO_AesSessionKey),
767 n->public_key, &sm->encrypted_key));
768 GNUNET_assert (GNUNET_OK ==
769 GNUNET_CRYPTO_rsa_sign (my_private_key, &sm->purpose,
770 &sm->signature));
771 pm = (struct PingMessage *) &sm[1];
772 pm->header.size = htons (sizeof (struct PingMessage));
773 pm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_PING);
774 pm->iv_seed =
775 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX);
776 derive_iv (&iv, &n->encrypt_key, pm->iv_seed, &n->peer);
777 pp.challenge = n->ping_challenge;
778 pp.target = n->peer;
779#if DEBUG_HANDSHAKE
780 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
781 "Encrypting `%s' and `%s' messages with challenge %u for `%4s' using key %u, IV %u (salt %u).\n",
782 "SET_KEY", "PING", (unsigned int) n->ping_challenge,
783 GNUNET_i2s (&n->peer), (unsigned int) n->encrypt_key.crc32,
784 GNUNET_CRYPTO_crc32_n (&iv, sizeof (iv)), pm->iv_seed);
785#endif
786 do_encrypt (n, &iv, &pp.target, &pm->target,
787 sizeof (struct PingMessage) - ((void *) &pm->target -
788 (void *) pm));
789 GNUNET_STATISTICS_update (stats,
790 gettext_noop
791 ("# SET_KEY and PING messages created"), 1,
792 GNUNET_NO);
793#if DEBUG_CORE
794 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
795 "Have %llu ms left for `%s' transmission.\n",
796 (unsigned long long)
797 GNUNET_TIME_absolute_get_remaining (me->deadline).rel_value,
798 "SET_KEY");
799#endif
800trigger_processing:
801 /* trigger queue processing */
802 process_encrypted_neighbour_queue (n);
803 if ((n->status != PEER_STATE_KEY_CONFIRMED) &&
804 (GNUNET_SCHEDULER_NO_TASK == n->retry_set_key_task))
805 n->retry_set_key_task =
806 GNUNET_SCHEDULER_add_delayed (n->set_key_retry_frequency,
807 &set_key_retry_task, n);
808}
809
810
811/**
812 * We received a SET_KEY message. Validate and update
813 * our key material and status.
814 *
815 * @param n the neighbour from which we received message m
816 * @param m the set key message we received
817 * @param ats performance data
818 * @param ats_count number of entries in ats (excluding 0-termination)
819 */
820static void
821handle_set_key (struct Neighbour *n, const struct SetKeyMessage *m,
822 const struct GNUNET_TRANSPORT_ATS_Information *ats,
823 uint32_t ats_count);
824
825
826
827/**
828 * PEERINFO is giving us a HELLO for a peer. Add the public key to
829 * the neighbour's struct and retry handling the set_key message. Or,
830 * if we did not get a HELLO, just free the set key message.
831 *
832 * @param cls pointer to the set key message
833 * @param peer the peer for which this is the HELLO
834 * @param hello HELLO message of that peer
835 * @param err_msg NULL if successful, otherwise contains error message
836 */
837static void
838process_hello_retry_handle_set_key (void *cls,
839 const struct GNUNET_PeerIdentity *peer,
840 const struct GNUNET_HELLO_Message *hello,
841 const char *err_msg)
842{
843 struct Neighbour *n = cls;
844 struct SetKeyMessage *sm = n->skm;
845
846 if (err_msg != NULL)
847 {
848 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
849 _("Error in communication with PEERINFO service\n"));
850 /* return; */
851 }
852
853 if (peer == NULL)
854 {
855 n->skm = NULL;
856 n->pitr = NULL;
857 if (n->public_key != NULL)
858 {
859#if DEBUG_CORE
860 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
861 "Received `%s' for `%4s', continuing processing of `%s' message.\n",
862 "HELLO", GNUNET_i2s (&n->peer), "SET_KEY");
863#endif
864 handle_set_key (n, sm, NULL, 0);
865 }
866 else
867 {
868 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
869 _
870 ("Ignoring `%s' message due to lack of public key for peer `%4s' (failed to obtain one).\n"),
871 "SET_KEY", GNUNET_i2s (&n->peer));
872 }
873 GNUNET_free (sm);
874 return;
875 }
876 if (n->public_key != NULL)
877 return; /* multiple HELLOs match!? */
878 n->public_key =
879 GNUNET_malloc (sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
880 if (GNUNET_OK != GNUNET_HELLO_get_key (hello, n->public_key))
881 {
882 GNUNET_break_op (0);
883 GNUNET_free (n->public_key);
884 n->public_key = NULL;
885 }
886}
887
888
889
890/**
891 * Task that will retry "send_key" if our previous attempt failed
892 * to yield a PONG.
893 */
894static void
895set_key_retry_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
896{
897 struct Neighbour *n = cls;
898
899#if DEBUG_CORE
900 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Retrying key transmission to `%4s'\n",
901 GNUNET_i2s (&n->peer));
902#endif
903 n->retry_set_key_task = GNUNET_SCHEDULER_NO_TASK;
904 n->set_key_retry_frequency =
905 GNUNET_TIME_relative_multiply (n->set_key_retry_frequency, 2);
906 send_key (n);
907}
908
909
910struct GSC_KeyExchangeInfo *
911GSC_KX_start (const struct GNUNET_PeerIdentity *pid)
912{
913 struct GSC_KeyExchangeInfo *kx;
914
915 kx = NULL;
916 return kx;
917}
918
919
920void
921GSC_KX_stop (struct GSC_KeyExchangeInfo *kx)
922{
923 if (kx->pitr != NULL)
924 {
925 GNUNET_PEERINFO_iterate_cancel (kx->pitr);
926 kx->pitr = NULL;
927 }
928 if (kx->retry_set_key_task != GNUNET_SCHEDULER_NO_TASK)
929 GNUNET_SCHEDULER_cancel (kx->retry_set_key_task);
930 GNUNET_free_non_null (kx->public_key);
931 GNUNET_free (kx);
932}
933
934
935int
936GSC_KX_init ()
937{
938 peerinfo = GNUNET_PEERINFO_connect (cfg);
939 if (NULL == peerinfo)
940 {
941 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
942 _("Could not access PEERINFO service. Exiting.\n"));
943 return GNUNET_SYSERR;
944 }
945 return GNUNET_OK;
946}
947
948
949void
950GSC_KX_done ()
951{
952 if (peerinfo != NULL)
953 {
954 GNUNET_PEERINFO_disconnect (peerinfo);
955 peerinfo = NULL;
956 }
957
958}
diff --git a/src/core/gnunet-service-core_kx.h b/src/core/gnunet-service-core_kx.h
new file mode 100644
index 000000000..f4f1daaeb
--- /dev/null
+++ b/src/core/gnunet-service-core_kx.h
@@ -0,0 +1,77 @@
1struct GSC_KeyExchangeInfo
2{
3
4 /**
5 * SetKeyMessage to transmit, NULL if we are not currently trying
6 * to send one.
7 */
8 struct SetKeyMessage *skm;
9
10 /**
11 * Non-NULL if we are currently looking up HELLOs for this peer.
12 * for this peer.
13 */
14 struct GNUNET_PEERINFO_IteratorContext *pitr;
15
16 /**
17 * Public key of the neighbour, NULL if we don't have it yet.
18 */
19 struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded *public_key;
20
21 /**
22 * We received a PING message before we got the "public_key"
23 * (or the SET_KEY). We keep it here until we have a key
24 * to decrypt it. NULL if no PING is pending.
25 */
26 struct PingMessage *pending_ping;
27
28 /**
29 * We received a PONG message before we got the "public_key"
30 * (or the SET_KEY). We keep it here until we have a key
31 * to decrypt it. NULL if no PONG is pending.
32 */
33 struct PongMessage *pending_pong;
34
35 /**
36 * Key we use to encrypt our messages for the other peer
37 * (initialized by us when we do the handshake).
38 */
39 struct GNUNET_CRYPTO_AesSessionKey encrypt_key;
40
41 /**
42 * Key we use to decrypt messages from the other peer
43 * (given to us by the other peer during the handshake).
44 */
45 struct GNUNET_CRYPTO_AesSessionKey decrypt_key;
46
47 /**
48 * At what time did we generate our encryption key?
49 */
50 struct GNUNET_TIME_Absolute encrypt_key_created;
51
52 /**
53 * At what time did the other peer generate the decryption key?
54 */
55 struct GNUNET_TIME_Absolute decrypt_key_created;
56
57 /**
58 * At what frequency are we currently re-trying SET_KEY messages?
59 */
60 struct GNUNET_TIME_Relative set_key_retry_frequency;
61
62 /**
63 * ID of task used for re-trying SET_KEY and PING message.
64 */
65 GNUNET_SCHEDULER_TaskIdentifier retry_set_key_task;
66
67 /**
68 * What was our PING challenge number (for this peer)?
69 */
70 uint32_t ping_challenge;
71
72 /**
73 * What is our connection status?
74 */
75 enum PeerStateMachine status;
76
77};
diff --git a/src/core/gnunet-service-core_neighbours.c b/src/core/gnunet-service-core_neighbours.c
new file mode 100644
index 000000000..12d002da8
--- /dev/null
+++ b/src/core/gnunet-service-core_neighbours.c
@@ -0,0 +1,617 @@
1/*
2 This file is part of GNUnet.
3 (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors)
4
5 GNUnet is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published
7 by the Free Software Foundation; either version 3, or (at your
8 option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with GNUnet; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 Boston, MA 02111-1307, USA.
19*/
20
21/**
22 * @file core/gnunet-service-core_neighbours.c
23 * @brief code for managing low-level 'plaintext' connections with transport (key exchange may or may not be done yet)
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_transport_service.h"
29#include "gnunet_service_core.h"
30#include "gnunet_service_core-neighbours.h"
31#include "gnunet_service_core-kx.h"
32
33
34/**
35 * Message ready for transmission via transport service. This struct
36 * is followed by the actual content of the message.
37 */
38struct MessageEntry
39{
40
41 /**
42 * We keep messages in a doubly linked list.
43 */
44 struct MessageEntry *next;
45
46 /**
47 * We keep messages in a doubly linked list.
48 */
49 struct MessageEntry *prev;
50
51 /**
52 * By when are we supposed to transmit this message?
53 */
54 struct GNUNET_TIME_Absolute deadline;
55
56 /**
57 * How long is the message? (number of bytes following the "struct
58 * MessageEntry", but not including the size of "struct
59 * MessageEntry" itself!)
60 */
61 size_t size;
62
63};
64
65
66/**
67 * Data kept per transport-connected peer.
68 */
69struct Neighbour
70{
71
72 /**
73 * Head of the batched message queue (already ordered, transmit
74 * starting with the head).
75 */
76 struct MessageEntry *message_head;
77
78 /**
79 * Tail of the batched message queue (already ordered, append new
80 * messages to tail).
81 */
82 struct MessageEntry *message_tail;
83
84 /**
85 * Handle for pending requests for transmission to this peer
86 * with the transport service. NULL if no request is pending.
87 */
88 struct GNUNET_TRANSPORT_TransmitHandle *th;
89
90 /**
91 * Information about the key exchange with the other peer.
92 */
93 struct GSC_KeyExchangeInfo *kxinfo;
94
95 /**
96 * Identity of the other peer.
97 */
98 struct GNUNET_PeerIdentity peer;
99
100 /**
101 * ID of task used for re-trying plaintext scheduling.
102 */
103 GNUNET_SCHEDULER_TaskIdentifier retry_plaintext_task;
104
105 /**
106 * Tracking bandwidth for sending to this peer.
107 */
108 struct GNUNET_BANDWIDTH_Tracker available_send_window;
109
110 /**
111 * Tracking bandwidth for sending to this peer.
112 */
113 struct GNUNET_BANDWIDTH_Tracker available_recv_window;
114
115
116};
117
118
119/**
120 * Map of peer identities to 'struct Neighbour'.
121 */
122static struct GNUNET_CONTAINER_MultiHashMap *neighbours;
123
124/**
125 * Transport service.
126 */
127static struct GNUNET_TRANSPORT_Handle *transport;
128
129
130
131/**
132 * Find the entry for the given neighbour.
133 *
134 * @param peer identity of the neighbour
135 * @return NULL if we are not connected, otherwise the
136 * neighbour's entry.
137 */
138static struct Neighbour *
139find_neighbour (const struct GNUNET_PeerIdentity *peer)
140{
141 return GNUNET_CONTAINER_multihashmap_get (neighbours, &peer->hashPubKey);
142}
143
144
145/**
146 * Free the given entry for the neighbour.
147 *
148 * @param n neighbour to free
149 */
150static void
151free_neighbour (struct Neighbour *n)
152{
153 struct MessageEntry *m;
154
155#if DEBUG_CORE
156 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
157 "Destroying neighbour entry for peer `%4s'\n",
158 GNUNET_i2s (&n->peer));
159#endif
160 while (NULL != (m = n->message_head))
161 {
162 GNUNET_CONTAINER_DLL_remove (n->message_head, n->message_tail, m);
163 GNUNET_free (m);
164 }
165 if (NULL != n->th)
166 {
167 GNUNET_TRANSPORT_notify_transmit_ready_cancel (n->th);
168 n->th = NULL;
169 }
170 if (NULL != n->kx)
171 {
172 GSC_KX_stop (n->kx);
173 n->kx = NULL;
174 }
175 if (n->retry_plaintext_task != GNUNET_SCHEDULER_NO_TASK)
176 {
177 GNUNET_SCHEDULER_cancel (n->retry_plaintext_task);
178 n->retry_plaintext_task = GNUNET_SCHEDULER_NO_TASK;
179 }
180 GNUNET_assert (GNUNET_OK ==
181 GNUNET_CONTAINER_multihashmap_remove (neighbours,
182 &n->peer.hashPubKey, n));
183 GNUNET_STATISTICS_set (stats, gettext_noop ("# neighbour entries allocated"),
184 GNUNET_CONTAINER_multihashmap_size (neighbours),
185 GNUNET_NO);
186 GNUNET_free (n);
187}
188
189
190/**
191 * Check if we have encrypted messages for the specified neighbour
192 * pending, and if so, check with the transport about sending them
193 * out.
194 *
195 * @param n neighbour to check.
196 */
197static void
198process_queue (struct Neighbour *n);
199
200
201/**
202 * Function called when the transport service is ready to receive a
203 * message for the respective peer
204 *
205 * @param cls neighbour to use message from
206 * @param size number of bytes we can transmit
207 * @param buf where to copy the message
208 * @return number of bytes transmitted
209 */
210static size_t
211transmit_ready (void *cls, size_t size, void *buf)
212{
213 struct Neighbour *n = cls;
214 struct MessageEntry *m;
215 size_t ret;
216 char *cbuf;
217
218 n->th = NULL;
219 m = n->message_head;
220 if (m == NULL)
221 {
222#if DEBUG_CORE
223 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
224 "Encrypted message queue empty, no messages added to buffer for `%4s'\n",
225 GNUNET_i2s (&n->peer));
226#endif
227 return 0;
228 }
229 GNUNET_CONTAINER_DLL_remove (n->encrypted_head, n->encrypted_tail, m);
230 if (buf == NULL)
231 {
232#if DEBUG_CORE
233 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
234 "Transmission of message of type %u and size %u failed\n",
235 (unsigned int)
236 ntohs (((struct GNUNET_MessageHeader *) &m[1])->type),
237 (unsigned int) m->size);
238#endif
239 GNUNET_free (m);
240 process_queue (n);
241 return 0;
242 }
243 ret = 0;
244 cbuf = buf;
245 GNUNET_assert (size >= m->size);
246 memcpy (cbuf, &m[1], m->size);
247 ret = m->size;
248 GNUNET_BANDWIDTH_tracker_consume (&n->available_send_window, m->size);
249#if DEBUG_CORE
250 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
251 "Copied message of type %u and size %u into transport buffer for `%4s'\n",
252 (unsigned int)
253 ntohs (((struct GNUNET_MessageHeader *) &m[1])->type),
254 (unsigned int) ret, GNUNET_i2s (&n->peer));
255#endif
256 GNUNET_free (m);
257 process_queue (n);
258 GNUNET_STATISTICS_update (GSC_stats,
259 gettext_noop
260 ("# encrypted bytes given to transport"), ret,
261 GNUNET_NO);
262 return ret;
263}
264
265
266/**
267 * Check if we have messages for the specified neighbour pending, and
268 * if so, check with the transport about sending them out.
269 *
270 * @param n neighbour to check.
271 */
272static void
273process_queue (struct Neighbour *n)
274{
275 struct MessageEntry *m;
276
277 if (n->th != NULL)
278 return; /* request already pending */
279 m = n->message_head;
280 if (m == NULL)
281 return;
282#if DEBUG_CORE > 1
283 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
284 "Asking transport for transmission of %u bytes to `%4s' in next %llu ms\n",
285 (unsigned int) m->size, GNUNET_i2s (&n->peer),
286 (unsigned long long)
287 GNUNET_TIME_absolute_get_remaining (m->deadline).rel_value);
288#endif
289 n->th =
290 GNUNET_TRANSPORT_notify_transmit_ready (transport, &n->peer, m->size,
291 m->priority,
292 GNUNET_TIME_absolute_get_remaining
293 (m->deadline),
294 &transmit_ready,
295 n);
296 if (n->th != NULL)
297 return;
298 /* message request too large or duplicate request */
299 GNUNET_break (0);
300 /* discard encrypted message */
301 GNUNET_CONTAINER_DLL_remove (n->encrypted_head, n->encrypted_tail, m);
302 GNUNET_free (m);
303 process_queue (n);
304}
305
306
307
308/**
309 * Function called by transport to notify us that
310 * a peer connected to us (on the network level).
311 *
312 * @param cls closure
313 * @param peer the peer that connected
314 * @param ats performance data
315 * @param ats_count number of entries in ats (excluding 0-termination)
316 */
317static void
318handle_transport_notify_connect (void *cls,
319 const struct GNUNET_PeerIdentity *peer,
320 const struct GNUNET_TRANSPORT_ATS_Information
321 *ats, uint32_t ats_count)
322{
323 struct Neighbour *n;
324
325 if (0 == memcmp (peer, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
326 {
327 GNUNET_break (0);
328 return;
329 }
330 n = find_neighbour (peer);
331 if (n != NULL)
332 {
333 /* duplicate connect notification!? */
334 GNUNET_break (0);
335 return;
336 }
337#if DEBUG_CORE
338 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received connection from `%4s'.\n",
339 GNUNET_i2s (peer));
340#endif
341 n = GNUNET_malloc (sizeof (struct Neighbour));
342 n->peer = *pid;
343 GNUNET_BANDWIDTH_tracker_init (&n->available_send_window,
344 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
345 MAX_WINDOW_TIME_S);
346 GNUNET_BANDWIDTH_tracker_init (&n->available_recv_window,
347 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
348 MAX_WINDOW_TIME_S);
349 GNUNET_assert (GNUNET_OK ==
350 GNUNET_CONTAINER_multihashmap_put (neighbours,
351 &n->peer.hashPubKey, n,
352 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
353 GNUNET_STATISTICS_set (stats, gettext_noop ("# neighbour entries allocated"),
354 GNUNET_CONTAINER_multihashmap_size (neighbours),
355 GNUNET_NO);
356 GNUNET_TRANSPORT_set_quota (transport, peer,
357 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
358 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT);
359 n->kx = GSC_KX_start (pid);
360}
361
362
363/**
364 * Function called by transport telling us that a peer
365 * disconnected.
366 *
367 * @param cls closure
368 * @param peer the peer that disconnected
369 */
370static void
371handle_transport_notify_disconnect (void *cls,
372 const struct GNUNET_PeerIdentity *peer)
373{
374 struct Neighbour *n;
375
376#if DEBUG_CORE
377 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
378 "Peer `%4s' disconnected from us; received notification from transport.\n",
379 GNUNET_i2s (peer));
380#endif
381 n = find_neighbour (peer);
382 if (n == NULL)
383 {
384 GNUNET_break (0);
385 return;
386 }
387 free_neighbour (n);
388}
389
390
391/**
392 * Function called by the transport for each received message.
393 *
394 * @param cls closure
395 * @param peer (claimed) identity of the other peer
396 * @param message the message
397 * @param ats performance data
398 * @param ats_count number of entries in ats (excluding 0-termination)
399 */
400static void
401handle_transport_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
402 const struct GNUNET_MessageHeader *message,
403 const struct GNUNET_TRANSPORT_ATS_Information *ats,
404 uint32_t ats_count)
405{
406 struct Neighbour *n;
407 struct GNUNET_TIME_Absolute now;
408 int up;
409 uint16_t type;
410 uint16_t size;
411 int changed;
412
413#if DEBUG_CORE > 1
414 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
415 "Received message of type %u from `%4s', demultiplexing.\n",
416 (unsigned int) ntohs (message->type), GNUNET_i2s (peer));
417#endif
418 if (0 == memcmp (peer, &my_identity, sizeof (struct GNUNET_PeerIdentity)))
419 {
420 GNUNET_break (0);
421 return;
422 }
423 n = find_neighbour (peer);
424 if (n == NULL)
425 {
426 /* received message from peer that is not connected!? */
427 GNUNET_break (0);
428 return;
429 }
430
431
432 changed = GNUNET_NO;
433 up = (n->status == PEER_STATE_KEY_CONFIRMED);
434 type = ntohs (message->type);
435 size = ntohs (message->size);
436 switch (type)
437 {
438 case GNUNET_MESSAGE_TYPE_CORE_SET_KEY:
439 if (size != sizeof (struct SetKeyMessage))
440 {
441 GNUNET_break_op (0);
442 return;
443 }
444 GNUNET_STATISTICS_update (stats, gettext_noop ("# session keys received"),
445 1, GNUNET_NO);
446 handle_set_key (n, (const struct SetKeyMessage *) message, ats, ats_count);
447 break;
448 case GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE:
449 if (size <
450 sizeof (struct EncryptedMessage) + sizeof (struct GNUNET_MessageHeader))
451 {
452 GNUNET_break_op (0);
453 return;
454 }
455 if ((n->status != PEER_STATE_KEY_RECEIVED) &&
456 (n->status != PEER_STATE_KEY_CONFIRMED))
457 {
458 GNUNET_STATISTICS_update (stats,
459 gettext_noop
460 ("# failed to decrypt message (no session key)"),
461 1, GNUNET_NO);
462 send_key (n);
463 return;
464 }
465 handle_encrypted_message (n, (const struct EncryptedMessage *) message, ats,
466 ats_count);
467 break;
468 case GNUNET_MESSAGE_TYPE_CORE_PING:
469 if (size != sizeof (struct PingMessage))
470 {
471 GNUNET_break_op (0);
472 return;
473 }
474 GNUNET_STATISTICS_update (stats, gettext_noop ("# PING messages received"),
475 1, GNUNET_NO);
476 if ((n->status != PEER_STATE_KEY_RECEIVED) &&
477 (n->status != PEER_STATE_KEY_CONFIRMED))
478 {
479#if DEBUG_CORE > 1
480 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
481 "Core service receives `%s' request from `%4s' but have not processed key; marking as pending.\n",
482 "PING", GNUNET_i2s (&n->peer));
483#endif
484 GNUNET_free_non_null (n->pending_ping);
485 n->pending_ping = GNUNET_malloc (sizeof (struct PingMessage));
486 memcpy (n->pending_ping, message, sizeof (struct PingMessage));
487 return;
488 }
489 handle_ping (n, (const struct PingMessage *) message, ats, ats_count);
490 break;
491 case GNUNET_MESSAGE_TYPE_CORE_PONG:
492 if (size != sizeof (struct PongMessage))
493 {
494 GNUNET_break_op (0);
495 return;
496 }
497 GNUNET_STATISTICS_update (stats, gettext_noop ("# PONG messages received"),
498 1, GNUNET_NO);
499 if ((n->status != PEER_STATE_KEY_RECEIVED) &&
500 (n->status != PEER_STATE_KEY_CONFIRMED))
501 {
502#if DEBUG_CORE > 1
503 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
504 "Core service receives `%s' request from `%4s' but have not processed key; marking as pending.\n",
505 "PONG", GNUNET_i2s (&n->peer));
506#endif
507 GNUNET_free_non_null (n->pending_pong);
508 n->pending_pong = GNUNET_malloc (sizeof (struct PongMessage));
509 memcpy (n->pending_pong, message, sizeof (struct PongMessage));
510 return;
511 }
512 handle_pong (n, (const struct PongMessage *) message, ats, ats_count);
513 break;
514 default:
515 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
516 _("Unsupported message of type %u received.\n"),
517 (unsigned int) type);
518 return;
519 }
520 if (n->status == PEER_STATE_KEY_CONFIRMED)
521 {
522 now = GNUNET_TIME_absolute_get ();
523 n->last_activity = now;
524 changed = GNUNET_YES;
525 if (!up)
526 {
527 GNUNET_STATISTICS_update (stats, gettext_noop ("# established sessions"),
528 1, GNUNET_NO);
529 n->time_established = now;
530 }
531 if (n->keep_alive_task != GNUNET_SCHEDULER_NO_TASK)
532 GNUNET_SCHEDULER_cancel (n->keep_alive_task);
533 n->keep_alive_task =
534 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide
535 (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
536 2), &send_keep_alive, n);
537 }
538 if (changed)
539 handle_peer_status_change (n);
540}
541
542
543/**
544 * Transmit the given message to the given target.
545 *
546 * @param target peer that should receive the message (must be connected)
547 * @param msg message to transmit
548 * @param timeout by when should the transmission be done?
549 */
550void
551GDS_NEIGHBOURS_transmit (const struct GNUNET_PeerIdentity *target,
552 const struct GNUNET_MessageHeader *msg,
553 struct GNUNET_TIME_Relative timeout)
554{
555
556}
557
558
559/**
560 * Initialize neighbours subsystem.
561 */
562int
563GSC_NEIGHBOURS_init ()
564{
565 neighbours = GNUNET_CONTAINER_multihashmap_create (128);
566 transport =
567 GNUNET_TRANSPORT_connect (GSC_cfg,
568 &GSC_my_identity, NULL,
569 &handle_transport_receive,
570 &handle_transport_notify_connect,
571 &handle_transport_notify_disconnect);
572 if (NULL == transport)
573 {
574 GNUNET_CONTAINER_multihashmap_destroy (neighbours);
575 neighbours = NULL;
576 return GNUNET_SYSERR;
577 }
578 return GNUNET_OK;
579}
580
581
582/**
583 * Wrapper around 'free_neighbour'.
584 *
585 * @param cls unused
586 * @param key peer identity
587 * @param value the 'struct Neighbour' to free
588 * @return GNUNET_OK (continue to iterate)
589 */
590static int
591free_neighbour_helper (void *cls, const GNUNET_HashCode * key, void *value)
592{
593 struct Neighbour *n = value;
594
595 free_neighbour (n);
596 return GNUNET_OK;
597}
598
599
600/**
601 * Shutdown neighbours subsystem.
602 */
603void
604GSC_NEIGHBOURS_done ()
605{
606 if (NULL == transport)
607 return;
608 GNUNET_CONTAINER_multihashmap_iterate (neighbours, &free_neighbour_helper,
609 NULL);
610 GNUNET_TRANSPORT_disconnect (transport);
611 transport = NULL;
612 GNUNET_CONTAINER_multihashmap_destroy (neighbours);
613 neighbours = NULL;
614}
615
616/* end of gnunet-service-core_neighbours.c */
617
diff --git a/src/core/gnunet-service-core_plan.c b/src/core/gnunet-service-core_plan.c
new file mode 100644
index 000000000..580038e08
--- /dev/null
+++ b/src/core/gnunet-service-core_plan.c
@@ -0,0 +1,563 @@
1
2
3
4/**
5 * Select messages for transmission. This heuristic uses a combination
6 * of earliest deadline first (EDF) scheduling (with bounded horizon)
7 * and priority-based discard (in case no feasible schedule exist) and
8 * speculative optimization (defer any kind of transmission until
9 * we either create a batch of significant size, 25% of max, or until
10 * we are close to a deadline). Furthermore, when scheduling the
11 * heuristic also packs as many messages into the batch as possible,
12 * starting with those with the earliest deadline. Yes, this is fun.
13 *
14 * @param n neighbour to select messages from
15 * @param size number of bytes to select for transmission
16 * @param retry_time set to the time when we should try again
17 * (only valid if this function returns zero)
18 * @return number of bytes selected, or 0 if we decided to
19 * defer scheduling overall; in that case, retry_time is set.
20 */
21static size_t
22select_messages (struct Neighbour *n, size_t size,
23 struct GNUNET_TIME_Relative *retry_time)
24{
25 struct MessageEntry *pos;
26 struct MessageEntry *min;
27 struct MessageEntry *last;
28 unsigned int min_prio;
29 struct GNUNET_TIME_Absolute t;
30 struct GNUNET_TIME_Absolute now;
31 struct GNUNET_TIME_Relative delta;
32 uint64_t avail;
33 struct GNUNET_TIME_Relative slack; /* how long could we wait before missing deadlines? */
34 size_t off;
35 uint64_t tsize;
36 unsigned int queue_size;
37 int discard_low_prio;
38
39 GNUNET_assert (NULL != n->messages);
40 now = GNUNET_TIME_absolute_get ();
41 /* last entry in linked list of messages processed */
42 last = NULL;
43 /* should we remove the entry with the lowest
44 * priority from consideration for scheduling at the
45 * end of the loop? */
46 queue_size = 0;
47 tsize = 0;
48 pos = n->messages;
49 while (pos != NULL)
50 {
51 queue_size++;
52 tsize += pos->size;
53 pos = pos->next;
54 }
55 discard_low_prio = GNUNET_YES;
56 while (GNUNET_YES == discard_low_prio)
57 {
58 min = NULL;
59 min_prio = UINT_MAX;
60 discard_low_prio = GNUNET_NO;
61 /* calculate number of bytes available for transmission at time "t" */
62 avail = GNUNET_BANDWIDTH_tracker_get_available (&n->available_send_window);
63 t = now;
64 /* how many bytes have we (hypothetically) scheduled so far */
65 off = 0;
66 /* maximum time we can wait before transmitting anything
67 * and still make all of our deadlines */
68 slack = GNUNET_TIME_UNIT_FOREVER_REL;
69 pos = n->messages;
70 /* note that we use "*2" here because we want to look
71 * a bit further into the future; much more makes no
72 * sense since new message might be scheduled in the
73 * meantime... */
74 while ((pos != NULL) && (off < size * 2))
75 {
76 if (pos->do_transmit == GNUNET_YES)
77 {
78 /* already removed from consideration */
79 pos = pos->next;
80 continue;
81 }
82 if (discard_low_prio == GNUNET_NO)
83 {
84 delta = GNUNET_TIME_absolute_get_difference (t, pos->deadline);
85 if (delta.rel_value > 0)
86 {
87 // FIXME: HUH? Check!
88 t = pos->deadline;
89 avail +=
90 GNUNET_BANDWIDTH_value_get_available_until (n->bw_out, delta);
91 }
92 if (avail < pos->size)
93 {
94 // FIXME: HUH? Check!
95 discard_low_prio = GNUNET_YES; /* we could not schedule this one! */
96 }
97 else
98 {
99 avail -= pos->size;
100 /* update slack, considering both its absolute deadline
101 * and relative deadlines caused by other messages
102 * with their respective load */
103 slack =
104 GNUNET_TIME_relative_min (slack,
105 GNUNET_BANDWIDTH_value_get_delay_for
106 (n->bw_out, avail));
107 if (pos->deadline.abs_value <= now.abs_value)
108 {
109 /* now or never */
110 slack = GNUNET_TIME_UNIT_ZERO;
111 }
112 else if (GNUNET_YES == pos->got_slack)
113 {
114 /* should be soon now! */
115 slack =
116 GNUNET_TIME_relative_min (slack,
117 GNUNET_TIME_absolute_get_remaining
118 (pos->slack_deadline));
119 }
120 else
121 {
122 slack =
123 GNUNET_TIME_relative_min (slack,
124 GNUNET_TIME_absolute_get_difference
125 (now, pos->deadline));
126 pos->got_slack = GNUNET_YES;
127 pos->slack_deadline =
128 GNUNET_TIME_absolute_min (pos->deadline,
129 GNUNET_TIME_relative_to_absolute
130 (GNUNET_CONSTANTS_MAX_CORK_DELAY));
131 }
132 }
133 }
134 off += pos->size;
135 t = GNUNET_TIME_absolute_max (pos->deadline, t); // HUH? Check!
136 if (pos->priority <= min_prio)
137 {
138 /* update min for discard */
139 min_prio = pos->priority;
140 min = pos;
141 }
142 pos = pos->next;
143 }
144 if (discard_low_prio)
145 {
146 GNUNET_assert (min != NULL);
147 /* remove lowest-priority entry from consideration */
148 min->do_transmit = GNUNET_YES; /* means: discard (for now) */
149 }
150 last = pos;
151 }
152 /* guard against sending "tiny" messages with large headers without
153 * urgent deadlines */
154 if ((slack.rel_value > GNUNET_CONSTANTS_MAX_CORK_DELAY.rel_value) &&
155 (size > 4 * off) && (queue_size <= MAX_PEER_QUEUE_SIZE - 2))
156 {
157 /* less than 25% of message would be filled with deadlines still
158 * being met if we delay by one second or more; so just wait for
159 * more data; but do not wait longer than 1s (since we don't want
160 * to delay messages for a really long time either). */
161 *retry_time = GNUNET_CONSTANTS_MAX_CORK_DELAY;
162 /* reset do_transmit values for next time */
163 while (pos != last)
164 {
165 pos->do_transmit = GNUNET_NO;
166 pos = pos->next;
167 }
168 GNUNET_STATISTICS_update (stats,
169 gettext_noop
170 ("# transmissions delayed due to corking"), 1,
171 GNUNET_NO);
172#if DEBUG_CORE
173 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
174 "Deferring transmission for %llums due to underfull message buffer size (%u/%u)\n",
175 (unsigned long long) retry_time->rel_value, (unsigned int) off,
176 (unsigned int) size);
177#endif
178 return 0;
179 }
180 /* select marked messages (up to size) for transmission */
181 off = 0;
182 pos = n->messages;
183 while (pos != last)
184 {
185 if ((pos->size <= size) && (pos->do_transmit == GNUNET_NO))
186 {
187 pos->do_transmit = GNUNET_YES; /* mark for transmission */
188 off += pos->size;
189 size -= pos->size;
190#if DEBUG_CORE > 1
191 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
192 "Selecting message of size %u for transmission\n",
193 (unsigned int) pos->size);
194#endif
195 }
196 else
197 {
198#if DEBUG_CORE > 1
199 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
200 "Not selecting message of size %u for transmission at this time (maximum is %u)\n",
201 (unsigned int) pos->size, size);
202#endif
203 pos->do_transmit = GNUNET_NO; /* mark for not transmitting! */
204 }
205 pos = pos->next;
206 }
207#if DEBUG_CORE
208 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
209 "Selected %llu/%llu bytes of %u/%u plaintext messages for transmission to `%4s'.\n",
210 (unsigned long long) off, (unsigned long long) tsize, queue_size,
211 (unsigned int) MAX_PEER_QUEUE_SIZE, GNUNET_i2s (&n->peer));
212#endif
213 return off;
214}
215
216
217/**
218 * Batch multiple messages into a larger buffer.
219 *
220 * @param n neighbour to take messages from
221 * @param buf target buffer
222 * @param size size of buf
223 * @param deadline set to transmission deadline for the result
224 * @param retry_time set to the time when we should try again
225 * (only valid if this function returns zero)
226 * @param priority set to the priority of the batch
227 * @return number of bytes written to buf (can be zero)
228 */
229static size_t
230batch_message (struct Neighbour *n, char *buf, size_t size,
231 struct GNUNET_TIME_Absolute *deadline,
232 struct GNUNET_TIME_Relative *retry_time, unsigned int *priority)
233{
234 char ntmb[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
235 struct NotifyTrafficMessage *ntm = (struct NotifyTrafficMessage *) ntmb;
236 struct MessageEntry *pos;
237 struct MessageEntry *prev;
238 struct MessageEntry *next;
239 size_t ret;
240
241 ret = 0;
242 *priority = 0;
243 *deadline = GNUNET_TIME_UNIT_FOREVER_ABS;
244 *retry_time = GNUNET_TIME_UNIT_FOREVER_REL;
245 if (0 == select_messages (n, size, retry_time))
246 {
247#if DEBUG_CORE
248 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
249 "No messages selected, will try again in %llu ms\n",
250 retry_time->rel_value);
251#endif
252 return 0;
253 }
254 ntm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_OUTBOUND);
255 ntm->ats_count = htonl (0);
256 ntm->ats.type = htonl (0);
257 ntm->ats.value = htonl (0);
258 ntm->peer = n->peer;
259 pos = n->messages;
260 prev = NULL;
261 while ((pos != NULL) && (size >= sizeof (struct GNUNET_MessageHeader)))
262 {
263 next = pos->next;
264 if (GNUNET_YES == pos->do_transmit)
265 {
266 GNUNET_assert (pos->size <= size);
267 /* do notifications */
268 /* FIXME: track if we have *any* client that wants
269 * full notifications and only do this if that is
270 * actually true */
271 if (pos->size <
272 GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (struct NotifyTrafficMessage))
273 {
274 memcpy (&ntm[1], &pos[1], pos->size);
275 ntm->header.size =
276 htons (sizeof (struct NotifyTrafficMessage) +
277 sizeof (struct GNUNET_MessageHeader));
278 send_to_all_clients (&ntm->header, GNUNET_YES,
279 GNUNET_CORE_OPTION_SEND_HDR_OUTBOUND);
280 }
281 else
282 {
283 /* message too large for 'full' notifications, we do at
284 * least the 'hdr' type */
285 memcpy (&ntm[1], &pos[1], sizeof (struct GNUNET_MessageHeader));
286 }
287 ntm->header.size =
288 htons (sizeof (struct NotifyTrafficMessage) + pos->size);
289 send_to_all_clients (&ntm->header, GNUNET_YES,
290 GNUNET_CORE_OPTION_SEND_FULL_OUTBOUND);
291#if DEBUG_HANDSHAKE
292 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
293 "Encrypting %u bytes with message of type %u and size %u\n",
294 pos->size,
295 (unsigned int)
296 ntohs (((const struct GNUNET_MessageHeader *) &pos[1])->type),
297 (unsigned int)
298 ntohs (((const struct GNUNET_MessageHeader *)
299 &pos[1])->size));
300#endif
301 /* copy for encrypted transmission */
302 memcpy (&buf[ret], &pos[1], pos->size);
303 ret += pos->size;
304 size -= pos->size;
305 *priority += pos->priority;
306#if DEBUG_CORE > 1
307 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
308 "Adding plaintext message of size %u with deadline %llu ms to batch\n",
309 (unsigned int) pos->size,
310 (unsigned long long)
311 GNUNET_TIME_absolute_get_remaining (pos->deadline).rel_value);
312#endif
313 deadline->abs_value =
314 GNUNET_MIN (deadline->abs_value, pos->deadline.abs_value);
315 GNUNET_free (pos);
316 if (prev == NULL)
317 n->messages = next;
318 else
319 prev->next = next;
320 }
321 else
322 {
323 prev = pos;
324 }
325 pos = next;
326 }
327#if DEBUG_CORE > 1
328 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
329 "Deadline for message batch is %llu ms\n",
330 GNUNET_TIME_absolute_get_remaining (*deadline).rel_value);
331#endif
332 return ret;
333}
334
335
336/**
337 * Remove messages with deadlines that have long expired from
338 * the queue.
339 *
340 * @param n neighbour to inspect
341 */
342static void
343discard_expired_messages (struct Neighbour *n)
344{
345 struct MessageEntry *prev;
346 struct MessageEntry *next;
347 struct MessageEntry *pos;
348 struct GNUNET_TIME_Absolute now;
349 struct GNUNET_TIME_Relative delta;
350 int disc;
351 unsigned int queue_length;
352
353 disc = GNUNET_NO;
354 now = GNUNET_TIME_absolute_get ();
355 prev = NULL;
356 queue_length = 0;
357 pos = n->messages;
358 while (pos != NULL)
359 {
360 queue_length++;
361 next = pos->next;
362 delta = GNUNET_TIME_absolute_get_difference (pos->deadline, now);
363 if (delta.rel_value > PAST_EXPIRATION_DISCARD_TIME.rel_value)
364 {
365#if DEBUG_CORE
366 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
367 "Message is %llu ms past due, discarding.\n",
368 delta.rel_value);
369#endif
370 if (prev == NULL)
371 n->messages = next;
372 else
373 prev->next = next;
374 GNUNET_STATISTICS_update (stats,
375 gettext_noop
376 ("# messages discarded (expired prior to transmission)"),
377 1, GNUNET_NO);
378 disc = GNUNET_YES;
379 GNUNET_free (pos);
380 }
381 else
382 prev = pos;
383 pos = next;
384 }
385 if ( (GNUNET_YES == disc) &&
386 (queue_length == MAX_PEER_QUEUE_SIZE) )
387 schedule_peer_messages (n);
388}
389
390
391/**
392 * Signature of the main function of a task.
393 *
394 * @param cls closure
395 * @param tc context information (why was this task triggered now)
396 */
397static void
398retry_plaintext_processing (void *cls,
399 const struct GNUNET_SCHEDULER_TaskContext *tc)
400{
401 struct Neighbour *n = cls;
402
403 n->retry_plaintext_task = GNUNET_SCHEDULER_NO_TASK;
404 process_plaintext_neighbour_queue (n);
405}
406
407
408/**
409 * Check if we have plaintext messages for the specified neighbour
410 * pending, and if so, consider batching and encrypting them (and
411 * then trigger processing of the encrypted queue if needed).
412 *
413 * @param n neighbour to check.
414 */
415static void
416process_plaintext_neighbour_queue (struct Neighbour *n)
417{
418 char pbuf[GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE + sizeof (struct EncryptedMessage)]; /* plaintext */
419 size_t used;
420 struct EncryptedMessage *em; /* encrypted message */
421 struct EncryptedMessage *ph; /* plaintext header */
422 struct MessageEntry *me;
423 unsigned int priority;
424 struct GNUNET_TIME_Absolute deadline;
425 struct GNUNET_TIME_Relative retry_time;
426 struct GNUNET_CRYPTO_AesInitializationVector iv;
427 struct GNUNET_CRYPTO_AuthKey auth_key;
428
429 if (n->retry_plaintext_task != GNUNET_SCHEDULER_NO_TASK)
430 {
431 GNUNET_SCHEDULER_cancel (n->retry_plaintext_task);
432 n->retry_plaintext_task = GNUNET_SCHEDULER_NO_TASK;
433 }
434 switch (n->status)
435 {
436 case PEER_STATE_DOWN:
437 send_key (n);
438#if DEBUG_CORE
439 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
440 "Not yet connected to `%4s', deferring processing of plaintext messages.\n",
441 GNUNET_i2s (&n->peer));
442#endif
443 return;
444 case PEER_STATE_KEY_SENT:
445 if (n->retry_set_key_task == GNUNET_SCHEDULER_NO_TASK)
446 n->retry_set_key_task =
447 GNUNET_SCHEDULER_add_delayed (n->set_key_retry_frequency,
448 &set_key_retry_task, n);
449#if DEBUG_CORE
450 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
451 "Not yet connected to `%4s', deferring processing of plaintext messages.\n",
452 GNUNET_i2s (&n->peer));
453#endif
454 return;
455 case PEER_STATE_KEY_RECEIVED:
456 if (n->retry_set_key_task == GNUNET_SCHEDULER_NO_TASK)
457 n->retry_set_key_task =
458 GNUNET_SCHEDULER_add_delayed (n->set_key_retry_frequency,
459 &set_key_retry_task, n);
460#if DEBUG_CORE
461 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
462 "Not yet connected to `%4s', deferring processing of plaintext messages.\n",
463 GNUNET_i2s (&n->peer));
464#endif
465 return;
466 case PEER_STATE_KEY_CONFIRMED:
467 /* ready to continue */
468 break;
469 }
470 discard_expired_messages (n);
471 if (n->messages == NULL)
472 {
473#if DEBUG_CORE
474 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
475 "Plaintext message queue for `%4s' is empty.\n",
476 GNUNET_i2s (&n->peer));
477#endif
478 return; /* no pending messages */
479 }
480 if (n->encrypted_head != NULL)
481 {
482#if DEBUG_CORE > 2
483 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
484 "Encrypted message queue for `%4s' is still full, delaying plaintext processing.\n",
485 GNUNET_i2s (&n->peer));
486#endif
487 return; /* wait for messages already encrypted to be
488 * processed first! */
489 }
490 ph = (struct EncryptedMessage *) pbuf;
491 deadline = GNUNET_TIME_UNIT_FOREVER_ABS;
492 priority = 0;
493 used = sizeof (struct EncryptedMessage);
494 used +=
495 batch_message (n, &pbuf[used],
496 GNUNET_CONSTANTS_MAX_ENCRYPTED_MESSAGE_SIZE, &deadline,
497 &retry_time, &priority);
498 if (used == sizeof (struct EncryptedMessage))
499 {
500#if DEBUG_CORE > 1
501 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
502 "No messages selected for transmission to `%4s' at this time, will try again later.\n",
503 GNUNET_i2s (&n->peer));
504#endif
505 /* no messages selected for sending, try again later... */
506 n->retry_plaintext_task =
507 GNUNET_SCHEDULER_add_delayed (retry_time, &retry_plaintext_processing,
508 n);
509 return;
510 }
511#if DEBUG_CORE_QUOTA
512 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
513 "Sending %u b/s as new limit to peer `%4s'\n",
514 (unsigned int) ntohl (n->bw_in.value__), GNUNET_i2s (&n->peer));
515#endif
516 ph->iv_seed =
517 htonl (GNUNET_CRYPTO_random_u32
518 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX));
519 ph->sequence_number = htonl (++n->last_sequence_number_sent);
520 ph->inbound_bw_limit = n->bw_in;
521 ph->timestamp = GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
522
523 /* setup encryption message header */
524 me = GNUNET_malloc (sizeof (struct MessageEntry) + used);
525 me->deadline = deadline;
526 me->priority = priority;
527 me->size = used;
528 em = (struct EncryptedMessage *) &me[1];
529 em->header.size = htons (used);
530 em->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_ENCRYPTED_MESSAGE);
531 em->iv_seed = ph->iv_seed;
532 derive_iv (&iv, &n->encrypt_key, ph->iv_seed, &n->peer);
533 /* encrypt */
534#if DEBUG_HANDSHAKE
535 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
536 "Encrypting %u bytes of plaintext messages for `%4s' for transmission in %llums.\n",
537 (unsigned int) used - ENCRYPTED_HEADER_SIZE,
538 GNUNET_i2s (&n->peer),
539 (unsigned long long)
540 GNUNET_TIME_absolute_get_remaining (deadline).rel_value);
541#endif
542 GNUNET_assert (GNUNET_OK ==
543 do_encrypt (n, &iv, &ph->sequence_number, &em->sequence_number,
544 used - ENCRYPTED_HEADER_SIZE));
545 derive_auth_key (&auth_key, &n->encrypt_key, ph->iv_seed,
546 n->encrypt_key_created);
547 GNUNET_CRYPTO_hmac (&auth_key, &em->sequence_number,
548 used - ENCRYPTED_HEADER_SIZE, &em->hmac);
549#if DEBUG_HANDSHAKE
550 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
551 "Authenticated %u bytes of ciphertext %u: `%s'\n",
552 used - ENCRYPTED_HEADER_SIZE,
553 GNUNET_CRYPTO_crc32_n (&em->sequence_number,
554 used - ENCRYPTED_HEADER_SIZE),
555 GNUNET_h2s (&em->hmac));
556#endif
557 /* append to transmission list */
558 GNUNET_CONTAINER_DLL_insert_after (n->encrypted_head, n->encrypted_tail,
559 n->encrypted_tail, me);
560 process_encrypted_neighbour_queue (n);
561 schedule_peer_messages (n);
562}
563
diff --git a/src/core/gnunet-service-core_sessions.c b/src/core/gnunet-service-core_sessions.c
new file mode 100644
index 000000000..13593e9d6
--- /dev/null
+++ b/src/core/gnunet-service-core_sessions.c
@@ -0,0 +1,713 @@
1/* code for managing of 'encrypted' sessions (key exchange done) */
2
3
4/**
5 * Record kept for each request for transmission issued by a
6 * client that is still pending.
7 */
8struct ClientActiveRequest;
9
10/**
11 * Data kept per session.
12 */
13struct Session
14{
15 /**
16 * Identity of the other peer.
17 */
18 struct GNUNET_PeerIdentity peer;
19
20 /**
21 * Head of list of requests from clients for transmission to
22 * this peer.
23 */
24 struct ClientActiveRequest *active_client_request_head;
25
26 /**
27 * Tail of list of requests from clients for transmission to
28 * this peer.
29 */
30 struct ClientActiveRequest *active_client_request_tail;
31
32 /**
33 * Performance data for the peer.
34 */
35 struct GNUNET_TRANSPORT_ATS_Information *ats;
36
37 /**
38 * Information about the key exchange with the other peer.
39 */
40 struct GSC_KeyExchangeInfo *kxinfo;
41
42 /**
43 * ID of task used for sending keep-alive pings.
44 */
45 GNUNET_SCHEDULER_TaskIdentifier keep_alive_task;
46
47 /**
48 * ID of task used for cleaning up dead neighbour entries.
49 */
50 GNUNET_SCHEDULER_TaskIdentifier dead_clean_task;
51
52 /**
53 * ID of task used for updating bandwidth quota for this neighbour.
54 */
55 GNUNET_SCHEDULER_TaskIdentifier quota_update_task;
56
57 /**
58 * At what time did we initially establish (as in, complete session
59 * key handshake) this connection? Should be zero if status != KEY_CONFIRMED.
60 */
61 struct GNUNET_TIME_Absolute time_established;
62
63 /**
64 * At what time did we last receive an encrypted message from the
65 * other peer? Should be zero if status != KEY_CONFIRMED.
66 */
67 struct GNUNET_TIME_Absolute last_activity;
68
69 /**
70 * Tracking bandwidth for sending to this peer.
71 */
72 struct GNUNET_BANDWIDTH_Tracker available_send_window;
73
74 /**
75 * Tracking bandwidth for receiving from this peer.
76 */
77 struct GNUNET_BANDWIDTH_Tracker available_recv_window;
78
79 /**
80 * How valueable were the messages of this peer recently?
81 */
82 unsigned long long current_preference;
83
84 /**
85 * Number of entries in 'ats'.
86 */
87 unsigned int ats_count;
88
89 /**
90 * Bit map indicating which of the 32 sequence numbers before the last
91 * were received (good for accepting out-of-order packets and
92 * estimating reliability of the connection)
93 */
94 unsigned int last_packets_bitmap;
95
96 /**
97 * last sequence number received on this connection (highest)
98 */
99 uint32_t last_sequence_number_received;
100
101 /**
102 * last sequence number transmitted
103 */
104 uint32_t last_sequence_number_sent;
105
106 /**
107 * Available bandwidth in for this peer (current target).
108 */
109 struct GNUNET_BANDWIDTH_Value32NBO bw_in;
110
111 /**
112 * Available bandwidth out for this peer (current target).
113 */
114 struct GNUNET_BANDWIDTH_Value32NBO bw_out;
115
116 /**
117 * Internal bandwidth limit set for this peer (initially typically
118 * set to "-1"). Actual "bw_out" is MIN of
119 * "bpm_out_internal_limit" and "bw_out_external_limit".
120 */
121 struct GNUNET_BANDWIDTH_Value32NBO bw_out_internal_limit;
122
123 /**
124 * External bandwidth limit set for this peer by the
125 * peer that we are communicating with. "bw_out" is MIN of
126 * "bw_out_internal_limit" and "bw_out_external_limit".
127 */
128 struct GNUNET_BANDWIDTH_Value32NBO bw_out_external_limit;
129
130};
131
132
133/**
134 * Map of peer identities to 'struct Session'.
135 */
136static struct GNUNET_CONTAINER_MultiHashMap *sessions;
137
138
139/**
140 * Session entry for "this" peer.
141 */
142static struct Session self;
143
144/**
145 * Sum of all preferences among all neighbours.
146 */
147static unsigned long long preference_sum;
148
149
150// FIXME.........
151
152/**
153 * At what time should the connection to the given neighbour
154 * time out (given no further activity?)
155 *
156 * @param n neighbour in question
157 * @return absolute timeout
158 */
159static struct GNUNET_TIME_Absolute
160get_neighbour_timeout (struct Neighbour *n)
161{
162 return GNUNET_TIME_absolute_add (n->last_activity,
163 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
164}
165
166
167/**
168 * Helper function for update_preference_sum.
169 */
170static int
171update_preference (void *cls, const GNUNET_HashCode * key, void *value)
172{
173 unsigned long long *ps = cls;
174 struct Neighbour *n = value;
175
176 n->current_preference /= 2;
177 *ps += n->current_preference;
178 return GNUNET_OK;
179}
180
181
182/**
183 * A preference value for a neighbour was update. Update
184 * the preference sum accordingly.
185 *
186 * @param inc how much was a preference value increased?
187 */
188static void
189update_preference_sum (unsigned long long inc)
190{
191 unsigned long long os;
192
193 os = preference_sum;
194 preference_sum += inc;
195 if (preference_sum >= os)
196 return; /* done! */
197 /* overflow! compensate by cutting all values in half! */
198 preference_sum = 0;
199 GNUNET_CONTAINER_multihashmap_iterate (neighbours, &update_preference,
200 &preference_sum);
201 GNUNET_STATISTICS_set (stats, gettext_noop ("# total peer preference"),
202 preference_sum, GNUNET_NO);
203}
204
205
206/**
207 * Find the entry for the given neighbour.
208 *
209 * @param peer identity of the neighbour
210 * @return NULL if we are not connected, otherwise the
211 * neighbour's entry.
212 */
213static struct Neighbour *
214find_neighbour (const struct GNUNET_PeerIdentity *peer)
215{
216 return GNUNET_CONTAINER_multihashmap_get (neighbours, &peer->hashPubKey);
217}
218
219
220/**
221 * Function called by transport telling us that a peer
222 * changed status.
223 *
224 * @param n the peer that changed status
225 */
226static void
227handle_peer_status_change (struct Neighbour *n)
228{
229 struct PeerStatusNotifyMessage *psnm;
230 char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
231 struct GNUNET_TRANSPORT_ATS_Information *ats;
232 size_t size;
233
234 if ((!n->is_connected) || (n->status != PEER_STATE_KEY_CONFIRMED))
235 return;
236#if DEBUG_CORE > 1
237 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%4s' changed status\n",
238 GNUNET_i2s (&n->peer));
239#endif
240 size =
241 sizeof (struct PeerStatusNotifyMessage) +
242 n->ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
243 if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
244 {
245 GNUNET_break (0);
246 /* recovery strategy: throw away performance data */
247 GNUNET_array_grow (n->ats, n->ats_count, 0);
248 size =
249 sizeof (struct PeerStatusNotifyMessage) +
250 n->ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
251 }
252 psnm = (struct PeerStatusNotifyMessage *) buf;
253 psnm->header.size = htons (size);
254 psnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_STATUS_CHANGE);
255 psnm->timeout = GNUNET_TIME_absolute_hton (get_neighbour_timeout (n));
256 psnm->bandwidth_in = n->bw_in;
257 psnm->bandwidth_out = n->bw_out;
258 psnm->peer = n->peer;
259 psnm->ats_count = htonl (n->ats_count);
260 ats = &psnm->ats;
261 memcpy (ats, n->ats,
262 n->ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information));
263 ats[n->ats_count].type = htonl (0);
264 ats[n->ats_count].value = htonl (0);
265 send_to_all_clients (&psnm->header, GNUNET_YES,
266 GNUNET_CORE_OPTION_SEND_STATUS_CHANGE);
267 GNUNET_STATISTICS_update (stats, gettext_noop ("# peer status changes"), 1,
268 GNUNET_NO);
269}
270
271
272
273/**
274 * Go over our message queue and if it is not too long, go
275 * over the pending requests from clients for this
276 * neighbour and send some clients a 'READY' notification.
277 *
278 * @param n which peer to process
279 */
280static void
281schedule_peer_messages (struct Neighbour *n)
282{
283 struct SendMessageReady smr;
284 struct ClientActiveRequest *car;
285 struct ClientActiveRequest *pos;
286 struct Client *c;
287 struct MessageEntry *mqe;
288 unsigned int queue_size;
289
290 /* check if neighbour queue is empty enough! */
291 if (n != &self)
292 {
293 queue_size = 0;
294 mqe = n->messages;
295 while (mqe != NULL)
296 {
297 queue_size++;
298 mqe = mqe->next;
299 }
300 if (queue_size >= MAX_PEER_QUEUE_SIZE)
301 {
302#if DEBUG_CORE_CLIENT
303 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
304 "Not considering client transmission requests: queue full\n");
305#endif
306 return; /* queue still full */
307 }
308 /* find highest priority request */
309 pos = n->active_client_request_head;
310 car = NULL;
311 while (pos != NULL)
312 {
313 if ((car == NULL) || (pos->priority > car->priority))
314 car = pos;
315 pos = pos->next;
316 }
317 }
318 else
319 {
320 car = n->active_client_request_head;
321 }
322 if (car == NULL)
323 return; /* no pending requests */
324#if DEBUG_CORE_CLIENT
325 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
326 "Permitting client transmission request to `%s'\n",
327 GNUNET_i2s (&n->peer));
328#endif
329 c = car->client;
330 GNUNET_CONTAINER_DLL_remove (n->active_client_request_head,
331 n->active_client_request_tail, car);
332 GNUNET_assert (GNUNET_YES ==
333 GNUNET_CONTAINER_multihashmap_remove (c->requests,
334 &n->peer.hashPubKey,
335 car));
336 smr.header.size = htons (sizeof (struct SendMessageReady));
337 smr.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_SEND_READY);
338 smr.size = htons (car->msize);
339 smr.smr_id = car->smr_id;
340 smr.peer = n->peer;
341 send_to_client (c, &smr.header, GNUNET_NO);
342 GNUNET_free (car);
343}
344
345
346
347/**
348 * Free the given entry for the neighbour (it has
349 * already been removed from the list at this point).
350 *
351 * @param n neighbour to free
352 */
353static void
354free_neighbour (struct Neighbour *n)
355{
356 struct MessageEntry *m;
357 struct ClientActiveRequest *car;
358
359#if DEBUG_CORE
360 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
361 "Destroying neighbour entry for peer `%4s'\n",
362 GNUNET_i2s (&n->peer));
363#endif
364 if (n->skm != NULL)
365 {
366 GNUNET_free (n->skm);
367 n->skm = NULL;
368 }
369 while (NULL != (m = n->messages))
370 {
371 n->messages = m->next;
372 GNUNET_free (m);
373 }
374 while (NULL != (m = n->encrypted_head))
375 {
376 GNUNET_CONTAINER_DLL_remove (n->encrypted_head, n->encrypted_tail, m);
377 GNUNET_free (m);
378 }
379 while (NULL != (car = n->active_client_request_head))
380 {
381 GNUNET_CONTAINER_DLL_remove (n->active_client_request_head,
382 n->active_client_request_tail, car);
383 GNUNET_assert (GNUNET_YES ==
384 GNUNET_CONTAINER_multihashmap_remove (car->client->requests,
385 &n->peer.hashPubKey,
386 car));
387 GNUNET_free (car);
388 }
389 if (NULL != n->th)
390 {
391 GNUNET_TRANSPORT_notify_transmit_ready_cancel (n->th);
392 n->th = NULL;
393 }
394 if (n->retry_plaintext_task != GNUNET_SCHEDULER_NO_TASK)
395 GNUNET_SCHEDULER_cancel (n->retry_plaintext_task);
396 if (n->quota_update_task != GNUNET_SCHEDULER_NO_TASK)
397 GNUNET_SCHEDULER_cancel (n->quota_update_task);
398 if (n->dead_clean_task != GNUNET_SCHEDULER_NO_TASK)
399 GNUNET_SCHEDULER_cancel (n->dead_clean_task);
400 if (n->keep_alive_task != GNUNET_SCHEDULER_NO_TASK)
401 GNUNET_SCHEDULER_cancel (n->keep_alive_task);
402 if (n->status == PEER_STATE_KEY_CONFIRMED)
403 GNUNET_STATISTICS_update (stats, gettext_noop ("# established sessions"),
404 -1, GNUNET_NO);
405 GNUNET_array_grow (n->ats, n->ats_count, 0);
406 GNUNET_free_non_null (n->pending_ping);
407 GNUNET_free_non_null (n->pending_pong);
408 GNUNET_free (n);
409}
410
411
412
413/**
414 * Task triggered when a neighbour entry is about to time out
415 * (and we should prevent this by sending a PING).
416 *
417 * @param cls the 'struct Neighbour'
418 * @param tc scheduler context (not used)
419 */
420static void
421send_keep_alive (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
422{
423 struct Neighbour *n = cls;
424 struct GNUNET_TIME_Relative retry;
425 struct GNUNET_TIME_Relative left;
426 struct MessageEntry *me;
427 struct PingMessage pp;
428 struct PingMessage *pm;
429 struct GNUNET_CRYPTO_AesInitializationVector iv;
430
431 n->keep_alive_task = GNUNET_SCHEDULER_NO_TASK;
432 /* send PING */
433 me = GNUNET_malloc (sizeof (struct MessageEntry) +
434 sizeof (struct PingMessage));
435 me->deadline = GNUNET_TIME_relative_to_absolute (MAX_PING_DELAY);
436 me->priority = PING_PRIORITY;
437 me->size = sizeof (struct PingMessage);
438 GNUNET_CONTAINER_DLL_insert_after (n->encrypted_head, n->encrypted_tail,
439 n->encrypted_tail, me);
440 pm = (struct PingMessage *) &me[1];
441 pm->header.size = htons (sizeof (struct PingMessage));
442 pm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_PING);
443 pm->iv_seed =
444 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX);
445 derive_iv (&iv, &n->encrypt_key, pm->iv_seed, &n->peer);
446 pp.challenge = n->ping_challenge;
447 pp.target = n->peer;
448#if DEBUG_HANDSHAKE
449 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
450 "Encrypting `%s' message with challenge %u for `%4s' using key %u, IV %u (salt %u).\n",
451 "PING", (unsigned int) n->ping_challenge, GNUNET_i2s (&n->peer),
452 (unsigned int) n->encrypt_key.crc32, GNUNET_CRYPTO_crc32_n (&iv,
453 sizeof
454 (iv)),
455 pm->iv_seed);
456#endif
457 do_encrypt (n, &iv, &pp.target, &pm->target,
458 sizeof (struct PingMessage) - ((void *) &pm->target -
459 (void *) pm));
460 process_encrypted_neighbour_queue (n);
461 /* reschedule PING job */
462 left = GNUNET_TIME_absolute_get_remaining (get_neighbour_timeout (n));
463 retry =
464 GNUNET_TIME_relative_max (GNUNET_TIME_relative_divide (left, 2),
465 MIN_PING_FREQUENCY);
466 n->keep_alive_task =
467 GNUNET_SCHEDULER_add_delayed (retry, &send_keep_alive, n);
468
469}
470
471/**
472 * Consider freeing the given neighbour since we may not need
473 * to keep it around anymore.
474 *
475 * @param n neighbour to consider discarding
476 */
477static void
478consider_free_neighbour (struct Neighbour *n);
479
480
481/**
482 * Task triggered when a neighbour entry might have gotten stale.
483 *
484 * @param cls the 'struct Neighbour'
485 * @param tc scheduler context (not used)
486 */
487static void
488consider_free_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
489{
490 struct Neighbour *n = cls;
491
492 n->dead_clean_task = GNUNET_SCHEDULER_NO_TASK;
493 consider_free_neighbour (n);
494}
495
496
497/**
498 * Consider freeing the given neighbour since we may not need
499 * to keep it around anymore.
500 *
501 * @param n neighbour to consider discarding
502 */
503static void
504consider_free_neighbour (struct Neighbour *n)
505{
506 struct GNUNET_TIME_Relative left;
507
508 if ((n->th != NULL) || (n->pitr != NULL) || (GNUNET_YES == n->is_connected))
509 return; /* no chance */
510
511 left = GNUNET_TIME_absolute_get_remaining (get_neighbour_timeout (n));
512 if (left.rel_value > 0)
513 {
514 if (n->dead_clean_task != GNUNET_SCHEDULER_NO_TASK)
515 GNUNET_SCHEDULER_cancel (n->dead_clean_task);
516 n->dead_clean_task =
517 GNUNET_SCHEDULER_add_delayed (left, &consider_free_task, n);
518 return;
519 }
520 /* actually free the neighbour... */
521 GNUNET_assert (GNUNET_YES ==
522 GNUNET_CONTAINER_multihashmap_remove (neighbours,
523 &n->peer.hashPubKey, n));
524 GNUNET_STATISTICS_set (stats, gettext_noop ("# neighbour entries allocated"),
525 GNUNET_CONTAINER_multihashmap_size (neighbours),
526 GNUNET_NO);
527 free_neighbour (n);
528}
529
530
531/**
532 * Function called when the transport service is ready to
533 * receive an encrypted message for the respective peer
534 *
535 * @param cls neighbour to use message from
536 * @param size number of bytes we can transmit
537 * @param buf where to copy the message
538 * @return number of bytes transmitted
539 */
540static size_t
541notify_encrypted_transmit_ready (void *cls, size_t size, void *buf)
542{
543 struct Neighbour *n = cls;
544 struct MessageEntry *m;
545 size_t ret;
546 char *cbuf;
547
548 n->th = NULL;
549 m = n->encrypted_head;
550 if (m == NULL)
551 {
552#if DEBUG_CORE
553 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
554 "Encrypted message queue empty, no messages added to buffer for `%4s'\n",
555 GNUNET_i2s (&n->peer));
556#endif
557 return 0;
558 }
559 GNUNET_CONTAINER_DLL_remove (n->encrypted_head, n->encrypted_tail, m);
560 ret = 0;
561 cbuf = buf;
562 if (buf != NULL)
563 {
564 GNUNET_assert (size >= m->size);
565 memcpy (cbuf, &m[1], m->size);
566 ret = m->size;
567 GNUNET_BANDWIDTH_tracker_consume (&n->available_send_window, m->size);
568#if DEBUG_CORE
569 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
570 "Copied message of type %u and size %u into transport buffer for `%4s'\n",
571 (unsigned int)
572 ntohs (((struct GNUNET_MessageHeader *) &m[1])->type),
573 (unsigned int) ret, GNUNET_i2s (&n->peer));
574#endif
575 process_encrypted_neighbour_queue (n);
576 }
577 else
578 {
579#if DEBUG_CORE
580 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
581 "Transmission of message of type %u and size %u failed\n",
582 (unsigned int)
583 ntohs (((struct GNUNET_MessageHeader *) &m[1])->type),
584 (unsigned int) m->size);
585#endif
586 }
587 GNUNET_free (m);
588 consider_free_neighbour (n);
589 GNUNET_STATISTICS_update (stats,
590 gettext_noop
591 ("# encrypted bytes given to transport"), ret,
592 GNUNET_NO);
593 return ret;
594}
595
596
597/**
598 * Check if we have encrypted messages for the specified neighbour
599 * pending, and if so, check with the transport about sending them
600 * out.
601 *
602 * @param n neighbour to check.
603 */
604static void
605process_encrypted_neighbour_queue (struct Neighbour *n)
606{
607 struct MessageEntry *m;
608
609 if (n->th != NULL)
610 return; /* request already pending */
611 if (GNUNET_YES != n->is_connected)
612 {
613 GNUNET_break (0);
614 return;
615 }
616 m = n->encrypted_head;
617 if (m == NULL)
618 {
619 /* encrypted queue empty, try plaintext instead */
620 process_plaintext_neighbour_queue (n);
621 return;
622 }
623#if DEBUG_CORE > 1
624 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
625 "Asking transport for transmission of %u bytes to `%4s' in next %llu ms\n",
626 (unsigned int) m->size, GNUNET_i2s (&n->peer),
627 (unsigned long long)
628 GNUNET_TIME_absolute_get_remaining (m->deadline).rel_value);
629#endif
630 n->th =
631 GNUNET_TRANSPORT_notify_transmit_ready (transport, &n->peer, m->size,
632 m->priority,
633 GNUNET_TIME_absolute_get_remaining
634 (m->deadline),
635 &notify_encrypted_transmit_ready,
636 n);
637 if (n->th == NULL)
638 {
639 /* message request too large or duplicate request */
640 GNUNET_break (0);
641 /* discard encrypted message */
642 GNUNET_CONTAINER_DLL_remove (n->encrypted_head, n->encrypted_tail, m);
643 GNUNET_free (m);
644 process_encrypted_neighbour_queue (n);
645 }
646}
647
648
649/**
650 * Initialize a new 'struct Neighbour'.
651 *
652 * @param pid ID of the new neighbour
653 * @return handle for the new neighbour
654 */
655static struct Neighbour *
656create_neighbour (const struct GNUNET_PeerIdentity *pid)
657{
658 struct Neighbour *n;
659 struct GNUNET_TIME_Absolute now;
660
661#if DEBUG_CORE
662 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
663 "Creating neighbour entry for peer `%4s'\n", GNUNET_i2s (pid));
664#endif
665 n = GNUNET_malloc (sizeof (struct Neighbour));
666 n->peer = *pid;
667 GNUNET_CRYPTO_aes_create_session_key (&n->encrypt_key);
668 now = GNUNET_TIME_absolute_get ();
669 n->encrypt_key_created = now;
670 n->last_activity = now;
671 n->set_key_retry_frequency = INITIAL_SET_KEY_RETRY_FREQUENCY;
672 n->bw_in = GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT;
673 n->bw_out = GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT;
674 n->bw_out_internal_limit = GNUNET_BANDWIDTH_value_init (UINT32_MAX);
675 n->bw_out_external_limit = GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT;
676 n->ping_challenge =
677 GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX);
678 GNUNET_assert (GNUNET_OK ==
679 GNUNET_CONTAINER_multihashmap_put (neighbours,
680 &n->peer.hashPubKey, n,
681 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
682 GNUNET_STATISTICS_set (stats, gettext_noop ("# neighbour entries allocated"),
683 GNUNET_CONTAINER_multihashmap_size (neighbours),
684 GNUNET_NO);
685 neighbour_quota_update (n, NULL);
686 consider_free_neighbour (n);
687 return n;
688}
689
690
691int
692GSC_NEIGHBOURS_init ()
693{
694 neighbours = GNUNET_CONTAINER_multihashmap_create (128);
695 self.public_key = &my_public_key;
696 self.peer = my_identity;
697 self.last_activity = GNUNET_TIME_UNIT_FOREVER_ABS;
698 self.status = PEER_STATE_KEY_CONFIRMED;
699 self.is_connected = GNUNET_YES;
700 return GNUNET_OK;
701}
702
703
704void
705GSC_NEIGHBOURS_done ()
706{
707 GNUNET_CONTAINER_multihashmap_iterate (neighbours, &free_neighbour_helper,
708 NULL);
709 GNUNET_CONTAINER_multihashmap_destroy (neighbours);
710 neighbours = NULL;
711 GNUNET_STATISTICS_set (stats, gettext_noop ("# neighbour entries allocated"),
712 0, GNUNET_NO);
713}
diff --git a/src/core/gnunet-service-core_typemap.c b/src/core/gnunet-service-core_typemap.c
new file mode 100644
index 000000000..3aa652999
--- /dev/null
+++ b/src/core/gnunet-service-core_typemap.c
@@ -0,0 +1,96 @@
1
2/**
3 * Bitmap of message types this peer is able to handle.
4 */
5static uint32_t my_type_map[(UINT16_MAX + 1) / 32];
6
7
8/**
9 * Compute a type map message for this peer.
10 *
11 * @return this peers current type map message.
12 */
13static struct GNUNET_MessageHeader *
14compute_type_map_message ()
15{
16 char *tmp;
17 uLongf dlen;
18 struct GNUNET_MessageHeader *hdr;
19
20#ifdef compressBound
21 dlen = compressBound (sizeof (my_type_map));
22#else
23 dlen = sizeof (my_type_map) + (sizeof (my_type_map) / 100) + 20;
24 /* documentation says 100.1% oldSize + 12 bytes, but we
25 * should be able to overshoot by more to be safe */
26#endif
27 hdr = GNUNET_malloc (dlen + sizeof (struct GNUNET_MessageHeader));
28 hdr->size = htons ((uint16_t) dlen + sizeof (struct GNUNET_MessageHeader));
29 tmp = (char *) &hdr[1];
30 if ((Z_OK !=
31 compress2 ((Bytef *) tmp, &dlen, (const Bytef *) my_type_map,
32 sizeof (my_type_map), 9)) || (dlen >= sizeof (my_type_map)))
33 {
34 dlen = sizeof (my_type_map);
35 memcpy (tmp, my_type_map, sizeof (my_type_map));
36 hdr->type = htons (GNUNET_MESSAGE_TYPE_CORE_BINARY_TYPE_MAP);
37 }
38 else
39 {
40 hdr->type = htons (GNUNET_MESSAGE_TYPE_CORE_COMPRESSED_TYPE_MAP);
41 }
42 return hdr;
43}
44
45
46/**
47 * Send a type map message to the neighbour.
48 *
49 * @param cls the type map message
50 * @param key neighbour's identity
51 * @param value 'struct Neighbour' of the target
52 * @return always GNUNET_OK
53 */
54static int
55send_type_map_to_neighbour (void *cls, const GNUNET_HashCode * key, void *value)
56{
57 struct GNUNET_MessageHeader *hdr = cls;
58 struct Neighbour *n = value;
59 struct MessageEntry *m;
60 uint16_t size;
61
62 if (n == &self)
63 return GNUNET_OK;
64 size = ntohs (hdr->size);
65 m = GNUNET_malloc (sizeof (struct MessageEntry) + size);
66 memcpy (&m[1], hdr, size);
67 m->deadline = GNUNET_TIME_UNIT_FOREVER_ABS;
68 m->slack_deadline = GNUNET_TIME_UNIT_FOREVER_ABS;
69 m->priority = UINT_MAX;
70 m->sender_status = n->status;
71 m->size = size;
72 m->next = n->messages;
73 n->messages = m;
74 return GNUNET_OK;
75}
76
77
78
79/**
80 * Send my type map to all connected peers (it got changed).
81 */
82static void
83broadcast_my_type_map ()
84{
85 struct GNUNET_MessageHeader *hdr;
86
87 if (NULL == neighbours)
88 return;
89 hdr = compute_type_map_message ();
90 GNUNET_CONTAINER_multihashmap_iterate (neighbours,
91 &send_type_map_to_neighbour, hdr);
92 GNUNET_free (hdr);
93}
94
95
96