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