diff options
author | Christian Grothoff <christian@grothoff.org> | 2016-09-20 19:53:24 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2016-09-20 19:53:24 +0000 |
commit | 03f0ae4bb10cf55bb9bab601d45fd96c2eb13603 (patch) | |
tree | 9089fc11319e7de97c43d2e0bf8e6d9b67836b92 /src/transport | |
parent | 450982bb56fde81bd512cb21360b809482caf19b (diff) | |
download | gnunet-03f0ae4bb10cf55bb9bab601d45fd96c2eb13603.tar.gz gnunet-03f0ae4bb10cf55bb9bab601d45fd96c2eb13603.zip |
migrating transport service to new MQ API
Diffstat (limited to 'src/transport')
-rw-r--r-- | src/transport/Makefile.am | 2 | ||||
-rw-r--r-- | src/transport/gnunet-service-transport.c | 2103 | ||||
-rw-r--r-- | src/transport/gnunet-service-transport.h | 112 | ||||
-rw-r--r-- | src/transport/gnunet-service-transport_blacklist.c | 933 | ||||
-rw-r--r-- | src/transport/gnunet-service-transport_blacklist.h | 159 | ||||
-rw-r--r-- | src/transport/gnunet-service-transport_clients.c | 1491 | ||||
-rw-r--r-- | src/transport/gnunet-service-transport_clients.h | 101 | ||||
-rw-r--r-- | src/transport/gnunet-service-transport_manipulation.c | 20 | ||||
-rw-r--r-- | src/transport/gnunet-service-transport_manipulation.h | 8 | ||||
-rw-r--r-- | src/transport/gnunet-service-transport_neighbours.c | 2 | ||||
-rw-r--r-- | src/transport/gnunet-service-transport_validation.c | 2 | ||||
-rw-r--r-- | src/transport/test_transport_api_manipulation_recv_tcp.c | 16 | ||||
-rw-r--r-- | src/transport/test_transport_api_manipulation_send_tcp.c | 22 |
13 files changed, 2195 insertions, 2776 deletions
diff --git a/src/transport/Makefile.am b/src/transport/Makefile.am index 2d79ae534..9fb451383 100644 --- a/src/transport/Makefile.am +++ b/src/transport/Makefile.am | |||
@@ -253,8 +253,6 @@ gnunet_transport_LDADD = \ | |||
253 | gnunet_service_transport_SOURCES = \ | 253 | gnunet_service_transport_SOURCES = \ |
254 | gnunet-service-transport.c gnunet-service-transport.h \ | 254 | gnunet-service-transport.c gnunet-service-transport.h \ |
255 | gnunet-service-transport_ats.h gnunet-service-transport_ats.c \ | 255 | gnunet-service-transport_ats.h gnunet-service-transport_ats.c \ |
256 | gnunet-service-transport_blacklist.h gnunet-service-transport_blacklist.c \ | ||
257 | gnunet-service-transport_clients.h gnunet-service-transport_clients.c \ | ||
258 | gnunet-service-transport_hello.h gnunet-service-transport_hello.c \ | 256 | gnunet-service-transport_hello.h gnunet-service-transport_hello.c \ |
259 | gnunet-service-transport_neighbours.h gnunet-service-transport_neighbours.c \ | 257 | gnunet-service-transport_neighbours.h gnunet-service-transport_neighbours.c \ |
260 | gnunet-service-transport_plugins.h gnunet-service-transport_plugins.c \ | 258 | gnunet-service-transport_plugins.h gnunet-service-transport_plugins.c \ |
diff --git a/src/transport/gnunet-service-transport.c b/src/transport/gnunet-service-transport.c index a21ddabd6..e7b221344 100644 --- a/src/transport/gnunet-service-transport.c +++ b/src/transport/gnunet-service-transport.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | This file is part of GNUnet. | 2 | This file is part of GNUnet. |
3 | Copyright (C) 2010-2015 GNUnet e.V. | 3 | Copyright (C) 2010-2016 GNUnet e.V. |
4 | 4 | ||
5 | GNUnet is free software; you can redistribute it and/or modify | 5 | GNUnet is free software; you can redistribute it and/or modify |
6 | it under the terms of the GNU General Public License as published | 6 | it under the terms of the GNU General Public License as published |
@@ -31,8 +31,6 @@ | |||
31 | #include "gnunet_ats_service.h" | 31 | #include "gnunet_ats_service.h" |
32 | #include "gnunet-service-transport.h" | 32 | #include "gnunet-service-transport.h" |
33 | #include "gnunet-service-transport_ats.h" | 33 | #include "gnunet-service-transport_ats.h" |
34 | #include "gnunet-service-transport_blacklist.h" | ||
35 | #include "gnunet-service-transport_clients.h" | ||
36 | #include "gnunet-service-transport_hello.h" | 34 | #include "gnunet-service-transport_hello.h" |
37 | #include "gnunet-service-transport_neighbours.h" | 35 | #include "gnunet-service-transport_neighbours.h" |
38 | #include "gnunet-service-transport_plugins.h" | 36 | #include "gnunet-service-transport_plugins.h" |
@@ -40,6 +38,25 @@ | |||
40 | #include "gnunet-service-transport_manipulation.h" | 38 | #include "gnunet-service-transport_manipulation.h" |
41 | #include "transport.h" | 39 | #include "transport.h" |
42 | 40 | ||
41 | /** | ||
42 | * Size of the blacklist hash map. | ||
43 | */ | ||
44 | #define TRANSPORT_BLACKLIST_HT_SIZE 64 | ||
45 | |||
46 | /** | ||
47 | * How many messages can we have pending for a given client process | ||
48 | * before we start to drop incoming messages? We typically should | ||
49 | * have only one client and so this would be the primary buffer for | ||
50 | * messages, so the number should be chosen rather generously. | ||
51 | * | ||
52 | * The expectation here is that most of the time the queue is large | ||
53 | * enough so that a drop is virtually never required. Note that | ||
54 | * this value must be about as large as 'TOTAL_MSGS' in the | ||
55 | * 'test_transport_api_reliability.c', otherwise that testcase may | ||
56 | * fail. | ||
57 | */ | ||
58 | #define MAX_PENDING (128 * 1024) | ||
59 | |||
43 | 60 | ||
44 | /** | 61 | /** |
45 | * Information we need for an asynchronous session kill. | 62 | * Information we need for an asynchronous session kill. |
@@ -73,7 +90,279 @@ struct GNUNET_ATS_SessionKiller | |||
73 | }; | 90 | }; |
74 | 91 | ||
75 | 92 | ||
76 | /* globals */ | 93 | /** |
94 | * What type of client is the `struct TransportClient` about? | ||
95 | */ | ||
96 | enum ClientType | ||
97 | { | ||
98 | /** | ||
99 | * We do not know yet (client is fresh). | ||
100 | */ | ||
101 | CT_NONE = 0, | ||
102 | |||
103 | /** | ||
104 | * Is the CORE service, we need to forward traffic to it. | ||
105 | */ | ||
106 | CT_CORE = 1, | ||
107 | |||
108 | /** | ||
109 | * It is a monitor, forward monitor data. | ||
110 | */ | ||
111 | CT_MONITOR = 2, | ||
112 | |||
113 | /** | ||
114 | * It is a blacklist, query about allowed connections. | ||
115 | */ | ||
116 | CT_BLACKLIST = 3 | ||
117 | }; | ||
118 | |||
119 | |||
120 | /** | ||
121 | * Context we use when performing a blacklist check. | ||
122 | */ | ||
123 | struct GST_BlacklistCheck; | ||
124 | |||
125 | /** | ||
126 | * Client connected to the transport service. | ||
127 | */ | ||
128 | struct TransportClient | ||
129 | { | ||
130 | |||
131 | /** | ||
132 | * This is a doubly-linked list. | ||
133 | */ | ||
134 | struct TransportClient *next; | ||
135 | |||
136 | /** | ||
137 | * This is a doubly-linked list. | ||
138 | */ | ||
139 | struct TransportClient *prev; | ||
140 | |||
141 | /** | ||
142 | * Handle to the client. | ||
143 | */ | ||
144 | struct GNUNET_SERVICE_Client *client; | ||
145 | |||
146 | /** | ||
147 | * Message queue to the client. | ||
148 | */ | ||
149 | struct GNUNET_MQ_Handle *mq; | ||
150 | |||
151 | /** | ||
152 | * What type of client is this? | ||
153 | */ | ||
154 | enum ClientType type; | ||
155 | |||
156 | union { | ||
157 | |||
158 | /** | ||
159 | * Peer identity to monitor the addresses of. | ||
160 | * Zero to monitor all neighbours. Valid if | ||
161 | * @e type is CT_MONITOR. | ||
162 | */ | ||
163 | struct GNUNET_PeerIdentity monitor_peer; | ||
164 | |||
165 | /** | ||
166 | * Additional details if @e type is CT_BLACKLIST. | ||
167 | */ | ||
168 | struct { | ||
169 | |||
170 | /** | ||
171 | * Blacklist check that we're currently performing (or NULL | ||
172 | * if we're performing one that has been cancelled). | ||
173 | */ | ||
174 | struct GST_BlacklistCheck *bc; | ||
175 | |||
176 | /** | ||
177 | * Set to #GNUNET_YES if we're currently waiting for a reply. | ||
178 | */ | ||
179 | int waiting_for_reply; | ||
180 | |||
181 | /** | ||
182 | * #GNUNET_YES if we have to call receive_done for this client | ||
183 | */ | ||
184 | int call_receive_done; | ||
185 | |||
186 | } blacklist; | ||
187 | |||
188 | } details; | ||
189 | |||
190 | }; | ||
191 | |||
192 | |||
193 | |||
194 | /** | ||
195 | * Context we use when performing a blacklist check. | ||
196 | */ | ||
197 | struct GST_BlacklistCheck | ||
198 | { | ||
199 | |||
200 | /** | ||
201 | * This is a linked list. | ||
202 | */ | ||
203 | struct GST_BlacklistCheck *next; | ||
204 | |||
205 | /** | ||
206 | * This is a linked list. | ||
207 | */ | ||
208 | struct GST_BlacklistCheck *prev; | ||
209 | |||
210 | /** | ||
211 | * Peer being checked. | ||
212 | */ | ||
213 | struct GNUNET_PeerIdentity peer; | ||
214 | |||
215 | /** | ||
216 | * Continuation to call with the result. | ||
217 | */ | ||
218 | GST_BlacklistTestContinuation cont; | ||
219 | |||
220 | /** | ||
221 | * Closure for @e cont. | ||
222 | */ | ||
223 | void *cont_cls; | ||
224 | |||
225 | /** | ||
226 | * Address for #GST_blacklist_abort_matching(), can be NULL. | ||
227 | */ | ||
228 | struct GNUNET_HELLO_Address *address; | ||
229 | |||
230 | /** | ||
231 | * Session for #GST_blacklist_abort_matching(), can be NULL. | ||
232 | */ | ||
233 | struct GNUNET_ATS_Session *session; | ||
234 | |||
235 | /** | ||
236 | * Our current position in the blacklisters list. | ||
237 | */ | ||
238 | struct TransportClient *bl_pos; | ||
239 | |||
240 | /** | ||
241 | * Current task performing the check. | ||
242 | */ | ||
243 | struct GNUNET_SCHEDULER_Task *task; | ||
244 | |||
245 | }; | ||
246 | |||
247 | |||
248 | /** | ||
249 | * Context for address to string operations | ||
250 | */ | ||
251 | struct AddressToStringContext | ||
252 | { | ||
253 | /** | ||
254 | * This is a doubly-linked list. | ||
255 | */ | ||
256 | struct AddressToStringContext *next; | ||
257 | |||
258 | /** | ||
259 | * This is a doubly-linked list. | ||
260 | */ | ||
261 | struct AddressToStringContext *prev; | ||
262 | |||
263 | /** | ||
264 | * Client that made the request. | ||
265 | */ | ||
266 | struct TransportClient* tc; | ||
267 | }; | ||
268 | |||
269 | |||
270 | /** | ||
271 | * Closure for #handle_send_transmit_continuation() | ||
272 | */ | ||
273 | struct SendTransmitContinuationContext | ||
274 | { | ||
275 | |||
276 | /** | ||
277 | * Client that made the request. | ||
278 | */ | ||
279 | struct TransportClient *tc; | ||
280 | |||
281 | /** | ||
282 | * Peer that was the target. | ||
283 | */ | ||
284 | struct GNUNET_PeerIdentity target; | ||
285 | |||
286 | /** | ||
287 | * At what time did we receive the message? | ||
288 | */ | ||
289 | struct GNUNET_TIME_Absolute send_time; | ||
290 | |||
291 | /** | ||
292 | * Unique ID, for logging. | ||
293 | */ | ||
294 | unsigned long long uuid; | ||
295 | |||
296 | /** | ||
297 | * Set to #GNUNET_YES if the connection for @e target goes | ||
298 | * down and we thus must no longer send the | ||
299 | * #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK message. | ||
300 | */ | ||
301 | int down; | ||
302 | }; | ||
303 | |||
304 | |||
305 | /** | ||
306 | * Head of linked list of all clients to this service. | ||
307 | */ | ||
308 | static struct TransportClient *clients_head; | ||
309 | |||
310 | /** | ||
311 | * Tail of linked list of all clients to this service. | ||
312 | */ | ||
313 | static struct TransportClient *clients_tail; | ||
314 | |||
315 | /** | ||
316 | * Map of peer identities to active send transmit continuation | ||
317 | * contexts. Used to flag contexts as 'dead' when a connection goes | ||
318 | * down. Values are of type `struct SendTransmitContinuationContext | ||
319 | * *`. | ||
320 | */ | ||
321 | static struct GNUNET_CONTAINER_MultiPeerMap *active_stccs; | ||
322 | |||
323 | /** | ||
324 | * Head of linked list of all pending address iterations | ||
325 | */ | ||
326 | static struct AddressToStringContext *a2s_head; | ||
327 | |||
328 | /** | ||
329 | * Tail of linked list of all pending address iterations | ||
330 | */ | ||
331 | static struct AddressToStringContext *a2s_tail; | ||
332 | |||
333 | /** | ||
334 | * Head of DLL of active blacklisting queries. | ||
335 | */ | ||
336 | static struct GST_BlacklistCheck *bc_head; | ||
337 | |||
338 | /** | ||
339 | * Tail of DLL of active blacklisting queries. | ||
340 | */ | ||
341 | static struct GST_BlacklistCheck *bc_tail; | ||
342 | |||
343 | /** | ||
344 | * Hashmap of blacklisted peers. Values are of type 'char *' (transport names), | ||
345 | * can be NULL if we have no static blacklist. | ||
346 | */ | ||
347 | static struct GNUNET_CONTAINER_MultiPeerMap *blacklist; | ||
348 | |||
349 | /** | ||
350 | * Notification context, to send updates on changes to active plugin | ||
351 | * connections. | ||
352 | */ | ||
353 | static struct GNUNET_NotificationContext *plugin_nc; | ||
354 | |||
355 | /** | ||
356 | * Plugin monitoring client we are currently syncing, NULL if all | ||
357 | * monitoring clients are in sync. | ||
358 | */ | ||
359 | static struct TransportClient *sync_client; | ||
360 | |||
361 | /** | ||
362 | * Peer identity that is all zeros, used as a way to indicate | ||
363 | * "all peers". Used for comparissons. | ||
364 | */ | ||
365 | static struct GNUNET_PeerIdentity all_zeros; | ||
77 | 366 | ||
78 | /** | 367 | /** |
79 | * Statistics handle. | 368 | * Statistics handle. |
@@ -96,11 +385,6 @@ struct GNUNET_PeerIdentity GST_my_identity; | |||
96 | struct GNUNET_PEERINFO_Handle *GST_peerinfo; | 385 | struct GNUNET_PEERINFO_Handle *GST_peerinfo; |
97 | 386 | ||
98 | /** | 387 | /** |
99 | * Handle to our service's server. | ||
100 | */ | ||
101 | static struct GNUNET_SERVER_Handle *GST_server; | ||
102 | |||
103 | /** | ||
104 | * Our private key. | 388 | * Our private key. |
105 | */ | 389 | */ |
106 | struct GNUNET_CRYPTO_EddsaPrivateKey *GST_my_private_key; | 390 | struct GNUNET_CRYPTO_EddsaPrivateKey *GST_my_private_key; |
@@ -137,6 +421,1029 @@ struct GNUNET_ATS_InterfaceScanner *GST_is; | |||
137 | 421 | ||
138 | 422 | ||
139 | /** | 423 | /** |
424 | * Queue the given message for transmission to the given client | ||
425 | * | ||
426 | * @param tc target of the message | ||
427 | * @param msg message to transmit | ||
428 | * @param may_drop #GNUNET_YES if the message can be dropped | ||
429 | */ | ||
430 | static void | ||
431 | unicast (struct TransportClient *tc, | ||
432 | const struct GNUNET_MessageHeader *msg, | ||
433 | int may_drop) | ||
434 | { | ||
435 | struct GNUNET_MQ_Envelope *env; | ||
436 | |||
437 | if ( (GNUNET_MQ_get_length (tc->mq) >= MAX_PENDING) && | ||
438 | (GNUNET_YES == may_drop) ) | ||
439 | { | ||
440 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
441 | "Dropping message of type %u and size %u, have %u/%u messages pending\n", | ||
442 | ntohs (msg->type), | ||
443 | ntohs (msg->size), | ||
444 | GNUNET_MQ_get_length (tc->mq), | ||
445 | MAX_PENDING); | ||
446 | GNUNET_STATISTICS_update (GST_stats, | ||
447 | gettext_noop | ||
448 | ("# messages dropped due to slow client"), 1, | ||
449 | GNUNET_NO); | ||
450 | return; | ||
451 | } | ||
452 | env = GNUNET_MQ_msg_copy (msg); | ||
453 | GNUNET_MQ_send (tc->mq, | ||
454 | env); | ||
455 | } | ||
456 | |||
457 | |||
458 | /** | ||
459 | * Called whenever a client connects. Allocates our | ||
460 | * data structures associated with that client. | ||
461 | * | ||
462 | * @param cls closure, NULL | ||
463 | * @param client identification of the client | ||
464 | * @param mq message queue for the client | ||
465 | * @return our `struct TransportClient` | ||
466 | */ | ||
467 | static void * | ||
468 | client_connect_cb (void *cls, | ||
469 | struct GNUNET_SERVICE_Client *client, | ||
470 | struct GNUNET_MQ_Handle *mq) | ||
471 | { | ||
472 | struct TransportClient *tc; | ||
473 | |||
474 | tc = GNUNET_new (struct TransportClient); | ||
475 | tc->client = client; | ||
476 | tc->mq = mq; | ||
477 | GNUNET_CONTAINER_DLL_insert (clients_head, | ||
478 | clients_tail, | ||
479 | tc); | ||
480 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
481 | "Client %p connected\n", | ||
482 | tc); | ||
483 | return tc; | ||
484 | } | ||
485 | |||
486 | |||
487 | /** | ||
488 | * Perform next action in the blacklist check. | ||
489 | * | ||
490 | * @param cls the `struct BlacklistCheck*` | ||
491 | */ | ||
492 | static void | ||
493 | do_blacklist_check (void *cls); | ||
494 | |||
495 | |||
496 | /** | ||
497 | * Mark the peer as down so we don't call the continuation | ||
498 | * context in the future. | ||
499 | * | ||
500 | * @param cls a `struct TransportClient` | ||
501 | * @param peer a peer we are sending to | ||
502 | * @param value a `struct SendTransmitContinuationContext` to mark | ||
503 | * @return #GNUNET_OK (continue to iterate) | ||
504 | */ | ||
505 | static int | ||
506 | mark_match_down (void *cls, | ||
507 | const struct GNUNET_PeerIdentity *peer, | ||
508 | void *value) | ||
509 | { | ||
510 | struct TransportClient *tc = cls; | ||
511 | struct SendTransmitContinuationContext *stcc = value; | ||
512 | |||
513 | if (tc == stcc->tc) | ||
514 | { | ||
515 | stcc->down = GNUNET_YES; | ||
516 | stcc->tc = NULL; | ||
517 | } | ||
518 | return GNUNET_OK; | ||
519 | } | ||
520 | |||
521 | |||
522 | /** | ||
523 | * Called whenever a client is disconnected. Frees our | ||
524 | * resources associated with that client. | ||
525 | * | ||
526 | * @param cls closure, NULL | ||
527 | * @param client identification of the client | ||
528 | * @param app_ctx our `struct TransportClient` | ||
529 | */ | ||
530 | static void | ||
531 | client_disconnect_cb (void *cls, | ||
532 | struct GNUNET_SERVICE_Client *client, | ||
533 | void *app_ctx) | ||
534 | { | ||
535 | struct TransportClient *tc = app_ctx; | ||
536 | struct GST_BlacklistCheck *bc; | ||
537 | |||
538 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
539 | "Client %p disconnected, cleaning up.\n", | ||
540 | tc); | ||
541 | GNUNET_CONTAINER_multipeermap_iterate (active_stccs, | ||
542 | &mark_match_down, | ||
543 | tc); | ||
544 | GNUNET_CONTAINER_DLL_remove (clients_head, | ||
545 | clients_tail, | ||
546 | tc); | ||
547 | switch (tc->type) | ||
548 | { | ||
549 | case CT_NONE: | ||
550 | break; | ||
551 | case CT_CORE: | ||
552 | break; | ||
553 | case CT_MONITOR: | ||
554 | break; | ||
555 | case CT_BLACKLIST: | ||
556 | for (bc = bc_head; NULL != bc; bc = bc->next) | ||
557 | { | ||
558 | if (bc->bl_pos != tc) | ||
559 | continue; | ||
560 | bc->bl_pos = tc->next; | ||
561 | if (NULL == bc->task) | ||
562 | bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, | ||
563 | bc); | ||
564 | } | ||
565 | break; | ||
566 | } | ||
567 | GNUNET_free (tc); | ||
568 | } | ||
569 | |||
570 | |||
571 | /** | ||
572 | * Function called for each of our connected neighbours. Notify the | ||
573 | * client about the existing neighbour. | ||
574 | * | ||
575 | * @param cls the `struct TransportClient *` to notify | ||
576 | * @param peer identity of the neighbour | ||
577 | * @param address the address | ||
578 | * @param state the current state of the peer | ||
579 | * @param state_timeout the time out for the state | ||
580 | * @param bandwidth_in inbound bandwidth in NBO | ||
581 | * @param bandwidth_out outbound bandwidth in NBO | ||
582 | */ | ||
583 | static void | ||
584 | notify_client_about_neighbour (void *cls, | ||
585 | const struct GNUNET_PeerIdentity *peer, | ||
586 | const struct GNUNET_HELLO_Address *address, | ||
587 | enum GNUNET_TRANSPORT_PeerState state, | ||
588 | struct GNUNET_TIME_Absolute state_timeout, | ||
589 | struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in, | ||
590 | struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out) | ||
591 | { | ||
592 | struct TransportClient *tc = cls; | ||
593 | struct ConnectInfoMessage cim; | ||
594 | |||
595 | if (GNUNET_NO == GST_neighbours_test_connected (peer)) | ||
596 | return; | ||
597 | cim.header.size = htons (sizeof (struct ConnectInfoMessage)); | ||
598 | cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT); | ||
599 | cim.id = *peer; | ||
600 | cim.quota_in = bandwidth_in; | ||
601 | cim.quota_out = bandwidth_out; | ||
602 | unicast (tc, | ||
603 | &cim.header, | ||
604 | GNUNET_NO); | ||
605 | } | ||
606 | |||
607 | |||
608 | /** | ||
609 | * Initialize a normal client. We got a start message from this | ||
610 | * client, add him to the list of clients for broadcasting of inbound | ||
611 | * messages. | ||
612 | * | ||
613 | * @param cls the client | ||
614 | * @param start the start message that was sent | ||
615 | */ | ||
616 | static void | ||
617 | handle_client_start (void *cls, | ||
618 | const struct StartMessage *start) | ||
619 | { | ||
620 | struct TransportClient *tc = cls; | ||
621 | const struct GNUNET_MessageHeader *hello; | ||
622 | uint32_t options; | ||
623 | |||
624 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
625 | "Client %p sent START\n", | ||
626 | tc); | ||
627 | options = ntohl (start->options); | ||
628 | if ((0 != (1 & options)) && | ||
629 | (0 != | ||
630 | memcmp (&start->self, | ||
631 | &GST_my_identity, | ||
632 | sizeof (struct GNUNET_PeerIdentity)))) | ||
633 | { | ||
634 | /* client thinks this is a different peer, reject */ | ||
635 | GNUNET_break (0); | ||
636 | GNUNET_SERVICE_client_drop (tc->client); | ||
637 | return; | ||
638 | } | ||
639 | if (CT_NONE != tc->type) | ||
640 | { | ||
641 | GNUNET_break (0); | ||
642 | GNUNET_SERVICE_client_drop (tc->client); | ||
643 | return; | ||
644 | } | ||
645 | if (0 != (2 & options)) | ||
646 | tc->type = CT_CORE; | ||
647 | hello = GST_hello_get (); | ||
648 | if (NULL != hello) | ||
649 | unicast (tc, | ||
650 | hello, | ||
651 | GNUNET_NO); | ||
652 | GST_neighbours_iterate (¬ify_client_about_neighbour, | ||
653 | tc); | ||
654 | GNUNET_SERVICE_client_continue (tc->client); | ||
655 | } | ||
656 | |||
657 | |||
658 | /** | ||
659 | * Client sent us a HELLO. Check the request. | ||
660 | * | ||
661 | * @param cls the client | ||
662 | * @param message the HELLO message | ||
663 | */ | ||
664 | static int | ||
665 | check_client_hello (void *cls, | ||
666 | const struct GNUNET_MessageHeader *message) | ||
667 | { | ||
668 | return GNUNET_OK; /* FIXME: check here? */ | ||
669 | } | ||
670 | |||
671 | |||
672 | /** | ||
673 | * Client sent us a HELLO. Process the request. | ||
674 | * | ||
675 | * @param cls the client | ||
676 | * @param message the HELLO message | ||
677 | */ | ||
678 | static void | ||
679 | handle_client_hello (void *cls, | ||
680 | const struct GNUNET_MessageHeader *message) | ||
681 | { | ||
682 | struct TransportClient *tc = cls; | ||
683 | |||
684 | GST_validation_handle_hello (message); | ||
685 | GNUNET_SERVICE_client_continue (tc->client); | ||
686 | } | ||
687 | |||
688 | |||
689 | /** | ||
690 | * Function called after the transmission is done. Notify the client that it is | ||
691 | * OK to send the next message. | ||
692 | * | ||
693 | * @param cls closure | ||
694 | * @param success #GNUNET_OK on success, #GNUNET_NO on failure, #GNUNET_SYSERR if we're not connected | ||
695 | * @param bytes_payload bytes payload sent | ||
696 | * @param bytes_on_wire bytes sent on wire | ||
697 | */ | ||
698 | static void | ||
699 | handle_send_transmit_continuation (void *cls, | ||
700 | int success, | ||
701 | size_t bytes_payload, | ||
702 | size_t bytes_on_wire) | ||
703 | { | ||
704 | struct SendTransmitContinuationContext *stcc = cls; | ||
705 | struct SendOkMessage send_ok_msg; | ||
706 | struct GNUNET_TIME_Relative delay; | ||
707 | const struct GNUNET_HELLO_Address *addr; | ||
708 | |||
709 | delay = GNUNET_TIME_absolute_get_duration (stcc->send_time); | ||
710 | addr = GST_neighbour_get_current_address (&stcc->target); | ||
711 | if (delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us) | ||
712 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
713 | "It took us %s to send %u/%u bytes to %s (%d, %s)\n", | ||
714 | GNUNET_STRINGS_relative_time_to_string (delay, | ||
715 | GNUNET_YES), | ||
716 | (unsigned int) bytes_payload, | ||
717 | (unsigned int) bytes_on_wire, | ||
718 | GNUNET_i2s (&stcc->target), | ||
719 | success, | ||
720 | (NULL != addr) ? addr->transport_name : "%"); | ||
721 | else | ||
722 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
723 | "It took us %s to send %u/%u bytes to %s (%d, %s)\n", | ||
724 | GNUNET_STRINGS_relative_time_to_string (delay, | ||
725 | GNUNET_YES), | ||
726 | (unsigned int) bytes_payload, | ||
727 | (unsigned int) bytes_on_wire, | ||
728 | GNUNET_i2s (&stcc->target), | ||
729 | success, | ||
730 | (NULL != addr) ? addr->transport_name : "%"); | ||
731 | |||
732 | if (GNUNET_NO == stcc->down) | ||
733 | { | ||
734 | /* Only send confirmation if we are still connected */ | ||
735 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
736 | "Sending SEND_OK for transmission request %llu\n", | ||
737 | stcc->uuid); | ||
738 | send_ok_msg.header.size = htons (sizeof (send_ok_msg)); | ||
739 | send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK); | ||
740 | send_ok_msg.bytes_msg = htonl (bytes_payload); | ||
741 | send_ok_msg.bytes_physical = htonl (bytes_on_wire); | ||
742 | send_ok_msg.success = htonl (success); | ||
743 | send_ok_msg.peer = stcc->target; | ||
744 | unicast (stcc->tc, | ||
745 | &send_ok_msg.header, | ||
746 | GNUNET_NO); | ||
747 | } | ||
748 | GNUNET_assert (GNUNET_OK == | ||
749 | GNUNET_CONTAINER_multipeermap_remove (active_stccs, | ||
750 | &stcc->target, | ||
751 | stcc)); | ||
752 | GNUNET_free (stcc); | ||
753 | } | ||
754 | |||
755 | |||
756 | /** | ||
757 | * Client asked for transmission to a peer. Process the request. | ||
758 | * | ||
759 | * @param cls the client | ||
760 | * @param obm the send message that was sent | ||
761 | */ | ||
762 | static int | ||
763 | check_client_send (void *cls, | ||
764 | const struct OutboundMessage *obm) | ||
765 | { | ||
766 | uint16_t size; | ||
767 | const struct GNUNET_MessageHeader *obmm; | ||
768 | |||
769 | size = ntohs (obm->header.size) - sizeof (struct OutboundMessage); | ||
770 | if (size < sizeof (struct GNUNET_MessageHeader)) | ||
771 | { | ||
772 | GNUNET_break (0); | ||
773 | return GNUNET_SYSERR; | ||
774 | } | ||
775 | obmm = (const struct GNUNET_MessageHeader *) &obm[1]; | ||
776 | if (size != ntohs (obmm->size)) | ||
777 | { | ||
778 | GNUNET_break (0); | ||
779 | return GNUNET_SYSERR; | ||
780 | } | ||
781 | return GNUNET_OK; | ||
782 | } | ||
783 | |||
784 | |||
785 | /** | ||
786 | * Client asked for transmission to a peer. Process the request. | ||
787 | * | ||
788 | * @param cls the client | ||
789 | * @param obm the send message that was sent | ||
790 | */ | ||
791 | static void | ||
792 | handle_client_send (void *cls, | ||
793 | const struct OutboundMessage *obm) | ||
794 | { | ||
795 | static unsigned long long uuid_gen; | ||
796 | struct TransportClient *tc = cls; | ||
797 | const struct GNUNET_MessageHeader *obmm; | ||
798 | struct SendTransmitContinuationContext *stcc; | ||
799 | |||
800 | obmm = (const struct GNUNET_MessageHeader *) &obm[1]; | ||
801 | if (GNUNET_NO == GST_neighbours_test_connected (&obm->peer)) | ||
802 | { | ||
803 | /* not connected, not allowed to send; can happen due to asynchronous operations */ | ||
804 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
805 | "Could not send message to peer `%s': not connected\n", | ||
806 | GNUNET_i2s (&obm->peer)); | ||
807 | GNUNET_STATISTICS_update (GST_stats, | ||
808 | gettext_noop | ||
809 | ("# bytes payload dropped (other peer was not connected)"), | ||
810 | ntohs (obmm->size), | ||
811 | GNUNET_NO); | ||
812 | GNUNET_SERVICE_client_continue (tc->client); | ||
813 | return; | ||
814 | } | ||
815 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
816 | "Received SEND request %llu for `%s' and first message of type %u and total size %u\n", | ||
817 | uuid_gen, | ||
818 | GNUNET_i2s (&obm->peer), | ||
819 | ntohs (obmm->type), | ||
820 | ntohs (obmm->size)); | ||
821 | GNUNET_SERVICE_client_continue (tc->client); | ||
822 | |||
823 | stcc = GNUNET_new (struct SendTransmitContinuationContext); | ||
824 | stcc->target = obm->peer; | ||
825 | stcc->tc = tc; | ||
826 | stcc->send_time = GNUNET_TIME_absolute_get (); | ||
827 | stcc->uuid = uuid_gen++; | ||
828 | (void) GNUNET_CONTAINER_multipeermap_put (active_stccs, | ||
829 | &stcc->target, | ||
830 | stcc, | ||
831 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
832 | GST_manipulation_send (&obm->peer, | ||
833 | obmm, | ||
834 | ntohs (obmm->size), | ||
835 | GNUNET_TIME_relative_ntoh (obm->timeout), | ||
836 | &handle_send_transmit_continuation, | ||
837 | stcc); | ||
838 | } | ||
839 | |||
840 | |||
841 | /** | ||
842 | * Take the given address and append it to the set of results sent back to | ||
843 | * the client. This function may be called serveral times for a single | ||
844 | * conversion. The last invocation will be with a @a address of | ||
845 | * NULL and a @a res of #GNUNET_OK. Thus, to indicate conversion | ||
846 | * errors, the callback might be called first with @a address NULL and | ||
847 | * @a res being #GNUNET_SYSERR. In that case, there will still be a | ||
848 | * subsequent call later with @a address NULL and @a res #GNUNET_OK. | ||
849 | * | ||
850 | * @param cls the `struct AddressToStringContext` | ||
851 | * @param buf text to transmit (contains the human-readable address, or NULL) | ||
852 | * @param res #GNUNET_OK if conversion was successful, #GNUNET_SYSERR on error, | ||
853 | * never #GNUNET_NO | ||
854 | */ | ||
855 | static void | ||
856 | transmit_address_to_client (void *cls, | ||
857 | const char *buf, | ||
858 | int res) | ||
859 | { | ||
860 | struct AddressToStringContext *actx = cls; | ||
861 | struct GNUNET_MQ_Envelope *env; | ||
862 | struct AddressToStringResultMessage *atsm; | ||
863 | size_t slen; | ||
864 | |||
865 | GNUNET_assert ( (GNUNET_OK == res) || | ||
866 | (GNUNET_SYSERR == res) ); | ||
867 | if (NULL == buf) | ||
868 | { | ||
869 | env = GNUNET_MQ_msg (atsm, | ||
870 | GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY); | ||
871 | if (GNUNET_OK == res) | ||
872 | { | ||
873 | /* this was the last call, transmit */ | ||
874 | atsm->res = htonl (GNUNET_OK); | ||
875 | atsm->addr_len = htonl (0); | ||
876 | GNUNET_MQ_send (actx->tc->mq, | ||
877 | env); | ||
878 | GNUNET_CONTAINER_DLL_remove (a2s_head, | ||
879 | a2s_tail, | ||
880 | actx); | ||
881 | return; | ||
882 | } | ||
883 | if (GNUNET_SYSERR == res) | ||
884 | { | ||
885 | /* address conversion failed, but there will be more callbacks */ | ||
886 | atsm->res = htonl (GNUNET_SYSERR); | ||
887 | atsm->addr_len = htonl (0); | ||
888 | GNUNET_MQ_send (actx->tc->mq, | ||
889 | env); | ||
890 | return; | ||
891 | } | ||
892 | } | ||
893 | GNUNET_assert (GNUNET_OK == res); | ||
894 | /* succesful conversion, append*/ | ||
895 | slen = strlen (buf) + 1; | ||
896 | env = GNUNET_MQ_msg_extra (atsm, | ||
897 | slen, | ||
898 | GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY); | ||
899 | atsm->res = htonl (GNUNET_YES); | ||
900 | atsm->addr_len = htonl (slen); | ||
901 | GNUNET_memcpy (&atsm[1], | ||
902 | buf, | ||
903 | slen); | ||
904 | GNUNET_MQ_send (actx->tc->mq, | ||
905 | env); | ||
906 | } | ||
907 | |||
908 | |||
909 | /** | ||
910 | * Client asked to resolve an address. Check the request. | ||
911 | * | ||
912 | * @param cls the client | ||
913 | * @param alum the resolution request | ||
914 | * @return #GNUNET_OK if @a alum is well-formed | ||
915 | */ | ||
916 | static int | ||
917 | check_client_address_to_string (void *cls, | ||
918 | const struct AddressLookupMessage *alum) | ||
919 | { | ||
920 | const char *plugin_name; | ||
921 | const char *address; | ||
922 | uint32_t address_len; | ||
923 | uint16_t size; | ||
924 | |||
925 | size = ntohs (alum->header.size); | ||
926 | address_len = ntohs (alum->addrlen); | ||
927 | if (size <= sizeof (struct AddressLookupMessage) + address_len) | ||
928 | { | ||
929 | GNUNET_break (0); | ||
930 | return GNUNET_SYSERR; | ||
931 | } | ||
932 | address = (const char *) &alum[1]; | ||
933 | plugin_name = (const char *) &address[address_len]; | ||
934 | if ('\0' != plugin_name[size - sizeof (struct AddressLookupMessage) - address_len - 1]) | ||
935 | { | ||
936 | GNUNET_break (0); | ||
937 | return GNUNET_SYSERR; | ||
938 | } | ||
939 | return GNUNET_OK; | ||
940 | } | ||
941 | |||
942 | |||
943 | /** | ||
944 | * Client asked to resolve an address. Process the request. | ||
945 | * | ||
946 | * @param cls the client | ||
947 | * @param alum the resolution request | ||
948 | */ | ||
949 | static void | ||
950 | handle_client_address_to_string (void *cls, | ||
951 | const struct AddressLookupMessage *alum) | ||
952 | { | ||
953 | struct TransportClient *tc = cls; | ||
954 | struct GNUNET_TRANSPORT_PluginFunctions *papi; | ||
955 | const char *plugin_name; | ||
956 | const char *address; | ||
957 | uint32_t address_len; | ||
958 | struct AddressToStringContext *actx; | ||
959 | struct GNUNET_MQ_Envelope *env; | ||
960 | struct AddressToStringResultMessage *atsm; | ||
961 | struct GNUNET_TIME_Relative rtimeout; | ||
962 | int32_t numeric; | ||
963 | |||
964 | address_len = ntohs (alum->addrlen); | ||
965 | address = (const char *) &alum[1]; | ||
966 | plugin_name = (const char *) &address[address_len]; | ||
967 | rtimeout = GNUNET_TIME_relative_ntoh (alum->timeout); | ||
968 | numeric = ntohs (alum->numeric_only); | ||
969 | papi = GST_plugins_printer_find (plugin_name); | ||
970 | if (NULL == papi) | ||
971 | { | ||
972 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
973 | "Failed to find plugin `%s'\n", | ||
974 | plugin_name); | ||
975 | env = GNUNET_MQ_msg (atsm, | ||
976 | GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY); | ||
977 | atsm->res = htonl (GNUNET_SYSERR); | ||
978 | atsm->addr_len = htonl (0); | ||
979 | GNUNET_MQ_send (tc->mq, | ||
980 | env); | ||
981 | env = GNUNET_MQ_msg (atsm, | ||
982 | GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY); | ||
983 | atsm->res = htonl (GNUNET_OK); | ||
984 | atsm->addr_len = htonl (0); | ||
985 | GNUNET_MQ_send (tc->mq, | ||
986 | env); | ||
987 | return; | ||
988 | } | ||
989 | actx = GNUNET_new (struct AddressToStringContext); | ||
990 | actx->tc = tc; | ||
991 | GNUNET_CONTAINER_DLL_insert (a2s_head, | ||
992 | a2s_tail, | ||
993 | actx); | ||
994 | GNUNET_SERVICE_client_disable_continue_warning (tc->client); | ||
995 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
996 | "Pretty-printing address of %u bytes using plugin `%s'\n", | ||
997 | address_len, | ||
998 | plugin_name); | ||
999 | papi->address_pretty_printer (papi->cls, | ||
1000 | plugin_name, | ||
1001 | address, | ||
1002 | address_len, | ||
1003 | numeric, | ||
1004 | rtimeout, | ||
1005 | &transmit_address_to_client, | ||
1006 | actx); | ||
1007 | } | ||
1008 | |||
1009 | |||
1010 | /** | ||
1011 | * Compose #PeerIterateResponseMessage using the given peer and address. | ||
1012 | * | ||
1013 | * @param peer identity of the peer | ||
1014 | * @param address the address, NULL on disconnect | ||
1015 | * @return composed message | ||
1016 | */ | ||
1017 | static struct PeerIterateResponseMessage * | ||
1018 | compose_address_iterate_response_message (const struct GNUNET_PeerIdentity *peer, | ||
1019 | const struct GNUNET_HELLO_Address *address) | ||
1020 | { | ||
1021 | struct PeerIterateResponseMessage *msg; | ||
1022 | size_t size; | ||
1023 | size_t tlen; | ||
1024 | size_t alen; | ||
1025 | char *addr; | ||
1026 | |||
1027 | GNUNET_assert (NULL != peer); | ||
1028 | if (NULL != address) | ||
1029 | { | ||
1030 | tlen = strlen (address->transport_name) + 1; | ||
1031 | alen = address->address_length; | ||
1032 | } | ||
1033 | else | ||
1034 | { | ||
1035 | tlen = 0; | ||
1036 | alen = 0; | ||
1037 | } | ||
1038 | size = (sizeof (struct PeerIterateResponseMessage) + alen + tlen); | ||
1039 | msg = GNUNET_malloc (size); | ||
1040 | msg->header.size = htons (size); | ||
1041 | msg->header.type | ||
1042 | = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_RESPONSE); | ||
1043 | msg->reserved = htonl (0); | ||
1044 | msg->peer = *peer; | ||
1045 | msg->addrlen = htonl (alen); | ||
1046 | msg->pluginlen = htonl (tlen); | ||
1047 | |||
1048 | if (NULL != address) | ||
1049 | { | ||
1050 | msg->local_address_info = htonl((uint32_t) address->local_info); | ||
1051 | addr = (char *) &msg[1]; | ||
1052 | GNUNET_memcpy (addr, | ||
1053 | address->address, | ||
1054 | alen); | ||
1055 | GNUNET_memcpy (&addr[alen], | ||
1056 | address->transport_name, | ||
1057 | tlen); | ||
1058 | } | ||
1059 | return msg; | ||
1060 | } | ||
1061 | |||
1062 | |||
1063 | /** | ||
1064 | * Context for #send_validation_information() and | ||
1065 | * #send_peer_information(). | ||
1066 | */ | ||
1067 | struct IterationContext | ||
1068 | { | ||
1069 | /** | ||
1070 | * Context to use for the transmission. | ||
1071 | */ | ||
1072 | struct TransportClient *tc; | ||
1073 | |||
1074 | /** | ||
1075 | * Which peers do we care about? | ||
1076 | */ | ||
1077 | struct GNUNET_PeerIdentity id; | ||
1078 | |||
1079 | /** | ||
1080 | * #GNUNET_YES if @e id should be ignored because we want all peers. | ||
1081 | */ | ||
1082 | int all; | ||
1083 | }; | ||
1084 | |||
1085 | |||
1086 | /** | ||
1087 | * Output information of neighbours to the given client. | ||
1088 | * | ||
1089 | * @param cls the `struct PeerIterationContext *` | ||
1090 | * @param peer identity of the neighbour | ||
1091 | * @param address the address | ||
1092 | * @param state current state this peer is in | ||
1093 | * @param state_timeout timeout for the current state of the peer | ||
1094 | * @param bandwidth_in inbound quota in NBO | ||
1095 | * @param bandwidth_out outbound quota in NBO | ||
1096 | */ | ||
1097 | static void | ||
1098 | send_peer_information (void *cls, | ||
1099 | const struct GNUNET_PeerIdentity *peer, | ||
1100 | const struct GNUNET_HELLO_Address *address, | ||
1101 | enum GNUNET_TRANSPORT_PeerState state, | ||
1102 | struct GNUNET_TIME_Absolute state_timeout, | ||
1103 | struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in, | ||
1104 | struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out) | ||
1105 | { | ||
1106 | struct IterationContext *pc = cls; | ||
1107 | struct GNUNET_MQ_Envelope *env; | ||
1108 | struct PeerIterateResponseMessage *msg; | ||
1109 | |||
1110 | if ( (GNUNET_YES != pc->all) && | ||
1111 | (0 != memcmp (peer, | ||
1112 | &pc->id, | ||
1113 | sizeof (pc->id))) ) | ||
1114 | return; | ||
1115 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1116 | "Sending information about `%s' using address `%s' in state `%s'\n", | ||
1117 | GNUNET_i2s(peer), | ||
1118 | (NULL != address) ? GST_plugins_a2s (address) : "<none>", | ||
1119 | GNUNET_TRANSPORT_ps2s (state)); | ||
1120 | msg = compose_address_iterate_response_message (peer, | ||
1121 | address); | ||
1122 | msg->state = htonl (state); | ||
1123 | msg->state_timeout = GNUNET_TIME_absolute_hton(state_timeout); | ||
1124 | env = GNUNET_MQ_msg_copy (&msg->header); | ||
1125 | GNUNET_free (msg); | ||
1126 | GNUNET_MQ_send (pc->tc->mq, | ||
1127 | env); | ||
1128 | } | ||
1129 | |||
1130 | |||
1131 | /** | ||
1132 | * Client asked to obtain information about a specific or all peers | ||
1133 | * Process the request. | ||
1134 | * | ||
1135 | * @param cls the client | ||
1136 | * @param msg the peer address information request | ||
1137 | */ | ||
1138 | static void | ||
1139 | handle_client_monitor_peers (void *cls, | ||
1140 | const struct PeerMonitorMessage *msg) | ||
1141 | { | ||
1142 | struct TransportClient *tc = cls; | ||
1143 | struct IterationContext pc; | ||
1144 | |||
1145 | if (CT_NONE != tc->type) | ||
1146 | { | ||
1147 | GNUNET_break (0); | ||
1148 | GNUNET_SERVICE_client_drop (tc->client); | ||
1149 | return; | ||
1150 | } | ||
1151 | GNUNET_SERVICE_client_disable_continue_warning (tc->client); | ||
1152 | GNUNET_SERVICE_client_mark_monitor (tc->client); | ||
1153 | |||
1154 | /* Send initial list */ | ||
1155 | pc.tc = tc; | ||
1156 | if (0 == memcmp (&msg->peer, | ||
1157 | &all_zeros, | ||
1158 | sizeof (struct GNUNET_PeerIdentity))) | ||
1159 | { | ||
1160 | /* iterate over all neighbours */ | ||
1161 | pc.all = GNUNET_YES; | ||
1162 | pc.id = msg->peer; | ||
1163 | } | ||
1164 | else | ||
1165 | { | ||
1166 | /* just return one neighbour */ | ||
1167 | pc.all = GNUNET_NO; | ||
1168 | pc.id = msg->peer; | ||
1169 | } | ||
1170 | GST_neighbours_iterate (&send_peer_information, | ||
1171 | &pc); | ||
1172 | |||
1173 | if (GNUNET_YES != ntohl (msg->one_shot)) | ||
1174 | { | ||
1175 | tc->details.monitor_peer = msg->peer; | ||
1176 | tc->type = CT_MONITOR; | ||
1177 | if (0 != memcmp (&msg->peer, | ||
1178 | &all_zeros, | ||
1179 | sizeof (struct GNUNET_PeerIdentity))) | ||
1180 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1181 | "Client %p started monitoring of the peer `%s'\n", | ||
1182 | tc, | ||
1183 | GNUNET_i2s (&msg->peer)); | ||
1184 | else | ||
1185 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1186 | "Client %p started monitoring all peers\n", | ||
1187 | tc); | ||
1188 | } | ||
1189 | else | ||
1190 | { | ||
1191 | struct GNUNET_MessageHeader *msg; | ||
1192 | struct GNUNET_MQ_Envelope *env; | ||
1193 | |||
1194 | env = GNUNET_MQ_msg (msg, | ||
1195 | GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_RESPONSE_END); | ||
1196 | GNUNET_MQ_send (tc->mq, | ||
1197 | env); | ||
1198 | } | ||
1199 | } | ||
1200 | |||
1201 | |||
1202 | /** | ||
1203 | * Function called by the plugin with information about the | ||
1204 | * current sessions managed by the plugin (for monitoring). | ||
1205 | * | ||
1206 | * @param cls closure | ||
1207 | * @param session session handle this information is about, | ||
1208 | * NULL to indicate that we are "in sync" (initial | ||
1209 | * iteration complete) | ||
1210 | * @param info information about the state of the session, | ||
1211 | * NULL if @a session is also NULL and we are | ||
1212 | * merely signalling that the initial iteration is over | ||
1213 | */ | ||
1214 | static void | ||
1215 | plugin_session_info_cb (void *cls, | ||
1216 | struct GNUNET_ATS_Session *session, | ||
1217 | const struct GNUNET_TRANSPORT_SessionInfo *info) | ||
1218 | { | ||
1219 | struct GNUNET_MQ_Envelope *env; | ||
1220 | struct TransportPluginMonitorMessage *msg; | ||
1221 | struct GNUNET_MessageHeader *sync; | ||
1222 | size_t size; | ||
1223 | size_t slen; | ||
1224 | uint16_t alen; | ||
1225 | char *name; | ||
1226 | char *addr; | ||
1227 | |||
1228 | if (0 == GNUNET_notification_context_get_size (plugin_nc)) | ||
1229 | { | ||
1230 | GST_plugins_monitor_subscribe (NULL, | ||
1231 | NULL); | ||
1232 | return; | ||
1233 | } | ||
1234 | if ( (NULL == info) && | ||
1235 | (NULL == session) ) | ||
1236 | { | ||
1237 | /* end of initial iteration */ | ||
1238 | if (NULL != sync_client) | ||
1239 | { | ||
1240 | env = GNUNET_MQ_msg (sync, | ||
1241 | GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PLUGIN_SYNC); | ||
1242 | GNUNET_MQ_send (sync_client->mq, | ||
1243 | env); | ||
1244 | sync_client = NULL; | ||
1245 | } | ||
1246 | return; | ||
1247 | } | ||
1248 | GNUNET_assert (NULL != info); | ||
1249 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1250 | "Plugin event for peer %s on transport %s\n", | ||
1251 | GNUNET_i2s (&info->address->peer), | ||
1252 | info->address->transport_name); | ||
1253 | slen = strlen (info->address->transport_name) + 1; | ||
1254 | alen = info->address->address_length; | ||
1255 | size = sizeof (struct TransportPluginMonitorMessage) + slen + alen; | ||
1256 | if (size > UINT16_MAX) | ||
1257 | { | ||
1258 | GNUNET_break (0); | ||
1259 | return; | ||
1260 | } | ||
1261 | msg = GNUNET_malloc (size); | ||
1262 | msg->header.size = htons (size); | ||
1263 | msg->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PLUGIN_EVENT); | ||
1264 | msg->session_state = htons ((uint16_t) info->state); | ||
1265 | msg->is_inbound = htons ((int16_t) info->is_inbound); | ||
1266 | msg->msgs_pending = htonl (info->num_msg_pending); | ||
1267 | msg->bytes_pending = htonl (info->num_bytes_pending); | ||
1268 | msg->timeout = GNUNET_TIME_absolute_hton (info->session_timeout); | ||
1269 | msg->delay = GNUNET_TIME_absolute_hton (info->receive_delay); | ||
1270 | msg->peer = info->address->peer; | ||
1271 | msg->session_id = (uint64_t) (intptr_t) session; | ||
1272 | msg->plugin_name_len = htons (slen); | ||
1273 | msg->plugin_address_len = htons (alen); | ||
1274 | name = (char *) &msg[1]; | ||
1275 | GNUNET_memcpy (name, | ||
1276 | info->address->transport_name, | ||
1277 | slen); | ||
1278 | addr = &name[slen]; | ||
1279 | GNUNET_memcpy (addr, | ||
1280 | info->address->address, | ||
1281 | alen); | ||
1282 | if (NULL != sync_client) | ||
1283 | { | ||
1284 | struct GNUNET_MQ_Envelope *env; | ||
1285 | |||
1286 | env = GNUNET_MQ_msg_copy (&msg->header); | ||
1287 | GNUNET_MQ_send (sync_client->mq, | ||
1288 | env); | ||
1289 | } | ||
1290 | else | ||
1291 | { | ||
1292 | GNUNET_notification_context_broadcast (plugin_nc, | ||
1293 | &msg->header, | ||
1294 | GNUNET_NO); | ||
1295 | } | ||
1296 | GNUNET_free (msg); | ||
1297 | } | ||
1298 | |||
1299 | |||
1300 | /** | ||
1301 | * Client asked to obtain information about all plugin connections. | ||
1302 | * | ||
1303 | * @param cls the client | ||
1304 | * @param message the peer address information request | ||
1305 | */ | ||
1306 | static void | ||
1307 | handle_client_monitor_plugins (void *cls, | ||
1308 | const struct GNUNET_MessageHeader *message) | ||
1309 | { | ||
1310 | struct TransportClient *tc = cls; | ||
1311 | |||
1312 | GNUNET_SERVICE_client_mark_monitor (tc->client); | ||
1313 | GNUNET_SERVICE_client_disable_continue_warning (tc->client); | ||
1314 | GNUNET_notification_context_add (plugin_nc, | ||
1315 | tc->mq); | ||
1316 | GNUNET_assert (NULL == sync_client); | ||
1317 | sync_client = tc; | ||
1318 | GST_plugins_monitor_subscribe (&plugin_session_info_cb, | ||
1319 | NULL); | ||
1320 | } | ||
1321 | |||
1322 | |||
1323 | /** | ||
1324 | * Broadcast the given message to all of our clients. | ||
1325 | * | ||
1326 | * @param msg message to broadcast | ||
1327 | * @param may_drop #GNUNET_YES if the message can be dropped / is payload | ||
1328 | */ | ||
1329 | void | ||
1330 | GST_clients_broadcast (const struct GNUNET_MessageHeader *msg, | ||
1331 | int may_drop) | ||
1332 | { | ||
1333 | struct TransportClient *tc; | ||
1334 | int done; | ||
1335 | |||
1336 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1337 | "Asked to broadcast message of type %u with %u bytes\n", | ||
1338 | (unsigned int) ntohs (msg->type), | ||
1339 | (unsigned int) ntohs (msg->size)); | ||
1340 | done = GNUNET_NO; | ||
1341 | for (tc = clients_head; NULL != tc; tc = tc->next) | ||
1342 | { | ||
1343 | if ( (GNUNET_YES == may_drop) && | ||
1344 | (CT_CORE != tc->type) ) | ||
1345 | continue; /* skip, this client does not care about payload */ | ||
1346 | unicast (tc, | ||
1347 | msg, | ||
1348 | may_drop); | ||
1349 | done = GNUNET_YES; | ||
1350 | } | ||
1351 | if (GNUNET_NO == done) | ||
1352 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1353 | "Message of type %u not delivered, is CORE service up?\n", | ||
1354 | ntohs (msg->type)); | ||
1355 | } | ||
1356 | |||
1357 | |||
1358 | /** | ||
1359 | * Broadcast the new active address to all clients monitoring the peer. | ||
1360 | * | ||
1361 | * @param peer peer this update is about (never NULL) | ||
1362 | * @param address address, NULL on disconnect | ||
1363 | * @param state the current state of the peer | ||
1364 | * @param state_timeout the time out for the state | ||
1365 | */ | ||
1366 | void | ||
1367 | GST_clients_broadcast_peer_notification (const struct GNUNET_PeerIdentity *peer, | ||
1368 | const struct GNUNET_HELLO_Address *address, | ||
1369 | enum GNUNET_TRANSPORT_PeerState state, | ||
1370 | struct GNUNET_TIME_Absolute state_timeout) | ||
1371 | { | ||
1372 | struct GNUNET_MQ_Envelope *env; | ||
1373 | struct PeerIterateResponseMessage *msg; | ||
1374 | struct TransportClient *tc; | ||
1375 | |||
1376 | msg = compose_address_iterate_response_message (peer, | ||
1377 | address); | ||
1378 | msg->state = htonl (state); | ||
1379 | msg->state_timeout = GNUNET_TIME_absolute_hton (state_timeout); | ||
1380 | for (tc = clients_head; NULL != tc; tc = tc->next) | ||
1381 | { | ||
1382 | if (CT_MONITOR != tc->type) | ||
1383 | continue; | ||
1384 | if ((0 == memcmp (&tc->details.monitor_peer, | ||
1385 | &all_zeros, | ||
1386 | sizeof (struct GNUNET_PeerIdentity))) || | ||
1387 | (0 == memcmp (&tc->details.monitor_peer, | ||
1388 | peer, | ||
1389 | sizeof (struct GNUNET_PeerIdentity)))) | ||
1390 | { | ||
1391 | env = GNUNET_MQ_msg_copy (&msg->header); | ||
1392 | GNUNET_MQ_send (tc->mq, | ||
1393 | env); | ||
1394 | } | ||
1395 | } | ||
1396 | GNUNET_free (msg); | ||
1397 | } | ||
1398 | |||
1399 | |||
1400 | /** | ||
1401 | * Mark the peer as down so we don't call the continuation | ||
1402 | * context in the future. | ||
1403 | * | ||
1404 | * @param cls NULL | ||
1405 | * @param peer peer that got disconnected | ||
1406 | * @param value a `struct SendTransmitContinuationContext` to mark | ||
1407 | * @return #GNUNET_OK (continue to iterate) | ||
1408 | */ | ||
1409 | static int | ||
1410 | mark_peer_down (void *cls, | ||
1411 | const struct GNUNET_PeerIdentity *peer, | ||
1412 | void *value) | ||
1413 | { | ||
1414 | struct SendTransmitContinuationContext *stcc = value; | ||
1415 | |||
1416 | stcc->down = GNUNET_YES; | ||
1417 | return GNUNET_OK; | ||
1418 | } | ||
1419 | |||
1420 | |||
1421 | /** | ||
1422 | * Notify all clients about a disconnect, and cancel | ||
1423 | * pending SEND_OK messages for this peer. | ||
1424 | * | ||
1425 | * @param peer peer that disconnected | ||
1426 | */ | ||
1427 | void | ||
1428 | GST_clients_broadcast_disconnect (const struct GNUNET_PeerIdentity *peer) | ||
1429 | { | ||
1430 | struct DisconnectInfoMessage disconnect_msg; | ||
1431 | |||
1432 | GNUNET_CONTAINER_multipeermap_get_multiple (active_stccs, | ||
1433 | peer, | ||
1434 | &mark_peer_down, | ||
1435 | NULL); | ||
1436 | disconnect_msg.header.size = htons (sizeof(struct DisconnectInfoMessage)); | ||
1437 | disconnect_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT); | ||
1438 | disconnect_msg.reserved = htonl (0); | ||
1439 | disconnect_msg.peer = *peer; | ||
1440 | GST_clients_broadcast (&disconnect_msg.header, | ||
1441 | GNUNET_NO); | ||
1442 | |||
1443 | } | ||
1444 | |||
1445 | |||
1446 | /** | ||
140 | * Transmit our HELLO message to the given (connected) neighbour. | 1447 | * Transmit our HELLO message to the given (connected) neighbour. |
141 | * | 1448 | * |
142 | * @param cls the 'HELLO' message | 1449 | * @param cls the 'HELLO' message |
@@ -170,7 +1477,8 @@ transmit_our_hello (void *cls, | |||
170 | hello, | 1477 | hello, |
171 | ntohs (hello->size), | 1478 | ntohs (hello->size), |
172 | hello_expiration, | 1479 | hello_expiration, |
173 | NULL, NULL); | 1480 | NULL, |
1481 | NULL); | ||
174 | } | 1482 | } |
175 | 1483 | ||
176 | 1484 | ||
@@ -240,8 +1548,11 @@ process_payload (const struct GNUNET_HELLO_Address *address, | |||
240 | im->header.size = htons (size); | 1548 | im->header.size = htons (size); |
241 | im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV); | 1549 | im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV); |
242 | im->peer = address->peer; | 1550 | im->peer = address->peer; |
243 | GNUNET_memcpy (&im[1], message, ntohs (message->size)); | 1551 | GNUNET_memcpy (&im[1], |
244 | GST_clients_broadcast (&im->header, GNUNET_YES); | 1552 | message, |
1553 | ntohs (message->size)); | ||
1554 | GST_clients_broadcast (&im->header, | ||
1555 | GNUNET_YES); | ||
245 | return ret; | 1556 | return ret; |
246 | } | 1557 | } |
247 | 1558 | ||
@@ -257,8 +1568,11 @@ kill_session_task (void *cls) | |||
257 | struct GNUNET_ATS_SessionKiller *sk = cls; | 1568 | struct GNUNET_ATS_SessionKiller *sk = cls; |
258 | 1569 | ||
259 | sk->task = NULL; | 1570 | sk->task = NULL; |
260 | GNUNET_CONTAINER_DLL_remove (sk_head, sk_tail, sk); | 1571 | GNUNET_CONTAINER_DLL_remove (sk_head, |
261 | sk->plugin->disconnect_session (sk->plugin->cls, sk->session); | 1572 | sk_tail, |
1573 | sk); | ||
1574 | sk->plugin->disconnect_session (sk->plugin->cls, | ||
1575 | sk->session); | ||
262 | GNUNET_free(sk); | 1576 | GNUNET_free(sk); |
263 | } | 1577 | } |
264 | 1578 | ||
@@ -290,7 +1604,8 @@ kill_session (const char *plugin_name, | |||
290 | sk = GNUNET_new (struct GNUNET_ATS_SessionKiller); | 1604 | sk = GNUNET_new (struct GNUNET_ATS_SessionKiller); |
291 | sk->session = session; | 1605 | sk->session = session; |
292 | sk->plugin = plugin; | 1606 | sk->plugin = plugin; |
293 | sk->task = GNUNET_SCHEDULER_add_now (&kill_session_task, sk); | 1607 | sk->task = GNUNET_SCHEDULER_add_now (&kill_session_task, |
1608 | sk); | ||
294 | GNUNET_CONTAINER_DLL_insert (sk_head, | 1609 | GNUNET_CONTAINER_DLL_insert (sk_head, |
295 | sk_tail, | 1610 | sk_tail, |
296 | sk); | 1611 | sk); |
@@ -418,7 +1733,9 @@ GST_receive_callback (void *cls, | |||
418 | GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, | 1733 | GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, |
419 | "Processing PONG from `%s'\n", | 1734 | "Processing PONG from `%s'\n", |
420 | GST_plugins_a2s (address)); | 1735 | GST_plugins_a2s (address)); |
421 | if (GNUNET_OK != GST_validation_handle_pong (&address->peer, message)) | 1736 | if (GNUNET_OK != |
1737 | GST_validation_handle_pong (&address->peer, | ||
1738 | message)) | ||
422 | { | 1739 | { |
423 | GNUNET_break_op (0); | 1740 | GNUNET_break_op (0); |
424 | GST_blacklist_abort_matching (address, | 1741 | GST_blacklist_abort_matching (address, |
@@ -508,12 +1825,11 @@ plugin_env_address_change_notification (void *cls, | |||
508 | const struct GNUNET_HELLO_Address *address) | 1825 | const struct GNUNET_HELLO_Address *address) |
509 | { | 1826 | { |
510 | static int addresses = 0; | 1827 | static int addresses = 0; |
511 | struct GNUNET_STATISTICS_Handle *cfg = GST_stats; | ||
512 | 1828 | ||
513 | if (GNUNET_YES == add_remove) | 1829 | if (GNUNET_YES == add_remove) |
514 | { | 1830 | { |
515 | addresses ++; | 1831 | addresses ++; |
516 | GNUNET_STATISTICS_update (cfg, | 1832 | GNUNET_STATISTICS_update (GST_stats, |
517 | "# transport addresses", | 1833 | "# transport addresses", |
518 | 1, | 1834 | 1, |
519 | GNUNET_NO); | 1835 | GNUNET_NO); |
@@ -527,7 +1843,7 @@ plugin_env_address_change_notification (void *cls, | |||
527 | else | 1843 | else |
528 | { | 1844 | { |
529 | addresses --; | 1845 | addresses --; |
530 | GNUNET_STATISTICS_update (cfg, | 1846 | GNUNET_STATISTICS_update (GST_stats, |
531 | "# transport addresses", | 1847 | "# transport addresses", |
532 | -1, | 1848 | -1, |
533 | GNUNET_NO); | 1849 | GNUNET_NO); |
@@ -579,16 +1895,20 @@ plugin_env_session_end (void *cls, | |||
579 | GNUNET_i2s (&address->peer), | 1895 | GNUNET_i2s (&address->peer), |
580 | GST_plugins_a2s (address)); | 1896 | GST_plugins_a2s (address)); |
581 | 1897 | ||
582 | GST_neighbours_session_terminated (&address->peer, session); | 1898 | GST_neighbours_session_terminated (&address->peer, |
1899 | session); | ||
583 | GST_ats_del_session (address, | 1900 | GST_ats_del_session (address, |
584 | session); | 1901 | session); |
585 | GST_blacklist_abort_matching (address, session); | 1902 | GST_blacklist_abort_matching (address, |
1903 | session); | ||
586 | 1904 | ||
587 | for (sk = sk_head; NULL != sk; sk = sk->next) | 1905 | for (sk = sk_head; NULL != sk; sk = sk->next) |
588 | { | 1906 | { |
589 | if (sk->session == session) | 1907 | if (sk->session == session) |
590 | { | 1908 | { |
591 | GNUNET_CONTAINER_DLL_remove (sk_head, sk_tail, sk); | 1909 | GNUNET_CONTAINER_DLL_remove (sk_head, |
1910 | sk_tail, | ||
1911 | sk); | ||
592 | GNUNET_SCHEDULER_cancel (sk->task); | 1912 | GNUNET_SCHEDULER_cancel (sk->task); |
593 | GNUNET_free(sk); | 1913 | GNUNET_free(sk); |
594 | break; | 1914 | break; |
@@ -672,7 +1992,9 @@ plugin_env_session_start (void *cls, | |||
672 | for example for UNIX, we have symmetric connections and thus we | 1992 | for example for UNIX, we have symmetric connections and thus we |
673 | may not know the address yet; add if necessary! */ | 1993 | may not know the address yet; add if necessary! */ |
674 | /* FIXME: maybe change API here so we just pass scope? */ | 1994 | /* FIXME: maybe change API here so we just pass scope? */ |
675 | memset (&prop, 0, sizeof (prop)); | 1995 | memset (&prop, |
1996 | 0, | ||
1997 | sizeof (prop)); | ||
676 | GNUNET_break (GNUNET_ATS_NET_UNSPECIFIED != scope); | 1998 | GNUNET_break (GNUNET_ATS_NET_UNSPECIFIED != scope); |
677 | prop.scope = scope; | 1999 | prop.scope = scope; |
678 | GST_ats_add_inbound_address (address, | 2000 | GST_ats_add_inbound_address (address, |
@@ -750,6 +2072,167 @@ ats_request_address_change (void *cls, | |||
750 | 2072 | ||
751 | 2073 | ||
752 | /** | 2074 | /** |
2075 | * Closure for #test_connection_ok(). | ||
2076 | */ | ||
2077 | struct TestConnectionContext | ||
2078 | { | ||
2079 | /** | ||
2080 | * Is this the first neighbour we're checking? | ||
2081 | */ | ||
2082 | int first; | ||
2083 | |||
2084 | /** | ||
2085 | * Handle to the blacklisting client we need to ask. | ||
2086 | */ | ||
2087 | struct TransportClient *tc; | ||
2088 | }; | ||
2089 | |||
2090 | |||
2091 | /** | ||
2092 | * Got the result about an existing connection from a new blacklister. | ||
2093 | * Shutdown the neighbour if necessary. | ||
2094 | * | ||
2095 | * @param cls unused | ||
2096 | * @param peer the neighbour that was investigated | ||
2097 | * @param address address associated with the request | ||
2098 | * @param session session associated with the request | ||
2099 | * @param allowed #GNUNET_OK if we can keep it, | ||
2100 | * #GNUNET_NO if we must shutdown the connection | ||
2101 | */ | ||
2102 | static void | ||
2103 | confirm_or_drop_neighbour (void *cls, | ||
2104 | const struct GNUNET_PeerIdentity *peer, | ||
2105 | const struct GNUNET_HELLO_Address *address, | ||
2106 | struct GNUNET_ATS_Session *session, | ||
2107 | int allowed) | ||
2108 | { | ||
2109 | if (GNUNET_OK == allowed) | ||
2110 | return; /* we're done */ | ||
2111 | GNUNET_STATISTICS_update (GST_stats, | ||
2112 | gettext_noop ("# disconnects due to blacklist"), | ||
2113 | 1, | ||
2114 | GNUNET_NO); | ||
2115 | GST_neighbours_force_disconnect (peer); | ||
2116 | } | ||
2117 | |||
2118 | |||
2119 | /** | ||
2120 | * Test if an existing connection is still acceptable given a new | ||
2121 | * blacklisting client. | ||
2122 | * | ||
2123 | * @param cls the `struct TestConnectionContext *` | ||
2124 | * @param peer identity of the peer | ||
2125 | * @param address the address | ||
2126 | * @param state current state this peer is in | ||
2127 | * @param state_timeout timeout for the current state of the peer | ||
2128 | * @param bandwidth_in bandwidth assigned inbound | ||
2129 | * @param bandwidth_out bandwidth assigned outbound | ||
2130 | */ | ||
2131 | static void | ||
2132 | test_connection_ok (void *cls, | ||
2133 | const struct GNUNET_PeerIdentity *peer, | ||
2134 | const struct GNUNET_HELLO_Address *address, | ||
2135 | enum GNUNET_TRANSPORT_PeerState state, | ||
2136 | struct GNUNET_TIME_Absolute state_timeout, | ||
2137 | struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in, | ||
2138 | struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out) | ||
2139 | { | ||
2140 | struct TestConnectionContext *tcc = cls; | ||
2141 | struct GST_BlacklistCheck *bc; | ||
2142 | |||
2143 | bc = GNUNET_new (struct GST_BlacklistCheck); | ||
2144 | GNUNET_CONTAINER_DLL_insert (bc_head, | ||
2145 | bc_tail, | ||
2146 | bc); | ||
2147 | bc->peer = *peer; | ||
2148 | bc->address = GNUNET_HELLO_address_copy (address); | ||
2149 | bc->cont = &confirm_or_drop_neighbour; | ||
2150 | bc->cont_cls = NULL; | ||
2151 | bc->bl_pos = tcc->tc; | ||
2152 | if (GNUNET_YES == tcc->first) | ||
2153 | { | ||
2154 | /* all would wait for the same client, no need to | ||
2155 | * create more than just the first task right now */ | ||
2156 | bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, | ||
2157 | bc); | ||
2158 | tcc->first = GNUNET_NO; | ||
2159 | } | ||
2160 | } | ||
2161 | |||
2162 | |||
2163 | /** | ||
2164 | * Initialize a blacklisting client. We got a blacklist-init | ||
2165 | * message from this client, add him to the list of clients | ||
2166 | * to query for blacklisting. | ||
2167 | * | ||
2168 | * @param cls the client | ||
2169 | * @param message the blacklist-init message that was sent | ||
2170 | */ | ||
2171 | static void | ||
2172 | handle_client_blacklist_init (void *cls, | ||
2173 | const struct GNUNET_MessageHeader *message) | ||
2174 | { | ||
2175 | struct TransportClient *tc = cls; | ||
2176 | struct TestConnectionContext tcc; | ||
2177 | |||
2178 | if (CT_NONE != tc->type) | ||
2179 | { | ||
2180 | GNUNET_break (0); | ||
2181 | GNUNET_SERVICE_client_drop (tc->client); | ||
2182 | return; | ||
2183 | } | ||
2184 | GNUNET_SERVICE_client_mark_monitor (tc->client); | ||
2185 | tc->type = CT_BLACKLIST; | ||
2186 | tc->details.blacklist.call_receive_done = GNUNET_YES; | ||
2187 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2188 | "New blacklist client %p\n", | ||
2189 | tc); | ||
2190 | /* confirm that all existing connections are OK! */ | ||
2191 | tcc.tc = tc; | ||
2192 | tcc.first = GNUNET_YES; | ||
2193 | GST_neighbours_iterate (&test_connection_ok, | ||
2194 | &tcc); | ||
2195 | } | ||
2196 | |||
2197 | |||
2198 | /** | ||
2199 | * Free the given entry in the blacklist. | ||
2200 | * | ||
2201 | * @param cls unused | ||
2202 | * @param key host identity (unused) | ||
2203 | * @param value the blacklist entry | ||
2204 | * @return #GNUNET_OK (continue to iterate) | ||
2205 | */ | ||
2206 | static int | ||
2207 | free_blacklist_entry (void *cls, | ||
2208 | const struct GNUNET_PeerIdentity *key, | ||
2209 | void *value) | ||
2210 | { | ||
2211 | char *be = value; | ||
2212 | |||
2213 | GNUNET_free_non_null (be); | ||
2214 | return GNUNET_OK; | ||
2215 | } | ||
2216 | |||
2217 | |||
2218 | /** | ||
2219 | * Set traffic metric to manipulate | ||
2220 | * | ||
2221 | * @param cls closure | ||
2222 | * @param message containing information | ||
2223 | */ | ||
2224 | static void | ||
2225 | handle_client_set_metric (void *cls, | ||
2226 | const struct TrafficMetricMessage *tm) | ||
2227 | { | ||
2228 | struct TransportClient *tc = cls; | ||
2229 | |||
2230 | GST_manipulation_set_metric (tm); | ||
2231 | GNUNET_SERVICE_client_continue (tc->client); | ||
2232 | } | ||
2233 | |||
2234 | |||
2235 | /** | ||
753 | * Function called when the service shuts down. Unloads our plugins | 2236 | * Function called when the service shuts down. Unloads our plugins |
754 | * and cancels pending validations. | 2237 | * and cancels pending validations. |
755 | * | 2238 | * |
@@ -758,6 +2241,8 @@ ats_request_address_change (void *cls, | |||
758 | static void | 2241 | static void |
759 | shutdown_task (void *cls) | 2242 | shutdown_task (void *cls) |
760 | { | 2243 | { |
2244 | struct AddressToStringContext *cur; | ||
2245 | |||
761 | GST_neighbours_stop (); | 2246 | GST_neighbours_stop (); |
762 | GST_plugins_unload (); | 2247 | GST_plugins_unload (); |
763 | GST_validation_stop (); | 2248 | GST_validation_stop (); |
@@ -768,8 +2253,28 @@ shutdown_task (void *cls) | |||
768 | GST_ats_connect = NULL; | 2253 | GST_ats_connect = NULL; |
769 | GNUNET_ATS_scanner_done (GST_is); | 2254 | GNUNET_ATS_scanner_done (GST_is); |
770 | GST_is = NULL; | 2255 | GST_is = NULL; |
771 | GST_clients_stop (); | 2256 | while (NULL != (cur = a2s_head)) |
772 | GST_blacklist_stop (); | 2257 | { |
2258 | GNUNET_CONTAINER_DLL_remove (a2s_head, | ||
2259 | a2s_tail, | ||
2260 | cur); | ||
2261 | GNUNET_free (cur); | ||
2262 | } | ||
2263 | if (NULL != plugin_nc) | ||
2264 | { | ||
2265 | GNUNET_notification_context_destroy (plugin_nc); | ||
2266 | plugin_nc = NULL; | ||
2267 | } | ||
2268 | GNUNET_CONTAINER_multipeermap_destroy (active_stccs); | ||
2269 | active_stccs = NULL; | ||
2270 | if (NULL != blacklist) | ||
2271 | { | ||
2272 | GNUNET_CONTAINER_multipeermap_iterate (blacklist, | ||
2273 | &free_blacklist_entry, | ||
2274 | NULL); | ||
2275 | GNUNET_CONTAINER_multipeermap_destroy (blacklist); | ||
2276 | blacklist = NULL; | ||
2277 | } | ||
773 | GST_hello_stop (); | 2278 | GST_hello_stop (); |
774 | GST_manipulation_stop (); | 2279 | GST_manipulation_stop (); |
775 | 2280 | ||
@@ -785,10 +2290,452 @@ shutdown_task (void *cls) | |||
785 | } | 2290 | } |
786 | if (NULL != GST_my_private_key) | 2291 | if (NULL != GST_my_private_key) |
787 | { | 2292 | { |
788 | GNUNET_free(GST_my_private_key); | 2293 | GNUNET_free (GST_my_private_key); |
789 | GST_my_private_key = NULL; | 2294 | GST_my_private_key = NULL; |
790 | } | 2295 | } |
791 | GST_server = NULL; | 2296 | } |
2297 | |||
2298 | |||
2299 | /** | ||
2300 | * Perform next action in the blacklist check. | ||
2301 | * | ||
2302 | * @param cls the `struct GST_BlacklistCheck *` | ||
2303 | */ | ||
2304 | static void | ||
2305 | do_blacklist_check (void *cls) | ||
2306 | { | ||
2307 | struct GST_BlacklistCheck *bc = cls; | ||
2308 | struct TransportClient *tc; | ||
2309 | struct GNUNET_MQ_Envelope *env; | ||
2310 | struct BlacklistMessage *bm; | ||
2311 | |||
2312 | bc->task = NULL; | ||
2313 | while (NULL != (tc = bc->bl_pos)) | ||
2314 | { | ||
2315 | if (CT_BLACKLIST == tc->type) | ||
2316 | break; | ||
2317 | bc->bl_pos = tc->next; | ||
2318 | } | ||
2319 | if (NULL == tc) | ||
2320 | { | ||
2321 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2322 | "No other blacklist clients active, will allow neighbour `%s'\n", | ||
2323 | GNUNET_i2s (&bc->peer)); | ||
2324 | |||
2325 | bc->cont (bc->cont_cls, | ||
2326 | &bc->peer, | ||
2327 | bc->address, | ||
2328 | bc->session, | ||
2329 | GNUNET_OK); | ||
2330 | GST_blacklist_test_cancel (bc); | ||
2331 | return; | ||
2332 | } | ||
2333 | if ( (NULL != tc->details.blacklist.bc) || | ||
2334 | (GNUNET_NO != tc->details.blacklist.waiting_for_reply) ) | ||
2335 | return; /* someone else busy with this client */ | ||
2336 | tc->details.blacklist.bc = bc; | ||
2337 | env = GNUNET_MQ_msg (bm, | ||
2338 | GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY); | ||
2339 | bm->is_allowed = htonl (0); | ||
2340 | bm->peer = bc->peer; | ||
2341 | GNUNET_MQ_send (tc->mq, | ||
2342 | env); | ||
2343 | if (GNUNET_YES == tc->details.blacklist.call_receive_done) | ||
2344 | { | ||
2345 | tc->details.blacklist.call_receive_done = GNUNET_NO; | ||
2346 | GNUNET_SERVICE_client_continue (tc->client); | ||
2347 | } | ||
2348 | tc->details.blacklist.waiting_for_reply = GNUNET_YES; | ||
2349 | } | ||
2350 | |||
2351 | |||
2352 | /** | ||
2353 | * A blacklisting client has sent us reply. Process it. | ||
2354 | * | ||
2355 | * @param cls the client | ||
2356 | * @param msg the blacklist-reply message that was sent | ||
2357 | */ | ||
2358 | static void | ||
2359 | handle_client_blacklist_reply (void *cls, | ||
2360 | const struct BlacklistMessage *msg) | ||
2361 | { | ||
2362 | struct TransportClient *tc = cls; | ||
2363 | struct GST_BlacklistCheck *bc; | ||
2364 | |||
2365 | if (CT_BLACKLIST != tc->type) | ||
2366 | { | ||
2367 | GNUNET_break (0); | ||
2368 | GNUNET_SERVICE_client_drop (tc->client); | ||
2369 | return; | ||
2370 | } | ||
2371 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2372 | "Blacklist client %p sent reply for `%s'\n", | ||
2373 | tc, | ||
2374 | GNUNET_i2s (&msg->peer)); | ||
2375 | bc = tc->details.blacklist.bc; | ||
2376 | tc->details.blacklist.bc = NULL; | ||
2377 | tc->details.blacklist.waiting_for_reply = GNUNET_NO; | ||
2378 | tc->details.blacklist.call_receive_done = GNUNET_YES; | ||
2379 | if (NULL != bc) | ||
2380 | { | ||
2381 | /* only run this if the blacklist check has not been | ||
2382 | * cancelled in the meantime... */ | ||
2383 | GNUNET_assert (bc->bl_pos == tc); | ||
2384 | if (ntohl (msg->is_allowed) == GNUNET_SYSERR) | ||
2385 | { | ||
2386 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2387 | "Blacklist check failed, peer not allowed\n"); | ||
2388 | /* For the duration of the continuation, make the ongoing | ||
2389 | check invisible (to avoid double-cancellation); then | ||
2390 | add it back again so we can re-use GST_blacklist_test_cancel() */ | ||
2391 | GNUNET_CONTAINER_DLL_remove (bc_head, | ||
2392 | bc_tail, | ||
2393 | bc); | ||
2394 | bc->cont (bc->cont_cls, | ||
2395 | &bc->peer, | ||
2396 | bc->address, | ||
2397 | bc->session, | ||
2398 | GNUNET_NO); | ||
2399 | GNUNET_CONTAINER_DLL_insert (bc_head, | ||
2400 | bc_tail, | ||
2401 | bc); | ||
2402 | GST_blacklist_test_cancel (bc); | ||
2403 | tc->details.blacklist.call_receive_done = GNUNET_NO; | ||
2404 | GNUNET_SERVICE_client_continue (tc->client); | ||
2405 | return; | ||
2406 | } | ||
2407 | else | ||
2408 | { | ||
2409 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2410 | "Blacklist check succeeded, continuing with checks\n"); | ||
2411 | tc->details.blacklist.call_receive_done = GNUNET_NO; | ||
2412 | GNUNET_SERVICE_client_continue (tc->client); | ||
2413 | bc->bl_pos = tc->next; | ||
2414 | bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, | ||
2415 | bc); | ||
2416 | } | ||
2417 | } | ||
2418 | /* check if any other blacklist checks are waiting for this blacklister */ | ||
2419 | for (bc = bc_head; bc != NULL; bc = bc->next) | ||
2420 | if ( (bc->bl_pos == tc) && | ||
2421 | (NULL == bc->task) ) | ||
2422 | { | ||
2423 | bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, | ||
2424 | bc); | ||
2425 | break; | ||
2426 | } | ||
2427 | } | ||
2428 | |||
2429 | |||
2430 | /** | ||
2431 | * Add the given peer to the blacklist (for the given transport). | ||
2432 | * | ||
2433 | * @param peer peer to blacklist | ||
2434 | * @param transport_name transport to blacklist for this peer, NULL for all | ||
2435 | */ | ||
2436 | void | ||
2437 | GST_blacklist_add_peer (const struct GNUNET_PeerIdentity *peer, | ||
2438 | const char *transport_name) | ||
2439 | { | ||
2440 | char *transport = NULL; | ||
2441 | |||
2442 | if (NULL != transport_name) | ||
2443 | { | ||
2444 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
2445 | "Adding peer `%s' with plugin `%s' to blacklist\n", | ||
2446 | GNUNET_i2s (peer), | ||
2447 | transport_name); | ||
2448 | transport = GNUNET_strdup (transport_name); | ||
2449 | } | ||
2450 | else | ||
2451 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
2452 | "Adding peer `%s' with all plugins to blacklist\n", | ||
2453 | GNUNET_i2s (peer)); | ||
2454 | if (NULL == blacklist) | ||
2455 | blacklist = | ||
2456 | GNUNET_CONTAINER_multipeermap_create (TRANSPORT_BLACKLIST_HT_SIZE, | ||
2457 | GNUNET_NO); | ||
2458 | |||
2459 | GNUNET_CONTAINER_multipeermap_put (blacklist, | ||
2460 | peer, | ||
2461 | transport, | ||
2462 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
2463 | } | ||
2464 | |||
2465 | |||
2466 | /** | ||
2467 | * Abort blacklist if @a address and @a session match. | ||
2468 | * | ||
2469 | * @param address address used to abort matching checks | ||
2470 | * @param session session used to abort matching checks | ||
2471 | */ | ||
2472 | void | ||
2473 | GST_blacklist_abort_matching (const struct GNUNET_HELLO_Address *address, | ||
2474 | struct GNUNET_ATS_Session *session) | ||
2475 | { | ||
2476 | struct GST_BlacklistCheck *bc; | ||
2477 | struct GST_BlacklistCheck *n; | ||
2478 | |||
2479 | n = bc_head; | ||
2480 | while (NULL != (bc = n)) | ||
2481 | { | ||
2482 | n = bc->next; | ||
2483 | if ( (bc->session == session) && | ||
2484 | (0 == GNUNET_HELLO_address_cmp (bc->address, | ||
2485 | address)) ) | ||
2486 | { | ||
2487 | bc->cont (bc->cont_cls, | ||
2488 | &bc->peer, | ||
2489 | bc->address, | ||
2490 | bc->session, | ||
2491 | GNUNET_SYSERR); | ||
2492 | GST_blacklist_test_cancel (bc); | ||
2493 | } | ||
2494 | } | ||
2495 | } | ||
2496 | |||
2497 | |||
2498 | /** | ||
2499 | * Test if the given blacklist entry matches. If so, | ||
2500 | * abort the iteration. | ||
2501 | * | ||
2502 | * @param cls the transport name to match (const char*) | ||
2503 | * @param key the key (unused) | ||
2504 | * @param value the 'char *' (name of a blacklisted transport) | ||
2505 | * @return #GNUNET_OK if the entry does not match, #GNUNET_NO if it matches | ||
2506 | */ | ||
2507 | static int | ||
2508 | test_blacklisted (void *cls, | ||
2509 | const struct GNUNET_PeerIdentity *key, | ||
2510 | void *value) | ||
2511 | { | ||
2512 | const char *transport_name = cls; | ||
2513 | char *be = value; | ||
2514 | |||
2515 | /* Blacklist entry be: | ||
2516 | * (NULL == be): peer is blacklisted with all plugins | ||
2517 | * (NULL != be): peer is blacklisted for a specific plugin | ||
2518 | * | ||
2519 | * If (NULL != transport_name) we look for a transport specific entry: | ||
2520 | * if (transport_name == be) forbidden | ||
2521 | * | ||
2522 | */ | ||
2523 | |||
2524 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2525 | "Comparing BL request for peer `%4s':`%s' with BL entry: `%s'\n", | ||
2526 | GNUNET_i2s (key), | ||
2527 | (NULL == transport_name) ? "unspecified" : transport_name, | ||
2528 | (NULL == be) ? "all plugins" : be); | ||
2529 | /* all plugins for this peer were blacklisted: disallow */ | ||
2530 | if (NULL == value) | ||
2531 | return GNUNET_NO; | ||
2532 | |||
2533 | /* blacklist check for specific transport */ | ||
2534 | if ( (NULL != transport_name) && | ||
2535 | (NULL != value) ) | ||
2536 | { | ||
2537 | if (0 == strcmp (transport_name, | ||
2538 | be)) | ||
2539 | return GNUNET_NO; /* plugin is blacklisted! */ | ||
2540 | } | ||
2541 | return GNUNET_OK; | ||
2542 | } | ||
2543 | |||
2544 | |||
2545 | /** | ||
2546 | * Test if a peer/transport combination is blacklisted. | ||
2547 | * | ||
2548 | * @param peer the identity of the peer to test | ||
2549 | * @param transport_name name of the transport to test, never NULL | ||
2550 | * @param cont function to call with result | ||
2551 | * @param cont_cls closure for @a cont | ||
2552 | * @param address address to pass back to @a cont, can be NULL | ||
2553 | * @param session session to pass back to @a cont, can be NULL | ||
2554 | * @return handle to the blacklist check, NULL if the decision | ||
2555 | * was made instantly and @a cont was already called | ||
2556 | */ | ||
2557 | struct GST_BlacklistCheck * | ||
2558 | GST_blacklist_test_allowed (const struct GNUNET_PeerIdentity *peer, | ||
2559 | const char *transport_name, | ||
2560 | GST_BlacklistTestContinuation cont, | ||
2561 | void *cont_cls, | ||
2562 | const struct GNUNET_HELLO_Address *address, | ||
2563 | struct GNUNET_ATS_Session *session) | ||
2564 | { | ||
2565 | struct GST_BlacklistCheck *bc; | ||
2566 | struct TransportClient *tc; | ||
2567 | |||
2568 | GNUNET_assert (NULL != peer); | ||
2569 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2570 | "Blacklist check for peer `%s':%s\n", | ||
2571 | GNUNET_i2s (peer), | ||
2572 | (NULL != transport_name) ? transport_name : "unspecified"); | ||
2573 | |||
2574 | /* Check local blacklist by iterating over hashmap | ||
2575 | * If iteration is aborted, we found a matching blacklist entry */ | ||
2576 | if ((NULL != blacklist) && | ||
2577 | (GNUNET_SYSERR == | ||
2578 | GNUNET_CONTAINER_multipeermap_get_multiple (blacklist, peer, | ||
2579 | &test_blacklisted, | ||
2580 | (void *) transport_name))) | ||
2581 | { | ||
2582 | /* Disallowed by config, disapprove instantly */ | ||
2583 | GNUNET_STATISTICS_update (GST_stats, | ||
2584 | gettext_noop ("# disconnects due to blacklist"), | ||
2585 | 1, | ||
2586 | GNUNET_NO); | ||
2587 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
2588 | _("Disallowing connection to peer `%s' on transport %s\n"), | ||
2589 | GNUNET_i2s (peer), | ||
2590 | (NULL != transport_name) ? transport_name : "unspecified"); | ||
2591 | if (NULL != cont) | ||
2592 | cont (cont_cls, | ||
2593 | peer, | ||
2594 | address, | ||
2595 | session, | ||
2596 | GNUNET_NO); | ||
2597 | return NULL; | ||
2598 | } | ||
2599 | |||
2600 | for (tc = clients_head; NULL != tc; tc = tc->next) | ||
2601 | if (CT_BLACKLIST == tc->type) | ||
2602 | break; | ||
2603 | if (NULL == tc) | ||
2604 | { | ||
2605 | /* no blacklist clients, approve instantly */ | ||
2606 | if (NULL != cont) | ||
2607 | cont (cont_cls, | ||
2608 | peer, | ||
2609 | address, | ||
2610 | session, | ||
2611 | GNUNET_OK); | ||
2612 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2613 | "Allowing connection to peer `%s' %s\n", | ||
2614 | GNUNET_i2s (peer), | ||
2615 | (NULL != transport_name) ? transport_name : ""); | ||
2616 | return NULL; | ||
2617 | } | ||
2618 | |||
2619 | /* need to query blacklist clients */ | ||
2620 | bc = GNUNET_new (struct GST_BlacklistCheck); | ||
2621 | GNUNET_CONTAINER_DLL_insert (bc_head, | ||
2622 | bc_tail, | ||
2623 | bc); | ||
2624 | bc->peer = *peer; | ||
2625 | bc->address = GNUNET_HELLO_address_copy (address); | ||
2626 | bc->session = session; | ||
2627 | bc->cont = cont; | ||
2628 | bc->cont_cls = cont_cls; | ||
2629 | bc->bl_pos = tc; | ||
2630 | bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, | ||
2631 | bc); | ||
2632 | return bc; | ||
2633 | } | ||
2634 | |||
2635 | |||
2636 | /** | ||
2637 | * Cancel a blacklist check. | ||
2638 | * | ||
2639 | * @param bc check to cancel | ||
2640 | */ | ||
2641 | void | ||
2642 | GST_blacklist_test_cancel (struct GST_BlacklistCheck *bc) | ||
2643 | { | ||
2644 | GNUNET_CONTAINER_DLL_remove (bc_head, | ||
2645 | bc_tail, | ||
2646 | bc); | ||
2647 | if (NULL != bc->bl_pos) | ||
2648 | { | ||
2649 | if ( (CT_BLACKLIST == bc->bl_pos->type) && | ||
2650 | (bc->bl_pos->details.blacklist.bc == bc) ) | ||
2651 | { | ||
2652 | /* we're at the head of the queue, remove us! */ | ||
2653 | bc->bl_pos->details.blacklist.bc = NULL; | ||
2654 | } | ||
2655 | } | ||
2656 | if (NULL != bc->task) | ||
2657 | { | ||
2658 | GNUNET_SCHEDULER_cancel (bc->task); | ||
2659 | bc->task = NULL; | ||
2660 | } | ||
2661 | GNUNET_free_non_null (bc->address); | ||
2662 | GNUNET_free (bc); | ||
2663 | } | ||
2664 | |||
2665 | |||
2666 | /** | ||
2667 | * Function to iterate over options in the blacklisting section for a peer. | ||
2668 | * | ||
2669 | * @param cls closure | ||
2670 | * @param section name of the section | ||
2671 | * @param option name of the option | ||
2672 | * @param value value of the option | ||
2673 | */ | ||
2674 | static void | ||
2675 | blacklist_cfg_iter (void *cls, | ||
2676 | const char *section, | ||
2677 | const char *option, | ||
2678 | const char *value) | ||
2679 | { | ||
2680 | unsigned int *res = cls; | ||
2681 | struct GNUNET_PeerIdentity peer; | ||
2682 | char *plugs; | ||
2683 | char *pos; | ||
2684 | |||
2685 | if (GNUNET_OK != | ||
2686 | GNUNET_CRYPTO_eddsa_public_key_from_string (option, | ||
2687 | strlen (option), | ||
2688 | &peer.public_key)) | ||
2689 | return; | ||
2690 | |||
2691 | if ((NULL == value) || (0 == strcmp(value, ""))) | ||
2692 | { | ||
2693 | /* Blacklist whole peer */ | ||
2694 | GST_blacklist_add_peer (&peer, NULL); | ||
2695 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
2696 | _("Adding blacklisting entry for peer `%s'\n"), | ||
2697 | GNUNET_i2s (&peer)); | ||
2698 | } | ||
2699 | else | ||
2700 | { | ||
2701 | plugs = GNUNET_strdup (value); | ||
2702 | for (pos = strtok (plugs, " "); pos != NULL; pos = strtok (NULL, " ")) | ||
2703 | { | ||
2704 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
2705 | _("Adding blacklisting entry for peer `%s':`%s'\n"), | ||
2706 | GNUNET_i2s (&peer), pos); | ||
2707 | GST_blacklist_add_peer (&peer, pos); | ||
2708 | } | ||
2709 | GNUNET_free (plugs); | ||
2710 | } | ||
2711 | (*res)++; | ||
2712 | } | ||
2713 | |||
2714 | |||
2715 | /** | ||
2716 | * Read blacklist configuration | ||
2717 | * | ||
2718 | * @param cfg the configuration handle | ||
2719 | * @param my_id my peer identity | ||
2720 | */ | ||
2721 | static void | ||
2722 | read_blacklist_configuration (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
2723 | const struct GNUNET_PeerIdentity *my_id) | ||
2724 | { | ||
2725 | char cfg_sect[512]; | ||
2726 | unsigned int res = 0; | ||
2727 | |||
2728 | GNUNET_snprintf (cfg_sect, | ||
2729 | sizeof (cfg_sect), | ||
2730 | "transport-blacklist-%s", | ||
2731 | GNUNET_i2s_full (my_id)); | ||
2732 | GNUNET_CONFIGURATION_iterate_section_values (cfg, | ||
2733 | cfg_sect, | ||
2734 | &blacklist_cfg_iter, | ||
2735 | &res); | ||
2736 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2737 | "Loaded %u blacklisting entries from configuration\n", | ||
2738 | res); | ||
792 | } | 2739 | } |
793 | 2740 | ||
794 | 2741 | ||
@@ -796,13 +2743,13 @@ shutdown_task (void *cls) | |||
796 | * Initiate transport service. | 2743 | * Initiate transport service. |
797 | * | 2744 | * |
798 | * @param cls closure | 2745 | * @param cls closure |
799 | * @param server the initialized server | ||
800 | * @param c configuration to use | 2746 | * @param c configuration to use |
2747 | * @param service the initialized service | ||
801 | */ | 2748 | */ |
802 | static void | 2749 | static void |
803 | run (void *cls, | 2750 | run (void *cls, |
804 | struct GNUNET_SERVER_Handle *server, | 2751 | const struct GNUNET_CONFIGURATION_Handle *c, |
805 | const struct GNUNET_CONFIGURATION_Handle *c) | 2752 | struct GNUNET_SERVICE_Handle *service) |
806 | { | 2753 | { |
807 | char *keyfile; | 2754 | char *keyfile; |
808 | struct GNUNET_CRYPTO_EddsaPrivateKey *pk; | 2755 | struct GNUNET_CRYPTO_EddsaPrivateKey *pk; |
@@ -832,7 +2779,6 @@ run (void *cls, | |||
832 | { | 2779 | { |
833 | hello_expiration = GNUNET_CONSTANTS_HELLO_ADDRESS_EXPIRATION; | 2780 | hello_expiration = GNUNET_CONSTANTS_HELLO_ADDRESS_EXPIRATION; |
834 | } | 2781 | } |
835 | GST_server = server; | ||
836 | pk = GNUNET_CRYPTO_eddsa_key_create_from_file (keyfile); | 2782 | pk = GNUNET_CRYPTO_eddsa_key_create_from_file (keyfile); |
837 | GNUNET_free (keyfile); | 2783 | GNUNET_free (keyfile); |
838 | GNUNET_assert (NULL != pk); | 2784 | GNUNET_assert (NULL != pk); |
@@ -842,7 +2788,7 @@ run (void *cls, | |||
842 | GST_peerinfo = GNUNET_PEERINFO_connect (GST_cfg); | 2788 | GST_peerinfo = GNUNET_PEERINFO_connect (GST_cfg); |
843 | GNUNET_CRYPTO_eddsa_key_get_public (GST_my_private_key, | 2789 | GNUNET_CRYPTO_eddsa_key_get_public (GST_my_private_key, |
844 | &GST_my_identity.public_key); | 2790 | &GST_my_identity.public_key); |
845 | GNUNET_assert(NULL != GST_my_private_key); | 2791 | GNUNET_assert (NULL != GST_my_private_key); |
846 | 2792 | ||
847 | GNUNET_log(GNUNET_ERROR_TYPE_INFO, | 2793 | GNUNET_log(GNUNET_ERROR_TYPE_INFO, |
848 | "My identity is `%4s'\n", | 2794 | "My identity is `%4s'\n", |
@@ -852,24 +2798,28 @@ run (void *cls, | |||
852 | NULL); | 2798 | NULL); |
853 | if (NULL == GST_peerinfo) | 2799 | if (NULL == GST_peerinfo) |
854 | { | 2800 | { |
855 | GNUNET_log(GNUNET_ERROR_TYPE_ERROR, | 2801 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
856 | _("Could not access PEERINFO service. Exiting.\n")); | 2802 | _("Could not access PEERINFO service. Exiting.\n")); |
857 | GNUNET_SCHEDULER_shutdown (); | 2803 | GNUNET_SCHEDULER_shutdown (); |
858 | return; | 2804 | return; |
859 | } | 2805 | } |
860 | 2806 | ||
861 | max_fd_rlimit = 0; | 2807 | max_fd_rlimit = 0; |
862 | #if HAVE_GETRLIMIT | 2808 | #if HAVE_GETRLIMIT |
863 | struct rlimit r_file; | ||
864 | if (0 == getrlimit (RLIMIT_NOFILE, &r_file)) | ||
865 | { | 2809 | { |
866 | max_fd_rlimit = r_file.rlim_cur; | 2810 | struct rlimit r_file; |
867 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 2811 | |
868 | "Maximum number of open files was: %u/%u\n", | 2812 | if (0 == getrlimit (RLIMIT_NOFILE, |
869 | (unsigned int) r_file.rlim_cur, | 2813 | &r_file)) |
870 | (unsigned int) r_file.rlim_max); | 2814 | { |
2815 | max_fd_rlimit = r_file.rlim_cur; | ||
2816 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2817 | "Maximum number of open files was: %u/%u\n", | ||
2818 | (unsigned int) r_file.rlim_cur, | ||
2819 | (unsigned int) r_file.rlim_max); | ||
2820 | } | ||
2821 | max_fd_rlimit = (9 * max_fd_rlimit) / 10; /* Keep 10% for rest of transport */ | ||
871 | } | 2822 | } |
872 | max_fd_rlimit = (9 * max_fd_rlimit) / 10; /* Keep 10% for rest of transport */ | ||
873 | #endif | 2823 | #endif |
874 | if (GNUNET_OK != | 2824 | if (GNUNET_OK != |
875 | GNUNET_CONFIGURATION_get_value_number (GST_cfg, | 2825 | GNUNET_CONFIGURATION_get_value_number (GST_cfg, |
@@ -897,9 +2847,8 @@ run (void *cls, | |||
897 | if (GNUNET_SYSERR == friend_only) | 2847 | if (GNUNET_SYSERR == friend_only) |
898 | friend_only = GNUNET_NO; /* According to topology defaults */ | 2848 | friend_only = GNUNET_NO; /* According to topology defaults */ |
899 | /* start subsystems */ | 2849 | /* start subsystems */ |
900 | GST_blacklist_start (GST_server, | 2850 | read_blacklist_configuration (GST_cfg, |
901 | GST_cfg, | 2851 | &GST_my_identity); |
902 | &GST_my_identity); | ||
903 | GST_is = GNUNET_ATS_scanner_init (); | 2852 | GST_is = GNUNET_ATS_scanner_init (); |
904 | GST_ats_connect = GNUNET_ATS_connectivity_init (GST_cfg); | 2853 | GST_ats_connect = GNUNET_ATS_connectivity_init (GST_cfg); |
905 | GST_ats = GNUNET_ATS_scheduling_init (GST_cfg, | 2854 | GST_ats = GNUNET_ATS_scheduling_init (GST_cfg, |
@@ -915,26 +2864,60 @@ run (void *cls, | |||
915 | &process_hello_update, | 2864 | &process_hello_update, |
916 | NULL); | 2865 | NULL); |
917 | GST_neighbours_start ((max_fd / 3) * 2); | 2866 | GST_neighbours_start ((max_fd / 3) * 2); |
918 | GST_clients_start (GST_server); | 2867 | active_stccs = GNUNET_CONTAINER_multipeermap_create (128, |
2868 | GNUNET_YES); | ||
2869 | plugin_nc = GNUNET_notification_context_create (0); | ||
919 | GST_validation_start ((max_fd / 3)); | 2870 | GST_validation_start ((max_fd / 3)); |
920 | } | 2871 | } |
921 | 2872 | ||
922 | 2873 | ||
923 | /** | 2874 | /** |
924 | * The main function for the transport service. | 2875 | * Define "main" method using service macro. |
925 | * | ||
926 | * @param argc number of arguments from the command line | ||
927 | * @param argv command line arguments | ||
928 | * @return 0 ok, 1 on error | ||
929 | */ | 2876 | */ |
930 | int | 2877 | GNUNET_SERVICE_MAIN |
931 | main (int argc, | 2878 | ("transport", |
932 | char * const *argv) | 2879 | GNUNET_SERVICE_OPTION_NONE, |
933 | { | 2880 | &run, |
934 | return | 2881 | &client_connect_cb, |
935 | (GNUNET_OK | 2882 | &client_disconnect_cb, |
936 | == GNUNET_SERVICE_run (argc, argv, "transport", | 2883 | NULL, |
937 | GNUNET_SERVICE_OPTION_NONE, &run, NULL )) ? 0 : 1; | 2884 | GNUNET_MQ_hd_fixed_size (client_start, |
938 | } | 2885 | GNUNET_MESSAGE_TYPE_TRANSPORT_START, |
2886 | struct StartMessage, | ||
2887 | NULL), | ||
2888 | GNUNET_MQ_hd_var_size (client_hello, | ||
2889 | GNUNET_MESSAGE_TYPE_HELLO, | ||
2890 | struct GNUNET_MessageHeader, | ||
2891 | NULL), | ||
2892 | GNUNET_MQ_hd_var_size (client_send, | ||
2893 | GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, | ||
2894 | struct OutboundMessage, | ||
2895 | NULL), | ||
2896 | GNUNET_MQ_hd_var_size (client_address_to_string, | ||
2897 | GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING, | ||
2898 | struct AddressLookupMessage, | ||
2899 | NULL), | ||
2900 | GNUNET_MQ_hd_fixed_size (client_monitor_peers, | ||
2901 | GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_REQUEST, | ||
2902 | struct PeerMonitorMessage, | ||
2903 | NULL), | ||
2904 | GNUNET_MQ_hd_fixed_size (client_blacklist_init, | ||
2905 | GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT, | ||
2906 | struct GNUNET_MessageHeader, | ||
2907 | NULL), | ||
2908 | GNUNET_MQ_hd_fixed_size (client_blacklist_reply, | ||
2909 | GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY, | ||
2910 | struct BlacklistMessage, | ||
2911 | NULL), | ||
2912 | GNUNET_MQ_hd_fixed_size (client_set_metric, | ||
2913 | GNUNET_MESSAGE_TYPE_TRANSPORT_TRAFFIC_METRIC, | ||
2914 | struct TrafficMetricMessage, | ||
2915 | NULL), | ||
2916 | GNUNET_MQ_hd_fixed_size (client_monitor_plugins, | ||
2917 | GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PLUGIN_START, | ||
2918 | struct GNUNET_MessageHeader, | ||
2919 | NULL), | ||
2920 | GNUNET_MQ_handler_end ()); | ||
2921 | |||
939 | 2922 | ||
940 | /* end of file gnunet-service-transport.c */ | 2923 | /* end of file gnunet-service-transport.c */ |
diff --git a/src/transport/gnunet-service-transport.h b/src/transport/gnunet-service-transport.h index 981996a00..2807afd79 100644 --- a/src/transport/gnunet-service-transport.h +++ b/src/transport/gnunet-service-transport.h | |||
@@ -92,6 +92,83 @@ typedef void | |||
92 | 92 | ||
93 | 93 | ||
94 | /** | 94 | /** |
95 | * Continuation called from a blacklist test. | ||
96 | * | ||
97 | * @param cls closure | ||
98 | * @param peer identity of peer that was tested | ||
99 | * @param address address associated with the request | ||
100 | * @param session session associated with the request | ||
101 | * @param result #GNUNET_OK if the connection is allowed, | ||
102 | * #GNUNET_NO if not, | ||
103 | * #GNUNET_SYSERR if operation was aborted | ||
104 | */ | ||
105 | typedef void | ||
106 | (*GST_BlacklistTestContinuation) (void *cls, | ||
107 | const struct GNUNET_PeerIdentity *peer, | ||
108 | const struct GNUNET_HELLO_Address *address, | ||
109 | struct GNUNET_ATS_Session *session, | ||
110 | int result); | ||
111 | |||
112 | |||
113 | /** | ||
114 | * Add the given peer to the blacklist (for the given transport). | ||
115 | * | ||
116 | * @param peer peer to blacklist | ||
117 | * @param transport_name transport to blacklist for this peer, NULL for all | ||
118 | */ | ||
119 | void | ||
120 | GST_blacklist_add_peer (const struct GNUNET_PeerIdentity *peer, | ||
121 | const char *transport_name); | ||
122 | |||
123 | |||
124 | /** | ||
125 | * Handle to an active blacklist check. | ||
126 | */ | ||
127 | struct GST_BlacklistCheck; | ||
128 | |||
129 | |||
130 | |||
131 | /** | ||
132 | * Test if a peer/transport combination is blacklisted. | ||
133 | * | ||
134 | * @param peer the identity of the peer to test | ||
135 | * @param transport_name name of the transport to test, never NULL | ||
136 | * @param cont function to call with result | ||
137 | * @param cont_cls closure for @a cont | ||
138 | * @param address address to pass back to @a cont, can be NULL | ||
139 | * @param session session to pass back to @a cont, can be NULL | ||
140 | * @return handle to the blacklist check, NULL if the decision | ||
141 | * was made instantly and @a cont was already called | ||
142 | */ | ||
143 | struct GST_BlacklistCheck * | ||
144 | GST_blacklist_test_allowed (const struct GNUNET_PeerIdentity *peer, | ||
145 | const char *transport_name, | ||
146 | GST_BlacklistTestContinuation cont, | ||
147 | void *cont_cls, | ||
148 | const struct GNUNET_HELLO_Address *address, | ||
149 | struct GNUNET_ATS_Session *session); | ||
150 | |||
151 | |||
152 | /** | ||
153 | * Abort blacklist if @a address and @a session match. | ||
154 | * | ||
155 | * @param address address used to abort matching checks | ||
156 | * @param session session used to abort matching checks | ||
157 | */ | ||
158 | void | ||
159 | GST_blacklist_abort_matching (const struct GNUNET_HELLO_Address *address, | ||
160 | struct GNUNET_ATS_Session *session); | ||
161 | |||
162 | /** | ||
163 | * Cancel a blacklist check. | ||
164 | * | ||
165 | * @param bc check to cancel | ||
166 | */ | ||
167 | void | ||
168 | GST_blacklist_test_cancel (struct GST_BlacklistCheck *bc); | ||
169 | |||
170 | |||
171 | /** | ||
95 | * Function called by the transport for each received message. | 172 | * Function called by the transport for each received message. |
96 | * | 173 | * |
97 | * @param cls closure, const char* with the name of the plugin we received the message from | 174 | * @param cls closure, const char* with the name of the plugin we received the message from |
@@ -110,6 +187,41 @@ GST_receive_callback (void *cls, | |||
110 | struct GNUNET_ATS_Session *session, | 187 | struct GNUNET_ATS_Session *session, |
111 | const struct GNUNET_MessageHeader *message); | 188 | const struct GNUNET_MessageHeader *message); |
112 | 189 | ||
190 | /** | ||
191 | * Broadcast the given message to all of our clients. | ||
192 | * | ||
193 | * @param msg message to broadcast | ||
194 | * @param may_drop #GNUNET_YES if the message can be dropped / is payload | ||
195 | */ | ||
196 | void | ||
197 | GST_clients_broadcast (const struct GNUNET_MessageHeader *msg, | ||
198 | int may_drop); | ||
199 | |||
200 | |||
201 | /** | ||
202 | * Broadcast the new active address to all clients monitoring the peer. | ||
203 | * | ||
204 | * @param peer peer this update is about (never NULL) | ||
205 | * @param address address, NULL on disconnect | ||
206 | * @param state the current state of the peer | ||
207 | * @param state_timeout the time out for the state | ||
208 | */ | ||
209 | void | ||
210 | GST_clients_broadcast_peer_notification (const struct GNUNET_PeerIdentity *peer, | ||
211 | const struct GNUNET_HELLO_Address *address, | ||
212 | enum GNUNET_TRANSPORT_PeerState state, | ||
213 | struct GNUNET_TIME_Absolute state_timeout); | ||
214 | |||
215 | |||
216 | /** | ||
217 | * Notify all clients about a disconnect, and cancel | ||
218 | * pending SEND_OK messages for this peer. | ||
219 | * | ||
220 | * @param peer peer that disconnected | ||
221 | */ | ||
222 | void | ||
223 | GST_clients_broadcast_disconnect (const struct GNUNET_PeerIdentity *peer); | ||
224 | |||
113 | 225 | ||
114 | 226 | ||
115 | 227 | ||
diff --git a/src/transport/gnunet-service-transport_blacklist.c b/src/transport/gnunet-service-transport_blacklist.c deleted file mode 100644 index b6c36a6cd..000000000 --- a/src/transport/gnunet-service-transport_blacklist.c +++ /dev/null | |||
@@ -1,933 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2010,2011 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file transport/gnunet-service-transport_blacklist.c | ||
23 | * @brief blacklisting implementation | ||
24 | * @author Christian Grothoff | ||
25 | * @author Matthias Wachs | ||
26 | * @details This is the blacklisting component of transport service. With | ||
27 | * blacklisting it is possible to deny connections to specific peers of | ||
28 | * to use a specific plugin to a specific peer. Peers can be blacklisted using | ||
29 | * the configuration or a blacklist client can be asked. | ||
30 | * | ||
31 | * To blacklist peers using the configuration you have to add a section to your | ||
32 | * configuration containing the peer id of the peer to blacklist and the plugin | ||
33 | * if required. | ||
34 | * | ||
35 | * Example: | ||
36 | * To blacklist connections to P565... on peer AG2P... using tcp add: | ||
37 | * [transport-blacklist-AG2PHES1BARB9IJCPAMJTFPVJ5V3A72S3F2A8SBUB8DAQ2V0O3V8G6G2JU56FHGFOHMQVKBSQFV98TCGTC3RJ1NINP82G0RC00N1520] | ||
38 | * P565723JO1C2HSN6J29TAQ22MN6CI8HTMUU55T0FUQG4CMDGGEQ8UCNBKUMB94GC8R9G4FB2SF9LDOBAJ6AMINBP4JHHDD6L7VD801G = tcp | ||
39 | * | ||
40 | * To blacklist connections to P565... on peer AG2P... using all plugins add: | ||
41 | * [transport-blacklist-AG2PHES1BARB9IJCPAMJTFPVJ5V3A72S3F2A8SBUB8DAQ2V0O3V8G6G2JU56FHGFOHMQVKBSQFV98TCGTC3RJ1NINP82G0RC00N1520] | ||
42 | * P565723JO1C2HSN6J29TAQ22MN6CI8HTMUU55T0FUQG4CMDGGEQ8UCNBKUMB94GC8R9G4FB2SF9LDOBAJ6AMINBP4JHHDD6L7VD801G = | ||
43 | * | ||
44 | * You can also add a blacklist client usign the blacklist api. On a blacklist | ||
45 | * check, blacklisting first checks internally if the peer is blacklisted and | ||
46 | * if not, it asks the blacklisting clients. Clients are asked if it is OK to | ||
47 | * connect to a peer ID, the plugin is omitted. | ||
48 | * | ||
49 | * On blacklist check for (peer, plugin) | ||
50 | * - Do we have a local blacklist entry for this peer and this plugin? | ||
51 | * - YES: disallow connection | ||
52 | * - Do we have a local blacklist entry for this peer and all plugins? | ||
53 | * - YES: disallow connection | ||
54 | * - Does one of the clients disallow? | ||
55 | * - YES: disallow connection | ||
56 | * | ||
57 | */ | ||
58 | #include "platform.h" | ||
59 | #include "gnunet-service-transport.h" | ||
60 | #include "gnunet-service-transport_blacklist.h" | ||
61 | #include "gnunet-service-transport_neighbours.h" | ||
62 | #include "transport.h" | ||
63 | |||
64 | /** | ||
65 | * Size of the blacklist hash map. | ||
66 | */ | ||
67 | #define TRANSPORT_BLACKLIST_HT_SIZE 64 | ||
68 | |||
69 | |||
70 | /** | ||
71 | * Context we use when performing a blacklist check. | ||
72 | */ | ||
73 | struct GST_BlacklistCheck; | ||
74 | |||
75 | |||
76 | /** | ||
77 | * Information kept for each client registered to perform | ||
78 | * blacklisting. | ||
79 | */ | ||
80 | struct Blacklisters | ||
81 | { | ||
82 | /** | ||
83 | * This is a linked list. | ||
84 | */ | ||
85 | struct Blacklisters *next; | ||
86 | |||
87 | /** | ||
88 | * This is a linked list. | ||
89 | */ | ||
90 | struct Blacklisters *prev; | ||
91 | |||
92 | /** | ||
93 | * Client responsible for this entry. | ||
94 | */ | ||
95 | struct GNUNET_SERVER_Client *client; | ||
96 | |||
97 | /** | ||
98 | * Blacklist check that we're currently performing (or NULL | ||
99 | * if we're performing one that has been cancelled). | ||
100 | */ | ||
101 | struct GST_BlacklistCheck *bc; | ||
102 | |||
103 | /** | ||
104 | * Set to #GNUNET_YES if we're currently waiting for a reply. | ||
105 | */ | ||
106 | int waiting_for_reply; | ||
107 | |||
108 | /** | ||
109 | * #GNUNET_YES if we have to call receive_done for this client | ||
110 | */ | ||
111 | int call_receive_done; | ||
112 | |||
113 | }; | ||
114 | |||
115 | |||
116 | |||
117 | /** | ||
118 | * Context we use when performing a blacklist check. | ||
119 | */ | ||
120 | struct GST_BlacklistCheck | ||
121 | { | ||
122 | |||
123 | /** | ||
124 | * This is a linked list. | ||
125 | */ | ||
126 | struct GST_BlacklistCheck *next; | ||
127 | |||
128 | /** | ||
129 | * This is a linked list. | ||
130 | */ | ||
131 | struct GST_BlacklistCheck *prev; | ||
132 | |||
133 | /** | ||
134 | * Peer being checked. | ||
135 | */ | ||
136 | struct GNUNET_PeerIdentity peer; | ||
137 | |||
138 | /** | ||
139 | * Continuation to call with the result. | ||
140 | */ | ||
141 | GST_BlacklistTestContinuation cont; | ||
142 | |||
143 | /** | ||
144 | * Closure for @e cont. | ||
145 | */ | ||
146 | void *cont_cls; | ||
147 | |||
148 | /** | ||
149 | * Address for #GST_blacklist_abort_matching(), can be NULL. | ||
150 | */ | ||
151 | struct GNUNET_HELLO_Address *address; | ||
152 | |||
153 | /** | ||
154 | * Session for #GST_blacklist_abort_matching(), can be NULL. | ||
155 | */ | ||
156 | struct GNUNET_ATS_Session *session; | ||
157 | |||
158 | /** | ||
159 | * Current transmission request handle for this client, or NULL if no | ||
160 | * request is pending. | ||
161 | */ | ||
162 | struct GNUNET_SERVER_TransmitHandle *th; | ||
163 | |||
164 | /** | ||
165 | * Our current position in the blacklisters list. | ||
166 | */ | ||
167 | struct Blacklisters *bl_pos; | ||
168 | |||
169 | /** | ||
170 | * Current task performing the check. | ||
171 | */ | ||
172 | struct GNUNET_SCHEDULER_Task *task; | ||
173 | |||
174 | }; | ||
175 | |||
176 | |||
177 | /** | ||
178 | * Head of DLL of active blacklisting queries. | ||
179 | */ | ||
180 | static struct GST_BlacklistCheck *bc_head; | ||
181 | |||
182 | /** | ||
183 | * Tail of DLL of active blacklisting queries. | ||
184 | */ | ||
185 | static struct GST_BlacklistCheck *bc_tail; | ||
186 | |||
187 | /** | ||
188 | * Head of DLL of blacklisting clients. | ||
189 | */ | ||
190 | static struct Blacklisters *bl_head; | ||
191 | |||
192 | /** | ||
193 | * Tail of DLL of blacklisting clients. | ||
194 | */ | ||
195 | static struct Blacklisters *bl_tail; | ||
196 | |||
197 | /** | ||
198 | * Hashmap of blacklisted peers. Values are of type 'char *' (transport names), | ||
199 | * can be NULL if we have no static blacklist. | ||
200 | */ | ||
201 | static struct GNUNET_CONTAINER_MultiPeerMap *blacklist; | ||
202 | |||
203 | |||
204 | /** | ||
205 | * Perform next action in the blacklist check. | ||
206 | * | ||
207 | * @param cls the `struct BlacklistCheck*` | ||
208 | */ | ||
209 | static void | ||
210 | do_blacklist_check (void *cls); | ||
211 | |||
212 | |||
213 | /** | ||
214 | * Called whenever a client is disconnected. Frees our | ||
215 | * resources associated with that client. | ||
216 | * | ||
217 | * @param cls closure (unused) | ||
218 | * @param client identification of the client | ||
219 | */ | ||
220 | static void | ||
221 | client_disconnect_notification (void *cls, | ||
222 | struct GNUNET_SERVER_Client *client) | ||
223 | { | ||
224 | struct Blacklisters *bl; | ||
225 | struct GST_BlacklistCheck *bc; | ||
226 | |||
227 | if (NULL == client) | ||
228 | return; | ||
229 | for (bl = bl_head; bl != NULL; bl = bl->next) | ||
230 | { | ||
231 | if (bl->client != client) | ||
232 | continue; | ||
233 | for (bc = bc_head; NULL != bc; bc = bc->next) | ||
234 | { | ||
235 | if (bc->bl_pos != bl) | ||
236 | continue; | ||
237 | bc->bl_pos = bl->next; | ||
238 | if (NULL != bc->th) | ||
239 | { | ||
240 | GNUNET_SERVER_notify_transmit_ready_cancel (bc->th); | ||
241 | bc->th = NULL; | ||
242 | } | ||
243 | if (NULL == bc->task) | ||
244 | bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc); | ||
245 | } | ||
246 | GNUNET_CONTAINER_DLL_remove (bl_head, bl_tail, bl); | ||
247 | GNUNET_SERVER_client_drop (bl->client); | ||
248 | GNUNET_free (bl); | ||
249 | break; | ||
250 | } | ||
251 | } | ||
252 | |||
253 | |||
254 | /** | ||
255 | * Function to iterate over options in the blacklisting section for a peer. | ||
256 | * | ||
257 | * @param cls closure | ||
258 | * @param section name of the section | ||
259 | * @param option name of the option | ||
260 | * @param value value of the option | ||
261 | */ | ||
262 | static void | ||
263 | blacklist_cfg_iter (void *cls, | ||
264 | const char *section, | ||
265 | const char *option, | ||
266 | const char *value) | ||
267 | { | ||
268 | unsigned int *res = cls; | ||
269 | struct GNUNET_PeerIdentity peer; | ||
270 | char *plugs; | ||
271 | char *pos; | ||
272 | |||
273 | if (GNUNET_OK != | ||
274 | GNUNET_CRYPTO_eddsa_public_key_from_string (option, | ||
275 | strlen (option), | ||
276 | &peer.public_key)) | ||
277 | return; | ||
278 | |||
279 | if ((NULL == value) || (0 == strcmp(value, ""))) | ||
280 | { | ||
281 | /* Blacklist whole peer */ | ||
282 | GST_blacklist_add_peer (&peer, NULL); | ||
283 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
284 | _("Adding blacklisting entry for peer `%s'\n"), | ||
285 | GNUNET_i2s (&peer)); | ||
286 | } | ||
287 | else | ||
288 | { | ||
289 | plugs = GNUNET_strdup (value); | ||
290 | for (pos = strtok (plugs, " "); pos != NULL; pos = strtok (NULL, " ")) | ||
291 | { | ||
292 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
293 | _("Adding blacklisting entry for peer `%s':`%s'\n"), | ||
294 | GNUNET_i2s (&peer), pos); | ||
295 | GST_blacklist_add_peer (&peer, pos); | ||
296 | } | ||
297 | GNUNET_free (plugs); | ||
298 | } | ||
299 | (*res)++; | ||
300 | } | ||
301 | |||
302 | |||
303 | /** | ||
304 | * Read blacklist configuration | ||
305 | * | ||
306 | * @param cfg the configuration handle | ||
307 | * @param my_id my peer identity | ||
308 | */ | ||
309 | static void | ||
310 | read_blacklist_configuration (const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
311 | const struct GNUNET_PeerIdentity *my_id) | ||
312 | { | ||
313 | char cfg_sect[512]; | ||
314 | unsigned int res = 0; | ||
315 | |||
316 | GNUNET_snprintf (cfg_sect, | ||
317 | sizeof (cfg_sect), | ||
318 | "transport-blacklist-%s", | ||
319 | GNUNET_i2s_full (my_id)); | ||
320 | GNUNET_CONFIGURATION_iterate_section_values (cfg, | ||
321 | cfg_sect, | ||
322 | &blacklist_cfg_iter, | ||
323 | &res); | ||
324 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
325 | "Loaded %u blacklisting entries from configuration\n", | ||
326 | res); | ||
327 | } | ||
328 | |||
329 | |||
330 | /** | ||
331 | * Start blacklist subsystem. | ||
332 | * | ||
333 | * @param server server used to accept clients from | ||
334 | * @param cfg configuration handle | ||
335 | * @param my_id my peer id | ||
336 | */ | ||
337 | void | ||
338 | GST_blacklist_start (struct GNUNET_SERVER_Handle *server, | ||
339 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
340 | const struct GNUNET_PeerIdentity *my_id) | ||
341 | { | ||
342 | GNUNET_assert (NULL != cfg); | ||
343 | GNUNET_assert (NULL != my_id); | ||
344 | read_blacklist_configuration (cfg, my_id); | ||
345 | GNUNET_SERVER_disconnect_notify (server, | ||
346 | &client_disconnect_notification, | ||
347 | NULL); | ||
348 | } | ||
349 | |||
350 | |||
351 | /** | ||
352 | * Free the given entry in the blacklist. | ||
353 | * | ||
354 | * @param cls unused | ||
355 | * @param key host identity (unused) | ||
356 | * @param value the blacklist entry | ||
357 | * @return #GNUNET_OK (continue to iterate) | ||
358 | */ | ||
359 | static int | ||
360 | free_blacklist_entry (void *cls, | ||
361 | const struct GNUNET_PeerIdentity *key, | ||
362 | void *value) | ||
363 | { | ||
364 | char *be = value; | ||
365 | |||
366 | GNUNET_free_non_null (be); | ||
367 | return GNUNET_OK; | ||
368 | } | ||
369 | |||
370 | |||
371 | /** | ||
372 | * Stop blacklist subsystem. | ||
373 | */ | ||
374 | void | ||
375 | GST_blacklist_stop () | ||
376 | { | ||
377 | if (NULL == blacklist) | ||
378 | return; | ||
379 | GNUNET_CONTAINER_multipeermap_iterate (blacklist, | ||
380 | &free_blacklist_entry, | ||
381 | NULL); | ||
382 | GNUNET_CONTAINER_multipeermap_destroy (blacklist); | ||
383 | blacklist = NULL; | ||
384 | } | ||
385 | |||
386 | |||
387 | /** | ||
388 | * Transmit blacklist query to the client. | ||
389 | * | ||
390 | * @param cls the `struct GST_BlacklistCheck` | ||
391 | * @param size number of bytes allowed | ||
392 | * @param buf where to copy the message | ||
393 | * @return number of bytes copied to @a buf | ||
394 | */ | ||
395 | static size_t | ||
396 | transmit_blacklist_message (void *cls, | ||
397 | size_t size, | ||
398 | void *buf) | ||
399 | { | ||
400 | struct GST_BlacklistCheck *bc = cls; | ||
401 | struct Blacklisters *bl; | ||
402 | struct BlacklistMessage bm; | ||
403 | |||
404 | bc->th = NULL; | ||
405 | if (0 == size) | ||
406 | { | ||
407 | GNUNET_assert (NULL == bc->task); | ||
408 | bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, | ||
409 | bc); | ||
410 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
411 | "Failed to send blacklist test for peer `%s' to client\n", | ||
412 | GNUNET_i2s (&bc->peer)); | ||
413 | return 0; | ||
414 | } | ||
415 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
416 | "Sending blacklist test for peer `%s' to client %p\n", | ||
417 | GNUNET_i2s (&bc->peer), | ||
418 | bc->bl_pos->client); | ||
419 | bl = bc->bl_pos; | ||
420 | bm.header.size = htons (sizeof (struct BlacklistMessage)); | ||
421 | bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY); | ||
422 | bm.is_allowed = htonl (0); | ||
423 | bm.peer = bc->peer; | ||
424 | GNUNET_memcpy (buf, | ||
425 | &bm, | ||
426 | sizeof (bm)); | ||
427 | if (GNUNET_YES == bl->call_receive_done) | ||
428 | { | ||
429 | GNUNET_SERVER_receive_done (bl->client, | ||
430 | GNUNET_OK); | ||
431 | bl->call_receive_done = GNUNET_NO; | ||
432 | } | ||
433 | |||
434 | bl->waiting_for_reply = GNUNET_YES; | ||
435 | return sizeof (bm); | ||
436 | } | ||
437 | |||
438 | |||
439 | /** | ||
440 | * Perform next action in the blacklist check. | ||
441 | * | ||
442 | * @param cls the `struct GST_BlacklistCheck *` | ||
443 | */ | ||
444 | static void | ||
445 | do_blacklist_check (void *cls) | ||
446 | { | ||
447 | struct GST_BlacklistCheck *bc = cls; | ||
448 | struct Blacklisters *bl; | ||
449 | |||
450 | bc->task = NULL; | ||
451 | bl = bc->bl_pos; | ||
452 | if (NULL == bl) | ||
453 | { | ||
454 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
455 | "No other blacklist clients active, will allow neighbour `%s'\n", | ||
456 | GNUNET_i2s (&bc->peer)); | ||
457 | |||
458 | bc->cont (bc->cont_cls, | ||
459 | &bc->peer, | ||
460 | bc->address, | ||
461 | bc->session, | ||
462 | GNUNET_OK); | ||
463 | GST_blacklist_test_cancel (bc); | ||
464 | return; | ||
465 | } | ||
466 | if ( (NULL != bl->bc) || | ||
467 | (GNUNET_NO != bl->waiting_for_reply) ) | ||
468 | return; /* someone else busy with this client */ | ||
469 | bl->bc = bc; | ||
470 | bc->th = | ||
471 | GNUNET_SERVER_notify_transmit_ready (bl->client, | ||
472 | sizeof (struct BlacklistMessage), | ||
473 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
474 | &transmit_blacklist_message, | ||
475 | bc); | ||
476 | } | ||
477 | |||
478 | |||
479 | /** | ||
480 | * Got the result about an existing connection from a new blacklister. | ||
481 | * Shutdown the neighbour if necessary. | ||
482 | * | ||
483 | * @param cls unused | ||
484 | * @param peer the neighbour that was investigated | ||
485 | * @param address address associated with the request | ||
486 | * @param session session associated with the request | ||
487 | * @param allowed #GNUNET_OK if we can keep it, | ||
488 | * #GNUNET_NO if we must shutdown the connection | ||
489 | */ | ||
490 | static void | ||
491 | confirm_or_drop_neighbour (void *cls, | ||
492 | const struct GNUNET_PeerIdentity *peer, | ||
493 | const struct GNUNET_HELLO_Address *address, | ||
494 | struct GNUNET_ATS_Session *session, | ||
495 | int allowed) | ||
496 | { | ||
497 | if (GNUNET_OK == allowed) | ||
498 | return; /* we're done */ | ||
499 | GNUNET_STATISTICS_update (GST_stats, | ||
500 | gettext_noop ("# disconnects due to blacklist"), | ||
501 | 1, | ||
502 | GNUNET_NO); | ||
503 | GST_neighbours_force_disconnect (peer); | ||
504 | } | ||
505 | |||
506 | |||
507 | /** | ||
508 | * Closure for #test_connection_ok(). | ||
509 | */ | ||
510 | struct TestConnectionContext | ||
511 | { | ||
512 | /** | ||
513 | * Is this the first neighbour we're checking? | ||
514 | */ | ||
515 | int first; | ||
516 | |||
517 | /** | ||
518 | * Handle to the blacklisting client we need to ask. | ||
519 | */ | ||
520 | struct Blacklisters *bl; | ||
521 | }; | ||
522 | |||
523 | |||
524 | /** | ||
525 | * Test if an existing connection is still acceptable given a new | ||
526 | * blacklisting client. | ||
527 | * | ||
528 | * @param cls the `struct TestConnectionContext *` | ||
529 | * @param peer identity of the peer | ||
530 | * @param address the address | ||
531 | * @param state current state this peer is in | ||
532 | * @param state_timeout timeout for the current state of the peer | ||
533 | * @param bandwidth_in bandwidth assigned inbound | ||
534 | * @param bandwidth_out bandwidth assigned outbound | ||
535 | */ | ||
536 | static void | ||
537 | test_connection_ok (void *cls, | ||
538 | const struct GNUNET_PeerIdentity *peer, | ||
539 | const struct GNUNET_HELLO_Address *address, | ||
540 | enum GNUNET_TRANSPORT_PeerState state, | ||
541 | struct GNUNET_TIME_Absolute state_timeout, | ||
542 | struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in, | ||
543 | struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out) | ||
544 | { | ||
545 | struct TestConnectionContext *tcc = cls; | ||
546 | struct GST_BlacklistCheck *bc; | ||
547 | |||
548 | bc = GNUNET_new (struct GST_BlacklistCheck); | ||
549 | GNUNET_CONTAINER_DLL_insert (bc_head, | ||
550 | bc_tail, | ||
551 | bc); | ||
552 | bc->peer = *peer; | ||
553 | bc->address = GNUNET_HELLO_address_copy (address); | ||
554 | bc->cont = &confirm_or_drop_neighbour; | ||
555 | bc->cont_cls = NULL; | ||
556 | bc->bl_pos = tcc->bl; | ||
557 | if (GNUNET_YES == tcc->first) | ||
558 | { | ||
559 | /* all would wait for the same client, no need to | ||
560 | * create more than just the first task right now */ | ||
561 | bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc); | ||
562 | tcc->first = GNUNET_NO; | ||
563 | } | ||
564 | } | ||
565 | |||
566 | |||
567 | /** | ||
568 | * Initialize a blacklisting client. We got a blacklist-init | ||
569 | * message from this client, add him to the list of clients | ||
570 | * to query for blacklisting. | ||
571 | * | ||
572 | * @param cls unused | ||
573 | * @param client the client | ||
574 | * @param message the blacklist-init message that was sent | ||
575 | */ | ||
576 | void | ||
577 | GST_blacklist_handle_init (void *cls, | ||
578 | struct GNUNET_SERVER_Client *client, | ||
579 | const struct GNUNET_MessageHeader *message) | ||
580 | { | ||
581 | struct Blacklisters *bl; | ||
582 | struct TestConnectionContext tcc; | ||
583 | |||
584 | for (bl = bl_head; NULL != bl; bl = bl->next) | ||
585 | if (bl->client == client) | ||
586 | { | ||
587 | GNUNET_break (0); | ||
588 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
589 | return; | ||
590 | } | ||
591 | |||
592 | GNUNET_SERVER_client_mark_monitor (client); | ||
593 | bl = GNUNET_new (struct Blacklisters); | ||
594 | bl->client = client; | ||
595 | bl->call_receive_done = GNUNET_YES; | ||
596 | GNUNET_SERVER_client_keep (client); | ||
597 | GNUNET_CONTAINER_DLL_insert_after (bl_head, | ||
598 | bl_tail, | ||
599 | bl_tail, | ||
600 | bl); | ||
601 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
602 | "New blacklist client %p\n", | ||
603 | client); | ||
604 | |||
605 | /* confirm that all existing connections are OK! */ | ||
606 | tcc.bl = bl; | ||
607 | tcc.first = GNUNET_YES; | ||
608 | GST_neighbours_iterate (&test_connection_ok, &tcc); | ||
609 | } | ||
610 | |||
611 | |||
612 | /** | ||
613 | * A blacklisting client has sent us reply. Process it. | ||
614 | * | ||
615 | * @param cls unused | ||
616 | * @param client the client | ||
617 | * @param message the blacklist-init message that was sent | ||
618 | */ | ||
619 | void | ||
620 | GST_blacklist_handle_reply (void *cls, | ||
621 | struct GNUNET_SERVER_Client *client, | ||
622 | const struct GNUNET_MessageHeader *message) | ||
623 | { | ||
624 | const struct BlacklistMessage *msg = | ||
625 | (const struct BlacklistMessage *) message; | ||
626 | struct Blacklisters *bl; | ||
627 | struct GST_BlacklistCheck *bc; | ||
628 | |||
629 | bl = bl_head; | ||
630 | while ((bl != NULL) && (bl->client != client)) | ||
631 | bl = bl->next; | ||
632 | if (NULL == bl) | ||
633 | { | ||
634 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
635 | "Blacklist client disconnected\n"); | ||
636 | GNUNET_SERVER_receive_done (client, | ||
637 | GNUNET_SYSERR); | ||
638 | return; | ||
639 | } | ||
640 | |||
641 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
642 | "Blacklist client %p sent reply for `%s'\n", | ||
643 | client, | ||
644 | GNUNET_i2s (&msg->peer)); | ||
645 | |||
646 | bc = bl->bc; | ||
647 | bl->bc = NULL; | ||
648 | bl->waiting_for_reply = GNUNET_NO; | ||
649 | bl->call_receive_done = GNUNET_YES; /* Remember to call receive_done */ | ||
650 | if (NULL != bc) | ||
651 | { | ||
652 | /* only run this if the blacklist check has not been | ||
653 | * cancelled in the meantime... */ | ||
654 | GNUNET_assert (bc->bl_pos == bl); | ||
655 | if (ntohl (msg->is_allowed) == GNUNET_SYSERR) | ||
656 | { | ||
657 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
658 | "Blacklist check failed, peer not allowed\n"); | ||
659 | /* For the duration of the continuation, make the ongoing | ||
660 | check invisible (to avoid double-cancellation); then | ||
661 | add it back again so we can re-use GST_blacklist_test_cancel() */ | ||
662 | GNUNET_CONTAINER_DLL_remove (bc_head, | ||
663 | bc_tail, | ||
664 | bc); | ||
665 | bc->cont (bc->cont_cls, | ||
666 | &bc->peer, | ||
667 | bc->address, | ||
668 | bc->session, | ||
669 | GNUNET_NO); | ||
670 | GNUNET_CONTAINER_DLL_insert (bc_head, | ||
671 | bc_tail, | ||
672 | bc); | ||
673 | GST_blacklist_test_cancel (bc); | ||
674 | GNUNET_SERVER_receive_done (bl->client, GNUNET_OK); | ||
675 | bl->call_receive_done = GNUNET_NO; | ||
676 | return; | ||
677 | } | ||
678 | else | ||
679 | { | ||
680 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
681 | "Blacklist check succeeded, continuing with checks\n"); | ||
682 | GNUNET_SERVER_receive_done (bl->client, | ||
683 | GNUNET_OK); | ||
684 | bl->call_receive_done = GNUNET_NO; | ||
685 | bc->bl_pos = bl->next; | ||
686 | bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, | ||
687 | bc); | ||
688 | } | ||
689 | } | ||
690 | /* check if any other blacklist checks are waiting for this blacklister */ | ||
691 | for (bc = bc_head; bc != NULL; bc = bc->next) | ||
692 | if ((bc->bl_pos == bl) && (NULL == bc->task)) | ||
693 | { | ||
694 | bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, | ||
695 | bc); | ||
696 | break; | ||
697 | } | ||
698 | } | ||
699 | |||
700 | |||
701 | /** | ||
702 | * Add the given peer to the blacklist (for the given transport). | ||
703 | * | ||
704 | * @param peer peer to blacklist | ||
705 | * @param transport_name transport to blacklist for this peer, NULL for all | ||
706 | */ | ||
707 | void | ||
708 | GST_blacklist_add_peer (const struct GNUNET_PeerIdentity *peer, | ||
709 | const char *transport_name) | ||
710 | { | ||
711 | char *transport = NULL; | ||
712 | |||
713 | if (NULL != transport_name) | ||
714 | { | ||
715 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
716 | "Adding peer `%s' with plugin `%s' to blacklist\n", | ||
717 | GNUNET_i2s (peer), transport_name); | ||
718 | transport = GNUNET_strdup (transport_name); | ||
719 | } | ||
720 | else | ||
721 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
722 | "Adding peer `%s' with all plugins to blacklist\n", | ||
723 | GNUNET_i2s (peer)); | ||
724 | if (NULL == blacklist) | ||
725 | blacklist = | ||
726 | GNUNET_CONTAINER_multipeermap_create (TRANSPORT_BLACKLIST_HT_SIZE, | ||
727 | GNUNET_NO); | ||
728 | |||
729 | GNUNET_CONTAINER_multipeermap_put (blacklist, peer, | ||
730 | transport, | ||
731 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
732 | } | ||
733 | |||
734 | |||
735 | /** | ||
736 | * Abort blacklist if @a address and @a session match. | ||
737 | * | ||
738 | * @param address address used to abort matching checks | ||
739 | * @param session session used to abort matching checks | ||
740 | */ | ||
741 | void | ||
742 | GST_blacklist_abort_matching (const struct GNUNET_HELLO_Address *address, | ||
743 | struct GNUNET_ATS_Session *session) | ||
744 | { | ||
745 | struct GST_BlacklistCheck *bc; | ||
746 | struct GST_BlacklistCheck *n; | ||
747 | |||
748 | n = bc_head; | ||
749 | while (NULL != (bc = n)) | ||
750 | { | ||
751 | n = bc->next; | ||
752 | if ( (bc->session == session) && | ||
753 | (0 == GNUNET_HELLO_address_cmp (bc->address, | ||
754 | address)) ) | ||
755 | { | ||
756 | bc->cont (bc->cont_cls, | ||
757 | &bc->peer, | ||
758 | bc->address, | ||
759 | bc->session, | ||
760 | GNUNET_SYSERR); | ||
761 | GST_blacklist_test_cancel (bc); | ||
762 | } | ||
763 | } | ||
764 | } | ||
765 | |||
766 | |||
767 | /** | ||
768 | * Test if the given blacklist entry matches. If so, | ||
769 | * abort the iteration. | ||
770 | * | ||
771 | * @param cls the transport name to match (const char*) | ||
772 | * @param key the key (unused) | ||
773 | * @param value the 'char *' (name of a blacklisted transport) | ||
774 | * @return #GNUNET_OK if the entry does not match, #GNUNET_NO if it matches | ||
775 | */ | ||
776 | static int | ||
777 | test_blacklisted (void *cls, | ||
778 | const struct GNUNET_PeerIdentity *key, | ||
779 | void *value) | ||
780 | { | ||
781 | const char *transport_name = cls; | ||
782 | char *be = value; | ||
783 | |||
784 | /* Blacklist entry be: | ||
785 | * (NULL == be): peer is blacklisted with all plugins | ||
786 | * (NULL != be): peer is blacklisted for a specific plugin | ||
787 | * | ||
788 | * If (NULL != transport_name) we look for a transport specific entry: | ||
789 | * if (transport_name == be) forbidden | ||
790 | * | ||
791 | */ | ||
792 | |||
793 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
794 | "Comparing BL request for peer `%4s':`%s' with BL entry: `%s'\n", | ||
795 | GNUNET_i2s (key), | ||
796 | (NULL == transport_name) ? "unspecified" : transport_name, | ||
797 | (NULL == be) ? "all plugins" : be); | ||
798 | /* all plugins for this peer were blacklisted: disallow */ | ||
799 | if (NULL == value) | ||
800 | return GNUNET_NO; | ||
801 | |||
802 | /* blacklist check for specific transport */ | ||
803 | if ((NULL != transport_name) && (NULL != value)) | ||
804 | { | ||
805 | if (0 == strcmp (transport_name, | ||
806 | be)) | ||
807 | return GNUNET_NO; /* plugin is blacklisted! */ | ||
808 | } | ||
809 | return GNUNET_OK; | ||
810 | } | ||
811 | |||
812 | |||
813 | /** | ||
814 | * Test if a peer/transport combination is blacklisted. | ||
815 | * | ||
816 | * @param peer the identity of the peer to test | ||
817 | * @param transport_name name of the transport to test, never NULL | ||
818 | * @param cont function to call with result | ||
819 | * @param cont_cls closure for @a cont | ||
820 | * @param address address to pass back to @a cont, can be NULL | ||
821 | * @param session session to pass back to @a cont, can be NULL | ||
822 | * @return handle to the blacklist check, NULL if the decision | ||
823 | * was made instantly and @a cont was already called | ||
824 | */ | ||
825 | struct GST_BlacklistCheck * | ||
826 | GST_blacklist_test_allowed (const struct GNUNET_PeerIdentity *peer, | ||
827 | const char *transport_name, | ||
828 | GST_BlacklistTestContinuation cont, | ||
829 | void *cont_cls, | ||
830 | const struct GNUNET_HELLO_Address *address, | ||
831 | struct GNUNET_ATS_Session *session) | ||
832 | { | ||
833 | struct GST_BlacklistCheck *bc; | ||
834 | |||
835 | GNUNET_assert (NULL != peer); | ||
836 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
837 | "Blacklist check for peer `%s':%s\n", | ||
838 | GNUNET_i2s (peer), | ||
839 | (NULL != transport_name) ? transport_name : "unspecified"); | ||
840 | |||
841 | /* Check local blacklist by iterating over hashmap | ||
842 | * If iteration is aborted, we found a matching blacklist entry */ | ||
843 | if ((NULL != blacklist) && | ||
844 | (GNUNET_SYSERR == | ||
845 | GNUNET_CONTAINER_multipeermap_get_multiple (blacklist, peer, | ||
846 | &test_blacklisted, | ||
847 | (void *) transport_name))) | ||
848 | { | ||
849 | /* Disallowed by config, disapprove instantly */ | ||
850 | GNUNET_STATISTICS_update (GST_stats, | ||
851 | gettext_noop ("# disconnects due to blacklist"), | ||
852 | 1, | ||
853 | GNUNET_NO); | ||
854 | GNUNET_log (GNUNET_ERROR_TYPE_INFO, | ||
855 | _("Disallowing connection to peer `%s' on transport %s\n"), | ||
856 | GNUNET_i2s (peer), | ||
857 | (NULL != transport_name) ? transport_name : "unspecified"); | ||
858 | if (NULL != cont) | ||
859 | cont (cont_cls, | ||
860 | peer, | ||
861 | address, | ||
862 | session, | ||
863 | GNUNET_NO); | ||
864 | return NULL; | ||
865 | } | ||
866 | |||
867 | if (NULL == bl_head) | ||
868 | { | ||
869 | /* no blacklist clients, approve instantly */ | ||
870 | if (NULL != cont) | ||
871 | cont (cont_cls, | ||
872 | peer, | ||
873 | address, | ||
874 | session, | ||
875 | GNUNET_OK); | ||
876 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
877 | "Allowing connection to peer `%s' %s\n", | ||
878 | GNUNET_i2s (peer), | ||
879 | (NULL != transport_name) ? transport_name : ""); | ||
880 | return NULL; | ||
881 | } | ||
882 | |||
883 | /* need to query blacklist clients */ | ||
884 | bc = GNUNET_new (struct GST_BlacklistCheck); | ||
885 | GNUNET_CONTAINER_DLL_insert (bc_head, | ||
886 | bc_tail, | ||
887 | bc); | ||
888 | bc->peer = *peer; | ||
889 | bc->address = GNUNET_HELLO_address_copy (address); | ||
890 | bc->session = session; | ||
891 | bc->cont = cont; | ||
892 | bc->cont_cls = cont_cls; | ||
893 | bc->bl_pos = bl_head; | ||
894 | bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc); | ||
895 | return bc; | ||
896 | } | ||
897 | |||
898 | |||
899 | /** | ||
900 | * Cancel a blacklist check. | ||
901 | * | ||
902 | * @param bc check to cancel | ||
903 | */ | ||
904 | void | ||
905 | GST_blacklist_test_cancel (struct GST_BlacklistCheck *bc) | ||
906 | { | ||
907 | GNUNET_CONTAINER_DLL_remove (bc_head, | ||
908 | bc_tail, | ||
909 | bc); | ||
910 | if (NULL != bc->bl_pos) | ||
911 | { | ||
912 | if (bc->bl_pos->bc == bc) | ||
913 | { | ||
914 | /* we're at the head of the queue, remove us! */ | ||
915 | bc->bl_pos->bc = NULL; | ||
916 | } | ||
917 | } | ||
918 | if (NULL != bc->task) | ||
919 | { | ||
920 | GNUNET_SCHEDULER_cancel (bc->task); | ||
921 | bc->task = NULL; | ||
922 | } | ||
923 | if (NULL != bc->th) | ||
924 | { | ||
925 | GNUNET_SERVER_notify_transmit_ready_cancel (bc->th); | ||
926 | bc->th = NULL; | ||
927 | } | ||
928 | GNUNET_free_non_null (bc->address); | ||
929 | GNUNET_free (bc); | ||
930 | } | ||
931 | |||
932 | |||
933 | /* end of file gnunet-service-transport_blacklist.c */ | ||
diff --git a/src/transport/gnunet-service-transport_blacklist.h b/src/transport/gnunet-service-transport_blacklist.h deleted file mode 100644 index 3888d33d3..000000000 --- a/src/transport/gnunet-service-transport_blacklist.h +++ /dev/null | |||
@@ -1,159 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2010,2011 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file transport/gnunet-service-transport_blacklist.h | ||
23 | * @brief blacklisting API | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #ifndef GNUNET_SERVICE_TRANSPORT_BLACKLIST_H | ||
27 | #define GNUNET_SERVICE_TRANSPORT_BLACKLIST_H | ||
28 | |||
29 | #include "gnunet_statistics_service.h" | ||
30 | #include "gnunet_ats_service.h" | ||
31 | #include "gnunet_util_lib.h" | ||
32 | |||
33 | /** | ||
34 | * Start blacklist subsystem. | ||
35 | * | ||
36 | * @param server server used to accept clients from | ||
37 | * @param cfg configuration handle | ||
38 | * @param my_id my peer id | ||
39 | */ | ||
40 | void | ||
41 | GST_blacklist_start (struct GNUNET_SERVER_Handle *server, | ||
42 | const struct GNUNET_CONFIGURATION_Handle *cfg, | ||
43 | const struct GNUNET_PeerIdentity *my_id); | ||
44 | |||
45 | |||
46 | /** | ||
47 | * Stop blacklist subsystem. | ||
48 | */ | ||
49 | void | ||
50 | GST_blacklist_stop (void); | ||
51 | |||
52 | |||
53 | /** | ||
54 | * Initialize a blacklisting client. We got a blacklist-init | ||
55 | * message from this client, add him to the list of clients | ||
56 | * to query for blacklisting. | ||
57 | * | ||
58 | * @param cls unused | ||
59 | * @param client the client | ||
60 | * @param message the blacklist-init message that was sent | ||
61 | */ | ||
62 | void | ||
63 | GST_blacklist_handle_init (void *cls, | ||
64 | struct GNUNET_SERVER_Client *client, | ||
65 | const struct GNUNET_MessageHeader *message); | ||
66 | |||
67 | |||
68 | /** | ||
69 | * A blacklisting client has sent us reply. Process it. | ||
70 | * | ||
71 | * @param cls unused | ||
72 | * @param client the client | ||
73 | * @param message the blacklist-init message that was sent | ||
74 | */ | ||
75 | void | ||
76 | GST_blacklist_handle_reply (void *cls, | ||
77 | struct GNUNET_SERVER_Client *client, | ||
78 | const struct GNUNET_MessageHeader *message); | ||
79 | |||
80 | |||
81 | /** | ||
82 | * Add the given peer to the blacklist (for the given transport). | ||
83 | * | ||
84 | * @param peer peer to blacklist | ||
85 | * @param transport_name transport to blacklist for this peer, NULL for all | ||
86 | */ | ||
87 | void | ||
88 | GST_blacklist_add_peer (const struct GNUNET_PeerIdentity *peer, | ||
89 | const char *transport_name); | ||
90 | |||
91 | |||
92 | /** | ||
93 | * Handle to an active blacklist check. | ||
94 | */ | ||
95 | struct GST_BlacklistCheck; | ||
96 | |||
97 | |||
98 | /** | ||
99 | * Continuation called from a blacklist test. | ||
100 | * | ||
101 | * @param cls closure | ||
102 | * @param peer identity of peer that was tested | ||
103 | * @param address address associated with the request | ||
104 | * @param session session associated with the request | ||
105 | * @param result #GNUNET_OK if the connection is allowed, | ||
106 | * #GNUNET_NO if not, | ||
107 | * #GNUNET_SYSERR if operation was aborted | ||
108 | */ | ||
109 | typedef void | ||
110 | (*GST_BlacklistTestContinuation) (void *cls, | ||
111 | const struct GNUNET_PeerIdentity *peer, | ||
112 | const struct GNUNET_HELLO_Address *address, | ||
113 | struct GNUNET_ATS_Session *session, | ||
114 | int result); | ||
115 | |||
116 | |||
117 | /** | ||
118 | * Test if a peer/transport combination is blacklisted. | ||
119 | * | ||
120 | * @param peer the identity of the peer to test | ||
121 | * @param transport_name name of the transport to test, never NULL | ||
122 | * @param cont function to call with result | ||
123 | * @param cont_cls closure for @a cont | ||
124 | * @param address address to pass back to @a cont, can be NULL | ||
125 | * @param session session to pass back to @a cont, can be NULL | ||
126 | * @return handle to the blacklist check, NULL if the decision | ||
127 | * was made instantly and @a cont was already called | ||
128 | */ | ||
129 | struct GST_BlacklistCheck * | ||
130 | GST_blacklist_test_allowed (const struct GNUNET_PeerIdentity *peer, | ||
131 | const char *transport_name, | ||
132 | GST_BlacklistTestContinuation cont, | ||
133 | void *cont_cls, | ||
134 | const struct GNUNET_HELLO_Address *address, | ||
135 | struct GNUNET_ATS_Session *session); | ||
136 | |||
137 | |||
138 | /** | ||
139 | * Abort blacklist if @a address and @a session match. | ||
140 | * | ||
141 | * @param address address used to abort matching checks | ||
142 | * @param session session used to abort matching checks | ||
143 | */ | ||
144 | void | ||
145 | GST_blacklist_abort_matching (const struct GNUNET_HELLO_Address *address, | ||
146 | struct GNUNET_ATS_Session *session); | ||
147 | |||
148 | |||
149 | |||
150 | /** | ||
151 | * Cancel a blacklist check. | ||
152 | * | ||
153 | * @param bc check to cancel | ||
154 | */ | ||
155 | void | ||
156 | GST_blacklist_test_cancel (struct GST_BlacklistCheck *bc); | ||
157 | |||
158 | #endif | ||
159 | /* end of file gnunet-service-transport_blacklist.h */ | ||
diff --git a/src/transport/gnunet-service-transport_clients.c b/src/transport/gnunet-service-transport_clients.c deleted file mode 100644 index 036fc5637..000000000 --- a/src/transport/gnunet-service-transport_clients.c +++ /dev/null | |||
@@ -1,1491 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2010-2015 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file transport/gnunet-service-transport_clients.c | ||
23 | * @brief communication with clients (core service and monitors) | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #include "platform.h" | ||
27 | #include "gnunet-service-transport_blacklist.h" | ||
28 | #include "gnunet-service-transport_clients.h" | ||
29 | #include "gnunet-service-transport_hello.h" | ||
30 | #include "gnunet-service-transport_neighbours.h" | ||
31 | #include "gnunet-service-transport_plugins.h" | ||
32 | #include "gnunet-service-transport_validation.h" | ||
33 | #include "gnunet-service-transport_manipulation.h" | ||
34 | #include "gnunet-service-transport.h" | ||
35 | #include "transport.h" | ||
36 | |||
37 | |||
38 | /** | ||
39 | * How many messages can we have pending for a given client process | ||
40 | * before we start to drop incoming messages? We typically should | ||
41 | * have only one client and so this would be the primary buffer for | ||
42 | * messages, so the number should be chosen rather generously. | ||
43 | * | ||
44 | * The expectation here is that most of the time the queue is large | ||
45 | * enough so that a drop is virtually never required. Note that | ||
46 | * this value must be about as large as 'TOTAL_MSGS' in the | ||
47 | * 'test_transport_api_reliability.c', otherwise that testcase may | ||
48 | * fail. | ||
49 | */ | ||
50 | #define MAX_PENDING (128 * 1024) | ||
51 | |||
52 | |||
53 | /** | ||
54 | * Linked list of messages to be transmitted to the client. Each | ||
55 | * entry is followed by the actual message. | ||
56 | */ | ||
57 | struct ClientMessageQueueEntry | ||
58 | { | ||
59 | /** | ||
60 | * This is a doubly-linked list. | ||
61 | */ | ||
62 | struct ClientMessageQueueEntry *next; | ||
63 | |||
64 | /** | ||
65 | * This is a doubly-linked list. | ||
66 | */ | ||
67 | struct ClientMessageQueueEntry *prev; | ||
68 | }; | ||
69 | |||
70 | |||
71 | /** | ||
72 | * Client connected to the transport service. | ||
73 | */ | ||
74 | struct TransportClient | ||
75 | { | ||
76 | |||
77 | /** | ||
78 | * This is a doubly-linked list. | ||
79 | */ | ||
80 | struct TransportClient *next; | ||
81 | |||
82 | /** | ||
83 | * This is a doubly-linked list. | ||
84 | */ | ||
85 | struct TransportClient *prev; | ||
86 | |||
87 | /** | ||
88 | * Handle to the client. | ||
89 | */ | ||
90 | struct GNUNET_SERVER_Client *client; | ||
91 | |||
92 | /** | ||
93 | * Linked list of messages yet to be transmitted to | ||
94 | * the client. | ||
95 | */ | ||
96 | struct ClientMessageQueueEntry *message_queue_head; | ||
97 | |||
98 | /** | ||
99 | * Tail of linked list of messages yet to be transmitted to the | ||
100 | * client. | ||
101 | */ | ||
102 | struct ClientMessageQueueEntry *message_queue_tail; | ||
103 | |||
104 | /** | ||
105 | * Current transmit request handle. | ||
106 | */ | ||
107 | struct GNUNET_SERVER_TransmitHandle *th; | ||
108 | |||
109 | /** | ||
110 | * Length of the list of messages pending for this client. | ||
111 | */ | ||
112 | unsigned int message_count; | ||
113 | |||
114 | /** | ||
115 | * Is this client interested in payload messages? | ||
116 | */ | ||
117 | int send_payload; | ||
118 | }; | ||
119 | |||
120 | |||
121 | /** | ||
122 | * Context for address to string operations | ||
123 | */ | ||
124 | struct AddressToStringContext | ||
125 | { | ||
126 | /** | ||
127 | * This is a doubly-linked list. | ||
128 | */ | ||
129 | struct AddressToStringContext *next; | ||
130 | |||
131 | /** | ||
132 | * This is a doubly-linked list. | ||
133 | */ | ||
134 | struct AddressToStringContext *prev; | ||
135 | |||
136 | /** | ||
137 | * Transmission context | ||
138 | */ | ||
139 | struct GNUNET_SERVER_TransmitContext* tc; | ||
140 | }; | ||
141 | |||
142 | |||
143 | /** | ||
144 | * Client monitoring changes of active addresses or validations | ||
145 | * of our neighbours. Which type is being monitored depends on the | ||
146 | * DLL this struct is in. | ||
147 | */ | ||
148 | struct MonitoringClient | ||
149 | { | ||
150 | /** | ||
151 | * This is a doubly-linked list. | ||
152 | */ | ||
153 | struct MonitoringClient *next; | ||
154 | |||
155 | /** | ||
156 | * This is a doubly-linked list. | ||
157 | */ | ||
158 | struct MonitoringClient *prev; | ||
159 | |||
160 | /** | ||
161 | * Handle to the client. | ||
162 | */ | ||
163 | struct GNUNET_SERVER_Client *client; | ||
164 | |||
165 | /** | ||
166 | * Peer identity to monitor the addresses of. | ||
167 | * Zero to monitor all neighrours. | ||
168 | */ | ||
169 | struct GNUNET_PeerIdentity peer; | ||
170 | |||
171 | }; | ||
172 | |||
173 | |||
174 | /** | ||
175 | * Closure for #handle_send_transmit_continuation() | ||
176 | */ | ||
177 | struct SendTransmitContinuationContext | ||
178 | { | ||
179 | /** | ||
180 | * Client that made the request. | ||
181 | */ | ||
182 | struct GNUNET_SERVER_Client *client; | ||
183 | |||
184 | /** | ||
185 | * Peer that was the target. | ||
186 | */ | ||
187 | struct GNUNET_PeerIdentity target; | ||
188 | |||
189 | /** | ||
190 | * At what time did we receive the message? | ||
191 | */ | ||
192 | struct GNUNET_TIME_Absolute send_time; | ||
193 | |||
194 | /** | ||
195 | * Unique ID, for logging. | ||
196 | */ | ||
197 | unsigned long long uuid; | ||
198 | |||
199 | /** | ||
200 | * Set to #GNUNET_YES if the connection for @e target goes | ||
201 | * down and we thus must no longer send the | ||
202 | * #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK message. | ||
203 | */ | ||
204 | int down; | ||
205 | }; | ||
206 | |||
207 | |||
208 | /** | ||
209 | * Head of linked list of all clients to this service. | ||
210 | */ | ||
211 | static struct TransportClient *clients_head; | ||
212 | |||
213 | /** | ||
214 | * Tail of linked list of all clients to this service. | ||
215 | */ | ||
216 | static struct TransportClient *clients_tail; | ||
217 | |||
218 | /** | ||
219 | * Map of peer identities to active send transmit continuation | ||
220 | * contexts. Used to flag contexts as 'dead' when a connection goes | ||
221 | * down. Values are of type `struct SendTransmitContinuationContext | ||
222 | * *`. | ||
223 | */ | ||
224 | static struct GNUNET_CONTAINER_MultiPeerMap *active_stccs; | ||
225 | |||
226 | /** | ||
227 | * Head of linked list of all pending address iterations | ||
228 | */ | ||
229 | static struct AddressToStringContext *a2s_head; | ||
230 | |||
231 | /** | ||
232 | * Tail of linked list of all pending address iterations | ||
233 | */ | ||
234 | static struct AddressToStringContext *a2s_tail; | ||
235 | |||
236 | /** | ||
237 | * Head of linked list of monitoring clients. | ||
238 | */ | ||
239 | static struct MonitoringClient *peer_monitoring_clients_head; | ||
240 | |||
241 | /** | ||
242 | * Tail of linked list of monitoring clients. | ||
243 | */ | ||
244 | static struct MonitoringClient *peer_monitoring_clients_tail; | ||
245 | |||
246 | /** | ||
247 | * Notification context, to send updates on changes to active addresses | ||
248 | * of our neighbours. | ||
249 | */ | ||
250 | static struct GNUNET_SERVER_NotificationContext *peer_nc; | ||
251 | |||
252 | /** | ||
253 | * Notification context, to send updates on changes to active addresses | ||
254 | * of our neighbours. | ||
255 | */ | ||
256 | static struct GNUNET_SERVER_NotificationContext *val_nc; | ||
257 | |||
258 | /** | ||
259 | * Notification context, to send updates on changes to active plugin | ||
260 | * connections. | ||
261 | */ | ||
262 | static struct GNUNET_SERVER_NotificationContext *plugin_nc; | ||
263 | |||
264 | /** | ||
265 | * Plugin monitoring client we are currently syncing, NULL if all | ||
266 | * monitoring clients are in sync. | ||
267 | */ | ||
268 | static struct GNUNET_SERVER_Client *sync_client; | ||
269 | |||
270 | /** | ||
271 | * Peer identity that is all zeros, used as a way to indicate | ||
272 | * "all peers". Used for comparissons. | ||
273 | */ | ||
274 | static struct GNUNET_PeerIdentity all_zeros; | ||
275 | |||
276 | |||
277 | /** | ||
278 | * Find the internal handle associated with the given client handle. | ||
279 | * | ||
280 | * @param client server's client handle to look up | ||
281 | * @return internal client handle | ||
282 | */ | ||
283 | static struct TransportClient * | ||
284 | lookup_client (struct GNUNET_SERVER_Client *client) | ||
285 | { | ||
286 | return GNUNET_SERVER_client_get_user_context (client, | ||
287 | struct TransportClient); | ||
288 | } | ||
289 | |||
290 | |||
291 | /** | ||
292 | * Create the internal handle for the given server client handle. | ||
293 | * | ||
294 | * @param client server's client handle to create our internal handle for | ||
295 | * @return fresh internal client handle | ||
296 | */ | ||
297 | static struct TransportClient * | ||
298 | setup_client (struct GNUNET_SERVER_Client *client) | ||
299 | { | ||
300 | struct TransportClient *tc; | ||
301 | |||
302 | GNUNET_assert (NULL == lookup_client (client)); | ||
303 | tc = GNUNET_new (struct TransportClient); | ||
304 | tc->client = client; | ||
305 | GNUNET_SERVER_client_set_user_context (client, tc); | ||
306 | GNUNET_CONTAINER_DLL_insert (clients_head, | ||
307 | clients_tail, | ||
308 | tc); | ||
309 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
310 | "Client %p connected\n", | ||
311 | tc); | ||
312 | return tc; | ||
313 | } | ||
314 | |||
315 | |||
316 | /** | ||
317 | * Find the handle to the monitoring client associated with the given | ||
318 | * client handle. | ||
319 | * | ||
320 | * @param head the head of the client queue to look in | ||
321 | * @param client server's client handle to look up | ||
322 | * @return handle to the monitoring client | ||
323 | */ | ||
324 | static struct MonitoringClient * | ||
325 | lookup_monitoring_client (struct MonitoringClient *head, | ||
326 | struct GNUNET_SERVER_Client *client) | ||
327 | { | ||
328 | struct MonitoringClient *mc; | ||
329 | |||
330 | for (mc = head; NULL != mc; mc = mc->next) | ||
331 | if (mc->client == client) | ||
332 | return mc; | ||
333 | return NULL; | ||
334 | } | ||
335 | |||
336 | |||
337 | /** | ||
338 | * Setup a new monitoring client using the given server client handle and | ||
339 | * the peer identity. | ||
340 | * | ||
341 | * @param client server's client handle to create our internal handle for | ||
342 | * @param peer identity of the peer to monitor the addresses of, | ||
343 | * zero to monitor all neighrours. | ||
344 | * @return handle to the new monitoring client | ||
345 | */ | ||
346 | static struct MonitoringClient * | ||
347 | setup_peer_monitoring_client (struct GNUNET_SERVER_Client *client, | ||
348 | const struct GNUNET_PeerIdentity *peer) | ||
349 | { | ||
350 | struct MonitoringClient *mc; | ||
351 | |||
352 | GNUNET_assert (NULL == | ||
353 | lookup_monitoring_client (peer_monitoring_clients_head, | ||
354 | client)); | ||
355 | mc = GNUNET_new (struct MonitoringClient); | ||
356 | mc->client = client; | ||
357 | mc->peer = *peer; | ||
358 | GNUNET_CONTAINER_DLL_insert (peer_monitoring_clients_head, | ||
359 | peer_monitoring_clients_tail, | ||
360 | mc); | ||
361 | GNUNET_SERVER_client_mark_monitor (client); | ||
362 | GNUNET_SERVER_notification_context_add (peer_nc, | ||
363 | client); | ||
364 | if (0 != memcmp (peer, | ||
365 | &all_zeros, | ||
366 | sizeof (struct GNUNET_PeerIdentity))) | ||
367 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
368 | "Client %p started monitoring of the peer `%s'\n", | ||
369 | mc, | ||
370 | GNUNET_i2s (peer)); | ||
371 | else | ||
372 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
373 | "Client %p started monitoring all peers\n", | ||
374 | mc); | ||
375 | return mc; | ||
376 | } | ||
377 | |||
378 | |||
379 | /** | ||
380 | * Function called to notify a client about the socket being ready to | ||
381 | * queue more data. @a buf will be NULL and @a size zero if the socket | ||
382 | * was closed for writing in the meantime. | ||
383 | * | ||
384 | * @param cls closure | ||
385 | * @param size number of bytes available in @a buf | ||
386 | * @param buf where the callee should write the message | ||
387 | * @return number of bytes written to @a buf | ||
388 | */ | ||
389 | static size_t | ||
390 | transmit_to_client_callback (void *cls, | ||
391 | size_t size, | ||
392 | void *buf) | ||
393 | { | ||
394 | struct TransportClient *tc = cls; | ||
395 | struct ClientMessageQueueEntry *q; | ||
396 | const struct GNUNET_MessageHeader *msg; | ||
397 | char *cbuf; | ||
398 | uint16_t msize; | ||
399 | size_t tsize; | ||
400 | |||
401 | tc->th = NULL; | ||
402 | if (NULL == buf) | ||
403 | { | ||
404 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
405 | "Transmission to client failed, closing connection.\n"); | ||
406 | return 0; | ||
407 | } | ||
408 | cbuf = buf; | ||
409 | tsize = 0; | ||
410 | while (NULL != (q = tc->message_queue_head)) | ||
411 | { | ||
412 | msg = (const struct GNUNET_MessageHeader *) &q[1]; | ||
413 | msize = ntohs (msg->size); | ||
414 | if (msize + tsize > size) | ||
415 | break; | ||
416 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
417 | "Transmitting message of type %u to client %p.\n", | ||
418 | ntohs (msg->type), | ||
419 | tc); | ||
420 | GNUNET_CONTAINER_DLL_remove (tc->message_queue_head, | ||
421 | tc->message_queue_tail, | ||
422 | q); | ||
423 | tc->message_count--; | ||
424 | GNUNET_memcpy (&cbuf[tsize], msg, msize); | ||
425 | GNUNET_free (q); | ||
426 | tsize += msize; | ||
427 | } | ||
428 | if (NULL != q) | ||
429 | { | ||
430 | GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader)); | ||
431 | tc->th = | ||
432 | GNUNET_SERVER_notify_transmit_ready (tc->client, msize, | ||
433 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
434 | &transmit_to_client_callback, tc); | ||
435 | GNUNET_assert (NULL != tc->th); | ||
436 | } | ||
437 | return tsize; | ||
438 | } | ||
439 | |||
440 | |||
441 | /** | ||
442 | * Queue the given message for transmission to the given client | ||
443 | * | ||
444 | * @param tc target of the message | ||
445 | * @param msg message to transmit | ||
446 | * @param may_drop #GNUNET_YES if the message can be dropped | ||
447 | */ | ||
448 | static void | ||
449 | unicast (struct TransportClient *tc, | ||
450 | const struct GNUNET_MessageHeader *msg, | ||
451 | int may_drop) | ||
452 | { | ||
453 | struct ClientMessageQueueEntry *q; | ||
454 | uint16_t msize; | ||
455 | |||
456 | if (NULL == msg) | ||
457 | { | ||
458 | GNUNET_break (0); | ||
459 | return; | ||
460 | } | ||
461 | if ( (tc->message_count >= MAX_PENDING) && | ||
462 | (GNUNET_YES == may_drop) ) | ||
463 | { | ||
464 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
465 | "Dropping message of type %u and size %u, have %u/%u messages pending\n", | ||
466 | ntohs (msg->type), | ||
467 | ntohs (msg->size), | ||
468 | tc->message_count, | ||
469 | MAX_PENDING); | ||
470 | GNUNET_STATISTICS_update (GST_stats, | ||
471 | gettext_noop | ||
472 | ("# messages dropped due to slow client"), 1, | ||
473 | GNUNET_NO); | ||
474 | return; | ||
475 | } | ||
476 | msize = ntohs (msg->size); | ||
477 | GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader)); | ||
478 | q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize); | ||
479 | GNUNET_memcpy (&q[1], msg, msize); | ||
480 | GNUNET_CONTAINER_DLL_insert_tail (tc->message_queue_head, | ||
481 | tc->message_queue_tail, | ||
482 | q); | ||
483 | tc->message_count++; | ||
484 | if (NULL != tc->th) | ||
485 | return; | ||
486 | tc->th = | ||
487 | GNUNET_SERVER_notify_transmit_ready (tc->client, msize, | ||
488 | GNUNET_TIME_UNIT_FOREVER_REL, | ||
489 | &transmit_to_client_callback, tc); | ||
490 | GNUNET_assert (NULL != tc->th); | ||
491 | } | ||
492 | |||
493 | |||
494 | /** | ||
495 | * Called whenever a client is disconnected. Frees our | ||
496 | * resources associated with that client. | ||
497 | * | ||
498 | * @param cls closure, NULL | ||
499 | * @param client identification of the client | ||
500 | */ | ||
501 | static void | ||
502 | client_disconnect_notification (void *cls, | ||
503 | struct GNUNET_SERVER_Client *client) | ||
504 | { | ||
505 | struct TransportClient *tc; | ||
506 | struct MonitoringClient *mc; | ||
507 | struct ClientMessageQueueEntry *mqe; | ||
508 | |||
509 | if (NULL == client) | ||
510 | return; | ||
511 | mc = lookup_monitoring_client (peer_monitoring_clients_head, | ||
512 | client); | ||
513 | if (NULL != mc) | ||
514 | { | ||
515 | GNUNET_CONTAINER_DLL_remove (peer_monitoring_clients_head, | ||
516 | peer_monitoring_clients_tail, | ||
517 | mc); | ||
518 | GNUNET_free (mc); | ||
519 | } | ||
520 | tc = lookup_client (client); | ||
521 | if (NULL == tc) | ||
522 | return; | ||
523 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
524 | "Client %p disconnected, cleaning up.\n", | ||
525 | tc); | ||
526 | while (NULL != (mqe = tc->message_queue_head)) | ||
527 | { | ||
528 | GNUNET_CONTAINER_DLL_remove (tc->message_queue_head, | ||
529 | tc->message_queue_tail, | ||
530 | mqe); | ||
531 | tc->message_count--; | ||
532 | GNUNET_free (mqe); | ||
533 | } | ||
534 | GNUNET_CONTAINER_DLL_remove (clients_head, | ||
535 | clients_tail, | ||
536 | tc); | ||
537 | GNUNET_SERVER_client_set_user_context (client, NULL); | ||
538 | if (NULL != tc->th) | ||
539 | { | ||
540 | GNUNET_SERVER_notify_transmit_ready_cancel (tc->th); | ||
541 | tc->th = NULL; | ||
542 | } | ||
543 | GNUNET_break (0 == tc->message_count); | ||
544 | GNUNET_free (tc); | ||
545 | } | ||
546 | |||
547 | |||
548 | /** | ||
549 | * Function called for each of our connected neighbours. Notify the | ||
550 | * client about the existing neighbour. | ||
551 | * | ||
552 | * @param cls the `struct TransportClient *` to notify | ||
553 | * @param peer identity of the neighbour | ||
554 | * @param address the address | ||
555 | * @param state the current state of the peer | ||
556 | * @param state_timeout the time out for the state | ||
557 | * @param bandwidth_in inbound bandwidth in NBO | ||
558 | * @param bandwidth_out outbound bandwidth in NBO | ||
559 | */ | ||
560 | static void | ||
561 | notify_client_about_neighbour (void *cls, | ||
562 | const struct GNUNET_PeerIdentity *peer, | ||
563 | const struct GNUNET_HELLO_Address *address, | ||
564 | enum GNUNET_TRANSPORT_PeerState state, | ||
565 | struct GNUNET_TIME_Absolute state_timeout, | ||
566 | struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in, | ||
567 | struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out) | ||
568 | { | ||
569 | struct TransportClient *tc = cls; | ||
570 | struct ConnectInfoMessage cim; | ||
571 | |||
572 | if (GNUNET_NO == GST_neighbours_test_connected (peer)) | ||
573 | return; | ||
574 | cim.header.size = htons (sizeof (struct ConnectInfoMessage)); | ||
575 | cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT); | ||
576 | cim.id = *peer; | ||
577 | cim.quota_in = bandwidth_in; | ||
578 | cim.quota_out = bandwidth_out; | ||
579 | unicast (tc, &cim.header, GNUNET_NO); | ||
580 | } | ||
581 | |||
582 | |||
583 | /** | ||
584 | * Initialize a normal client. We got a start message from this | ||
585 | * client, add him to the list of clients for broadcasting of inbound | ||
586 | * messages. | ||
587 | * | ||
588 | * @param cls unused | ||
589 | * @param client the client | ||
590 | * @param message the start message that was sent | ||
591 | */ | ||
592 | static void | ||
593 | clients_handle_start (void *cls, | ||
594 | struct GNUNET_SERVER_Client *client, | ||
595 | const struct GNUNET_MessageHeader *message) | ||
596 | { | ||
597 | const struct StartMessage *start; | ||
598 | const struct GNUNET_MessageHeader *hello; | ||
599 | struct TransportClient *tc; | ||
600 | uint32_t options; | ||
601 | |||
602 | tc = lookup_client (client); | ||
603 | if (NULL != tc) | ||
604 | { | ||
605 | /* got 'start' twice from the same client, not allowed */ | ||
606 | GNUNET_break (0); | ||
607 | GNUNET_SERVER_receive_done (client, | ||
608 | GNUNET_SYSERR); | ||
609 | return; | ||
610 | } | ||
611 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
612 | "Client %p sent START\n", | ||
613 | client); | ||
614 | start = (const struct StartMessage *) message; | ||
615 | options = ntohl (start->options); | ||
616 | if ((0 != (1 & options)) && | ||
617 | (0 != | ||
618 | memcmp (&start->self, | ||
619 | &GST_my_identity, | ||
620 | sizeof (struct GNUNET_PeerIdentity)))) | ||
621 | { | ||
622 | /* client thinks this is a different peer, reject */ | ||
623 | GNUNET_break (0); | ||
624 | GNUNET_SERVER_receive_done (client, | ||
625 | GNUNET_SYSERR); | ||
626 | return; | ||
627 | } | ||
628 | tc = setup_client (client); | ||
629 | tc->send_payload = (0 != (2 & options)); | ||
630 | hello = GST_hello_get (); | ||
631 | if (NULL != hello) | ||
632 | unicast (tc, | ||
633 | hello, | ||
634 | GNUNET_NO); | ||
635 | GST_neighbours_iterate (¬ify_client_about_neighbour, | ||
636 | tc); | ||
637 | GNUNET_SERVER_receive_done (client, | ||
638 | GNUNET_OK); | ||
639 | } | ||
640 | |||
641 | |||
642 | /** | ||
643 | * Client sent us a HELLO. Process the request. | ||
644 | * | ||
645 | * @param cls unused | ||
646 | * @param client the client | ||
647 | * @param message the HELLO message | ||
648 | */ | ||
649 | static void | ||
650 | clients_handle_hello (void *cls, | ||
651 | struct GNUNET_SERVER_Client *client, | ||
652 | const struct GNUNET_MessageHeader *message) | ||
653 | { | ||
654 | GST_validation_handle_hello (message); | ||
655 | GNUNET_SERVER_receive_done (client, GNUNET_OK); | ||
656 | } | ||
657 | |||
658 | |||
659 | /** | ||
660 | * Function called after the transmission is done. Notify the client that it is | ||
661 | * OK to send the next message. | ||
662 | * | ||
663 | * @param cls closure | ||
664 | * @param success #GNUNET_OK on success, #GNUNET_NO on failure, #GNUNET_SYSERR if we're not connected | ||
665 | * @param bytes_payload bytes payload sent | ||
666 | * @param bytes_on_wire bytes sent on wire | ||
667 | */ | ||
668 | static void | ||
669 | handle_send_transmit_continuation (void *cls, | ||
670 | int success, | ||
671 | size_t bytes_payload, | ||
672 | size_t bytes_on_wire) | ||
673 | { | ||
674 | struct SendTransmitContinuationContext *stcc = cls; | ||
675 | struct SendOkMessage send_ok_msg; | ||
676 | struct GNUNET_TIME_Relative delay; | ||
677 | const struct GNUNET_HELLO_Address *addr; | ||
678 | |||
679 | delay = GNUNET_TIME_absolute_get_duration (stcc->send_time); | ||
680 | addr = GST_neighbour_get_current_address (&stcc->target); | ||
681 | if (delay.rel_value_us > GNUNET_CONSTANTS_LATENCY_WARN.rel_value_us) | ||
682 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
683 | "It took us %s to send %u/%u bytes to %s (%d, %s)\n", | ||
684 | GNUNET_STRINGS_relative_time_to_string (delay, | ||
685 | GNUNET_YES), | ||
686 | (unsigned int) bytes_payload, | ||
687 | (unsigned int) bytes_on_wire, | ||
688 | GNUNET_i2s (&stcc->target), | ||
689 | success, | ||
690 | (NULL != addr) ? addr->transport_name : "%"); | ||
691 | else | ||
692 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
693 | "It took us %s to send %u/%u bytes to %s (%d, %s)\n", | ||
694 | GNUNET_STRINGS_relative_time_to_string (delay, | ||
695 | GNUNET_YES), | ||
696 | (unsigned int) bytes_payload, | ||
697 | (unsigned int) bytes_on_wire, | ||
698 | GNUNET_i2s (&stcc->target), | ||
699 | success, | ||
700 | (NULL != addr) ? addr->transport_name : "%"); | ||
701 | |||
702 | if (GNUNET_NO == stcc->down) | ||
703 | { | ||
704 | /* Only send confirmation if we are still connected */ | ||
705 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
706 | "Sending SEND_OK for transmission request %llu\n", | ||
707 | stcc->uuid); | ||
708 | send_ok_msg.header.size = htons (sizeof (send_ok_msg)); | ||
709 | send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK); | ||
710 | send_ok_msg.bytes_msg = htonl (bytes_payload); | ||
711 | send_ok_msg.bytes_physical = htonl (bytes_on_wire); | ||
712 | send_ok_msg.success = htonl (success); | ||
713 | send_ok_msg.peer = stcc->target; | ||
714 | GST_clients_unicast (stcc->client, | ||
715 | &send_ok_msg.header, | ||
716 | GNUNET_NO); | ||
717 | } | ||
718 | GNUNET_SERVER_client_drop (stcc->client); | ||
719 | GNUNET_assert (GNUNET_OK == | ||
720 | GNUNET_CONTAINER_multipeermap_remove (active_stccs, | ||
721 | &stcc->target, | ||
722 | stcc)); | ||
723 | GNUNET_free (stcc); | ||
724 | } | ||
725 | |||
726 | |||
727 | /** | ||
728 | * Client asked for transmission to a peer. Process the request. | ||
729 | * | ||
730 | * @param cls unused | ||
731 | * @param client the client | ||
732 | * @param message the send message that was sent | ||
733 | */ | ||
734 | static void | ||
735 | clients_handle_send (void *cls, | ||
736 | struct GNUNET_SERVER_Client *client, | ||
737 | const struct GNUNET_MessageHeader *message) | ||
738 | { | ||
739 | static unsigned long long uuid_gen; | ||
740 | const struct OutboundMessage *obm; | ||
741 | const struct GNUNET_MessageHeader *obmm; | ||
742 | struct SendTransmitContinuationContext *stcc; | ||
743 | uint16_t size; | ||
744 | uint16_t msize; | ||
745 | struct TransportClient *tc; | ||
746 | |||
747 | tc = lookup_client (client); | ||
748 | if (NULL == tc) | ||
749 | { | ||
750 | /* client asked for transmission before 'START' */ | ||
751 | GNUNET_break (0); | ||
752 | GNUNET_SERVER_receive_done (client, | ||
753 | GNUNET_SYSERR); | ||
754 | return; | ||
755 | } | ||
756 | |||
757 | size = ntohs (message->size); | ||
758 | if (size < | ||
759 | sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader)) | ||
760 | { | ||
761 | GNUNET_break (0); | ||
762 | GNUNET_SERVER_receive_done (client, | ||
763 | GNUNET_SYSERR); | ||
764 | return; | ||
765 | } | ||
766 | obm = (const struct OutboundMessage *) message; | ||
767 | obmm = (const struct GNUNET_MessageHeader *) &obm[1]; | ||
768 | msize = size - sizeof (struct OutboundMessage); | ||
769 | if (msize < sizeof (struct GNUNET_MessageHeader)) | ||
770 | { | ||
771 | GNUNET_break (0); | ||
772 | GNUNET_SERVER_receive_done (client, | ||
773 | GNUNET_SYSERR); | ||
774 | return; | ||
775 | } | ||
776 | |||
777 | if (GNUNET_NO == GST_neighbours_test_connected (&obm->peer)) | ||
778 | { | ||
779 | /* not connected, not allowed to send; can happen due to asynchronous operations */ | ||
780 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
781 | "Could not send message to peer `%s': not connected\n", | ||
782 | GNUNET_i2s (&obm->peer)); | ||
783 | GNUNET_STATISTICS_update (GST_stats, | ||
784 | gettext_noop | ||
785 | ("# bytes payload dropped (other peer was not connected)"), | ||
786 | msize, GNUNET_NO); | ||
787 | GNUNET_SERVER_receive_done (client, | ||
788 | GNUNET_OK); | ||
789 | return; | ||
790 | } | ||
791 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
792 | "Received SEND request %llu for `%s' and first message of type %u and total size %u\n", | ||
793 | uuid_gen, | ||
794 | GNUNET_i2s (&obm->peer), | ||
795 | ntohs (obmm->type), | ||
796 | msize); | ||
797 | GNUNET_SERVER_receive_done (client, | ||
798 | GNUNET_OK); | ||
799 | stcc = GNUNET_new (struct SendTransmitContinuationContext); | ||
800 | stcc->target = obm->peer; | ||
801 | stcc->client = client; | ||
802 | stcc->send_time = GNUNET_TIME_absolute_get (); | ||
803 | stcc->uuid = uuid_gen++; | ||
804 | (void) GNUNET_CONTAINER_multipeermap_put (active_stccs, | ||
805 | &stcc->target, | ||
806 | stcc, | ||
807 | GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE); | ||
808 | GNUNET_SERVER_client_keep (client); | ||
809 | GST_manipulation_send (&obm->peer, | ||
810 | obmm, | ||
811 | msize, | ||
812 | GNUNET_TIME_relative_ntoh (obm->timeout), | ||
813 | &handle_send_transmit_continuation, | ||
814 | stcc); | ||
815 | } | ||
816 | |||
817 | |||
818 | /** | ||
819 | * Take the given address and append it to the set of results sent back to | ||
820 | * the client. This function may be called serveral times for a single | ||
821 | * conversion. The last invocation will be with a @a address of | ||
822 | * NULL and a @a res of #GNUNET_OK. Thus, to indicate conversion | ||
823 | * errors, the callback might be called first with @a address NULL and | ||
824 | * @a res being #GNUNET_SYSERR. In that case, there will still be a | ||
825 | * subsequent call later with @a address NULL and @a res #GNUNET_OK. | ||
826 | * | ||
827 | * @param cls the transmission context used (`struct GNUNET_SERVER_TransmitContext *`) | ||
828 | * @param buf text to transmit (contains the human-readable address, or NULL) | ||
829 | * @param res #GNUNET_OK if conversion was successful, #GNUNET_SYSERR on error, | ||
830 | * never #GNUNET_NO | ||
831 | */ | ||
832 | static void | ||
833 | transmit_address_to_client (void *cls, | ||
834 | const char *buf, | ||
835 | int res) | ||
836 | { | ||
837 | struct AddressToStringContext *actx = cls; | ||
838 | struct AddressToStringResultMessage *atsm; | ||
839 | size_t len; | ||
840 | size_t slen; | ||
841 | |||
842 | GNUNET_assert ( (GNUNET_OK == res) || | ||
843 | (GNUNET_SYSERR == res) ); | ||
844 | if (NULL == buf) | ||
845 | { | ||
846 | len = sizeof (struct AddressToStringResultMessage); | ||
847 | atsm = GNUNET_malloc (len); | ||
848 | atsm->header.size = ntohs (len); | ||
849 | atsm->header.type = ntohs (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY); | ||
850 | if (GNUNET_OK == res) | ||
851 | { | ||
852 | /* this was the last call, transmit */ | ||
853 | atsm->res = htonl (GNUNET_OK); | ||
854 | atsm->addr_len = htonl (0); | ||
855 | GNUNET_SERVER_transmit_context_append_message (actx->tc, | ||
856 | (const struct GNUNET_MessageHeader *) atsm); | ||
857 | GNUNET_SERVER_transmit_context_run (actx->tc, | ||
858 | GNUNET_TIME_UNIT_FOREVER_REL); | ||
859 | GNUNET_CONTAINER_DLL_remove (a2s_head, | ||
860 | a2s_tail, | ||
861 | actx); | ||
862 | GNUNET_free (atsm); | ||
863 | GNUNET_free (actx); | ||
864 | return; | ||
865 | } | ||
866 | if (GNUNET_SYSERR == res) | ||
867 | { | ||
868 | /* address conversion failed, but there will be more callbacks */ | ||
869 | atsm->res = htonl (GNUNET_SYSERR); | ||
870 | atsm->addr_len = htonl (0); | ||
871 | GNUNET_SERVER_transmit_context_append_message (actx->tc, | ||
872 | (const struct GNUNET_MessageHeader *) atsm); | ||
873 | GNUNET_free (atsm); | ||
874 | return; | ||
875 | } | ||
876 | } | ||
877 | GNUNET_assert (GNUNET_OK == res); | ||
878 | /* succesful conversion, append*/ | ||
879 | slen = strlen (buf) + 1; | ||
880 | len = sizeof (struct AddressToStringResultMessage) + slen; | ||
881 | atsm = GNUNET_malloc (len); | ||
882 | atsm->header.size = ntohs (len); | ||
883 | atsm->header.type = ntohs (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY); | ||
884 | atsm->res = htonl (GNUNET_YES); | ||
885 | atsm->addr_len = htonl (slen); | ||
886 | GNUNET_memcpy (&atsm[1], | ||
887 | buf, | ||
888 | slen); | ||
889 | GNUNET_SERVER_transmit_context_append_message (actx->tc, | ||
890 | (const struct GNUNET_MessageHeader *) atsm); | ||
891 | GNUNET_free (atsm); | ||
892 | } | ||
893 | |||
894 | |||
895 | /** | ||
896 | * Client asked to resolve an address. Process the request. | ||
897 | * | ||
898 | * @param cls unused | ||
899 | * @param client the client | ||
900 | * @param message the resolution request | ||
901 | */ | ||
902 | static void | ||
903 | clients_handle_address_to_string (void *cls, | ||
904 | struct GNUNET_SERVER_Client *client, | ||
905 | const struct GNUNET_MessageHeader *message) | ||
906 | { | ||
907 | const struct AddressLookupMessage *alum; | ||
908 | struct GNUNET_TRANSPORT_PluginFunctions *papi; | ||
909 | const char *plugin_name; | ||
910 | const char *address; | ||
911 | uint32_t address_len; | ||
912 | uint16_t size; | ||
913 | struct GNUNET_SERVER_TransmitContext *tc; | ||
914 | struct AddressToStringContext *actx; | ||
915 | struct AddressToStringResultMessage atsm; | ||
916 | struct GNUNET_TIME_Relative rtimeout; | ||
917 | int32_t numeric; | ||
918 | |||
919 | size = ntohs (message->size); | ||
920 | if (size < sizeof (struct AddressLookupMessage)) | ||
921 | { | ||
922 | GNUNET_break (0); | ||
923 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
924 | return; | ||
925 | } | ||
926 | alum = (const struct AddressLookupMessage *) message; | ||
927 | address_len = ntohs (alum->addrlen); | ||
928 | if (size <= sizeof (struct AddressLookupMessage) + address_len) | ||
929 | { | ||
930 | GNUNET_break (0); | ||
931 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
932 | return; | ||
933 | } | ||
934 | address = (const char *) &alum[1]; | ||
935 | plugin_name = (const char *) &address[address_len]; | ||
936 | if ('\0' != plugin_name[size - sizeof (struct AddressLookupMessage) - address_len - 1]) | ||
937 | { | ||
938 | GNUNET_break (0); | ||
939 | GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); | ||
940 | return; | ||
941 | } | ||
942 | rtimeout = GNUNET_TIME_relative_ntoh (alum->timeout); | ||
943 | numeric = ntohs (alum->numeric_only); | ||
944 | tc = GNUNET_SERVER_transmit_context_create (client); | ||
945 | papi = GST_plugins_printer_find (plugin_name); | ||
946 | if (NULL == papi) | ||
947 | { | ||
948 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
949 | "Failed to find plugin `%s'\n", | ||
950 | plugin_name); | ||
951 | atsm.header.size = ntohs (sizeof (struct AddressToStringResultMessage)); | ||
952 | atsm.header.type = ntohs (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY); | ||
953 | atsm.res = htonl (GNUNET_SYSERR); | ||
954 | atsm.addr_len = htonl (0); | ||
955 | GNUNET_SERVER_transmit_context_append_message (tc, | ||
956 | &atsm.header); | ||
957 | atsm.header.size = ntohs (sizeof (struct AddressToStringResultMessage)); | ||
958 | atsm.header.type = ntohs (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY); | ||
959 | atsm.res = htonl (GNUNET_OK); | ||
960 | atsm.addr_len = htonl (0); | ||
961 | GNUNET_SERVER_transmit_context_append_message (tc, | ||
962 | &atsm.header); | ||
963 | GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL); | ||
964 | return; | ||
965 | } | ||
966 | actx = GNUNET_new (struct AddressToStringContext); | ||
967 | actx->tc = tc; | ||
968 | GNUNET_CONTAINER_DLL_insert (a2s_head, a2s_tail, actx); | ||
969 | GNUNET_SERVER_disable_receive_done_warning (client); | ||
970 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
971 | "Pretty-printing address of %u bytes using plugin `%s'\n", | ||
972 | address_len, | ||
973 | plugin_name); | ||
974 | papi->address_pretty_printer (papi->cls, | ||
975 | plugin_name, | ||
976 | address, address_len, | ||
977 | numeric, | ||
978 | rtimeout, | ||
979 | &transmit_address_to_client, | ||
980 | actx); | ||
981 | } | ||
982 | |||
983 | |||
984 | /** | ||
985 | * Compose #PeerIterateResponseMessage using the given peer and address. | ||
986 | * | ||
987 | * @param peer identity of the peer | ||
988 | * @param address the address, NULL on disconnect | ||
989 | * @return composed message | ||
990 | */ | ||
991 | static struct PeerIterateResponseMessage * | ||
992 | compose_address_iterate_response_message (const struct GNUNET_PeerIdentity *peer, | ||
993 | const struct GNUNET_HELLO_Address *address) | ||
994 | { | ||
995 | struct PeerIterateResponseMessage *msg; | ||
996 | size_t size; | ||
997 | size_t tlen; | ||
998 | size_t alen; | ||
999 | char *addr; | ||
1000 | |||
1001 | GNUNET_assert (NULL != peer); | ||
1002 | if (NULL != address) | ||
1003 | { | ||
1004 | tlen = strlen (address->transport_name) + 1; | ||
1005 | alen = address->address_length; | ||
1006 | } | ||
1007 | else | ||
1008 | { | ||
1009 | tlen = 0; | ||
1010 | alen = 0; | ||
1011 | } | ||
1012 | size = (sizeof (struct PeerIterateResponseMessage) + alen + tlen); | ||
1013 | msg = GNUNET_malloc (size); | ||
1014 | msg->header.size = htons (size); | ||
1015 | msg->header.type = | ||
1016 | htons (GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_RESPONSE); | ||
1017 | msg->reserved = htonl (0); | ||
1018 | msg->peer = *peer; | ||
1019 | msg->addrlen = htonl (alen); | ||
1020 | msg->pluginlen = htonl (tlen); | ||
1021 | |||
1022 | if (NULL != address) | ||
1023 | { | ||
1024 | msg->local_address_info = htonl((uint32_t) address->local_info); | ||
1025 | addr = (char *) &msg[1]; | ||
1026 | GNUNET_memcpy (addr, address->address, alen); | ||
1027 | GNUNET_memcpy (&addr[alen], address->transport_name, tlen); | ||
1028 | } | ||
1029 | return msg; | ||
1030 | } | ||
1031 | |||
1032 | |||
1033 | /** | ||
1034 | * Context for #send_validation_information() and | ||
1035 | * #send_peer_information(). | ||
1036 | */ | ||
1037 | struct IterationContext | ||
1038 | { | ||
1039 | /** | ||
1040 | * Context to use for the transmission. | ||
1041 | */ | ||
1042 | struct GNUNET_SERVER_TransmitContext *tc; | ||
1043 | |||
1044 | /** | ||
1045 | * Which peers do we care about? | ||
1046 | */ | ||
1047 | struct GNUNET_PeerIdentity id; | ||
1048 | |||
1049 | /** | ||
1050 | * #GNUNET_YES if @e id should be ignored because we want all peers. | ||
1051 | */ | ||
1052 | int all; | ||
1053 | }; | ||
1054 | |||
1055 | |||
1056 | /** | ||
1057 | * Output information of neighbours to the given client. | ||
1058 | * | ||
1059 | * @param cls the `struct PeerIterationContext *` | ||
1060 | * @param peer identity of the neighbour | ||
1061 | * @param address the address | ||
1062 | * @param state current state this peer is in | ||
1063 | * @param state_timeout timeout for the current state of the peer | ||
1064 | * @param bandwidth_in inbound quota in NBO | ||
1065 | * @param bandwidth_out outbound quota in NBO | ||
1066 | */ | ||
1067 | static void | ||
1068 | send_peer_information (void *cls, | ||
1069 | const struct GNUNET_PeerIdentity *peer, | ||
1070 | const struct GNUNET_HELLO_Address *address, | ||
1071 | enum GNUNET_TRANSPORT_PeerState state, | ||
1072 | struct GNUNET_TIME_Absolute state_timeout, | ||
1073 | struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in, | ||
1074 | struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out) | ||
1075 | { | ||
1076 | struct IterationContext *pc = cls; | ||
1077 | struct PeerIterateResponseMessage *msg; | ||
1078 | |||
1079 | if ( (GNUNET_YES != pc->all) && | ||
1080 | (0 != memcmp (peer, &pc->id, sizeof (pc->id))) ) | ||
1081 | return; | ||
1082 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1083 | "Sending information about `%s' using address `%s' in state `%s'\n", | ||
1084 | GNUNET_i2s(peer), | ||
1085 | (NULL != address) ? GST_plugins_a2s (address) : "<none>", | ||
1086 | GNUNET_TRANSPORT_ps2s (state)); | ||
1087 | msg = compose_address_iterate_response_message (peer, address); | ||
1088 | msg->state = htonl (state); | ||
1089 | msg->state_timeout = GNUNET_TIME_absolute_hton(state_timeout); | ||
1090 | GNUNET_SERVER_transmit_context_append_message (pc->tc, &msg->header); | ||
1091 | GNUNET_free (msg); | ||
1092 | } | ||
1093 | |||
1094 | |||
1095 | /** | ||
1096 | * Client asked to obtain information about a specific or all peers | ||
1097 | * Process the request. | ||
1098 | * | ||
1099 | * @param cls unused | ||
1100 | * @param client the client | ||
1101 | * @param message the peer address information request | ||
1102 | */ | ||
1103 | static void | ||
1104 | clients_handle_monitor_peers (void *cls, | ||
1105 | struct GNUNET_SERVER_Client *client, | ||
1106 | const struct GNUNET_MessageHeader *message) | ||
1107 | { | ||
1108 | struct GNUNET_SERVER_TransmitContext *tc; | ||
1109 | const struct PeerMonitorMessage *msg; | ||
1110 | struct IterationContext pc; | ||
1111 | |||
1112 | msg = (const struct PeerMonitorMessage *) message; | ||
1113 | if ( (GNUNET_YES != ntohl (msg->one_shot)) && | ||
1114 | (NULL != lookup_monitoring_client (peer_monitoring_clients_head, | ||
1115 | client)) ) | ||
1116 | { | ||
1117 | GNUNET_break (0); | ||
1118 | GNUNET_SERVER_receive_done (client, | ||
1119 | GNUNET_SYSERR); | ||
1120 | return; | ||
1121 | } | ||
1122 | GNUNET_SERVER_disable_receive_done_warning (client); | ||
1123 | GNUNET_SERVER_client_mark_monitor (client); | ||
1124 | pc.tc = tc = GNUNET_SERVER_transmit_context_create (client); | ||
1125 | |||
1126 | /* Send initial list */ | ||
1127 | if (0 == memcmp (&msg->peer, | ||
1128 | &all_zeros, | ||
1129 | sizeof (struct GNUNET_PeerIdentity))) | ||
1130 | { | ||
1131 | /* iterate over all neighbours */ | ||
1132 | pc.all = GNUNET_YES; | ||
1133 | pc.id = msg->peer; | ||
1134 | } | ||
1135 | else | ||
1136 | { | ||
1137 | /* just return one neighbour */ | ||
1138 | pc.all = GNUNET_NO; | ||
1139 | pc.id = msg->peer; | ||
1140 | } | ||
1141 | GST_neighbours_iterate (&send_peer_information, | ||
1142 | &pc); | ||
1143 | |||
1144 | if (GNUNET_YES != ntohl (msg->one_shot)) | ||
1145 | { | ||
1146 | setup_peer_monitoring_client (client, | ||
1147 | &msg->peer); | ||
1148 | } | ||
1149 | else | ||
1150 | { | ||
1151 | GNUNET_SERVER_transmit_context_append_data (tc, | ||
1152 | NULL, | ||
1153 | 0, | ||
1154 | GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_RESPONSE_END); | ||
1155 | } | ||
1156 | GNUNET_SERVER_transmit_context_run (tc, | ||
1157 | GNUNET_TIME_UNIT_FOREVER_REL); | ||
1158 | } | ||
1159 | |||
1160 | |||
1161 | /** | ||
1162 | * Function called by the plugin with information about the | ||
1163 | * current sessions managed by the plugin (for monitoring). | ||
1164 | * | ||
1165 | * @param cls closure | ||
1166 | * @param session session handle this information is about, | ||
1167 | * NULL to indicate that we are "in sync" (initial | ||
1168 | * iteration complete) | ||
1169 | * @param info information about the state of the session, | ||
1170 | * NULL if @a session is also NULL and we are | ||
1171 | * merely signalling that the initial iteration is over | ||
1172 | */ | ||
1173 | static void | ||
1174 | plugin_session_info_cb (void *cls, | ||
1175 | struct GNUNET_ATS_Session *session, | ||
1176 | const struct GNUNET_TRANSPORT_SessionInfo *info) | ||
1177 | { | ||
1178 | struct TransportPluginMonitorMessage *msg; | ||
1179 | struct GNUNET_MessageHeader sync; | ||
1180 | size_t size; | ||
1181 | size_t slen; | ||
1182 | uint16_t alen; | ||
1183 | char *name; | ||
1184 | char *addr; | ||
1185 | |||
1186 | if (0 == GNUNET_SERVER_notification_context_get_size (plugin_nc)) | ||
1187 | { | ||
1188 | GST_plugins_monitor_subscribe (NULL, | ||
1189 | NULL); | ||
1190 | return; | ||
1191 | } | ||
1192 | if ( (NULL == info) && | ||
1193 | (NULL == session) ) | ||
1194 | { | ||
1195 | /* end of initial iteration */ | ||
1196 | if (NULL != sync_client) | ||
1197 | { | ||
1198 | sync.size = htons (sizeof (struct GNUNET_MessageHeader)); | ||
1199 | sync.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PLUGIN_SYNC); | ||
1200 | GNUNET_SERVER_notification_context_unicast (plugin_nc, | ||
1201 | sync_client, | ||
1202 | &sync, | ||
1203 | GNUNET_NO); | ||
1204 | sync_client = NULL; | ||
1205 | } | ||
1206 | return; | ||
1207 | } | ||
1208 | GNUNET_assert (NULL != info); | ||
1209 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1210 | "Plugin event for peer %s on transport %s\n", | ||
1211 | GNUNET_i2s (&info->address->peer), | ||
1212 | info->address->transport_name); | ||
1213 | slen = strlen (info->address->transport_name) + 1; | ||
1214 | alen = info->address->address_length; | ||
1215 | size = sizeof (struct TransportPluginMonitorMessage) + slen + alen; | ||
1216 | if (size > UINT16_MAX) | ||
1217 | { | ||
1218 | GNUNET_break (0); | ||
1219 | return; | ||
1220 | } | ||
1221 | msg = GNUNET_malloc (size); | ||
1222 | msg->header.size = htons (size); | ||
1223 | msg->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PLUGIN_EVENT); | ||
1224 | msg->session_state = htons ((uint16_t) info->state); | ||
1225 | msg->is_inbound = htons ((int16_t) info->is_inbound); | ||
1226 | msg->msgs_pending = htonl (info->num_msg_pending); | ||
1227 | msg->bytes_pending = htonl (info->num_bytes_pending); | ||
1228 | msg->timeout = GNUNET_TIME_absolute_hton (info->session_timeout); | ||
1229 | msg->delay = GNUNET_TIME_absolute_hton (info->receive_delay); | ||
1230 | msg->peer = info->address->peer; | ||
1231 | msg->session_id = (uint64_t) (intptr_t) session; | ||
1232 | msg->plugin_name_len = htons (slen); | ||
1233 | msg->plugin_address_len = htons (alen); | ||
1234 | name = (char *) &msg[1]; | ||
1235 | GNUNET_memcpy (name, | ||
1236 | info->address->transport_name, | ||
1237 | slen); | ||
1238 | addr = &name[slen]; | ||
1239 | GNUNET_memcpy (addr, | ||
1240 | info->address->address, | ||
1241 | alen); | ||
1242 | if (NULL != sync_client) | ||
1243 | GNUNET_SERVER_notification_context_unicast (plugin_nc, | ||
1244 | sync_client, | ||
1245 | &msg->header, | ||
1246 | GNUNET_NO); | ||
1247 | else | ||
1248 | GNUNET_SERVER_notification_context_broadcast (plugin_nc, | ||
1249 | &msg->header, | ||
1250 | GNUNET_NO); | ||
1251 | GNUNET_free (msg); | ||
1252 | } | ||
1253 | |||
1254 | |||
1255 | /** | ||
1256 | * Client asked to obtain information about all plugin connections. | ||
1257 | * | ||
1258 | * @param cls unused | ||
1259 | * @param client the client | ||
1260 | * @param message the peer address information request | ||
1261 | */ | ||
1262 | static void | ||
1263 | clients_handle_monitor_plugins (void *cls, | ||
1264 | struct GNUNET_SERVER_Client *client, | ||
1265 | const struct GNUNET_MessageHeader *message) | ||
1266 | { | ||
1267 | GNUNET_SERVER_client_mark_monitor (client); | ||
1268 | GNUNET_SERVER_disable_receive_done_warning (client); | ||
1269 | GNUNET_SERVER_notification_context_add (plugin_nc, | ||
1270 | client); | ||
1271 | GNUNET_assert (NULL == sync_client); | ||
1272 | sync_client = client; | ||
1273 | GST_plugins_monitor_subscribe (&plugin_session_info_cb, | ||
1274 | NULL); | ||
1275 | } | ||
1276 | |||
1277 | |||
1278 | /** | ||
1279 | * Start handling requests from clients. | ||
1280 | * | ||
1281 | * @param server server used to accept clients from. | ||
1282 | */ | ||
1283 | void | ||
1284 | GST_clients_start (struct GNUNET_SERVER_Handle *server) | ||
1285 | { | ||
1286 | static const struct GNUNET_SERVER_MessageHandler handlers[] = { | ||
1287 | {&clients_handle_start, NULL, | ||
1288 | GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)}, | ||
1289 | {&clients_handle_hello, NULL, | ||
1290 | GNUNET_MESSAGE_TYPE_HELLO, 0}, | ||
1291 | {&clients_handle_send, NULL, | ||
1292 | GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0}, | ||
1293 | {&clients_handle_address_to_string, NULL, | ||
1294 | GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING, 0}, | ||
1295 | {&clients_handle_monitor_peers, NULL, | ||
1296 | GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_REQUEST, | ||
1297 | sizeof (struct PeerMonitorMessage)}, | ||
1298 | {&GST_blacklist_handle_init, NULL, | ||
1299 | GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT, | ||
1300 | sizeof (struct GNUNET_MessageHeader)}, | ||
1301 | {&GST_blacklist_handle_reply, NULL, | ||
1302 | GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY, | ||
1303 | sizeof (struct BlacklistMessage)}, | ||
1304 | {&GST_manipulation_set_metric, NULL, | ||
1305 | GNUNET_MESSAGE_TYPE_TRANSPORT_TRAFFIC_METRIC, | ||
1306 | sizeof (struct TrafficMetricMessage) }, | ||
1307 | {&clients_handle_monitor_plugins, NULL, | ||
1308 | GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PLUGIN_START, | ||
1309 | sizeof (struct GNUNET_MessageHeader) }, | ||
1310 | {NULL, NULL, 0, 0} | ||
1311 | }; | ||
1312 | active_stccs = GNUNET_CONTAINER_multipeermap_create (128, | ||
1313 | GNUNET_YES); | ||
1314 | peer_nc = GNUNET_SERVER_notification_context_create (server, 0); | ||
1315 | val_nc = GNUNET_SERVER_notification_context_create (server, 0); | ||
1316 | plugin_nc = GNUNET_SERVER_notification_context_create (server, 0); | ||
1317 | GNUNET_SERVER_add_handlers (server, handlers); | ||
1318 | GNUNET_SERVER_disconnect_notify (server, | ||
1319 | &client_disconnect_notification, | ||
1320 | NULL); | ||
1321 | } | ||
1322 | |||
1323 | |||
1324 | /** | ||
1325 | * Stop processing clients. | ||
1326 | */ | ||
1327 | void | ||
1328 | GST_clients_stop () | ||
1329 | { | ||
1330 | struct AddressToStringContext *cur; | ||
1331 | |||
1332 | while (NULL != (cur = a2s_head)) | ||
1333 | { | ||
1334 | GNUNET_SERVER_transmit_context_destroy (cur->tc, GNUNET_NO); | ||
1335 | GNUNET_CONTAINER_DLL_remove (a2s_head, a2s_tail, cur); | ||
1336 | GNUNET_free (cur); | ||
1337 | } | ||
1338 | if (NULL != peer_nc) | ||
1339 | { | ||
1340 | GNUNET_SERVER_notification_context_destroy (peer_nc); | ||
1341 | peer_nc = NULL; | ||
1342 | } | ||
1343 | if (NULL != val_nc) | ||
1344 | { | ||
1345 | GNUNET_SERVER_notification_context_destroy (val_nc); | ||
1346 | val_nc = NULL; | ||
1347 | } | ||
1348 | if (NULL != plugin_nc) | ||
1349 | { | ||
1350 | GNUNET_SERVER_notification_context_destroy (plugin_nc); | ||
1351 | plugin_nc = NULL; | ||
1352 | } | ||
1353 | GNUNET_CONTAINER_multipeermap_destroy (active_stccs); | ||
1354 | active_stccs = NULL; | ||
1355 | } | ||
1356 | |||
1357 | |||
1358 | /** | ||
1359 | * Broadcast the given message to all of our clients. | ||
1360 | * | ||
1361 | * @param msg message to broadcast | ||
1362 | * @param may_drop #GNUNET_YES if the message can be dropped / is payload | ||
1363 | */ | ||
1364 | void | ||
1365 | GST_clients_broadcast (const struct GNUNET_MessageHeader *msg, | ||
1366 | int may_drop) | ||
1367 | { | ||
1368 | struct TransportClient *tc; | ||
1369 | int done; | ||
1370 | |||
1371 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1372 | "Asked to broadcast message of type %u with %u bytes\n", | ||
1373 | (unsigned int) ntohs (msg->type), | ||
1374 | (unsigned int) ntohs (msg->size)); | ||
1375 | done = GNUNET_NO; | ||
1376 | for (tc = clients_head; NULL != tc; tc = tc->next) | ||
1377 | { | ||
1378 | if ( (GNUNET_YES == may_drop) && | ||
1379 | (GNUNET_YES != tc->send_payload) ) | ||
1380 | continue; /* skip, this client does not care about payload */ | ||
1381 | unicast (tc, msg, may_drop); | ||
1382 | done = GNUNET_YES; | ||
1383 | } | ||
1384 | if (GNUNET_NO == done) | ||
1385 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
1386 | "Message of type %u not delivered, is CORE service up?\n", | ||
1387 | ntohs (msg->type)); | ||
1388 | } | ||
1389 | |||
1390 | |||
1391 | /** | ||
1392 | * Send the given message to a particular client | ||
1393 | * | ||
1394 | * @param client target of the message | ||
1395 | * @param msg message to transmit | ||
1396 | * @param may_drop #GNUNET_YES if the message can be dropped | ||
1397 | */ | ||
1398 | void | ||
1399 | GST_clients_unicast (struct GNUNET_SERVER_Client *client, | ||
1400 | const struct GNUNET_MessageHeader *msg, | ||
1401 | int may_drop) | ||
1402 | { | ||
1403 | struct TransportClient *tc; | ||
1404 | |||
1405 | tc = lookup_client (client); | ||
1406 | if (NULL == tc) | ||
1407 | return; /* client got disconnected in the meantime, drop message */ | ||
1408 | unicast (tc, msg, may_drop); | ||
1409 | } | ||
1410 | |||
1411 | |||
1412 | /** | ||
1413 | * Broadcast the new active address to all clients monitoring the peer. | ||
1414 | * | ||
1415 | * @param peer peer this update is about (never NULL) | ||
1416 | * @param address address, NULL on disconnect | ||
1417 | * @param state the current state of the peer | ||
1418 | * @param state_timeout the time out for the state | ||
1419 | */ | ||
1420 | void | ||
1421 | GST_clients_broadcast_peer_notification (const struct GNUNET_PeerIdentity *peer, | ||
1422 | const struct GNUNET_HELLO_Address *address, | ||
1423 | enum GNUNET_TRANSPORT_PeerState state, | ||
1424 | struct GNUNET_TIME_Absolute state_timeout) | ||
1425 | { | ||
1426 | struct PeerIterateResponseMessage *msg; | ||
1427 | struct MonitoringClient *mc; | ||
1428 | |||
1429 | msg = compose_address_iterate_response_message (peer, address); | ||
1430 | msg->state = htonl (state); | ||
1431 | msg->state_timeout = GNUNET_TIME_absolute_hton (state_timeout); | ||
1432 | for (mc = peer_monitoring_clients_head; NULL != mc; mc = mc->next) | ||
1433 | if ((0 == memcmp (&mc->peer, &all_zeros, | ||
1434 | sizeof (struct GNUNET_PeerIdentity))) || | ||
1435 | (0 == memcmp (&mc->peer, peer, | ||
1436 | sizeof (struct GNUNET_PeerIdentity)))) | ||
1437 | GNUNET_SERVER_notification_context_unicast (peer_nc, | ||
1438 | mc->client, | ||
1439 | &msg->header, | ||
1440 | GNUNET_NO); | ||
1441 | GNUNET_free (msg); | ||
1442 | } | ||
1443 | |||
1444 | |||
1445 | /** | ||
1446 | * Mark the peer as down so we don't call the continuation | ||
1447 | * context in the future. | ||
1448 | * | ||
1449 | * @param cls NULL | ||
1450 | * @param peer peer that got disconnected | ||
1451 | * @param value a `struct SendTransmitContinuationContext` to mark | ||
1452 | * @return #GNUNET_OK (continue to iterate) | ||
1453 | */ | ||
1454 | static int | ||
1455 | mark_peer_down (void *cls, | ||
1456 | const struct GNUNET_PeerIdentity *peer, | ||
1457 | void *value) | ||
1458 | { | ||
1459 | struct SendTransmitContinuationContext *stcc = value; | ||
1460 | |||
1461 | stcc->down = GNUNET_YES; | ||
1462 | return GNUNET_OK; | ||
1463 | } | ||
1464 | |||
1465 | |||
1466 | /** | ||
1467 | * Notify all clients about a disconnect, and cancel | ||
1468 | * pending SEND_OK messages for this peer. | ||
1469 | * | ||
1470 | * @param peer peer that disconnected | ||
1471 | */ | ||
1472 | void | ||
1473 | GST_clients_broadcast_disconnect (const struct GNUNET_PeerIdentity *peer) | ||
1474 | { | ||
1475 | struct DisconnectInfoMessage disconnect_msg; | ||
1476 | |||
1477 | GNUNET_CONTAINER_multipeermap_get_multiple (active_stccs, | ||
1478 | peer, | ||
1479 | &mark_peer_down, | ||
1480 | NULL); | ||
1481 | disconnect_msg.header.size = htons (sizeof(struct DisconnectInfoMessage)); | ||
1482 | disconnect_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT); | ||
1483 | disconnect_msg.reserved = htonl (0); | ||
1484 | disconnect_msg.peer = *peer; | ||
1485 | GST_clients_broadcast (&disconnect_msg.header, | ||
1486 | GNUNET_NO); | ||
1487 | |||
1488 | } | ||
1489 | |||
1490 | |||
1491 | /* end of file gnunet-service-transport_clients.c */ | ||
diff --git a/src/transport/gnunet-service-transport_clients.h b/src/transport/gnunet-service-transport_clients.h deleted file mode 100644 index d85e1e340..000000000 --- a/src/transport/gnunet-service-transport_clients.h +++ /dev/null | |||
@@ -1,101 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. | ||
3 | Copyright (C) 2010,2011 GNUnet e.V. | ||
4 | |||
5 | GNUnet is free software; you can redistribute it and/or modify | ||
6 | it under the terms of the GNU General Public License as published | ||
7 | by the Free Software Foundation; either version 3, or (at your | ||
8 | option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU General Public License | ||
16 | along with GNUnet; see the file COPYING. If not, write to the | ||
17 | Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | ||
19 | */ | ||
20 | |||
21 | /** | ||
22 | * @file transport/gnunet-service-transport_clients.h | ||
23 | * @brief client management API | ||
24 | * @author Christian Grothoff | ||
25 | */ | ||
26 | #ifndef GNUNET_SERVICE_TRANSPORT_CLIENTS_H | ||
27 | #define GNUNET_SERVICE_TRANSPORT_CLIENTS_H | ||
28 | |||
29 | #include "gnunet_transport_service.h" | ||
30 | #include "gnunet_statistics_service.h" | ||
31 | #include "gnunet_util_lib.h" | ||
32 | #include "gnunet_hello_lib.h" | ||
33 | |||
34 | |||
35 | /** | ||
36 | * Start handling requests from clients. | ||
37 | * | ||
38 | * @param server server used to accept clients from. | ||
39 | */ | ||
40 | void | ||
41 | GST_clients_start (struct GNUNET_SERVER_Handle *server); | ||
42 | |||
43 | |||
44 | /** | ||
45 | * Stop processing clients. | ||
46 | */ | ||
47 | void | ||
48 | GST_clients_stop (void); | ||
49 | |||
50 | |||
51 | /** | ||
52 | * Broadcast the given message to all of our clients. | ||
53 | * | ||
54 | * @param msg message to broadcast | ||
55 | * @param may_drop #GNUNET_YES if the message can be dropped / is payload | ||
56 | */ | ||
57 | void | ||
58 | GST_clients_broadcast (const struct GNUNET_MessageHeader *msg, | ||
59 | int may_drop); | ||
60 | |||
61 | |||
62 | /** | ||
63 | * Send the given message to a particular client | ||
64 | * | ||
65 | * @param client target of the message | ||
66 | * @param msg message to transmit | ||
67 | * @param may_drop #GNUNET_YES if the message can be dropped | ||
68 | */ | ||
69 | void | ||
70 | GST_clients_unicast (struct GNUNET_SERVER_Client *client, | ||
71 | const struct GNUNET_MessageHeader *msg, | ||
72 | int may_drop); | ||
73 | |||
74 | |||
75 | /** | ||
76 | * Broadcast the new active address to all clients monitoring the peer. | ||
77 | * | ||
78 | * @param peer peer this update is about (never NULL) | ||
79 | * @param address address, NULL on disconnect | ||
80 | * @param state the current state of the peer | ||
81 | * @param state_timeout the time out for the state | ||
82 | */ | ||
83 | void | ||
84 | GST_clients_broadcast_peer_notification (const struct GNUNET_PeerIdentity *peer, | ||
85 | const struct GNUNET_HELLO_Address *address, | ||
86 | enum GNUNET_TRANSPORT_PeerState state, | ||
87 | struct GNUNET_TIME_Absolute state_timeout); | ||
88 | |||
89 | |||
90 | /** | ||
91 | * Notify all clients about a disconnect, and cancel | ||
92 | * pending SEND_OK messages for this peer. | ||
93 | * | ||
94 | * @param peer peer that disconnected | ||
95 | */ | ||
96 | void | ||
97 | GST_clients_broadcast_disconnect (const struct GNUNET_PeerIdentity *peer); | ||
98 | |||
99 | |||
100 | #endif | ||
101 | /* end of file gnunet-service-transport_clients.h */ | ||
diff --git a/src/transport/gnunet-service-transport_manipulation.c b/src/transport/gnunet-service-transport_manipulation.c index 1af023d4d..f198d6e49 100644 --- a/src/transport/gnunet-service-transport_manipulation.c +++ b/src/transport/gnunet-service-transport_manipulation.c | |||
@@ -25,8 +25,6 @@ | |||
25 | * @author Matthias Wachs | 25 | * @author Matthias Wachs |
26 | */ | 26 | */ |
27 | #include "platform.h" | 27 | #include "platform.h" |
28 | #include "gnunet-service-transport_blacklist.h" | ||
29 | #include "gnunet-service-transport_clients.h" | ||
30 | #include "gnunet-service-transport_hello.h" | 28 | #include "gnunet-service-transport_hello.h" |
31 | #include "gnunet-service-transport_neighbours.h" | 29 | #include "gnunet-service-transport_neighbours.h" |
32 | #include "gnunet-service-transport_plugins.h" | 30 | #include "gnunet-service-transport_plugins.h" |
@@ -170,20 +168,14 @@ static struct GNUNET_SCHEDULER_Task *generic_send_delay_task; | |||
170 | /** | 168 | /** |
171 | * Set traffic metric to manipulate | 169 | * Set traffic metric to manipulate |
172 | * | 170 | * |
173 | * @param cls closure | ||
174 | * @param client client sending message | ||
175 | * @param message containing information | 171 | * @param message containing information |
176 | */ | 172 | */ |
177 | void | 173 | void |
178 | GST_manipulation_set_metric (void *cls, | 174 | GST_manipulation_set_metric (const struct TrafficMetricMessage *tm) |
179 | struct GNUNET_SERVER_Client *client, | ||
180 | const struct GNUNET_MessageHeader *message) | ||
181 | { | 175 | { |
182 | const struct TrafficMetricMessage *tm; | ||
183 | static struct GNUNET_PeerIdentity zero; | 176 | static struct GNUNET_PeerIdentity zero; |
184 | struct TM_Peer *tmp; | 177 | struct TM_Peer *tmp; |
185 | 178 | ||
186 | tm = (const struct TrafficMetricMessage *) message; | ||
187 | if (0 == memcmp (&tm->peer, | 179 | if (0 == memcmp (&tm->peer, |
188 | &zero, | 180 | &zero, |
189 | sizeof(struct GNUNET_PeerIdentity))) | 181 | sizeof(struct GNUNET_PeerIdentity))) |
@@ -192,13 +184,11 @@ GST_manipulation_set_metric (void *cls, | |||
192 | "Received traffic metrics for all peers\n"); | 184 | "Received traffic metrics for all peers\n"); |
193 | delay_in = GNUNET_TIME_relative_ntoh (tm->delay_in); | 185 | delay_in = GNUNET_TIME_relative_ntoh (tm->delay_in); |
194 | delay_out = GNUNET_TIME_relative_ntoh (tm->delay_out); | 186 | delay_out = GNUNET_TIME_relative_ntoh (tm->delay_out); |
195 | GNUNET_SERVER_receive_done (client, | ||
196 | GNUNET_OK); | ||
197 | return; | 187 | return; |
198 | } | 188 | } |
199 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 189 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
200 | "Received traffic metrics for peer `%s'\n", | 190 | "Received traffic metrics for peer `%s'\n", |
201 | GNUNET_i2s(&tm->peer)); | 191 | GNUNET_i2s (&tm->peer)); |
202 | if (NULL == | 192 | if (NULL == |
203 | (tmp = GNUNET_CONTAINER_multipeermap_get (peers, | 193 | (tmp = GNUNET_CONTAINER_multipeermap_get (peers, |
204 | &tm->peer))) | 194 | &tm->peer))) |
@@ -214,8 +204,6 @@ GST_manipulation_set_metric (void *cls, | |||
214 | &tm->properties); | 204 | &tm->properties); |
215 | tmp->delay_in = GNUNET_TIME_relative_ntoh (tm->delay_in); | 205 | tmp->delay_in = GNUNET_TIME_relative_ntoh (tm->delay_in); |
216 | tmp->delay_out = GNUNET_TIME_relative_ntoh (tm->delay_out); | 206 | tmp->delay_out = GNUNET_TIME_relative_ntoh (tm->delay_out); |
217 | GNUNET_SERVER_receive_done (client, | ||
218 | GNUNET_OK); | ||
219 | } | 207 | } |
220 | 208 | ||
221 | 209 | ||
@@ -494,7 +482,9 @@ GST_manipulation_peer_disconnect (const struct GNUNET_PeerIdentity *peer) | |||
494 | while (NULL != (dqe = next)) | 482 | while (NULL != (dqe = next)) |
495 | { | 483 | { |
496 | next = dqe->next; | 484 | next = dqe->next; |
497 | if (0 == memcmp(peer, &dqe->id, sizeof(dqe->id))) | 485 | if (0 == memcmp (peer, |
486 | &dqe->id, | ||
487 | sizeof (dqe->id))) | ||
498 | { | 488 | { |
499 | GNUNET_CONTAINER_DLL_remove (generic_dqe_head, | 489 | GNUNET_CONTAINER_DLL_remove (generic_dqe_head, |
500 | generic_dqe_tail, | 490 | generic_dqe_tail, |
diff --git a/src/transport/gnunet-service-transport_manipulation.h b/src/transport/gnunet-service-transport_manipulation.h index 6c7cede41..312dd1168 100644 --- a/src/transport/gnunet-service-transport_manipulation.h +++ b/src/transport/gnunet-service-transport_manipulation.h | |||
@@ -28,8 +28,6 @@ | |||
28 | #define GNUNET_SERVICE_TRANSPORT_MANIPULATION_H | 28 | #define GNUNET_SERVICE_TRANSPORT_MANIPULATION_H |
29 | 29 | ||
30 | #include "platform.h" | 30 | #include "platform.h" |
31 | #include "gnunet-service-transport_blacklist.h" | ||
32 | #include "gnunet-service-transport_clients.h" | ||
33 | #include "gnunet-service-transport_hello.h" | 31 | #include "gnunet-service-transport_hello.h" |
34 | #include "gnunet-service-transport_neighbours.h" | 32 | #include "gnunet-service-transport_neighbours.h" |
35 | #include "gnunet-service-transport_plugins.h" | 33 | #include "gnunet-service-transport_plugins.h" |
@@ -41,14 +39,10 @@ | |||
41 | /** | 39 | /** |
42 | * Set traffic metric to manipulate | 40 | * Set traffic metric to manipulate |
43 | * | 41 | * |
44 | * @param cls closure | ||
45 | * @param client client sending message | ||
46 | * @param message containing information | 42 | * @param message containing information |
47 | */ | 43 | */ |
48 | void | 44 | void |
49 | GST_manipulation_set_metric (void *cls, | 45 | GST_manipulation_set_metric (const struct TrafficMetricMessage *tm); |
50 | struct GNUNET_SERVER_Client *client, | ||
51 | const struct GNUNET_MessageHeader *message); | ||
52 | 46 | ||
53 | 47 | ||
54 | /** | 48 | /** |
diff --git a/src/transport/gnunet-service-transport_neighbours.c b/src/transport/gnunet-service-transport_neighbours.c index 2614c8551..d82112e03 100644 --- a/src/transport/gnunet-service-transport_neighbours.c +++ b/src/transport/gnunet-service-transport_neighbours.c | |||
@@ -26,8 +26,6 @@ | |||
26 | #include "platform.h" | 26 | #include "platform.h" |
27 | #include "gnunet_ats_service.h" | 27 | #include "gnunet_ats_service.h" |
28 | #include "gnunet-service-transport_ats.h" | 28 | #include "gnunet-service-transport_ats.h" |
29 | #include "gnunet-service-transport_blacklist.h" | ||
30 | #include "gnunet-service-transport_clients.h" | ||
31 | #include "gnunet-service-transport_neighbours.h" | 29 | #include "gnunet-service-transport_neighbours.h" |
32 | #include "gnunet-service-transport_manipulation.h" | 30 | #include "gnunet-service-transport_manipulation.h" |
33 | #include "gnunet-service-transport_plugins.h" | 31 | #include "gnunet-service-transport_plugins.h" |
diff --git a/src/transport/gnunet-service-transport_validation.c b/src/transport/gnunet-service-transport_validation.c index 494f88f11..505626b59 100644 --- a/src/transport/gnunet-service-transport_validation.c +++ b/src/transport/gnunet-service-transport_validation.c | |||
@@ -25,8 +25,6 @@ | |||
25 | */ | 25 | */ |
26 | #include "platform.h" | 26 | #include "platform.h" |
27 | #include "gnunet-service-transport_ats.h" | 27 | #include "gnunet-service-transport_ats.h" |
28 | #include "gnunet-service-transport_blacklist.h" | ||
29 | #include "gnunet-service-transport_clients.h" | ||
30 | #include "gnunet-service-transport_hello.h" | 28 | #include "gnunet-service-transport_hello.h" |
31 | #include "gnunet-service-transport_neighbours.h" | 29 | #include "gnunet-service-transport_neighbours.h" |
32 | #include "gnunet-service-transport_plugins.h" | 30 | #include "gnunet-service-transport_plugins.h" |
diff --git a/src/transport/test_transport_api_manipulation_recv_tcp.c b/src/transport/test_transport_api_manipulation_recv_tcp.c index 3014715b1..69ccf5763 100644 --- a/src/transport/test_transport_api_manipulation_recv_tcp.c +++ b/src/transport/test_transport_api_manipulation_recv_tcp.c | |||
@@ -60,6 +60,16 @@ do_free (void *cls) | |||
60 | 60 | ||
61 | 61 | ||
62 | static void | 62 | static void |
63 | delayed_transmit (void *cls) | ||
64 | { | ||
65 | struct GNUNET_TRANSPORT_TESTING_SendClosure *sc = cls; | ||
66 | |||
67 | start_delayed = GNUNET_TIME_absolute_get (); | ||
68 | GNUNET_TRANSPORT_TESTING_large_send (sc); | ||
69 | } | ||
70 | |||
71 | |||
72 | static void | ||
63 | sendtask (void *cls) | 73 | sendtask (void *cls) |
64 | { | 74 | { |
65 | struct GNUNET_TRANSPORT_TESTING_SendClosure *sc; | 75 | struct GNUNET_TRANSPORT_TESTING_SendClosure *sc; |
@@ -84,7 +94,11 @@ sendtask (void *cls) | |||
84 | &prop, | 94 | &prop, |
85 | delay, | 95 | delay, |
86 | GNUNET_TIME_UNIT_ZERO); | 96 | GNUNET_TIME_UNIT_ZERO); |
87 | start_delayed = GNUNET_TIME_absolute_get(); | 97 | /* wait 1s to allow manipulation to go into effect */ |
98 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, | ||
99 | &delayed_transmit, | ||
100 | sc); | ||
101 | return; | ||
88 | } | 102 | } |
89 | GNUNET_TRANSPORT_TESTING_large_send (sc); | 103 | GNUNET_TRANSPORT_TESTING_large_send (sc); |
90 | } | 104 | } |
diff --git a/src/transport/test_transport_api_manipulation_send_tcp.c b/src/transport/test_transport_api_manipulation_send_tcp.c index fbb7ccbdb..602d4d277 100644 --- a/src/transport/test_transport_api_manipulation_send_tcp.c +++ b/src/transport/test_transport_api_manipulation_send_tcp.c | |||
@@ -59,6 +59,16 @@ do_free (void *cls) | |||
59 | 59 | ||
60 | 60 | ||
61 | static void | 61 | static void |
62 | delayed_transmit (void *cls) | ||
63 | { | ||
64 | struct GNUNET_TRANSPORT_TESTING_SendClosure *sc = cls; | ||
65 | |||
66 | start_delayed = GNUNET_TIME_absolute_get (); | ||
67 | GNUNET_TRANSPORT_TESTING_large_send (sc); | ||
68 | } | ||
69 | |||
70 | |||
71 | static void | ||
62 | sendtask (void *cls) | 72 | sendtask (void *cls) |
63 | { | 73 | { |
64 | struct GNUNET_TRANSPORT_TESTING_SendClosure *sc; | 74 | struct GNUNET_TRANSPORT_TESTING_SendClosure *sc; |
@@ -76,14 +86,20 @@ sendtask (void *cls) | |||
76 | } | 86 | } |
77 | if (1 == messages_recv) | 87 | if (1 == messages_recv) |
78 | { | 88 | { |
79 | memset (&prop, 0, sizeof (prop)); | 89 | memset (&prop, |
90 | 0, | ||
91 | sizeof (prop)); | ||
80 | delay = GNUNET_TIME_UNIT_SECONDS; | 92 | delay = GNUNET_TIME_UNIT_SECONDS; |
81 | GNUNET_TRANSPORT_manipulation_set (ccc->p[0]->tmh, | 93 | GNUNET_TRANSPORT_manipulation_set (ccc->p[0]->tmh, |
82 | &ccc->p[1]->id, | 94 | &ccc->p[1]->id, |
83 | &prop, | 95 | &prop, |
84 | GNUNET_TIME_UNIT_ZERO, | 96 | GNUNET_TIME_UNIT_ZERO, |
85 | delay); | 97 | delay); |
86 | start_delayed = GNUNET_TIME_absolute_get(); | 98 | /* wait 1s to allow manipulation to go into effect */ |
99 | GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, | ||
100 | &delayed_transmit, | ||
101 | sc); | ||
102 | return; | ||
87 | } | 103 | } |
88 | GNUNET_TRANSPORT_TESTING_large_send (sc); | 104 | GNUNET_TRANSPORT_TESTING_large_send (sc); |
89 | } | 105 | } |
@@ -120,7 +136,7 @@ notify_receive (void *cls, | |||
120 | if (0 == messages_recv) | 136 | if (0 == messages_recv) |
121 | { | 137 | { |
122 | /* Received non-delayed message */ | 138 | /* Received non-delayed message */ |
123 | dur_normal = GNUNET_TIME_absolute_get_duration(start_normal); | 139 | dur_normal = GNUNET_TIME_absolute_get_duration (start_normal); |
124 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 140 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
125 | "Received non-delayed message %u after %s\n", | 141 | "Received non-delayed message %u after %s\n", |
126 | messages_recv, | 142 | messages_recv, |