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