diff options
author | Christian Grothoff <christian@grothoff.org> | 2011-10-06 13:19:16 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2011-10-06 13:19:16 +0000 |
commit | 4a5fc4b938bc98a2edc71d4875779619d0cebeec (patch) | |
tree | a816afcf4e6d7c25e0ea8217dc89d810b8fa1eac /src/core/gnunet-service-core_clients.c | |
parent | 2fb1bb841a5a7ce3783d84cea68938a8202928aa (diff) | |
download | gnunet-4a5fc4b938bc98a2edc71d4875779619d0cebeec.tar.gz gnunet-4a5fc4b938bc98a2edc71d4875779619d0cebeec.zip |
stuff
Diffstat (limited to 'src/core/gnunet-service-core_clients.c')
-rw-r--r-- | src/core/gnunet-service-core_clients.c | 739 |
1 files changed, 319 insertions, 420 deletions
diff --git a/src/core/gnunet-service-core_clients.c b/src/core/gnunet-service-core_clients.c index 791e9f5f9..a0d5da65c 100644 --- a/src/core/gnunet-service-core_clients.c +++ b/src/core/gnunet-service-core_clients.c | |||
@@ -29,6 +29,8 @@ | |||
29 | #include "gnunet_service_core.h" | 29 | #include "gnunet_service_core.h" |
30 | #include "gnunet_service_core_clients.h" | 30 | #include "gnunet_service_core_clients.h" |
31 | #include "gnunet_service_core_sessions.h" | 31 | #include "gnunet_service_core_sessions.h" |
32 | #include "gnunet_service_core_typemap.h" | ||
33 | |||
32 | 34 | ||
33 | 35 | ||
34 | /** | 36 | /** |
@@ -80,74 +82,42 @@ struct Client | |||
80 | 82 | ||
81 | 83 | ||
82 | /** | 84 | /** |
83 | * Record kept for each request for transmission issued by a | 85 | * Head of linked list of our clients. |
84 | * client that is still pending. | ||
85 | */ | 86 | */ |
86 | struct ClientActiveRequest | 87 | static struct Client *client_head; |
87 | { | ||
88 | |||
89 | /** | ||
90 | * Active requests are kept in a doubly-linked list of | ||
91 | * the respective target peer. | ||
92 | */ | ||
93 | struct ClientActiveRequest *next; | ||
94 | |||
95 | /** | ||
96 | * Active requests are kept in a doubly-linked list of | ||
97 | * the respective target peer. | ||
98 | */ | ||
99 | struct ClientActiveRequest *prev; | ||
100 | |||
101 | /** | ||
102 | * Handle to the client. | ||
103 | */ | ||
104 | struct Client *client; | ||
105 | |||
106 | /** | ||
107 | * By what time would the client want to see this message out? | ||
108 | */ | ||
109 | struct GNUNET_TIME_Absolute deadline; | ||
110 | |||
111 | /** | ||
112 | * How important is this request. | ||
113 | */ | ||
114 | uint32_t priority; | ||
115 | |||
116 | /** | ||
117 | * How many more requests does this client have? | ||
118 | */ | ||
119 | uint32_t queue_size; | ||
120 | |||
121 | /** | ||
122 | * How many bytes does the client intend to send? | ||
123 | */ | ||
124 | uint16_t msize; | ||
125 | |||
126 | /** | ||
127 | * Unique request ID (in big endian). | ||
128 | */ | ||
129 | uint16_t smr_id; | ||
130 | |||
131 | }; | ||
132 | |||
133 | |||
134 | 88 | ||
135 | /** | 89 | /** |
136 | * Linked list of our clients. | 90 | * Tail of linked list of our clients. |
137 | */ | 91 | */ |
138 | static struct Client *clients; | 92 | static struct Client *client_tail; |
139 | 93 | ||
140 | /** | 94 | /** |
141 | * Context for notifications we need to send to our clients. | 95 | * Context for notifications we need to send to our clients. |
142 | */ | 96 | */ |
143 | static struct GNUNET_SERVER_NotificationContext *notifier; | 97 | static struct GNUNET_SERVER_NotificationContext *notifier; |
144 | 98 | ||
99 | /** | ||
100 | * Tokenizer for messages received from clients. | ||
101 | */ | ||
102 | static struct GNUNET_SERVER_MessageStreamTokenizer *client_mst; | ||
103 | |||
145 | 104 | ||
146 | /** | 105 | /** |
147 | * Our message stream tokenizer (for encrypted payload). | 106 | * Lookup our client struct given the server's client handle. |
107 | * | ||
108 | * @param client server client handle to look up | ||
109 | * @return our client handle for the client | ||
148 | */ | 110 | */ |
149 | static struct GNUNET_SERVER_MessageStreamTokenizer *mst; | 111 | static struct Client * |
112 | find_client (struct GNUNET_SERVER_Client *client) | ||
113 | { | ||
114 | struct Client *c; | ||
150 | 115 | ||
116 | c = client_head; | ||
117 | while ((c != NULL) && (c->client_handle != client)) | ||
118 | c = c->next; | ||
119 | return c; | ||
120 | } | ||
151 | 121 | ||
152 | 122 | ||
153 | /** | 123 | /** |
@@ -159,7 +129,8 @@ static struct GNUNET_SERVER_MessageStreamTokenizer *mst; | |||
159 | * client's queue is getting too large? | 129 | * client's queue is getting too large? |
160 | */ | 130 | */ |
161 | static void | 131 | static void |
162 | send_to_client (struct Client *client, const struct GNUNET_MessageHeader *msg, | 132 | send_to_client (struct Client *client, |
133 | const struct GNUNET_MessageHeader *msg, | ||
163 | int can_drop) | 134 | int can_drop) |
164 | { | 135 | { |
165 | #if DEBUG_CORE_CLIENT | 136 | #if DEBUG_CORE_CLIENT |
@@ -173,79 +144,142 @@ send_to_client (struct Client *client, const struct GNUNET_MessageHeader *msg, | |||
173 | } | 144 | } |
174 | 145 | ||
175 | 146 | ||
147 | /** | ||
148 | * Test if the client is interested in messages of the given type. | ||
149 | * | ||
150 | * @param type message type | ||
151 | * @param c client to test | ||
152 | * @return GNUNET_YES if 'c' is interested, GNUNET_NO if not. | ||
153 | */ | ||
154 | static int | ||
155 | type_match (uint16_t type, | ||
156 | struct Client *c) | ||
157 | { | ||
158 | unsigned int i; | ||
176 | 159 | ||
160 | for (i=0;i<c->tcnt;i++) | ||
161 | if (type == c->types[i]) | ||
162 | return GNUNET_YES; | ||
163 | return GNUNET_NO; | ||
164 | } | ||
177 | 165 | ||
178 | 166 | ||
179 | /** | 167 | /** |
180 | * Send a message to all of our current clients that have | 168 | * Send a message to all of our current clients that have the right |
181 | * the right options set. | 169 | * options set. |
182 | * | 170 | * |
183 | * @param msg message to multicast | 171 | * @param msg message to multicast |
184 | * @param can_drop can this message be discarded if the queue is too long | 172 | * @param can_drop can this message be discarded if the queue is too long |
185 | * @param options mask to use | 173 | * @param options mask to use |
174 | * @param type type of the embedded message, 0 for none | ||
186 | */ | 175 | */ |
187 | static void | 176 | static void |
188 | send_to_all_clients (const struct GNUNET_MessageHeader *msg, int can_drop, | 177 | send_to_all_clients (const struct GNUNET_MessageHeader *msg, |
189 | int options) | 178 | int can_drop, |
179 | int options, | ||
180 | uint16_t type) | ||
190 | { | 181 | { |
191 | struct Client *c; | 182 | struct Client *c; |
192 | 183 | ||
193 | c = clients; | 184 | for (c = client_head; c != NULL; c = c->next) |
194 | while (c != NULL) | ||
195 | { | 185 | { |
196 | if (0 != (c->options & options)) | 186 | if ( (0 == (c->options & options)) && |
197 | { | 187 | (GNUNET_YES != type_match (type, c)) ) |
188 | continue; | ||
198 | #if DEBUG_CORE_CLIENT > 1 | 189 | #if DEBUG_CORE_CLIENT > 1 |
199 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 190 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
200 | "Sending message of type %u to client.\n", | 191 | "Sending message of type %u to client.\n", |
201 | (unsigned int) ntohs (msg->type)); | 192 | (unsigned int) ntohs (msg->type)); |
202 | #endif | 193 | #endif |
203 | send_to_client (c, msg, can_drop); | 194 | send_to_client (c, msg, can_drop); |
204 | } | ||
205 | c = c->next; | ||
206 | } | 195 | } |
207 | } | 196 | } |
208 | 197 | ||
209 | 198 | ||
199 | /** | ||
200 | * Handle CORE_INIT request. | ||
201 | * | ||
202 | * @param cls unused | ||
203 | * @param client new client that sent INIT | ||
204 | * @param message the 'struct InitMessage' (presumably) | ||
205 | */ | ||
206 | static void | ||
207 | handle_client_init (void *cls, struct GNUNET_SERVER_Client *client, | ||
208 | const struct GNUNET_MessageHeader *message) | ||
209 | { | ||
210 | const struct InitMessage *im; | ||
211 | struct InitReplyMessage irm; | ||
212 | struct Client *c; | ||
213 | uint16_t msize; | ||
214 | const uint16_t *types; | ||
215 | uint16_t *wtypes; | ||
216 | unsigned int i; | ||
217 | |||
218 | /* check that we don't have an entry already */ | ||
219 | c = find_client (client); | ||
220 | if (NULL != c) | ||
221 | { | ||
222 | GNUNET_break (0); | ||
223 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
224 | return; | ||
225 | } | ||
226 | msize = ntohs (message->size); | ||
227 | if (msize < sizeof (struct InitMessage)) | ||
228 | { | ||
229 | GNUNET_break (0); | ||
230 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
231 | return; | ||
232 | } | ||
233 | GNUNET_SERVER_notification_context_add (notifier, client); | ||
234 | im = (const struct InitMessage *) message; | ||
235 | types = (const uint16_t *) &im[1]; | ||
236 | msize -= sizeof (struct InitMessage); | ||
237 | c = GNUNET_malloc (sizeof (struct Client) + msize); | ||
238 | c->client_handle = client; | ||
239 | c->tcnt = msize / sizeof (uint16_t); | ||
240 | c->options = ntohl (im->options); | ||
241 | c->types = (const uint16_t *) &c[1]; | ||
242 | wtypes = (uint16_t *) & c[1]; | ||
243 | for (i = 0; i < c->tcnt; i++) | ||
244 | wtypes[i] = ntohs (types[i]); | ||
245 | GSC_TYPEMAP_add (wtypes, c->tcnt); | ||
246 | GNUNET_CONTAINER_DLL_insert (client_head, | ||
247 | client_tail, | ||
248 | c); | ||
249 | #if DEBUG_CORE_CLIENT | ||
250 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
251 | "Client connecting to core service is interested in %u message types\n", | ||
252 | (unsigned int) c->tcnt); | ||
253 | #endif | ||
254 | /* send init reply message */ | ||
255 | irm.header.size = htons (sizeof (struct InitReplyMessage)); | ||
256 | irm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY); | ||
257 | irm.reserved = htonl (0); | ||
258 | irm.publicKey = GSC_my_public_key; | ||
259 | send_to_client (c, &irm.header, GNUNET_NO); | ||
260 | if (0 != (c->options & GNUNET_CORE_OPTION_SEND_CONNECT)) | ||
261 | GSC_SESSIONS_notify_client_about_sessions (c); | ||
262 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
263 | } | ||
264 | |||
210 | 265 | ||
211 | /** | 266 | /** |
212 | * Handle CORE_SEND_REQUEST message. | 267 | * Handle CORE_SEND_REQUEST message. |
268 | * | ||
269 | * @param cls unused | ||
270 | * @param client new client that sent CORE_SEND_REQUEST | ||
271 | * @param message the 'struct InitMessage' (presumably) | ||
213 | */ | 272 | */ |
214 | static void | 273 | static void |
215 | handle_client_send_request (void *cls, struct GNUNET_SERVER_Client *client, | 274 | handle_client_send_request (void *cls, struct GNUNET_SERVER_Client *client, |
216 | const struct GNUNET_MessageHeader *message) | 275 | const struct GNUNET_MessageHeader *message) |
217 | { | 276 | { |
218 | const struct SendMessageRequest *req; | 277 | const struct SendMessageRequest *req; |
219 | struct Neighbour *n; | ||
220 | struct Client *c; | 278 | struct Client *c; |
221 | struct ClientActiveRequest *car; | 279 | struct ClientActiveRequest *car; |
222 | 280 | ||
223 | req = (const struct SendMessageRequest *) message; | 281 | req = (const struct SendMessageRequest *) message; |
224 | if (0 == | 282 | c = find_client (client); |
225 | memcmp (&req->peer, &my_identity, sizeof (struct GNUNET_PeerIdentity))) | ||
226 | n = &self; | ||
227 | else | ||
228 | n = find_neighbour (&req->peer); | ||
229 | if ((n == NULL) || (GNUNET_YES != n->is_connected) || | ||
230 | (n->status != PEER_STATE_KEY_CONFIRMED)) | ||
231 | { | ||
232 | /* neighbour must have disconnected since request was issued, | ||
233 | * ignore (client will realize it once it processes the | ||
234 | * disconnect notification) */ | ||
235 | #if DEBUG_CORE_CLIENT | ||
236 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
237 | "Dropped client request for transmission (am disconnected)\n"); | ||
238 | #endif | ||
239 | GNUNET_STATISTICS_update (stats, | ||
240 | gettext_noop | ||
241 | ("# send requests dropped (disconnected)"), 1, | ||
242 | GNUNET_NO); | ||
243 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
244 | return; | ||
245 | } | ||
246 | c = clients; | ||
247 | while ((c != NULL) && (c->client_handle != client)) | ||
248 | c = c->next; | ||
249 | if (c == NULL) | 283 | if (c == NULL) |
250 | { | 284 | { |
251 | /* client did not send INIT first! */ | 285 | /* client did not send INIT first! */ |
@@ -255,10 +289,6 @@ handle_client_send_request (void *cls, struct GNUNET_SERVER_Client *client, | |||
255 | } | 289 | } |
256 | if (c->requests == NULL) | 290 | if (c->requests == NULL) |
257 | c->requests = GNUNET_CONTAINER_multihashmap_create (16); | 291 | c->requests = GNUNET_CONTAINER_multihashmap_create (16); |
258 | #if DEBUG_CORE_CLIENT | ||
259 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
260 | "Received client transmission request. queueing\n"); | ||
261 | #endif | ||
262 | car = GNUNET_CONTAINER_multihashmap_get (c->requests, &req->peer.hashPubKey); | 292 | car = GNUNET_CONTAINER_multihashmap_get (c->requests, &req->peer.hashPubKey); |
263 | if (car == NULL) | 293 | if (car == NULL) |
264 | { | 294 | { |
@@ -269,153 +299,109 @@ handle_client_send_request (void *cls, struct GNUNET_SERVER_Client *client, | |||
269 | &req->peer.hashPubKey, | 299 | &req->peer.hashPubKey, |
270 | car, | 300 | car, |
271 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)); | 301 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_FAST)); |
272 | GNUNET_CONTAINER_DLL_insert (n->active_client_request_head, | ||
273 | n->active_client_request_tail, car); | ||
274 | car->client = c; | 302 | car->client = c; |
275 | } | 303 | } |
304 | car->target = req->peer; | ||
305 | GNUNET_SERVER_client_keep (client); | ||
306 | car->client_handle = client; | ||
276 | car->deadline = GNUNET_TIME_absolute_ntoh (req->deadline); | 307 | car->deadline = GNUNET_TIME_absolute_ntoh (req->deadline); |
277 | car->priority = ntohl (req->priority); | 308 | car->priority = ntohl (req->priority); |
278 | car->queue_size = ntohl (req->queue_size); | ||
279 | car->msize = ntohs (req->size); | 309 | car->msize = ntohs (req->size); |
280 | car->smr_id = req->smr_id; | 310 | car->smr_id = req->smr_id; |
281 | schedule_peer_messages (n); | 311 | if (0 == |
312 | memcmp (&req->peer, &GSC_my_identity, sizeof (struct GNUNET_PeerIdentity))) | ||
313 | GSC_CLIENTS_solicit_request (car); | ||
314 | else | ||
315 | GSC_SESSIONS_queue_request (car); | ||
282 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | 316 | GNUNET_SERVER_receive_done (client, GNUNET_OK); |
283 | } | 317 | } |
284 | 318 | ||
285 | 319 | ||
286 | /** | 320 | /** |
287 | * Notify client about an existing connection to one of our neighbours. | 321 | * Handle CORE_SEND request. |
288 | */ | 322 | * |
289 | static int | 323 | * @param cls unused |
290 | notify_client_about_neighbour (void *cls, const GNUNET_HashCode * key, | 324 | * @param client the client issuing the request |
291 | void *value) | 325 | * @param message the "struct SendMessage" |
292 | { | ||
293 | struct Client *c = cls; | ||
294 | struct Neighbour *n = value; | ||
295 | size_t size; | ||
296 | char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1]; | ||
297 | struct GNUNET_TRANSPORT_ATS_Information *ats; | ||
298 | struct ConnectNotifyMessage *cnm; | ||
299 | |||
300 | size = | ||
301 | sizeof (struct ConnectNotifyMessage) + | ||
302 | (n->ats_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information); | ||
303 | if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE) | ||
304 | { | ||
305 | GNUNET_break (0); | ||
306 | /* recovery strategy: throw away performance data */ | ||
307 | GNUNET_array_grow (n->ats, n->ats_count, 0); | ||
308 | size = | ||
309 | sizeof (struct ConnectNotifyMessage) + | ||
310 | (n->ats_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information); | ||
311 | } | ||
312 | cnm = (struct ConnectNotifyMessage *) buf; | ||
313 | cnm->header.size = htons (size); | ||
314 | cnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT); | ||
315 | cnm->ats_count = htonl (n->ats_count); | ||
316 | ats = &cnm->ats; | ||
317 | memcpy (ats, n->ats, | ||
318 | sizeof (struct GNUNET_TRANSPORT_ATS_Information) * n->ats_count); | ||
319 | ats[n->ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR); | ||
320 | ats[n->ats_count].value = htonl (0); | ||
321 | if (n->status == PEER_STATE_KEY_CONFIRMED) | ||
322 | { | ||
323 | #if DEBUG_CORE_CLIENT | ||
324 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message to client.\n", | ||
325 | "NOTIFY_CONNECT"); | ||
326 | #endif | ||
327 | cnm->peer = n->peer; | ||
328 | send_to_client (c, &cnm->header, GNUNET_NO); | ||
329 | } | ||
330 | return GNUNET_OK; | ||
331 | } | ||
332 | |||
333 | |||
334 | |||
335 | /** | ||
336 | * Handle CORE_INIT request. | ||
337 | */ | 326 | */ |
338 | static void | 327 | static void |
339 | handle_client_init (void *cls, struct GNUNET_SERVER_Client *client, | 328 | handle_client_send (void *cls, struct GNUNET_SERVER_Client *client, |
340 | const struct GNUNET_MessageHeader *message) | 329 | const struct GNUNET_MessageHeader *message) |
341 | { | 330 | { |
342 | const struct InitMessage *im; | 331 | const struct SendMessage *sm; |
343 | struct InitReplyMessage irm; | ||
344 | struct Client *c; | 332 | struct Client *c; |
333 | struct ClientActiveRequest *car; | ||
345 | uint16_t msize; | 334 | uint16_t msize; |
346 | const uint16_t *types; | ||
347 | uint16_t *wtypes; | ||
348 | unsigned int i; | ||
349 | 335 | ||
350 | #if DEBUG_CORE_CLIENT | ||
351 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
352 | "Client connecting to core service with `%s' message\n", "INIT"); | ||
353 | #endif | ||
354 | /* check that we don't have an entry already */ | ||
355 | c = clients; | ||
356 | while (c != NULL) | ||
357 | { | ||
358 | if (client == c->client_handle) | ||
359 | { | ||
360 | GNUNET_break (0); | ||
361 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
362 | return; | ||
363 | } | ||
364 | c = c->next; | ||
365 | } | ||
366 | msize = ntohs (message->size); | 336 | msize = ntohs (message->size); |
367 | if (msize < sizeof (struct InitMessage)) | 337 | if (msize < |
338 | sizeof (struct SendMessage) + sizeof (struct GNUNET_MessageHeader)) | ||
368 | { | 339 | { |
369 | GNUNET_break (0); | 340 | GNUNET_break (0); |
370 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | 341 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); |
371 | return; | 342 | return; |
372 | } | 343 | } |
373 | GNUNET_SERVER_notification_context_add (notifier, client); | 344 | sm = (const struct SendMessage *) message; |
374 | im = (const struct InitMessage *) message; | 345 | msize -= sizeof (struct SendMessage); |
375 | types = (const uint16_t *) &im[1]; | 346 | GNUNET_break (0 == ntohl (sm->reserved)); |
376 | msize -= sizeof (struct InitMessage); | 347 | c = find_client (client); |
377 | c = GNUNET_malloc (sizeof (struct Client) + msize); | 348 | if (c == NULL) |
378 | c->client_handle = client; | ||
379 | c->next = clients; | ||
380 | clients = c; | ||
381 | c->tcnt = msize / sizeof (uint16_t); | ||
382 | c->types = (const uint16_t *) &c[1]; | ||
383 | wtypes = (uint16_t *) & c[1]; | ||
384 | for (i = 0; i < c->tcnt; i++) | ||
385 | { | 349 | { |
386 | wtypes[i] = ntohs (types[i]); | 350 | /* client did not send INIT first! */ |
387 | my_type_map[wtypes[i] / 32] |= (1 << (wtypes[i] % 32)); | 351 | GNUNET_break (0); |
352 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
353 | return; | ||
388 | } | 354 | } |
389 | if (c->tcnt > 0) | 355 | car = GNUNET_CONTAINER_multihashmap_get (c->requests, &sm->peer.hashPubKey); |
390 | broadcast_my_type_map (); | 356 | if (NULL == car) |
391 | c->options = ntohl (im->options); | ||
392 | #if DEBUG_CORE_CLIENT | ||
393 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
394 | "Client %p is interested in %u message types\n", c, | ||
395 | (unsigned int) c->tcnt); | ||
396 | #endif | ||
397 | /* send init reply message */ | ||
398 | irm.header.size = htons (sizeof (struct InitReplyMessage)); | ||
399 | irm.header.type = htons (GNUNET_MESSAGE_TYPE_CORE_INIT_REPLY); | ||
400 | irm.reserved = htonl (0); | ||
401 | memcpy (&irm.publicKey, &my_public_key, | ||
402 | sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)); | ||
403 | #if DEBUG_CORE_CLIENT | ||
404 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message to client.\n", | ||
405 | "INIT_REPLY"); | ||
406 | #endif | ||
407 | send_to_client (c, &irm.header, GNUNET_NO); | ||
408 | if (0 != (c->options & GNUNET_CORE_OPTION_SEND_CONNECT)) | ||
409 | { | 357 | { |
410 | /* notify new client about existing neighbours */ | 358 | /* client did not request transmission first! */ |
411 | GNUNET_CONTAINER_multihashmap_iterate (neighbours, | 359 | GNUNET_break (0); |
412 | ¬ify_client_about_neighbour, c); | 360 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); |
361 | return; | ||
413 | } | 362 | } |
363 | GNUNET_assert (GNUNET_YES == | ||
364 | GNUNET_CONTAINER_multihashmap_remove (c->requests, | ||
365 | &sm->peer.hashPubKey, | ||
366 | car)); | ||
367 | GNUNET_SERVER_mst_receive (client_mst, | ||
368 | car, | ||
369 | &sm[1], msize, | ||
370 | GNUNET_YES, | ||
371 | GNUNET_NO); | ||
372 | if (0 != | ||
373 | memcmp (&car->peer, &GSC_my_identity, sizeof (struct GNUNET_PeerIdentity))) | ||
374 | GSC_SESSIONS_dequeue_request (car); | ||
375 | GNUNET_free (car); | ||
414 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | 376 | GNUNET_SERVER_receive_done (client, GNUNET_OK); |
415 | } | 377 | } |
416 | 378 | ||
417 | 379 | ||
418 | /** | 380 | /** |
381 | * Functions with this signature are called whenever a complete | ||
382 | * message is received by the tokenizer. Used by the 'client_mst' for | ||
383 | * dispatching messages from clients to either the SESSION subsystem | ||
384 | * or other CLIENT (for loopback). | ||
385 | * | ||
386 | * @param cls closure | ||
387 | * @param client reservation request ('struct ClientActiveRequest') | ||
388 | * @param message the actual message | ||
389 | */ | ||
390 | static void | ||
391 | client_tokenizer_callback (void *cls, void *client, | ||
392 | const struct GNUNET_MessageHeader *message) | ||
393 | { | ||
394 | struct ClientActiveRequest *car = client; | ||
395 | |||
396 | if (0 == | ||
397 | memcmp (&car->peer, &GSC_my_identity, sizeof (struct GNUNET_PeerIdentity))) | ||
398 | GDS_CLIENTS_deliver_message (&GSC_my_identity, &payload->header); | ||
399 | else | ||
400 | GSC_SESSIONS_transmit (car, &payload->header); | ||
401 | } | ||
402 | |||
403 | |||
404 | /** | ||
419 | * Free client request records. | 405 | * Free client request records. |
420 | * | 406 | * |
421 | * @param cls NULL | 407 | * @param cls NULL |
@@ -428,14 +414,8 @@ destroy_active_client_request (void *cls, const GNUNET_HashCode * key, | |||
428 | void *value) | 414 | void *value) |
429 | { | 415 | { |
430 | struct ClientActiveRequest *car = value; | 416 | struct ClientActiveRequest *car = value; |
431 | struct Neighbour *n; | ||
432 | struct GNUNET_PeerIdentity peer; | ||
433 | 417 | ||
434 | peer.hashPubKey = *key; | 418 | GSC_SESSIONS_dequeue_request (car); |
435 | n = find_neighbour (&peer); | ||
436 | GNUNET_assert (NULL != n); | ||
437 | GNUNET_CONTAINER_DLL_remove (n->active_client_request_head, | ||
438 | n->active_client_request_tail, car); | ||
439 | GNUNET_free (car); | 419 | GNUNET_free (car); |
440 | return GNUNET_YES; | 420 | return GNUNET_YES; |
441 | } | 421 | } |
@@ -448,12 +428,10 @@ destroy_active_client_request (void *cls, const GNUNET_HashCode * key, | |||
448 | * @param client identification of the client | 428 | * @param client identification of the client |
449 | */ | 429 | */ |
450 | static void | 430 | static void |
451 | handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) | 431 | handle_client_disconnect (void *cls, |
432 | struct GNUNET_SERVER_Client *client) | ||
452 | { | 433 | { |
453 | struct Client *pos; | 434 | struct Client *c; |
454 | struct Client *prev; | ||
455 | unsigned int i; | ||
456 | const uint16_t *wtypes; | ||
457 | 435 | ||
458 | if (client == NULL) | 436 | if (client == NULL) |
459 | return; | 437 | return; |
@@ -461,214 +439,110 @@ handle_client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) | |||
461 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 439 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
462 | "Client %p has disconnected from core service.\n", client); | 440 | "Client %p has disconnected from core service.\n", client); |
463 | #endif | 441 | #endif |
464 | prev = NULL; | 442 | c = find_client (client); |
465 | pos = clients; | 443 | if (c == NULL) |
466 | while (pos != NULL) | 444 | return; /* client never sent INIT */ |
467 | { | 445 | GNUNET_CONTAINER_DLL_remove (client_head, |
468 | if (client == pos->client_handle) | 446 | client_tail, |
469 | break; | 447 | c); |
470 | prev = pos; | 448 | if (c->requests != NULL) |
471 | pos = pos->next; | ||
472 | } | ||
473 | if (pos == NULL) | ||
474 | { | ||
475 | /* client never sent INIT */ | ||
476 | return; | ||
477 | } | ||
478 | if (prev == NULL) | ||
479 | clients = pos->next; | ||
480 | else | ||
481 | prev->next = pos->next; | ||
482 | if (pos->requests != NULL) | ||
483 | { | 449 | { |
484 | GNUNET_CONTAINER_multihashmap_iterate (pos->requests, | 450 | GNUNET_CONTAINER_multihashmap_iterate (c->requests, |
485 | &destroy_active_client_request, | 451 | &destroy_active_client_request, |
486 | NULL); | 452 | NULL); |
487 | GNUNET_CONTAINER_multihashmap_destroy (pos->requests); | 453 | GNUNET_CONTAINER_multihashmap_destroy (c->requests); |
488 | } | ||
489 | GNUNET_free (pos); | ||
490 | |||
491 | /* rebuild my_type_map */ | ||
492 | memset (my_type_map, 0, sizeof (my_type_map)); | ||
493 | for (pos = clients; NULL != pos; pos = pos->next) | ||
494 | { | ||
495 | wtypes = (const uint16_t *) &pos[1]; | ||
496 | for (i = 0; i < pos->tcnt; i++) | ||
497 | my_type_map[wtypes[i] / 32] |= (1 << (wtypes[i] % 32)); | ||
498 | } | 454 | } |
499 | broadcast_my_type_map (); | 455 | GSC_TYPEMAP_remove (c->types, c->tcnt); |
456 | GNUNET_free (c); | ||
500 | } | 457 | } |
501 | 458 | ||
502 | 459 | ||
503 | 460 | ||
504 | 461 | ||
505 | 462 | ||
463 | |||
464 | // FIXME from here....................................... | ||
465 | |||
466 | |||
467 | |||
506 | /** | 468 | /** |
507 | * Handle CORE_SEND request. | 469 | * Tell a client that we are ready to receive the message. |
508 | * | 470 | * |
509 | * @param cls unused | 471 | * @param car request that is now ready; the responsibility |
510 | * @param client the client issuing the request | 472 | * for the handle remains shared between CLIENTS |
511 | * @param message the "struct SendMessage" | 473 | * and SESSIONS after this call. |
512 | */ | 474 | */ |
513 | static void | 475 | void |
514 | handle_client_send (void *cls, struct GNUNET_SERVER_Client *client, | 476 | GSC_CLIENTS_solicit_request (struct GSC_ClientActiveRequest *car) |
515 | const struct GNUNET_MessageHeader *message) | ||
516 | { | 477 | { |
517 | const struct SendMessage *sm; | 478 | } |
518 | struct Neighbour *n; | ||
519 | struct MessageEntry *prev; | ||
520 | struct MessageEntry *pos; | ||
521 | struct MessageEntry *e; | ||
522 | struct MessageEntry *min_prio_entry; | ||
523 | struct MessageEntry *min_prio_prev; | ||
524 | unsigned int min_prio; | ||
525 | unsigned int queue_size; | ||
526 | uint16_t msize; | ||
527 | 479 | ||
528 | msize = ntohs (message->size); | 480 | |
529 | if (msize < | 481 | /** |
530 | sizeof (struct SendMessage) + sizeof (struct GNUNET_MessageHeader)) | 482 | * Tell a client that we will never be ready to receive the |
483 | * given message in time (disconnect or timeout). | ||
484 | * | ||
485 | * @param car request that now permanently failed; the | ||
486 | * responsibility for the handle is now returned | ||
487 | * to CLIENTS (SESSIONS is done with it). | ||
488 | */ | ||
489 | void | ||
490 | GSC_CLIENTS_reject_request (struct GSC_ClientActiveRequest *car) | ||
491 | { | ||
492 | } | ||
493 | |||
494 | |||
495 | |||
496 | |||
497 | /** | ||
498 | * Notify client about an existing connection to one of our neighbours. | ||
499 | */ | ||
500 | static int | ||
501 | notify_client_about_neighbour (void *cls, const GNUNET_HashCode * key, | ||
502 | void *value) | ||
503 | { | ||
504 | struct Client *c = cls; | ||
505 | struct Neighbour *n = value; | ||
506 | size_t size; | ||
507 | char buf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1]; | ||
508 | struct GNUNET_TRANSPORT_ATS_Information *ats; | ||
509 | struct ConnectNotifyMessage *cnm; | ||
510 | |||
511 | size = | ||
512 | sizeof (struct ConnectNotifyMessage) + | ||
513 | (n->ats_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information); | ||
514 | if (size >= GNUNET_SERVER_MAX_MESSAGE_SIZE) | ||
531 | { | 515 | { |
532 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
533 | "msize is %u, should be at least %u (in %s:%d)\n", msize, | ||
534 | sizeof (struct SendMessage) + | ||
535 | sizeof (struct GNUNET_MessageHeader), __FILE__, __LINE__); | ||
536 | GNUNET_break (0); | 516 | GNUNET_break (0); |
537 | if (client != NULL) | 517 | /* recovery strategy: throw away performance data */ |
538 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | 518 | GNUNET_array_grow (n->ats, n->ats_count, 0); |
539 | return; | 519 | size = |
540 | } | 520 | sizeof (struct ConnectNotifyMessage) + |
541 | sm = (const struct SendMessage *) message; | 521 | (n->ats_count) * sizeof (struct GNUNET_TRANSPORT_ATS_Information); |
542 | msize -= sizeof (struct SendMessage); | ||
543 | if (0 == | ||
544 | memcmp (&sm->peer, &my_identity, sizeof (struct GNUNET_PeerIdentity))) | ||
545 | { | ||
546 | /* loopback */ | ||
547 | GNUNET_SERVER_mst_receive (mst, &self, (const char *) &sm[1], msize, | ||
548 | GNUNET_YES, GNUNET_NO); | ||
549 | if (client != NULL) | ||
550 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
551 | return; | ||
552 | } | ||
553 | n = find_neighbour (&sm->peer); | ||
554 | if ((n == NULL) || (GNUNET_YES != n->is_connected) || | ||
555 | (n->status != PEER_STATE_KEY_CONFIRMED)) | ||
556 | { | ||
557 | /* attempt to send message to peer that is not connected anymore | ||
558 | * (can happen due to asynchrony) */ | ||
559 | GNUNET_STATISTICS_update (stats, | ||
560 | gettext_noop | ||
561 | ("# messages discarded (disconnected)"), 1, | ||
562 | GNUNET_NO); | ||
563 | if (client != NULL) | ||
564 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
565 | return; | ||
566 | } | ||
567 | #if DEBUG_CORE | ||
568 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
569 | "Core received `%s' request, queueing %u bytes of plaintext data for transmission to `%4s'.\n", | ||
570 | "SEND", (unsigned int) msize, GNUNET_i2s (&sm->peer)); | ||
571 | #endif | ||
572 | discard_expired_messages (n); | ||
573 | /* bound queue size */ | ||
574 | /* NOTE: this entire block to bound the queue size should be | ||
575 | * obsolete with the new client-request code and the | ||
576 | * 'schedule_peer_messages' mechanism; we still have this code in | ||
577 | * here for now as a sanity check for the new mechanmism; | ||
578 | * ultimately, we should probably simply reject SEND messages that | ||
579 | * are not 'approved' (or provide a new core API for very unreliable | ||
580 | * delivery that always sends with priority 0). Food for thought. */ | ||
581 | min_prio = UINT32_MAX; | ||
582 | min_prio_entry = NULL; | ||
583 | min_prio_prev = NULL; | ||
584 | queue_size = 0; | ||
585 | prev = NULL; | ||
586 | pos = n->messages; | ||
587 | while (pos != NULL) | ||
588 | { | ||
589 | if (pos->priority <= min_prio) | ||
590 | { | ||
591 | min_prio_entry = pos; | ||
592 | min_prio_prev = prev; | ||
593 | min_prio = pos->priority; | ||
594 | } | ||
595 | queue_size++; | ||
596 | prev = pos; | ||
597 | pos = pos->next; | ||
598 | } | 522 | } |
599 | if (queue_size >= MAX_PEER_QUEUE_SIZE) | 523 | cnm = (struct ConnectNotifyMessage *) buf; |
524 | cnm->header.size = htons (size); | ||
525 | cnm->header.type = htons (GNUNET_MESSAGE_TYPE_CORE_NOTIFY_CONNECT); | ||
526 | cnm->ats_count = htonl (n->ats_count); | ||
527 | ats = &cnm->ats; | ||
528 | memcpy (ats, n->ats, | ||
529 | sizeof (struct GNUNET_TRANSPORT_ATS_Information) * n->ats_count); | ||
530 | ats[n->ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR); | ||
531 | ats[n->ats_count].value = htonl (0); | ||
532 | if (n->status == PEER_STATE_KEY_CONFIRMED) | ||
600 | { | 533 | { |
601 | /* queue full */ | 534 | #if DEBUG_CORE_CLIENT |
602 | if (ntohl (sm->priority) <= min_prio) | 535 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending `%s' message to client.\n", |
603 | { | 536 | "NOTIFY_CONNECT"); |
604 | /* discard new entry; this should no longer happen! */ | ||
605 | GNUNET_break (0); | ||
606 | #if DEBUG_CORE | ||
607 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
608 | "Queue full (%u/%u), discarding new request (%u bytes of type %u)\n", | ||
609 | queue_size, (unsigned int) MAX_PEER_QUEUE_SIZE, | ||
610 | (unsigned int) msize, (unsigned int) ntohs (message->type)); | ||
611 | #endif | ||
612 | GNUNET_STATISTICS_update (stats, | ||
613 | gettext_noop ("# discarded CORE_SEND requests"), | ||
614 | 1, GNUNET_NO); | ||
615 | |||
616 | if (client != NULL) | ||
617 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
618 | return; | ||
619 | } | ||
620 | GNUNET_assert (min_prio_entry != NULL); | ||
621 | /* discard "min_prio_entry" */ | ||
622 | #if DEBUG_CORE | ||
623 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
624 | "Queue full, discarding existing older request\n"); | ||
625 | #endif | ||
626 | GNUNET_STATISTICS_update (stats, | ||
627 | gettext_noop | ||
628 | ("# discarded lower priority CORE_SEND requests"), | ||
629 | 1, GNUNET_NO); | ||
630 | if (min_prio_prev == NULL) | ||
631 | n->messages = min_prio_entry->next; | ||
632 | else | ||
633 | min_prio_prev->next = min_prio_entry->next; | ||
634 | GNUNET_free (min_prio_entry); | ||
635 | } | ||
636 | |||
637 | #if DEBUG_CORE | ||
638 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
639 | "Adding transmission request for `%4s' of size %u to queue\n", | ||
640 | GNUNET_i2s (&sm->peer), (unsigned int) msize); | ||
641 | #endif | 537 | #endif |
642 | GNUNET_break (0 == ntohl (sm->reserved)); | 538 | cnm->peer = n->peer; |
643 | e = GNUNET_malloc (sizeof (struct MessageEntry) + msize); | 539 | send_to_client (c, &cnm->header, GNUNET_NO); |
644 | e->deadline = GNUNET_TIME_absolute_ntoh (sm->deadline); | ||
645 | e->priority = ntohl (sm->priority); | ||
646 | e->size = msize; | ||
647 | if (GNUNET_YES != (int) ntohl (sm->cork)) | ||
648 | e->got_slack = GNUNET_YES; | ||
649 | memcpy (&e[1], &sm[1], msize); | ||
650 | |||
651 | /* insert, keep list sorted by deadline */ | ||
652 | prev = NULL; | ||
653 | pos = n->messages; | ||
654 | while ((pos != NULL) && (pos->deadline.abs_value < e->deadline.abs_value)) | ||
655 | { | ||
656 | prev = pos; | ||
657 | pos = pos->next; | ||
658 | } | 540 | } |
659 | if (prev == NULL) | 541 | return GNUNET_OK; |
660 | n->messages = e; | ||
661 | else | ||
662 | prev->next = e; | ||
663 | e->next = pos; | ||
664 | |||
665 | /* consider scheduling now */ | ||
666 | process_plaintext_neighbour_queue (n); | ||
667 | if (client != NULL) | ||
668 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
669 | } | 542 | } |
670 | 543 | ||
671 | 544 | ||
545 | |||
672 | /** | 546 | /** |
673 | * Helper function for handle_client_iterate_peers. | 547 | * Helper function for handle_client_iterate_peers. |
674 | * | 548 | * |
@@ -956,16 +830,36 @@ send_p2p_message_to_client (struct Neighbour *sender, struct Client *client, | |||
956 | 830 | ||
957 | 831 | ||
958 | 832 | ||
833 | /** | ||
834 | * Notify a particular client about a change to existing connection to | ||
835 | * one of our neighbours (check if the client is interested). Called | ||
836 | * from 'GSC_SESSIONS_notify_client_about_sessions'. | ||
837 | * | ||
838 | * @param client client to notify | ||
839 | * @param neighbour identity of the neighbour that changed status | ||
840 | * @param tmap_old previous type map for the neighbour, NULL for disconnect | ||
841 | * @param tmap_new updated type map for the neighbour, NULL for disconnect | ||
842 | */ | ||
843 | void | ||
844 | GDS_CLIENTS_notify_client_about_neighbour (struct GSC_Client *client, | ||
845 | const struct GNUNET_PeerIdentity *neighbour, | ||
846 | const struct GSC_TypeMap *tmap_old, | ||
847 | const struct GSC_TypeMap *tmap_new) | ||
848 | { | ||
849 | } | ||
850 | |||
959 | 851 | ||
960 | /** | 852 | /** |
961 | * Notify client about a change to existing connection to one of our neighbours. | 853 | * Notify client about a change to existing connection to one of our neighbours. |
962 | * | 854 | * |
963 | * @param neighbour identity of the neighbour that changed status | 855 | * @param neighbour identity of the neighbour that changed status |
964 | * @param tmap updated type map for the neighbour, NULL for disconnect | 856 | * @param tmap_old previous type map for the neighbour, NULL for disconnect |
857 | * @param tmap_new updated type map for the neighbour, NULL for disconnect | ||
965 | */ | 858 | */ |
966 | void | 859 | void |
967 | GDS_CLIENTS_notify_clients_about_neighbour (const struct GNUNET_PeerIdentity *neighbour, | 860 | GDS_CLIENTS_notify_clients_about_neighbour (const struct GNUNET_PeerIdentity *neighbour, |
968 | const struct GSC_TypeMap *tmap) | 861 | const struct GSC_TypeMap *tmap_old, |
862 | const struct GSC_TypeMap *tmap_new) | ||
969 | { | 863 | { |
970 | } | 864 | } |
971 | 865 | ||
@@ -1050,7 +944,11 @@ GSC_CLIENTS_deliver_message (const struct GNUNET_PeerIdentity *sender, | |||
1050 | } | 944 | } |
1051 | 945 | ||
1052 | 946 | ||
1053 | 947 | /** | |
948 | * Initialize clients subsystem. | ||
949 | * | ||
950 | * @param server handle to server clients connect to | ||
951 | */ | ||
1054 | void | 952 | void |
1055 | GSC_CLIENTS_init (struct GNUNET_SERVER_Handle *server) | 953 | GSC_CLIENTS_init (struct GNUNET_SERVER_Handle *server) |
1056 | { | 954 | { |
@@ -1076,27 +974,28 @@ GSC_CLIENTS_init (struct GNUNET_SERVER_Handle *server) | |||
1076 | }; | 974 | }; |
1077 | 975 | ||
1078 | /* setup notification */ | 976 | /* setup notification */ |
977 | client_mst = GNUNET_SERVER_mst_create (&client_tokenizer_callback, NULL); | ||
1079 | notifier = | 978 | notifier = |
1080 | GNUNET_SERVER_notification_context_create (server, MAX_NOTIFY_QUEUE); | 979 | GNUNET_SERVER_notification_context_create (server, MAX_NOTIFY_QUEUE); |
1081 | GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL); | 980 | GNUNET_SERVER_disconnect_notify (server, &handle_client_disconnect, NULL); |
1082 | GNUNET_SERVER_add_handlers (server, handlers); | 981 | GNUNET_SERVER_add_handlers (server, handlers); |
1083 | mst = GNUNET_SERVER_mst_create (&deliver_message, NULL); | ||
1084 | } | 982 | } |
1085 | 983 | ||
1086 | 984 | ||
985 | /** | ||
986 | * Shutdown clients subsystem. | ||
987 | */ | ||
1087 | void | 988 | void |
1088 | GSC_CLIENTS_done () | 989 | GSC_CLIENTS_done () |
1089 | { | 990 | { |
1090 | struct Client *c; | 991 | struct Client *c; |
1091 | 992 | ||
1092 | while (NULL != (c = clients)) | 993 | while (NULL != (c = client_head)) |
1093 | handle_client_disconnect (NULL, c->client_handle); | 994 | handle_client_disconnect (NULL, c->client_handle); |
1094 | GNUNET_SERVER_notification_context_destroy (notifier); | 995 | GNUNET_SERVER_notification_context_destroy (notifier); |
1095 | notifier = NULL; | 996 | notifier = NULL; |
1096 | if (mst != NULL) | 997 | GNUNET_SERVER_MST_destroy (client_mst); |
1097 | { | 998 | client_mst = NULL; |
1098 | GNUNET_SERVER_mst_destroy (mst); | ||
1099 | mst = NULL; | ||
1100 | } | ||
1101 | |||
1102 | } | 999 | } |
1000 | |||
1001 | /* end of gnunet-service-core_clients.c */ | ||