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