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