fixing #1632
[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, can be NULL (on failure)
1383  * @param target target of the transmission
1384  * @param result status code for the transmission request
1385  */
1386 static void
1387 transmit_send_ok (struct TransportClient *client,
1388                   struct NeighbourList *n,
1389                   const struct GNUNET_PeerIdentity *target,
1390                   int result)
1391 {
1392   struct SendOkMessage send_ok_msg;
1393
1394   send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1395   send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1396   send_ok_msg.success = htonl (result);
1397   if (n != NULL)
1398     send_ok_msg.latency = GNUNET_TIME_relative_hton (n->latency);
1399   else
1400     send_ok_msg.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_FOREVER_REL);
1401   send_ok_msg.peer = *target;
1402   transmit_to_client (client, &send_ok_msg.header, GNUNET_NO);
1403 }
1404
1405
1406 /**
1407  * Function called by the GNUNET_TRANSPORT_TransmitFunction
1408  * upon "completion" of a send request.  This tells the API
1409  * that it is now legal to send another message to the given
1410  * peer.
1411  *
1412  * @param cls closure, identifies the entry on the
1413  *            message queue that was transmitted and the
1414  *            client responsible for queuing the message
1415  * @param target the peer receiving the message
1416  * @param result GNUNET_OK on success, if the transmission
1417  *           failed, we should not tell the client to transmit
1418  *           more messages
1419  */
1420 static void
1421 transmit_send_continuation (void *cls,
1422                             const struct GNUNET_PeerIdentity *target,
1423                             int result)
1424 {
1425   struct MessageQueue *mq = cls;
1426   struct NeighbourList *n;
1427
1428   GNUNET_STATISTICS_update (stats,
1429                             gettext_noop ("# bytes pending with plugins"),
1430                             - (int64_t) mq->message_buf_size,
1431                             GNUNET_NO);
1432   if (result == GNUNET_OK)
1433     {
1434       GNUNET_STATISTICS_update (stats,
1435                                 gettext_noop ("# bytes successfully transmitted by plugins"),
1436                                 mq->message_buf_size,
1437                                 GNUNET_NO);
1438     }
1439   else
1440     {
1441       GNUNET_STATISTICS_update (stats,
1442                                 gettext_noop ("# bytes with transmission failure by plugins"),
1443                                 mq->message_buf_size,
1444                                 GNUNET_NO);
1445     }
1446   if (mq->specific_address != NULL)
1447     {
1448       if (result == GNUNET_OK)
1449         {
1450           mq->specific_address->timeout =
1451             GNUNET_TIME_relative_to_absolute
1452             (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1453           if (mq->specific_address->validated == GNUNET_YES)
1454             mark_address_connected (mq->specific_address);
1455         }
1456       else
1457         {
1458           if (mq->specific_address->connected != GNUNET_NO)
1459             {
1460 #if DEBUG_TRANSPORT
1461               GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1462                           "Marking address `%s' as no longer connected (due to transmission problem)\n",
1463                           a2s (mq->specific_address->ready_list->plugin->short_name,
1464                                mq->specific_address->addr,
1465                                mq->specific_address->addrlen));
1466 #endif
1467               GNUNET_STATISTICS_update (stats,
1468                                         gettext_noop ("# connected addresses"),
1469                                         -1,
1470                                         GNUNET_NO);
1471               mq->specific_address->connected = GNUNET_NO;
1472             }
1473         }
1474       if (! mq->internal_msg)
1475         mq->specific_address->in_transmit = GNUNET_NO;
1476     }
1477   n = find_neighbour(&mq->neighbour_id);
1478   if (mq->client != NULL)
1479     transmit_send_ok (mq->client, n, target, result);
1480   GNUNET_free (mq);
1481   if (n != NULL)
1482     try_transmission_to_peer (n);
1483 }
1484
1485
1486 /**
1487  * Find an address in any of the available transports for
1488  * the given neighbour that would be good for message
1489  * transmission.  This is essentially the transport selection
1490  * routine.
1491  *
1492  * @param neighbour for whom to select an address
1493  * @return selected address, NULL if we have none
1494  */
1495 struct ForeignAddressList *
1496 find_ready_address(struct NeighbourList *neighbour)
1497 {
1498   struct ReadyList *head = neighbour->plugins;
1499   struct ForeignAddressList *addresses;
1500   struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1501   struct ForeignAddressList *best_address;
1502
1503   best_address = NULL;
1504   while (head != NULL)
1505     {
1506       addresses = head->addresses;
1507       while (addresses != NULL)
1508         {
1509           if ( (addresses->timeout.abs_value < now.abs_value) &&
1510                (addresses->connected == GNUNET_YES) )
1511             {
1512 #if DEBUG_TRANSPORT
1513               GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1514                           "Marking long-time inactive connection to `%4s' as down.\n",
1515                           GNUNET_i2s (&neighbour->id));
1516 #endif
1517               GNUNET_STATISTICS_update (stats,
1518                                         gettext_noop ("# connected addresses"),
1519                                         -1,
1520                                         GNUNET_NO);
1521               addresses->connected = GNUNET_NO;
1522             }
1523           addresses = addresses->next;
1524         }
1525
1526       addresses = head->addresses;
1527       while (addresses != NULL)
1528         {
1529 #if DEBUG_TRANSPORT > 1
1530           if (addresses->addr != NULL)
1531             GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1532                         "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
1533                         a2s (head->plugin->short_name,
1534                              addresses->addr,
1535                              addresses->addrlen),
1536                         GNUNET_i2s (&neighbour->id),
1537                         addresses->connected,
1538                         addresses->in_transmit,
1539                         addresses->validated,
1540                         addresses->connect_attempts,
1541                         (unsigned long long) addresses->timeout.abs_value,
1542                         (unsigned int) addresses->distance);
1543 #endif
1544           if ( ( (best_address == NULL) ||
1545                  (addresses->connected == GNUNET_YES) ||
1546                  (best_address->connected == GNUNET_NO) ) &&
1547                (addresses->in_transmit == GNUNET_NO) &&
1548                ( (best_address == NULL) ||
1549                  (addresses->latency.rel_value < best_address->latency.rel_value)) )
1550             best_address = addresses;
1551           /* FIXME: also give lower-latency addresses that are not
1552              connected a chance some times... */
1553           addresses = addresses->next;
1554         }
1555       head = head->next;
1556     }
1557   if (best_address != NULL)
1558     {
1559 #if DEBUG_TRANSPORT
1560       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1561                   "Best address found (`%s') has latency of %llu ms.\n",
1562                   (best_address->addrlen > 0)
1563                   ? a2s (best_address->ready_list->plugin->short_name,
1564                        best_address->addr,
1565                        best_address->addrlen)
1566                   : "<inbound>",
1567                   best_address->latency.rel_value);
1568 #endif
1569     }
1570   else
1571     {
1572       GNUNET_STATISTICS_update (stats,
1573                                 gettext_noop ("# transmission attempts failed (no address)"),
1574                                 1,
1575                                 GNUNET_NO);
1576     }
1577   return best_address;
1578
1579 }
1580
1581
1582 /**
1583  * We should re-try transmitting to the given peer,
1584  * hopefully we've learned something in the meantime.
1585  */
1586 static void
1587 retry_transmission_task (void *cls,
1588                          const struct GNUNET_SCHEDULER_TaskContext *tc)
1589 {
1590   struct NeighbourList *n = cls;
1591
1592   n->retry_task = GNUNET_SCHEDULER_NO_TASK;
1593   try_transmission_to_peer (n);
1594 }
1595
1596
1597 /**
1598  * Check the ready list for the given neighbour and if a plugin is
1599  * ready for transmission (and if we have a message), do so!
1600  *
1601  * @param neighbour target peer for which to transmit
1602  */
1603 static void
1604 try_transmission_to_peer (struct NeighbourList *neighbour)
1605 {
1606   struct ReadyList *rl;
1607   struct MessageQueue *mq;
1608   struct GNUNET_TIME_Relative timeout;
1609   ssize_t ret;
1610   int force_address;
1611
1612   if (neighbour->messages_head == NULL)
1613     {
1614 #if DEBUG_TRANSPORT
1615       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1616                   "Transmission queue for `%4s' is empty\n",
1617                   GNUNET_i2s (&neighbour->id));
1618 #endif
1619       return;                     /* nothing to do */
1620     }
1621   rl = NULL;
1622   mq = neighbour->messages_head;
1623   force_address = GNUNET_YES;
1624   if (mq->specific_address == NULL)
1625     {
1626       mq->specific_address = find_ready_address(neighbour);
1627       GNUNET_STATISTICS_update (stats,
1628                                 gettext_noop ("# transport selected peer address freely"),
1629                                 1,
1630                                 GNUNET_NO);
1631       force_address = GNUNET_NO;
1632     }
1633   if (mq->specific_address == NULL)
1634     {
1635       GNUNET_STATISTICS_update (stats,
1636                                 gettext_noop ("# transport failed to selected peer address"),
1637                                 1,
1638                                 GNUNET_NO);
1639       timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
1640       if (timeout.rel_value == 0)
1641         {
1642 #if DEBUG_TRANSPORT
1643           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1644                       "No destination address available to transmit message of size %u to peer `%4s'\n",
1645                       mq->message_buf_size,
1646                       GNUNET_i2s (&mq->neighbour_id));
1647 #endif
1648           GNUNET_STATISTICS_update (stats,
1649                                     gettext_noop ("# bytes in message queue for other peers"),
1650                                     - (int64_t) mq->message_buf_size,
1651                                     GNUNET_NO);
1652           GNUNET_STATISTICS_update (stats,
1653                                     gettext_noop ("# bytes discarded (no destination address available)"),
1654                                     mq->message_buf_size,
1655                                     GNUNET_NO);
1656           if (mq->client != NULL)
1657             transmit_send_ok (mq->client, neighbour, &neighbour->id, GNUNET_NO);
1658           GNUNET_CONTAINER_DLL_remove (neighbour->messages_head,
1659                                        neighbour->messages_tail,
1660                                        mq);
1661           GNUNET_free (mq);
1662           return;               /* nobody ready */
1663         }
1664       GNUNET_STATISTICS_update (stats,
1665                                 gettext_noop ("# message delivery deferred (no address)"),
1666                                 1,
1667                                 GNUNET_NO);
1668       if (neighbour->retry_task != GNUNET_SCHEDULER_NO_TASK)
1669         GNUNET_SCHEDULER_cancel (neighbour->retry_task);
1670       neighbour->retry_task = GNUNET_SCHEDULER_add_delayed (timeout,
1671                                                             &retry_transmission_task,
1672                                                             neighbour);
1673 #if DEBUG_TRANSPORT
1674       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1675                   "No validated destination address available to transmit message of size %u to peer `%4s', will wait %llums to find an address.\n",
1676                   mq->message_buf_size,
1677                   GNUNET_i2s (&mq->neighbour_id),
1678                   timeout.rel_value);
1679 #endif
1680       /* FIXME: might want to trigger peerinfo lookup here
1681          (unless that's already pending...) */
1682       return;
1683     }
1684   GNUNET_CONTAINER_DLL_remove (neighbour->messages_head,
1685                                neighbour->messages_tail,
1686                                mq);
1687   if (mq->specific_address->connected == GNUNET_NO)
1688     mq->specific_address->connect_attempts++;
1689   rl = mq->specific_address->ready_list;
1690   mq->plugin = rl->plugin;
1691   if (!mq->internal_msg)
1692     mq->specific_address->in_transmit = GNUNET_YES;
1693 #if DEBUG_TRANSPORT
1694   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1695               "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
1696               mq->message_buf_size,
1697               GNUNET_i2s (&neighbour->id),
1698               (mq->specific_address->addr != NULL)
1699               ? a2s (mq->plugin->short_name,
1700                      mq->specific_address->addr,
1701                      mq->specific_address->addrlen)
1702               : "<inbound>",
1703               rl->plugin->short_name);
1704 #endif
1705   GNUNET_STATISTICS_update (stats,
1706                             gettext_noop ("# bytes in message queue for other peers"),
1707                             - (int64_t) mq->message_buf_size,
1708                             GNUNET_NO);
1709   GNUNET_STATISTICS_update (stats,
1710                             gettext_noop ("# bytes pending with plugins"),
1711                             mq->message_buf_size,
1712                             GNUNET_NO);
1713   ret = rl->plugin->api->send (rl->plugin->api->cls,
1714                                &mq->neighbour_id,
1715                                mq->message_buf,
1716                                mq->message_buf_size,
1717                                mq->priority,
1718                                GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1719                                mq->specific_address->session,
1720                                mq->specific_address->addr,
1721                                mq->specific_address->addrlen,
1722                                force_address,
1723                                &transmit_send_continuation, mq);
1724   if (ret == -1)
1725     {
1726       /* failure, but 'send' would not call continuation in this case,
1727          so we need to do it here! */
1728       transmit_send_continuation (mq,
1729                                   &mq->neighbour_id,
1730                                   GNUNET_SYSERR);
1731     }
1732 }
1733
1734
1735 /**
1736  * Send the specified message to the specified peer.
1737  *
1738  * @param client source of the transmission request (can be NULL)
1739  * @param peer_address ForeignAddressList where we should send this message
1740  * @param priority how important is the message
1741  * @param timeout how long do we have to transmit?
1742  * @param message_buf message(s) to send GNUNET_MessageHeader(s)
1743  * @param message_buf_size total size of all messages in message_buf
1744  * @param is_internal is this an internal message; these are pre-pended and
1745  *                    also do not count for plugins being "ready" to transmit
1746  * @param neighbour handle to the neighbour for transmission
1747  */
1748 static void
1749 transmit_to_peer (struct TransportClient *client,
1750                   struct ForeignAddressList *peer_address,
1751                   unsigned int priority,
1752                   struct GNUNET_TIME_Relative timeout,
1753                   const char *message_buf,
1754                   size_t message_buf_size,
1755                   int is_internal, struct NeighbourList *neighbour)
1756 {
1757   struct MessageQueue *mq;
1758
1759 #if EXTRA_CHECKS
1760   if (client != NULL)
1761     {
1762       /* check for duplicate submission */
1763       mq = neighbour->messages_head;
1764       while (NULL != mq)
1765         {
1766           if (mq->client == client)
1767             {
1768               /* client transmitted to same peer twice
1769                  before getting SEND_OK! */
1770               GNUNET_break (0);
1771               return;
1772             }
1773           mq = mq->next;
1774         }
1775     }
1776 #endif
1777   GNUNET_STATISTICS_update (stats,
1778                             gettext_noop ("# bytes in message queue for other peers"),
1779                             message_buf_size,
1780                             GNUNET_NO);
1781   mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
1782   mq->specific_address = peer_address;
1783   mq->client = client;
1784   /* FIXME: this memcpy can be up to 7% of our total runtime! */
1785   memcpy (&mq[1], message_buf, message_buf_size);
1786   mq->message_buf = (const char*) &mq[1];
1787   mq->message_buf_size = message_buf_size;
1788   memcpy(&mq->neighbour_id, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
1789   mq->internal_msg = is_internal;
1790   mq->priority = priority;
1791   mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1792   if (is_internal)
1793     GNUNET_CONTAINER_DLL_insert (neighbour->messages_head,
1794                                  neighbour->messages_tail,
1795                                  mq);
1796   else
1797     GNUNET_CONTAINER_DLL_insert_after (neighbour->messages_head,
1798                                        neighbour->messages_tail,
1799                                        neighbour->messages_tail,
1800                                        mq);
1801   try_transmission_to_peer (neighbour);
1802 }
1803
1804
1805 /**
1806  * FIXME: document.
1807  */
1808 struct GeneratorContext
1809 {
1810   struct TransportPlugin *plug_pos;
1811   struct OwnAddressList *addr_pos;
1812   struct GNUNET_TIME_Absolute expiration;
1813 };
1814
1815
1816 /**
1817  * FIXME: document.
1818  */
1819 static size_t
1820 address_generator (void *cls, size_t max, void *buf)
1821 {
1822   struct GeneratorContext *gc = cls;
1823   size_t ret;
1824
1825   while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
1826     {
1827       gc->plug_pos = gc->plug_pos->next;
1828       gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
1829     }
1830   if (NULL == gc->plug_pos)
1831     {
1832
1833       return 0;
1834     }
1835   ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
1836                                   gc->expiration,
1837                                   &gc->addr_pos[1],
1838                                   gc->addr_pos->addrlen, buf, max);
1839   gc->addr_pos = gc->addr_pos->next;
1840   return ret;
1841 }
1842
1843
1844 /**
1845  * Construct our HELLO message from all of the addresses of
1846  * all of the transports.
1847  */
1848 static void
1849 refresh_hello ()
1850 {
1851   struct GNUNET_HELLO_Message *hello;
1852   struct TransportClient *cpos;
1853   struct NeighbourList *npos;
1854   struct GeneratorContext gc;
1855
1856   gc.plug_pos = plugins;
1857   gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
1858   gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1859   hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
1860 #if DEBUG_TRANSPORT
1861   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1862               "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
1863 #endif
1864   GNUNET_STATISTICS_update (stats,
1865                             gettext_noop ("# refreshed my HELLO"),
1866                             1,
1867                             GNUNET_NO);
1868   cpos = clients;
1869   while (cpos != NULL)
1870     {
1871       transmit_to_client (cpos,
1872                           (const struct GNUNET_MessageHeader *) hello,
1873                           GNUNET_NO);
1874       cpos = cpos->next;
1875     }
1876
1877   GNUNET_free_non_null (our_hello);
1878   our_hello = hello;
1879   GNUNET_PEERINFO_add_peer (peerinfo, our_hello);
1880   npos = neighbours;
1881   while (npos != NULL)
1882     {
1883 #if DEBUG_TRANSPORT
1884       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1885                   "Transmitting updated `%s' to neighbour `%4s'\n",
1886                   "HELLO", GNUNET_i2s (&npos->id));
1887 #endif
1888       GNUNET_STATISTICS_update (stats,
1889                                 gettext_noop ("# transmitted my HELLO to other peers"),
1890                                 1,
1891                                 GNUNET_NO);
1892       transmit_to_peer (NULL, NULL, 0,
1893                         HELLO_ADDRESS_EXPIRATION,
1894                         (const char *) our_hello,
1895                         GNUNET_HELLO_size(our_hello),
1896                         GNUNET_NO, npos);
1897       npos = npos->next;
1898     }
1899 }
1900
1901
1902 /**
1903  * Task used to clean up expired addresses for a plugin.
1904  *
1905  * @param cls closure
1906  * @param tc context
1907  */
1908 static void
1909 expire_address_task (void *cls,
1910                      const struct GNUNET_SCHEDULER_TaskContext *tc);
1911
1912
1913 /**
1914  * Update the list of addresses for this plugin,
1915  * expiring those that are past their expiration date.
1916  *
1917  * @param plugin addresses of which plugin should be recomputed?
1918  * @param fresh set to GNUNET_YES if a new address was added
1919  *        and we need to regenerate the HELLO even if nobody
1920  *        expired
1921  */
1922 static void
1923 update_addresses (struct TransportPlugin *plugin, 
1924                   int fresh)
1925 {
1926   static struct GNUNET_TIME_Absolute last_update;
1927   struct GNUNET_TIME_Relative min_remaining;
1928   struct GNUNET_TIME_Relative remaining;
1929   struct GNUNET_TIME_Absolute now;
1930   struct OwnAddressList *pos;
1931   struct OwnAddressList *prev;
1932   struct OwnAddressList *next;
1933   int expired;
1934
1935   if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
1936     GNUNET_SCHEDULER_cancel (plugin->address_update_task);
1937   plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1938   now = GNUNET_TIME_absolute_get ();
1939   min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
1940   expired = (GNUNET_TIME_absolute_get_duration (last_update).rel_value > (HELLO_ADDRESS_EXPIRATION.rel_value / 4));
1941   prev = NULL;
1942   pos = plugin->addresses;
1943   while (pos != NULL)
1944     {
1945       next = pos->next;
1946       if (pos->expires.abs_value < now.abs_value)
1947         {
1948           expired = GNUNET_YES;
1949           if (prev == NULL)
1950             plugin->addresses = pos->next;
1951           else
1952             prev->next = pos->next;
1953           GNUNET_free (pos);
1954         }
1955       else
1956         {
1957           remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
1958           if (remaining.rel_value < min_remaining.rel_value)
1959             min_remaining = remaining;
1960           prev = pos;
1961         }
1962       pos = next;
1963     }
1964
1965   if (expired || fresh)
1966     {
1967       last_update = now;
1968       refresh_hello ();
1969     }
1970   min_remaining = GNUNET_TIME_relative_min (min_remaining,
1971                                             GNUNET_TIME_relative_divide (HELLO_ADDRESS_EXPIRATION,
1972                                                                          2));
1973   plugin->address_update_task
1974     = GNUNET_SCHEDULER_add_delayed (min_remaining,
1975                                     &expire_address_task, plugin);
1976 }
1977
1978
1979 /**
1980  * Task used to clean up expired addresses for a plugin.
1981  *
1982  * @param cls closure
1983  * @param tc context
1984  */
1985 static void
1986 expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1987 {
1988   struct TransportPlugin *plugin = cls;
1989
1990   plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1991   if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
1992     update_addresses (plugin, GNUNET_NO);
1993 }
1994
1995
1996 /**
1997  * Iterator over hash map entries that NULLs the session of validation
1998  * entries that match the given session.
1999  *
2000  * @param cls closure (the 'struct Session*' to match against)
2001  * @param key current key code (peer ID, not used)
2002  * @param value value in the hash map ('struct ValidationEntry*')
2003  * @return GNUNET_YES (we should continue to iterate)
2004  */
2005 static int
2006 remove_session_validations (void *cls,
2007                             const GNUNET_HashCode * key,
2008                             void *value)
2009 {
2010   struct Session *session = cls;
2011   struct ValidationEntry *ve = value;
2012
2013   if (session == ve->session)
2014     ve->session = NULL;
2015   return GNUNET_YES;
2016 }
2017
2018
2019 /**
2020  * We've been disconnected from the other peer (for some
2021  * connection-oriented transport).  Either quickly
2022  * re-establish the connection or signal the disconnect
2023  * to the CORE.
2024  *
2025  * Only signal CORE level disconnect if ALL addresses
2026  * for the peer are exhausted.
2027  *
2028  * @param p overall plugin context
2029  * @param nl neighbour that was disconnected
2030  */
2031 static void
2032 try_fast_reconnect (struct TransportPlugin *p,
2033                     struct NeighbourList *nl)
2034 {
2035   /* FIXME-MW: fast reconnect / transport switching not implemented... */
2036   /* Note: the idea here is to hide problems with transports (or
2037      switching between plugins) from the core to eliminate the need to
2038      re-negotiate session keys and the like; OTOH, we should tell core
2039      quickly (much faster than timeout) `if a connection was lost and
2040      could not be re-established (i.e. other peer went down or is
2041      unable / refuses to communicate);
2042
2043      So we should consider:
2044      1) ideally: our own willingness / need to connect
2045      2) prior failures to connect to this peer (by plugin)
2046      3) ideally: reasons why other peer terminated (as far as knowable)
2047
2048      Most importantly, it must be POSSIBLE for another peer to terminate
2049      a connection for a while (without us instantly re-establishing it).
2050      Similarly, if another peer is gone we should quickly notify CORE.
2051      OTOH, if there was a minor glitch (i.e. crash of gnunet-service-transport
2052      on the other end), we should reconnect in such a way that BOTH CORE
2053      services never even notice.
2054      Furthermore, the same mechanism (or small variation) could be used
2055      to switch to a better-performing plugin (ATS).
2056
2057      Finally, this needs to be tested throughly... */                                                           
2058
2059   /*
2060    * GNUNET_NO in the call below makes transport disconnect the peer,
2061    * even if only a single address (out of say, six) went away.  This
2062    * function must be careful to ONLY disconnect if the peer is gone,
2063    * not just a specifi address.
2064    *
2065    * More specifically, half the places it was used had it WRONG.
2066    */
2067
2068   /* No reconnect, signal disconnect instead! */
2069   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2070             "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2071             "try_fast_reconnect");
2072   disconnect_neighbour (nl, GNUNET_YES);
2073 }
2074
2075
2076 /**
2077  * Function that will be called whenever the plugin internally
2078  * cleans up a session pointer and hence the service needs to
2079  * discard all of those sessions as well.  Plugins that do not
2080  * use sessions can simply omit calling this function and always
2081  * use NULL wherever a session pointer is needed.
2082  *
2083  * @param cls closure
2084  * @param peer which peer was the session for
2085  * @param session which session is being destoyed
2086  */
2087 static void
2088 plugin_env_session_end  (void *cls,
2089                          const struct GNUNET_PeerIdentity *peer,
2090                          struct Session *session)
2091 {
2092   struct TransportPlugin *p = cls;
2093   struct NeighbourList *nl;
2094   struct ReadyList *rl;
2095   struct ForeignAddressList *pos;
2096   struct ForeignAddressList *prev;
2097
2098   GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2099                                          &remove_session_validations,
2100                                          session);
2101   nl = find_neighbour (peer);
2102   if (nl == NULL)
2103     return; /* was never marked as connected */
2104   rl = nl->plugins;
2105   while (rl != NULL)
2106     {
2107       if (rl->plugin == p)
2108         break;
2109       rl = rl->next;
2110     }
2111   if (rl == NULL)
2112     return; /* was never marked as connected */
2113   prev = NULL;
2114   pos = rl->addresses;
2115   while ( (pos != NULL) &&
2116           (pos->session != session) )
2117     {
2118       prev = pos;
2119       pos = pos->next;
2120     }
2121   if (pos == NULL)
2122     return; /* was never marked as connected */
2123   pos->session = NULL;
2124   if (pos->addrlen != 0)
2125     {
2126       if (nl->received_pong != GNUNET_NO)
2127         try_fast_reconnect (p, nl);
2128       return;
2129     }
2130   /* was inbound connection, free 'pos' */
2131   if (prev == NULL)
2132     rl->addresses = pos->next;
2133   else
2134     prev->next = pos->next;
2135   if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2136     {
2137       GNUNET_SCHEDULER_cancel (pos->revalidate_task);
2138       pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2139     }
2140   GNUNET_free (pos);
2141   if (nl->received_pong == GNUNET_NO)
2142     return; /* nothing to do, never connected... */
2143   /* check if we have any validated addresses left */
2144   pos = rl->addresses;
2145   while (pos != NULL)
2146     {
2147       if (pos->validated)
2148         {
2149           try_fast_reconnect (p, nl);
2150           return;
2151         }
2152       pos = pos->next;
2153     }
2154   /* no valid addresses left, signal disconnect! */
2155
2156   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2157             "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2158             "plugin_env_session_end");
2159   /* FIXME: This doesn't mean there are no addresses left for this PEER,
2160    * it means there aren't any left for this PLUGIN/PEER combination! So
2161    * calling disconnect_neighbor here with GNUNET_NO forces disconnect
2162    * when it isn't necessary. Using GNUNET_YES at least checks to see
2163    * if there are any addresses that work first, so as not to overdo it.
2164    * --NE
2165    */
2166   disconnect_neighbour (nl, GNUNET_YES);
2167 }
2168
2169
2170 /**
2171  * Function that must be called by each plugin to notify the
2172  * transport service about the addresses under which the transport
2173  * provided by the plugin can be reached.
2174  *
2175  * @param cls closure
2176  * @param name name of the transport that generated the address
2177  * @param addr one of the addresses of the host, NULL for the last address
2178  *        the specific address format depends on the transport
2179  * @param addrlen length of the address
2180  * @param expires when should this address automatically expire?
2181  */
2182 static void
2183 plugin_env_notify_address (void *cls,
2184                            const char *name,
2185                            const void *addr,
2186                            uint16_t addrlen,
2187                            struct GNUNET_TIME_Relative expires)
2188 {
2189   struct TransportPlugin *p = cls;
2190   struct OwnAddressList *al;
2191   struct GNUNET_TIME_Absolute abex;
2192
2193   GNUNET_assert (addr != NULL);
2194   abex = GNUNET_TIME_relative_to_absolute (expires);
2195   GNUNET_assert (p == find_transport (name));
2196   al = p->addresses;
2197   while (al != NULL)
2198     {
2199       if ((addrlen == al->addrlen) && (0 == memcmp (addr, &al[1], addrlen)))
2200         {             
2201           al->expires = abex;
2202           update_addresses (p, GNUNET_NO);
2203           return;
2204         }
2205       al = al->next;
2206     }
2207
2208   al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
2209   al->next = p->addresses;
2210   p->addresses = al;
2211   al->expires = abex;
2212   al->addrlen = addrlen;
2213   memcpy (&al[1], addr, addrlen);
2214   update_addresses (p, GNUNET_YES);
2215 }
2216
2217
2218 /**
2219  * Notify all of our clients about a peer connecting.
2220  */
2221 static void
2222 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
2223                         struct GNUNET_TIME_Relative latency,
2224                         uint32_t distance)
2225 {
2226   struct ConnectInfoMessage * cim;
2227   struct TransportClient *cpos;
2228   uint32_t ats_count;
2229   size_t size;
2230
2231 #if DEBUG_TRANSPORT
2232   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2233               "Notifying clients about connection from `%s'\n",
2234               GNUNET_i2s (peer));
2235 #endif
2236   GNUNET_STATISTICS_update (stats,
2237                             gettext_noop ("# peers connected"),
2238                             1,
2239                             GNUNET_NO);
2240
2241   ats_count = 2;
2242   size  = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
2243   if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
2244   {
2245           GNUNET_break(0);
2246   }
2247   cim = GNUNET_malloc (size);
2248
2249   cim->header.size = htons (size);
2250   cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2251   cim->ats_count = htonl(2);
2252   (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
2253   (&(cim->ats))[0].value = htonl (distance);
2254   (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
2255   (&(cim->ats))[1].value = htonl ((uint32_t) latency.rel_value);
2256   (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
2257   (&(cim->ats))[2].value = htonl (0);
2258   memcpy (&cim->id, peer, sizeof (struct GNUNET_PeerIdentity));
2259   cpos = clients;
2260   while (cpos != NULL)
2261     {
2262       transmit_to_client (cpos, &(cim->header), GNUNET_NO);
2263       cpos = cpos->next;
2264     }
2265   GNUNET_free (cim);
2266 }
2267
2268
2269 /**
2270  * Notify all of our clients about a peer disconnecting.
2271  */
2272 static void
2273 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
2274 {
2275   struct DisconnectInfoMessage dim;
2276   struct TransportClient *cpos;
2277
2278 #if DEBUG_TRANSPORT
2279   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2280               "Notifying clients about lost connection to `%s'\n",
2281               GNUNET_i2s (peer));
2282 #endif
2283   GNUNET_STATISTICS_update (stats,
2284                             gettext_noop ("# peers connected"),
2285                             -1,
2286                             GNUNET_NO);
2287   dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
2288   dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2289   dim.reserved = htonl (0);
2290   memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
2291   cpos = clients;
2292   while (cpos != NULL)
2293     {
2294       transmit_to_client (cpos, &dim.header, GNUNET_NO);
2295       cpos = cpos->next;
2296     }
2297 }
2298
2299
2300 /**
2301  * Find a ForeignAddressList entry for the given neighbour
2302  * that matches the given address and transport.
2303  *
2304  * @param neighbour which peer we care about
2305  * @param tname name of the transport plugin
2306  * @param session session to look for, NULL for 'any'; otherwise
2307  *        can be used for the service to "learn" this session ID
2308  *        if 'addr' matches
2309  * @param addr binary address
2310  * @param addrlen length of addr
2311  * @return NULL if no such entry exists
2312  */
2313 static struct ForeignAddressList *
2314 find_peer_address(struct NeighbourList *neighbour,
2315                   const char *tname,
2316                   struct Session *session,
2317                   const char *addr,
2318                   uint16_t addrlen)
2319 {
2320   struct ReadyList *head;
2321   struct ForeignAddressList *pos;
2322
2323   head = neighbour->plugins;
2324   while (head != NULL)
2325     {
2326       if (0 == strcmp (tname, head->plugin->short_name))
2327         break;
2328       head = head->next;
2329     }
2330   if (head == NULL)
2331     return NULL;
2332   pos = head->addresses;
2333   while ( (pos != NULL) &&
2334           ( (pos->addrlen != addrlen) ||
2335             (memcmp(pos->addr, addr, addrlen) != 0) ) )
2336     {
2337       if ( (session != NULL) &&
2338            (pos->session == session) )
2339         return pos;
2340       pos = pos->next;
2341     }
2342   if ( (session != NULL) && (pos != NULL) )
2343     pos->session = session; /* learn it! */
2344   return pos;
2345 }
2346
2347
2348 /**
2349  * Get the peer address struct for the given neighbour and
2350  * address.  If it doesn't yet exist, create it.
2351  *
2352  * @param neighbour which peer we care about
2353  * @param tname name of the transport plugin
2354  * @param session session of the plugin, or NULL for none
2355  * @param addr binary address
2356  * @param addrlen length of addr
2357  * @return NULL if we do not have a transport plugin for 'tname'
2358  */
2359 static struct ForeignAddressList *
2360 add_peer_address (struct NeighbourList *neighbour,
2361                   const char *tname,
2362                   struct Session *session,
2363                   const char *addr,
2364                   uint16_t addrlen)
2365 {
2366   struct ReadyList *head;
2367   struct ForeignAddressList *ret;
2368
2369   ret = find_peer_address (neighbour, tname, session, addr, addrlen);
2370   if (ret != NULL)
2371     return ret;
2372   head = neighbour->plugins;
2373
2374   while (head != NULL)
2375     {
2376       if (0 == strcmp (tname, head->plugin->short_name))
2377         break;
2378       head = head->next;
2379     }
2380   if (head == NULL)
2381     return NULL;
2382   ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
2383   ret->session = session;
2384   if (addrlen > 0)
2385     {
2386       ret->addr = (const char*) &ret[1];
2387       memcpy (&ret[1], addr, addrlen);
2388     }
2389   else
2390     {
2391       ret->addr = NULL;
2392     }
2393   ret->addrlen = addrlen;
2394   ret->expires = GNUNET_TIME_relative_to_absolute
2395     (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2396   ret->latency = GNUNET_TIME_relative_get_forever();
2397   ret->distance = -1;
2398   ret->timeout = GNUNET_TIME_relative_to_absolute
2399     (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2400   ret->ready_list = head;
2401   ret->next = head->addresses;
2402   head->addresses = ret;
2403   return ret;
2404 }
2405
2406
2407 /**
2408  * Closure for 'add_validated_address'.
2409  */
2410 struct AddValidatedAddressContext
2411 {
2412   /**
2413    * Entry that has been validated.
2414    */
2415   const struct ValidationEntry *ve;
2416
2417   /**
2418    * Flag set after we have added the address so
2419    * that we terminate the iteration next time.
2420    */
2421   int done;
2422 };
2423
2424
2425 /**
2426  * Callback function used to fill a buffer of max bytes with a list of
2427  * addresses in the format used by HELLOs.  Should use
2428  * "GNUNET_HELLO_add_address" as a helper function.
2429  *
2430  * @param cls the 'struct AddValidatedAddressContext' with the validated address
2431  * @param max maximum number of bytes that can be written to buf
2432  * @param buf where to write the address information
2433  * @return number of bytes written, 0 to signal the
2434  *         end of the iteration.
2435  */
2436 static size_t
2437 add_validated_address (void *cls,
2438                        size_t max, void *buf)
2439 {
2440   struct AddValidatedAddressContext *avac = cls;
2441   const struct ValidationEntry *ve = avac->ve;
2442
2443   if (GNUNET_YES == avac->done)
2444     return 0;
2445   avac->done = GNUNET_YES;
2446   return GNUNET_HELLO_add_address (ve->transport_name,
2447                                    GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION),
2448                                    ve->addr,
2449                                    ve->addrlen,
2450                                    buf,
2451                                    max);
2452 }
2453
2454
2455
2456 /**
2457  * Closure for 'check_address_exists'.
2458  */
2459 struct CheckAddressExistsClosure
2460 {
2461   /**
2462    * Address to check for.
2463    */
2464   const void *addr;
2465
2466   /**
2467    * Name of the transport.
2468    */
2469   const char *tname;
2470
2471   /**
2472    * Session, or NULL.
2473    */
2474   struct Session *session;
2475
2476   /**
2477    * Set to GNUNET_YES if the address exists.
2478    */
2479   int exists;
2480
2481   /**
2482    * Length of addr.
2483    */
2484   uint16_t addrlen;
2485
2486 };
2487
2488
2489 /**
2490  * Iterator over hash map entries.  Checks if the given
2491  * validation entry is for the same address as what is given
2492  * in the closure.
2493  *
2494  * @param cls the 'struct CheckAddressExistsClosure*'
2495  * @param key current key code (ignored)
2496  * @param value value in the hash map ('struct ValidationEntry')
2497  * @return GNUNET_YES if we should continue to
2498  *         iterate (mismatch), GNUNET_NO if not (entry matched)
2499  */
2500 static int
2501 check_address_exists (void *cls,
2502                       const GNUNET_HashCode * key,
2503                       void *value)
2504 {
2505   struct CheckAddressExistsClosure *caec = cls;
2506   struct ValidationEntry *ve = value;
2507
2508   if ( (0 == strcmp (caec->tname,
2509                      ve->transport_name)) &&
2510        (caec->addrlen == ve->addrlen) &&
2511        (0 == memcmp (caec->addr,
2512                      ve->addr,
2513                      caec->addrlen)) )
2514     {
2515       caec->exists = GNUNET_YES;
2516       return GNUNET_NO;
2517     }
2518   if ( (ve->session != NULL) &&
2519        (caec->session == ve->session) )
2520     {
2521       caec->exists = GNUNET_YES;
2522       return GNUNET_NO;
2523     }
2524   return GNUNET_YES;
2525 }
2526
2527
2528
2529 /**
2530  * Iterator to free entries in the validation_map.
2531  *
2532  * @param cls closure (unused)
2533  * @param key current key code
2534  * @param value value in the hash map (validation to abort)
2535  * @return GNUNET_YES (always)
2536  */
2537 static int
2538 abort_validation (void *cls,
2539                   const GNUNET_HashCode * key,
2540                   void *value)
2541 {
2542   struct ValidationEntry *va = value;
2543
2544   if (GNUNET_SCHEDULER_NO_TASK != va->timeout_task)
2545     GNUNET_SCHEDULER_cancel (va->timeout_task);
2546   GNUNET_free (va->transport_name);
2547   if (va->chvc != NULL)
2548     {
2549       va->chvc->ve_count--;
2550       if (va->chvc->ve_count == 0)
2551         {
2552           GNUNET_CONTAINER_DLL_remove (chvc_head,
2553                                        chvc_tail,
2554                                        va->chvc);
2555           GNUNET_free (va->chvc);
2556         }
2557       va->chvc = NULL;
2558     }
2559   GNUNET_free (va);
2560   return GNUNET_YES;
2561 }
2562
2563
2564 /**
2565  * HELLO validation cleanup task (validation failed).
2566  *
2567  * @param cls the 'struct ValidationEntry' that failed
2568  * @param tc scheduler context (unused)
2569  */
2570 static void
2571 timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2572 {
2573   struct ValidationEntry *va = cls;
2574   struct GNUNET_PeerIdentity pid;
2575
2576   va->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2577   GNUNET_STATISTICS_update (stats,
2578                             gettext_noop ("# address validation timeouts"),
2579                             1,
2580                             GNUNET_NO);
2581   GNUNET_CRYPTO_hash (&va->publicKey,
2582                       sizeof (struct
2583                               GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2584                       &pid.hashPubKey);
2585   GNUNET_break (GNUNET_OK ==
2586                 GNUNET_CONTAINER_multihashmap_remove (validation_map,
2587                                                       &pid.hashPubKey,
2588                                                       va));
2589   abort_validation (NULL, NULL, va);
2590 }
2591
2592
2593 static void
2594 neighbour_timeout_task (void *cls,
2595                        const struct GNUNET_SCHEDULER_TaskContext *tc)
2596 {
2597   struct NeighbourList *n = cls;
2598
2599 #if DEBUG_TRANSPORT
2600   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2601               "Neighbour `%4s' has timed out!\n", GNUNET_i2s (&n->id));
2602 #endif
2603   GNUNET_STATISTICS_update (stats,
2604                             gettext_noop ("# disconnects due to timeout"),
2605                             1,
2606                             GNUNET_NO);
2607   n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2608   disconnect_neighbour (n, GNUNET_NO);
2609 }
2610
2611
2612 /**
2613  * Schedule the job that will cause us to send a PING to the
2614  * foreign address to evaluate its validity and latency.
2615  *
2616  * @param fal address to PING
2617  */
2618 static void
2619 schedule_next_ping (struct ForeignAddressList *fal);
2620
2621
2622 /**
2623  * Add the given address to the list of foreign addresses
2624  * available for the given peer (check for duplicates).
2625  *
2626  * @param cls the respective 'struct NeighbourList' to update
2627  * @param tname name of the transport
2628  * @param expiration expiration time
2629  * @param addr the address
2630  * @param addrlen length of the address
2631  * @return GNUNET_OK (always)
2632  */
2633 static int
2634 add_to_foreign_address_list (void *cls,
2635                              const char *tname,
2636                              struct GNUNET_TIME_Absolute expiration,
2637                              const void *addr,
2638                              uint16_t addrlen)
2639 {
2640   struct NeighbourList *n = cls;
2641   struct ForeignAddressList *fal;
2642   int try;
2643
2644   GNUNET_STATISTICS_update (stats,
2645                             gettext_noop ("# valid peer addresses returned by PEERINFO"),
2646                             1,
2647                             GNUNET_NO);
2648   try = GNUNET_NO;
2649   fal = find_peer_address (n, tname, NULL, addr, addrlen);
2650   if (fal == NULL)
2651     {
2652 #if DEBUG_TRANSPORT_HELLO
2653       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2654                   "Adding address `%s' (%s) for peer `%4s' due to PEERINFO data for %llums.\n",
2655                   a2s (tname, addr, addrlen),
2656                   tname,
2657                   GNUNET_i2s (&n->id),
2658                   expiration.abs_value);
2659 #endif
2660       fal = add_peer_address (n, tname, NULL, addr, addrlen);
2661       if (fal == NULL)
2662         {
2663           GNUNET_STATISTICS_update (stats,
2664                                     gettext_noop ("# previously validated addresses lacking transport"),
2665                                     1,
2666                                     GNUNET_NO);
2667         }
2668       else
2669         {
2670           fal->expires = GNUNET_TIME_absolute_max (expiration,
2671                                                    fal->expires);
2672           schedule_next_ping (fal);
2673         }
2674       try = GNUNET_YES;
2675     }
2676   else
2677     {
2678       fal->expires = GNUNET_TIME_absolute_max (expiration,
2679                                                fal->expires);
2680     }
2681   if (fal == NULL)
2682     {
2683       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2684                   "Failed to add new address for `%4s'\n",
2685                   GNUNET_i2s (&n->id));
2686       return GNUNET_OK;
2687     }
2688   if (fal->validated == GNUNET_NO)
2689     {
2690       fal->validated = GNUNET_YES;
2691       GNUNET_STATISTICS_update (stats,
2692                                 gettext_noop ("# peer addresses considered valid"),
2693                                 1,
2694                                 GNUNET_NO);
2695     }
2696   if (try == GNUNET_YES)
2697     {
2698       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2699                   "Have new addresses, will try to trigger transmissions.\n");
2700       try_transmission_to_peer (n);
2701     }
2702   return GNUNET_OK;
2703 }
2704
2705
2706 /**
2707  * Add addresses in validated HELLO "h" to the set of addresses
2708  * we have for this peer.
2709  *
2710  * @param cls closure ('struct NeighbourList*')
2711  * @param peer id of the peer, NULL for last call
2712  * @param h hello message for the peer (can be NULL)
2713  */
2714 static void
2715 add_hello_for_peer (void *cls,
2716                     const struct GNUNET_PeerIdentity *peer,
2717                     const struct GNUNET_HELLO_Message *h)
2718 {
2719   struct NeighbourList *n = cls;
2720
2721   if (peer == NULL)
2722     {
2723       GNUNET_STATISTICS_update (stats,
2724                                 gettext_noop ("# outstanding peerinfo iterate requests"),
2725                                 -1,
2726                                 GNUNET_NO);
2727       n->piter = NULL;
2728       return;
2729     }
2730   if (h == NULL)
2731     return; /* no HELLO available */
2732 #if DEBUG_TRANSPORT
2733   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2734               "Peerinfo had `%s' message for peer `%4s', adding existing addresses.\n",
2735               "HELLO",
2736               GNUNET_i2s (peer));
2737 #endif
2738   if (GNUNET_YES != n->public_key_valid)
2739     {
2740       GNUNET_HELLO_get_key (h, &n->publicKey);
2741       n->public_key_valid = GNUNET_YES;
2742     }
2743   GNUNET_HELLO_iterate_addresses (h,
2744                                   GNUNET_NO,
2745                                   &add_to_foreign_address_list,
2746                                   n);
2747 }
2748
2749
2750 /**
2751  * Create a fresh entry in our neighbour list for the given peer.
2752  * Will try to transmit our current HELLO to the new neighbour.
2753  * Do not call this function directly, use 'setup_peer_check_blacklist.
2754  *
2755  * @param peer the peer for which we create the entry
2756  * @param do_hello should we schedule transmitting a HELLO
2757  * @return the new neighbour list entry
2758  */
2759 static struct NeighbourList *
2760 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer,
2761                      int do_hello)
2762 {
2763   struct NeighbourList *n;
2764   struct TransportPlugin *tp;
2765   struct ReadyList *rl;
2766
2767 #if DEBUG_TRANSPORT
2768   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2769               "Setting up state for neighbour `%4s'\n",
2770               GNUNET_i2s (peer));
2771 #endif
2772   GNUNET_assert (our_hello != NULL);
2773   GNUNET_STATISTICS_update (stats,
2774                             gettext_noop ("# active neighbours"),
2775                             1,
2776                             GNUNET_NO);
2777   n = GNUNET_malloc (sizeof (struct NeighbourList));
2778   n->next = neighbours;
2779   neighbours = n;
2780   n->id = *peer;
2781   n->peer_timeout =
2782     GNUNET_TIME_relative_to_absolute
2783     (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2784   GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
2785                                  GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
2786                                  MAX_BANDWIDTH_CARRY_S);
2787   tp = plugins;
2788   while (tp != NULL)
2789     {
2790       if ((tp->api->send != NULL) && (!is_blacklisted(peer, tp)))
2791         {
2792           rl = GNUNET_malloc (sizeof (struct ReadyList));
2793           rl->neighbour = n;
2794           rl->next = n->plugins;
2795           n->plugins = rl;
2796           rl->plugin = tp;
2797           rl->addresses = NULL;
2798         }
2799       tp = tp->next;
2800     }
2801   n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
2802   n->distance = -1;
2803   n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2804                                                   &neighbour_timeout_task, n);
2805   if (do_hello)
2806     {
2807       GNUNET_STATISTICS_update (stats,
2808                                 gettext_noop ("# peerinfo new neighbor iterate requests"),
2809                                 1,
2810                                 GNUNET_NO);
2811       GNUNET_STATISTICS_update (stats,
2812                                 gettext_noop ("# outstanding peerinfo iterate requests"),
2813                                 1,
2814                                 GNUNET_NO);
2815       n->piter = GNUNET_PEERINFO_iterate (peerinfo, peer,
2816                                           GNUNET_TIME_UNIT_FOREVER_REL,
2817                                           &add_hello_for_peer, n);
2818
2819       GNUNET_STATISTICS_update (stats,
2820                                 gettext_noop ("# HELLO's sent to new neighbors"),
2821                                 1,
2822                                 GNUNET_NO);
2823       transmit_to_peer (NULL, NULL, 0,
2824                         HELLO_ADDRESS_EXPIRATION,
2825                         (const char *) our_hello, GNUNET_HELLO_size(our_hello),
2826                         GNUNET_NO, n);
2827     }
2828   return n;
2829 }
2830
2831
2832 /**
2833  * Function called after we have checked if communicating
2834  * with a given peer is acceptable.
2835  *
2836  * @param cls closure
2837  * @param n NULL if communication is not acceptable
2838  */
2839 typedef void (*SetupContinuation)(void *cls,
2840                                   struct NeighbourList *n);
2841
2842
2843 /**
2844  * Information kept for each client registered to perform
2845  * blacklisting.
2846  */
2847 struct Blacklisters
2848 {
2849   /**
2850    * This is a linked list.
2851    */
2852   struct Blacklisters *next;
2853
2854   /**
2855    * This is a linked list.
2856    */
2857   struct Blacklisters *prev;
2858
2859   /**
2860    * Client responsible for this entry.
2861    */
2862   struct GNUNET_SERVER_Client *client;
2863
2864   /**
2865    * Blacklist check that we're currently performing.
2866    */
2867   struct BlacklistCheck *bc;
2868
2869 };
2870
2871
2872 /**
2873  * Head of DLL of blacklisting clients.
2874  */
2875 static struct Blacklisters *bl_head;
2876
2877 /**
2878  * Tail of DLL of blacklisting clients.
2879  */
2880 static struct Blacklisters *bl_tail;
2881
2882
2883 /**
2884  * Context we use when performing a blacklist check.
2885  */
2886 struct BlacklistCheck
2887 {
2888
2889   /**
2890    * This is a linked list.
2891    */
2892   struct BlacklistCheck *next;
2893
2894   /**
2895    * This is a linked list.
2896    */
2897   struct BlacklistCheck *prev;
2898
2899   /**
2900    * Peer being checked.
2901    */
2902   struct GNUNET_PeerIdentity peer;
2903
2904   /**
2905    * Option for setup neighbour afterwards.
2906    */
2907   int do_hello;
2908
2909   /**
2910    * Continuation to call with the result.
2911    */
2912   SetupContinuation cont;
2913
2914   /**
2915    * Closure for cont.
2916    */
2917   void *cont_cls;
2918
2919   /**
2920    * Current transmission request handle for this client, or NULL if no
2921    * request is pending.
2922    */
2923   struct GNUNET_CONNECTION_TransmitHandle *th;
2924
2925   /**
2926    * Our current position in the blacklisters list.
2927    */
2928   struct Blacklisters *bl_pos;
2929
2930   /**
2931    * Current task performing the check.
2932    */
2933   GNUNET_SCHEDULER_TaskIdentifier task;
2934
2935 };
2936
2937 /**
2938  * Head of DLL of active blacklisting queries.
2939  */
2940 static struct BlacklistCheck *bc_head;
2941
2942 /**
2943  * Tail of DLL of active blacklisting queries.
2944  */
2945 static struct BlacklistCheck *bc_tail;
2946
2947
2948 /**
2949  * Perform next action in the blacklist check.
2950  *
2951  * @param cls the 'struct BlacklistCheck*'
2952  * @param tc unused
2953  */
2954 static void
2955 do_blacklist_check (void *cls,
2956                     const struct GNUNET_SCHEDULER_TaskContext *tc);
2957
2958
2959 /**
2960  * Transmit blacklist query to the client.
2961  *
2962  * @param cls the 'struct BlacklistCheck'
2963  * @param size number of bytes allowed
2964  * @param buf where to copy the message
2965  * @return number of bytes copied to buf
2966  */
2967 static size_t
2968 transmit_blacklist_message (void *cls,
2969                             size_t size,
2970                             void *buf)
2971 {
2972   struct BlacklistCheck *bc = cls;
2973   struct Blacklisters *bl;
2974   struct BlacklistMessage bm;
2975
2976   bc->th = NULL;
2977   if (size == 0)
2978     {
2979       GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK);
2980       bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
2981                                            bc);
2982       return 0;
2983     }
2984   bl = bc->bl_pos;
2985   bm.header.size = htons (sizeof (struct BlacklistMessage));
2986   bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
2987   bm.is_allowed = htonl (0);
2988   bm.peer = bc->peer;
2989   memcpy (buf, &bm, sizeof (bm));
2990   GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
2991   return sizeof (bm);
2992 }
2993
2994
2995 /**
2996  * Perform next action in the blacklist check.
2997  *
2998  * @param cls the 'struct BlacklistCheck*'
2999  * @param tc unused
3000  */
3001 static void
3002 do_blacklist_check (void *cls,
3003                     const struct GNUNET_SCHEDULER_TaskContext *tc)
3004 {
3005   struct BlacklistCheck *bc = cls;
3006   struct Blacklisters *bl;
3007
3008   bc->task = GNUNET_SCHEDULER_NO_TASK;
3009   bl = bc->bl_pos;
3010   if (bl == NULL)
3011     {
3012       bc->cont (bc->cont_cls,
3013                 setup_new_neighbour (&bc->peer, bc->do_hello));         
3014       GNUNET_free (bc);
3015       return;
3016     }
3017   if (bl->bc == NULL)
3018     {
3019       bl->bc = bc;
3020       bc->th = GNUNET_SERVER_notify_transmit_ready (bl->client,
3021                                                     sizeof (struct BlacklistMessage),
3022                                                     GNUNET_TIME_UNIT_FOREVER_REL,
3023                                                     &transmit_blacklist_message,
3024                                                     bc);
3025     }
3026 }
3027
3028
3029 /**
3030  * Obtain a 'struct NeighbourList' for the given peer.  If such an entry
3031  * does not yet exist, check the blacklist.  If the blacklist says creating
3032  * one is acceptable, create one and call the continuation; otherwise
3033  * call the continuation with NULL.
3034  *
3035  * @param peer peer to setup or look up a struct NeighbourList for
3036  * @param do_hello should we also schedule sending our HELLO to the peer
3037  *        if this is a new record
3038  * @param cont function to call with the 'struct NeigbhbourList*'
3039  * @param cont_cls closure for cont
3040  */
3041 static void
3042 setup_peer_check_blacklist (const struct GNUNET_PeerIdentity *peer,
3043                             int do_hello,
3044                             SetupContinuation cont,
3045                             void *cont_cls)
3046 {
3047   struct NeighbourList *n;
3048   struct BlacklistCheck *bc;
3049
3050   n = find_neighbour(peer);
3051   if (n != NULL)
3052     {
3053       if (cont != NULL)
3054         cont (cont_cls, n);
3055       return;
3056     }
3057   if (bl_head == NULL)
3058     {
3059       if (cont != NULL)
3060         cont (cont_cls, setup_new_neighbour (peer, do_hello));
3061       else
3062         setup_new_neighbour(peer, do_hello);
3063       return;
3064     }
3065   bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3066   GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3067   bc->peer = *peer;
3068   bc->do_hello = do_hello;
3069   bc->cont = cont;
3070   bc->cont_cls = cont_cls;
3071   bc->bl_pos = bl_head;
3072   bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3073                                        bc);
3074 }
3075
3076
3077 /**
3078  * Function called with the result of querying a new blacklister about
3079  * it being allowed (or not) to continue to talk to an existing neighbour.
3080  *
3081  * @param cls the original 'struct NeighbourList'
3082  * @param n NULL if we need to disconnect
3083  */
3084 static void
3085 confirm_or_drop_neighbour (void *cls,
3086                            struct NeighbourList *n)
3087 {
3088   struct NeighbourList * orig = cls;
3089
3090   if (n == NULL)
3091     {
3092       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3093               "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&orig->id),
3094               "confirm_or_drop_neighboUr");
3095       disconnect_neighbour (orig, GNUNET_NO);
3096     }
3097 }
3098
3099
3100 /**
3101  * Handle a request to start a blacklist.
3102  *
3103  * @param cls closure (always NULL)
3104  * @param client identification of the client
3105  * @param message the actual message
3106  */
3107 static void
3108 handle_blacklist_init (void *cls,
3109                        struct GNUNET_SERVER_Client *client,
3110                        const struct GNUNET_MessageHeader *message)
3111 {
3112   struct Blacklisters *bl;
3113   struct BlacklistCheck *bc;
3114   struct NeighbourList *n;
3115
3116   bl = bl_head;
3117   while (bl != NULL)
3118     {
3119       if (bl->client == client)
3120         {
3121           GNUNET_break (0);
3122           GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3123           return;
3124         }
3125       bl = bl->next;
3126     }
3127   bl = GNUNET_malloc (sizeof (struct Blacklisters));
3128   bl->client = client;
3129   GNUNET_SERVER_client_keep (client);
3130   GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
3131   /* confirm that all existing connections are OK! */
3132   n = neighbours;
3133   while (NULL != n)
3134     {
3135       bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3136       GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3137       bc->peer = n->id;
3138       bc->do_hello = GNUNET_NO;
3139       bc->cont = &confirm_or_drop_neighbour;
3140       bc->cont_cls = n;
3141       bc->bl_pos = bl;
3142       if (n == neighbours) /* all would wait for the same client, no need to
3143                               create more than just the first task right now */
3144         bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3145                                              bc);
3146       n = n->next;
3147     }
3148 }
3149
3150
3151 /**
3152  * Handle a request to blacklist a peer.
3153  *
3154  * @param cls closure (always NULL)
3155  * @param client identification of the client
3156  * @param message the actual message
3157  */
3158 static void
3159 handle_blacklist_reply (void *cls,
3160                         struct GNUNET_SERVER_Client *client,
3161                         const struct GNUNET_MessageHeader *message)
3162 {
3163   const struct BlacklistMessage *msg = (const struct BlacklistMessage*) message;
3164   struct Blacklisters *bl;
3165   struct BlacklistCheck *bc;
3166
3167   bl = bl_head;
3168   while ( (bl != NULL) &&
3169           (bl->client != client) )
3170     bl = bl->next;
3171   if (bl == NULL)
3172     {
3173       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3174       return;
3175     }
3176   bc = bl->bc;
3177   bl->bc = NULL;
3178   if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
3179     {
3180       bc->cont (bc->cont_cls, NULL);
3181       GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
3182       GNUNET_free (bc);
3183     }
3184   else
3185     {
3186       bc->bl_pos = bc->bl_pos->next;
3187       bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3188                                            bc);
3189     }
3190   /* check if any other bc's are waiting for this blacklister */
3191   bc = bc_head;
3192   while (bc != NULL)
3193     {
3194       if ( (bc->bl_pos == bl) &&
3195            (GNUNET_SCHEDULER_NO_TASK == bc->task) )
3196         bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3197                                              bc);
3198       bc = bc->next;
3199     }
3200 }
3201
3202
3203 /**
3204  * Send periodic PING messages to a given foreign address.
3205  *
3206  * @param cls our 'struct PeriodicValidationContext*'
3207  * @param tc task context
3208  */
3209 static void
3210 send_periodic_ping (void *cls,
3211                     const struct GNUNET_SCHEDULER_TaskContext *tc)
3212 {
3213   struct ForeignAddressList *peer_address = cls;
3214   struct TransportPlugin *tp;
3215   struct ValidationEntry *va;
3216   struct NeighbourList *neighbour;
3217   struct TransportPingMessage ping;
3218   struct CheckAddressExistsClosure caec;
3219   char * message_buf;
3220   uint16_t hello_size;
3221   size_t slen;
3222   size_t tsize;
3223
3224   peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3225   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
3226     return;
3227   tp = peer_address->ready_list->plugin;
3228   neighbour = peer_address->ready_list->neighbour;
3229   if (GNUNET_YES != neighbour->public_key_valid)
3230     {
3231       /* no public key yet, try again later */
3232       schedule_next_ping (peer_address);
3233       return;
3234     }
3235   caec.addr = peer_address->addr;
3236   caec.addrlen = peer_address->addrlen;
3237   caec.tname = tp->short_name;
3238   caec.session = peer_address->session;
3239   caec.exists = GNUNET_NO;
3240   GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3241                                          &check_address_exists,
3242                                          &caec);
3243   if (caec.exists == GNUNET_YES)
3244     {
3245       /* During validation attempts we will likely trigger the other
3246          peer trying to validate our address which in turn will cause
3247          it to send us its HELLO, so we expect to hit this case rather
3248          frequently.  Only print something if we are very verbose. */
3249 #if DEBUG_TRANSPORT > 1
3250       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3251                   "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
3252                   (peer_address->addr != NULL)
3253                   ? a2s (tp->short_name,
3254                          peer_address->addr,
3255                          peer_address->addrlen)
3256                   : "<inbound>",
3257                   tp->short_name,
3258                   GNUNET_i2s (&neighbour->id));
3259 #endif
3260       schedule_next_ping (peer_address);
3261       return;
3262     }
3263   va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
3264   va->transport_name = GNUNET_strdup (tp->short_name);
3265   va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
3266                                             UINT_MAX);
3267   va->send_time = GNUNET_TIME_absolute_get();
3268   va->session = peer_address->session;
3269   if (peer_address->addr != NULL)
3270     {
3271       va->addr = (const void*) &va[1];
3272       memcpy (&va[1], peer_address->addr, peer_address->addrlen);
3273       va->addrlen = peer_address->addrlen;
3274     }
3275   memcpy(&va->publicKey,
3276          &neighbour->publicKey,
3277          sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3278
3279   va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
3280                                                    &timeout_hello_validation,
3281                                                    va);
3282   GNUNET_CONTAINER_multihashmap_put (validation_map,
3283                                      &neighbour->id.hashPubKey,
3284                                      va,
3285                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3286
3287   if (peer_address->validated != GNUNET_YES)
3288     hello_size = GNUNET_HELLO_size(our_hello);
3289   else
3290     hello_size = 0;
3291
3292   tsize = sizeof(struct TransportPingMessage) + hello_size;
3293
3294   if (peer_address->addr != NULL)
3295     {
3296       slen = strlen (tp->short_name) + 1;
3297       tsize += slen + peer_address->addrlen;
3298     }
3299   else
3300     {
3301       slen = 0; /* make gcc happy */
3302     }
3303   message_buf = GNUNET_malloc(tsize);
3304   ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3305   ping.challenge = htonl(va->challenge);
3306   memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
3307   if (peer_address->validated != GNUNET_YES)
3308     {
3309       memcpy(message_buf, our_hello, hello_size);
3310     }
3311
3312   if (peer_address->addr != NULL)
3313     {
3314       ping.header.size = htons(sizeof(struct TransportPingMessage) +
3315                                peer_address->addrlen +
3316                                slen);
3317       memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
3318              tp->short_name,
3319              slen);
3320       memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
3321              peer_address->addr,
3322              peer_address->addrlen);
3323     }
3324   else
3325     {
3326       ping.header.size = htons(sizeof(struct TransportPingMessage));
3327     }
3328
3329   memcpy(&message_buf[hello_size],
3330          &ping,
3331          sizeof(struct TransportPingMessage));
3332
3333 #if DEBUG_TRANSPORT_REVALIDATION
3334   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3335               "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s'\n",
3336               (peer_address->addr != NULL)
3337               ? a2s (peer_address->plugin->short_name,
3338                      peer_address->addr,
3339                      peer_address->addrlen)
3340               : "<inbound>",
3341               tp->short_name,
3342               GNUNET_i2s (&neighbour->id),
3343               "HELLO", hello_size,
3344               "PING");
3345 #endif
3346   if (peer_address->validated != GNUNET_YES)
3347     GNUNET_STATISTICS_update (stats,
3348                               gettext_noop ("# PING with HELLO messages sent"),
3349                               1,
3350                               GNUNET_NO);
3351   else
3352     GNUNET_STATISTICS_update (stats,
3353                               gettext_noop ("# PING without HELLO messages sent"),
3354                               1,
3355                               GNUNET_NO);
3356   GNUNET_STATISTICS_update (stats,
3357                             gettext_noop ("# PING messages sent for re-validation"),
3358                             1,
3359                             GNUNET_NO);
3360   transmit_to_peer (NULL, peer_address,
3361                     GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3362                     HELLO_VERIFICATION_TIMEOUT,
3363                     message_buf, tsize,
3364                     GNUNET_YES, neighbour);
3365   GNUNET_free(message_buf);
3366   schedule_next_ping (peer_address);
3367 }
3368
3369
3370 /**
3371  * Schedule the job that will cause us to send a PING to the
3372  * foreign address to evaluate its validity and latency.
3373  *
3374  * @param fal address to PING
3375  */
3376 static void
3377 schedule_next_ping (struct ForeignAddressList *fal)
3378 {
3379   struct GNUNET_TIME_Relative delay;
3380
3381   if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
3382     return;
3383   delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
3384   delay.rel_value /= 2; /* do before expiration */
3385   delay = GNUNET_TIME_relative_min (delay,
3386                                     LATENCY_EVALUATION_MAX_DELAY);
3387   if (GNUNET_YES != fal->estimated)
3388     {
3389       delay = GNUNET_TIME_UNIT_ZERO;
3390       fal->estimated = GNUNET_YES;
3391     }                           
3392   if (GNUNET_YES == fal->connected)
3393     {
3394       delay = GNUNET_TIME_relative_min (delay,
3395                                         CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
3396     }
3397   /* FIXME: also adjust delay based on how close the last
3398      observed latency is to the latency of the best alternative */
3399   /* bound how fast we can go */
3400   delay = GNUNET_TIME_relative_max (delay,
3401                                     GNUNET_TIME_UNIT_SECONDS);
3402   /* randomize a bit (to avoid doing all at the same time) */
3403   delay.rel_value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
3404   fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(delay,
3405                                                       &send_periodic_ping,
3406                                                       fal);
3407 }
3408
3409
3410
3411
3412 /**
3413  * Function that will be called if we receive some payload
3414  * from another peer.
3415  *
3416  * @param message the payload
3417  * @param n peer who claimed to be the sender
3418  */
3419 static void
3420 handle_payload_message (const struct GNUNET_MessageHeader *message,
3421                                                 struct NeighbourList *n)
3422 {
3423   struct InboundMessage *im;
3424   struct TransportClient *cpos;
3425   uint16_t msize;
3426
3427   msize = ntohs (message->size);
3428   if (n->received_pong == GNUNET_NO)
3429     {
3430       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3431                   "Received message of type %u and size %u from `%4s', but no pong yet!!\n",
3432                   ntohs (message->type),
3433                   ntohs (message->size),
3434                   GNUNET_i2s (&n->id));
3435       GNUNET_free_non_null (n->pre_connect_message_buffer);
3436       n->pre_connect_message_buffer = GNUNET_malloc (msize);
3437       memcpy (n->pre_connect_message_buffer, message, msize);
3438       return;
3439     }
3440
3441 #if DEBUG_TRANSPORT
3442   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3443               "Received message of type %u and size %u from `%4s', sending to all clients.\n",
3444               ntohs (message->type),
3445               ntohs (message->size),
3446               GNUNET_i2s (&n->id));
3447 #endif
3448   if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3449                                                       (ssize_t) msize))
3450     {
3451       n->quota_violation_count++;
3452 #if DEBUG_TRANSPORT
3453       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,                      
3454                   "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
3455                   n->in_tracker.available_bytes_per_s__,
3456                   n->quota_violation_count);
3457 #endif
3458       /* Discount 32k per violation */
3459       GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3460                                         - 32 * 1024);           
3461     }
3462   else
3463     {
3464       if (n->quota_violation_count > 0)
3465         {
3466           /* try to add 32k back */
3467           GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3468                                             32 * 1024);
3469           n->quota_violation_count--;
3470         }
3471     }
3472   GNUNET_STATISTICS_update (stats,
3473                             gettext_noop ("# payload received from other peers"),
3474                             msize,
3475                             GNUNET_NO);
3476   /* transmit message to all clients */
3477   uint32_t ats_count = 2;
3478   size_t size = sizeof (struct InboundMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information) + msize;
3479   if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
3480           GNUNET_break(0);
3481
3482   im = GNUNET_malloc (size);
3483   im->header.size = htons (size);
3484   im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
3485   im->peer = n->id;
3486   im->ats_count = htonl(ats_count);
3487   /* Setting ATS data */
3488   (&(im->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
3489   (&(im->ats))[0].value = htonl (n->distance);
3490   (&(im->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
3491   (&(im->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
3492   (&(im->ats))[ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
3493   (&(im->ats))[ats_count].value = htonl (0);
3494
3495   memcpy (&((&(im->ats))[ats_count+1]), message, msize);
3496   cpos = clients;
3497   while (cpos != NULL)
3498     {
3499       transmit_to_client (cpos, &im->header, GNUNET_YES);
3500       cpos = cpos->next;
3501     }
3502   GNUNET_free (im);
3503 }
3504
3505
3506 /**
3507  * Iterator over hash map entries.  Checks if the given validation
3508  * entry is for the same challenge as what is given in the PONG.
3509  *
3510  * @param cls the 'struct TransportPongMessage*'
3511  * @param key peer identity
3512  * @param value value in the hash map ('struct ValidationEntry')
3513  * @return GNUNET_YES if we should continue to
3514  *         iterate (mismatch), GNUNET_NO if not (entry matched)
3515  */
3516 static int
3517 check_pending_validation (void *cls,
3518                           const GNUNET_HashCode * key,
3519                           void *value)
3520 {
3521   const struct TransportPongMessage *pong = cls;
3522   struct ValidationEntry *ve = value;
3523   struct AddValidatedAddressContext avac;
3524   unsigned int challenge = ntohl(pong->challenge);
3525   struct GNUNET_HELLO_Message *hello;
3526   struct GNUNET_PeerIdentity target;
3527   struct NeighbourList *n;
3528   struct ForeignAddressList *fal;
3529   struct OwnAddressList *oal;
3530   struct TransportPlugin *tp;
3531   struct GNUNET_MessageHeader *prem;
3532   uint16_t ps;
3533   const char *addr;
3534   size_t slen;
3535   size_t alen;
3536
3537   ps = ntohs (pong->header.size);
3538   if (ps < sizeof (struct TransportPongMessage))
3539     {
3540       GNUNET_break_op (0);
3541       return GNUNET_NO;
3542     }
3543   addr = (const char*) &pong[1];
3544   slen = strlen (ve->transport_name) + 1;
3545   if ( (ps - sizeof (struct TransportPongMessage) < slen) ||
3546        (ve->challenge != challenge) ||
3547        (addr[slen-1] != '\0') ||
3548        (0 != strcmp (addr, ve->transport_name)) ||
3549        (ntohl (pong->purpose.size)
3550         != sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
3551         sizeof (uint32_t) +
3552         sizeof (struct GNUNET_TIME_AbsoluteNBO) +
3553         sizeof (struct GNUNET_PeerIdentity) + ps - sizeof (struct TransportPongMessage)) )
3554     {
3555       return GNUNET_YES;
3556     }
3557
3558   alen = ps - sizeof (struct TransportPongMessage) - slen;
3559   switch (ntohl (pong->purpose.purpose))
3560     {
3561     case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN:
3562       if ( (ve->addrlen + slen != ntohl (pong->addrlen)) ||
3563            (0 != memcmp (&addr[slen],
3564                          ve->addr,
3565                          ve->addrlen)) )
3566         {
3567           return GNUNET_YES; /* different entry, keep trying! */
3568         }
3569       if (0 != memcmp (&pong->pid,
3570                        key,
3571                        sizeof (struct GNUNET_PeerIdentity)))
3572         {
3573           GNUNET_break_op (0);
3574           return GNUNET_NO;
3575         }
3576       if (GNUNET_OK !=
3577           GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
3578                                     &pong->purpose,
3579                                     &pong->signature,
3580                                     &ve->publicKey))
3581         {
3582           GNUNET_break_op (0);
3583           return GNUNET_NO;
3584         }
3585
3586 #if DEBUG_TRANSPORT
3587       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3588                   "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
3589                   GNUNET_h2s (key),
3590                   a2s (ve->transport_name,
3591                        (const struct sockaddr *) ve->addr,
3592                        ve->addrlen),
3593                   ve->transport_name);
3594 #endif
3595       break;
3596     case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING:
3597       if (0 != memcmp (&pong->pid,
3598                          &my_identity,
3599                          sizeof (struct GNUNET_PeerIdentity)))
3600         {
3601           GNUNET_break_op (0);
3602           return GNUNET_NO;
3603         }
3604       if (ve->addrlen != 0)
3605         {
3606           /* must have been for a different validation entry */
3607           return GNUNET_YES;
3608         }
3609       tp = find_transport (ve->transport_name);
3610       if (tp == NULL)
3611         {
3612           GNUNET_break (0);
3613           return GNUNET_YES;
3614         }
3615       oal = tp->addresses;
3616       while (NULL != oal)
3617         {
3618           if ( (oal->addrlen == alen) &&
3619                (0 == memcmp (&oal[1],
3620                              &addr[slen],
3621                              alen)) )
3622             break;
3623           oal = oal->next;
3624         }
3625       if (oal == NULL)
3626         {
3627           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3628                       _("Not accepting PONG with address `%s' since I cannot confirm having this address.\n"),
3629                       a2s (ve->transport_name,
3630                            &addr[slen],
3631                            alen));
3632           return GNUNET_NO;     
3633         }
3634       if (GNUNET_OK !=
3635           GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING,
3636                                     &pong->purpose,
3637                                     &pong->signature,
3638                                     &ve->publicKey))
3639         {
3640           GNUNET_break_op (0);
3641           return GNUNET_NO;
3642         }
3643
3644 #if DEBUG_TRANSPORT
3645       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3646                   "Confirmed that peer `%4s' is talking to us using address `%s' (%s) for us.\n",
3647                   GNUNET_h2s (key),
3648                   a2s (ve->transport_name,
3649                        &addr[slen],
3650                        alen),
3651                   ve->transport_name);
3652 #endif
3653       break;
3654     default:
3655       GNUNET_break_op (0);
3656       return GNUNET_NO;
3657     }
3658   if (GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value == 0)
3659     {
3660       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3661                   _("Received expired signature.  Check system time.\n"));
3662       return GNUNET_NO;
3663     }
3664   GNUNET_STATISTICS_update (stats,
3665                             gettext_noop ("# address validation successes"),
3666                             1,
3667                             GNUNET_NO);
3668   /* create the updated HELLO */
3669   GNUNET_CRYPTO_hash (&ve->publicKey,
3670                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3671                       &target.hashPubKey);
3672   if (ve->addr != NULL)
3673     {
3674       avac.done = GNUNET_NO;
3675       avac.ve = ve;
3676       hello = GNUNET_HELLO_create (&ve->publicKey,
3677                                    &add_validated_address,
3678                                    &avac);
3679       GNUNET_PEERINFO_add_peer (peerinfo,
3680                                 hello);
3681       GNUNET_free (hello);
3682     }
3683   n = find_neighbour (&target);
3684   if (n != NULL)
3685     {
3686       n->publicKey = ve->publicKey;
3687       n->public_key_valid = GNUNET_YES;
3688       fal = add_peer_address (n,
3689                               ve->transport_name,
3690                               ve->session,
3691                               ve->addr,
3692                               ve->addrlen);
3693       GNUNET_assert (fal != NULL);
3694       fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
3695       fal->validated = GNUNET_YES;
3696       mark_address_connected (fal);
3697       GNUNET_STATISTICS_update (stats,
3698                                 gettext_noop ("# peer addresses considered valid"),
3699                                 1,
3700                                 GNUNET_NO);
3701       fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
3702       schedule_next_ping (fal);
3703       if (n->latency.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
3704         n->latency = fal->latency;
3705       else
3706         n->latency.rel_value = (fal->latency.rel_value + n->latency.rel_value) / 2;
3707
3708       n->distance = fal->distance;
3709       if (GNUNET_NO == n->received_pong)
3710         {
3711           n->received_pong = GNUNET_YES;
3712           notify_clients_connect (&target, n->latency, n->distance);
3713           if (NULL != (prem = n->pre_connect_message_buffer))
3714             {
3715               n->pre_connect_message_buffer = NULL;
3716               handle_payload_message (prem, n);
3717               GNUNET_free (prem);
3718             }
3719         }
3720       if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
3721         {
3722           GNUNET_SCHEDULER_cancel (n->retry_task);
3723           n->retry_task = GNUNET_SCHEDULER_NO_TASK;
3724           try_transmission_to_peer (n);
3725         }
3726     }
3727
3728   /* clean up validation entry */
3729   GNUNET_assert (GNUNET_YES ==
3730                  GNUNET_CONTAINER_multihashmap_remove (validation_map,
3731                                                        key,
3732                                                        ve));
3733   abort_validation (NULL, NULL, ve);
3734   return GNUNET_NO;
3735 }
3736
3737
3738 /**
3739  * Function that will be called if we receive a validation
3740  * of an address challenge that we transmitted to another
3741  * peer.  Note that the validation should only be considered
3742  * acceptable if the challenge matches AND if the sender
3743  * address is at least a plausible address for this peer
3744  * (otherwise we may be seeing a MiM attack).
3745  *
3746  * @param cls closure
3747  * @param message the pong message
3748  * @param peer who responded to our challenge
3749  * @param sender_address string describing our sender address (as observed
3750  *         by the other peer in binary format)
3751  * @param sender_address_len number of bytes in 'sender_address'
3752  */
3753 static void
3754 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
3755              const struct GNUNET_PeerIdentity *peer,
3756              const char *sender_address,
3757              size_t sender_address_len)
3758 {
3759 #if DEBUG_TRANSPORT > 1
3760   /* we get tons of these that just get discarded, only log
3761      if we are quite verbose */
3762   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3763               "Receiving `%s' message from `%4s'.\n", "PONG",
3764               GNUNET_i2s (peer));
3765 #endif
3766   GNUNET_STATISTICS_update (stats,
3767                             gettext_noop ("# PONG messages received"),
3768                             1,
3769                             GNUNET_NO);
3770   if (GNUNET_SYSERR !=
3771       GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
3772                                                   &peer->hashPubKey,
3773                                                   &check_pending_validation,
3774                                                   (void*) message))
3775     {
3776       /* This is *expected* to happen a lot since we send
3777          PONGs to *all* known addresses of the sender of
3778          the PING, so most likely we get multiple PONGs
3779          per PING, and all but the first PONG will end up
3780          here. So really we should not print anything here
3781          unless we want to be very, very verbose... */
3782 #if DEBUG_TRANSPORT > 2
3783       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3784                   "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
3785                   "PONG",
3786                   GNUNET_i2s (peer),
3787                   "PING");
3788 #endif
3789       return;
3790     }
3791
3792 }
3793
3794
3795 /**
3796  * Try to validate a neighbour's address by sending him our HELLO and a PING.
3797  *
3798  * @param cls the 'struct ValidationEntry*'
3799  * @param neighbour neighbour to validate, NULL if validation failed
3800  */
3801 static void
3802 transmit_hello_and_ping (void *cls,
3803                          struct NeighbourList *neighbour)
3804 {
3805   struct ValidationEntry *va = cls;
3806   struct ForeignAddressList *peer_address;
3807   struct TransportPingMessage ping;
3808   uint16_t hello_size;
3809   size_t tsize;
3810   char * message_buf;
3811   struct GNUNET_PeerIdentity id;
3812   size_t slen;
3813
3814   GNUNET_CRYPTO_hash (&va->publicKey,
3815                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3816                       &id.hashPubKey);
3817   if (neighbour == NULL)
3818     {
3819       /* FIXME: stats... */
3820       GNUNET_break (GNUNET_OK ==
3821                     GNUNET_CONTAINER_multihashmap_remove (validation_map,
3822                                                           &id.hashPubKey,
3823                                                           va));
3824       abort_validation (NULL, NULL, va);
3825       return;
3826     }
3827   neighbour->publicKey = va->publicKey;
3828   neighbour->public_key_valid = GNUNET_YES;
3829   peer_address = add_peer_address (neighbour,
3830                                    va->transport_name, NULL,
3831                                    (const void*) &va[1],
3832                                    va->addrlen);
3833   if (peer_address == NULL)
3834     {
3835       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3836                   "Failed to add peer `%4s' for plugin `%s'\n",
3837                   GNUNET_i2s (&neighbour->id),
3838                   va->transport_name);
3839       GNUNET_break (GNUNET_OK ==
3840                     GNUNET_CONTAINER_multihashmap_remove (validation_map,
3841                                                           &id.hashPubKey,
3842                                                           va));
3843       abort_validation (NULL, NULL, va);
3844       return;
3845     }
3846   hello_size = GNUNET_HELLO_size(our_hello);
3847   slen = strlen(va->transport_name) + 1;
3848   tsize = sizeof(struct TransportPingMessage) + hello_size + va->addrlen + slen;
3849   message_buf = GNUNET_malloc(tsize);
3850   ping.challenge = htonl(va->challenge);
3851   ping.header.size = htons(sizeof(struct TransportPingMessage) + slen + va->addrlen);
3852   ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3853   memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
3854   memcpy(message_buf, our_hello, hello_size);
3855   memcpy(&message_buf[hello_size],
3856          &ping,
3857          sizeof(struct TransportPingMessage));
3858   memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
3859          va->transport_name,
3860          slen);
3861   memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
3862          &va[1],
3863          va->addrlen);
3864 #if DEBUG_TRANSPORT
3865   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3866               "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
3867               (va->addrlen == 0)
3868               ? "<inbound>"
3869               : a2s (va->transport_name,
3870                      (const void*) &va[1], va->addrlen),
3871               va->transport_name,
3872               GNUNET_i2s (&neighbour->id),
3873               "HELLO", hello_size,
3874               "PING", sizeof (struct TransportPingMessage) + va->addrlen + slen);
3875 #endif
3876
3877   GNUNET_STATISTICS_update (stats,
3878                             gettext_noop ("# PING messages sent for initial validation"),
3879                             1,
3880                             GNUNET_NO);
3881   transmit_to_peer (NULL, peer_address,
3882                     GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3883                     HELLO_VERIFICATION_TIMEOUT,
3884                     message_buf, tsize,
3885                     GNUNET_YES, neighbour);
3886   GNUNET_free(message_buf);
3887 }
3888
3889
3890 /**
3891  * Check if the given address is already being validated; if not,
3892  * append the given address to the list of entries that are being be
3893  * validated and initiate validation.
3894  *
3895  * @param cls closure ('struct CheckHelloValidatedContext *')
3896  * @param tname name of the transport
3897  * @param expiration expiration time
3898  * @param addr the address
3899  * @param addrlen length of the address
3900  * @return GNUNET_OK (always)
3901  */
3902 static int
3903 run_validation (void *cls,
3904                 const char *tname,
3905                 struct GNUNET_TIME_Absolute expiration,
3906                 const void *addr,
3907                 uint16_t addrlen)
3908 {
3909   struct CheckHelloValidatedContext *chvc = cls;
3910   struct GNUNET_PeerIdentity id;
3911   struct TransportPlugin *tp;
3912   struct ValidationEntry *va;
3913   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
3914   struct CheckAddressExistsClosure caec;
3915   struct OwnAddressList *oal;
3916
3917   GNUNET_assert (addr != NULL);
3918
3919   GNUNET_STATISTICS_update (stats,
3920                             gettext_noop ("# peer addresses scheduled for validation"),
3921                             1,
3922                             GNUNET_NO);
3923   tp = find_transport (tname);
3924   if (tp == NULL)
3925     {
3926       GNUNET_log (GNUNET_ERROR_TYPE_INFO |
3927                   GNUNET_ERROR_TYPE_BULK,
3928                   _
3929                   ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
3930                   tname);
3931       GNUNET_STATISTICS_update (stats,
3932                                 gettext_noop ("# peer addresses not validated (plugin not available)"),
3933                                 1,
3934                                 GNUNET_NO);
3935       return GNUNET_OK;
3936     }
3937   /* check if this is one of our own addresses */
3938   oal = tp->addresses;
3939   while (NULL != oal)
3940     {
3941       if ( (oal->addrlen == addrlen) &&
3942            (0 == memcmp (&oal[1],
3943                          addr,
3944                          addrlen)) )
3945         {
3946           /* not plausible, this address is equivalent to our own address! */
3947           GNUNET_STATISTICS_update (stats,
3948                                     gettext_noop ("# peer addresses not validated (loopback)"),
3949                                     1,
3950                                     GNUNET_NO);
3951           return GNUNET_OK;
3952         }
3953       oal = oal->next;
3954     }
3955   GNUNET_HELLO_get_key (chvc->hello, &pk);
3956   GNUNET_CRYPTO_hash (&pk,
3957                       sizeof (struct
3958                               GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3959                       &id.hashPubKey);
3960
3961   if (is_blacklisted(&id, tp))
3962     {
3963 #if DEBUG_TRANSPORT
3964       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3965                   "Attempted to validate blacklisted peer `%s' using `%s'!\n",
3966                   GNUNET_i2s(&id),
3967                   tname);
3968 #endif
3969       return GNUNET_OK;
3970     }
3971
3972   caec.addr = addr;
3973   caec.addrlen = addrlen;
3974   caec.session = NULL;
3975   caec.tname = tname;
3976   caec.exists = GNUNET_NO;
3977   GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3978                                          &check_address_exists,
3979                                          &caec);
3980   if (caec.exists == GNUNET_YES)
3981     {
3982       /* During validation attempts we will likely trigger the other
3983          peer trying to validate our address which in turn will cause
3984          it to send us its HELLO, so we expect to hit this case rather
3985          frequently.  Only print something if we are very verbose. */
3986 #if DEBUG_TRANSPORT > 1
3987       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3988                   "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
3989                   a2s (tname, addr, addrlen),
3990                   tname,
3991                   GNUNET_i2s (&id));
3992 #endif
3993       GNUNET_STATISTICS_update (stats,
3994                                 gettext_noop ("# peer addresses not validated (in progress)"),
3995                                 1,
3996                                 GNUNET_NO);
3997       return GNUNET_OK;
3998     }
3999   va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
4000   va->chvc = chvc;
4001   chvc->ve_count++;
4002   va->transport_name = GNUNET_strdup (tname);
4003   va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
4004                                             UINT_MAX);
4005   va->send_time = GNUNET_TIME_absolute_get();
4006   va->addr = (const void*) &va[1];
4007   memcpy (&va[1], addr, addrlen);
4008   va->addrlen = addrlen;
4009   GNUNET_HELLO_get_key (chvc->hello,
4010                         &va->publicKey);
4011   va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
4012                                                    &timeout_hello_validation,
4013                                                    va);
4014   GNUNET_CONTAINER_multihashmap_put (validation_map,
4015                                      &id.hashPubKey,
4016                                      va,
4017                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
4018   setup_peer_check_blacklist (&id, GNUNET_NO,
4019                               &transmit_hello_and_ping,
4020                               va);
4021   return GNUNET_OK;
4022 }
4023
4024
4025 /**
4026  * Check if addresses in validated hello "h" overlap with
4027  * those in "chvc->hello" and validate the rest.
4028  *
4029  * @param cls closure
4030  * @param peer id of the peer, NULL for last call
4031  * @param h hello message for the peer (can be NULL)
4032  */
4033 static void
4034 check_hello_validated (void *cls,
4035                        const struct GNUNET_PeerIdentity *peer,
4036                        const struct GNUNET_HELLO_Message *h)
4037 {
4038   struct CheckHelloValidatedContext *chvc = cls;
4039   struct GNUNET_HELLO_Message *plain_hello;
4040   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4041   struct GNUNET_PeerIdentity target;
4042   struct NeighbourList *n;
4043
4044   if (peer == NULL)
4045     {
4046       GNUNET_STATISTICS_update (stats,
4047                                 gettext_noop ("# outstanding peerinfo iterate requests"),
4048                                 -1,
4049                                 GNUNET_NO);
4050       chvc->piter = NULL;
4051       if (GNUNET_NO == chvc->hello_known)
4052         {
4053           /* notify PEERINFO about the peer now, so that we at least
4054              have the public key if some other component needs it */
4055           GNUNET_HELLO_get_key (chvc->hello, &pk);
4056           GNUNET_CRYPTO_hash (&pk,
4057                               sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4058                               &target.hashPubKey);
4059           plain_hello = GNUNET_HELLO_create (&pk,
4060                                              NULL,
4061                                              NULL);
4062           GNUNET_PEERINFO_add_peer (peerinfo, plain_hello);
4063           GNUNET_free (plain_hello);
4064 #if DEBUG_TRANSPORT_HELLO
4065           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4066                       "PEERINFO had no `%s' message for peer `%4s', full validation needed.\n",
4067                       "HELLO",
4068                       GNUNET_i2s (&target));
4069 #endif
4070           GNUNET_STATISTICS_update (stats,
4071                                     gettext_noop ("# new HELLOs requiring full validation"),
4072                                     1,
4073                                     GNUNET_NO);
4074           GNUNET_HELLO_iterate_addresses (chvc->hello,
4075                                           GNUNET_NO,
4076                                           &run_validation,
4077                                           chvc);
4078         }
4079       else
4080         {
4081           GNUNET_STATISTICS_update (stats,
4082                                     gettext_noop ("# duplicate HELLO (peer known)"),
4083                                     1,
4084                                     GNUNET_NO);
4085         }
4086       chvc->ve_count--;
4087       if (chvc->ve_count == 0)
4088         {
4089           GNUNET_CONTAINER_DLL_remove (chvc_head,
4090                                        chvc_tail,
4091                                        chvc);
4092           GNUNET_free (chvc);   
4093         }
4094       return;
4095     }
4096   if (h == NULL)
4097     return;
4098 #if DEBUG_TRANSPORT_HELLO
4099   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4100               "PEERINFO had `%s' message for peer `%4s', validating only new addresses.\n",
4101               "HELLO",
4102               GNUNET_i2s (peer));
4103 #endif
4104   chvc->hello_known = GNUNET_YES;
4105   n = find_neighbour (peer);
4106   if (n != NULL)
4107     {
4108 #if DEBUG_TRANSPORT_HELLO
4109       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4110                   "Calling hello_iterate_addresses for %s!\n",
4111                   GNUNET_i2s (peer));
4112 #endif
4113       GNUNET_HELLO_iterate_addresses (h,
4114                                       GNUNET_NO,
4115                                       &add_to_foreign_address_list,
4116                                       n);
4117       try_transmission_to_peer (n);
4118     }
4119   else
4120     {
4121 #if DEBUG_TRANSPORT_HELLO
4122       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4123                   "No existing neighbor record for %s!\n",
4124                   GNUNET_i2s (peer));
4125 #endif
4126       GNUNET_STATISTICS_update (stats,
4127                                 gettext_noop ("# no existing neighbour record (validating HELLO)"),
4128                                 1,
4129                                 GNUNET_NO);
4130     }
4131   GNUNET_STATISTICS_update (stats,
4132                             gettext_noop ("# HELLO validations (update case)"),
4133                             1,
4134                             GNUNET_NO);
4135   GNUNET_HELLO_iterate_new_addresses (chvc->hello,
4136                                       h,
4137                                       GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME),
4138                                       &run_validation,
4139                                       chvc);
4140 }
4141
4142
4143 /**
4144  * Process HELLO-message.
4145  *
4146  * @param plugin transport involved, may be NULL
4147  * @param message the actual message
4148  * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
4149  */
4150 static int
4151 process_hello (struct TransportPlugin *plugin,
4152                const struct GNUNET_MessageHeader *message)
4153 {
4154   uint16_t hsize;
4155   struct GNUNET_PeerIdentity target;
4156   const struct GNUNET_HELLO_Message *hello;
4157   struct CheckHelloValidatedContext *chvc;
4158   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
4159 #if DEBUG_TRANSPORT_HELLO > 2
4160   char *my_id;
4161 #endif
4162   hsize = ntohs (message->size);
4163   if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
4164       (hsize < sizeof (struct GNUNET_MessageHeader)))
4165     {
4166       GNUNET_break (0);
4167       return GNUNET_SYSERR;
4168     }
4169   GNUNET_STATISTICS_update (stats,
4170                             gettext_noop ("# HELLOs received for validation"),
4171                             1,
4172                             GNUNET_NO);
4173
4174   /* first, check if load is too high */
4175   if (GNUNET_SCHEDULER_get_load (GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
4176     {
4177       GNUNET_STATISTICS_update (stats,
4178                                 gettext_noop ("# HELLOs ignored due to high load"),
4179                                 1,
4180                                 GNUNET_NO);
4181 #if DEBUG_TRANSPORT_HELLO
4182       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4183                   "Ignoring `%s' for `%4s', load too high.\n",
4184                   "HELLO",
4185                   GNUNET_i2s (&target));
4186 #endif
4187       return GNUNET_OK;
4188     }
4189   hello = (const struct GNUNET_HELLO_Message *) message;
4190   if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
4191     {
4192 #if DEBUG_TRANSPORT_HELLO
4193       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4194                   "Unable to get public key from `%s' for `%4s'!\n",
4195                   "HELLO",
4196                   GNUNET_i2s (&target));
4197 #endif
4198       GNUNET_break_op (0);
4199       return GNUNET_SYSERR;
4200     }
4201
4202   GNUNET_CRYPTO_hash (&publicKey,
4203                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4204                       &target.hashPubKey);
4205
4206 #if DEBUG_TRANSPORT_HELLO
4207   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4208               "Received `%s' message for `%4s'\n",
4209               "HELLO",
4210               GNUNET_i2s (&target));
4211 #endif
4212
4213   if (0 == memcmp (&my_identity,
4214                    &target,
4215                    sizeof (struct GNUNET_PeerIdentity)))
4216     {
4217       GNUNET_STATISTICS_update (stats,
4218                                 gettext_noop ("# HELLOs ignored for validation (is my own HELLO)"),
4219                                 1,
4220                                 GNUNET_NO);
4221       return GNUNET_OK;
4222     }
4223   chvc = chvc_head;
4224   while (NULL != chvc)
4225     {
4226       if (GNUNET_HELLO_equals (hello,
4227                                chvc->hello,
4228                                GNUNET_TIME_absolute_get ()).abs_value > 0)
4229         {
4230 #if DEBUG_TRANSPORT_HELLO > 2
4231           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4232                       "Received duplicate `%s' message for `%4s'; ignored\n",
4233                       "HELLO",
4234                       GNUNET_i2s (&target));
4235 #endif
4236           return GNUNET_OK; /* validation already pending */
4237         }
4238       if (GNUNET_HELLO_size(hello) == GNUNET_HELLO_size (chvc->hello))
4239         GNUNET_break (0 != memcmp (hello, chvc->hello,
4240                                    GNUNET_HELLO_size(hello)));
4241       chvc = chvc->next;
4242     }
4243
4244 #if BREAK_TESTS
4245   struct NeighbourList *temp_neighbor = find_neighbour(&target);
4246   if ((NULL != temp_neighbor))
4247     {
4248       fprintf(stderr, "Already know peer, ignoring hello\n");
4249       return GNUNET_OK;
4250     }
4251 #endif
4252
4253 #if DEBUG_TRANSPORT_HELLO > 2
4254   if (plugin != NULL)
4255     {
4256       my_id = GNUNET_strdup(GNUNET_i2s(plugin->env.my_identity));
4257       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4258                   "%s: Starting validation of `%s' message for `%4s' via '%s' of size %u\n",
4259                   my_id,
4260                   "HELLO",
4261                   GNUNET_i2s (&target),
4262                   plugin->short_name,
4263                   GNUNET_HELLO_size(hello));
4264       GNUNET_free(my_id);
4265     }
4266 #endif
4267   chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
4268   chvc->ve_count = 1;
4269   chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
4270   memcpy (&chvc[1], hello, hsize);
4271   GNUNET_CONTAINER_DLL_insert (chvc_head,
4272                                chvc_tail,
4273                                chvc);
4274   /* finally, check if HELLO was previously validated
4275      (continuation will then schedule actual validation) */
4276   GNUNET_STATISTICS_update (stats,
4277                             gettext_noop ("# peerinfo process hello iterate requests"),
4278                             1,
4279                             GNUNET_NO);
4280   GNUNET_STATISTICS_update (stats,
4281                             gettext_noop ("# outstanding peerinfo iterate requests"),
4282                             1,
4283                             GNUNET_NO);
4284   chvc->piter = GNUNET_PEERINFO_iterate (peerinfo,
4285                                          &target,
4286                                          HELLO_VERIFICATION_TIMEOUT,
4287                                          &check_hello_validated, chvc);
4288   return GNUNET_OK;
4289 }
4290
4291
4292 /**
4293  * The peer specified by the given neighbour has timed-out or a plugin
4294  * has disconnected.  We may either need to do nothing (other plugins
4295  * still up), or trigger a full disconnect and clean up.  This
4296  * function updates our state and does the necessary notifications.
4297  * Also notifies our clients that the neighbour is now officially
4298  * gone.
4299  *
4300  * @param n the neighbour list entry for the peer
4301  * @param check GNUNET_YES to check if ALL addresses for this peer
4302  *              are gone, GNUNET_NO to force a disconnect of the peer
4303  *              regardless of whether other addresses exist.
4304  */
4305 static void
4306 disconnect_neighbour (struct NeighbourList *n, int check)
4307 {
4308   struct ReadyList *rpos;
4309   struct NeighbourList *npos;
4310   struct NeighbourList *nprev;
4311   struct MessageQueue *mq;
4312   struct ForeignAddressList *peer_addresses;
4313   struct ForeignAddressList *peer_pos;
4314
4315   if (GNUNET_YES == check)
4316     {
4317       rpos = n->plugins;
4318       while (NULL != rpos)
4319         {
4320           peer_addresses = rpos->addresses;
4321           while (peer_addresses != NULL)
4322             {
4323               if (GNUNET_YES == peer_addresses->connected)
4324                 {
4325                   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4326                             "NOT Disconnecting from `%4s', still have live addresses!\n",
4327                             GNUNET_i2s (&n->id));
4328                   return;             /* still connected */
4329                 }
4330               peer_addresses = peer_addresses->next;
4331             }
4332           rpos = rpos->next;
4333         }
4334     }
4335 #if DEBUG_TRANSPORT
4336   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4337               "Disconnecting from `%4s'\n",
4338               GNUNET_i2s (&n->id));
4339 #endif
4340   /* remove n from neighbours list */
4341   nprev = NULL;
4342   npos = neighbours;
4343   while ((npos != NULL) && (npos != n))
4344     {
4345       nprev = npos;
4346       npos = npos->next;
4347     }
4348   GNUNET_assert (npos != NULL);
4349   if (nprev == NULL)
4350     neighbours = n->next;
4351   else
4352     nprev->next = n->next;
4353
4354   /* notify all clients about disconnect */
4355   if (GNUNET_YES == n->received_pong)
4356     notify_clients_disconnect (&n->id);
4357
4358   /* clean up all plugins, cancel connections and pending transmissions */
4359   while (NULL != (rpos = n->plugins))
4360     {
4361       n->plugins = rpos->next;
4362       rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
4363       while (rpos->addresses != NULL)
4364         {
4365           peer_pos = rpos->addresses;
4366           rpos->addresses = peer_pos->next;
4367           if (peer_pos->connected == GNUNET_YES)
4368             GNUNET_STATISTICS_update (stats,
4369                                       gettext_noop ("# connected addresses"),
4370                                       -1,
4371                                       GNUNET_NO);
4372           if (GNUNET_YES == peer_pos->validated)
4373             GNUNET_STATISTICS_update (stats,
4374                                       gettext_noop ("# peer addresses considered valid"),
4375                                       -1,
4376                                       GNUNET_NO);
4377           if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
4378             {
4379               GNUNET_SCHEDULER_cancel (peer_pos->revalidate_task);
4380               peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
4381             }
4382           GNUNET_free(peer_pos);
4383         }
4384       GNUNET_free (rpos);
4385     }
4386
4387   /* free all messages on the queue */
4388   while (NULL != (mq = n->messages_head))
4389     {
4390       GNUNET_STATISTICS_update (stats,
4391                                 gettext_noop ("# bytes in message queue for other peers"),
4392                                 - (int64_t) mq->message_buf_size,
4393                                 GNUNET_NO);
4394       GNUNET_STATISTICS_update (stats,
4395                                 gettext_noop ("# bytes discarded due to disconnect"),
4396                                 mq->message_buf_size,
4397                                 GNUNET_NO);
4398       GNUNET_CONTAINER_DLL_remove (n->messages_head,
4399                                    n->messages_tail,
4400                                    mq);
4401       GNUNET_assert (0 == memcmp(&mq->neighbour_id,
4402                                  &n->id,
4403                                  sizeof(struct GNUNET_PeerIdentity)));
4404       GNUNET_free (mq);
4405     }
4406   if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
4407     {
4408       GNUNET_SCHEDULER_cancel (n->timeout_task);
4409       n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
4410     }
4411   if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4412     {
4413       GNUNET_SCHEDULER_cancel (n->retry_task);
4414       n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4415     }
4416   if (n->piter != NULL)
4417     {
4418       GNUNET_PEERINFO_iterate_cancel (n->piter);
4419       GNUNET_STATISTICS_update (stats,
4420                                 gettext_noop ("# outstanding peerinfo iterate requests"),
4421                                 -1,
4422                                 GNUNET_NO);
4423       n->piter = NULL;
4424     }
4425   /* finally, free n itself */
4426   GNUNET_STATISTICS_update (stats,
4427                             gettext_noop ("# active neighbours"),
4428                             -1,
4429                             GNUNET_NO);
4430   GNUNET_free_non_null (n->pre_connect_message_buffer);
4431   GNUNET_free (n);
4432 }
4433
4434
4435 /**
4436  * We have received a PING message from someone.  Need to send a PONG message
4437  * in response to the peer by any means necessary.
4438  */
4439 static int
4440 handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
4441             const struct GNUNET_PeerIdentity *peer,
4442             struct Session *session,
4443             const char *sender_address,
4444             uint16_t sender_address_len)
4445 {
4446   struct TransportPlugin *plugin = cls;
4447   struct SessionHeader *session_header = (struct SessionHeader*) session;
4448   struct TransportPingMessage *ping;
4449   struct TransportPongMessage *pong;
4450   struct NeighbourList *n;
4451   struct ReadyList *rl;
4452   struct ForeignAddressList *fal;
4453   struct OwnAddressList *oal;
4454   const char *addr;
4455   size_t alen;
4456   size_t slen;
4457
4458   if (ntohs (message->size) < sizeof (struct TransportPingMessage))
4459     {
4460       GNUNET_break_op (0);
4461       return GNUNET_SYSERR;
4462     }
4463
4464   ping = (struct TransportPingMessage *) message;
4465   if (0 != memcmp (&ping->target,
4466                    plugin->env.my_identity,
4467                    sizeof (struct GNUNET_PeerIdentity)))
4468     {
4469       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4470                   _("Received `%s' message from `%s' destined for `%s' which is not me!\n"),
4471                   "PING",
4472                   (sender_address != NULL)
4473                   ? a2s (plugin->short_name,
4474                          (const struct sockaddr *)sender_address,
4475                          sender_address_len)
4476                   : "<inbound>",
4477                   GNUNET_i2s (&ping->target));
4478       return GNUNET_SYSERR;
4479     }
4480 #if DEBUG_PING_PONG
4481   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4482               "Processing `%s' from `%s'\n",
4483               "PING",
4484               (sender_address != NULL)
4485               ? a2s (plugin->short_name,
4486                      (const struct sockaddr *)sender_address,
4487                      sender_address_len)
4488               : "<inbound>");
4489 #endif
4490   GNUNET_STATISTICS_update (stats,
4491                             gettext_noop ("# PING messages received"),
4492                             1,
4493                             GNUNET_NO);
4494   addr = (const char*) &ping[1];
4495   alen = ntohs (message->size) - sizeof (struct TransportPingMessage);
4496   slen = strlen (plugin->short_name) + 1;
4497   if (alen == 0)
4498     {
4499       /* peer wants to confirm that we have an outbound connection to him */
4500       if (session == NULL)
4501         {
4502           GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4503                       _("Refusing to create PONG since I do not have a session with `%s'.\n"),
4504                       GNUNET_i2s (peer));
4505           return GNUNET_SYSERR;
4506         }
4507       pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len + slen);
4508       pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len + slen);
4509       pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
4510       pong->purpose.size =
4511         htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4512                sizeof (uint32_t) +
4513                sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4514                sizeof (struct GNUNET_PeerIdentity) + sender_address_len + slen);
4515       pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING);
4516       pong->challenge = ping->challenge;
4517       pong->addrlen = htonl(sender_address_len + slen);
4518       memcpy(&pong->pid,
4519              peer,
4520              sizeof(struct GNUNET_PeerIdentity));
4521       memcpy (&pong[1],
4522               plugin->short_name,
4523               slen);
4524       if ((sender_address!=NULL) && (sender_address_len > 0))
4525                   memcpy (&((char*)&pong[1])[slen],
4526                           sender_address,
4527                           sender_address_len);
4528       if (GNUNET_TIME_absolute_get_remaining (session_header->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4)
4529         {
4530           /* create / update cached sig */
4531 #if DEBUG_TRANSPORT
4532           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4533                       "Creating PONG signature to indicate active connection.\n");
4534 #endif
4535           session_header->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
4536           pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
4537           GNUNET_assert (GNUNET_OK ==
4538                          GNUNET_CRYPTO_rsa_sign (my_private_key,
4539                                                  &pong->purpose,
4540                                                  &session_header->pong_signature));
4541         }
4542       else
4543         {
4544           pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
4545         }
4546       memcpy (&pong->signature,
4547               &session_header->pong_signature,
4548               sizeof (struct GNUNET_CRYPTO_RsaSignature));
4549
4550
4551     }
4552   else
4553     {
4554       /* peer wants to confirm that this is one of our addresses */
4555       addr += slen;
4556       alen -= slen;
4557       if (GNUNET_OK !=
4558           plugin->api->check_address (plugin->api->cls,
4559                                       addr,
4560                                       alen))
4561         {
4562           GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4563                       _("Not confirming PING with address `%s' since I cannot confirm having this address.\n"),
4564                       a2s (plugin->short_name,
4565                            addr,
4566                            alen));
4567           return GNUNET_NO;
4568         }
4569       oal = plugin->addresses;
4570       while (NULL != oal)
4571         {
4572           if ( (oal->addrlen == alen) &&
4573                (0 == memcmp (addr,
4574                              &oal[1],
4575                              alen)) )
4576             break;
4577           oal = oal->next;
4578         }
4579       pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + alen + slen);
4580       pong->header.size = htons (sizeof (struct TransportPongMessage) + alen + slen);
4581       pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
4582       pong->purpose.size =
4583         htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4584                sizeof (uint32_t) +
4585                sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4586                sizeof (struct GNUNET_PeerIdentity) + alen + slen);
4587       pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN);
4588       pong->challenge = ping->challenge;
4589       pong->addrlen = htonl(alen + slen);
4590       memcpy(&pong->pid,
4591              &my_identity,
4592              sizeof(struct GNUNET_PeerIdentity));
4593       memcpy (&pong[1], plugin->short_name, slen);
4594       memcpy (&((char*)&pong[1])[slen], addr, alen);
4595       if ( (oal != NULL) &&
4596            (GNUNET_TIME_absolute_get_remaining (oal->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4) )
4597         {
4598           /* create / update cached sig */
4599 #if DEBUG_TRANSPORT
4600           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4601                       "Creating PONG signature to indicate ownership.\n");
4602 #endif
4603           oal->pong_sig_expires = GNUNET_TIME_absolute_min (oal->expires,
4604                                                             GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
4605           pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
4606           GNUNET_assert (GNUNET_OK ==
4607                          GNUNET_CRYPTO_rsa_sign (my_private_key,
4608                                                  &pong->purpose,
4609                                                  &oal->pong_signature));        
4610           memcpy (&pong->signature,
4611                   &oal->pong_signature,
4612                   sizeof (struct GNUNET_CRYPTO_RsaSignature));
4613         }
4614       else if (oal == NULL)
4615         {
4616           /* not using cache (typically DV-only) */
4617           pong->expiration = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
4618           GNUNET_assert (GNUNET_OK ==
4619                          GNUNET_CRYPTO_rsa_sign (my_private_key,
4620                                                  &pong->purpose,
4621                                                  &pong->signature));    
4622         }
4623       else
4624         {
4625           /* can used cached version */
4626           pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
4627           memcpy (&pong->signature,
4628                   &oal->pong_signature,
4629                   sizeof (struct GNUNET_CRYPTO_RsaSignature));
4630         }
4631     }
4632   n = find_neighbour(peer);
4633   GNUNET_assert (n != NULL);
4634   /* first try reliable response transmission */
4635   rl = n->plugins;
4636   while (rl != NULL)
4637     {
4638       fal = rl->addresses;
4639       while (fal != NULL)
4640         {
4641           if (-1 != rl->plugin->api->send (rl->plugin->api->cls,
4642                                            peer,
4643                                            (const char*) pong,
4644                                            ntohs (pong->header.size),
4645                                            TRANSPORT_PONG_PRIORITY,
4646                                            HELLO_VERIFICATION_TIMEOUT,
4647                                            fal->session,
4648                                            fal->addr,
4649                                            fal->addrlen,
4650                                            GNUNET_SYSERR,
4651                                            NULL, NULL))
4652             {
4653               /* done! */
4654               GNUNET_STATISTICS_update (stats,
4655                                         gettext_noop ("# PONGs unicast via reliable transport"),
4656                                         1,
4657                                         GNUNET_NO);
4658               GNUNET_free (pong);
4659               return GNUNET_OK;
4660             }
4661           fal = fal->next;
4662         }
4663       rl = rl->next;
4664     }
4665   /* no reliable method found, do multicast */
4666   GNUNET_STATISTICS_update (stats,
4667                             gettext_noop ("# PONGs multicast to all available addresses"),
4668                             1,
4669                             GNUNET_NO);
4670   rl = n->plugins;
4671   while (rl != NULL)
4672     {
4673       fal = rl->addresses;
4674       while (fal != NULL)
4675         {
4676           transmit_to_peer(NULL, fal,
4677                            TRANSPORT_PONG_PRIORITY,
4678                            HELLO_VERIFICATION_TIMEOUT,
4679                            (const char *)pong,
4680                            ntohs(pong->header.size),
4681                            GNUNET_YES,
4682                            n);
4683           fal = fal->next;
4684         }
4685       rl = rl->next;
4686     }
4687   GNUNET_free(pong);
4688   return GNUNET_OK;
4689 }
4690
4691
4692 /**
4693  * Function called by the plugin for each received message.
4694  * Update data volumes, possibly notify plugins about
4695  * reducing the rate at which they read from the socket
4696  * and generally forward to our receive callback.
4697  *
4698  * @param cls the "struct TransportPlugin *" we gave to the plugin
4699  * @param peer (claimed) identity of the other peer
4700  * @param message the message, NULL if we only care about
4701  *                learning about the delay until we should receive again
4702  * @param ats information for automatic transport selection
4703  * @param ats_count number of elements in ats not including 0-terminator
4704  * @param session identifier used for this session (can be NULL)
4705  * @param sender_address binary address of the sender (if observed)
4706  * @param sender_address_len number of bytes in sender_address
4707  * @return how long in ms the plugin should wait until receiving more data
4708  *         (plugins that do not support this, can ignore the return value)
4709  */
4710 static struct GNUNET_TIME_Relative
4711 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
4712                     const struct GNUNET_MessageHeader *message,
4713                     const struct GNUNET_TRANSPORT_ATS_Information *ats,
4714                     uint32_t ats_count,
4715                     struct Session *session,
4716                     const char *sender_address,
4717                     uint16_t sender_address_len)
4718 {
4719   struct TransportPlugin *plugin = cls;
4720   struct ReadyList *service_context;
4721   struct ForeignAddressList *peer_address;
4722   uint16_t msize;
4723   struct NeighbourList *n;
4724   struct GNUNET_TIME_Relative ret;
4725   if (is_blacklisted (peer, plugin))
4726     return GNUNET_TIME_UNIT_FOREVER_REL;
4727   uint32_t distance;
4728   int c;
4729
4730   n = find_neighbour (peer);
4731   if (n == NULL)
4732     n = setup_new_neighbour (peer, GNUNET_YES);
4733   service_context = n->plugins;
4734   while ((service_context != NULL) && (plugin != service_context->plugin))
4735     service_context = service_context->next;
4736   GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
4737   peer_address = NULL;
4738   distance = 1;
4739   for (c=0; c<ats_count; c++)
4740   {
4741           if (ntohl(ats[c].type) == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
4742           {
4743                   distance = ntohl(ats[c].value);
4744           }
4745   }
4746
4747   if (message != NULL)
4748     {
4749       if ( (session != NULL) ||
4750            (sender_address != NULL) )
4751         peer_address = add_peer_address (n,
4752                                          plugin->short_name,
4753                                          session,
4754                                          sender_address,
4755                                          sender_address_len);
4756       if (peer_address != NULL)
4757         {
4758           peer_address->distance = distance;
4759           if (GNUNET_YES == peer_address->validated)
4760             mark_address_connected (peer_address);
4761           peer_address->timeout
4762             =
4763             GNUNET_TIME_relative_to_absolute
4764             (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
4765           schedule_next_ping (peer_address);
4766         }
4767       /* update traffic received amount ... */
4768       msize = ntohs (message->size);
4769       GNUNET_STATISTICS_update (stats,
4770                                 gettext_noop ("# bytes received from other peers"),
4771                                 msize,
4772                                 GNUNET_NO);
4773       n->distance = distance;
4774       n->peer_timeout =
4775         GNUNET_TIME_relative_to_absolute
4776         (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
4777       GNUNET_SCHEDULER_cancel (n->timeout_task);
4778       n->timeout_task =
4779         GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
4780                                       &neighbour_timeout_task, n);
4781       if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
4782         {
4783           /* dropping message due to frequent inbound volume violations! */
4784           GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
4785                       GNUNET_ERROR_TYPE_BULK,
4786                       _
4787                       ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
4788                       n->in_tracker.available_bytes_per_s__,
4789                       n->quota_violation_count);
4790           GNUNET_STATISTICS_update (stats,
4791                                     gettext_noop ("# bandwidth quota violations by other peers"),
4792                                     1,
4793                                     GNUNET_NO);
4794           return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
4795         }
4796
4797 #if DEBUG_PING_PONG
4798           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4799                       "Received message of type %u and size %u from `%4s', sending to all clients.\n",
4800                       ntohs (message->type),
4801                       ntohs (message->size),
4802                       GNUNET_i2s (peer));
4803 #endif
4804       switch (ntohs (message->type))
4805         {
4806         case GNUNET_MESSAGE_TYPE_HELLO:
4807           GNUNET_STATISTICS_update (stats,
4808                                     gettext_noop ("# HELLO messages received from other peers"),
4809                                     1,
4810                                     GNUNET_NO);
4811           process_hello (plugin, message);
4812           break;
4813         case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
4814           handle_ping (plugin, message, peer, session, sender_address, sender_address_len);
4815           break;
4816         case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
4817           handle_pong (plugin, message, peer, sender_address, sender_address_len);
4818           break;
4819         default:
4820           handle_payload_message (message, n);
4821           break;
4822         }
4823     }
4824   ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
4825   if (ret.rel_value > 0)
4826     {
4827       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4828                   "Throttling read (%llu bytes excess at %u b/s), waiting %llums before reading more.\n",
4829                   (unsigned long long) n->in_tracker.consumption_since_last_update__,
4830                   (unsigned int) n->in_tracker.available_bytes_per_s__,
4831                   (unsigned long long) ret.rel_value);
4832       GNUNET_STATISTICS_update (stats,
4833                                 gettext_noop ("# ms throttling suggested"),
4834                                 (int64_t) ret.rel_value,
4835                                 GNUNET_NO);
4836     }
4837   return ret;
4838 }
4839
4840 /**
4841  * Handle START-message.  This is the first message sent to us
4842  * by any client which causes us to add it to our list.
4843  *
4844  * @param cls closure (always NULL)
4845  * @param client identification of the client
4846  * @param message the actual message
4847  */
4848 static void
4849 handle_start (void *cls,
4850               struct GNUNET_SERVER_Client *client,
4851               const struct GNUNET_MessageHeader *message)
4852 {
4853   const struct StartMessage *start;
4854   struct TransportClient *c;
4855   struct ConnectInfoMessage * cim;
4856   struct NeighbourList *n;
4857   uint32_t ats_count;
4858   size_t size;
4859
4860   start = (const struct StartMessage*) message;
4861 #if DEBUG_TRANSPORT
4862   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4863               "Received `%s' request from client\n", "START");
4864 #endif
4865   c = clients;
4866   while (c != NULL)
4867     {
4868       if (c->client == client)
4869         {
4870           /* client already on our list! */
4871           GNUNET_break (0);
4872           GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
4873           return;
4874         }
4875       c = c->next;
4876     }
4877   if ( (GNUNET_NO != ntohl (start->do_check)) &&
4878        (0 != memcmp (&start->self,
4879                      &my_identity,
4880                      sizeof (struct GNUNET_PeerIdentity))) )
4881     {
4882       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4883                   _("Rejecting control connection from peer `%s', which is not me!\n"),
4884                   GNUNET_i2s (&start->self));
4885       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
4886       return;
4887     }
4888   c = GNUNET_malloc (sizeof (struct TransportClient));
4889   c->next = clients;
4890   clients = c;
4891   c->client = client;
4892   if (our_hello != NULL)
4893   {
4894 #if DEBUG_TRANSPORT
4895       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4896                   "Sending our own `%s' to new client\n", "HELLO");
4897 #endif
4898       transmit_to_client (c,
4899                           (const struct GNUNET_MessageHeader *) our_hello,
4900                           GNUNET_NO);
4901       /* tell new client about all existing connections */
4902       ats_count = 2;
4903       size  = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
4904       if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
4905       {
4906           GNUNET_break(0);
4907       }
4908       cim = GNUNET_malloc (size);
4909       cim->header.size = htons (size);
4910       cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
4911       cim->ats_count = htonl(ats_count);
4912       (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
4913       (&(cim->ats))[2].value = htonl (0);
4914       n = neighbours;
4915       while (n != NULL)
4916           {
4917                   if (GNUNET_YES == n->received_pong)
4918                   {
4919                           (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
4920                           (&(cim->ats))[0].value = htonl (n->distance);
4921                           (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
4922                           (&(cim->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
4923                           cim->id = n->id;
4924                           transmit_to_client (c, &cim->header, GNUNET_NO);
4925                   }
4926             n = n->next;
4927       }
4928       GNUNET_free (cim);
4929   }
4930   GNUNET_SERVER_receive_done (client, GNUNET_OK);
4931 }
4932
4933
4934 /**
4935  * Handle HELLO-message.
4936  *
4937  * @param cls closure (always NULL)
4938  * @param client identification of the client
4939  * @param message the actual message
4940  */
4941 static void
4942 handle_hello (void *cls,
4943               struct GNUNET_SERVER_Client *client,
4944               const struct GNUNET_MessageHeader *message)
4945 {
4946   int ret;
4947
4948   GNUNET_STATISTICS_update (stats,
4949                             gettext_noop ("# HELLOs received from clients"),
4950                             1,
4951                             GNUNET_NO);
4952   ret = process_hello (NULL, message);
4953   GNUNET_SERVER_receive_done (client, ret);
4954 }
4955
4956
4957 /**
4958  * Closure for 'transmit_client_message'; followed by
4959  * 'msize' bytes of the actual message.
4960  */
4961 struct TransmitClientMessageContext
4962 {
4963   /**
4964    * Client on whom's behalf we are sending.
4965    */
4966   struct GNUNET_SERVER_Client *client;
4967
4968   /**
4969    * Timeout for the transmission.
4970    */
4971   struct GNUNET_TIME_Absolute timeout;
4972
4973   /**
4974    * Message priority.
4975    */
4976   uint32_t priority;
4977
4978   /**
4979    * Size of the message in bytes.
4980    */
4981   uint16_t msize;
4982 };
4983
4984
4985 /**
4986  * Schedule transmission of a message we got from a client to a peer.
4987  *
4988  * @param cls the 'struct TransmitClientMessageContext*'
4989  * @param n destination, or NULL on error (in that case, drop the message)
4990  */
4991 static void
4992 transmit_client_message (void *cls,
4993                          struct NeighbourList *n)
4994 {
4995   struct TransmitClientMessageContext *tcmc = cls;
4996   struct TransportClient *tc;
4997
4998   tc = clients;
4999   while ((tc != NULL) && (tc->client != tcmc->client))
5000     tc = tc->next;
5001
5002   if (n != NULL)
5003     {
5004       transmit_to_peer (tc, NULL, tcmc->priority,
5005                         GNUNET_TIME_absolute_get_remaining (tcmc->timeout),
5006                         (char *)&tcmc[1],
5007                         tcmc->msize, GNUNET_NO, n);
5008     }
5009   GNUNET_SERVER_receive_done (tcmc->client, GNUNET_OK);
5010   GNUNET_SERVER_client_drop (tcmc->client);
5011   GNUNET_free (tcmc);
5012 }
5013
5014
5015 /**
5016  * Handle SEND-message.
5017  *
5018  * @param cls closure (always NULL)
5019  * @param client identification of the client
5020  * @param message the actual message
5021  */
5022 static void
5023 handle_send (void *cls,
5024              struct GNUNET_SERVER_Client *client,
5025              const struct GNUNET_MessageHeader *message)
5026 {
5027   const struct OutboundMessage *obm;
5028   const struct GNUNET_MessageHeader *obmm;
5029   struct TransmitClientMessageContext *tcmc;
5030   uint16_t size;
5031   uint16_t msize;
5032
5033   size = ntohs (message->size);
5034   if (size <
5035       sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
5036     {
5037       GNUNET_break (0);
5038       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5039       return;
5040     }
5041   GNUNET_STATISTICS_update (stats,
5042                             gettext_noop ("# payload received for other peers"),
5043                             size,
5044                             GNUNET_NO);
5045   obm = (const struct OutboundMessage *) message;
5046   obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5047   msize = size - sizeof (struct OutboundMessage);
5048
5049   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5050               "Received `%s' request from client with target `%4s' and message of type %u and size %u\n",
5051               "SEND", GNUNET_i2s (&obm->peer),
5052               ntohs (obmm->type),
5053               msize);
5054
5055   tcmc = GNUNET_malloc (sizeof (struct TransmitClientMessageContext) + msize);
5056   tcmc->client = client;
5057   tcmc->priority = ntohl (obm->priority);
5058   tcmc->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
5059   tcmc->msize = msize;
5060   /* FIXME: this memcpy can be up to 7% of our total runtime */
5061   memcpy (&tcmc[1], obmm, msize);
5062   GNUNET_SERVER_client_keep (client);
5063   setup_peer_check_blacklist (&obm->peer, GNUNET_YES,
5064                               &transmit_client_message,
5065                               tcmc);
5066 }
5067
5068
5069 /**
5070  * Handle request connect message
5071  *
5072  * @param cls closure (always NULL)
5073  * @param client identification of the client
5074  * @param message the actual message
5075  */
5076 static void
5077 handle_request_connect (void *cls,
5078                         struct GNUNET_SERVER_Client *client,
5079                         const struct GNUNET_MessageHeader *message)
5080 {
5081   const struct TransportRequestConnectMessage *trcm =
5082     (const struct TransportRequestConnectMessage *) message;
5083
5084   GNUNET_STATISTICS_update (stats,
5085                             gettext_noop ("# REQUEST CONNECT messages received"),
5086                             1,
5087                             GNUNET_NO);
5088   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Received a request connect message for peer %s\n", GNUNET_i2s(&trcm->peer));
5089   setup_peer_check_blacklist (&trcm->peer, GNUNET_YES,
5090                               NULL, NULL);
5091   GNUNET_SERVER_receive_done (client, GNUNET_OK);
5092 }
5093
5094 /**
5095  * Handle SET_QUOTA-message.
5096  *
5097  * @param cls closure (always NULL)
5098  * @param client identification of the client
5099  * @param message the actual message
5100  */
5101 static void
5102 handle_set_quota (void *cls,
5103                   struct GNUNET_SERVER_Client *client,
5104                   const struct GNUNET_MessageHeader *message)
5105 {
5106   const struct QuotaSetMessage *qsm =
5107     (const struct QuotaSetMessage *) message;
5108   struct NeighbourList *n;
5109
5110   GNUNET_STATISTICS_update (stats,
5111                             gettext_noop ("# SET QUOTA messages received"),
5112                             1,
5113                             GNUNET_NO);
5114   n = find_neighbour (&qsm->peer);
5115   if (n == NULL)
5116     {
5117       GNUNET_SERVER_receive_done (client, GNUNET_OK);
5118       GNUNET_STATISTICS_update (stats,
5119                                 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
5120                                 1,
5121                                 GNUNET_NO);
5122       return;
5123     }
5124 #if DEBUG_TRANSPORT
5125   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5126               "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
5127               "SET_QUOTA",
5128               (unsigned int) ntohl (qsm->quota.value__),
5129               (unsigned int) n->in_tracker.available_bytes_per_s__,
5130               GNUNET_i2s (&qsm->peer));
5131 #endif
5132   GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
5133                                          qsm->quota);
5134   if (0 == ntohl (qsm->quota.value__))
5135     {
5136       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5137                 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&n->id),
5138                 "SET_QUOTA");
5139       disconnect_neighbour (n, GNUNET_NO);
5140     }
5141   GNUNET_SERVER_receive_done (client, GNUNET_OK);
5142 }
5143
5144
5145 /**
5146  * Take the given address and append it to the set of results sent back to
5147  * the client.
5148  *
5149  * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
5150  * @param address the resolved name, NULL to indicate the last response
5151  */
5152 static void
5153 transmit_address_to_client (void *cls, const char *address)
5154 {
5155   struct GNUNET_SERVER_TransmitContext *tc = cls;
5156   size_t slen;
5157
5158   if (NULL == address)
5159     slen = 0;
5160   else
5161     slen = strlen (address) + 1;
5162
5163   GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
5164                                               GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5165   if (NULL == address)
5166     GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5167 }
5168
5169
5170 /**
5171  * Handle AddressLookup-message.
5172  *
5173  * @param cls closure (always NULL)
5174  * @param client identification of the client
5175  * @param message the actual message
5176  */
5177 static void
5178 handle_address_lookup (void *cls,
5179                        struct GNUNET_SERVER_Client *client,
5180                        const struct GNUNET_MessageHeader *message)
5181 {
5182   const struct AddressLookupMessage *alum;
5183   struct TransportPlugin *lsPlugin;
5184   const char *nameTransport;
5185   const char *address;
5186   uint16_t size;
5187   struct GNUNET_SERVER_TransmitContext *tc;
5188   struct GNUNET_TIME_Absolute timeout;
5189   struct GNUNET_TIME_Relative rtimeout;
5190   int32_t numeric;
5191
5192   size = ntohs (message->size);
5193   if (size < sizeof (struct AddressLookupMessage))
5194     {
5195       GNUNET_break_op (0);
5196       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5197       return;
5198     }
5199   alum = (const struct AddressLookupMessage *) message;
5200   uint32_t addressLen = ntohl (alum->addrlen);
5201   if (size <= sizeof (struct AddressLookupMessage) + addressLen)
5202     {
5203       GNUNET_break_op (0);
5204       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5205       return;
5206     }
5207   address = (const char *) &alum[1];
5208   nameTransport = (const char *) &address[addressLen];
5209   if (nameTransport
5210       [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
5211     {
5212       GNUNET_break_op (0);
5213       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5214       return;
5215     }
5216   timeout = GNUNET_TIME_absolute_ntoh (alum->timeout);
5217   rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
5218   numeric = ntohl (alum->numeric_only);
5219   lsPlugin = find_transport (nameTransport);
5220   if (NULL == lsPlugin)
5221     {
5222       tc = GNUNET_SERVER_transmit_context_create (client);
5223       GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5224                                                   GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5225       GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5226       return;
5227     }
5228   tc = GNUNET_SERVER_transmit_context_create (client);
5229   lsPlugin->api->address_pretty_printer (lsPlugin->api->cls,
5230                                          nameTransport,
5231                                          address, addressLen,
5232                                          numeric,
5233                                          rtimeout,
5234                                          &transmit_address_to_client, tc);
5235 }
5236
5237
5238 /**
5239  * Setup the environment for this plugin.
5240  */
5241 static void
5242 create_environment (struct TransportPlugin *plug)
5243 {
5244   plug->env.cfg = cfg;
5245   plug->env.my_identity = &my_identity;
5246   plug->env.our_hello = &our_hello;
5247   plug->env.cls = plug;
5248   plug->env.receive = &plugin_env_receive;
5249   plug->env.notify_address = &plugin_env_notify_address;
5250   plug->env.session_end = &plugin_env_session_end;
5251   plug->env.max_connections = max_connect_per_transport;
5252   plug->env.stats = stats;
5253 }
5254
5255
5256 /**
5257  * Start the specified transport (load the plugin).
5258  */
5259 static void
5260 start_transport (struct GNUNET_SERVER_Handle *server,
5261                  const char *name)
5262 {
5263   struct TransportPlugin *plug;
5264   char *libname;
5265
5266   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5267               _("Loading `%s' transport plugin\n"), name);
5268   GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
5269   plug = GNUNET_malloc (sizeof (struct TransportPlugin));
5270   create_environment (plug);
5271   plug->short_name = GNUNET_strdup (name);
5272   plug->lib_name = libname;
5273   plug->next = plugins;
5274   plugins = plug;
5275   plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
5276   if (plug->api == NULL)
5277     {
5278       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5279                   _("Failed to load transport plugin for `%s'\n"), name);
5280       GNUNET_free (plug->short_name);
5281       plugins = plug->next;
5282       GNUNET_free (libname);
5283       GNUNET_free (plug);
5284     }
5285 }
5286
5287
5288 /**
5289  * Called whenever a client is disconnected.  Frees our
5290  * resources associated with that client.
5291  *
5292  * @param cls closure
5293  * @param client identification of the client
5294  */
5295 static void
5296 client_disconnect_notification (void *cls,
5297                                 struct GNUNET_SERVER_Client *client)
5298 {
5299   struct TransportClient *pos;
5300   struct TransportClient *prev;
5301   struct ClientMessageQueueEntry *mqe;
5302   struct Blacklisters *bl;
5303   struct BlacklistCheck *bc;
5304
5305   if (client == NULL)
5306     return;
5307 #if DEBUG_TRANSPORT
5308   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
5309               "Client disconnected, cleaning up.\n");
5310 #endif
5311   /* clean up blacklister */
5312   bl = bl_head;
5313   while (bl != NULL)
5314     {
5315       if (bl->client == client)
5316         {
5317           bc = bc_head;
5318           while (bc != NULL)
5319             {
5320               if (bc->bl_pos == bl)
5321                 {
5322                   bc->bl_pos = bl->next;
5323                   if (bc->th != NULL)
5324                     {
5325                       GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th);
5326                       bc->th = NULL;            
5327                     }
5328                   if (bc->task == GNUNET_SCHEDULER_NO_TASK)
5329                     bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
5330                                                          bc);
5331                   break;
5332                 }
5333               bc = bc->next;
5334             }
5335           GNUNET_CONTAINER_DLL_remove (bl_head,
5336                                        bl_tail,
5337                                        bl);
5338           GNUNET_SERVER_client_drop (bl->client);
5339           GNUNET_free (bl);
5340           break;
5341         }
5342       bl = bl->next;
5343     }
5344   /* clean up 'normal' clients */
5345   prev = NULL;
5346   pos = clients;
5347   while ((pos != NULL) && (pos->client != client))
5348     {
5349       prev = pos;
5350       pos = pos->next;
5351     }
5352   if (pos == NULL)
5353     return;
5354   while (NULL != (mqe = pos->message_queue_head))
5355     {
5356       GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
5357                                    pos->message_queue_tail,
5358                                    mqe);
5359       pos->message_count--;
5360       GNUNET_free (mqe);
5361     }
5362   if (prev == NULL)
5363     clients = pos->next;
5364   else
5365     prev->next = pos->next;
5366   if (GNUNET_YES == pos->tcs_pending)
5367     {
5368       pos->client = NULL;
5369       return;
5370     }
5371   if (pos->th != NULL)
5372     {
5373       GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
5374       pos->th = NULL;
5375     }
5376   GNUNET_break (0 == pos->message_count);
5377   GNUNET_free (pos);
5378 }
5379
5380
5381 /**
5382  * Function called when the service shuts down.  Unloads our plugins
5383  * and cancels pending validations.
5384  *
5385  * @param cls closure, unused
5386  * @param tc task context (unused)
5387  */
5388 static void
5389 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
5390 {
5391   struct TransportPlugin *plug;
5392   struct OwnAddressList *al;
5393   struct CheckHelloValidatedContext *chvc;
5394
5395   while (neighbours != NULL)
5396     {
5397       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5398               "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&neighbours->id),
5399               "SHUTDOWN_TASK");
5400       disconnect_neighbour (neighbours, GNUNET_NO);
5401     }
5402 #if DEBUG_TRANSPORT
5403   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5404               "Transport service is unloading plugins...\n");
5405 #endif
5406   while (NULL != (plug = plugins))
5407     {
5408       plugins = plug->next;
5409       if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
5410         {
5411           GNUNET_SCHEDULER_cancel (plug->address_update_task);
5412           plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
5413         }
5414       GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
5415       GNUNET_free (plug->lib_name);
5416       GNUNET_free (plug->short_name);
5417       while (NULL != (al = plug->addresses))
5418         {
5419           plug->addresses = al->next;
5420           GNUNET_free (al);
5421         }
5422       GNUNET_free (plug);
5423     }
5424   if (my_private_key != NULL)
5425     GNUNET_CRYPTO_rsa_key_free (my_private_key);
5426   GNUNET_free_non_null (our_hello);
5427
5428   GNUNET_CONTAINER_multihashmap_iterate (validation_map,
5429                                          &abort_validation,
5430                                          NULL);
5431   GNUNET_CONTAINER_multihashmap_destroy (validation_map);
5432   validation_map = NULL;
5433
5434   /* free 'chvc' data structure */
5435   while (NULL != (chvc = chvc_head))
5436     {
5437       chvc_head = chvc->next;
5438       if (chvc->piter != NULL)
5439         {
5440           GNUNET_PEERINFO_iterate_cancel (chvc->piter);
5441           GNUNET_STATISTICS_update (stats,
5442                                     gettext_noop ("# outstanding peerinfo iterate requests"),
5443                                     -1,
5444                                     GNUNET_NO);
5445         }
5446       else
5447         GNUNET_break (0);
5448       GNUNET_assert (chvc->ve_count == 0);
5449       GNUNET_free (chvc);
5450     }
5451   chvc_tail = NULL;
5452
5453   if (stats != NULL)
5454     {
5455       GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
5456       stats = NULL;
5457     }
5458   if (peerinfo != NULL)
5459     {
5460       GNUNET_PEERINFO_disconnect (peerinfo);
5461       peerinfo = NULL;
5462     }
5463   /* Can we assume those are gone by now, or do we need to clean up
5464      explicitly!? */
5465   GNUNET_break (bl_head == NULL);
5466   GNUNET_break (bc_head == NULL);
5467 }
5468
5469
5470 /**
5471  * Initiate transport service.
5472  *
5473  * @param cls closure
5474  * @param server the initialized server
5475  * @param c configuration to use
5476  */
5477 static void
5478 run (void *cls,
5479      struct GNUNET_SERVER_Handle *server,
5480      const struct GNUNET_CONFIGURATION_Handle *c)
5481 {
5482   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
5483     {&handle_start, NULL,
5484      GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)},
5485     {&handle_hello, NULL,
5486      GNUNET_MESSAGE_TYPE_HELLO, 0},
5487     {&handle_send, NULL,
5488      GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
5489     {&handle_request_connect, NULL,
5490      GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT, sizeof(struct TransportRequestConnectMessage)},
5491     {&handle_set_quota, NULL,
5492      GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
5493     {&handle_address_lookup, NULL,
5494      GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
5495      0},
5496     {&handle_blacklist_init, NULL,
5497      GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT, sizeof (struct GNUNET_MessageHeader)},
5498     {&handle_blacklist_reply, NULL,
5499      GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY, sizeof (struct BlacklistMessage)},
5500     {NULL, NULL, 0, 0}
5501   };
5502   char *plugs;
5503   char *pos;
5504   int no_transports;
5505   unsigned long long tneigh;
5506   char *keyfile;
5507
5508   cfg = c;
5509   stats = GNUNET_STATISTICS_create ("transport", cfg);
5510   validation_map = GNUNET_CONTAINER_multihashmap_create (64);
5511   /* parse configuration */
5512   if ((GNUNET_OK !=
5513        GNUNET_CONFIGURATION_get_value_number (c,
5514                                               "TRANSPORT",
5515                                               "NEIGHBOUR_LIMIT",
5516                                               &tneigh)) ||
5517       (GNUNET_OK !=
5518        GNUNET_CONFIGURATION_get_value_filename (c,
5519                                                 "GNUNETD",
5520                                                 "HOSTKEY", &keyfile)))
5521     {
5522       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5523                   _
5524                   ("Transport service is lacking key configuration settings.  Exiting.\n"));
5525       GNUNET_SCHEDULER_shutdown ();
5526       if (stats != NULL)
5527         {
5528           GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
5529           stats = NULL;
5530         }
5531       GNUNET_CONTAINER_multihashmap_destroy (validation_map);
5532       validation_map = NULL;
5533       return;
5534     }
5535   max_connect_per_transport = (uint32_t) tneigh;
5536   peerinfo = GNUNET_PEERINFO_connect (cfg);
5537   if (peerinfo == NULL)
5538     {
5539       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5540                   _("Could not access PEERINFO service.  Exiting.\n")); 
5541       GNUNET_SCHEDULER_shutdown ();
5542       if (stats != NULL)
5543         {
5544           GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
5545           stats = NULL;
5546         }
5547       GNUNET_CONTAINER_multihashmap_destroy (validation_map);
5548       validation_map = NULL;
5549       GNUNET_free (keyfile);
5550       return;
5551     }
5552   my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
5553   GNUNET_free (keyfile);
5554   if (my_private_key == NULL)
5555     {
5556       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5557                   _
5558                   ("Transport service could not access hostkey.  Exiting.\n"));
5559       GNUNET_SCHEDULER_shutdown ();
5560       if (stats != NULL)
5561         {
5562           GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
5563           stats = NULL;
5564         }
5565       GNUNET_CONTAINER_multihashmap_destroy (validation_map);
5566       validation_map = NULL;
5567       return;
5568     }
5569   GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
5570   GNUNET_CRYPTO_hash (&my_public_key,
5571                       sizeof (my_public_key), &my_identity.hashPubKey);
5572   /* setup notification */
5573   GNUNET_SERVER_disconnect_notify (server,
5574                                    &client_disconnect_notification, NULL);
5575   /* load plugins... */
5576   no_transports = 1;
5577   if (GNUNET_OK ==
5578       GNUNET_CONFIGURATION_get_value_string (c,
5579                                              "TRANSPORT", "PLUGINS", &plugs))
5580     {
5581       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5582                   _("Starting transport plugins `%s'\n"), plugs);
5583       pos = strtok (plugs, " ");
5584       while (pos != NULL)
5585         {
5586           start_transport (server, pos);
5587           no_transports = 0;
5588           pos = strtok (NULL, " ");
5589         }
5590       GNUNET_free (plugs);
5591     }
5592   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
5593                                 &shutdown_task, NULL);
5594   if (no_transports)
5595     refresh_hello ();
5596
5597 #if DEBUG_TRANSPORT
5598   GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
5599 #endif
5600   /* If we have a blacklist file, read from it */
5601   read_blacklist_file(cfg);
5602   /* process client requests */
5603   GNUNET_SERVER_add_handlers (server, handlers);
5604 }
5605
5606
5607 /**
5608  * The main function for the transport service.
5609  *
5610  * @param argc number of arguments from the command line
5611  * @param argv command line arguments
5612  * @return 0 ok, 1 on error
5613  */
5614 int
5615 main (int argc, char *const *argv)
5616 {
5617   a2s (NULL, NULL, 0); /* make compiler happy */
5618   return (GNUNET_OK ==
5619           GNUNET_SERVICE_run (argc,
5620                               argv,
5621                               "transport",
5622                               GNUNET_SERVICE_OPTION_NONE,
5623                               &run, NULL)) ? 0 : 1;
5624 }
5625
5626 /* end of gnunet-service-transport.c */