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