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