connected peer lookup
[oweals/gnunet.git] / src / transport / gnunet-service-transport.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009, 2010 Christian Grothoff (and other contributing authors)
4
5      GNUnet is free software; you can redistribute it and/or modify
6      it under the terms of the GNU General Public License as published
7      by the Free Software Foundation; either version 3, or (at your
8      option) any later version.
9
10      GNUnet is distributed in the hope that it will be useful, but
11      WITHOUT ANY WARRANTY; without even the implied warranty of
12      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13      General Public License for more details.
14
15      You should have received a copy of the GNU General Public License
16      along with GNUnet; see the file COPYING.  If not, write to the
17      Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18      Boston, MA 02111-1307, USA.
19 */
20
21 /**
22  * @file transport/gnunet-service-transport.c
23  * @brief low-level P2P messaging
24  * @author Christian Grothoff
25  *
26  */
27 #include "platform.h"
28 #include "gnunet_client_lib.h"
29 #include "gnunet_container_lib.h"
30 #include "gnunet_constants.h"
31 #include "gnunet_getopt_lib.h"
32 #include "gnunet_hello_lib.h"
33 #include "gnunet_os_lib.h"
34 #include "gnunet_peerinfo_service.h"
35 #include "gnunet_plugin_lib.h"
36 #include "gnunet_protocols.h"
37 #include "gnunet_service_lib.h"
38 #include "gnunet_signatures.h"
39 #include "gnunet_transport_plugin.h"
40 #include "transport.h"
41 #include "transport_ats.h"
42
43
44 #define DEBUG_BLACKLIST GNUNET_NO
45
46 #define DEBUG_PING_PONG GNUNET_NO
47
48 #define DEBUG_TRANSPORT_HELLO GNUNET_NO
49
50 /**
51  * Should we do some additional checks (to validate behavior
52  * of clients)?
53  */
54 #define EXTRA_CHECKS GNUNET_YES
55
56 /**
57  * How many messages can we have pending for a given client process
58  * before we start to drop incoming messages?  We typically should
59  * have only one client and so this would be the primary buffer for
60   * messages, so the number should be chosen rather generously.
61  *
62  * The expectation here is that most of the time the queue is large
63  * enough so that a drop is virtually never required.  Note that
64  * this value must be about as large as 'TOTAL_MSGS' in the
65  * 'test_transport_api_reliability.c', otherwise that testcase may
66  * fail.
67  */
68 #define MAX_PENDING (128 * 1024)
69
70 /**
71  * Size of the per-transport blacklist hash maps.
72  */
73 #define TRANSPORT_BLACKLIST_HT_SIZE 16
74
75 /**
76  * How often should we try to reconnect to a peer using a particular
77  * transport plugin before giving up?  Note that the plugin may be
78  * added back to the list after PLUGIN_RETRY_FREQUENCY expires.
79  */
80 #define MAX_CONNECT_RETRY 3
81
82 /**
83  * Limit on the number of ready-to-run tasks when validating
84  * HELLOs.  If more tasks are ready to run, we will drop
85  * HELLOs instead of validating them.
86  */
87 #define MAX_HELLO_LOAD 4
88
89 /**
90  * How often must a peer violate bandwidth quotas before we start
91  * to simply drop its messages?
92  */
93 #define QUOTA_VIOLATION_DROP_THRESHOLD 10
94
95 /**
96  * How long until a HELLO verification attempt should time out?
97  * Must be rather small, otherwise a partially successful HELLO
98  * validation (some addresses working) might not be available
99  * before a client's request for a connection fails for good.
100  * Besides, if a single request to an address takes a long time,
101  * then the peer is unlikely worthwhile anyway.
102  */
103 #define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
104
105 /**
106  * How long is a PONG signature valid?  We'll recycle a signature until
107  * 1/4 of this time is remaining.  PONGs should expire so that if our
108  * external addresses change an adversary cannot replay them indefinitely.
109  * OTOH, we don't want to spend too much time generating PONG signatures,
110  * so they must have some lifetime to reduce our CPU usage.
111  */
112 #define PONG_SIGNATURE_LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
113
114 /**
115  * Priority to use for PONG messages.
116  */
117 #define TRANSPORT_PONG_PRIORITY 4
118
119 /**
120  * How often do we re-add (cheaper) plugins to our list of plugins
121  * to try for a given connected peer?
122  */
123 #define PLUGIN_RETRY_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
124
125 /**
126  * After how long do we expire an address in a HELLO that we just
127  * validated?  This value is also used for our own addresses when we
128  * create a HELLO.
129  */
130 #define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
131
132
133 /**
134  * How long before an existing address expires should we again try to
135  * validate it?  Must be (significantly) smaller than
136  * HELLO_ADDRESS_EXPIRATION.
137  */
138 #define HELLO_REVALIDATION_START_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
139
140 /**
141  * Maximum frequency for re-evaluating latencies for all transport addresses.
142  */
143 #define LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
144
145 /**
146  * Maximum frequency for re-evaluating latencies for connected addresses.
147  */
148 #define CONNECTED_LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
149
150 /**
151  * List of addresses of other peers
152  */
153 struct ForeignAddressList
154 {
155   /**
156    * This is a linked list.
157    */
158   struct ForeignAddressList *next;
159
160   /**
161    * Which ready list does this entry belong to.
162    */
163   struct ReadyList *ready_list;
164
165   /**
166    * How long until we auto-expire this address (unless it is
167    * re-confirmed by the transport)?
168    */
169   struct GNUNET_TIME_Absolute expires;
170
171   /**
172    * Task used to re-validate addresses, updates latencies and
173    * verifies liveness.
174    */
175   GNUNET_SCHEDULER_TaskIdentifier revalidate_task;
176
177   /**
178    * The address.
179    */
180   const void *addr;
181
182   /**
183    * Session (or NULL if no valid session currently exists or if the
184    * plugin does not use sessions).
185    */
186   struct Session *session;
187
188   struct ATS_ressource_entry * ressources;
189
190   struct ATS_quality_entry * quality;
191
192   /**
193    * What was the last latency observed for this address, plugin and peer?
194    */
195   struct GNUNET_TIME_Relative latency;
196
197   /**
198    * If we did not successfully transmit a message to the given peer
199    * via this connection during the specified time, we should consider
200    * the connection to be dead.  This is used in the case that a TCP
201    * transport simply stalls writing to the stream but does not
202    * formerly get a signal that the other peer died.
203    */
204   struct GNUNET_TIME_Absolute timeout;
205
206   /**
207    * How often have we tried to connect using this plugin?  Used to
208    * discriminate against addresses that do not work well.
209    * FIXME: not yet used, but should be!
210    */
211   unsigned int connect_attempts;
212
213   /**
214    * DV distance to this peer (1 if no DV is used).
215    * FIXME: need to set this from transport plugins!
216    */
217   uint32_t distance;
218
219   /**
220    * Length of addr.
221    */
222   uint16_t addrlen;
223
224   /**
225    * Have we ever estimated the latency of this address?  Used to
226    * ensure that the first time we add an address, we immediately
227    * probe its latency.
228    */
229   int8_t estimated;
230
231   /**
232    * Are we currently connected via this address?  The first time we
233    * successfully transmit or receive data to a peer via a particular
234    * address, we set this to GNUNET_YES.  If we later get an error
235    * (disconnect notification, transmission failure, timeout), we set
236    * it back to GNUNET_NO.
237    */
238   int8_t connected;
239
240   /**
241    * Is this plugin currently busy transmitting to the specific target?
242    * GNUNET_NO if not (initial, default state is GNUNET_NO).   Internal
243    * messages do not count as 'in transmit'.
244    */
245   int8_t in_transmit;
246
247   /**
248    * Has this address been validated yet?
249    */
250   int8_t validated;
251
252 };
253
254
255 /**
256  * Entry in linked list of network addresses for ourselves.  Also
257  * includes a cached signature for 'struct TransportPongMessage's.
258  */
259 struct OwnAddressList
260 {
261   /**
262    * This is a linked list.
263    */
264   struct OwnAddressList *next;
265
266   /**
267    * How long until the current signature expires? (ZERO if the
268    * signature was never created).
269    */
270   struct GNUNET_TIME_Absolute pong_sig_expires;
271
272   /**
273    * Signature for a 'struct TransportPongMessage' for this address.
274    */
275   struct GNUNET_CRYPTO_RsaSignature pong_signature;
276
277   /**
278    * Length of addr.
279    */
280   uint32_t addrlen;
281
282 };
283
284
285 /**
286  * Entry in linked list of all of our plugins.
287  */
288 struct TransportPlugin
289 {
290   /**
291    * This is a linked list.
292    */
293   struct TransportPlugin *next;
294
295   /**
296    * API of the transport as returned by the plugin's
297    * initialization function.
298    */
299   struct GNUNET_TRANSPORT_PluginFunctions *api;
300
301   /**
302    * Short name for the plugin (i.e. "tcp").
303    */
304   char *short_name;
305
306   /**
307    * Name of the library (i.e. "gnunet_plugin_transport_tcp").
308    */
309   char *lib_name;
310
311   /**
312    * List of our known addresses for this transport.
313    */
314   struct OwnAddressList *addresses;
315
316   /**
317    * Environment this transport service is using
318    * for this plugin.
319    */
320   struct GNUNET_TRANSPORT_PluginEnvironment env;
321
322   /**
323    * ID of task that is used to clean up expired addresses.
324    */
325   GNUNET_SCHEDULER_TaskIdentifier address_update_task;
326
327   /**
328    * Set to GNUNET_YES if we need to scrap the existing list of
329    * "addresses" and start fresh when we receive the next address
330    * update from a transport.  Set to GNUNET_NO if we should just add
331    * the new address to the list and wait for the commit call.
332    */
333   int rebuild;
334
335   struct ATS_plugin * rc;
336
337   /**
338    * Hashmap of blacklisted peers for this particular transport.
339    */
340   struct GNUNET_CONTAINER_MultiHashMap *blacklist;
341 };
342
343 struct NeighbourList;
344
345 /**
346  * For each neighbour we keep a list of messages
347  * that we still want to transmit to the neighbour.
348  */
349 struct MessageQueue
350 {
351
352   /**
353    * This is a doubly linked list.
354    */
355   struct MessageQueue *next;
356
357   /**
358    * This is a doubly linked list.
359    */
360   struct MessageQueue *prev;
361
362   /**
363    * The message(s) we want to transmit, GNUNET_MessageHeader(s)
364    * stuck together in memory.  Allocated at the end of this struct.
365    */
366   const char *message_buf;
367
368   /**
369    * Size of the message buf
370    */
371   size_t message_buf_size;
372
373   /**
374    * Client responsible for queueing the message;
375    * used to check that a client has no two messages
376    * pending for the same target.  Can be NULL.
377    */
378   struct TransportClient *client;
379
380   /**
381    * Using which specific address should we send this message?
382    */
383   struct ForeignAddressList *specific_address;
384
385   /**
386    * Peer ID of the Neighbour this entry belongs to.
387    */
388   struct GNUNET_PeerIdentity neighbour_id;
389
390   /**
391    * Plugin that we used for the transmission.
392    * NULL until we scheduled a transmission.
393    */
394   struct TransportPlugin *plugin;
395
396   /**
397    * At what time should we fail?
398    */
399   struct GNUNET_TIME_Absolute timeout;
400
401   /**
402    * Internal message of the transport system that should not be
403    * included in the usual SEND-SEND_OK transmission confirmation
404    * traffic management scheme.  Typically, "internal_msg" will
405    * be set whenever "client" is NULL (but it is not strictly
406    * required).
407    */
408   int internal_msg;
409
410   /**
411    * How important is the message?
412    */
413   unsigned int priority;
414
415 };
416
417
418 /**
419  * For a given Neighbour, which plugins are available
420  * to talk to this peer and what are their costs?
421  */
422 struct ReadyList
423 {
424   /**
425    * This is a linked list.
426    */
427   struct ReadyList *next;
428
429   /**
430    * Which of our transport plugins does this entry
431    * represent?
432    */
433   struct TransportPlugin *plugin;
434
435   /**
436    * Transport addresses, latency, and readiness for
437    * this particular plugin.
438    */
439   struct ForeignAddressList *addresses;
440
441   /**
442    * To which neighbour does this ready list belong to?
443    */
444   struct NeighbourList *neighbour;
445 };
446
447
448 /**
449  * Entry in linked list of all of our current neighbours.
450  */
451 struct NeighbourList
452 {
453
454   /**
455    * This is a linked list.
456    */
457   struct NeighbourList *next;
458
459   /**
460    * Which of our transports is connected to this peer
461    * and what is their status?
462    */
463   struct ReadyList *plugins;
464
465   /**
466    * Head of list of messages we would like to send to this peer;
467    * must contain at most one message per client.
468    */
469   struct MessageQueue *messages_head;
470
471   /**
472    * Tail of list of messages we would like to send to this peer; must
473    * contain at most one message per client.
474    */
475   struct MessageQueue *messages_tail;
476
477   /**
478    * Head of list of messages of messages we expected the continuation
479    * to be called to destroy the message
480    */
481   struct MessageQueue *cont_head;
482
483   /**
484    * Tail of list of messages of messages we expected the continuation
485    * to be called to destroy the message
486    */
487   struct MessageQueue *cont_tail;
488
489   /**
490    * Buffer for at most one payload message used when we receive
491    * payload data before our PING-PONG has succeeded.  We then
492    * store such messages in this intermediary buffer until the
493    * connection is fully up.
494    */
495   struct GNUNET_MessageHeader *pre_connect_message_buffer;
496
497   /**
498    * Context for peerinfo iteration.
499    * NULL after we are done processing peerinfo's information.
500    */
501   struct GNUNET_PEERINFO_IteratorContext *piter;
502
503   /**
504    * Public key for this peer.   Valid only if the respective flag is set below.
505    */
506   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
507
508   /**
509    * Identity of this neighbour.
510    */
511   struct GNUNET_PeerIdentity id;
512
513   /**
514    * ID of task scheduled to run when this peer is about to
515    * time out (will free resources associated with the peer).
516    */
517   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
518
519   /**
520    * ID of task scheduled to run when we should retry transmitting
521    * the head of the message queue.  Actually triggered when the
522    * transmission is timing out (we trigger instantly when we have
523    * a chance of success).
524    */
525   GNUNET_SCHEDULER_TaskIdentifier retry_task;
526
527   /**
528    * How long until we should consider this peer dead
529    * (if we don't receive another message in the
530    * meantime)?
531    */
532   struct GNUNET_TIME_Absolute peer_timeout;
533
534   /**
535    * Tracker for inbound bandwidth.
536    */
537   struct GNUNET_BANDWIDTH_Tracker in_tracker;
538
539   /**
540    * The latency we have seen for this particular address for
541    * this particular peer.  This latency may have been calculated
542    * over multiple transports.  This value reflects how long it took
543    * us to receive a response when SENDING via this particular
544    * transport/neighbour/address combination!
545    *
546    * FIXME: we need to periodically send PINGs to update this
547    * latency (at least more often than the current "huge" (11h?)
548    * update interval).
549    */
550   struct GNUNET_TIME_Relative latency;
551
552   /**
553    * How often has the other peer (recently) violated the
554    * inbound traffic limit?  Incremented by 10 per violation,
555    * decremented by 1 per non-violation (for each
556    * time interval).
557    */
558   unsigned int quota_violation_count;
559
560   /**
561    * DV distance to this peer (1 if no DV is used).
562    */
563   uint32_t distance;
564
565   /**
566    * Have we seen an PONG from this neighbour in the past (and
567    * not had a disconnect since)?
568    */
569   int received_pong;
570
571   /**
572    * Do we have a valid public key for this neighbour?
573    */
574   int public_key_valid;
575
576   /**
577    * Performance data for the peer.
578    */
579   struct GNUNET_TRANSPORT_ATS_Information *ats;
580
581   /**
582    * Identity of the neighbour.
583    */
584   struct GNUNET_PeerIdentity peer;
585
586 };
587
588 /**
589  * Message used to ask a peer to validate receipt (to check an address
590  * from a HELLO).  Followed by the address we are trying to validate,
591  * or an empty address if we are just sending a PING to confirm that a
592  * connection which the receiver (of the PING) initiated is still valid.
593  */
594 struct TransportPingMessage
595 {
596
597   /**
598    * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
599    */
600   struct GNUNET_MessageHeader header;
601
602   /**
603    * Challenge code (to ensure fresh reply).
604    */
605   uint32_t challenge GNUNET_PACKED;
606
607   /**
608    * Who is the intended recipient?
609    */
610   struct GNUNET_PeerIdentity target;
611
612 };
613
614
615 /**
616  * Message used to validate a HELLO.  The challenge is included in the
617  * confirmation to make matching of replies to requests possible.  The
618  * signature signs our public key, an expiration time and our address.<p>
619  *
620  * This message is followed by our transport address that the PING tried
621  * to confirm (if we liked it).  The address can be empty (zero bytes)
622  * if the PING had not address either (and we received the request via
623  * a connection that we initiated).
624  */
625 struct TransportPongMessage
626 {
627
628   /**
629    * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
630    */
631   struct GNUNET_MessageHeader header;
632
633   /**
634    * Challenge code from PING (showing freshness).  Not part of what
635    * is signed so that we can re-use signatures.
636    */
637   uint32_t challenge GNUNET_PACKED;
638
639   /**
640    * Signature.
641    */
642   struct GNUNET_CRYPTO_RsaSignature signature;
643
644   /**
645    * What are we signing and why?  Two possible reason codes can be here:
646    * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN to confirm that this is a
647    * plausible address for this peer (pid is set to identity of signer); or
648    * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING to confirm that this is
649    * an address we used to connect to the peer with the given pid.
650    */
651   struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
652
653   /**
654    * When does this signature expire?
655    */
656   struct GNUNET_TIME_AbsoluteNBO expiration;
657
658   /**
659    * Either the identity of the peer Who signed this message, or the
660    * identity of the peer that we're connected to using the given
661    * address (depending on purpose.type).
662    */
663   struct GNUNET_PeerIdentity pid;
664
665   /**
666    * Size of address appended to this message (part of what is
667    * being signed, hence not redundant).
668    */
669   uint32_t addrlen;
670
671 };
672
673
674 /**
675  * Linked list of messages to be transmitted to the client.  Each
676  * entry is followed by the actual message.
677  */
678 struct ClientMessageQueueEntry
679 {
680   /**
681    * This is a doubly-linked list.
682    */
683   struct ClientMessageQueueEntry *next;
684
685   /**
686    * This is a doubly-linked list.
687    */
688   struct ClientMessageQueueEntry *prev;
689 };
690
691
692 /**
693  * Client connected to the transport service.
694  */
695 struct TransportClient
696 {
697
698   /**
699    * This is a linked list.
700    */
701   struct TransportClient *next;
702
703   /**
704    * Handle to the client.
705    */
706   struct GNUNET_SERVER_Client *client;
707
708   /**
709    * Linked list of messages yet to be transmitted to
710    * the client.
711    */
712   struct ClientMessageQueueEntry *message_queue_head;
713
714   /**
715    * Tail of linked list of messages yet to be transmitted to the
716    * client.
717    */
718   struct ClientMessageQueueEntry *message_queue_tail;
719
720   /**
721    * Current transmit request handle.
722    */
723   struct GNUNET_CONNECTION_TransmitHandle *th;
724
725   /**
726    * Is a call to "transmit_send_continuation" pending?  If so, we
727    * must not free this struct (even if the corresponding client
728    * disconnects) and instead only remove it from the linked list and
729    * set the "client" field to NULL.
730    */
731   int tcs_pending;
732
733   /**
734    * Length of the list of messages pending for this client.
735    */
736   unsigned int message_count;
737
738 };
739
740
741 /**
742  * Context of currently active requests to peerinfo
743  * for validation of HELLOs.
744  */
745 struct CheckHelloValidatedContext;
746
747
748 /**
749  * Entry in map of all HELLOs awaiting validation.
750  */
751 struct ValidationEntry 
752 {
753
754   /**
755    * NULL if this entry is not part of a larger HELLO validation.
756    */
757   struct CheckHelloValidatedContext *chvc;
758
759   /**
760    * The address, actually a pointer to the end
761    * of this struct.  Do not free!
762    */
763   const void *addr;
764
765   /**
766    * Name of the transport.
767    */
768   char *transport_name;
769
770   /**
771    * The public key of the peer.
772    */
773   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
774
775   /**
776    * ID of task that will clean up this entry if we don't succeed
777    * with the validation first.
778    */
779   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
780
781   /**
782    * At what time did we send this validation?
783    */
784   struct GNUNET_TIME_Absolute send_time;
785
786   /**
787    * Session being validated (or NULL for none).
788    */
789   struct Session *session;
790
791   /**
792    * Challenge number we used.
793    */
794   uint32_t challenge;
795
796   /**
797    * Length of addr.
798    */
799   uint16_t addrlen;
800
801 };
802
803
804 /**
805  * Context of currently active requests to peerinfo
806  * for validation of HELLOs.
807  */
808 struct CheckHelloValidatedContext
809 {
810
811   /**
812    * This is a doubly-linked list.
813    */
814   struct CheckHelloValidatedContext *next;
815
816   /**
817    * This is a doubly-linked list.
818    */
819   struct CheckHelloValidatedContext *prev;
820
821   /**
822    * Hello that we are validating.
823    */
824   const struct GNUNET_HELLO_Message *hello;
825
826   /**
827    * Context for peerinfo iteration.
828    * NULL after we are done processing peerinfo's information.
829    */
830   struct GNUNET_PEERINFO_IteratorContext *piter;
831
832   /**
833    * Was a HELLO known for this peer to peerinfo?
834    */
835   int hello_known;
836
837   /**
838    * Number of validation entries currently referring to this
839    * CHVC.
840    */
841   unsigned int ve_count;
842 };
843
844
845 /**
846  * Our HELLO message.
847  */
848 static struct GNUNET_HELLO_Message *our_hello;
849
850 /**
851  * Our public key.
852  */
853 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
854
855 /**
856  * Our identity.
857  */
858 static struct GNUNET_PeerIdentity my_identity;
859
860 /**
861  * Our private key.
862  */
863 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
864
865 /**
866  * Our configuration.
867  */
868 const struct GNUNET_CONFIGURATION_Handle *cfg;
869
870 /**
871  * Linked list of all clients to this service.
872  */
873 static struct TransportClient *clients;
874
875 /**
876  * All loaded plugins.
877  */
878 static struct TransportPlugin *plugins;
879
880 /**
881  * Handle to peerinfo service.
882  */
883 static struct GNUNET_PEERINFO_Handle *peerinfo;
884
885 /**
886  * All known neighbours and their HELLOs.
887  */
888 static struct NeighbourList *neighbours;
889
890 /**
891  * Number of neighbours we'd like to have.
892  */
893 static uint32_t max_connect_per_transport;
894
895 /**
896  * Head of linked list.
897  */
898 static struct CheckHelloValidatedContext *chvc_head;
899
900 /**
901  * Tail of linked list.
902  */
903 static struct CheckHelloValidatedContext *chvc_tail;
904
905 /**
906  * Map of PeerIdentities to 'struct ValidationEntry*'s (addresses
907  * of the given peer that we are currently validating).
908  */
909 static struct GNUNET_CONTAINER_MultiHashMap *validation_map;
910
911 /**
912  * Handle for reporting statistics.
913  */
914 static struct GNUNET_STATISTICS_Handle *stats;
915
916 /**
917  * Identifier of 'refresh_hello' task.
918  */
919 static GNUNET_SCHEDULER_TaskIdentifier hello_task;
920
921 /**
922  * Identifier of ats scheduler task.
923  */
924 static GNUNET_SCHEDULER_TaskIdentifier ats_task;
925
926 /**
927  * Is transport service shutting down ?
928  */
929 static int shutdown_in_progress;
930
931 /**
932  * Handle for ats information
933  */
934 static struct ATS_Handle *ats;
935
936 /**
937  * Time of last ats execution
938  */
939 struct GNUNET_TIME_Absolute last_ats_execution;
940 /**
941  * Minimum interval between two ATS executions
942  */
943 struct GNUNET_TIME_Relative ats_minimum_interval;
944 /**
945  * Regular interval when ATS execution is triggered
946  */
947 struct GNUNET_TIME_Relative ats_regular_interval;
948
949 /**
950  * The peer specified by the given neighbour has timed-out or a plugin
951  * has disconnected.  We may either need to do nothing (other plugins
952  * still up), or trigger a full disconnect and clean up.  This
953  * function updates our state and do the necessary notifications.
954  * Also notifies our clients that the neighbour is now officially
955  * gone.
956  *
957  * @param n the neighbour list entry for the peer
958  * @param check should we just check if all plugins
959  *        disconnected or must we ask all plugins to
960  *        disconnect?
961  */
962 static void disconnect_neighbour (struct NeighbourList *n, int check);
963
964 /**
965  * Check the ready list for the given neighbour and if a plugin is
966  * ready for transmission (and if we have a message), do so!
967  *
968  * @param nexi target peer for which to transmit
969  */
970 static void try_transmission_to_peer (struct NeighbourList *n);
971
972 struct ForeignAddressList * get_preferred_ats_address (
973                 struct NeighbourList *n);
974
975 /**
976  * Find an entry in the neighbour list for a particular peer.
977  *
978  * @return NULL if not found.
979  */
980 static struct NeighbourList *
981 find_neighbour (const struct GNUNET_PeerIdentity *key)
982 {
983   struct NeighbourList *head = neighbours;
984
985   while ((head != NULL) &&
986         (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
987     head = head->next;
988   return head;
989 }
990
991 static int update_addr_value (struct ForeignAddressList *fal, uint32_t value , int ats_index)
992 {
993   int c;
994   int set = GNUNET_NO;
995   for (c=0; c<available_quality_metrics; c++)
996   {
997     if (ats_index == qm[c].atis_index)
998     {
999       fal->quality[c].values[0] = fal->quality[c].values[1];
1000       fal->quality[c].values[1] = fal->quality[c].values[2];
1001       fal->quality[c].values[2] = value;
1002       set = GNUNET_YES;
1003       ats_modify_problem_state (ats, ATS_QUALITY_UPDATED);
1004     }
1005   }
1006   if (set == GNUNET_NO)
1007   {
1008     for (c=0; c<available_ressources; c++)
1009     {
1010       if (ats_index == ressources[c].atis_index)
1011       {
1012         fal->ressources[c].c = value;
1013         set = GNUNET_YES;
1014         ats_modify_problem_state (ats, ATS_COST_UPDATED);
1015       }
1016     }
1017   }
1018   return set;
1019 }
1020
1021 static int
1022 update_addr_ats (struct ForeignAddressList *fal, 
1023                  const struct GNUNET_TRANSPORT_ATS_Information *ats_data, 
1024                  int ats_count)
1025 {
1026   int c1, set;
1027   set = GNUNET_NO;
1028   for (c1=0; c1<ats_count; c1++)
1029     {
1030       set = update_addr_value(fal, ntohl(ats_data[c1].value), ntohl(ats_data[c1].type));
1031     }
1032   return set;
1033 }
1034
1035 /**
1036  * Find an entry in the transport list for a particular transport.
1037  *
1038  * @return NULL if not found.
1039  */
1040 static struct TransportPlugin *
1041 find_transport (const char *short_name)
1042 {
1043   struct TransportPlugin *head = plugins;
1044   while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
1045     head = head->next;
1046   return head;
1047 }
1048
1049 /**
1050  * Is a particular peer blacklisted for a particular transport?
1051  *
1052  * @param peer the peer to check for
1053  * @param plugin the plugin used to connect to the peer
1054  *
1055  * @return GNUNET_YES if the peer is blacklisted, GNUNET_NO if not
1056  */
1057 static int
1058 is_blacklisted (const struct GNUNET_PeerIdentity *peer, struct TransportPlugin *plugin)
1059 {
1060
1061   if (plugin->blacklist != NULL)
1062     {
1063       if (GNUNET_CONTAINER_multihashmap_contains (plugin->blacklist, &peer->hashPubKey) == GNUNET_YES)
1064         {
1065 #if DEBUG_BLACKLIST
1066           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1067                       "Peer `%s:%s' is blacklisted!\n",
1068                       plugin->short_name, GNUNET_i2s (peer));
1069 #endif
1070           if (stats != NULL)
1071             GNUNET_STATISTICS_update (stats, "# blacklisted peers refused", 1, GNUNET_NO);
1072           return GNUNET_YES;
1073         }
1074     }
1075
1076   return GNUNET_NO;
1077 }
1078
1079
1080 static void
1081 add_peer_to_blacklist (struct GNUNET_PeerIdentity *peer, 
1082                        char *transport_name)
1083 {
1084   struct TransportPlugin *plugin;
1085
1086   plugin = find_transport(transport_name);
1087   if (plugin == NULL) /* Nothing to do */
1088     return;
1089 #if DEBUG_TRANSPORT
1090   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1091               "Adding peer `%s' with plugin `%s' to blacklist\n",
1092               GNUNET_i2s (peer),
1093               transport_name);
1094 #endif
1095   if (plugin->blacklist == NULL)
1096     plugin->blacklist = GNUNET_CONTAINER_multihashmap_create(TRANSPORT_BLACKLIST_HT_SIZE);
1097   GNUNET_assert(plugin->blacklist != NULL);
1098   GNUNET_CONTAINER_multihashmap_put(plugin->blacklist, &peer->hashPubKey,
1099                                     NULL,
1100                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1101 }
1102
1103
1104 /**
1105  * Read the blacklist file, containing transport:peer entries.
1106  * Provided the transport is loaded, set up hashmap with these
1107  * entries to blacklist peers by transport.
1108  *
1109  */
1110 static void
1111 read_blacklist_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
1112 {
1113   char *fn;
1114   char *data;
1115   size_t pos;
1116   size_t colon_pos;
1117   int tsize;
1118   struct GNUNET_PeerIdentity pid;
1119   struct stat frstat;
1120   struct GNUNET_CRYPTO_HashAsciiEncoded enc;
1121   unsigned int entries_found;
1122   char *transport_name;
1123
1124   if (GNUNET_OK !=
1125       GNUNET_CONFIGURATION_get_value_filename (cfg,
1126                                                "TRANSPORT",
1127                                                "BLACKLIST_FILE",
1128                                                &fn))
1129     {
1130 #if DEBUG_TRANSPORT
1131       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1132                   "Option `%s' in section `%s' not specified!\n",
1133                   "BLACKLIST_FILE",
1134                   "TRANSPORT");
1135 #endif
1136       return;
1137     }
1138   if (GNUNET_OK != GNUNET_DISK_file_test (fn))
1139     GNUNET_DISK_fn_write (fn, NULL, 0, GNUNET_DISK_PERM_USER_READ
1140         | GNUNET_DISK_PERM_USER_WRITE);
1141   if (0 != STAT (fn, &frstat))
1142     {
1143       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1144                   _("Could not read blacklist file `%s'\n"), fn);
1145       GNUNET_free (fn);
1146       return;
1147     }
1148   if (frstat.st_size == 0)
1149     {
1150 #if DEBUG_TRANSPORT
1151       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1152                   _("Blacklist file `%s' is empty.\n"),
1153                   fn);
1154 #endif
1155       GNUNET_free (fn);
1156       return;
1157     }
1158   /* FIXME: use mmap */
1159   data = GNUNET_malloc_large (frstat.st_size);
1160   GNUNET_assert(data != NULL);
1161   if (frstat.st_size !=
1162       GNUNET_DISK_fn_read (fn, data, frstat.st_size))
1163     {
1164       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1165                   _("Failed to read blacklist from `%s'\n"), fn);
1166       GNUNET_free (fn);
1167       GNUNET_free (data);
1168       return;
1169     }
1170   entries_found = 0;
1171   pos = 0;
1172   while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1173     pos++;
1174   while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) &&
1175          (pos <= frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
1176     {
1177       colon_pos = pos;
1178       while ((colon_pos < frstat.st_size) && (data[colon_pos] != ':') && !isspace ( (unsigned char) data[colon_pos]))
1179         colon_pos++;
1180
1181       if (colon_pos >= frstat.st_size)
1182         {
1183           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1184                       _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1185                       (unsigned long long) colon_pos);
1186           GNUNET_free (fn);
1187           GNUNET_free (data);
1188           return;
1189         }
1190
1191       if (isspace( (unsigned char) data[colon_pos]))
1192       {
1193         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1194                     _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1195                     (unsigned long long) colon_pos);
1196         pos = colon_pos;
1197         while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1198           pos++;
1199         continue;
1200       }
1201       tsize = colon_pos - pos;
1202       if ((pos >= frstat.st_size) || (pos + tsize >= frstat.st_size) || (tsize == 0))
1203         {
1204           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1205                       _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1206                       (unsigned long long) colon_pos);
1207           GNUNET_free (fn);
1208           GNUNET_free (data);
1209           return;
1210         }
1211
1212       if (tsize < 1)
1213         continue;
1214
1215       transport_name = GNUNET_malloc(tsize + 1);
1216       memcpy(transport_name, &data[pos], tsize);
1217       pos = colon_pos + 1;
1218 #if DEBUG_TRANSPORT
1219       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1220                   "Read transport name %s in blacklist file.\n",
1221                   transport_name);
1222 #endif
1223       memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
1224       if (!isspace ( (unsigned char) enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
1225         {
1226           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1227                       _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1228                       (unsigned long long) pos);
1229           pos++;
1230           while ((pos < frstat.st_size) && (!isspace ( (unsigned char) data[pos])))
1231             pos++;
1232           GNUNET_free_non_null(transport_name);
1233           continue;
1234         }
1235       enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
1236       if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &pid.hashPubKey))
1237         {
1238           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1239                       _("Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n"),
1240                       (unsigned long long) pos,
1241                       &enc);
1242         }
1243       else
1244         {
1245           if (0 != memcmp (&pid,
1246                            &my_identity,
1247                            sizeof (struct GNUNET_PeerIdentity)))
1248             {
1249               entries_found++;
1250               add_peer_to_blacklist (&pid,
1251                                      transport_name);
1252             }
1253           else
1254             {
1255               GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1256                           _("Found myself `%s' in blacklist (useless, ignored)\n"),
1257                           GNUNET_i2s (&pid));
1258             }
1259         }
1260       pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
1261       GNUNET_free_non_null(transport_name);
1262       while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1263         pos++;
1264     }
1265   GNUNET_STATISTICS_update (stats, "# Transport entries blacklisted", entries_found, GNUNET_NO);
1266   GNUNET_free (data);
1267   GNUNET_free (fn);
1268 }
1269
1270
1271 /**
1272  * Function called to notify a client about the socket being ready to
1273  * queue more data.  "buf" will be NULL and "size" zero if the socket
1274  * was closed for writing in the meantime.
1275  *
1276  * @param cls closure
1277  * @param size number of bytes available in buf
1278  * @param buf where the callee should write the message
1279  * @return number of bytes written to buf
1280  */
1281 static size_t
1282 transmit_to_client_callback (void *cls, size_t size, void *buf)
1283 {
1284   struct TransportClient *client = cls;
1285   struct ClientMessageQueueEntry *q;
1286   uint16_t msize;
1287   size_t tsize;
1288   const struct GNUNET_MessageHeader *msg;
1289   char *cbuf;
1290
1291   client->th = NULL;
1292   if (buf == NULL)
1293     {
1294 #if DEBUG_TRANSPORT 
1295       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1296                   "Transmission to client failed, closing connection.\n");
1297 #endif
1298       /* fatal error with client, free message queue! */
1299       while (NULL != (q = client->message_queue_head))
1300         {
1301           GNUNET_STATISTICS_update (stats,
1302                                     gettext_noop ("# bytes discarded (could not transmit to client)"),
1303                                     ntohs (((const struct GNUNET_MessageHeader*)&q[1])->size),
1304                                     GNUNET_NO);
1305           GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1306                                        client->message_queue_tail,
1307                                        q);
1308           GNUNET_free (q);
1309         }
1310       client->message_count = 0;
1311       return 0;
1312     }
1313   cbuf = buf;
1314   tsize = 0;
1315   while (NULL != (q = client->message_queue_head))
1316     {
1317       msg = (const struct GNUNET_MessageHeader *) &q[1];
1318       msize = ntohs (msg->size);
1319       if (msize + tsize > size)
1320         break;
1321 #if DEBUG_TRANSPORT
1322       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1323                   "Transmitting message of type %u to client.\n",
1324                   ntohs (msg->type));
1325 #endif
1326       GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1327                                    client->message_queue_tail,
1328                                    q);
1329       memcpy (&cbuf[tsize], msg, msize);
1330       tsize += msize;
1331       GNUNET_free (q);
1332       client->message_count--;
1333     }
1334   if (NULL != q)
1335     {
1336       GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1337       client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1338                                                         msize,
1339                                                         GNUNET_TIME_UNIT_FOREVER_REL,
1340                                                         &transmit_to_client_callback,
1341                                                         client);
1342       GNUNET_assert (client->th != NULL);
1343     }
1344   return tsize;
1345 }
1346
1347
1348 /**
1349  * Convert an address to a string.
1350  *
1351  * @param plugin name of the plugin responsible for the address
1352  * @param addr binary address
1353  * @param addr_len number of bytes in addr
1354  * @return NULL on error, otherwise address string
1355  */
1356 static const char*
1357 a2s (const char *plugin,
1358      const void *addr,
1359      uint16_t addr_len)
1360 {
1361   struct TransportPlugin *p;
1362
1363   if (plugin == NULL)
1364     return NULL;
1365   p = find_transport (plugin);
1366   if ((p == NULL) || (addr_len == 0) || (addr == NULL))
1367     return NULL;
1368
1369   return p->api->address_to_string (NULL,
1370                                     addr,
1371                                     addr_len);
1372   return NULL;
1373 }
1374
1375
1376
1377
1378 /**
1379  * Iterator to free entries in the validation_map.
1380  *
1381  * @param cls closure (unused)
1382  * @param key current key code
1383  * @param value value in the hash map (validation to abort)
1384  * @return GNUNET_YES (always)
1385  */
1386 static int
1387 abort_validation (void *cls,
1388                   const GNUNET_HashCode * key,
1389                   void *value)
1390 {
1391   struct ValidationEntry *va = value;
1392
1393   if (GNUNET_SCHEDULER_NO_TASK != va->timeout_task)
1394     GNUNET_SCHEDULER_cancel (va->timeout_task);
1395   GNUNET_free (va->transport_name);
1396   if (va->chvc != NULL)
1397     {
1398       va->chvc->ve_count--;
1399       if (va->chvc->ve_count == 0)
1400         {
1401           GNUNET_CONTAINER_DLL_remove (chvc_head,
1402                                        chvc_tail,
1403                                        va->chvc);
1404           GNUNET_free (va->chvc);
1405         }
1406       va->chvc = NULL;
1407     }
1408   GNUNET_free (va);
1409   return GNUNET_YES;
1410 }
1411
1412
1413 /**
1414  * HELLO validation cleanup task (validation failed).
1415  *
1416  * @param cls the 'struct ValidationEntry' that failed
1417  * @param tc scheduler context (unused)
1418  */
1419 static void
1420 timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1421 {
1422   struct ValidationEntry *va = cls;
1423   struct GNUNET_PeerIdentity pid;
1424
1425   va->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1426   GNUNET_STATISTICS_update (stats,
1427                             gettext_noop ("# address validation timeouts"),
1428                             1,
1429                             GNUNET_NO);
1430   GNUNET_CRYPTO_hash (&va->publicKey,
1431                       sizeof (struct
1432                               GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1433                       &pid.hashPubKey);
1434   GNUNET_break (GNUNET_OK ==
1435                 GNUNET_CONTAINER_multihashmap_remove (validation_map,
1436                                                       &pid.hashPubKey,
1437                                                       va));
1438   abort_validation (NULL, NULL, va);
1439 }
1440
1441
1442
1443 /**
1444  * Send the specified message to the specified client.  Since multiple
1445  * messages may be pending for the same client at a time, this code
1446  * makes sure that no message is lost.
1447  *
1448  * @param client client to transmit the message to
1449  * @param msg the message to send
1450  * @param may_drop can this message be dropped if the
1451  *        message queue for this client is getting far too large?
1452  */
1453 static void
1454 transmit_to_client (struct TransportClient *client,
1455                     const struct GNUNET_MessageHeader *msg, int may_drop)
1456 {
1457   struct ClientMessageQueueEntry *q;
1458   uint16_t msize;
1459
1460   if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
1461     {
1462       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1463                   _
1464                   ("Dropping message of type %u and size %u, have %u messages pending (%u is the soft limit)\n"),
1465                   ntohs (msg->type),
1466                   ntohs (msg->size),
1467                   client->message_count,
1468                   MAX_PENDING);
1469       GNUNET_STATISTICS_update (stats,
1470                                 gettext_noop ("# messages dropped due to slow client"),
1471                                 1,
1472                                 GNUNET_NO);
1473       return;
1474     }
1475   msize = ntohs (msg->size);
1476   GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1477   q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
1478   memcpy (&q[1], msg, msize);
1479   GNUNET_CONTAINER_DLL_insert_after (client->message_queue_head,
1480                                      client->message_queue_tail,
1481                                      client->message_queue_tail,
1482                                      q);
1483   client->message_count++;
1484   if (client->th == NULL)
1485     {
1486       client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1487                                                         msize,
1488                                                         GNUNET_TIME_UNIT_FOREVER_REL,
1489                                                         &transmit_to_client_callback,
1490                                                         client);
1491       GNUNET_assert (client->th != NULL);
1492     }
1493 }
1494
1495
1496 /**
1497  * Transmit a 'SEND_OK' notification to the given client for the
1498  * given neighbour.
1499  *
1500  * @param client who to notify
1501  * @param n neighbour to notify about, can be NULL (on failure)
1502  * @param target target of the transmission
1503  * @param result status code for the transmission request
1504  */
1505 static void
1506 transmit_send_ok (struct TransportClient *client,
1507                   struct NeighbourList *n,
1508                   const struct GNUNET_PeerIdentity *target,
1509                   int result)
1510 {
1511   struct SendOkMessage send_ok_msg;
1512
1513   send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1514   send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1515   send_ok_msg.success = htonl (result);
1516   if (n != NULL)
1517     send_ok_msg.latency = GNUNET_TIME_relative_hton (n->latency);
1518   else
1519     send_ok_msg.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_FOREVER_REL);
1520   send_ok_msg.peer = *target;
1521   transmit_to_client (client, &send_ok_msg.header, GNUNET_NO);
1522 }
1523
1524
1525 /**
1526  * Mark the given FAL entry as 'connected' (and hence preferred for
1527  * sending); also mark all others for the same peer as 'not connected'
1528  * (since only one can be preferred).
1529  *
1530  * @param fal address to set to 'connected'
1531  */
1532 static void
1533 mark_address_connected (struct ForeignAddressList *fal);
1534
1535
1536
1537 /**
1538  * We should re-try transmitting to the given peer,
1539  * hopefully we've learned something in the meantime.
1540  */
1541 static void
1542 retry_transmission_task (void *cls,
1543                          const struct GNUNET_SCHEDULER_TaskContext *tc)
1544 {
1545   struct NeighbourList *n = cls;
1546
1547   n->retry_task = GNUNET_SCHEDULER_NO_TASK;
1548   try_transmission_to_peer (n);
1549 }
1550
1551
1552 /**
1553  * Function called by the GNUNET_TRANSPORT_TransmitFunction
1554  * upon "completion" of a send request.  This tells the API
1555  * that it is now legal to send another message to the given
1556  * peer.
1557  *
1558  * @param cls closure, identifies the entry on the
1559  *            message queue that was transmitted and the
1560  *            client responsible for queuing the message
1561  * @param target the peer receiving the message
1562  * @param result GNUNET_OK on success, if the transmission
1563  *           failed, we should not tell the client to transmit
1564  *           more messages
1565  */
1566 static void
1567 transmit_send_continuation (void *cls,
1568                             const struct GNUNET_PeerIdentity *target,
1569                             int result)
1570 {
1571   struct MessageQueue *mq = cls;
1572   struct NeighbourList *n;
1573
1574   GNUNET_STATISTICS_update (stats,
1575                             gettext_noop ("# bytes pending with plugins"),
1576                             - (int64_t) mq->message_buf_size,
1577                             GNUNET_NO);
1578   if (result == GNUNET_OK)
1579     {
1580       GNUNET_STATISTICS_update (stats,
1581                                 gettext_noop ("# bytes successfully transmitted by plugins"),
1582                                 mq->message_buf_size,
1583                                 GNUNET_NO);
1584     }
1585   else
1586     {
1587       GNUNET_STATISTICS_update (stats,
1588                                 gettext_noop ("# bytes with transmission failure by plugins"),
1589                                 mq->message_buf_size,
1590                                 GNUNET_NO);
1591     }
1592   if (mq->specific_address != NULL)
1593     {
1594       if (result == GNUNET_OK)
1595         {
1596           mq->specific_address->timeout =
1597             GNUNET_TIME_relative_to_absolute
1598             (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1599           if (mq->specific_address->validated == GNUNET_YES)
1600             mark_address_connected (mq->specific_address);
1601         }
1602       else
1603         {
1604           if (mq->specific_address->connected != GNUNET_NO)
1605             {
1606 #if DEBUG_TRANSPORT
1607               GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1608                           "Marking address `%s' as no longer connected (due to transmission problem)\n",
1609                           a2s (mq->specific_address->ready_list->plugin->short_name,
1610                                mq->specific_address->addr,
1611                                mq->specific_address->addrlen));
1612 #endif
1613               GNUNET_STATISTICS_update (stats,
1614                                         gettext_noop ("# connected addresses"),
1615                                         -1,
1616                                         GNUNET_NO);
1617               mq->specific_address->connected = GNUNET_NO;
1618             }
1619         }
1620       if (! mq->internal_msg)
1621         mq->specific_address->in_transmit = GNUNET_NO;
1622     }
1623   n = find_neighbour (&mq->neighbour_id);
1624   if (mq->client != NULL)
1625     transmit_send_ok (mq->client, n, target, result);
1626   if (n != NULL)
1627     {
1628       GNUNET_CONTAINER_DLL_remove (n->cont_head,
1629                                    n->cont_tail,
1630                                    mq);
1631     }
1632   GNUNET_free (mq);
1633   if (n != NULL) 
1634     {
1635       if (result == GNUNET_OK) 
1636         try_transmission_to_peer (n);
1637       else if (GNUNET_SCHEDULER_NO_TASK == n->retry_task)
1638         n->retry_task = GNUNET_SCHEDULER_add_now (&retry_transmission_task,
1639                                                   n);
1640     }   
1641 }
1642
1643
1644 /**
1645  * Check the ready list for the given neighbour and if a plugin is
1646  * ready for transmission (and if we have a message), do so!
1647  *
1648  * @param neighbour target peer for which to transmit
1649  */
1650 static void
1651 try_transmission_to_peer (struct NeighbourList *n)
1652 {
1653   struct ReadyList *rl;
1654   struct MessageQueue *mq;
1655   struct GNUNET_TIME_Relative timeout;
1656   ssize_t ret;
1657   int force_address;
1658
1659   if (n->messages_head == NULL)
1660     {
1661 #if DEBUG_TRANSPORT
1662       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1663                   "Transmission queue for `%4s' is empty\n",
1664                   GNUNET_i2s (&n->id));
1665 #endif
1666       return;                     /* nothing to do */
1667     }
1668   rl = NULL;
1669   mq = n->messages_head;
1670   force_address = GNUNET_YES;
1671   if (mq->specific_address == NULL)
1672     {
1673       /* TODO: ADD ATS */
1674       mq->specific_address = get_preferred_ats_address(n);
1675       GNUNET_STATISTICS_update (stats,
1676                                 gettext_noop ("# transport selected peer address freely"),
1677                                 1,
1678                                 GNUNET_NO);
1679       force_address = GNUNET_NO;
1680     }
1681   if (mq->specific_address == NULL)
1682     {
1683       GNUNET_STATISTICS_update (stats,
1684                                 gettext_noop ("# transport failed to selected peer address"),
1685                                 1,
1686                                 GNUNET_NO);
1687       timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
1688       if (timeout.rel_value == 0)
1689         {
1690 #if DEBUG_TRANSPORT
1691           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1692                       "No destination address available to transmit message of size %u to peer `%4s'\n",
1693                       mq->message_buf_size,
1694                       GNUNET_i2s (&mq->neighbour_id));
1695 #endif
1696           GNUNET_STATISTICS_update (stats,
1697                                     gettext_noop ("# bytes in message queue for other peers"),
1698                                     - (int64_t) mq->message_buf_size,
1699                                     GNUNET_NO);
1700           GNUNET_STATISTICS_update (stats,
1701                                     gettext_noop ("# bytes discarded (no destination address available)"),
1702                                     mq->message_buf_size,
1703                                     GNUNET_NO);
1704           if (mq->client != NULL)
1705             transmit_send_ok (mq->client, n, &n->id, GNUNET_NO);
1706           GNUNET_CONTAINER_DLL_remove (n->messages_head,
1707                                        n->messages_tail,
1708                                        mq);
1709           GNUNET_free (mq);
1710           return;               /* nobody ready */
1711         }
1712       GNUNET_STATISTICS_update (stats,
1713                                 gettext_noop ("# message delivery deferred (no address)"),
1714                                 1,
1715                                 GNUNET_NO);
1716       if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
1717         GNUNET_SCHEDULER_cancel (n->retry_task);
1718       n->retry_task = GNUNET_SCHEDULER_add_delayed (timeout,
1719                                                     &retry_transmission_task,
1720                                                     n);
1721 #if DEBUG_TRANSPORT
1722       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1723                   "No validated destination address available to transmit message of size %u to peer `%4s', will wait %llums to find an address.\n",
1724                   mq->message_buf_size,
1725                   GNUNET_i2s (&mq->neighbour_id),
1726                   timeout.rel_value);
1727 #endif
1728       /* FIXME: might want to trigger peerinfo lookup here
1729          (unless that's already pending...) */
1730       return;
1731     }
1732   GNUNET_CONTAINER_DLL_remove (n->messages_head,
1733                                n->messages_tail,
1734                                mq);
1735   if (mq->specific_address->connected == GNUNET_NO)
1736     mq->specific_address->connect_attempts++;
1737   rl = mq->specific_address->ready_list;
1738   mq->plugin = rl->plugin;
1739   if (!mq->internal_msg)
1740     mq->specific_address->in_transmit = GNUNET_YES;
1741 #if DEBUG_TRANSPORT
1742   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1743               "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
1744               mq->message_buf_size,
1745               GNUNET_i2s (&n->id),
1746               (mq->specific_address->addr != NULL)
1747               ? a2s (mq->plugin->short_name,
1748                      mq->specific_address->addr,
1749                      mq->specific_address->addrlen)
1750               : "<inbound>",
1751               rl->plugin->short_name);
1752 #endif
1753   GNUNET_STATISTICS_update (stats,
1754                             gettext_noop ("# bytes in message queue for other peers"),
1755                             - (int64_t) mq->message_buf_size,
1756                             GNUNET_NO);
1757   GNUNET_STATISTICS_update (stats,
1758                             gettext_noop ("# bytes pending with plugins"),
1759                             mq->message_buf_size,
1760                             GNUNET_NO);
1761
1762   GNUNET_CONTAINER_DLL_insert (n->cont_head,
1763                                n->cont_tail,
1764                                mq);
1765
1766   ret = rl->plugin->api->send (rl->plugin->api->cls,
1767                                &mq->neighbour_id,
1768                                mq->message_buf,
1769                                mq->message_buf_size,
1770                                mq->priority,
1771                                GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1772                                mq->specific_address->session,
1773                                mq->specific_address->addr,
1774                                mq->specific_address->addrlen,
1775                                force_address,
1776                                &transmit_send_continuation, mq);
1777   if (ret == -1)
1778     {
1779       /* failure, but 'send' would not call continuation in this case,
1780          so we need to do it here! */
1781       transmit_send_continuation (mq,
1782                                   &mq->neighbour_id,
1783                                   GNUNET_SYSERR);
1784     }
1785 }
1786
1787
1788 /**
1789  * Send the specified message to the specified peer.
1790  *
1791  * @param client source of the transmission request (can be NULL)
1792  * @param peer_address ForeignAddressList where we should send this message
1793  * @param priority how important is the message
1794  * @param timeout how long do we have to transmit?
1795  * @param message_buf message(s) to send GNUNET_MessageHeader(s)
1796  * @param message_buf_size total size of all messages in message_buf
1797  * @param is_internal is this an internal message; these are pre-pended and
1798  *                    also do not count for plugins being "ready" to transmit
1799  * @param neighbour handle to the neighbour for transmission
1800  */
1801 static void
1802 transmit_to_peer (struct TransportClient *client,
1803                   struct ForeignAddressList *peer_address,
1804                   unsigned int priority,
1805                   struct GNUNET_TIME_Relative timeout,
1806                   const char *message_buf,
1807                   size_t message_buf_size,
1808                   int is_internal, struct NeighbourList *neighbour)
1809 {
1810   struct MessageQueue *mq;
1811
1812 #if EXTRA_CHECKS
1813   if (client != NULL)
1814     {
1815       /* check for duplicate submission */
1816       mq = neighbour->messages_head;
1817       while (NULL != mq)
1818         {
1819           if (mq->client == client)
1820             {
1821               /* client transmitted to same peer twice
1822                  before getting SEND_OK! */
1823               GNUNET_break (0);
1824               return;
1825             }
1826           mq = mq->next;
1827         }
1828     }
1829 #endif
1830   GNUNET_STATISTICS_update (stats,
1831                             gettext_noop ("# bytes in message queue for other peers"),
1832                             message_buf_size,
1833                             GNUNET_NO);
1834   mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
1835   mq->specific_address = peer_address;
1836   mq->client = client;
1837   /* FIXME: this memcpy can be up to 7% of our total runtime! */
1838   memcpy (&mq[1], message_buf, message_buf_size);
1839   mq->message_buf = (const char*) &mq[1];
1840   mq->message_buf_size = message_buf_size;
1841   memcpy(&mq->neighbour_id, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
1842   mq->internal_msg = is_internal;
1843   mq->priority = priority;
1844   mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1845   if (is_internal)
1846     GNUNET_CONTAINER_DLL_insert (neighbour->messages_head,
1847                                  neighbour->messages_tail,
1848                                  mq);
1849   else
1850     GNUNET_CONTAINER_DLL_insert_after (neighbour->messages_head,
1851                                        neighbour->messages_tail,
1852                                        neighbour->messages_tail,
1853                                        mq);
1854   try_transmission_to_peer (neighbour);
1855 }
1856
1857
1858 /**
1859  * Send a plain PING (without address or our HELLO) to the given
1860  * foreign address to try to establish a connection (and validate
1861  * that the other peer is really who he claimed he is).
1862  *
1863  * @param n neighbour to PING
1864  */
1865 static void
1866 transmit_plain_ping (struct NeighbourList *n)
1867 {
1868   struct ValidationEntry *ve;
1869   struct TransportPingMessage ping;
1870   struct ReadyList *rl;
1871   struct TransportPlugin *plugin;
1872   struct ForeignAddressList *fal;
1873
1874   if (! n->public_key_valid)
1875     {
1876       /* This should not happen since the other peer
1877          should send us a HELLO prior to sending his
1878          PING */
1879       GNUNET_break_op (0);
1880       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1881                   "Could not transmit plain PING to `%s': public key not known\n",
1882                   GNUNET_i2s (&n->id));
1883       return;
1884     }
1885   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1886               "Looking for addresses to transmit plain PING to `%s'\n",
1887               GNUNET_i2s (&n->id));
1888   for (rl = n->plugins; rl != NULL; rl = rl->next)
1889     {
1890       plugin = rl->plugin;
1891       for (fal = rl->addresses; fal != NULL; fal = fal->next)
1892         {
1893           if (! fal->connected)
1894             continue;      
1895           ve = GNUNET_malloc (sizeof (struct ValidationEntry));
1896           ve->transport_name = GNUNET_strdup (plugin->short_name);
1897           ve->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
1898                                                     UINT_MAX);
1899           ve->send_time = GNUNET_TIME_absolute_get();
1900           ve->session = fal->session;
1901           memcpy(&ve->publicKey,
1902                  &n->publicKey,
1903                  sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
1904           ve->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
1905                                                            &timeout_hello_validation,
1906                                                            ve);
1907           GNUNET_CONTAINER_multihashmap_put (validation_map,
1908                                              &n->id.hashPubKey,
1909                                              ve,
1910                                              GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1911           ping.header.size = htons(sizeof(struct TransportPingMessage));
1912           ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
1913           ping.challenge = htonl(ve->challenge);
1914           memcpy(&ping.target, &n->id, sizeof(struct GNUNET_PeerIdentity));
1915           GNUNET_STATISTICS_update (stats,
1916                                     gettext_noop ("# PING without HELLO messages sent"),
1917                                     1,
1918                                     GNUNET_NO);
1919           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1920                       "Transmitting plain PING to `%s'\n",
1921                       GNUNET_i2s (&n->id));
1922           transmit_to_peer (NULL, 
1923                             fal,
1924                             GNUNET_SCHEDULER_PRIORITY_DEFAULT,
1925                             HELLO_VERIFICATION_TIMEOUT,
1926                             (const char*) &ping, sizeof (ping),
1927                             GNUNET_YES, n);
1928         }
1929     }
1930 }
1931
1932
1933 /**
1934  * Mark the given FAL entry as 'connected' (and hence preferred for
1935  * sending); also mark all others for the same peer as 'not connected'
1936  * (since only one can be preferred).
1937  *
1938  * @param fal address to set to 'connected'
1939  */
1940 static void
1941 mark_address_connected (struct ForeignAddressList *fal)
1942 {
1943   struct ForeignAddressList *pos;
1944   int cnt;
1945
1946   GNUNET_assert (GNUNET_YES == fal->validated);
1947   if (fal->connected == GNUNET_YES)
1948     return; /* nothing to do */
1949   cnt = GNUNET_YES;
1950   pos = fal->ready_list->addresses;
1951   while (pos != NULL)
1952     {
1953       if (GNUNET_YES == pos->connected)
1954         {
1955 #if DEBUG_TRANSPORT
1956           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1957                       "Marking address `%s' as no longer connected (due to connect on other address)\n",
1958                       a2s (pos->ready_list->plugin->short_name,
1959                            pos->addr,
1960                            pos->addrlen));
1961 #endif
1962           GNUNET_break (cnt == GNUNET_YES);
1963           cnt = GNUNET_NO;
1964           pos->connected = GNUNET_NO;
1965           GNUNET_STATISTICS_update (stats,
1966                                     gettext_noop ("# connected addresses"),
1967                                     -1,
1968                                     GNUNET_NO);
1969         }
1970       pos = pos->next;
1971     }
1972   fal->connected = GNUNET_YES;
1973   if (GNUNET_YES == cnt)
1974     {
1975       GNUNET_STATISTICS_update (stats,
1976                                 gettext_noop ("# connected addresses"),
1977                                 1,
1978                                 GNUNET_NO);
1979     }
1980 }
1981
1982
1983 /**
1984  * Find an address in any of the available transports for
1985  * the given neighbour that would be good for message
1986  * transmission.  This is essentially the transport selection
1987  * routine.
1988  *
1989  * @param neighbour for whom to select an address
1990  * @return selected address, NULL if we have none
1991  */
1992 struct ForeignAddressList *
1993 find_ready_address(struct NeighbourList *neighbour)
1994 {
1995   struct ReadyList *head = neighbour->plugins;
1996   struct ForeignAddressList *addresses;
1997   struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1998   struct ForeignAddressList *best_address;
1999
2000   /* Hack to prefer unix domain sockets */
2001   struct ForeignAddressList *unix_address = NULL;
2002
2003   best_address = NULL;
2004   while (head != NULL)
2005     {
2006       addresses = head->addresses;
2007       while (addresses != NULL)
2008         {
2009           if ( (addresses->timeout.abs_value < now.abs_value) &&
2010                (addresses->connected == GNUNET_YES) )
2011             {
2012 #if DEBUG_TRANSPORT
2013               GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2014                           "Marking long-time inactive connection to `%4s' as down.\n",
2015                           GNUNET_i2s (&neighbour->id));
2016 #endif
2017               GNUNET_STATISTICS_update (stats,
2018                                         gettext_noop ("# connected addresses"),
2019                                         -1,
2020                                         GNUNET_NO);
2021               addresses->connected = GNUNET_NO;
2022             }
2023           addresses = addresses->next;
2024         }
2025
2026       addresses = head->addresses;
2027       while (addresses != NULL)
2028         {
2029 #if DEBUG_TRANSPORT
2030           if (addresses->addr != NULL)
2031             GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2032                         "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
2033                         a2s (head->plugin->short_name,
2034                              addresses->addr,
2035                              addresses->addrlen),
2036                         GNUNET_i2s (&neighbour->id),
2037                         addresses->connected,
2038                         addresses->in_transmit,
2039                         addresses->validated,
2040                         addresses->connect_attempts,
2041                         (unsigned long long) addresses->timeout.abs_value,
2042                         (unsigned int) addresses->distance);
2043 #endif
2044           if (0==strcmp(head->plugin->short_name,"unix"))
2045             {
2046               if ( (unix_address == NULL) || 
2047                    ( (unix_address != NULL) &&
2048                      (addresses->latency.rel_value < unix_address->latency.rel_value) ) )
2049                 unix_address = addresses;
2050             }
2051           if ( ( (best_address == NULL) ||
2052                  (addresses->connected == GNUNET_YES) ||
2053                  (best_address->connected == GNUNET_NO) ) &&
2054                (addresses->in_transmit == GNUNET_NO) &&
2055                ( (best_address == NULL) ||
2056                  (addresses->latency.rel_value < best_address->latency.rel_value)) )
2057             best_address = addresses;
2058           /* FIXME: also give lower-latency addresses that are not
2059              connected a chance some times... */
2060           addresses = addresses->next;
2061         }
2062       if (unix_address != NULL)
2063           break;
2064       head = head->next;
2065     }
2066   if (unix_address != NULL)
2067     {
2068       best_address = unix_address;
2069 #if DEBUG_TRANSPORT
2070       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, 
2071                   "Found UNIX address, forced this address\n");
2072 #endif
2073     }
2074   if (best_address != NULL)
2075     {
2076 #if DEBUG_TRANSPORT
2077       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2078                   "Best address found (`%s') has latency of %llu ms.\n",
2079                   (best_address->addrlen > 0)
2080                   ? a2s (best_address->ready_list->plugin->short_name,
2081                          best_address->addr,
2082                        best_address->addrlen)
2083                   : "<inbound>",
2084                   best_address->latency.rel_value);
2085 #endif
2086     }
2087   else
2088     {
2089       GNUNET_STATISTICS_update (stats,
2090                                 gettext_noop ("# transmission attempts failed (no address)"),
2091                                 1,
2092                                 GNUNET_NO);
2093     }
2094
2095   return best_address;
2096
2097 }
2098
2099
2100 /**
2101  * FIXME: document.
2102  */
2103 struct GeneratorContext
2104 {
2105   struct TransportPlugin *plug_pos;
2106   struct OwnAddressList *addr_pos;
2107   struct GNUNET_TIME_Absolute expiration;
2108 };
2109
2110
2111 /**
2112  * FIXME: document.
2113  */
2114 static size_t
2115 address_generator (void *cls, size_t max, void *buf)
2116 {
2117   struct GeneratorContext *gc = cls;
2118   size_t ret;
2119
2120   while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
2121     {
2122       gc->plug_pos = gc->plug_pos->next;
2123       gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
2124     }
2125   if (NULL == gc->plug_pos)
2126     {
2127
2128       return 0;
2129     }
2130   ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
2131                                   gc->expiration,
2132                                   &gc->addr_pos[1],
2133                                   gc->addr_pos->addrlen, buf, max);
2134   gc->addr_pos = gc->addr_pos->next;
2135   return ret;
2136 }
2137
2138
2139 /**
2140  * Construct our HELLO message from all of the addresses of
2141  * all of the transports.
2142  *
2143  * @param cls unused
2144  * @param tc scheduler context
2145  */
2146 static void
2147 refresh_hello_task (void *cls,
2148                     const struct GNUNET_SCHEDULER_TaskContext *tc)
2149 {
2150   struct GNUNET_HELLO_Message *hello;
2151   struct TransportClient *cpos;
2152   struct NeighbourList *npos;
2153   struct GeneratorContext gc;
2154
2155   hello_task = GNUNET_SCHEDULER_NO_TASK;
2156   gc.plug_pos = plugins;
2157   gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
2158   gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
2159   hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
2160 #if DEBUG_TRANSPORT
2161   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2162               "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
2163 #endif
2164   GNUNET_STATISTICS_update (stats,
2165                             gettext_noop ("# refreshed my HELLO"),
2166                             1,
2167                             GNUNET_NO);
2168   cpos = clients;
2169   while (cpos != NULL)
2170     {
2171       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2172                   "Transmitting my HELLO to client!\n");
2173       transmit_to_client (cpos,
2174                           (const struct GNUNET_MessageHeader *) hello,
2175                           GNUNET_NO);
2176       cpos = cpos->next;
2177     }
2178
2179   GNUNET_free_non_null (our_hello);
2180   our_hello = hello;
2181   GNUNET_PEERINFO_add_peer (peerinfo, our_hello);
2182   for (npos = neighbours; npos != NULL; npos = npos->next)
2183     {
2184       if (! npos->received_pong)
2185         continue;
2186 #if DEBUG_TRANSPORT
2187       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2188                   "Transmitting updated `%s' to neighbour `%4s'\n",
2189                   "HELLO", GNUNET_i2s (&npos->id));
2190 #endif
2191       GNUNET_STATISTICS_update (stats,
2192                                 gettext_noop ("# transmitted my HELLO to other peers"),
2193                                 1,
2194                                 GNUNET_NO);
2195       transmit_to_peer (NULL, NULL, 0,
2196                         HELLO_ADDRESS_EXPIRATION,
2197                         (const char *) our_hello,
2198                         GNUNET_HELLO_size(our_hello),
2199                         GNUNET_NO, npos);
2200     }
2201 }
2202
2203
2204 /**
2205  * Schedule task to refresh hello (unless such a
2206  * task exists already).
2207  */
2208 static void
2209 refresh_hello ()
2210 {
2211 #if DEBUG_TRANSPORT_HELLO
2212   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2213               "refresh_hello() called!\n");
2214 #endif
2215   if (hello_task != GNUNET_SCHEDULER_NO_TASK)
2216     return;
2217   hello_task
2218     = GNUNET_SCHEDULER_add_now (&refresh_hello_task,
2219                                 NULL);
2220 }
2221
2222
2223 /**
2224  * Iterator over hash map entries that NULLs the session of validation
2225  * entries that match the given session.
2226  *
2227  * @param cls closure (the 'struct Session*' to match against)
2228  * @param key current key code (peer ID, not used)
2229  * @param value value in the hash map ('struct ValidationEntry*')
2230  * @return GNUNET_YES (we should continue to iterate)
2231  */
2232 static int
2233 remove_session_validations (void *cls,
2234                             const GNUNET_HashCode * key,
2235                             void *value)
2236 {
2237   struct Session *session = cls;
2238   struct ValidationEntry *ve = value;
2239
2240   if (session == ve->session)
2241     ve->session = NULL;
2242   return GNUNET_YES;
2243 }
2244
2245
2246 /**
2247  * We've been disconnected from the other peer (for some
2248  * connection-oriented transport).  Either quickly
2249  * re-establish the connection or signal the disconnect
2250  * to the CORE.
2251  *
2252  * Only signal CORE level disconnect if ALL addresses
2253  * for the peer are exhausted.
2254  *
2255  * @param p overall plugin context
2256  * @param nl neighbour that was disconnected
2257  */
2258 static void
2259 try_fast_reconnect (struct TransportPlugin *p,
2260                     struct NeighbourList *nl)
2261 {
2262   /* FIXME-MW: fast reconnect / transport switching not implemented... */
2263   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2264               "try_fast_reconnect not implemented!\n");
2265   /* Note: the idea here is to hide problems with transports (or
2266      switching between plugins) from the core to eliminate the need to
2267      re-negotiate session keys and the like; OTOH, we should tell core
2268      quickly (much faster than timeout) `if a connection was lost and
2269      could not be re-established (i.e. other peer went down or is
2270      unable / refuses to communicate);
2271
2272      So we should consider:
2273      1) ideally: our own willingness / need to connect
2274      2) prior failures to connect to this peer (by plugin)
2275      3) ideally: reasons why other peer terminated (as far as knowable)
2276
2277      Most importantly, it must be POSSIBLE for another peer to terminate
2278      a connection for a while (without us instantly re-establishing it).
2279      Similarly, if another peer is gone we should quickly notify CORE.
2280      OTOH, if there was a minor glitch (i.e. crash of gnunet-service-transport
2281      on the other end), we should reconnect in such a way that BOTH CORE
2282      services never even notice.
2283      Furthermore, the same mechanism (or small variation) could be used
2284      to switch to a better-performing plugin (ATS).
2285
2286      Finally, this needs to be tested throughly... */
2287
2288   /*
2289    * GNUNET_NO in the call below makes transport disconnect the peer,
2290    * even if only a single address (out of say, six) went away.  This
2291    * function must be careful to ONLY disconnect if the peer is gone,
2292    * not just a specific address.
2293    *
2294    * More specifically, half the places it was used had it WRONG.
2295    */
2296
2297   /* No reconnect, signal disconnect instead! */
2298 #if DEBUG_TRANSPORT
2299 #endif
2300   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2301             "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2302             "try_fast_reconnect");
2303
2304   GNUNET_STATISTICS_update (stats,
2305                             gettext_noop ("# disconnects due to try_fast_reconnect"),
2306                             1,
2307                             GNUNET_NO);
2308 #if DISCONNECT || 1
2309   disconnect_neighbour (nl, GNUNET_YES);
2310 #endif
2311 }
2312
2313
2314 /**
2315  * Function that will be called whenever the plugin internally
2316  * cleans up a session pointer and hence the service needs to
2317  * discard all of those sessions as well.  Plugins that do not
2318  * use sessions can simply omit calling this function and always
2319  * use NULL wherever a session pointer is needed.
2320  *
2321  * @param cls closure
2322  * @param peer which peer was the session for
2323  * @param session which session is being destoyed
2324  */
2325 static void
2326 plugin_env_session_end  (void *cls,
2327                          const struct GNUNET_PeerIdentity *peer,
2328                          struct Session *session)
2329 {
2330   struct TransportPlugin *p = cls;
2331   struct NeighbourList *nl;
2332   struct ReadyList *rl;
2333   struct ForeignAddressList *pos;
2334   struct ForeignAddressList *prev;
2335
2336 #if DEBUG_TRANSPORT
2337   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2338               "Session ended with peer `%4s', %s\n", 
2339               GNUNET_i2s(peer),
2340               "plugin_env_session_end");
2341 #endif
2342   GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2343                                          &remove_session_validations,
2344                                          session);
2345   nl = find_neighbour (peer);
2346   if (nl == NULL)
2347     {
2348 #if DEBUG_TRANSPORT
2349       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2350                   "No neighbour record found for peer `%4s'\n", 
2351                   GNUNET_i2s(peer));
2352 #endif
2353       return; /* was never marked as connected */
2354     }
2355   rl = nl->plugins;
2356   while (rl != NULL)
2357     {
2358       if (rl->plugin == p)
2359         break;
2360       rl = rl->next;
2361     }
2362   if (rl == NULL)
2363     {
2364 #if DEBUG_TRANSPORT
2365       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2366                   "Plugin was associated with peer `%4s'\n", 
2367                   GNUNET_i2s(peer));
2368 #endif
2369       GNUNET_STATISTICS_update (stats,
2370                                 gettext_noop ("# disconnects due to session end"),
2371                                 1,
2372                                 GNUNET_NO);
2373       disconnect_neighbour (nl, GNUNET_YES);
2374       return;
2375     }
2376   prev = NULL;
2377   pos = rl->addresses;
2378   while ( (pos != NULL) &&
2379           (pos->session != session) )
2380     {
2381       prev = pos;
2382       pos = pos->next;
2383     }
2384   if (pos == NULL)
2385     {
2386 #if DEBUG_TRANSPORT
2387       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2388                   "Session was never marked as ready for peer `%4s'\n", 
2389                   GNUNET_i2s(peer));
2390 #endif
2391
2392       int validations_pending = GNUNET_CONTAINER_multihashmap_contains (validation_map, &peer->hashPubKey);
2393
2394       /* No session was marked as ready, but we have pending validations so do not disconnect from neighbour */
2395       if (validations_pending ==GNUNET_YES)
2396         {
2397 #if DEBUG_TRANSPORT
2398       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2399                   "Not disconnecting from peer `%4s due to pending address validations\n", GNUNET_i2s(peer));
2400 #endif
2401         return;
2402         }
2403
2404       //FIXME: This conflicts with inbound tcp connections and tcp nat ... debugging in progress
2405       GNUNET_STATISTICS_update (stats,
2406                                 gettext_noop ("# disconnects due to unready session"),
2407                                 1,
2408                                 GNUNET_NO);
2409
2410       disconnect_neighbour (nl, GNUNET_YES);
2411       return; /* was never marked as connected */
2412     }
2413   pos->session = NULL;
2414   pos->connected = GNUNET_NO;
2415   if (pos->addrlen != 0)
2416     {
2417       if (nl->received_pong != GNUNET_NO)
2418         {
2419           GNUNET_STATISTICS_update (stats,
2420                                     gettext_noop ("# try_fast_reconnect thanks to plugin_env_session_end"),
2421                                     1,
2422                                     GNUNET_NO);
2423           if (GNUNET_YES == pos->connected)                  
2424               try_fast_reconnect (p, nl);           
2425         }
2426       else
2427         {
2428           GNUNET_STATISTICS_update (stats,
2429                                     gettext_noop ("# disconnects due to missing pong"),
2430                                     1,
2431                                     GNUNET_NO);
2432           /* FIXME this is never true?! See: line 2416*/
2433           if (GNUNET_YES == pos->connected)
2434             disconnect_neighbour (nl, GNUNET_YES);
2435         }
2436       return;
2437     }
2438
2439   GNUNET_STATISTICS_update (stats,
2440                               gettext_noop ("# connected addresses"),
2441                               -1,
2442                               GNUNET_NO);
2443
2444   /* was inbound connection, free 'pos' */
2445   if (prev == NULL)
2446     rl->addresses = pos->next;
2447   else
2448     prev->next = pos->next;
2449   if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2450     {
2451       GNUNET_SCHEDULER_cancel (pos->revalidate_task);
2452       pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2453     }
2454   GNUNET_free_non_null(pos->ressources);
2455   GNUNET_free_non_null(pos->quality);
2456   ats_modify_problem_state (ats, ATS_MODIFIED);
2457
2458   if (GNUNET_YES != pos->connected)
2459     {
2460       /* nothing else to do, connection was never up... */
2461       GNUNET_free (pos);
2462       return; 
2463     }
2464   GNUNET_free (pos);
2465
2466   if (nl->received_pong == GNUNET_NO)
2467     {
2468       GNUNET_STATISTICS_update (stats,
2469                                 gettext_noop ("# disconnects due to NO pong"),
2470                                 1,
2471                                 GNUNET_NO);
2472       disconnect_neighbour (nl, GNUNET_YES);
2473       return; /* nothing to do, never connected... */
2474     }
2475   /* check if we have any validated addresses left */
2476   pos = rl->addresses;
2477   while (pos != NULL)
2478     {
2479       if (GNUNET_YES == pos->validated)
2480         {
2481           GNUNET_STATISTICS_update (stats,
2482                                     gettext_noop ("# try_fast_reconnect thanks to validated_address"),
2483                                     1,
2484                                     GNUNET_NO);
2485           try_fast_reconnect (p, nl);
2486           return;
2487         }
2488       pos = pos->next;
2489     }
2490   /* no valid addresses left, signal disconnect! */
2491
2492 #if DEBUG_TRANSPORT
2493   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2494               "Disconnecting peer `%4s', %s\n", 
2495               GNUNET_i2s(peer),
2496               "plugin_env_session_end");
2497 #endif
2498   /* FIXME: This doesn't mean there are no addresses left for this PEER,
2499    * it means there aren't any left for this PLUGIN/PEER combination! So
2500    * calling disconnect_neighbour here with GNUNET_NO forces disconnect
2501    * when it isn't necessary. Using GNUNET_YES at least checks to see
2502    * if there are any addresses that work first, so as not to overdo it.
2503    * --NE
2504    */
2505   GNUNET_STATISTICS_update (stats,
2506                             gettext_noop ("# disconnects due to plugin_env_session_end"),
2507                             1,
2508                             GNUNET_NO);
2509   disconnect_neighbour (nl, GNUNET_YES);
2510 }
2511
2512
2513 /**
2514  * Function that must be called by each plugin to notify the
2515  * transport service about the addresses under which the transport
2516  * provided by the plugin can be reached.
2517  *
2518  * @param cls closure
2519  * @param add_remove GNUNET_YES to add, GNUNET_NO to remove the address
2520  * @param addr one of the addresses of the host, NULL for the last address
2521  *        the specific address format depends on the transport
2522  * @param addrlen length of the address
2523  */
2524 static void
2525 plugin_env_notify_address (void *cls,
2526                            int add_remove,
2527                            const void *addr,
2528                            size_t addrlen)
2529 {
2530   struct TransportPlugin *p = cls;
2531   struct OwnAddressList *al;
2532   struct OwnAddressList *prev;
2533
2534   GNUNET_assert (p->api != NULL);
2535 #if DEBUG_TRANSPORT
2536   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2537               (add_remove == GNUNET_YES)
2538               ? "Adding `%s':%s to the set of our addresses\n"
2539               : "Removing `%s':%s from the set of our addresses\n",
2540               a2s (p->short_name,
2541                    addr, addrlen),
2542               p->short_name);
2543 #endif
2544   GNUNET_assert (addr != NULL);
2545   if (GNUNET_NO == add_remove)
2546     {
2547       prev = NULL;
2548       al = p->addresses;
2549       while (al != NULL)
2550         {
2551           if ( (addrlen == al->addrlen) &&
2552                (0 == memcmp (addr, &al[1], addrlen)) )
2553             {
2554               if (prev == NULL)
2555                 p->addresses = al->next;
2556               else
2557                 prev->next = al->next;
2558               GNUNET_free (al);
2559               refresh_hello ();
2560               return;
2561             }
2562           prev = al;
2563           al = al->next;
2564         }
2565       GNUNET_break (0);
2566       return;
2567     }
2568   al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
2569   al->next = p->addresses;
2570   p->addresses = al;
2571   al->addrlen = addrlen;
2572   memcpy (&al[1], addr, addrlen);
2573   refresh_hello ();
2574 }
2575
2576
2577 /**
2578  * Notify all of our clients about a peer connecting.
2579  */
2580 static void
2581 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
2582                         struct GNUNET_TIME_Relative latency,
2583                         uint32_t distance)
2584 {
2585   struct ConnectInfoMessage * cim;
2586   struct TransportClient *cpos;
2587   uint32_t ats_count;
2588   size_t size;
2589
2590   if (0 == memcmp (peer,
2591                    &my_identity,
2592                    sizeof (struct GNUNET_PeerIdentity)))
2593     {
2594       GNUNET_break (0);
2595       return;
2596     }
2597 #if DEBUG_TRANSPORT
2598   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2599               "Notifying clients about connection with `%s'\n",
2600               GNUNET_i2s (peer));
2601 #endif
2602   GNUNET_STATISTICS_update (stats,
2603                             gettext_noop ("# peers connected"),
2604                             1,
2605                             GNUNET_NO);
2606
2607   ats_count = 2;
2608   size  = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
2609   if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
2610     {
2611       GNUNET_break(0);
2612     }
2613   cim = GNUNET_malloc (size);
2614   cim->header.size = htons (size);
2615   cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2616   cim->ats_count = htonl(2);
2617   (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
2618   (&(cim->ats))[0].value = htonl (distance);
2619   (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
2620   (&(cim->ats))[1].value = htonl ((uint32_t) latency.rel_value);
2621   (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
2622   (&(cim->ats))[2].value = htonl (0);
2623   memcpy (&cim->id, peer, sizeof (struct GNUNET_PeerIdentity));
2624
2625   /* notify ats about connecting peer */
2626   /* notify ats about connecting peer */
2627   if ((ats != NULL) && (shutdown_in_progress == GNUNET_NO))
2628   {
2629     ats_modify_problem_state(ats, ATS_MODIFIED);
2630     ats_calculate_bandwidth_distribution (ats, stats);
2631   }
2632
2633
2634   cpos = clients;
2635   while (cpos != NULL)
2636     {
2637       transmit_to_client (cpos, &(cim->header), GNUNET_NO);
2638       cpos = cpos->next;
2639     }
2640
2641   GNUNET_free (cim);
2642 }
2643
2644
2645 /**
2646  * Notify all of our clients about a peer disconnecting.
2647  */
2648 static void
2649 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
2650 {
2651   struct DisconnectInfoMessage dim;
2652   struct TransportClient *cpos;
2653
2654   if (0 == memcmp (peer,
2655                    &my_identity,
2656                    sizeof (struct GNUNET_PeerIdentity)))
2657     {
2658       GNUNET_break (0);
2659       return;
2660     }
2661 #if DEBUG_TRANSPORT
2662   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2663               "Notifying clients about lost connection to `%s'\n",
2664               GNUNET_i2s (peer));
2665 #endif
2666   GNUNET_STATISTICS_update (stats,
2667                             gettext_noop ("# peers connected"),
2668                             -1,
2669                             GNUNET_NO);
2670   dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
2671   dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2672   dim.reserved = htonl (0);
2673   memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
2674
2675   /* notify ats about connecting peer */
2676   if ((ats != NULL) && (shutdown_in_progress == GNUNET_NO))
2677   {
2678     ats_modify_problem_state(ats, ATS_MODIFIED);
2679     ats_calculate_bandwidth_distribution (ats, stats);
2680   }
2681
2682   cpos = clients;
2683   while (cpos != NULL)
2684     {
2685       transmit_to_client (cpos, &dim.header, GNUNET_NO);
2686       cpos = cpos->next;
2687     }
2688 }
2689
2690
2691 /**
2692  * Find a ForeignAddressList entry for the given neighbour
2693  * that matches the given address and transport.
2694  *
2695  * @param neighbour which peer we care about
2696  * @param tname name of the transport plugin
2697  * @param session session to look for, NULL for 'any'; otherwise
2698  *        can be used for the service to "learn" this session ID
2699  *        if 'addr' matches
2700  * @param addr binary address
2701  * @param addrlen length of addr
2702  * @return NULL if no such entry exists
2703  */
2704 static struct ForeignAddressList *
2705 find_peer_address(struct NeighbourList *neighbour,
2706                   const char *tname,
2707                   struct Session *session,
2708                   const char *addr,
2709                   uint16_t addrlen)
2710 {
2711   struct ReadyList *head;
2712   struct ForeignAddressList *pos;
2713
2714   head = neighbour->plugins;
2715   while (head != NULL)
2716     {
2717       if (0 == strcmp (tname, head->plugin->short_name))
2718         break;
2719       head = head->next;
2720     }
2721   if (head == NULL)
2722     return NULL;
2723   pos = head->addresses;
2724   while ( (pos != NULL) &&
2725           ( (pos->addrlen != addrlen) ||
2726             (memcmp(pos->addr, addr, addrlen) != 0) ) )
2727     {
2728       if ( (session != NULL) &&
2729            (pos->session == session) )
2730         return pos;
2731       pos = pos->next;
2732     }
2733   if ( (session != NULL) && (pos != NULL) )
2734     pos->session = session; /* learn it! */
2735   return pos;
2736 }
2737
2738
2739 /**
2740  * Get the peer address struct for the given neighbour and
2741  * address.  If it doesn't yet exist, create it.
2742  *
2743  * @param neighbour which peer we care about
2744  * @param tname name of the transport plugin
2745  * @param session session of the plugin, or NULL for none
2746  * @param addr binary address
2747  * @param addrlen length of addr
2748  * @return NULL if we do not have a transport plugin for 'tname'
2749  */
2750 static struct ForeignAddressList *
2751 add_peer_address (struct NeighbourList *neighbour,
2752                   const char *tname,
2753                   struct Session *session,
2754                   const char *addr,
2755                   uint16_t addrlen)
2756 {
2757   struct ReadyList *head;
2758   struct ForeignAddressList *ret;
2759   int c;
2760
2761   ret = find_peer_address (neighbour, tname, session, addr, addrlen);
2762   if (ret != NULL)
2763     return ret;
2764   head = neighbour->plugins;
2765
2766   while (head != NULL)
2767     {
2768       if (0 == strcmp (tname, head->plugin->short_name))
2769         break;
2770       head = head->next;
2771     }
2772   if (head == NULL)
2773     return NULL;
2774   ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
2775   ret->session = session;
2776   if ((addrlen > 0) && (addr != NULL))
2777     {
2778       ret->addr = (const char*) &ret[1];
2779       memcpy (&ret[1], addr, addrlen);
2780     }
2781   else
2782     {
2783       ret->addr = NULL;
2784     }
2785
2786   ret->ressources = GNUNET_malloc(available_ressources * sizeof (struct ATS_ressource_entry));
2787   for (c=0; c<available_ressources; c++)
2788     {
2789       struct ATS_ressource_entry *r = ret->ressources;
2790       r[c].index = c;
2791       r[c].atis_index = ressources[c].atis_index;
2792       if (0 == strcmp(neighbour->plugins->plugin->short_name,"unix"))
2793         {
2794           r[c].c = ressources[c].c_unix;
2795         }
2796       else if (0 == strcmp(neighbour->plugins->plugin->short_name,"udp"))
2797         {
2798           r[c].c = ressources[c].c_udp;
2799         }
2800       else if (0 == strcmp(neighbour->plugins->plugin->short_name,"tcp"))
2801         {
2802           r[c].c = ressources[c].c_tcp;
2803         }
2804       else if (0 == strcmp(neighbour->plugins->plugin->short_name,"http"))
2805         {
2806           r[c].c = ressources[c].c_http;
2807         }
2808       else if (0 == strcmp(neighbour->plugins->plugin->short_name,"https"))
2809         {
2810           r[c].c = ressources[c].c_https;
2811         }
2812       else if (0 == strcmp(neighbour->plugins->plugin->short_name,"wlan"))
2813         {
2814           r[c].c = ressources[c].c_wlan;
2815         }
2816       else
2817         {
2818           r[c].c = ressources[c].c_default;
2819           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2820                       "Assigning default cost to peer `%s' addr plugin `%s'! This should not happen!\n",
2821                       GNUNET_i2s(&neighbour->peer), 
2822                       neighbour->plugins->plugin->short_name);
2823         }
2824     }
2825
2826   ret->quality = GNUNET_malloc (available_quality_metrics * sizeof (struct ATS_quality_entry));
2827   ret->addrlen = addrlen;
2828   ret->expires = GNUNET_TIME_relative_to_absolute
2829     (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2830   ret->latency = GNUNET_TIME_relative_get_forever();
2831   ret->distance = -1;
2832   ret->timeout = GNUNET_TIME_relative_to_absolute
2833     (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2834   ret->ready_list = head;
2835   ret->next = head->addresses;
2836   head->addresses = ret;
2837   return ret;
2838 }
2839
2840
2841 /**
2842  * Closure for 'add_validated_address'.
2843  */
2844 struct AddValidatedAddressContext
2845 {
2846   /**
2847    * Entry that has been validated.
2848    */
2849   const struct ValidationEntry *ve;
2850
2851   /**
2852    * Flag set after we have added the address so
2853    * that we terminate the iteration next time.
2854    */
2855   int done;
2856 };
2857
2858
2859 /**
2860  * Callback function used to fill a buffer of max bytes with a list of
2861  * addresses in the format used by HELLOs.  Should use
2862  * "GNUNET_HELLO_add_address" as a helper function.
2863  *
2864  * @param cls the 'struct AddValidatedAddressContext' with the validated address
2865  * @param max maximum number of bytes that can be written to buf
2866  * @param buf where to write the address information
2867  * @return number of bytes written, 0 to signal the
2868  *         end of the iteration.
2869  */
2870 static size_t
2871 add_validated_address (void *cls,
2872                        size_t max, void *buf)
2873 {
2874   struct AddValidatedAddressContext *avac = cls;
2875   const struct ValidationEntry *ve = avac->ve;
2876
2877   if (GNUNET_YES == avac->done)
2878     return 0;
2879   avac->done = GNUNET_YES;
2880   return GNUNET_HELLO_add_address (ve->transport_name,
2881                                    GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION),
2882                                    ve->addr,
2883                                    ve->addrlen,
2884                                    buf,
2885                                    max);
2886 }
2887
2888
2889
2890 /**
2891  * Closure for 'check_address_exists'.
2892  */
2893 struct CheckAddressExistsClosure
2894 {
2895   /**
2896    * Address to check for.
2897    */
2898   const void *addr;
2899
2900   /**
2901    * Name of the transport.
2902    */
2903   const char *tname;
2904
2905   /**
2906    * Session, or NULL.
2907    */
2908   struct Session *session;
2909
2910   /**
2911    * Set to GNUNET_YES if the address exists.
2912    */
2913   int exists;
2914
2915   /**
2916    * Length of addr.
2917    */
2918   uint16_t addrlen;
2919
2920 };
2921
2922
2923 /**
2924  * Iterator over hash map entries.  Checks if the given
2925  * validation entry is for the same address as what is given
2926  * in the closure.
2927  *
2928  * @param cls the 'struct CheckAddressExistsClosure*'
2929  * @param key current key code (ignored)
2930  * @param value value in the hash map ('struct ValidationEntry')
2931  * @return GNUNET_YES if we should continue to
2932  *         iterate (mismatch), GNUNET_NO if not (entry matched)
2933  */
2934 static int
2935 check_address_exists (void *cls,
2936                       const GNUNET_HashCode * key,
2937                       void *value)
2938 {
2939   struct CheckAddressExistsClosure *caec = cls;
2940   struct ValidationEntry *ve = value;
2941
2942   if ( (0 == strcmp (caec->tname,
2943                      ve->transport_name)) &&
2944        (caec->addrlen == ve->addrlen) &&
2945        (0 == memcmp (caec->addr,
2946                      ve->addr,
2947                      caec->addrlen)) )
2948     {
2949       caec->exists = GNUNET_YES;
2950       return GNUNET_NO;
2951     }
2952   if ( (ve->session != NULL) &&
2953        (caec->session == ve->session) )
2954     {
2955       caec->exists = GNUNET_YES;
2956       return GNUNET_NO;
2957     }
2958   return GNUNET_YES;
2959 }
2960
2961
2962 static void
2963 neighbour_timeout_task (void *cls,
2964                        const struct GNUNET_SCHEDULER_TaskContext *tc)
2965 {
2966   struct NeighbourList *n = cls;
2967
2968 #if DEBUG_TRANSPORT
2969   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2970               "Neighbour `%4s' has timed out!\n", GNUNET_i2s (&n->id));
2971 #endif
2972   GNUNET_STATISTICS_update (stats,
2973                             gettext_noop ("# disconnects due to timeout"),
2974                             1,
2975                             GNUNET_NO);
2976   n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2977   disconnect_neighbour (n, GNUNET_NO);
2978 }
2979
2980
2981 /**
2982  * Schedule the job that will cause us to send a PING to the
2983  * foreign address to evaluate its validity and latency.
2984  *
2985  * @param fal address to PING
2986  */
2987 static void
2988 schedule_next_ping (struct ForeignAddressList *fal);
2989
2990
2991 /**
2992  * Add the given address to the list of foreign addresses
2993  * available for the given peer (check for duplicates).
2994  *
2995  * @param cls the respective 'struct NeighbourList' to update
2996  * @param tname name of the transport
2997  * @param expiration expiration time
2998  * @param addr the address
2999  * @param addrlen length of the address
3000  * @return GNUNET_OK (always)
3001  */
3002 static int
3003 add_to_foreign_address_list (void *cls,
3004                              const char *tname,
3005                              struct GNUNET_TIME_Absolute expiration,
3006                              const void *addr,
3007                              uint16_t addrlen)
3008 {
3009   struct NeighbourList *n = cls;
3010   struct ForeignAddressList *fal;
3011   int try;
3012
3013   GNUNET_STATISTICS_update (stats,
3014                             gettext_noop ("# valid peer addresses returned by PEERINFO"),
3015                             1,
3016                             GNUNET_NO);
3017   try = GNUNET_NO;
3018   fal = find_peer_address (n, tname, NULL, addr, addrlen);
3019   if (fal == NULL)
3020     {
3021 #if DEBUG_TRANSPORT_HELLO
3022       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3023                   "Adding address `%s' (%s) for peer `%4s' due to PEERINFO data for %llums.\n",
3024                   a2s (tname, addr, addrlen),
3025                   tname,
3026                   GNUNET_i2s (&n->id),
3027                   expiration.abs_value);
3028 #endif
3029       fal = add_peer_address (n, tname, NULL, addr, addrlen);
3030       if (fal == NULL)
3031         {
3032           GNUNET_STATISTICS_update (stats,
3033                                     gettext_noop ("# previously validated addresses lacking transport"),
3034                                     1,
3035                                     GNUNET_NO);
3036         }
3037       else
3038         {
3039           fal->expires = GNUNET_TIME_absolute_max (expiration,
3040                                                    fal->expires);
3041           schedule_next_ping (fal);
3042         }
3043       try = GNUNET_YES;
3044     }
3045   else
3046     {
3047       fal->expires = GNUNET_TIME_absolute_max (expiration,
3048                                                fal->expires);
3049     }
3050   if (fal == NULL)
3051     {
3052 #if DEBUG_TRANSPORT
3053       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3054                   "Failed to add new address for `%4s'\n",
3055                   GNUNET_i2s (&n->id));
3056 #endif
3057       return GNUNET_OK;
3058     }
3059   if (fal->validated == GNUNET_NO)
3060     {
3061       fal->validated = GNUNET_YES;
3062       GNUNET_STATISTICS_update (stats,
3063                                 gettext_noop ("# peer addresses considered valid"),
3064                                 1,
3065                                 GNUNET_NO);
3066     }
3067   if (try == GNUNET_YES)
3068     {
3069 #if DEBUG_TRANSPORT
3070       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3071                   "Have new addresses, will try to trigger transmissions.\n");
3072 #endif
3073       try_transmission_to_peer (n);
3074     }
3075   return GNUNET_OK;
3076 }
3077
3078
3079 /**
3080  * Add addresses in validated HELLO "h" to the set of addresses
3081  * we have for this peer.
3082  *
3083  * @param cls closure ('struct NeighbourList*')
3084  * @param peer id of the peer, NULL for last call
3085  * @param h hello message for the peer (can be NULL)
3086  * @param err_msg NULL if successful, otherwise contains error message
3087  */
3088 static void
3089 add_hello_for_peer (void *cls,
3090                     const struct GNUNET_PeerIdentity *peer,
3091                     const struct GNUNET_HELLO_Message *h,
3092                     const char *err_msg)
3093 {
3094   struct NeighbourList *n = cls;
3095
3096   if (err_msg != NULL)
3097     {
3098 #if DEBUG_TRANSPORT
3099       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3100                   _("Error in communication with PEERINFO service: %s\n"),
3101                   err_msg);
3102 #endif
3103       /* return; */
3104     }
3105   if (peer == NULL)
3106     {
3107       GNUNET_STATISTICS_update (stats,
3108                                 gettext_noop ("# outstanding peerinfo iterate requests"),
3109                                 -1,
3110                                 GNUNET_NO);
3111       n->piter = NULL;
3112       return;
3113     }
3114   if (h == NULL)
3115     return; /* no HELLO available */
3116 #if DEBUG_TRANSPORT
3117   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3118               "Peerinfo had `%s' message for peer `%4s', adding existing addresses.\n",
3119               "HELLO",
3120               GNUNET_i2s (peer));
3121 #endif
3122   if (GNUNET_YES != n->public_key_valid)
3123     {
3124       GNUNET_HELLO_get_key (h, &n->publicKey);
3125       n->public_key_valid = GNUNET_YES;
3126     }
3127   GNUNET_HELLO_iterate_addresses (h,
3128                                   GNUNET_NO,
3129                                   &add_to_foreign_address_list,
3130                                   n);
3131 }
3132
3133
3134 /**
3135  * Create a fresh entry in our neighbour list for the given peer.
3136  * Will try to transmit our current HELLO to the new neighbour.
3137  * Do not call this function directly, use 'setup_peer_check_blacklist.
3138  *
3139  * @param peer the peer for which we create the entry
3140  * @param do_hello should we schedule transmitting a HELLO
3141  * @return the new neighbour list entry
3142  */
3143 static struct NeighbourList *
3144 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer,
3145                      int do_hello)
3146 {
3147   struct NeighbourList *n;
3148   struct TransportPlugin *tp;
3149   struct ReadyList *rl;
3150
3151   GNUNET_assert (0 != memcmp (peer,
3152                               &my_identity,
3153                               sizeof (struct GNUNET_PeerIdentity)));
3154 #if DEBUG_TRANSPORT
3155   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3156               "Setting up state for neighbour `%4s'\n",
3157               GNUNET_i2s (peer));
3158 #endif
3159   GNUNET_STATISTICS_update (stats,
3160                             gettext_noop ("# active neighbours"),
3161                             1,
3162                             GNUNET_NO);
3163   n = GNUNET_malloc (sizeof (struct NeighbourList));
3164   n->next = neighbours;
3165   neighbours = n;
3166   n->id = *peer;
3167   n->peer_timeout =
3168     GNUNET_TIME_relative_to_absolute
3169     (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3170   GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
3171                                  GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
3172                                  MAX_BANDWIDTH_CARRY_S);
3173   tp = plugins;
3174   while (tp != NULL)
3175     {
3176       if ((tp->api->send != NULL) && (!is_blacklisted(peer, tp)))
3177         {
3178           rl = GNUNET_malloc (sizeof (struct ReadyList));
3179           rl->neighbour = n;
3180           rl->next = n->plugins;
3181           n->plugins = rl;
3182           rl->plugin = tp;
3183           rl->addresses = NULL;
3184         }
3185       tp = tp->next;
3186     }
3187   n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
3188   n->distance = -1;
3189   n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
3190                                                   &neighbour_timeout_task, n);
3191   if (do_hello)
3192     {
3193       GNUNET_STATISTICS_update (stats,
3194                                 gettext_noop ("# peerinfo new neighbor iterate requests"),
3195                                 1,
3196                                 GNUNET_NO);
3197       GNUNET_STATISTICS_update (stats,
3198                                 gettext_noop ("# outstanding peerinfo iterate requests"),
3199                                 1,
3200                                 GNUNET_NO);
3201       n->piter = GNUNET_PEERINFO_iterate (peerinfo, peer,
3202                                           GNUNET_TIME_UNIT_FOREVER_REL,
3203                                           &add_hello_for_peer, n);
3204
3205       GNUNET_STATISTICS_update (stats,
3206                                 gettext_noop ("# HELLO's sent to new neighbors"),
3207                                 1,
3208                                 GNUNET_NO);
3209       if (NULL != our_hello)
3210         transmit_to_peer (NULL, NULL, 0,
3211                           HELLO_ADDRESS_EXPIRATION,
3212                           (const char *) our_hello, GNUNET_HELLO_size(our_hello),
3213                           GNUNET_NO, n);
3214     }
3215   return n;
3216 }
3217
3218
3219 /**
3220  * Function called after we have checked if communicating
3221  * with a given peer is acceptable.
3222  *
3223  * @param cls closure
3224  * @param n NULL if communication is not acceptable
3225  */
3226 typedef void (*SetupContinuation)(void *cls,
3227                                   struct NeighbourList *n);
3228
3229
3230 /**
3231  * Information kept for each client registered to perform
3232  * blacklisting.
3233  */
3234 struct Blacklisters
3235 {
3236   /**
3237    * This is a linked list.
3238    */
3239   struct Blacklisters *next;
3240
3241   /**
3242    * This is a linked list.
3243    */
3244   struct Blacklisters *prev;
3245
3246   /**
3247    * Client responsible for this entry.
3248    */
3249   struct GNUNET_SERVER_Client *client;
3250
3251   /**
3252    * Blacklist check that we're currently performing.
3253    */
3254   struct BlacklistCheck *bc;
3255
3256 };
3257
3258
3259 /**
3260  * Head of DLL of blacklisting clients.
3261  */
3262 static struct Blacklisters *bl_head;
3263
3264 /**
3265  * Tail of DLL of blacklisting clients.
3266  */
3267 static struct Blacklisters *bl_tail;
3268
3269
3270 /**
3271  * Context we use when performing a blacklist check.
3272  */
3273 struct BlacklistCheck
3274 {
3275
3276   /**
3277    * This is a linked list.
3278    */
3279   struct BlacklistCheck *next;
3280
3281   /**
3282    * This is a linked list.
3283    */
3284   struct BlacklistCheck *prev;
3285
3286   /**
3287    * Peer being checked.
3288    */
3289   struct GNUNET_PeerIdentity peer;
3290
3291   /**
3292    * Option for setup neighbour afterwards.
3293    */
3294   int do_hello;
3295
3296   /**
3297    * Continuation to call with the result.
3298    */
3299   SetupContinuation cont;
3300
3301   /**
3302    * Closure for cont.
3303    */
3304   void *cont_cls;
3305
3306   /**
3307    * Current transmission request handle for this client, or NULL if no
3308    * request is pending.
3309    */
3310   struct GNUNET_CONNECTION_TransmitHandle *th;
3311
3312   /**
3313    * Our current position in the blacklisters list.
3314    */
3315   struct Blacklisters *bl_pos;
3316
3317   /**
3318    * Current task performing the check.
3319    */
3320   GNUNET_SCHEDULER_TaskIdentifier task;
3321
3322 };
3323
3324 /**
3325  * Head of DLL of active blacklisting queries.
3326  */
3327 static struct BlacklistCheck *bc_head;
3328
3329 /**
3330  * Tail of DLL of active blacklisting queries.
3331  */
3332 static struct BlacklistCheck *bc_tail;
3333
3334
3335 /**
3336  * Perform next action in the blacklist check.
3337  *
3338  * @param cls the 'struct BlacklistCheck*'
3339  * @param tc unused
3340  */
3341 static void
3342 do_blacklist_check (void *cls,
3343                     const struct GNUNET_SCHEDULER_TaskContext *tc);
3344
3345 /**
3346  * Transmit blacklist query to the client.
3347  *
3348  * @param cls the 'struct BlacklistCheck'
3349  * @param size number of bytes allowed
3350  * @param buf where to copy the message
3351  * @return number of bytes copied to buf
3352  */
3353 static size_t
3354 transmit_blacklist_message (void *cls,
3355                             size_t size,
3356                             void *buf)
3357 {
3358   struct BlacklistCheck *bc = cls;
3359   struct Blacklisters *bl;
3360   struct BlacklistMessage bm;
3361
3362   bc->th = NULL;
3363   if (size == 0)
3364     {
3365       GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK);
3366       bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3367                                            bc);
3368       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3369                   "Failed to send blacklist test for peer `%s' to client\n",
3370                   GNUNET_i2s (&bc->peer));
3371       return 0;
3372     }
3373 #if DEBUG_TRANSPORT
3374   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3375               "Sending blacklist test for peer `%s' to client\n",
3376               GNUNET_i2s (&bc->peer));
3377 #endif
3378   bl = bc->bl_pos;
3379   bm.header.size = htons (sizeof (struct BlacklistMessage));
3380   bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
3381   bm.is_allowed = htonl (0);
3382   bm.peer = bc->peer;
3383   memcpy (buf, &bm, sizeof (bm));
3384   GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
3385   return sizeof (bm);
3386 }
3387
3388
3389 /**
3390  * Perform next action in the blacklist check.
3391  *
3392  * @param cls the 'struct BlacklistCheck*'
3393  * @param tc unused
3394  */
3395 static void
3396 do_blacklist_check (void *cls,
3397                     const struct GNUNET_SCHEDULER_TaskContext *tc)
3398 {
3399   struct BlacklistCheck *bc = cls;
3400   struct Blacklisters *bl;
3401
3402   bc->task = GNUNET_SCHEDULER_NO_TASK;
3403   bl = bc->bl_pos;
3404   if (bl == NULL)
3405     {
3406 #if DEBUG_TRANSPORT
3407       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3408                   "No blacklist clients active, will now setup neighbour record for peer `%s'\n",
3409                   GNUNET_i2s (&bc->peer));
3410 #endif
3411       bc->cont (bc->cont_cls,
3412                 setup_new_neighbour (&bc->peer, bc->do_hello));
3413       GNUNET_free (bc);
3414       return;
3415     }
3416   if (bl->bc == NULL)
3417     {
3418       bl->bc = bc;
3419       bc->th = GNUNET_SERVER_notify_transmit_ready (bl->client,
3420                                                     sizeof (struct BlacklistMessage),
3421                                                     GNUNET_TIME_UNIT_FOREVER_REL,
3422                                                     &transmit_blacklist_message,
3423                                                     bc);
3424     }
3425 }
3426
3427
3428 /**
3429  * Obtain a 'struct NeighbourList' for the given peer.  If such an entry
3430  * does not yet exist, check the blacklist.  If the blacklist says creating
3431  * one is acceptable, create one and call the continuation; otherwise
3432  * call the continuation with NULL.
3433  *
3434  * @param peer peer to setup or look up a struct NeighbourList for
3435  * @param do_hello should we also schedule sending our HELLO to the peer
3436  *        if this is a new record
3437  * @param cont function to call with the 'struct NeigbhbourList*'
3438  * @param cont_cls closure for cont
3439  */
3440 static void
3441 setup_peer_check_blacklist (const struct GNUNET_PeerIdentity *peer,
3442                             int do_hello,
3443                             SetupContinuation cont,
3444                             void *cont_cls)
3445 {
3446   struct NeighbourList *n;
3447   struct BlacklistCheck *bc;
3448
3449   n = find_neighbour(peer);
3450   if (n != NULL)
3451     {
3452 #if DEBUG_TRANSPORT
3453       GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, 
3454                  "Neighbour record exists for peer `%s'\n", 
3455                  GNUNET_i2s(peer));
3456 #endif
3457       if (cont != NULL)
3458         cont (cont_cls, n);
3459       return;
3460     }
3461   if (bl_head == NULL)
3462     {
3463       if (cont != NULL)
3464         cont (cont_cls, setup_new_neighbour (peer, do_hello));
3465       else
3466         setup_new_neighbour(peer, do_hello);
3467       return;
3468     }
3469   bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3470   GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3471   bc->peer = *peer;
3472   bc->do_hello = do_hello;
3473   bc->cont = cont;
3474   bc->cont_cls = cont_cls;
3475   bc->bl_pos = bl_head;
3476   bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3477                                        bc);
3478 }
3479
3480
3481 /**
3482  * Function called with the result of querying a new blacklister about
3483  * it being allowed (or not) to continue to talk to an existing neighbour.
3484  *
3485  * @param cls the original 'struct NeighbourList'
3486  * @param n NULL if we need to disconnect
3487  */
3488 static void
3489 confirm_or_drop_neighbour (void *cls,
3490                            struct NeighbourList *n)
3491 {
3492   struct NeighbourList * orig = cls;
3493
3494   if (n == NULL)
3495     {
3496 #if DEBUG_TRANSPORT
3497       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3498               "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&orig->id),
3499               "confirm_or_drop_neighboUr");
3500 #endif
3501       GNUNET_STATISTICS_update (stats,
3502                                 gettext_noop ("# disconnects due to blacklist"),
3503                                 1,
3504                                 GNUNET_NO);
3505       disconnect_neighbour (orig, GNUNET_NO);
3506     }
3507 }
3508
3509
3510 /**
3511  * Handle a request to start a blacklist.
3512  *
3513  * @param cls closure (always NULL)
3514  * @param client identification of the client
3515  * @param message the actual message
3516  */
3517 static void
3518 handle_blacklist_init (void *cls,
3519                        struct GNUNET_SERVER_Client *client,
3520                        const struct GNUNET_MessageHeader *message)
3521 {
3522   struct Blacklisters *bl;
3523   struct BlacklistCheck *bc;
3524   struct NeighbourList *n;
3525
3526   bl = bl_head;
3527   while (bl != NULL)
3528     {
3529       if (bl->client == client)
3530         {
3531           GNUNET_break (0);
3532           GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3533           return;
3534         }
3535       bl = bl->next;
3536     }
3537   bl = GNUNET_malloc (sizeof (struct Blacklisters));
3538   bl->client = client;
3539   GNUNET_SERVER_client_keep (client);
3540   GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
3541   /* confirm that all existing connections are OK! */
3542   n = neighbours;
3543   while (NULL != n)
3544     {
3545       bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3546       GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3547       bc->peer = n->id;
3548       bc->do_hello = GNUNET_NO;
3549       bc->cont = &confirm_or_drop_neighbour;
3550       bc->cont_cls = n;
3551       bc->bl_pos = bl;
3552       if (n == neighbours) /* all would wait for the same client, no need to
3553                               create more than just the first task right now */
3554         bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3555                                              bc);
3556       n = n->next;
3557     }
3558 }
3559
3560
3561 /**
3562  * Handle a request to blacklist a peer.
3563  *
3564  * @param cls closure (always NULL)
3565  * @param client identification of the client
3566  * @param message the actual message
3567  */
3568 static void
3569 handle_blacklist_reply (void *cls,
3570                         struct GNUNET_SERVER_Client *client,
3571                         const struct GNUNET_MessageHeader *message)
3572 {
3573   const struct BlacklistMessage *msg = (const struct BlacklistMessage*) message;
3574   struct Blacklisters *bl;
3575   struct BlacklistCheck *bc;
3576
3577   bl = bl_head;
3578   while ( (bl != NULL) &&
3579           (bl->client != client) )
3580     bl = bl->next;
3581   if (bl == NULL)
3582     {
3583 #if DEBUG_TRANSPORT
3584       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3585                   "Blacklist client disconnected\n");
3586 #endif
3587       /* FIXME: other error handling here!? */
3588       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3589       return;
3590     }
3591   bc = bl->bc;
3592   bl->bc = NULL;
3593   if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
3594     {
3595 #if DEBUG_TRANSPORT
3596       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3597                   "Blacklist check failed, peer not allowed\n");
3598 #endif
3599       bc->cont (bc->cont_cls, NULL);
3600       GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
3601       GNUNET_free (bc);
3602     }
3603   else
3604     {
3605 #if DEBUG_TRANSPORT
3606       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3607                   "Blacklist check succeeded, continuing with checks\n");
3608 #endif
3609       bc->bl_pos = bc->bl_pos->next;
3610       bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3611                                            bc);
3612     }
3613   /* check if any other bc's are waiting for this blacklister */
3614   bc = bc_head;
3615   while (bc != NULL)
3616     {
3617       if ( (bc->bl_pos == bl) &&
3618            (GNUNET_SCHEDULER_NO_TASK == bc->task) )
3619         bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3620                                              bc);
3621       bc = bc->next;
3622     }
3623 }
3624
3625
3626 /**
3627  * Send periodic PING messages to a given foreign address.
3628  *
3629  * @param cls our 'struct PeriodicValidationContext*'
3630  * @param tc task context
3631  */
3632 static void
3633 send_periodic_ping (void *cls,
3634                     const struct GNUNET_SCHEDULER_TaskContext *tc)
3635 {
3636   struct ForeignAddressList *peer_address = cls;
3637   struct TransportPlugin *tp;
3638   struct ValidationEntry *va;
3639   struct NeighbourList *neighbour;
3640   struct TransportPingMessage ping;
3641   struct CheckAddressExistsClosure caec;
3642   char * message_buf;
3643   uint16_t hello_size;
3644   size_t slen;
3645   size_t tsize;
3646
3647   peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3648   if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
3649     return;
3650   tp = peer_address->ready_list->plugin;
3651   neighbour = peer_address->ready_list->neighbour;
3652   if (GNUNET_YES != neighbour->public_key_valid)
3653     {
3654       /* no public key yet, try again later */
3655       schedule_next_ping (peer_address);
3656       return;
3657     }
3658   caec.addr = peer_address->addr;
3659   caec.addrlen = peer_address->addrlen;
3660   caec.tname = tp->short_name;
3661   caec.session = peer_address->session;
3662   caec.exists = GNUNET_NO;
3663   GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3664                                          &check_address_exists,
3665                                          &caec);
3666   if (caec.exists == GNUNET_YES)
3667     {
3668       /* During validation attempts we will likely trigger the other
3669          peer trying to validate our address which in turn will cause
3670          it to send us its HELLO, so we expect to hit this case rather
3671          frequently.  Only print something if we are very verbose. */
3672 #if DEBUG_TRANSPORT > 1
3673       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3674                   "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
3675                   (peer_address->addr != NULL)
3676                   ? a2s (tp->short_name,
3677                          peer_address->addr,
3678                          peer_address->addrlen)
3679                   : "<inbound>",
3680                   tp->short_name,
3681                   GNUNET_i2s (&neighbour->id));
3682 #endif
3683       schedule_next_ping (peer_address);
3684       return;
3685     }
3686   va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
3687   va->transport_name = GNUNET_strdup (tp->short_name);
3688   va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
3689                                             UINT_MAX);
3690   va->send_time = GNUNET_TIME_absolute_get();
3691   va->session = peer_address->session;
3692   if (peer_address->addr != NULL)
3693     {
3694       va->addr = (const void*) &va[1];
3695       memcpy (&va[1], peer_address->addr, peer_address->addrlen);
3696       va->addrlen = peer_address->addrlen;
3697     }
3698   memcpy(&va->publicKey,
3699          &neighbour->publicKey,
3700          sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3701
3702   va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
3703                                                    &timeout_hello_validation,
3704                                                    va);
3705   GNUNET_CONTAINER_multihashmap_put (validation_map,
3706                                      &neighbour->id.hashPubKey,
3707                                      va,
3708                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3709
3710   if (peer_address->validated != GNUNET_YES)
3711     hello_size = GNUNET_HELLO_size(our_hello);
3712   else
3713     hello_size = 0;
3714
3715   tsize = sizeof(struct TransportPingMessage) + hello_size;
3716
3717   if (peer_address->addr != NULL)
3718     {
3719       slen = strlen (tp->short_name) + 1;
3720       tsize += slen + peer_address->addrlen;
3721     }
3722   else
3723     {
3724       slen = 0; /* make gcc happy */
3725     }
3726   message_buf = GNUNET_malloc(tsize);
3727   ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3728   ping.challenge = htonl(va->challenge);
3729   memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
3730   if (peer_address->validated != GNUNET_YES)
3731     {
3732       memcpy(message_buf, our_hello, hello_size);
3733     }
3734
3735   if (peer_address->addr != NULL)
3736     {
3737       ping.header.size = htons(sizeof(struct TransportPingMessage) +
3738                                peer_address->addrlen +
3739                                slen);
3740       memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
3741              tp->short_name,
3742              slen);
3743       memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
3744              peer_address->addr,
3745              peer_address->addrlen);
3746     }
3747   else
3748     {
3749       ping.header.size = htons(sizeof(struct TransportPingMessage));
3750     }
3751
3752   memcpy(&message_buf[hello_size],
3753          &ping,
3754          sizeof(struct TransportPingMessage));
3755
3756 #if DEBUG_TRANSPORT_REVALIDATION
3757   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3758               "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s'\n",
3759               (peer_address->addr != NULL)
3760               ? a2s (peer_address->plugin->short_name,
3761                      peer_address->addr,
3762                      peer_address->addrlen)
3763               : "<inbound>",
3764               tp->short_name,
3765               GNUNET_i2s (&neighbour->id),
3766               "HELLO", hello_size,
3767               "PING");
3768 #endif
3769   if (peer_address->validated != GNUNET_YES)
3770     GNUNET_STATISTICS_update (stats,
3771                               gettext_noop ("# PING with HELLO messages sent"),
3772                               1,
3773                               GNUNET_NO);
3774   else
3775     GNUNET_STATISTICS_update (stats,
3776                               gettext_noop ("# PING without HELLO messages sent"),
3777                               1,
3778                               GNUNET_NO);
3779   GNUNET_STATISTICS_update (stats,
3780                             gettext_noop ("# PING messages sent for re-validation"),
3781                             1,
3782                             GNUNET_NO);
3783   transmit_to_peer (NULL, peer_address,
3784                     GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3785                     HELLO_VERIFICATION_TIMEOUT,
3786                     message_buf, tsize,
3787                     GNUNET_YES, neighbour);
3788   GNUNET_free(message_buf);
3789   schedule_next_ping (peer_address);
3790 }
3791
3792
3793 /**
3794  * Schedule the job that will cause us to send a PING to the
3795  * foreign address to evaluate its validity and latency.
3796  *
3797  * @param fal address to PING
3798  */
3799 static void
3800 schedule_next_ping (struct ForeignAddressList *fal)
3801 {
3802   struct GNUNET_TIME_Relative delay;
3803
3804   if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
3805     return;
3806   delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
3807   delay.rel_value /= 2; /* do before expiration */
3808   delay = GNUNET_TIME_relative_min (delay,
3809                                     LATENCY_EVALUATION_MAX_DELAY);
3810   if (GNUNET_YES != fal->estimated)
3811     {
3812       delay = GNUNET_TIME_UNIT_ZERO;
3813       fal->estimated = GNUNET_YES;
3814     }
3815   if (GNUNET_YES == fal->connected)
3816     {
3817       delay = GNUNET_TIME_relative_min (delay,
3818                                         CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
3819     }
3820   /* FIXME: also adjust delay based on how close the last
3821      observed latency is to the latency of the best alternative */
3822   /* bound how fast we can go */
3823   delay = GNUNET_TIME_relative_max (delay,
3824                                     GNUNET_TIME_UNIT_SECONDS);
3825   /* randomize a bit (to avoid doing all at the same time) */
3826   delay.rel_value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
3827   fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(delay,
3828                                                       &send_periodic_ping,
3829                                                       fal);
3830 }
3831
3832
3833
3834
3835 /**
3836  * Function that will be called if we receive some payload
3837  * from another peer.
3838  *
3839  * @param message the payload
3840  * @param n peer who claimed to be the sender
3841  */
3842 static void
3843 handle_payload_message (const struct GNUNET_MessageHeader *message,
3844                         struct NeighbourList *n)
3845 {
3846   struct InboundMessage *im;
3847   struct TransportClient *cpos;
3848   uint16_t msize;
3849
3850   msize = ntohs (message->size);
3851   if (n->received_pong == GNUNET_NO)
3852     {
3853 #if DEBUG_TRANSPORT
3854       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3855                   "Received message of type %u and size %u from `%4s', but no pong yet!\n",
3856                   ntohs (message->type),
3857                   ntohs (message->size),
3858                   GNUNET_i2s (&n->id));
3859 #endif
3860       GNUNET_free_non_null (n->pre_connect_message_buffer);
3861       n->pre_connect_message_buffer = GNUNET_malloc (msize);
3862       memcpy (n->pre_connect_message_buffer, message, msize);
3863       return;
3864     }
3865
3866 #if DEBUG_TRANSPORT
3867   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3868               "Received message of type %u and size %u from `%4s', sending to all clients.\n",
3869               ntohs (message->type),
3870               ntohs (message->size),
3871               GNUNET_i2s (&n->id));
3872 #endif
3873   if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3874                                                       (ssize_t) msize))
3875     {
3876       n->quota_violation_count++;
3877 #if DEBUG_TRANSPORT
3878       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3879                   "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
3880                   n->in_tracker.available_bytes_per_s__,
3881                   n->quota_violation_count);
3882 #endif
3883       /* Discount 32k per violation */
3884       GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3885                                         - 32 * 1024);
3886     }
3887   else
3888     {
3889       if (n->quota_violation_count > 0)
3890         {
3891           /* try to add 32k back */
3892           GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3893                                             32 * 1024);
3894           n->quota_violation_count--;
3895         }
3896     }
3897   GNUNET_STATISTICS_update (stats,
3898                             gettext_noop ("# payload received from other peers"),
3899                             msize,
3900                             GNUNET_NO);
3901   /* transmit message to all clients */
3902   uint32_t ats_count = 2;
3903   size_t size = sizeof (struct InboundMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information) + msize;
3904   if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
3905           GNUNET_break(0);
3906
3907   im = GNUNET_malloc (size);
3908   im->header.size = htons (size);
3909   im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
3910   im->peer = n->id;
3911   im->ats_count = htonl(ats_count);
3912   /* Setting ATS data */
3913   (&(im->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
3914   (&(im->ats))[0].value = htonl (n->distance);
3915   (&(im->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
3916   (&(im->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
3917   (&(im->ats))[ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
3918   (&(im->ats))[ats_count].value = htonl (0);
3919
3920   memcpy (&((&(im->ats))[ats_count+1]), message, msize);
3921   cpos = clients;
3922   while (cpos != NULL)
3923     {
3924       transmit_to_client (cpos, &im->header, GNUNET_YES);
3925       cpos = cpos->next;
3926     }
3927   GNUNET_free (im);
3928 }
3929
3930
3931 /**
3932  * Iterator over hash map entries.  Checks if the given validation
3933  * entry is for the same challenge as what is given in the PONG.
3934  *
3935  * @param cls the 'struct TransportPongMessage*'
3936  * @param key peer identity
3937  * @param value value in the hash map ('struct ValidationEntry')
3938  * @return GNUNET_YES if we should continue to
3939  *         iterate (mismatch), GNUNET_NO if not (entry matched)
3940  */
3941 static int
3942 check_pending_validation (void *cls,
3943                           const GNUNET_HashCode * key,
3944                           void *value)
3945 {
3946   const struct TransportPongMessage *pong = cls;
3947   struct ValidationEntry *ve = value;
3948   struct AddValidatedAddressContext avac;
3949   unsigned int challenge = ntohl(pong->challenge);
3950   struct GNUNET_HELLO_Message *hello;
3951   struct GNUNET_PeerIdentity target;
3952   struct NeighbourList *n;
3953   struct ForeignAddressList *fal;
3954   struct OwnAddressList *oal;
3955   struct TransportPlugin *tp;
3956   struct GNUNET_MessageHeader *prem;
3957   uint16_t ps;
3958   const char *addr;
3959   size_t slen;
3960   size_t alen;
3961
3962   ps = ntohs (pong->header.size);
3963   if (ps < sizeof (struct TransportPongMessage))
3964     {
3965       GNUNET_break_op (0);
3966       return GNUNET_NO;
3967     }
3968   addr = (const char*) &pong[1];
3969   slen = strlen (ve->transport_name) + 1;
3970   if ( (ps - sizeof (struct TransportPongMessage) < slen) ||
3971        (ve->challenge != challenge) ||
3972        (addr[slen-1] != '\0') ||
3973        (0 != strcmp (addr, ve->transport_name)) ||
3974        (ntohl (pong->purpose.size)
3975         != sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
3976         sizeof (uint32_t) +
3977         sizeof (struct GNUNET_TIME_AbsoluteNBO) +
3978         sizeof (struct GNUNET_PeerIdentity) + ps - sizeof (struct TransportPongMessage)) )
3979     {
3980       return GNUNET_YES;
3981     }
3982
3983   alen = ps - sizeof (struct TransportPongMessage) - slen;
3984   switch (ntohl (pong->purpose.purpose))
3985     {
3986     case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN:
3987       if ( (ve->addrlen + slen != ntohl (pong->addrlen)) ||
3988            (0 != memcmp (&addr[slen],
3989                          ve->addr,
3990                          ve->addrlen)) )
3991         {
3992           return GNUNET_YES; /* different entry, keep trying! */
3993         }
3994       if (0 != memcmp (&pong->pid,
3995                        key,
3996                        sizeof (struct GNUNET_PeerIdentity)))
3997         {
3998           GNUNET_break_op (0);
3999           return GNUNET_NO;
4000         }
4001       if (GNUNET_OK !=
4002           GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
4003                                     &pong->purpose,
4004                                     &pong->signature,
4005                                     &ve->publicKey))
4006         {
4007           GNUNET_break_op (0);
4008           return GNUNET_NO;
4009         }
4010
4011 #if DEBUG_TRANSPORT
4012       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4013                   "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
4014                   GNUNET_h2s (key),
4015                   a2s (ve->transport_name,
4016                        (const struct sockaddr *) ve->addr,
4017                        ve->addrlen),
4018                   ve->transport_name);
4019 #endif
4020       break;
4021     case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING:
4022       if (0 != memcmp (&pong->pid,
4023                          &my_identity,
4024                          sizeof (struct GNUNET_PeerIdentity)))
4025         {
4026           char * peer;
4027
4028           GNUNET_asprintf(&peer, "%s",GNUNET_i2s (&pong->pid));
4029 #if DEBUG_TRANSPORT
4030           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4031                       "Received PONG for different identity: I am `%s', PONG identity: `%s'\n",
4032                       GNUNET_i2s (&my_identity), 
4033                       peer );
4034 #endif
4035           GNUNET_free (peer);
4036           return GNUNET_NO;
4037         }
4038       if (ve->addrlen != 0)
4039         {
4040           /* must have been for a different validation entry */
4041           return GNUNET_YES;
4042         }
4043       tp = find_transport (ve->transport_name);
4044       if (tp == NULL)
4045         {
4046           GNUNET_break (0);
4047           return GNUNET_YES;
4048         }
4049       oal = tp->addresses;
4050       while (NULL != oal)
4051         {
4052           if ( (oal->addrlen == alen) &&
4053                (0 == memcmp (&oal[1],
4054                              &addr[slen],
4055                              alen)) )
4056             break;
4057           oal = oal->next;
4058         }
4059       if (oal == NULL)
4060         {
4061           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4062                       _("Not accepting PONG from `%s' with address `%s' since I cannot confirm using this address.\n"),
4063                       GNUNET_i2s (&pong->pid),
4064                       a2s (ve->transport_name,
4065                            &addr[slen],
4066                            alen));
4067           /* FIXME: since the sender of the PONG currently uses the
4068              wrong address (see FIMXE there!), we cannot run a 
4069              proper check here... */
4070 #if FIXME_URGENT
4071           return GNUNET_NO;
4072 #endif
4073         }
4074       if (GNUNET_OK !=
4075           GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING,
4076                                     &pong->purpose,
4077                                     &pong->signature,
4078                                     &ve->publicKey))
4079         {
4080           GNUNET_break_op (0);
4081           return GNUNET_NO;
4082         }
4083
4084 #if DEBUG_TRANSPORT
4085       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4086                   "Confirmed that peer `%4s' is talking to us using address `%s' (%s) for us.\n",
4087                   GNUNET_h2s (key),
4088                   a2s (ve->transport_name,
4089                        &addr[slen],
4090                        alen),
4091                   ve->transport_name);
4092 #endif
4093       break;
4094     default:
4095       GNUNET_break_op (0);
4096       return GNUNET_NO;
4097     }
4098   if (GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value == 0)
4099     {
4100       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4101                   _("Received expired signature.  Check system time.\n"));
4102       return GNUNET_NO;
4103     }
4104   GNUNET_STATISTICS_update (stats,
4105                             gettext_noop ("# address validation successes"),
4106                             1,
4107                             GNUNET_NO);
4108   /* create the updated HELLO */
4109   GNUNET_CRYPTO_hash (&ve->publicKey,
4110                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4111                       &target.hashPubKey);
4112   if (ve->addr != NULL)
4113     {
4114       avac.done = GNUNET_NO;
4115       avac.ve = ve;
4116       hello = GNUNET_HELLO_create (&ve->publicKey,
4117                                    &add_validated_address,
4118                                    &avac);
4119       GNUNET_PEERINFO_add_peer (peerinfo,
4120                                 hello);
4121       GNUNET_free (hello);
4122     }
4123   n = find_neighbour (&target);
4124   if (n != NULL)
4125     {
4126       n->publicKey = ve->publicKey;
4127       n->public_key_valid = GNUNET_YES;
4128       fal = add_peer_address (n,
4129                               ve->transport_name,
4130                               ve->session,
4131                               ve->addr,
4132                               ve->addrlen);
4133       GNUNET_assert (fal != NULL);
4134       fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
4135       fal->validated = GNUNET_YES;
4136       mark_address_connected (fal);
4137       GNUNET_STATISTICS_update (stats,
4138                                 gettext_noop ("# peer addresses considered valid"),
4139                                 1,
4140                                 GNUNET_NO);
4141       fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
4142       update_addr_value (fal, GNUNET_TIME_absolute_get_duration (ve->send_time).rel_value, GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
4143
4144       schedule_next_ping (fal);
4145       if (n->latency.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
4146         n->latency = fal->latency;
4147       else
4148         n->latency.rel_value = (fal->latency.rel_value + n->latency.rel_value) / 2;
4149
4150       n->distance = fal->distance;
4151       if (GNUNET_NO == n->received_pong)
4152         {
4153           n->received_pong = GNUNET_YES;
4154           notify_clients_connect (&target, n->latency, n->distance);
4155           if (NULL != (prem = n->pre_connect_message_buffer))
4156             {
4157               n->pre_connect_message_buffer = NULL;
4158               handle_payload_message (prem, n);
4159               GNUNET_free (prem);
4160             }
4161         }
4162       if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4163         {
4164           GNUNET_SCHEDULER_cancel (n->retry_task);
4165           n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4166           try_transmission_to_peer (n);
4167         }
4168     }
4169
4170   /* clean up validation entry */
4171   GNUNET_assert (GNUNET_YES ==
4172                  GNUNET_CONTAINER_multihashmap_remove (validation_map,
4173                                                        key,
4174                                                        ve));
4175   abort_validation (NULL, NULL, ve);
4176   return GNUNET_NO;
4177 }
4178
4179
4180 /**
4181  * Function that will be called if we receive a validation
4182  * of an address challenge that we transmitted to another
4183  * peer.  Note that the validation should only be considered
4184  * acceptable if the challenge matches AND if the sender
4185  * address is at least a plausible address for this peer
4186  * (otherwise we may be seeing a MiM attack).
4187  *
4188  * @param cls closure
4189  * @param message the pong message
4190  * @param peer who responded to our challenge
4191  * @param sender_address string describing our sender address (as observed
4192  *         by the other peer in binary format)
4193  * @param sender_address_len number of bytes in 'sender_address'
4194  */
4195 static void
4196 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
4197              const struct GNUNET_PeerIdentity *peer,
4198              const char *sender_address,
4199              size_t sender_address_len)
4200 {
4201   if (0 == memcmp (peer,
4202                    &my_identity,
4203                    sizeof (struct GNUNET_PeerIdentity)))
4204     {
4205       /* PONG send to self, ignore */
4206       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4207                   "Receiving `%s' message from myself\n", 
4208                   "PONG");
4209       return;
4210     }
4211 #if DEBUG_TRANSPORT > 1
4212   /* we get tons of these that just get discarded, only log
4213      if we are quite verbose */
4214   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4215               "Receiving `%s' message from `%4s'.\n", "PONG",
4216               GNUNET_i2s (peer));
4217 #endif
4218   GNUNET_STATISTICS_update (stats,
4219                             gettext_noop ("# PONG messages received"),
4220                             1,
4221                             GNUNET_NO);
4222   if (GNUNET_SYSERR !=
4223       GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
4224                                                   &peer->hashPubKey,
4225                                                   &check_pending_validation,
4226                                                   (void*) message))
4227     {
4228       /* This is *expected* to happen a lot since we send
4229          PONGs to *all* known addresses of the sender of
4230          the PING, so most likely we get multiple PONGs
4231          per PING, and all but the first PONG will end up
4232          here. So really we should not print anything here
4233          unless we want to be very, very verbose... */
4234 #if DEBUG_TRANSPORT > 2
4235       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4236                   "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
4237                   "PONG",
4238                   GNUNET_i2s (peer),
4239                   "PING");
4240 #endif
4241       return;
4242     }
4243
4244 }
4245
4246
4247 /**
4248  * Try to validate a neighbour's address by sending him our HELLO and a PING.
4249  *
4250  * @param cls the 'struct ValidationEntry*'
4251  * @param neighbour neighbour to validate, NULL if validation failed
4252  */
4253 static void
4254 transmit_hello_and_ping (void *cls,
4255                          struct NeighbourList *neighbour)
4256 {
4257   struct ValidationEntry *va = cls;
4258   struct ForeignAddressList *peer_address;
4259   struct TransportPingMessage ping;
4260   uint16_t hello_size;
4261   size_t tsize;
4262   char * message_buf;
4263   struct GNUNET_PeerIdentity id;
4264   size_t slen;
4265
4266   GNUNET_CRYPTO_hash (&va->publicKey,
4267                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4268                       &id.hashPubKey);
4269   if (neighbour == NULL)
4270     {
4271       /* FIXME: stats... */
4272       GNUNET_break (GNUNET_OK ==
4273                     GNUNET_CONTAINER_multihashmap_remove (validation_map,
4274                                                           &id.hashPubKey,
4275                                                           va));
4276       abort_validation (NULL, NULL, va);
4277       return;
4278     }
4279   neighbour->publicKey = va->publicKey;
4280   neighbour->public_key_valid = GNUNET_YES;
4281   peer_address = add_peer_address (neighbour,
4282                                    va->transport_name, NULL,
4283                                    (const void*) &va[1],
4284                                    va->addrlen);
4285   if (peer_address == NULL)
4286     {
4287       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4288                   "Failed to add peer `%4s' for plugin `%s'\n",
4289                   GNUNET_i2s (&neighbour->id),
4290                   va->transport_name);
4291       GNUNET_break (GNUNET_OK ==
4292                     GNUNET_CONTAINER_multihashmap_remove (validation_map,
4293                                                           &id.hashPubKey,
4294                                                           va));
4295       abort_validation (NULL, NULL, va);
4296       return;
4297     }
4298   if (NULL == our_hello)
4299     refresh_hello_task (NULL, NULL);
4300   hello_size = GNUNET_HELLO_size(our_hello);
4301   slen = strlen(va->transport_name) + 1;
4302   tsize = sizeof(struct TransportPingMessage) + hello_size + va->addrlen + slen;
4303   message_buf = GNUNET_malloc(tsize);
4304   ping.challenge = htonl(va->challenge);
4305   ping.header.size = htons(sizeof(struct TransportPingMessage) + slen + va->addrlen);
4306   ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
4307   memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
4308   memcpy(message_buf, our_hello, hello_size);
4309   memcpy(&message_buf[hello_size],
4310          &ping,
4311          sizeof(struct TransportPingMessage));
4312   memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
4313          va->transport_name,
4314          slen);
4315   memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
4316          &va[1],
4317          va->addrlen);
4318 #if DEBUG_TRANSPORT
4319   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4320               "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
4321               (va->addrlen == 0)
4322               ? "<inbound>"
4323               : a2s (va->transport_name,
4324                      (const void*) &va[1], va->addrlen),
4325               va->transport_name,
4326               GNUNET_i2s (&neighbour->id),
4327               "HELLO", hello_size,
4328               "PING", sizeof (struct TransportPingMessage) + va->addrlen + slen);
4329 #endif
4330
4331   GNUNET_STATISTICS_update (stats,
4332                             gettext_noop ("# PING messages sent for initial validation"),
4333                             1,
4334                             GNUNET_NO);
4335   transmit_to_peer (NULL, peer_address,
4336                     GNUNET_SCHEDULER_PRIORITY_DEFAULT,
4337                     HELLO_VERIFICATION_TIMEOUT,
4338                     message_buf, tsize,
4339                     GNUNET_YES, neighbour);
4340   GNUNET_free(message_buf);
4341 }
4342
4343
4344 /**
4345  * Check if the given address is already being validated; if not,
4346  * append the given address to the list of entries that are being be
4347  * validated and initiate validation.
4348  *
4349  * @param cls closure ('struct CheckHelloValidatedContext *')
4350  * @param tname name of the transport
4351  * @param expiration expiration time
4352  * @param addr the address
4353  * @param addrlen length of the address
4354  * @return GNUNET_OK (always)
4355  */
4356 static int
4357 run_validation (void *cls,
4358                 const char *tname,
4359                 struct GNUNET_TIME_Absolute expiration,
4360                 const void *addr,
4361                 uint16_t addrlen)
4362 {
4363   struct CheckHelloValidatedContext *chvc = cls;
4364   struct GNUNET_PeerIdentity id;
4365   struct TransportPlugin *tp;
4366   struct ValidationEntry *va;
4367   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4368   struct CheckAddressExistsClosure caec;
4369   struct OwnAddressList *oal;
4370
4371   GNUNET_assert (addr != NULL);
4372
4373   GNUNET_STATISTICS_update (stats,
4374                             gettext_noop ("# peer addresses scheduled for validation"),
4375                             1,
4376                             GNUNET_NO);
4377   tp = find_transport (tname);
4378   if (tp == NULL)
4379     {
4380       GNUNET_log (GNUNET_ERROR_TYPE_INFO |
4381                   GNUNET_ERROR_TYPE_BULK,
4382                   _
4383                   ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
4384                   tname);
4385       GNUNET_STATISTICS_update (stats,
4386                                 gettext_noop ("# peer addresses not validated (plugin not available)"),
4387                                 1,
4388                                 GNUNET_NO);
4389       return GNUNET_OK;
4390     }
4391   /* check if this is one of our own addresses */
4392   oal = tp->addresses;
4393   while (NULL != oal)
4394     {
4395       if ( (oal->addrlen == addrlen) &&
4396            (0 == memcmp (&oal[1],
4397                          addr,
4398                          addrlen)) )
4399         {
4400           /* not plausible, this address is equivalent to our own address! */
4401           GNUNET_STATISTICS_update (stats,
4402                                     gettext_noop ("# peer addresses not validated (loopback)"),
4403                                     1,
4404                                     GNUNET_NO);
4405           return GNUNET_OK;
4406         }
4407       oal = oal->next;
4408     }
4409   GNUNET_HELLO_get_key (chvc->hello, &pk);
4410   GNUNET_CRYPTO_hash (&pk,
4411                       sizeof (struct
4412                               GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4413                       &id.hashPubKey);
4414
4415   if (is_blacklisted(&id, tp))
4416     {
4417 #if DEBUG_TRANSPORT
4418       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4419                   "Attempted to validate blacklisted peer `%s' using `%s'!\n",
4420                   GNUNET_i2s(&id),
4421                   tname);
4422 #endif
4423       return GNUNET_OK;
4424     }
4425
4426   caec.addr = addr;
4427   caec.addrlen = addrlen;
4428   caec.session = NULL;
4429   caec.tname = tname;
4430   caec.exists = GNUNET_NO;
4431   GNUNET_CONTAINER_multihashmap_iterate (validation_map,
4432                                          &check_address_exists,
4433                                          &caec);
4434   if (caec.exists == GNUNET_YES)
4435     {
4436       /* During validation attempts we will likely trigger the other
4437          peer trying to validate our address which in turn will cause
4438          it to send us its HELLO, so we expect to hit this case rather
4439          frequently.  Only print something if we are very verbose. */
4440 #if DEBUG_TRANSPORT > 1
4441       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4442                   "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
4443                   a2s (tname, addr, addrlen),
4444                   tname,
4445                   GNUNET_i2s (&id));
4446 #endif
4447       GNUNET_STATISTICS_update (stats,
4448                                 gettext_noop ("# peer addresses not validated (in progress)"),
4449                                 1,
4450                                 GNUNET_NO);
4451       return GNUNET_OK;
4452     }
4453   va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
4454   va->chvc = chvc;
4455   chvc->ve_count++;
4456   va->transport_name = GNUNET_strdup (tname);
4457   va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
4458                                             UINT_MAX);
4459   va->send_time = GNUNET_TIME_absolute_get();
4460   va->addr = (const void*) &va[1];
4461   memcpy (&va[1], addr, addrlen);
4462   va->addrlen = addrlen;
4463   GNUNET_HELLO_get_key (chvc->hello,
4464                         &va->publicKey);
4465   va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
4466                                                    &timeout_hello_validation,
4467                                                    va);
4468   GNUNET_CONTAINER_multihashmap_put (validation_map,
4469                                      &id.hashPubKey,
4470                                      va,
4471                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
4472   setup_peer_check_blacklist (&id, GNUNET_NO,
4473                               &transmit_hello_and_ping,
4474                               va);
4475   return GNUNET_OK;
4476 }
4477
4478
4479 /**
4480  * Check if addresses in validated hello "h" overlap with
4481  * those in "chvc->hello" and validate the rest.
4482  *
4483  * @param cls closure
4484  * @param peer id of the peer, NULL for last call
4485  * @param h hello message for the peer (can be NULL)
4486  * @param err_msg NULL if successful, otherwise contains error message
4487  */
4488 static void
4489 check_hello_validated (void *cls,
4490                        const struct GNUNET_PeerIdentity *peer,
4491                        const struct GNUNET_HELLO_Message *h,
4492                        const char *err_msg)
4493 {
4494   struct CheckHelloValidatedContext *chvc = cls;
4495   struct GNUNET_HELLO_Message *plain_hello;
4496   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4497   struct GNUNET_PeerIdentity target;
4498   struct NeighbourList *n;
4499
4500   if (err_msg != NULL)
4501     {
4502 #if DEBUG_TRANSPORT
4503       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4504                   _("Error in communication with PEERINFO service: %s\n"),
4505                   err_msg);
4506 #endif
4507       /* return; */
4508   }
4509
4510   if (peer == NULL)
4511     {
4512       GNUNET_STATISTICS_update (stats,
4513                                 gettext_noop ("# outstanding peerinfo iterate requests"),
4514                                 -1,
4515                                 GNUNET_NO);
4516       chvc->piter = NULL;
4517       if (GNUNET_NO == chvc->hello_known)
4518         {
4519           /* notify PEERINFO about the peer now, so that we at least
4520              have the public key if some other component needs it */
4521           GNUNET_HELLO_get_key (chvc->hello, &pk);
4522           GNUNET_CRYPTO_hash (&pk,
4523                               sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4524                               &target.hashPubKey);
4525           plain_hello = GNUNET_HELLO_create (&pk,
4526                                              NULL,
4527                                              NULL);
4528           GNUNET_PEERINFO_add_peer (peerinfo, plain_hello);
4529           GNUNET_free (plain_hello);
4530 #if DEBUG_TRANSPORT_HELLO
4531           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4532                       "PEERINFO had no `%s' message for peer `%4s', full validation needed.\n",
4533                       "HELLO",
4534                       GNUNET_i2s (&target));
4535 #endif
4536           GNUNET_STATISTICS_update (stats,
4537                                     gettext_noop ("# new HELLOs requiring full validation"),
4538                                     1,
4539                                     GNUNET_NO);
4540           GNUNET_HELLO_iterate_addresses (chvc->hello,
4541                                           GNUNET_NO,
4542                                           &run_validation,
4543                                           chvc);
4544         }
4545       else
4546         {
4547           GNUNET_STATISTICS_update (stats,
4548                                     gettext_noop ("# duplicate HELLO (peer known)"),
4549                                     1,
4550                                     GNUNET_NO);
4551         }
4552       chvc->ve_count--;
4553       if (chvc->ve_count == 0)
4554         {
4555           GNUNET_CONTAINER_DLL_remove (chvc_head,
4556                                        chvc_tail,
4557                                        chvc);
4558           GNUNET_free (chvc);
4559         }
4560       return;
4561     }
4562   if (h == NULL)
4563     return;
4564 #if DEBUG_TRANSPORT_HELLO
4565   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4566               "PEERINFO had `%s' message for peer `%4s', validating only new addresses.\n",
4567               "HELLO",
4568               GNUNET_i2s (peer));
4569 #endif
4570   chvc->hello_known = GNUNET_YES;
4571   n = find_neighbour (peer);
4572   if (n != NULL)
4573     {
4574 #if DEBUG_TRANSPORT_HELLO
4575       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4576                   "Calling hello_iterate_addresses for %s!\n",
4577                   GNUNET_i2s (peer));
4578 #endif
4579       GNUNET_HELLO_iterate_addresses (h,
4580                                       GNUNET_NO,
4581                                       &add_to_foreign_address_list,
4582                                       n);
4583       try_transmission_to_peer (n);
4584     }
4585   else
4586     {
4587 #if DEBUG_TRANSPORT_HELLO
4588       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4589                   "No existing neighbor record for %s!\n",
4590                   GNUNET_i2s (peer));
4591 #endif
4592       GNUNET_STATISTICS_update (stats,
4593                                 gettext_noop ("# no existing neighbour record (validating HELLO)"),
4594                                 1,
4595                                 GNUNET_NO);
4596     }
4597   GNUNET_STATISTICS_update (stats,
4598                             gettext_noop ("# HELLO validations (update case)"),
4599                             1,
4600                             GNUNET_NO);
4601   GNUNET_HELLO_iterate_new_addresses (chvc->hello,
4602                                       h,
4603                                       GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME),
4604                                       &run_validation,
4605                                       chvc);
4606 }
4607
4608
4609 /**
4610  * Process HELLO-message.
4611  *
4612  * @param plugin transport involved, may be NULL
4613  * @param message the actual message
4614  * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
4615  */
4616 static int
4617 process_hello (struct TransportPlugin *plugin,
4618                const struct GNUNET_MessageHeader *message)
4619 {
4620   uint16_t hsize;
4621   struct GNUNET_PeerIdentity target;
4622   const struct GNUNET_HELLO_Message *hello;
4623   struct CheckHelloValidatedContext *chvc;
4624   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
4625   struct NeighbourList *n;
4626 #if DEBUG_TRANSPORT_HELLO > 2
4627   char *my_id;
4628 #endif
4629
4630   hsize = ntohs (message->size);
4631   if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
4632       (hsize < sizeof (struct GNUNET_MessageHeader)))
4633     {
4634       GNUNET_break (0);
4635       return GNUNET_SYSERR;
4636     }
4637   GNUNET_STATISTICS_update (stats,
4638                             gettext_noop ("# HELLOs received for validation"),
4639                             1,
4640                             GNUNET_NO);
4641
4642   hello = (const struct GNUNET_HELLO_Message *) message;
4643   if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
4644     {
4645 #if DEBUG_TRANSPORT_HELLO
4646       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4647                   "Unable to get public key from `%s' for `%4s'!\n",
4648                   "HELLO",
4649                   GNUNET_i2s (&target));
4650 #endif
4651       GNUNET_break_op (0);
4652       return GNUNET_SYSERR;
4653     }
4654   GNUNET_CRYPTO_hash (&publicKey,
4655                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4656                       &target.hashPubKey);
4657
4658 #if DEBUG_TRANSPORT_HELLO
4659   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4660               "Received `%s' message for `%4s'\n",
4661               "HELLO",
4662               GNUNET_i2s (&target));
4663 #endif
4664   if (0 == memcmp (&my_identity,
4665                    &target,
4666                    sizeof (struct GNUNET_PeerIdentity)))
4667     {
4668       GNUNET_STATISTICS_update (stats,
4669                                 gettext_noop ("# HELLOs ignored for validation (is my own HELLO)"),
4670                                 1,
4671                                 GNUNET_NO);
4672       return GNUNET_OK;
4673     }
4674   n = find_neighbour (&target);
4675   if ( (NULL != n) &&
4676        (! n->public_key_valid) )
4677     {
4678       GNUNET_HELLO_get_key (hello, &n->publicKey);
4679       n->public_key_valid = GNUNET_YES;
4680     }
4681
4682   /* check if load is too high before doing expensive stuff */
4683   if (GNUNET_SCHEDULER_get_load (GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
4684     {
4685       GNUNET_STATISTICS_update (stats,
4686                                 gettext_noop ("# HELLOs ignored due to high load"),
4687                                 1,
4688                                 GNUNET_NO);
4689 #if DEBUG_TRANSPORT_HELLO
4690       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4691                   "Ignoring `%s' for `%4s', load too high.\n",
4692                   "HELLO",
4693                   GNUNET_i2s (&target));
4694 #endif
4695       return GNUNET_OK;
4696     }
4697
4698
4699   chvc = chvc_head;
4700   while (NULL != chvc)
4701     {
4702       if (GNUNET_HELLO_equals (hello,
4703                                chvc->hello,
4704                                GNUNET_TIME_absolute_get ()).abs_value > 0)
4705         {
4706 #if DEBUG_TRANSPORT_HELLO > 2
4707           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4708                       "Received duplicate `%s' message for `%4s'; ignored\n",
4709                       "HELLO",
4710                       GNUNET_i2s (&target));
4711 #endif
4712           return GNUNET_OK; /* validation already pending */
4713         }
4714       if (GNUNET_HELLO_size (hello) == GNUNET_HELLO_size (chvc->hello))
4715         GNUNET_break (0 != memcmp (hello, chvc->hello,
4716                                    GNUNET_HELLO_size(hello)));
4717       chvc = chvc->next;
4718     }
4719
4720 #if BREAK_TESTS
4721   struct NeighbourList *temp_neighbor = find_neighbour(&target);
4722   if ((NULL != temp_neighbor))
4723     {
4724       fprintf(stderr, "Already know peer, ignoring hello\n");
4725       return GNUNET_OK;
4726     }
4727 #endif
4728
4729 #if DEBUG_TRANSPORT_HELLO > 2
4730   if (plugin != NULL)
4731     {
4732       my_id = GNUNET_strdup(GNUNET_i2s(plugin->env.my_identity));
4733 #if DEBUG_TRANSPORT
4734       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4735                   "%s: Starting validation of `%s' message for `%4s' via '%s' of size %u\n",
4736                   my_id,
4737                   "HELLO",
4738                   GNUNET_i2s (&target),
4739                   plugin->short_name,
4740                   GNUNET_HELLO_size(hello));
4741 #endif
4742       GNUNET_free(my_id);
4743     }
4744 #endif
4745   chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
4746   chvc->ve_count = 1;
4747   chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
4748   memcpy (&chvc[1], hello, hsize);
4749   GNUNET_CONTAINER_DLL_insert (chvc_head,
4750                                chvc_tail,
4751                                chvc);
4752   /* finally, check if HELLO was previously validated
4753      (continuation will then schedule actual validation) */
4754   GNUNET_STATISTICS_update (stats,
4755                             gettext_noop ("# peerinfo process hello iterate requests"),
4756                             1,
4757                             GNUNET_NO);
4758   GNUNET_STATISTICS_update (stats,
4759                             gettext_noop ("# outstanding peerinfo iterate requests"),
4760                             1,
4761                             GNUNET_NO);
4762   chvc->piter = GNUNET_PEERINFO_iterate (peerinfo,
4763                                          &target,
4764                                          HELLO_VERIFICATION_TIMEOUT,
4765                                          &check_hello_validated, chvc);
4766   return GNUNET_OK;
4767 }
4768
4769
4770 /**
4771  * The peer specified by the given neighbour has timed-out or a plugin
4772  * has disconnected.  We may either need to do nothing (other plugins
4773  * still up), or trigger a full disconnect and clean up.  This
4774  * function updates our state and does the necessary notifications.
4775  * Also notifies our clients that the neighbour is now officially
4776  * gone.
4777  *
4778  * @param n the neighbour list entry for the peer
4779  * @param check GNUNET_YES to check if ALL addresses for this peer
4780  *              are gone, GNUNET_NO to force a disconnect of the peer
4781  *              regardless of whether other addresses exist.
4782  */
4783 static void
4784 disconnect_neighbour (struct NeighbourList *n, int check)
4785 {
4786   struct ReadyList *rpos;
4787   struct NeighbourList *npos;
4788   struct NeighbourList *nprev;
4789   struct MessageQueue *mq;
4790   struct ForeignAddressList *peer_addresses;
4791   struct ForeignAddressList *peer_pos;
4792
4793   if (GNUNET_YES == check)
4794     {
4795       rpos = n->plugins;
4796       while (NULL != rpos)
4797         {
4798           peer_addresses = rpos->addresses;
4799           while (peer_addresses != NULL)
4800             {
4801                   // Do not disconnect if: an address is connected or an inbound address exists
4802               if ((GNUNET_YES == peer_addresses->connected) || (peer_addresses->addrlen == 0))
4803                 {
4804 #if DEBUG_TRANSPORT
4805                   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4806                               "NOT Disconnecting from `%4s', still have live address `%s'!\n",
4807                               GNUNET_i2s (&n->id),
4808                               a2s (peer_addresses->ready_list->plugin->short_name,
4809                                    peer_addresses->addr,
4810                                    peer_addresses->addrlen));
4811 #endif
4812                   return;             /* still connected */
4813                 }
4814               peer_addresses = peer_addresses->next;
4815             }
4816           rpos = rpos->next;
4817         }
4818     }
4819 #if DEBUG_TRANSPORT
4820   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4821               "Disconnecting from `%4s'\n",
4822               GNUNET_i2s (&n->id));
4823 #endif
4824
4825   /* remove n from neighbours list */
4826   nprev = NULL;
4827   npos = neighbours;
4828   while ((npos != NULL) && (npos != n))
4829     {
4830       nprev = npos;
4831       npos = npos->next;
4832     }
4833   GNUNET_assert (npos != NULL);
4834   if (nprev == NULL)
4835     neighbours = n->next;
4836   else
4837     nprev->next = n->next;
4838
4839   /* notify all clients about disconnect */
4840   if (GNUNET_YES == n->received_pong)
4841     notify_clients_disconnect (&n->id);
4842
4843   ats_modify_problem_state(ats, ATS_MODIFIED);
4844
4845   /* clean up all plugins, cancel connections and pending transmissions */
4846   while (NULL != (rpos = n->plugins))
4847     {
4848       n->plugins = rpos->next;
4849       rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
4850       while (rpos->addresses != NULL)
4851         {
4852           peer_pos = rpos->addresses;
4853           rpos->addresses = peer_pos->next;
4854           if (peer_pos->connected == GNUNET_YES)
4855             GNUNET_STATISTICS_update (stats,
4856                                       gettext_noop ("# connected addresses"),
4857                                       -1,
4858                                       GNUNET_NO);
4859           if (GNUNET_YES == peer_pos->validated)
4860             GNUNET_STATISTICS_update (stats,
4861                                       gettext_noop ("# peer addresses considered valid"),
4862                                       -1,
4863                                       GNUNET_NO);
4864           if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
4865             {
4866               GNUNET_SCHEDULER_cancel (peer_pos->revalidate_task);
4867               peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
4868             }
4869           GNUNET_free(peer_pos->ressources);
4870           peer_pos->ressources = NULL;
4871           GNUNET_free(peer_pos->quality);
4872           peer_pos->ressources = NULL;
4873           GNUNET_free(peer_pos);
4874         }
4875       GNUNET_free (rpos);
4876     }
4877
4878   /* free all messages on the queue */
4879   while (NULL != (mq = n->messages_head))
4880     {
4881       GNUNET_STATISTICS_update (stats,
4882                                 gettext_noop ("# bytes in message queue for other peers"),
4883                                 - (int64_t) mq->message_buf_size,
4884                                 GNUNET_NO);
4885       GNUNET_STATISTICS_update (stats,
4886                                 gettext_noop ("# bytes discarded due to disconnect"),
4887                                 mq->message_buf_size,
4888                                 GNUNET_NO);
4889       GNUNET_CONTAINER_DLL_remove (n->messages_head,
4890                                    n->messages_tail,
4891                                    mq);
4892       GNUNET_assert (0 == memcmp(&mq->neighbour_id,
4893                                  &n->id,
4894                                  sizeof(struct GNUNET_PeerIdentity)));
4895       GNUNET_free (mq);
4896     }
4897
4898   while (NULL != (mq = n->cont_head))
4899     {
4900
4901       GNUNET_CONTAINER_DLL_remove (n->cont_head,
4902                                    n->cont_tail,
4903                                    mq);
4904       GNUNET_assert (0 == memcmp(&mq->neighbour_id,
4905                                  &n->id,
4906                                  sizeof(struct GNUNET_PeerIdentity)));
4907       GNUNET_free (mq);
4908     }
4909
4910   if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
4911     {
4912       GNUNET_SCHEDULER_cancel (n->timeout_task);
4913       n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
4914     }
4915   if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4916     {
4917       GNUNET_SCHEDULER_cancel (n->retry_task);
4918       n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4919     }
4920   if (n->piter != NULL)
4921     {
4922       GNUNET_PEERINFO_iterate_cancel (n->piter);
4923       GNUNET_STATISTICS_update (stats,
4924                                 gettext_noop ("# outstanding peerinfo iterate requests"),
4925                                 -1,
4926                                 GNUNET_NO);
4927       n->piter = NULL;
4928     }
4929   /* finally, free n itself */
4930   GNUNET_STATISTICS_update (stats,
4931                             gettext_noop ("# active neighbours"),
4932                             -1,
4933                             GNUNET_NO);
4934   GNUNET_free_non_null (n->pre_connect_message_buffer);
4935   GNUNET_free (n);
4936 }
4937
4938
4939 /**
4940  * We have received a PING message from someone.  Need to send a PONG message
4941  * in response to the peer by any means necessary.
4942  */
4943 static int
4944 handle_ping (void *cls, const struct GNUNET_MessageHeader *message,
4945              const struct GNUNET_PeerIdentity *peer,
4946              struct Session *session,
4947              const char *sender_address,
4948              uint16_t sender_address_len)
4949 {
4950   struct TransportPlugin *plugin = cls;
4951   struct SessionHeader *session_header = (struct SessionHeader*) session;
4952   struct TransportPingMessage *ping;
4953   struct TransportPongMessage *pong;
4954   struct NeighbourList *n;
4955   struct ReadyList *rl;
4956   struct ForeignAddressList *fal;
4957   struct OwnAddressList *oal;
4958   const char *addr;
4959   size_t alen;
4960   size_t slen;
4961   int did_pong;
4962
4963   if (ntohs (message->size) < sizeof (struct TransportPingMessage))
4964     {
4965       GNUNET_break_op (0);
4966       return GNUNET_SYSERR;
4967     }
4968
4969   ping = (struct TransportPingMessage *) message;
4970   if (0 != memcmp (&ping->target,
4971                    plugin->env.my_identity,
4972                    sizeof (struct GNUNET_PeerIdentity)))
4973     {
4974 #if DEBUG_TRANSPORT
4975       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4976                   _("Received `%s' message from `%s' destined for `%s' which is not me!\n"),
4977                   "PING",
4978                   (sender_address != NULL)
4979                   ? a2s (plugin->short_name,
4980                          (const struct sockaddr *)sender_address,
4981                          sender_address_len)
4982                   : "<inbound>",
4983                   GNUNET_i2s (&ping->target));
4984 #endif
4985       return GNUNET_SYSERR;
4986     }
4987 #if DEBUG_PING_PONG
4988   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4989               "Processing `%s' from `%s'\n",
4990               "PING",
4991               (sender_address != NULL)
4992               ? a2s (plugin->short_name,
4993                      (const struct sockaddr *)sender_address,
4994                      sender_address_len)
4995               : "<inbound>");
4996 #endif
4997   GNUNET_STATISTICS_update (stats,
4998                             gettext_noop ("# PING messages received"),
4999                             1,
5000                             GNUNET_NO);
5001   addr = (const char*) &ping[1];
5002   alen = ntohs (message->size) - sizeof (struct TransportPingMessage);
5003   slen = strlen (plugin->short_name) + 1;
5004   if (alen == 0)
5005     {
5006       /* peer wants to confirm that we have an outbound connection to him */
5007       if (session == NULL)
5008         {
5009           GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5010                       _("Refusing to create PONG since I do not have a session with `%s'.\n"),
5011                       GNUNET_i2s (peer));
5012           return GNUNET_SYSERR;
5013         }
5014       /* FIXME-urg: the use of 'sender_address' in the code below is doubly-wrong:
5015         1) it is NULL when we need to have a real value
5016         2) it is documented to be the address of the sender (source-IP), where
5017         what we actually want is our LISTEN IP (what we 'bound' to); which we don't even
5018         have...
5019       */
5020       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5021                   "Creating PONG indicating that we received a connection at our address `%s' from `%s'.\n",
5022                   a2s (plugin->short_name,
5023                        sender_address,
5024                        sender_address_len),                    
5025                   GNUNET_i2s (peer));
5026
5027       pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len + slen);
5028       pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len + slen);
5029       pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
5030       pong->purpose.size =
5031         htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
5032                sizeof (uint32_t) +
5033                sizeof (struct GNUNET_TIME_AbsoluteNBO) +
5034                sizeof (struct GNUNET_PeerIdentity) + sender_address_len + slen);
5035       pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING);
5036       pong->challenge = ping->challenge;
5037       pong->addrlen = htonl(sender_address_len + slen);
5038       memcpy(&pong->pid,
5039              peer,
5040              sizeof(struct GNUNET_PeerIdentity));
5041       memcpy (&pong[1],
5042               plugin->short_name,
5043               slen);
5044       if ((sender_address!=NULL) && (sender_address_len > 0))
5045                   memcpy (&((char*)&pong[1])[slen],
5046                           sender_address,
5047                           sender_address_len);
5048       if (GNUNET_TIME_absolute_get_remaining (session_header->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4)
5049         {
5050           /* create / update cached sig */
5051 #if DEBUG_TRANSPORT
5052           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5053                       "Creating PONG signature to indicate active connection.\n");
5054 #endif
5055           session_header->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
5056           pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
5057           GNUNET_assert (GNUNET_OK ==
5058                          GNUNET_CRYPTO_rsa_sign (my_private_key,
5059                                                  &pong->purpose,
5060                                                  &session_header->pong_signature));
5061         }
5062       else
5063         {
5064           pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
5065         }
5066       memcpy (&pong->signature,
5067               &session_header->pong_signature,
5068               sizeof (struct GNUNET_CRYPTO_RsaSignature));
5069
5070
5071     }
5072   else
5073     {
5074       /* peer wants to confirm that this is one of our addresses */
5075       addr += slen;
5076       alen -= slen;
5077       if (GNUNET_OK !=
5078           plugin->api->check_address (plugin->api->cls,
5079                                       addr,
5080                                       alen))
5081         {
5082           GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5083                       _("Not confirming PING with address `%s' since I cannot confirm having this address.\n"),
5084                       a2s (plugin->short_name,
5085                            addr,
5086                            alen));
5087           return GNUNET_NO;
5088         }
5089       oal = plugin->addresses;
5090       while (NULL != oal)
5091         {
5092           if ( (oal->addrlen == alen) &&
5093                (0 == memcmp (addr,
5094                              &oal[1],
5095                              alen)) )
5096             break;
5097           oal = oal->next;
5098         }
5099       pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + alen + slen);
5100       pong->header.size = htons (sizeof (struct TransportPongMessage) + alen + slen);
5101       pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
5102       pong->purpose.size =
5103         htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
5104                sizeof (uint32_t) +
5105                sizeof (struct GNUNET_TIME_AbsoluteNBO) +
5106                sizeof (struct GNUNET_PeerIdentity) + alen + slen);
5107       pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN);
5108       pong->challenge = ping->challenge;
5109       pong->addrlen = htonl(alen + slen);
5110       memcpy(&pong->pid,
5111              &my_identity,
5112              sizeof(struct GNUNET_PeerIdentity));
5113       memcpy (&pong[1], plugin->short_name, slen);
5114       memcpy (&((char*)&pong[1])[slen], addr, alen);
5115       if ( (oal != NULL) &&
5116            (GNUNET_TIME_absolute_get_remaining (oal->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4) )
5117         {
5118           /* create / update cached sig */
5119 #if DEBUG_TRANSPORT
5120           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5121                       "Creating PONG signature to indicate ownership.\n");
5122 #endif
5123           oal->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
5124           pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
5125           GNUNET_assert (GNUNET_OK ==
5126                          GNUNET_CRYPTO_rsa_sign (my_private_key,
5127                                                  &pong->purpose,
5128                                                  &oal->pong_signature));
5129           memcpy (&pong->signature,
5130                   &oal->pong_signature,
5131                   sizeof (struct GNUNET_CRYPTO_RsaSignature));
5132         }
5133       else if (oal == NULL)
5134         {
5135           /* not using cache (typically DV-only) */
5136           pong->expiration = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
5137           GNUNET_assert (GNUNET_OK ==
5138                          GNUNET_CRYPTO_rsa_sign (my_private_key,
5139                                                  &pong->purpose,
5140                                                  &pong->signature));
5141         }
5142       else
5143         {
5144           /* can used cached version */
5145           pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
5146           memcpy (&pong->signature,
5147                   &oal->pong_signature,
5148                   sizeof (struct GNUNET_CRYPTO_RsaSignature));
5149         }
5150     }
5151   n = find_neighbour(peer);
5152   GNUNET_assert (n != NULL);
5153   did_pong = GNUNET_NO;
5154   /* first try reliable response transmission */
5155   rl = n->plugins;
5156   while (rl != NULL)
5157     {
5158       fal = rl->addresses;
5159       while (fal != NULL)
5160         {
5161           if (-1 != rl->plugin->api->send (rl->plugin->api->cls,
5162                                            peer,
5163                                            (const char*) pong,
5164                                            ntohs (pong->header.size),
5165                                            TRANSPORT_PONG_PRIORITY,
5166                                            HELLO_VERIFICATION_TIMEOUT,
5167                                            fal->session,
5168                                            fal->addr,
5169                                            fal->addrlen,
5170                                            GNUNET_SYSERR,
5171                                            NULL, NULL))
5172             {
5173               GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5174                           "Transmitted PONG to `%s' via reliable mechanism\n",
5175                           GNUNET_i2s (peer));
5176               /* done! */
5177               GNUNET_STATISTICS_update (stats,
5178                                         gettext_noop ("# PONGs unicast via reliable transport"),
5179                                         1,
5180                                         GNUNET_NO);
5181               GNUNET_free (pong);
5182               return GNUNET_OK;
5183             }
5184           did_pong = GNUNET_YES;
5185           fal = fal->next;
5186         }
5187       rl = rl->next;
5188     }
5189   /* no reliable method found, do multicast */
5190   GNUNET_STATISTICS_update (stats,
5191                             gettext_noop ("# PONGs multicast to all available addresses"),
5192                             1,
5193                             GNUNET_NO);
5194   rl = n->plugins;
5195   while (rl != NULL)
5196     {
5197       fal = rl->addresses;
5198       while (fal != NULL)
5199         {
5200           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5201                       "Transmitting PONG to `%s' via unreliable mechanism `%s':%s\n",
5202                       GNUNET_i2s (peer),
5203                       a2s (rl->plugin->short_name,
5204                            fal->addr,
5205                            fal->addrlen),
5206                       rl->plugin->short_name);
5207           transmit_to_peer(NULL, fal,
5208                            TRANSPORT_PONG_PRIORITY,
5209                            HELLO_VERIFICATION_TIMEOUT,
5210                            (const char *)pong,
5211                            ntohs(pong->header.size),
5212                            GNUNET_YES,
5213                            n);
5214           did_pong = GNUNET_YES;
5215           fal = fal->next;
5216         }
5217       rl = rl->next;
5218     }
5219   GNUNET_free(pong);
5220   if (GNUNET_YES != did_pong)
5221     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5222                 _("Could not send PONG to `%s': no address available\n"),
5223                 GNUNET_i2s (peer));
5224   return GNUNET_OK;
5225 }
5226
5227
5228 /**
5229  * Function called by the plugin for each received message.  Update
5230  * data volumes, possibly notify plugins about reducing the rate at
5231  * which they read from the socket and generally forward to our
5232  * receive callback.
5233  *
5234  * @param cls the "struct TransportPlugin *" we gave to the plugin
5235  * @param peer (claimed) identity of the other peer
5236  * @param message the message, NULL if we only care about
5237  *                learning about the delay until we should receive again
5238  * @param ats_data information for automatic transport selection
5239  * @param ats_count number of elements in ats not including 0-terminator
5240  * @param session identifier used for this session (can be NULL)
5241  * @param sender_address binary address of the sender (if observed)
5242  * @param sender_address_len number of bytes in sender_address
5243  * @return how long in ms the plugin should wait until receiving more data
5244  *         (plugins that do not support this, can ignore the return value)
5245  */
5246 static struct GNUNET_TIME_Relative
5247 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
5248                     const struct GNUNET_MessageHeader *message,
5249                     const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
5250                     uint32_t ats_count,
5251                     struct Session *session,
5252                     const char *sender_address,
5253                     uint16_t sender_address_len)
5254 {
5255   struct TransportPlugin *plugin = cls;
5256   struct ReadyList *service_context;
5257   struct ForeignAddressList *peer_address;
5258   uint16_t msize;
5259   struct NeighbourList *n;
5260   struct GNUNET_TIME_Relative ret;
5261   uint32_t distance;
5262   int c;
5263
5264   if (0 == memcmp (peer,
5265                    &my_identity,
5266                    sizeof (struct GNUNET_PeerIdentity)))
5267     {
5268       /* refuse to receive from myself */
5269       GNUNET_break (0); 
5270       return GNUNET_TIME_UNIT_FOREVER_REL;
5271     }
5272   if (is_blacklisted (peer, plugin))
5273     return GNUNET_TIME_UNIT_FOREVER_REL;
5274   n = find_neighbour (peer);
5275   if (n == NULL)
5276     n = setup_new_neighbour (peer, GNUNET_YES);
5277   service_context = n->plugins;
5278   while ((service_context != NULL) && (plugin != service_context->plugin))
5279     service_context = service_context->next;
5280   GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
5281   peer_address = NULL;
5282   distance = 1;
5283
5284   for (c=0; c<ats_count; c++)
5285     if (ntohl(ats_data[c].type) == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
5286       distance = ntohl(ats_data[c].value);
5287
5288
5289   if (message != NULL)
5290     {
5291       if ( (session != NULL) ||
5292            (sender_address != NULL) )
5293         peer_address = add_peer_address (n,
5294                                          plugin->short_name,
5295                                          session,
5296                                          sender_address,
5297                                          sender_address_len);
5298       if (peer_address != NULL)
5299         {
5300           update_addr_ats(peer_address, ats_data, ats_count);
5301           update_addr_value(peer_address, distance, GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5302           
5303           peer_address->distance = distance;
5304           if (GNUNET_YES == peer_address->validated)
5305             mark_address_connected (peer_address);
5306           peer_address->timeout
5307             = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5308           schedule_next_ping (peer_address);
5309         }
5310       /* update traffic received amount ... */
5311       msize = ntohs (message->size);
5312
5313       GNUNET_STATISTICS_update (stats,
5314                                 gettext_noop ("# bytes received from other peers"),
5315                                 msize,
5316                                 GNUNET_NO);
5317       n->distance = distance;
5318       n->peer_timeout =
5319         GNUNET_TIME_relative_to_absolute
5320         (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5321       GNUNET_SCHEDULER_cancel (n->timeout_task);
5322       n->timeout_task =
5323         GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
5324                                       &neighbour_timeout_task, n);
5325       if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
5326         {
5327           /* dropping message due to frequent inbound volume violations! */
5328           GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
5329                       GNUNET_ERROR_TYPE_BULK,
5330                       _
5331                       ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
5332                       n->in_tracker.available_bytes_per_s__,
5333                       n->quota_violation_count);
5334           GNUNET_STATISTICS_update (stats,
5335                                     gettext_noop ("# bandwidth quota violations by other peers"),
5336                                     1,
5337                                     GNUNET_NO);
5338           return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
5339         }
5340     if ((ntohs(message->type) == GNUNET_MESSAGE_TYPE_TRANSPORT_ATS) &&
5341         (ntohs(message->size) == (sizeof (struct GNUNET_MessageHeader) + sizeof (uint32_t))))
5342       {
5343         uint32_t value =  ntohl(*((uint32_t *) &message[1]));
5344         //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "GNUNET_MESSAGE_TYPE_TRANSPORT_ATS: %i \n", value);
5345         /* Force ressource and quality update */
5346         if ((value == 4) && (ats != NULL))
5347             ats_modify_problem_state(ats, ATS_QUALITY_COST_UPDATED);
5348         /* Force cost update */
5349         if ((value == 3) && (ats != NULL))
5350           ats_modify_problem_state(ats, ATS_COST_UPDATED);
5351         /* Force quality update */
5352         if ((value == 2) && (ats != NULL))
5353           ats_modify_problem_state(ats, ATS_QUALITY_UPDATED);
5354         /* Force full rebuild */
5355         if ((value == 1) && (ats != NULL))
5356           ats_modify_problem_state(ats, ATS_MODIFIED);
5357       }
5358     
5359 #if DEBUG_PING_PONG
5360     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5361                 "Received message of type %u and size %u from `%4s', sending to all clients.\n",
5362                 ntohs (message->type),
5363                 ntohs (message->size),
5364                 GNUNET_i2s (peer));
5365 #endif
5366       switch (ntohs (message->type))
5367         {
5368         case GNUNET_MESSAGE_TYPE_HELLO:
5369           GNUNET_STATISTICS_update (stats,
5370                                     gettext_noop ("# HELLO messages received from other peers"),
5371                                     1,
5372                                     GNUNET_NO);
5373           process_hello (plugin, message);
5374           break;
5375         case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
5376           handle_ping (plugin, message, peer, session, sender_address, sender_address_len);
5377           if (! n->received_pong)
5378             transmit_plain_ping (n);
5379           break;
5380         case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
5381           handle_pong (plugin, message, peer, sender_address, sender_address_len);
5382           break;
5383         case GNUNET_MESSAGE_TYPE_TRANSPORT_ATS:
5384           break;
5385         default:
5386           handle_payload_message (message, n);
5387           break;
5388         }
5389     }
5390   ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
5391   if (ret.rel_value > 0)
5392     {
5393 #if DEBUG_TRANSPORT 
5394       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5395                   "Throttling read (%llu bytes excess at %u b/s), waiting %llu ms before reading more.\n",
5396                   (unsigned long long) n->in_tracker.consumption_since_last_update__,
5397                   (unsigned int) n->in_tracker.available_bytes_per_s__,
5398                   (unsigned long long) ret.rel_value);
5399 #endif
5400       GNUNET_STATISTICS_update (stats,
5401                                 gettext_noop ("# ms throttling suggested"),
5402                                 (int64_t) ret.rel_value,
5403                                 GNUNET_NO);
5404     }
5405   return ret;
5406 }
5407
5408 /**
5409  * Handle START-message.  This is the first message sent to us
5410  * by any client which causes us to add it to our list.
5411  *
5412  * @param cls closure (always NULL)
5413  * @param client identification of the client
5414  * @param message the actual message
5415  */
5416 static void
5417 handle_start (void *cls,
5418               struct GNUNET_SERVER_Client *client,
5419               const struct GNUNET_MessageHeader *message)
5420 {
5421   const struct StartMessage *start;
5422   struct TransportClient *c;
5423   struct ConnectInfoMessage * cim;
5424   struct NeighbourList *n;
5425   uint32_t ats_count;
5426   size_t size;
5427
5428   start = (const struct StartMessage*) message;
5429 #if DEBUG_TRANSPORT
5430   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5431               "Received `%s' request from client\n", "START");
5432 #endif
5433   c = clients;
5434   while (c != NULL)
5435     {
5436       if (c->client == client)
5437         {
5438           /* client already on our list! */
5439           GNUNET_break (0);
5440           GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5441           return;
5442         }
5443       c = c->next;
5444     }
5445   if ( (GNUNET_NO != ntohl (start->do_check)) &&
5446        (0 != memcmp (&start->self,
5447                      &my_identity,
5448                      sizeof (struct GNUNET_PeerIdentity))) )
5449     {
5450       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5451                   _("Rejecting control connection from peer `%s', which is not me!\n"),
5452                   GNUNET_i2s (&start->self));
5453       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5454       return;
5455     }
5456   c = GNUNET_malloc (sizeof (struct TransportClient));
5457   c->next = clients;
5458   clients = c;
5459   c->client = client;
5460   if (our_hello != NULL)
5461     {
5462 #if DEBUG_TRANSPORT
5463       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5464                   "Sending our own `%s' to new client\n", "HELLO");
5465 #endif
5466       transmit_to_client (c,
5467                           (const struct GNUNET_MessageHeader *) our_hello,
5468                           GNUNET_NO);
5469       /* tell new client about all existing connections */
5470       ats_count = 2;
5471       size  = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
5472       if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
5473         {
5474           GNUNET_break(0);
5475         }
5476       cim = GNUNET_malloc (size);
5477       cim->header.size = htons (size);
5478       cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
5479       cim->ats_count = htonl(ats_count);
5480       (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
5481       (&(cim->ats))[2].value = htonl (0);
5482       n = neighbours;
5483       while (n != NULL)
5484         {
5485           if (GNUNET_YES == n->received_pong)
5486             {
5487               (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5488               (&(cim->ats))[0].value = htonl (n->distance);
5489               (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
5490               (&(cim->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
5491               cim->id = n->id;
5492               transmit_to_client (c, &cim->header, GNUNET_NO);
5493             }
5494           n = n->next;
5495         }
5496       GNUNET_free (cim);
5497     }
5498   else
5499     {
5500 #if DEBUG_TRANSPORT_HELLO
5501       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5502                   "No HELLO created yet, will transmit HELLO to client later!\n");
5503 #endif
5504       refresh_hello ();
5505     }
5506   GNUNET_SERVER_receive_done (client, GNUNET_OK);
5507 }
5508
5509
5510 /**
5511  * Handle HELLO-message.
5512  *
5513  * @param cls closure (always NULL)
5514  * @param client identification of the client
5515  * @param message the actual message
5516  */
5517 static void
5518 handle_hello (void *cls,
5519               struct GNUNET_SERVER_Client *client,
5520               const struct GNUNET_MessageHeader *message)
5521 {
5522   int ret;
5523
5524   GNUNET_STATISTICS_update (stats,
5525                             gettext_noop ("# HELLOs received from clients"),
5526                             1,
5527                             GNUNET_NO);
5528   ret = process_hello (NULL, message);
5529   GNUNET_SERVER_receive_done (client, ret);
5530 }
5531
5532
5533 /**
5534  * Closure for 'transmit_client_message'; followed by
5535  * 'msize' bytes of the actual message.
5536  */
5537 struct TransmitClientMessageContext
5538 {
5539   /**
5540    * Client on whom's behalf we are sending.
5541    */
5542   struct GNUNET_SERVER_Client *client;
5543
5544   /**
5545    * Timeout for the transmission.
5546    */
5547   struct GNUNET_TIME_Absolute timeout;
5548
5549   /**
5550    * Message priority.
5551    */
5552   uint32_t priority;
5553
5554   /**
5555    * Size of the message in bytes.
5556    */
5557   uint16_t msize;
5558 };
5559
5560
5561 /**
5562  * Schedule transmission of a message we got from a client to a peer.
5563  *
5564  * @param cls the 'struct TransmitClientMessageContext*'
5565  * @param n destination, or NULL on error (in that case, drop the message)
5566  */
5567 static void
5568 transmit_client_message (void *cls,
5569                          struct NeighbourList *n)
5570 {
5571   struct TransmitClientMessageContext *tcmc = cls;
5572   struct TransportClient *tc;
5573
5574   tc = clients;
5575   while ((tc != NULL) && (tc->client != tcmc->client))
5576     tc = tc->next;
5577
5578   if (n != NULL)
5579     {
5580       transmit_to_peer (tc, NULL, tcmc->priority,
5581                         GNUNET_TIME_absolute_get_remaining (tcmc->timeout),
5582                         (char *)&tcmc[1],
5583                         tcmc->msize, GNUNET_NO, n);
5584     }
5585   GNUNET_SERVER_receive_done (tcmc->client, GNUNET_OK);
5586   GNUNET_SERVER_client_drop (tcmc->client);
5587   GNUNET_free (tcmc);
5588 }
5589
5590
5591 /**
5592  * Handle SEND-message.
5593  *
5594  * @param cls closure (always NULL)
5595  * @param client identification of the client
5596  * @param message the actual message
5597  */
5598 static void
5599 handle_send (void *cls,
5600              struct GNUNET_SERVER_Client *client,
5601              const struct GNUNET_MessageHeader *message)
5602 {
5603   const struct OutboundMessage *obm;
5604   const struct GNUNET_MessageHeader *obmm;
5605   struct TransmitClientMessageContext *tcmc;
5606   uint16_t size;
5607   uint16_t msize;
5608
5609   size = ntohs (message->size);
5610   if (size <
5611       sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
5612     {
5613       GNUNET_break (0);
5614       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5615       return;
5616     }
5617   GNUNET_STATISTICS_update (stats,
5618                             gettext_noop ("# payload received for other peers"),
5619                             size,
5620                             GNUNET_NO);
5621   obm = (const struct OutboundMessage *) message;
5622   obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5623   msize = size - sizeof (struct OutboundMessage);
5624 #if DEBUG_TRANSPORT
5625   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5626               "Received `%s' request from client with target `%4s' and message of type %u and size %u\n",
5627               "SEND", GNUNET_i2s (&obm->peer),
5628               ntohs (obmm->type),
5629               msize);
5630 #endif
5631   tcmc = GNUNET_malloc (sizeof (struct TransmitClientMessageContext) + msize);
5632   tcmc->client = client;
5633   tcmc->priority = ntohl (obm->priority);
5634   tcmc->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
5635   tcmc->msize = msize;
5636   /* FIXME: this memcpy can be up to 7% of our total runtime */
5637   memcpy (&tcmc[1], obmm, msize);
5638   GNUNET_SERVER_client_keep (client);
5639   setup_peer_check_blacklist (&obm->peer, GNUNET_YES,
5640                               &transmit_client_message,
5641                               tcmc);
5642 }
5643
5644
5645 /**
5646  * Handle request connect message
5647  *
5648  * @param cls closure (always NULL)
5649  * @param client identification of the client
5650  * @param message the actual message
5651  */
5652 static void
5653 handle_request_connect (void *cls,
5654                         struct GNUNET_SERVER_Client *client,
5655                         const struct GNUNET_MessageHeader *message)
5656 {
5657   const struct TransportRequestConnectMessage *trcm =
5658     (const struct TransportRequestConnectMessage *) message;
5659
5660   GNUNET_STATISTICS_update (stats,
5661                             gettext_noop ("# REQUEST CONNECT messages received"),
5662                             1,
5663                             GNUNET_NO);
5664 #if DEBUG_TRANSPORT
5665   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, 
5666              "Received a request connect message for peer `%s'\n", 
5667              GNUNET_i2s(&trcm->peer));
5668 #endif
5669   setup_peer_check_blacklist (&trcm->peer, GNUNET_YES,
5670                               NULL, NULL);
5671   GNUNET_SERVER_receive_done (client, GNUNET_OK);
5672 }
5673
5674
5675 /**
5676  * Handle SET_QUOTA-message.
5677  *
5678  * @param cls closure (always NULL)
5679  * @param client identification of the client
5680  * @param message the actual message
5681  */
5682 static void
5683 handle_set_quota (void *cls,
5684                   struct GNUNET_SERVER_Client *client,
5685                   const struct GNUNET_MessageHeader *message)
5686 {
5687   const struct QuotaSetMessage *qsm =
5688     (const struct QuotaSetMessage *) message;
5689   struct NeighbourList *n;
5690
5691   GNUNET_STATISTICS_update (stats,
5692                             gettext_noop ("# SET QUOTA messages received"),
5693                             1,
5694                             GNUNET_NO);
5695   n = find_neighbour (&qsm->peer);
5696   if (n == NULL)
5697     {
5698       GNUNET_SERVER_receive_done (client, GNUNET_OK);
5699       GNUNET_STATISTICS_update (stats,
5700                                 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
5701                                 1,
5702                                 GNUNET_NO);
5703       return;
5704     }
5705 #if DEBUG_TRANSPORT 
5706   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5707               "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
5708               "SET_QUOTA",
5709               (unsigned int) ntohl (qsm->quota.value__),
5710               (unsigned int) n->in_tracker.available_bytes_per_s__,
5711               GNUNET_i2s (&qsm->peer));
5712 #endif
5713   GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
5714                                          qsm->quota);
5715   if (0 == ntohl (qsm->quota.value__))
5716     {
5717 #if DEBUG_TRANSPORT
5718       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5719                 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&n->id),
5720                 "SET_QUOTA");
5721 #endif
5722       GNUNET_STATISTICS_update (stats,
5723                                 gettext_noop ("# disconnects due to quota of 0"),
5724                                 1,
5725                                 GNUNET_NO);
5726       disconnect_neighbour (n, GNUNET_NO);
5727     }
5728   GNUNET_SERVER_receive_done (client, GNUNET_OK);
5729 }
5730
5731
5732 /**
5733  * Take the given address and append it to the set of results sent back to
5734  * the client.
5735  *
5736  * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
5737  * @param address the resolved name, NULL to indicate the last response
5738  */
5739 static void
5740 transmit_address_to_client (void *cls, const char *address)
5741 {
5742   struct GNUNET_SERVER_TransmitContext *tc = cls;
5743   size_t slen;
5744
5745   if (NULL != address)
5746     {
5747       slen = strlen (address) + 1;
5748       GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
5749                                                   GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5750     }
5751   else
5752     {
5753       GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5754     }
5755 }
5756
5757
5758 /**
5759  * Handle AddressLookup-message.
5760  *
5761  * @param cls closure (always NULL)
5762  * @param client identification of the client
5763  * @param message the actual message
5764  */
5765 static void
5766 handle_address_lookup (void *cls,
5767                        struct GNUNET_SERVER_Client *client,
5768                        const struct GNUNET_MessageHeader *message)
5769 {
5770   const struct AddressLookupMessage *alum;
5771   struct TransportPlugin *lsPlugin;
5772   const char *nameTransport;
5773   const char *address;
5774   uint16_t size;
5775   struct GNUNET_SERVER_TransmitContext *tc;
5776   struct GNUNET_TIME_Absolute timeout;
5777   struct GNUNET_TIME_Relative rtimeout;
5778   int32_t numeric;
5779
5780   size = ntohs (message->size);
5781   if (size < sizeof (struct AddressLookupMessage))
5782     {
5783       GNUNET_break_op (0);
5784       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5785       return;
5786     }
5787   alum = (const struct AddressLookupMessage *) message;
5788   uint32_t addressLen = ntohl (alum->addrlen);
5789   if (size <= sizeof (struct AddressLookupMessage) + addressLen)
5790     {
5791       GNUNET_break_op (0);
5792       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5793       return;
5794     }
5795   address = (const char *) &alum[1];
5796   nameTransport = (const char *) &address[addressLen];
5797   if (nameTransport
5798       [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
5799     {
5800       GNUNET_break_op (0);
5801       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5802       return;
5803     }
5804   timeout = GNUNET_TIME_absolute_ntoh (alum->timeout);
5805   rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
5806   numeric = ntohl (alum->numeric_only);
5807   lsPlugin = find_transport (nameTransport);
5808   if (NULL == lsPlugin)
5809     {
5810       tc = GNUNET_SERVER_transmit_context_create (client);
5811       GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5812                                                   GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5813       GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5814       return;
5815     }
5816   GNUNET_SERVER_disable_receive_done_warning (client);
5817   tc = GNUNET_SERVER_transmit_context_create (client);
5818   lsPlugin->api->address_pretty_printer (lsPlugin->api->cls,
5819                                          nameTransport,
5820                                          address, addressLen,
5821                                          numeric,
5822                                          rtimeout,
5823                                          &transmit_address_to_client, tc);
5824 }
5825
5826 /**
5827  * Handle AddressLookup-message.
5828  *
5829  * @param cls closure (always NULL)
5830  * @param client identification of the client
5831  * @param message the actual message
5832  */
5833 static void
5834 handle_peer_address_lookup (void *cls,
5835                        struct GNUNET_SERVER_Client *client,
5836                        const struct GNUNET_MessageHeader *message)
5837 {
5838   const struct PeerAddressLookupMessage *peer_address_lookup;
5839   struct NeighbourList *neighbor_iterator;
5840   struct ReadyList *ready_iterator;
5841   struct ForeignAddressList *foreign_address_iterator;
5842   struct TransportPlugin *transport_plugin;
5843
5844   uint16_t size;
5845   struct GNUNET_SERVER_TransmitContext *tc;
5846   struct GNUNET_TIME_Absolute timeout;
5847   struct GNUNET_TIME_Relative rtimeout;
5848   char *addr_buf;
5849
5850   size = ntohs (message->size);
5851   if (size < sizeof (struct PeerAddressLookupMessage))
5852     {
5853       GNUNET_break_op (0);
5854       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5855       return;
5856     }
5857   peer_address_lookup = (const struct PeerAddressLookupMessage *) message;
5858
5859   timeout = GNUNET_TIME_absolute_ntoh (peer_address_lookup->timeout);
5860   rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
5861
5862   neighbor_iterator = neighbours;
5863   while (neighbor_iterator != NULL)
5864     {
5865       if (0 == memcmp(&neighbor_iterator->id, &peer_address_lookup->peer, sizeof(struct GNUNET_PeerIdentity)))
5866         break;
5867       neighbor_iterator = neighbor_iterator->next;
5868     }
5869
5870   /* Found no neighbor matching this peer id (shouldn't be possible, but...) */
5871   if (neighbor_iterator == NULL)
5872     {
5873       GNUNET_break(0);
5874       tc = GNUNET_SERVER_transmit_context_create (client);
5875       GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5876                                                   GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5877       GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5878       return;
5879     }
5880
5881   ready_iterator = neighbor_iterator->plugins;
5882   GNUNET_SERVER_disable_receive_done_warning (client);
5883   tc = GNUNET_SERVER_transmit_context_create (client);
5884   while(ready_iterator != NULL)
5885     {
5886       foreign_address_iterator = ready_iterator->addresses;
5887       while (foreign_address_iterator != NULL)
5888         {
5889           transport_plugin = foreign_address_iterator->ready_list->plugin;
5890           if (foreign_address_iterator->addr != NULL)
5891             {
5892               GNUNET_asprintf (&addr_buf, "%s --- %s",
5893                                a2s (transport_plugin->short_name,
5894                                     foreign_address_iterator->addr,
5895                                     foreign_address_iterator->addrlen),
5896                                (foreign_address_iterator->connected
5897                                    == GNUNET_YES) ? "CONNECTED"
5898                                    : "DISCONNECTED");
5899               transmit_address_to_client(tc, addr_buf);
5900               GNUNET_free(addr_buf);
5901             }
5902
5903           foreign_address_iterator = foreign_address_iterator->next;
5904         }
5905       ready_iterator = ready_iterator->next;
5906     }
5907   GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5908                                               GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5909   GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5910 }
5911
5912
5913 /**
5914  * Setup the environment for this plugin.
5915  */
5916 static void
5917 create_environment (struct TransportPlugin *plug)
5918 {
5919   plug->env.cfg = cfg;
5920   plug->env.my_identity = &my_identity;
5921   plug->env.our_hello = &our_hello;
5922   plug->env.cls = plug;
5923   plug->env.receive = &plugin_env_receive;
5924   plug->env.notify_address = &plugin_env_notify_address;
5925   plug->env.session_end = &plugin_env_session_end;
5926   plug->env.max_connections = max_connect_per_transport;
5927   plug->env.stats = stats;
5928 }
5929
5930
5931 /**
5932  * Start the specified transport (load the plugin).
5933  */
5934 static void
5935 start_transport (struct GNUNET_SERVER_Handle *server,
5936                  const char *name)
5937 {
5938   struct TransportPlugin *plug;
5939   char *libname;
5940
5941   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5942               _("Loading `%s' transport plugin\n"), name);
5943   GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
5944   plug = GNUNET_malloc (sizeof (struct TransportPlugin));
5945   create_environment (plug);
5946   plug->short_name = GNUNET_strdup (name);
5947   plug->lib_name = libname;
5948   plug->next = plugins;
5949   plugins = plug;
5950   plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
5951   if (plug->api == NULL)
5952     {
5953       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5954                   _("Failed to load transport plugin for `%s'\n"), name);
5955       GNUNET_free (plug->short_name);
5956       plugins = plug->next;
5957       GNUNET_free (libname);
5958       GNUNET_free (plug);
5959     }
5960 }
5961
5962
5963 /**
5964  * Called whenever a client is disconnected.  Frees our
5965  * resources associated with that client.
5966  *
5967  * @param cls closure
5968  * @param client identification of the client
5969  */
5970 static void
5971 client_disconnect_notification (void *cls,
5972                                 struct GNUNET_SERVER_Client *client)
5973 {
5974   struct TransportClient *pos;
5975   struct TransportClient *prev;
5976   struct ClientMessageQueueEntry *mqe;
5977   struct Blacklisters *bl;
5978   struct BlacklistCheck *bc;
5979
5980   if (client == NULL)
5981     return;
5982 #if DEBUG_TRANSPORT
5983   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
5984               "Client disconnected, cleaning up.\n");
5985 #endif
5986   /* clean up blacklister */
5987   bl = bl_head;
5988   while (bl != NULL)
5989     {
5990       if (bl->client == client)
5991         {
5992           bc = bc_head;
5993           while (bc != NULL)
5994             {
5995               if (bc->bl_pos == bl)
5996                 {
5997                   bc->bl_pos = bl->next;
5998                   if (bc->th != NULL)
5999                     {
6000                       GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th);
6001                       bc->th = NULL;
6002                     }
6003                   if (bc->task == GNUNET_SCHEDULER_NO_TASK)
6004                     bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
6005                                                          bc);
6006                   break;
6007                 }
6008               bc = bc->next;
6009             }
6010           GNUNET_CONTAINER_DLL_remove (bl_head,
6011                                        bl_tail,
6012                                        bl);
6013           GNUNET_SERVER_client_drop (bl->client);
6014           GNUNET_free (bl);
6015           break;
6016         }
6017       bl = bl->next;
6018     }
6019   /* clean up 'normal' clients */
6020   prev = NULL;
6021   pos = clients;
6022   while ((pos != NULL) && (pos->client != client))
6023     {
6024       prev = pos;
6025       pos = pos->next;
6026     }
6027   if (pos == NULL)
6028     return;
6029   while (NULL != (mqe = pos->message_queue_head))
6030     {
6031       GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
6032                                    pos->message_queue_tail,
6033                                    mqe);
6034       pos->message_count--;
6035       GNUNET_free (mqe);
6036     }
6037   if (prev == NULL)
6038     clients = pos->next;
6039   else
6040     prev->next = pos->next;
6041   if (GNUNET_YES == pos->tcs_pending)
6042     {
6043       pos->client = NULL;
6044       return;
6045     }
6046   if (pos->th != NULL)
6047     {
6048       GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
6049       pos->th = NULL;
6050     }
6051   GNUNET_break (0 == pos->message_count);
6052   GNUNET_free (pos);
6053 }
6054
6055
6056 /**
6057  * Function called when the service shuts down.  Unloads our plugins
6058  * and cancels pending validations.
6059  *
6060  * @param cls closure, unused
6061  * @param tc task context (unused)
6062  */
6063 static void
6064 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
6065 {
6066   struct TransportPlugin *plug;
6067   struct TransportPlugin *tmp;
6068   struct OwnAddressList *al;
6069   struct CheckHelloValidatedContext *chvc;
6070
6071   shutdown_in_progress = GNUNET_YES;
6072   while (neighbours != NULL)
6073     {
6074 #if DEBUG_TRANSPORT
6075       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6076                   "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&neighbours->id),
6077                   "SHUTDOWN_TASK");
6078 #endif
6079       disconnect_neighbour (neighbours, GNUNET_NO);
6080     }
6081 #if DEBUG_TRANSPORT
6082   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6083               "Transport service is unloading plugins...\n");
6084 #endif
6085   plug = plugins;
6086   while (plug != NULL)
6087     {
6088       if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
6089         {
6090           GNUNET_SCHEDULER_cancel (plug->address_update_task);
6091           plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
6092         }
6093       GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
6094       GNUNET_free (plug->lib_name);
6095       GNUNET_free (plug->short_name);
6096       while (NULL != (al = plug->addresses))
6097         {
6098           plug->addresses = al->next;
6099           GNUNET_free (al);
6100         }
6101       tmp = plug->next;
6102       GNUNET_free (plug);
6103       plug = tmp;
6104     }
6105   if (my_private_key != NULL)
6106     GNUNET_CRYPTO_rsa_key_free (my_private_key);
6107   GNUNET_free_non_null (our_hello);
6108
6109   GNUNET_CONTAINER_multihashmap_iterate (validation_map,
6110                                          &abort_validation,
6111                                          NULL);
6112   GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6113   validation_map = NULL;
6114
6115
6116   if (ats_task != GNUNET_SCHEDULER_NO_TASK)
6117   {
6118     GNUNET_SCHEDULER_cancel(ats_task);
6119     ats_task = GNUNET_SCHEDULER_NO_TASK;
6120   }
6121   if (ats != NULL)
6122     ats_shutdown (ats);
6123
6124   /* free 'chvc' data structure */
6125   while (NULL != (chvc = chvc_head))
6126     {
6127       chvc_head = chvc->next;
6128       if (chvc->piter != NULL)
6129         {
6130           GNUNET_PEERINFO_iterate_cancel (chvc->piter);
6131           GNUNET_STATISTICS_update (stats,
6132                                     gettext_noop ("# outstanding peerinfo iterate requests"),
6133                                     -1,
6134                                     GNUNET_NO);
6135           chvc->ve_count --;
6136         }
6137       else
6138           GNUNET_break (0);
6139       GNUNET_assert (chvc->ve_count == 0);
6140       GNUNET_free (chvc);
6141     }
6142   chvc_tail = NULL;
6143
6144   if (stats != NULL)
6145     {
6146       GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6147       stats = NULL;
6148     }
6149   if (peerinfo != NULL)
6150     {
6151       GNUNET_PEERINFO_disconnect (peerinfo);
6152       peerinfo = NULL;
6153     }
6154   if (GNUNET_SCHEDULER_NO_TASK != hello_task)
6155     {
6156       GNUNET_SCHEDULER_cancel (hello_task);
6157       hello_task = GNUNET_SCHEDULER_NO_TASK;
6158     }
6159   /* Can we assume those are gone by now, or do we need to clean up
6160      explicitly!? */
6161   GNUNET_break (bl_head == NULL);
6162   GNUNET_break (bc_head == NULL);
6163 }
6164
6165
6166 void ats_result_cb ()
6167 {
6168   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6169       "ATS Result callback\n");
6170 }
6171
6172
6173 void create_ats_information ( struct ATS_peer **p,
6174                               int * c_p,
6175                               struct ATS_mechanism ** m,
6176                               int * c_m )
6177 {
6178 #if VERBOSE_ATS
6179   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6180       "ATS requires clean address information\n");
6181 #endif
6182   struct ATS_mechanism * mechanisms;
6183   struct ATS_peer *peers;
6184
6185   int connected_addresses = 0;
6186   int c_peers = 0;
6187   int c_mechs = 0;
6188   struct NeighbourList *next = neighbours;
6189
6190   while (next!=NULL)
6191   {
6192     int found_addresses = GNUNET_NO;
6193     struct ReadyList *r_next = next->plugins;
6194     while (r_next != NULL)
6195     {
6196         struct ForeignAddressList * a_next = r_next->addresses;
6197         while (a_next != NULL)
6198         {
6199             c_mechs++;
6200             found_addresses = GNUNET_YES;
6201             a_next = a_next->next;
6202         }
6203         r_next = r_next->next;
6204     }
6205     if (found_addresses) c_peers++;
6206     next = next->next;
6207   }
6208
6209 #if VERBOSE_ATS
6210   GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6211       "Found %u peers with % u transport mechanisms\n", c_peers, c_mechs);
6212 #endif
6213
6214   if ((c_peers == 0) && (c_mechs == 0))
6215   {
6216     peers = NULL;
6217     (*c_p) = 0;
6218     mechanisms = NULL;
6219     (*c_m) = 0;
6220     return;
6221   }
6222
6223   mechanisms = GNUNET_malloc((1+c_mechs) * sizeof (struct ATS_mechanism));
6224   peers =  GNUNET_malloc((1+c_peers) * sizeof (struct ATS_peer));
6225
6226   c_mechs = 1;
6227   c_peers = 1;
6228
6229   next = neighbours;
6230   while (next!=NULL)
6231   {
6232     int found_addresses = GNUNET_NO;
6233     struct ReadyList *r_next = next->plugins;
6234     while (r_next != NULL)
6235     {
6236         struct ForeignAddressList * a_next = r_next->addresses;
6237         while (a_next != NULL)
6238         {
6239             if (a_next->connected == GNUNET_YES)
6240               connected_addresses ++;
6241             if (found_addresses == GNUNET_NO)
6242             {
6243               peers[c_peers].peer = next->id;
6244               peers[c_peers].m_head = NULL;
6245               peers[c_peers].m_tail = NULL;
6246               peers[c_peers].f = 1.0 / c_mechs;
6247             }
6248
6249             mechanisms[c_mechs].addr = a_next;
6250             mechanisms[c_mechs].col_index = c_mechs;
6251             mechanisms[c_mechs].peer = &peers[c_peers];
6252             mechanisms[c_mechs].next = NULL;
6253             mechanisms[c_mechs].plugin = r_next->plugin;
6254             mechanisms[c_mechs].ressources = a_next->ressources;
6255             mechanisms[c_mechs].quality = a_next->quality;
6256
6257             GNUNET_CONTAINER_DLL_insert_tail(peers[c_peers].m_head,
6258                                              peers[c_peers].m_tail,
6259                                              &mechanisms[c_mechs]);
6260             found_addresses = GNUNET_YES;
6261             c_mechs++;
6262
6263             a_next = a_next->next;
6264         }
6265         r_next = r_next->next;
6266     }
6267     if (found_addresses == GNUNET_YES)
6268         c_peers++;
6269     next = next->next;
6270   }
6271   c_mechs--;
6272   c_peers--;
6273   (*c_m) = c_mechs;
6274   (*c_p) = c_peers;
6275   (*p) = peers;
6276   (*m) = mechanisms;
6277
6278   GNUNET_STATISTICS_set(stats,
6279                         gettext_noop ("# connected addresses"),
6280                         connected_addresses,
6281                         GNUNET_NO);
6282 }
6283
6284 static void
6285 schedule_ats (void *cls,
6286               const struct GNUNET_SCHEDULER_TaskContext *tc)
6287 {
6288   struct ATS_Handle *ats = (struct ATS_Handle *) cls;
6289   if (ats==NULL)
6290     return;
6291
6292   ats_task = GNUNET_SCHEDULER_NO_TASK;
6293   if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
6294       return;
6295
6296   if (shutdown_in_progress == GNUNET_YES)
6297           return;
6298
6299   struct GNUNET_TIME_Relative delta =
6300       GNUNET_TIME_absolute_get_difference (last_ats_execution, GNUNET_TIME_absolute_get());
6301   if (delta.rel_value < ats_minimum_interval.rel_value)
6302   {
6303 #if DEBUG_ATS
6304     GNUNET_log (GNUNET_ERROR_TYPE_BULK,
6305         "Minimum time between cycles not reached\n");
6306 #endif
6307     return;
6308   }
6309
6310 #if DEBUG_ATS
6311   GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Running scheduled calculation\n");
6312 #endif
6313   ats_calculate_bandwidth_distribution (ats, stats);
6314   last_ats_execution = GNUNET_TIME_absolute_get();
6315
6316   ats_task = GNUNET_SCHEDULER_add_delayed (ats_regular_interval,
6317                                   &schedule_ats, ats);
6318 }
6319
6320 struct ForeignAddressList * get_preferred_ats_address (
6321                 struct NeighbourList *n)
6322 {
6323   // TODO get ATS prefered address
6324   return find_ready_address(n);
6325 }
6326
6327 /**
6328  * Initiate transport service.
6329  *
6330  * @param cls closure
6331  * @param server the initialized server
6332  * @param c configuration to use
6333  */
6334 static void
6335 run (void *cls,
6336      struct GNUNET_SERVER_Handle *server,
6337      const struct GNUNET_CONFIGURATION_Handle *c)
6338 {
6339   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
6340     {&handle_start, NULL,
6341      GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)},
6342     {&handle_hello, NULL,
6343      GNUNET_MESSAGE_TYPE_HELLO, 0},
6344     {&handle_send, NULL,
6345      GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
6346     {&handle_request_connect, NULL,
6347      GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT, sizeof(struct TransportRequestConnectMessage)},
6348     {&handle_set_quota, NULL,
6349      GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
6350     {&handle_address_lookup, NULL,
6351      GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
6352      0},
6353     {&handle_peer_address_lookup, NULL,
6354      GNUNET_MESSAGE_TYPE_TRANSPORT_PEER_ADDRESS_LOOKUP,
6355      0},
6356     {&handle_blacklist_init, NULL,
6357      GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT, sizeof (struct GNUNET_MessageHeader)},
6358     {&handle_blacklist_reply, NULL,
6359      GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY, sizeof (struct BlacklistMessage)},
6360     {NULL, NULL, 0, 0}
6361   };
6362   char *plugs;
6363   char *pos;
6364   int no_transports;
6365   unsigned long long tneigh;
6366   char *keyfile;
6367
6368   shutdown_in_progress = GNUNET_NO;
6369   cfg = c;
6370   stats = GNUNET_STATISTICS_create ("transport", cfg);
6371   validation_map = GNUNET_CONTAINER_multihashmap_create (64);
6372   /* parse configuration */
6373   if ((GNUNET_OK !=
6374        GNUNET_CONFIGURATION_get_value_number (c,
6375                                               "TRANSPORT",
6376                                               "NEIGHBOUR_LIMIT",
6377                                               &tneigh)) ||
6378       (GNUNET_OK !=
6379        GNUNET_CONFIGURATION_get_value_filename (c,
6380                                                 "GNUNETD",
6381                                                 "HOSTKEY", &keyfile)))
6382     {
6383       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6384                   _
6385                   ("Transport service is lacking key configuration settings.  Exiting.\n"));
6386       GNUNET_SCHEDULER_shutdown ();
6387       if (stats != NULL)
6388         {
6389           GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6390           stats = NULL;
6391         }
6392       GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6393       validation_map = NULL;
6394       return;
6395     }
6396
6397   max_connect_per_transport = (uint32_t) tneigh;
6398   peerinfo = GNUNET_PEERINFO_connect (cfg);
6399   if (peerinfo == NULL)
6400     {
6401       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6402                   _("Could not access PEERINFO service.  Exiting.\n"));
6403       GNUNET_SCHEDULER_shutdown ();
6404       if (stats != NULL)
6405         {
6406           GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6407           stats = NULL;
6408         }
6409       GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6410       validation_map = NULL;
6411       GNUNET_free (keyfile);
6412       return;
6413     }
6414   my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
6415   GNUNET_free (keyfile);
6416   if (my_private_key == NULL)
6417     {
6418       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6419                   _
6420                   ("Transport service could not access hostkey.  Exiting.\n"));
6421       GNUNET_SCHEDULER_shutdown ();
6422       if (stats != NULL)
6423         {
6424           GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6425           stats = NULL;
6426         }
6427       GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6428       validation_map = NULL;
6429       return;
6430     }
6431   GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
6432   GNUNET_CRYPTO_hash (&my_public_key,
6433                       sizeof (my_public_key), &my_identity.hashPubKey);
6434   /* setup notification */
6435   GNUNET_SERVER_disconnect_notify (server,
6436                                    &client_disconnect_notification, NULL);
6437   /* load plugins... */
6438   no_transports = 1;
6439   if (GNUNET_OK ==
6440       GNUNET_CONFIGURATION_get_value_string (c,
6441                                              "TRANSPORT", "PLUGINS", &plugs))
6442     {
6443       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6444                   _("Starting transport plugins `%s'\n"), plugs);
6445       pos = strtok (plugs, " ");
6446       while (pos != NULL)
6447         {
6448           start_transport (server, pos);
6449           no_transports = 0;
6450           pos = strtok (NULL, " ");
6451         }
6452       GNUNET_free (plugs);
6453     }
6454   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
6455                                 &shutdown_task, NULL);
6456   if (no_transports)
6457     refresh_hello ();
6458
6459   /* Initializing ATS */
6460   int co;
6461   char * section;
6462   unsigned long long  value;
6463
6464   double D = 1.0;
6465   double U = 1.0;
6466   double R = 1.0;
6467   int v_b_min = 64000;
6468   int v_n_min = 5;
6469
6470   ats_minimum_interval = ATS_MIN_INTERVAL;
6471   ats_regular_interval = ATS_EXEC_INTERVAL;
6472
6473   /* loading cost ressources */
6474   for (co=0; co<available_ressources; co++)
6475   {
6476     GNUNET_asprintf(&section,"%s_UP",ressources[co].cfg_param);
6477     if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
6478     {
6479       if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg,
6480           "transport",
6481           section,
6482           &value))
6483       {
6484 #if DEBUG_ATS
6485               GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6486                   "Found ressource cost: [%s] = %llu\n",
6487                   section, value);
6488 #endif
6489               ressources[co].c_max = value;
6490       }
6491     }
6492     GNUNET_free (section);
6493     GNUNET_asprintf(&section,"%s_DOWN",ressources[co].cfg_param);
6494     if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
6495     {
6496       if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg,
6497           "transport",
6498           section,
6499           &value))
6500       {
6501 #if DEBUG_ATS
6502               GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6503                   "Found ressource cost: [%s] = %llu\n",
6504                   section, value);
6505 #endif
6506               ressources[co].c_min = value;
6507       }
6508     }
6509     GNUNET_free (section);
6510   }
6511
6512   ats = ats_init (D, U, R, v_b_min, v_n_min,
6513                   ATS_MAX_ITERATIONS, ATS_MAX_EXEC_DURATION,
6514                   create_ats_information,
6515                   ats_result_cb);
6516
6517   int log_problem = GNUNET_NO;
6518   int log_solution = GNUNET_NO;
6519   int overwrite_dump = GNUNET_NO;
6520   int minimum_peers = 0;
6521   int minimum_addresses = 0;
6522
6523   if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_MLP"))
6524     log_problem = GNUNET_CONFIGURATION_get_value_yesno (cfg,
6525                              "transport","DUMP_MLP");
6526
6527   if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_SOLUTION"))
6528     log_solution = GNUNET_CONFIGURATION_get_value_yesno (cfg,
6529                                   "transport","DUMP_SOLUTION");
6530   if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_OVERWRITE"))
6531     overwrite_dump = GNUNET_CONFIGURATION_get_value_yesno (cfg,
6532                                   "transport","DUMP_OVERWRITE");
6533   if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_MIN_PEERS"))
6534   {
6535           GNUNET_CONFIGURATION_get_value_number(cfg,
6536               "transport","DUMP_MIN_PEERS", &value);
6537           minimum_peers = value;
6538   }
6539   if (GNUNET_CONFIGURATION_have_value(cfg,
6540       "transport", "DUMP_MIN_ADDRS"))
6541   {
6542       GNUNET_CONFIGURATION_get_value_number(cfg,
6543         "transport","DUMP_MIN_ADDRS", &value);
6544       minimum_addresses= value;
6545   }
6546   if (GNUNET_CONFIGURATION_have_value(cfg,
6547       "transport", "DUMP_OVERWRITE"))
6548   {
6549       GNUNET_CONFIGURATION_get_value_number(cfg,
6550           "transport","DUMP_OVERWRITE", &value);
6551       overwrite_dump = value;
6552   }
6553
6554   if (GNUNET_CONFIGURATION_have_value(cfg,
6555       "transport", "ATS_MIN_INTERVAL"))
6556   {
6557       GNUNET_CONFIGURATION_get_value_number(cfg,
6558           "transport","ATS_MIN_INTERVAL", &value);
6559       ats_minimum_interval.rel_value = value;
6560   }
6561
6562   if (GNUNET_CONFIGURATION_have_value(cfg,
6563       "transport", "ATS_EXEC_INTERVAL"))
6564   {
6565       GNUNET_CONFIGURATION_get_value_number(cfg,
6566           "transport","ATS_EXEC_INTERVAL", &value);
6567       ats_regular_interval.rel_value = value;
6568   }
6569   if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "ATS_MIN_INTERVAL"))
6570   {
6571       GNUNET_CONFIGURATION_get_value_number(cfg,
6572           "transport","ATS_MIN_INTERVAL", &value);
6573       ats_minimum_interval.rel_value = value;
6574   }
6575
6576   ats_set_logging_options (ats,
6577                           minimum_addresses,
6578                           minimum_peers,
6579                           overwrite_dump,
6580                           log_solution,
6581                           log_problem);
6582
6583   if (ats != NULL)
6584     ats_task = GNUNET_SCHEDULER_add_now (&schedule_ats, ats);
6585
6586
6587
6588
6589 #if DEBUG_TRANSPORT
6590   GNUNET_log (GNUNET_ERROR_TYPE_INFO, 
6591               _("Transport service ready.\n"));
6592 #endif
6593   /* If we have a blacklist file, read from it */
6594   read_blacklist_file(cfg);
6595   /* process client requests */
6596   GNUNET_SERVER_add_handlers (server, handlers);
6597 }
6598
6599
6600 /**
6601  * The main function for the transport service.
6602  *
6603  * @param argc number of arguments from the command line
6604  * @param argv command line arguments
6605  * @return 0 ok, 1 on error
6606  */
6607 int
6608 main (int argc, char *const *argv)
6609 {
6610   a2s (NULL, NULL, 0); /* make compiler happy */
6611   return (GNUNET_OK ==
6612           GNUNET_SERVICE_run (argc,
6613                               argv,
6614                               "transport",
6615                               GNUNET_SERVICE_OPTION_NONE,
6616                               &run, NULL)) ? 0 : 1;
6617 }
6618
6619 /* end of gnunet-service-transport.c */