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