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