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