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