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