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