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