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