initial transport level blacklist stuff
[oweals/gnunet.git] / src / transport / gnunet-service-transport.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009 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 2, 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  * NOTE:
27  * - This code uses 'GNUNET_a2s' for debug printing in many places,
28  *   which is technically wrong since it assumes we have IP+Port 
29  *   (v4/v6) addresses.  Once we add transports like http or smtp
30  *   this will have to be changed!
31  * - Already wrong with dv.
32  */
33 #include "platform.h"
34 #include "gnunet_client_lib.h"
35 #include "gnunet_container_lib.h"
36 #include "gnunet_constants.h"
37 #include "gnunet_getopt_lib.h"
38 #include "gnunet_hello_lib.h"
39 #include "gnunet_os_lib.h"
40 #include "gnunet_peerinfo_service.h"
41 #include "gnunet_plugin_lib.h"
42 #include "gnunet_protocols.h"
43 #include "gnunet_service_lib.h"
44 #include "gnunet_signatures.h"
45 #include "plugin_transport.h"
46 #include "transport.h"
47
48 #define DEBUG_BLACKLIST GNUNET_NO
49
50 #define DEBUG_PING_PONG GNUNET_NO
51
52 /**
53  * Should we do some additional checks (to validate behavior
54  * of clients)?
55  */
56 #define EXTRA_CHECKS GNUNET_YES
57
58 /**
59  * How many messages can we have pending for a given client process
60  * before we start to drop incoming messages?  We typically should
61  * have only one client and so this would be the primary buffer for
62  * messages, so the number should be chosen rather generously.
63  *
64  * The expectation here is that most of the time the queue is large
65  * enough so that a drop is virtually never required.
66  */
67 #define MAX_PENDING 128
68
69 /**
70  * How often should we try to reconnect to a peer using a particular
71  * transport plugin before giving up?  Note that the plugin may be
72  * added back to the list after PLUGIN_RETRY_FREQUENCY expires.
73  */
74 #define MAX_CONNECT_RETRY 3
75
76 /**
77  * Limit on the number of ready-to-run tasks when validating 
78  * HELLOs.  If more tasks are ready to run, we will drop 
79  * HELLOs instead of validating them.
80  */
81 #define MAX_HELLO_LOAD 4
82
83 /**
84  * How often must a peer violate bandwidth quotas before we start
85  * to simply drop its messages?
86  */
87 #define QUOTA_VIOLATION_DROP_THRESHOLD 10
88
89 /**
90  * How long until a HELLO verification attempt should time out?
91  * Must be rather small, otherwise a partially successful HELLO
92  * validation (some addresses working) might not be available
93  * before a client's request for a connection fails for good.
94  * Besides, if a single request to an address takes a long time,
95  * then the peer is unlikely worthwhile anyway.
96  */
97 #define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
98
99 /**
100  * Priority to use for PONG messages.
101  */
102 #define TRANSPORT_PONG_PRIORITY 4
103
104 /**
105  * How often do we re-add (cheaper) plugins to our list of plugins
106  * to try for a given connected peer?
107  */
108 #define PLUGIN_RETRY_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
109
110 /**
111  * After how long do we expire an address in a HELLO that we just
112  * validated?  This value is also used for our own addresses when we
113  * create a HELLO.
114  */
115 #define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
116
117
118 /**
119  * How long before an existing address expires should we again try to
120  * validate it?  Must be (significantly) smaller than
121  * HELLO_ADDRESS_EXPIRATION.
122  */
123 #define HELLO_REVALIDATION_START_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
124
125 /**
126  * Maximum frequency for re-evaluating latencies for all transport addresses.
127  */
128 #define LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
129
130 /**
131  * Maximum frequency for re-evaluating latencies for connected addresses.
132  */
133 #define CONNECTED_LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
134
135
136 /**
137  * List of addresses of other peers
138  */
139 struct ForeignAddressList
140 {
141   /**
142    * This is a linked list.
143    */
144   struct ForeignAddressList *next;
145
146   /**
147    * Which ready list does this entry belong to.
148    */
149   struct ReadyList *ready_list;
150
151   /**
152    * How long until we auto-expire this address (unless it is
153    * re-confirmed by the transport)?
154    */
155   struct GNUNET_TIME_Absolute expires;
156
157   /**
158    * Task used to re-validate addresses, updates latencies and
159    * verifies liveness.
160    */
161   GNUNET_SCHEDULER_TaskIdentifier revalidate_task;
162
163   /**
164    * Length of addr.
165    */
166   size_t addrlen;
167
168   /**
169    * The address.
170    */
171   const void *addr;
172
173   /**
174    * Session (or NULL if no valid session currently exists or if the
175    * plugin does not use sessions).
176    */
177   struct Session *session;
178
179   /**
180    * What was the last latency observed for this address, plugin and peer?
181    */
182   struct GNUNET_TIME_Relative latency;
183
184   /**
185    * If we did not successfully transmit a message to the given peer
186    * via this connection during the specified time, we should consider
187    * the connection to be dead.  This is used in the case that a TCP
188    * transport simply stalls writing to the stream but does not
189    * formerly get a signal that the other peer died.
190    */
191   struct GNUNET_TIME_Absolute timeout;
192
193   /**
194    * How often have we tried to connect using this plugin?  Used to
195    * discriminate against addresses that do not work well.
196    * FIXME: not yet used, but should be!
197    */
198   unsigned int connect_attempts;
199
200   /**
201    * DV distance to this peer (1 if no DV is used). 
202    * FIXME: need to set this from transport plugins!
203    */
204   uint32_t distance;
205
206   /**
207    * Have we ever estimated the latency of this address?  Used to
208    * ensure that the first time we add an address, we immediately
209    * probe its latency.
210    */
211   int8_t estimated;
212
213   /**
214    * Are we currently connected via this address?  The first time we
215    * successfully transmit or receive data to a peer via a particular
216    * address, we set this to GNUNET_YES.  If we later get an error
217    * (disconnect notification, transmission failure, timeout), we set
218    * it back to GNUNET_NO.  
219    */
220   int8_t connected;
221
222   /**
223    * Is this plugin currently busy transmitting to the specific target?
224    * GNUNET_NO if not (initial, default state is GNUNET_NO).   Internal
225    * messages do not count as 'in transmit'.
226    */
227   int8_t in_transmit;
228
229   /**
230    * Has this address been validated yet?
231    */
232   int8_t validated;
233
234 };
235
236
237 /**
238  * Entry in linked list of network addresses for ourselves.
239  */
240 struct OwnAddressList
241 {
242   /**
243    * This is a linked list.
244    */
245   struct OwnAddressList *next;
246
247   /**
248    * The address, actually a pointer to the end
249    * of this struct.  Do not free!
250    */
251   const void *addr;
252   
253   /**
254    * How long until we auto-expire this address (unless it is
255    * re-confirmed by the transport)?
256    */
257   struct GNUNET_TIME_Absolute expires;
258
259   /**
260    * Length of addr.
261    */
262   size_t addrlen;
263
264 };
265
266
267 /**
268  * Entry in linked list of all of our plugins.
269  */
270 struct TransportPlugin
271 {
272
273   /**
274    * This is a linked list.
275    */
276   struct TransportPlugin *next;
277
278   /**
279    * API of the transport as returned by the plugin's
280    * initialization function.
281    */
282   struct GNUNET_TRANSPORT_PluginFunctions *api;
283
284   /**
285    * Short name for the plugin (i.e. "tcp").
286    */
287   char *short_name;
288
289   /**
290    * Name of the library (i.e. "gnunet_plugin_transport_tcp").
291    */
292   char *lib_name;
293
294   /**
295    * List of our known addresses for this transport.
296    */
297   struct OwnAddressList *addresses;
298
299   /**
300    * Environment this transport service is using
301    * for this plugin.
302    */
303   struct GNUNET_TRANSPORT_PluginEnvironment env;
304
305   /**
306    * ID of task that is used to clean up expired addresses.
307    */
308   GNUNET_SCHEDULER_TaskIdentifier address_update_task;
309
310   /**
311    * Set to GNUNET_YES if we need to scrap the existing list of
312    * "addresses" and start fresh when we receive the next address
313    * update from a transport.  Set to GNUNET_NO if we should just add
314    * the new address to the list and wait for the commit call.
315    */
316   int rebuild;
317
318   /**
319    * Hashmap of blacklisted peers for this particular transport.
320    */
321   struct GNUNET_CONTAINER_MultiHashMap *blacklist;
322 };
323
324 struct NeighbourList;
325
326 /**
327  * For each neighbour we keep a list of messages
328  * that we still want to transmit to the neighbour.
329  */
330 struct MessageQueue
331 {
332
333   /**
334    * This is a doubly linked list.
335    */
336   struct MessageQueue *next;
337
338   /**
339    * This is a doubly linked list.
340    */
341   struct MessageQueue *prev;
342
343   /**
344    * The message(s) we want to transmit, GNUNET_MessageHeader(s)
345    * stuck together in memory.  Allocated at the end of this struct.
346    */
347   const char *message_buf;
348
349   /**
350    * Size of the message buf
351    */
352   size_t message_buf_size;
353
354   /**
355    * Client responsible for queueing the message;
356    * used to check that a client has no two messages
357    * pending for the same target.  Can be NULL.
358    */
359   struct TransportClient *client;
360
361   /**
362    * Using which specific address should we send this message?
363    */
364   struct ForeignAddressList *specific_address;
365
366   /**
367    * Peer ID of the Neighbour this entry belongs to.
368    */
369   struct GNUNET_PeerIdentity neighbour_id;
370
371   /**
372    * Plugin that we used for the transmission.
373    * NULL until we scheduled a transmission.
374    */
375   struct TransportPlugin *plugin;
376
377   /**
378    * At what time should we fail?
379    */
380   struct GNUNET_TIME_Absolute timeout;
381
382   /**
383    * Internal message of the transport system that should not be
384    * included in the usual SEND-SEND_OK transmission confirmation
385    * traffic management scheme.  Typically, "internal_msg" will
386    * be set whenever "client" is NULL (but it is not strictly
387    * required).
388    */
389   int internal_msg;
390
391   /**
392    * How important is the message?
393    */
394   unsigned int priority;
395
396 };
397
398
399 /**
400  * For a given Neighbour, which plugins are available
401  * to talk to this peer and what are their costs?
402  */
403 struct ReadyList
404 {
405   /**
406    * This is a linked list.
407    */
408   struct ReadyList *next;
409
410   /**
411    * Which of our transport plugins does this entry
412    * represent?
413    */
414   struct TransportPlugin *plugin;
415
416   /**
417    * Transport addresses, latency, and readiness for
418    * this particular plugin.
419    */
420   struct ForeignAddressList *addresses;
421
422   /**
423    * To which neighbour does this ready list belong to?
424    */
425   struct NeighbourList *neighbour;
426
427 };
428
429
430 /**
431  * Entry in linked list of all of our current neighbours.
432  */
433 struct NeighbourList
434 {
435
436   /**
437    * This is a linked list.
438    */
439   struct NeighbourList *next;
440
441   /**
442    * Which of our transports is connected to this peer
443    * and what is their status?
444    */
445   struct ReadyList *plugins;
446
447   /**
448    * Head of list of messages we would like to send to this peer;
449    * must contain at most one message per client.
450    */
451   struct MessageQueue *messages_head;
452
453   /**
454    * Tail of list of messages we would like to send to this peer; must
455    * contain at most one message per client.
456    */
457   struct MessageQueue *messages_tail;
458
459   /**
460    * Buffer for at most one payload message used when we receive
461    * payload data before our PING-PONG has succeeded.  We then
462    * store such messages in this intermediary buffer until the
463    * connection is fully up.  
464    */
465   struct GNUNET_MessageHeader *pre_connect_message_buffer;
466
467   /**
468    * Context for peerinfo iteration.
469    * NULL after we are done processing peerinfo's information.
470    */
471   struct GNUNET_PEERINFO_IteratorContext *piter;
472
473   /**
474    * Public key for this peer.   Valid only if the respective flag is set below.
475    */
476   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
477
478   /**
479    * Identity of this neighbour.
480    */
481   struct GNUNET_PeerIdentity id;
482
483   /**
484    * ID of task scheduled to run when this peer is about to
485    * time out (will free resources associated with the peer).
486    */
487   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
488
489   /**
490    * ID of task scheduled to run when we should retry transmitting
491    * the head of the message queue.  Actually triggered when the
492    * transmission is timing out (we trigger instantly when we have
493    * a chance of success).
494    */
495   GNUNET_SCHEDULER_TaskIdentifier retry_task;
496
497   /**
498    * How long until we should consider this peer dead
499    * (if we don't receive another message in the
500    * meantime)?
501    */
502   struct GNUNET_TIME_Absolute peer_timeout;
503
504   /**
505    * Tracker for inbound bandwidth.
506    */
507   struct GNUNET_BANDWIDTH_Tracker in_tracker;
508
509   /**
510    * The latency we have seen for this particular address for
511    * this particular peer.  This latency may have been calculated
512    * over multiple transports.  This value reflects how long it took
513    * us to receive a response when SENDING via this particular
514    * transport/neighbour/address combination!
515    *
516    * FIXME: we need to periodically send PINGs to update this
517    * latency (at least more often than the current "huge" (11h?)
518    * update interval).
519    */
520   struct GNUNET_TIME_Relative latency;
521
522   /**
523    * How often has the other peer (recently) violated the
524    * inbound traffic limit?  Incremented by 10 per violation,
525    * decremented by 1 per non-violation (for each
526    * time interval).
527    */
528   unsigned int quota_violation_count;
529
530   /**
531    * DV distance to this peer (1 if no DV is used). 
532    */
533   uint32_t distance;
534
535   /**
536    * Have we seen an PONG from this neighbour in the past (and
537    * not had a disconnect since)?
538    */
539   int received_pong;
540
541   /**
542    * Do we have a valid public key for this neighbour?
543    */
544   int public_key_valid;
545
546 };
547
548 /**
549  * Message used to ask a peer to validate receipt (to check an address
550  * from a HELLO).  
551  */
552 struct TransportPingMessage
553 {
554
555   /**
556    * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
557    */
558   struct GNUNET_MessageHeader header;
559
560   /**
561    * Random challenge number (in network byte order).
562    */
563   uint32_t challenge GNUNET_PACKED;
564
565   /**
566    * Who is the intended recipient?
567    */
568   struct GNUNET_PeerIdentity target;
569
570 };
571
572
573 /**
574  * Message used to validate a HELLO.  The challenge is included in the
575  * confirmation to make matching of replies to requests possible.  The
576  * signature signs the original challenge number, our public key, the
577  * sender's address (so that the sender can check that the address we
578  * saw is plausible for him and possibly detect a MiM attack) and a
579  * timestamp (to limit replay).<p>
580  *
581  * This message is followed by the address of the
582  * client that we are observing (which is part of what
583  * is being signed).
584  */
585 struct TransportPongMessage
586 {
587
588   /**
589    * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
590    */
591   struct GNUNET_MessageHeader header;
592
593   /**
594    * For padding, always zero.
595    */
596   uint32_t reserved GNUNET_PACKED;
597
598   /**
599    * Signature.
600    */
601   struct GNUNET_CRYPTO_RsaSignature signature;
602
603   /**
604    * What are we signing and why?
605    */
606   struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
607
608   /**
609    * Random challenge number (in network byte order).
610    */
611   uint32_t challenge GNUNET_PACKED;
612
613   /**
614    * Who signed this message?
615    */
616   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded signer;
617
618   /**
619    * Size of address appended to this message
620    */
621   size_t addrlen;
622
623 };
624
625
626 /**
627  * Linked list of messages to be transmitted to the client.  Each
628  * entry is followed by the actual message.
629  */
630 struct ClientMessageQueueEntry
631 {
632   /**
633    * This is a doubly-linked list.
634    */
635   struct ClientMessageQueueEntry *next;
636
637   /**
638    * This is a doubly-linked list.
639    */
640   struct ClientMessageQueueEntry *prev;
641 };
642
643
644 /**
645  * Client connected to the transport service.
646  */
647 struct TransportClient
648 {
649
650   /**
651    * This is a linked list.
652    */
653   struct TransportClient *next;
654
655   /**
656    * Handle to the client.
657    */
658   struct GNUNET_SERVER_Client *client;
659
660   /**
661    * Linked list of messages yet to be transmitted to
662    * the client.
663    */
664   struct ClientMessageQueueEntry *message_queue_head;
665
666   /**
667    * Tail of linked list of messages yet to be transmitted to the
668    * client.
669    */
670   struct ClientMessageQueueEntry *message_queue_tail;
671
672   /**
673    * Current transmit request handle.
674    */ 
675   struct GNUNET_CONNECTION_TransmitHandle *th;
676
677   /**
678    * Is a call to "transmit_send_continuation" pending?  If so, we
679    * must not free this struct (even if the corresponding client
680    * disconnects) and instead only remove it from the linked list and
681    * set the "client" field to NULL.
682    */
683   int tcs_pending;
684
685   /**
686    * Length of the list of messages pending for this client.
687    */
688   unsigned int message_count;
689
690 };
691
692
693 /**
694  * Entry in map of all HELLOs awaiting validation.
695  */
696 struct ValidationEntry
697 {
698
699   /**
700    * The address, actually a pointer to the end
701    * of this struct.  Do not free!
702    */
703   const void *addr;
704
705   /**
706    * Name of the transport.
707    */
708   char *transport_name;
709
710   /**
711    * The public key of the peer.
712    */
713   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
714
715   /**
716    * ID of task that will clean up this entry if we don't succeed
717    * with the validation first.
718    */
719   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
720
721   /**
722    * At what time did we send this validation?
723    */
724   struct GNUNET_TIME_Absolute send_time;
725
726   /**
727    * Session being validated (or NULL for none).
728    */
729   struct Session *session;
730
731   /**
732    * Length of addr.
733    */
734   size_t addrlen;
735
736   /**
737    * Challenge number we used.
738    */
739   uint32_t challenge;
740
741 };
742
743
744 /**
745  * Context of currently active requests to peerinfo
746  * for validation of HELLOs.
747  */
748 struct CheckHelloValidatedContext
749 {
750
751   /**
752    * This is a doubly-linked list.
753    */
754   struct CheckHelloValidatedContext *next;
755
756   /**
757    * This is a doubly-linked list.
758    */
759   struct CheckHelloValidatedContext *prev;
760
761   /**
762    * Hello that we are validating.
763    */
764   const struct GNUNET_HELLO_Message *hello;
765
766   /**
767    * Context for peerinfo iteration.
768    * NULL after we are done processing peerinfo's information.
769    */
770   struct GNUNET_PEERINFO_IteratorContext *piter;
771   
772   /**
773    * Was a HELLO known for this peer to peerinfo?
774    */
775   int hello_known;
776
777 };
778
779
780
781 /**
782  * Our HELLO message.
783  */
784 static struct GNUNET_HELLO_Message *our_hello;
785
786 /**
787  * "version" of "our_hello".  Used to see if a given neighbour has
788  * already been sent the latest version of our HELLO message.
789  */
790 static unsigned int our_hello_version;
791
792 /**
793  * Our public key.
794  */
795 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
796
797 /**
798  * Our identity.
799  */
800 static struct GNUNET_PeerIdentity my_identity;
801
802 /**
803  * Our private key.
804  */
805 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
806
807 /**
808  * Our scheduler.
809  */
810 struct GNUNET_SCHEDULER_Handle *sched;
811
812 /**
813  * Our configuration.
814  */
815 const struct GNUNET_CONFIGURATION_Handle *cfg;
816
817 /**
818  * Linked list of all clients to this service.
819  */
820 static struct TransportClient *clients;
821
822 /**
823  * All loaded plugins.
824  */
825 static struct TransportPlugin *plugins;
826
827 /**
828  * Our server.
829  */
830 static struct GNUNET_SERVER_Handle *server;
831
832 /**
833  * All known neighbours and their HELLOs.
834  */
835 static struct NeighbourList *neighbours;
836
837 /**
838  * Number of neighbours we'd like to have.
839  */
840 static uint32_t max_connect_per_transport;
841
842 /**
843  * Head of linked list.
844  */
845 static struct CheckHelloValidatedContext *chvc_head;
846
847 /**
848  * Tail of linked list.
849  */
850 static struct CheckHelloValidatedContext *chvc_tail;
851
852 /**
853  * Map of PeerIdentities to 'struct ValidationEntry*'s (addresses
854  * of the given peer that we are currently validating).
855  */
856 static struct GNUNET_CONTAINER_MultiHashMap *validation_map;
857
858 /**
859  * Handle for reporting statistics.
860  */
861 static struct GNUNET_STATISTICS_Handle *stats;
862
863
864 /**
865  * The peer specified by the given neighbour has timed-out or a plugin
866  * has disconnected.  We may either need to do nothing (other plugins
867  * still up), or trigger a full disconnect and clean up.  This
868  * function updates our state and do the necessary notifications.
869  * Also notifies our clients that the neighbour is now officially
870  * gone.
871  *
872  * @param n the neighbour list entry for the peer
873  * @param check should we just check if all plugins
874  *        disconnected or must we ask all plugins to
875  *        disconnect?
876  */
877 static void disconnect_neighbour (struct NeighbourList *n, int check);
878
879 /**
880  * Check the ready list for the given neighbour and if a plugin is
881  * ready for transmission (and if we have a message), do so!
882  *
883  * @param neighbour target peer for which to transmit
884  */
885 static void try_transmission_to_peer (struct NeighbourList *neighbour);
886
887
888 /**
889  * Find an entry in the neighbour list for a particular peer.
890  *  
891  * @return NULL if not found.
892  */
893 static struct NeighbourList *
894 find_neighbour (const struct GNUNET_PeerIdentity *key)
895 {
896   struct NeighbourList *head = neighbours;
897
898   while ((head != NULL) &&
899         (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
900     head = head->next;
901   return head;
902 }
903
904
905 /**
906  * Find an entry in the transport list for a particular transport.
907  *
908  * @return NULL if not found.
909  */
910 static struct TransportPlugin *
911 find_transport (const char *short_name)
912 {
913   struct TransportPlugin *head = plugins;
914   while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
915     head = head->next;
916   return head;
917 }
918
919 /**
920  * Is a particular peer blacklisted for a particular transport?
921  *
922  * @param peer the peer to check for
923  * @param plugin the plugin used to connect to the peer
924  *
925  * @return GNUNET_YES if the peer is blacklisted, GNUNET_NO if not
926  */
927 static int
928 is_blacklisted (const struct GNUNET_PeerIdentity *peer, struct TransportPlugin *plugin)
929 {
930
931   if (plugin->blacklist != NULL)
932     {
933       if (GNUNET_CONTAINER_multihashmap_contains(plugin->blacklist, &peer->hashPubKey) == GNUNET_YES)
934         {
935 #if DEBUG_BLACKLIST
936           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
937                       _("Peer `%s:%s' is blacklisted!\n"),
938                       plugin->short_name, GNUNET_i2s (peer));
939 #endif
940           return GNUNET_YES;
941         }
942     }
943
944   return GNUNET_NO;
945 }
946
947 static void
948 add_peer_to_blacklist (struct GNUNET_PeerIdentity *peer, char *transport_name)
949 {
950   struct TransportPlugin *plugin;
951
952   plugin = find_transport(transport_name);
953
954   if (plugin == NULL) /* Nothing to do */
955     return;
956
957   if (plugin->blacklist == NULL)
958     {
959       plugin->blacklist = GNUNET_CONTAINER_multihashmap_create(100); /* FIXME: estimated number of peers or what? */
960     }
961
962   GNUNET_assert(plugin->blacklist != NULL);
963
964   GNUNET_CONTAINER_multihashmap_put(plugin->blacklist, &peer->hashPubKey, NULL, GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
965 }
966
967 /**
968  * Read the blacklist file, containing transport:peer entries.
969  * Provided the transport is loaded, set up hashmap with these
970  * entries to blacklist peers by transport.
971  *
972  */
973 static void
974 read_blacklist_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
975 {
976   char *fn;
977   char *data;
978   size_t pos;
979   size_t colon_pos;
980   int tsize;
981   struct GNUNET_PeerIdentity pid;
982   struct stat frstat;
983   struct GNUNET_CRYPTO_HashAsciiEncoded enc;
984   unsigned int entries_found;
985   char *transport_name;
986
987   if (GNUNET_OK !=
988       GNUNET_CONFIGURATION_get_value_filename (cfg,
989                                                "TRANSPORT",
990                                                "BLACKLIST_FILE",
991                                                &fn))
992     {
993       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
994                   _("Option `%s' in section `%s' not specified!\n"),
995                   "BLACKLIST_FILE",
996                   "TRANSPORT");
997       return;
998     }
999   if (GNUNET_OK != GNUNET_DISK_file_test (fn))
1000     GNUNET_DISK_fn_write (fn, NULL, 0, GNUNET_DISK_PERM_USER_READ
1001         | GNUNET_DISK_PERM_USER_WRITE);
1002   if (0 != STAT (fn, &frstat))
1003     {
1004       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1005                   _("Could not read blacklist file `%s'\n"), fn);
1006       GNUNET_free (fn);
1007       return;
1008     }
1009   if (frstat.st_size == 0)
1010     {
1011       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1012                   _("Blacklist file `%s' is empty.\n"),
1013                   fn);
1014       GNUNET_free (fn);
1015       return;
1016     }
1017   data = GNUNET_malloc_large (frstat.st_size);
1018   if (frstat.st_size !=
1019       GNUNET_DISK_fn_read (fn, data, frstat.st_size))
1020     {
1021       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1022                   _("Failed to read blacklist from `%s'\n"), fn);
1023       GNUNET_free (fn);
1024       GNUNET_free (data);
1025       return;
1026     }
1027   entries_found = 0;
1028   pos = 0;
1029   while ((pos < frstat.st_size) && isspace (data[pos]))
1030     pos++;
1031   while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) &&
1032          (pos <= frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
1033     {
1034       colon_pos = pos;
1035       while ((colon_pos < frstat.st_size) && (data[colon_pos] != ':') && !isspace (data[colon_pos]))
1036         colon_pos++;
1037
1038       if (colon_pos >= frstat.st_size)
1039         {
1040           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1041                       _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1042                       (unsigned long long) colon_pos);
1043           GNUNET_free (fn);
1044           GNUNET_free (data);
1045           return;
1046         }
1047
1048       if (isspace(data[colon_pos]))
1049       {
1050         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1051                     _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1052                     (unsigned long long) colon_pos);
1053         pos = colon_pos;
1054         while ((pos < frstat.st_size) && isspace (data[pos]))
1055           pos++;
1056         continue;
1057       }
1058       tsize = colon_pos - pos;
1059       if ((pos >= frstat.st_size) || (pos + tsize >= frstat.st_size))
1060         {
1061           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1062                       _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1063                       (unsigned long long) colon_pos);
1064           GNUNET_free (fn);
1065           GNUNET_free (data);
1066           return;
1067         }
1068
1069       transport_name = GNUNET_malloc(tsize);
1070       memcpy(transport_name, &data[pos], tsize);
1071       pos = colon_pos + 1;
1072
1073
1074       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1075                   _("Read transport name %s in blacklist file.\n"),
1076                   transport_name);
1077
1078       memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
1079       if (!isspace (enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
1080         {
1081           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1082                       _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1083                       (unsigned long long) pos);
1084           pos++;
1085           while ((pos < frstat.st_size) && (!isspace (data[pos])))
1086             pos++;
1087           GNUNET_free_non_null(transport_name);
1088           continue;
1089         }
1090       enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
1091       if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &pid.hashPubKey))
1092         {
1093           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1094                       _("Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n"),
1095                       (unsigned long long) pos,
1096                       &enc);
1097         }
1098       else
1099         {
1100           if (0 != memcmp (&pid,
1101                            &my_identity,
1102                            sizeof (struct GNUNET_PeerIdentity)))
1103             {
1104               entries_found++;
1105               add_peer_to_blacklist (&pid,
1106                               transport_name);
1107               GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1108                           _("Found blacklisted peer `%s:%s' in configuration\n"),
1109                           transport_name, GNUNET_i2s (&pid));
1110             }
1111           else
1112             {
1113               GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1114                           _("Found myself `%s' in blacklist (useless, ignored)\n"),
1115                           GNUNET_i2s (&pid));
1116             }
1117         }
1118       pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
1119       GNUNET_free_non_null(transport_name);
1120       while ((pos < frstat.st_size) && isspace (data[pos]))
1121         pos++;
1122     }
1123   GNUNET_free (data);
1124   GNUNET_free (fn);
1125
1126 }
1127
1128 /**
1129  * Function called to notify a client about the socket being ready to
1130  * queue more data.  "buf" will be NULL and "size" zero if the socket
1131  * was closed for writing in the meantime.
1132  *
1133  * @param cls closure
1134  * @param size number of bytes available in buf
1135  * @param buf where the callee should write the message
1136  * @return number of bytes written to buf
1137  */
1138 static size_t
1139 transmit_to_client_callback (void *cls, size_t size, void *buf)
1140 {
1141   struct TransportClient *client = cls;
1142   struct ClientMessageQueueEntry *q;
1143   uint16_t msize;
1144   size_t tsize;
1145   const struct GNUNET_MessageHeader *msg;
1146   char *cbuf;
1147
1148   client->th = NULL;
1149   if (buf == NULL)
1150     {
1151       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1152                   "Transmission to client failed, closing connection.\n");
1153       /* fatal error with client, free message queue! */
1154       while (NULL != (q = client->message_queue_head))
1155         {
1156           GNUNET_STATISTICS_update (stats,
1157                                     gettext_noop ("# bytes discarded (could not transmit to client)"),
1158                                     ntohs (((const struct GNUNET_MessageHeader*)&q[1])->size),
1159                                     GNUNET_NO);      
1160           GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1161                                        client->message_queue_tail,
1162                                        q);
1163           GNUNET_free (q);
1164         }
1165       client->message_count = 0;
1166       return 0;
1167     }
1168   cbuf = buf;
1169   tsize = 0;
1170   while (NULL != (q = client->message_queue_head))
1171     {
1172       msg = (const struct GNUNET_MessageHeader *) &q[1];
1173       msize = ntohs (msg->size);
1174       if (msize + tsize > size)
1175         break;
1176 #if DEBUG_TRANSPORT
1177       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1178                   "Transmitting message of type %u to client.\n",
1179                   ntohs (msg->type));
1180 #endif
1181       GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1182                                    client->message_queue_tail,
1183                                    q);
1184       memcpy (&cbuf[tsize], msg, msize);
1185       tsize += msize;
1186       GNUNET_free (q);
1187       client->message_count--;
1188     }
1189   if (NULL != q)
1190     {
1191       GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1192       client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1193                                                         msize,
1194                                                         GNUNET_TIME_UNIT_FOREVER_REL,
1195                                                         &transmit_to_client_callback,
1196                                                         client);
1197       GNUNET_assert (client->th != NULL);
1198     }
1199   return tsize;
1200 }
1201
1202
1203 /**
1204  * Mark the given FAL entry as 'connected' (and hence preferred for
1205  * sending); also mark all others for the same peer as 'not connected'
1206  * (since only one can be preferred).
1207  *
1208  * @param fal address to set to 'connected'
1209  */
1210 static void
1211 mark_address_connected (struct ForeignAddressList *fal)
1212 {
1213   struct ForeignAddressList *pos;
1214   int cnt;
1215
1216   GNUNET_assert (GNUNET_YES == fal->validated);
1217   if (fal->connected == GNUNET_YES)
1218     return; /* nothing to do */
1219   cnt = GNUNET_YES;
1220   pos = fal->ready_list->addresses;
1221   while (pos != NULL)
1222     {
1223       if (GNUNET_YES == pos->connected)
1224         {
1225           GNUNET_break (cnt == GNUNET_YES);
1226           cnt = GNUNET_NO;
1227           pos->connected = GNUNET_NO;
1228         }
1229       pos = pos->next;
1230     }
1231   fal->connected = GNUNET_YES;
1232   if (GNUNET_YES == cnt)
1233     {
1234       GNUNET_STATISTICS_update (stats,
1235                                 gettext_noop ("# connected addresses"),
1236                                 1,
1237                                 GNUNET_NO);
1238     }
1239 }
1240
1241
1242 /**
1243  * Send the specified message to the specified client.  Since multiple
1244  * messages may be pending for the same client at a time, this code
1245  * makes sure that no message is lost.
1246  *
1247  * @param client client to transmit the message to
1248  * @param msg the message to send
1249  * @param may_drop can this message be dropped if the
1250  *        message queue for this client is getting far too large?
1251  */
1252 static void
1253 transmit_to_client (struct TransportClient *client,
1254                     const struct GNUNET_MessageHeader *msg, int may_drop)
1255 {
1256   struct ClientMessageQueueEntry *q;
1257   uint16_t msize;
1258
1259   if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
1260     {
1261       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1262                   _
1263                   ("Dropping message, have %u messages pending (%u is the soft limit)\n"),
1264                   client->message_count, MAX_PENDING);
1265       /* TODO: call to statistics... */
1266       return;
1267     }
1268   msize = ntohs (msg->size);
1269   GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1270   q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
1271   memcpy (&q[1], msg, msize);
1272   GNUNET_CONTAINER_DLL_insert_after (client->message_queue_head,
1273                                      client->message_queue_tail,
1274                                      client->message_queue_tail,
1275                                      q);                                     
1276   client->message_count++;
1277   if (client->th == NULL)
1278     {
1279       client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1280                                                         msize,
1281                                                         GNUNET_TIME_UNIT_FOREVER_REL,
1282                                                         &transmit_to_client_callback,
1283                                                         client);
1284       GNUNET_assert (client->th != NULL);
1285     }
1286 }
1287
1288
1289 /**
1290  * Transmit a 'SEND_OK' notification to the given client for the
1291  * given neighbour.
1292  *
1293  * @param client who to notify
1294  * @param n neighbour to notify about
1295  * @param result status code for the transmission request
1296  */
1297 static void
1298 transmit_send_ok (struct TransportClient *client,
1299                   struct NeighbourList *n,
1300                   int result)
1301 {
1302   struct SendOkMessage send_ok_msg;
1303
1304   send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1305   send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1306   send_ok_msg.success = htonl (result);
1307   send_ok_msg.latency = GNUNET_TIME_relative_hton (n->latency);
1308   send_ok_msg.peer = n->id;
1309   transmit_to_client (client, &send_ok_msg.header, GNUNET_NO); 
1310 }
1311
1312
1313 /**
1314  * Function called by the GNUNET_TRANSPORT_TransmitFunction
1315  * upon "completion" of a send request.  This tells the API
1316  * that it is now legal to send another message to the given
1317  * peer.
1318  *
1319  * @param cls closure, identifies the entry on the
1320  *            message queue that was transmitted and the
1321  *            client responsible for queueing the message
1322  * @param target the peer receiving the message
1323  * @param result GNUNET_OK on success, if the transmission
1324  *           failed, we should not tell the client to transmit
1325  *           more messages
1326  */
1327 static void
1328 transmit_send_continuation (void *cls,
1329                             const struct GNUNET_PeerIdentity *target,
1330                             int result)
1331 {
1332   struct MessageQueue *mq = cls;
1333   struct NeighbourList *n;
1334   
1335   GNUNET_STATISTICS_update (stats,
1336                             gettext_noop ("# bytes pending with plugins"),
1337                             - (int64_t) mq->message_buf_size,
1338                             GNUNET_NO);
1339   if (result == GNUNET_OK)
1340     {
1341       GNUNET_STATISTICS_update (stats,
1342                                 gettext_noop ("# bytes successfully transmitted by plugins"),
1343                                 mq->message_buf_size,
1344                                 GNUNET_NO);      
1345     }
1346   else
1347     {
1348       GNUNET_STATISTICS_update (stats,
1349                                 gettext_noop ("# bytes with transmission failure by plugins"),
1350                                 mq->message_buf_size,
1351                                 GNUNET_NO);      
1352     }  
1353   n = find_neighbour(&mq->neighbour_id);
1354   GNUNET_assert (n != NULL);
1355   if (mq->specific_address != NULL)
1356     {
1357       if (result == GNUNET_OK)    
1358         {
1359           mq->specific_address->timeout =
1360             GNUNET_TIME_relative_to_absolute
1361             (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1362           if (mq->specific_address->validated == GNUNET_YES)
1363             mark_address_connected (mq->specific_address);
1364         }    
1365       else
1366         {
1367           if (mq->specific_address->connected != GNUNET_NO)
1368             {
1369               GNUNET_STATISTICS_update (stats,
1370                                         gettext_noop ("# connected addresses"),
1371                                         -1,
1372                                         GNUNET_NO);
1373               mq->specific_address->connected = GNUNET_NO;
1374             }
1375         }    
1376       if (! mq->internal_msg) 
1377         mq->specific_address->in_transmit = GNUNET_NO;
1378     }
1379   if (mq->client != NULL)
1380     transmit_send_ok (mq->client, n, result);
1381   GNUNET_free (mq);
1382   try_transmission_to_peer (n);
1383 }
1384
1385
1386 /**
1387  * Find an address in any of the available transports for
1388  * the given neighbour that would be good for message
1389  * transmission.  This is essentially the transport selection
1390  * routine.
1391  *
1392  * @param neighbour for whom to select an address
1393  * @return selected address, NULL if we have none
1394  */
1395 struct ForeignAddressList *
1396 find_ready_address(struct NeighbourList *neighbour)
1397 {
1398   struct ReadyList *head = neighbour->plugins;
1399   struct ForeignAddressList *addresses;
1400   struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1401   struct ForeignAddressList *best_address;
1402
1403   best_address = NULL;
1404   while (head != NULL)
1405     {
1406       addresses = head->addresses;
1407       while (addresses != NULL)
1408         {
1409           if ( (addresses->timeout.value < now.value) && 
1410                (addresses->connected == GNUNET_YES) )
1411             {
1412 #if DEBUG_TRANSPORT
1413               GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1414                           "Marking long-time inactive connection to `%4s' as down.\n",
1415                           GNUNET_i2s (&neighbour->id));
1416 #endif
1417               GNUNET_STATISTICS_update (stats,
1418                                         gettext_noop ("# connected addresses"),
1419                                         -1,
1420                                         GNUNET_NO);
1421               addresses->connected = GNUNET_NO;
1422             }
1423           addresses = addresses->next;
1424         }
1425
1426       addresses = head->addresses;
1427       while (addresses != NULL)
1428         {
1429 #if DEBUG_TRANSPORT > 1
1430           if (addresses->addr != NULL)
1431             GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1432                         "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
1433                         GNUNET_a2s (addresses->addr,
1434                                     addresses->addrlen),
1435                         GNUNET_i2s (&neighbour->id),
1436                         addresses->connected,
1437                         addresses->in_transmit,
1438                         addresses->validated,
1439                         addresses->connect_attempts,
1440                         (unsigned long long) addresses->timeout.value,
1441                         (unsigned int) addresses->distance);
1442 #endif
1443           if ( ( (best_address == NULL) || 
1444                  (addresses->connected == GNUNET_YES) ||
1445                  (best_address->connected == GNUNET_NO) ) &&
1446                (addresses->in_transmit == GNUNET_NO) &&
1447                ( (best_address == NULL) || 
1448                  (addresses->latency.value < best_address->latency.value)) )
1449             best_address = addresses;            
1450           /* FIXME: also give lower-latency addresses that are not
1451              connected a chance some times... */
1452           addresses = addresses->next;
1453         }
1454       head = head->next;
1455     }
1456   if (best_address != NULL)
1457     {
1458 #if DEBUG_TRANSPORT
1459       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1460                   "Best address found has latency of %llu ms.\n",
1461                   best_address->latency.value);
1462 #endif
1463     }
1464   else
1465     {
1466       GNUNET_STATISTICS_update (stats,
1467                                 gettext_noop ("# transmission attempts failed (no address)"),
1468                                 1,
1469                                 GNUNET_NO);
1470     }
1471   return best_address;
1472
1473 }
1474
1475
1476 /**
1477  * We should re-try transmitting to the given peer,
1478  * hopefully we've learned something in the meantime.
1479  */
1480 static void
1481 retry_transmission_task (void *cls,
1482                          const struct GNUNET_SCHEDULER_TaskContext *tc)
1483 {
1484   struct NeighbourList *n = cls;
1485
1486   n->retry_task = GNUNET_SCHEDULER_NO_TASK;
1487   try_transmission_to_peer (n);
1488 }
1489
1490
1491 /**
1492  * Check the ready list for the given neighbour and if a plugin is
1493  * ready for transmission (and if we have a message), do so!
1494  *
1495  * @param neighbour target peer for which to transmit
1496  */
1497 static void
1498 try_transmission_to_peer (struct NeighbourList *neighbour)
1499 {
1500   struct ReadyList *rl;
1501   struct MessageQueue *mq;
1502   struct GNUNET_TIME_Relative timeout;
1503   ssize_t ret;
1504   int force_address;
1505
1506   if (neighbour->messages_head == NULL)
1507     {
1508 #if DEBUG_TRANSPORT
1509       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1510                   "Transmission queue for `%4s' is empty\n",
1511                   GNUNET_i2s (&neighbour->id));
1512 #endif
1513       return;                     /* nothing to do */
1514     }
1515   rl = NULL;
1516   mq = neighbour->messages_head;
1517   force_address = GNUNET_YES;
1518   if (mq->specific_address == NULL)
1519     {
1520       mq->specific_address = find_ready_address(neighbour); 
1521       GNUNET_STATISTICS_update (stats,
1522                                 gettext_noop ("# transport selected peer address freely"),
1523                                 1,
1524                                 GNUNET_NO); 
1525       force_address = GNUNET_NO;
1526     }
1527   if (mq->specific_address == NULL)
1528     {
1529       GNUNET_STATISTICS_update (stats,
1530                                 gettext_noop ("# transport failed to selected peer address"),
1531                                 1,
1532                                 GNUNET_NO); 
1533       timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
1534       if (timeout.value == 0)
1535         {
1536 #if DEBUG_TRANSPORT
1537           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1538                       "No destination address available to transmit message of size %u to peer `%4s'\n",
1539                       mq->message_buf_size,
1540                       GNUNET_i2s (&mq->neighbour_id));
1541 #endif
1542           GNUNET_STATISTICS_update (stats,
1543                                     gettext_noop ("# bytes in message queue for other peers"),
1544                                     - (int64_t) mq->message_buf_size,
1545                                     GNUNET_NO);
1546           GNUNET_STATISTICS_update (stats,
1547                                     gettext_noop ("# bytes discarded (no destination address available)"),
1548                                     mq->message_buf_size,
1549                                     GNUNET_NO);      
1550           if (mq->client != NULL)
1551             transmit_send_ok (mq->client, neighbour, GNUNET_NO);
1552           GNUNET_CONTAINER_DLL_remove (neighbour->messages_head,
1553                                        neighbour->messages_tail,
1554                                        mq);
1555           GNUNET_free (mq);
1556           return;               /* nobody ready */ 
1557         }
1558       GNUNET_STATISTICS_update (stats,
1559                                 gettext_noop ("# message delivery deferred (no address)"),
1560                                 1,
1561                                 GNUNET_NO);
1562       if (neighbour->retry_task != GNUNET_SCHEDULER_NO_TASK)
1563         GNUNET_SCHEDULER_cancel (sched,
1564                                  neighbour->retry_task);
1565       neighbour->retry_task = GNUNET_SCHEDULER_add_delayed (sched,
1566                                                             timeout,
1567                                                             &retry_transmission_task,
1568                                                             neighbour);
1569 #if DEBUG_TRANSPORT
1570       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1571                   "No validated destination address available to transmit message of size %u to peer `%4s', will wait %llums to find an address.\n",
1572                   mq->message_buf_size,
1573                   GNUNET_i2s (&mq->neighbour_id),
1574                   timeout.value);
1575 #endif
1576       /* FIXME: might want to trigger peerinfo lookup here
1577          (unless that's already pending...) */
1578       return;    
1579     }
1580   GNUNET_CONTAINER_DLL_remove (neighbour->messages_head,
1581                                neighbour->messages_tail,
1582                                mq);
1583   if (mq->specific_address->connected == GNUNET_NO)
1584     mq->specific_address->connect_attempts++;
1585   rl = mq->specific_address->ready_list;
1586   mq->plugin = rl->plugin;
1587   if (!mq->internal_msg)
1588     mq->specific_address->in_transmit = GNUNET_YES;
1589 #if DEBUG_TRANSPORT
1590   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1591               "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
1592               mq->message_buf_size,
1593               GNUNET_i2s (&neighbour->id), 
1594               (mq->specific_address->addr != NULL)
1595               ? GNUNET_a2s (mq->specific_address->addr,
1596                             mq->specific_address->addrlen)
1597               : "<inbound>",
1598               rl->plugin->short_name);
1599 #endif
1600   GNUNET_STATISTICS_update (stats,
1601                             gettext_noop ("# bytes in message queue for other peers"),
1602                             - (int64_t) mq->message_buf_size,
1603                             GNUNET_NO);
1604   GNUNET_STATISTICS_update (stats,
1605                             gettext_noop ("# bytes pending with plugins"),
1606                             mq->message_buf_size,
1607                             GNUNET_NO);
1608   ret = rl->plugin->api->send (rl->plugin->api->cls,
1609                                &mq->neighbour_id,
1610                                mq->message_buf,
1611                                mq->message_buf_size,
1612                                mq->priority,
1613                                GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1614                                mq->specific_address->session,
1615                                mq->specific_address->addr,
1616                                mq->specific_address->addrlen,
1617                                force_address,
1618                                &transmit_send_continuation, mq);
1619   if (ret == -1)
1620     {
1621       /* failure, but 'send' would not call continuation in this case,
1622          so we need to do it here! */
1623       transmit_send_continuation (mq, 
1624                                   &mq->neighbour_id,
1625                                   GNUNET_SYSERR);
1626     }
1627 }
1628
1629
1630 /**
1631  * Send the specified message to the specified peer.
1632  *
1633  * @param client source of the transmission request (can be NULL)
1634  * @param peer_address ForeignAddressList where we should send this message
1635  * @param priority how important is the message
1636  * @param timeout how long do we have to transmit?
1637  * @param message_buf message(s) to send GNUNET_MessageHeader(s)
1638  * @param message_buf_size total size of all messages in message_buf
1639  * @param is_internal is this an internal message; these are pre-pended and
1640  *                    also do not count for plugins being "ready" to transmit
1641  * @param neighbour handle to the neighbour for transmission
1642  */
1643 static void
1644 transmit_to_peer (struct TransportClient *client,
1645                   struct ForeignAddressList *peer_address,
1646                   unsigned int priority,
1647                   struct GNUNET_TIME_Relative timeout,
1648                   const char *message_buf,
1649                   size_t message_buf_size,
1650                   int is_internal, struct NeighbourList *neighbour)
1651 {
1652   struct MessageQueue *mq;
1653
1654 #if EXTRA_CHECKS
1655   if (client != NULL)
1656     {
1657       /* check for duplicate submission */
1658       mq = neighbour->messages_head;
1659       while (NULL != mq)
1660         {
1661           if (mq->client == client)
1662             {
1663               /* client transmitted to same peer twice
1664                  before getting SEND_OK! */
1665               GNUNET_break (0);
1666               return;
1667             }
1668           mq = mq->next;
1669         }
1670     }
1671 #endif
1672   GNUNET_STATISTICS_update (stats,
1673                             gettext_noop ("# bytes in message queue for other peers"),
1674                             message_buf_size,
1675                             GNUNET_NO);
1676   mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
1677   mq->specific_address = peer_address;
1678   mq->client = client;
1679   memcpy (&mq[1], message_buf, message_buf_size);
1680   mq->message_buf = (const char*) &mq[1];
1681   mq->message_buf_size = message_buf_size;
1682   memcpy(&mq->neighbour_id, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
1683   mq->internal_msg = is_internal;
1684   mq->priority = priority;
1685   mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1686   if (is_internal)    
1687     GNUNET_CONTAINER_DLL_insert (neighbour->messages_head,
1688                                  neighbour->messages_tail,
1689                                  mq);
1690   else
1691     GNUNET_CONTAINER_DLL_insert_after (neighbour->messages_head,
1692                                        neighbour->messages_tail,
1693                                        neighbour->messages_tail,
1694                                        mq);
1695   try_transmission_to_peer (neighbour);
1696 }
1697
1698
1699 /**
1700  * FIXME: document.
1701  */
1702 struct GeneratorContext
1703 {
1704   struct TransportPlugin *plug_pos;
1705   struct OwnAddressList *addr_pos;
1706   struct GNUNET_TIME_Absolute expiration;
1707 };
1708
1709
1710 /**
1711  * FIXME: document.
1712  */
1713 static size_t
1714 address_generator (void *cls, size_t max, void *buf)
1715 {
1716   struct GeneratorContext *gc = cls;
1717   size_t ret;
1718
1719   while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
1720     {
1721       gc->plug_pos = gc->plug_pos->next;
1722       gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
1723     }
1724   if (NULL == gc->plug_pos)
1725     {
1726
1727       return 0;
1728     }
1729   ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
1730                                   gc->expiration,
1731                                   gc->addr_pos->addr,
1732                                   gc->addr_pos->addrlen, buf, max);
1733   gc->addr_pos = gc->addr_pos->next;
1734   return ret;
1735 }
1736
1737
1738 /**
1739  * Construct our HELLO message from all of the addresses of
1740  * all of the transports.
1741  */
1742 static void
1743 refresh_hello ()
1744 {
1745   struct GNUNET_HELLO_Message *hello;
1746   struct TransportClient *cpos;
1747   struct NeighbourList *npos;
1748   struct GeneratorContext gc;
1749
1750   gc.plug_pos = plugins;
1751   gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
1752   gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1753   hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
1754 #if DEBUG_TRANSPORT
1755   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1756               "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
1757 #endif
1758   GNUNET_STATISTICS_update (stats,
1759                             gettext_noop ("# refreshed my HELLO"),
1760                             1,
1761                             GNUNET_NO);
1762   cpos = clients;
1763   while (cpos != NULL)
1764     {
1765       transmit_to_client (cpos,
1766                           (const struct GNUNET_MessageHeader *) hello,
1767                           GNUNET_NO);
1768       cpos = cpos->next;
1769     }
1770
1771   GNUNET_free_non_null (our_hello);
1772   our_hello = hello;
1773   our_hello_version++;
1774   GNUNET_PEERINFO_add_peer (cfg, sched, &my_identity, our_hello);
1775   npos = neighbours;
1776   while (npos != NULL)
1777     {
1778 #if DEBUG_TRANSPORT
1779       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1780                   "Transmitting updated `%s' to neighbour `%4s'\n",
1781                   "HELLO", GNUNET_i2s (&npos->id));
1782 #endif
1783       GNUNET_STATISTICS_update (stats,
1784                                 gettext_noop ("# transmitted my HELLO to other peers"),
1785                                 1,
1786                                 GNUNET_NO);
1787       transmit_to_peer (NULL, NULL, 0,
1788                         HELLO_ADDRESS_EXPIRATION,
1789                         (const char *) our_hello, 
1790                         GNUNET_HELLO_size(our_hello),
1791                         GNUNET_NO, npos);
1792       npos = npos->next;
1793     }
1794 }
1795
1796
1797 /**
1798  * Task used to clean up expired addresses for a plugin.
1799  *
1800  * @param cls closure
1801  * @param tc context
1802  */
1803 static void
1804 expire_address_task (void *cls,
1805                      const struct GNUNET_SCHEDULER_TaskContext *tc);
1806
1807
1808 /**
1809  * Update the list of addresses for this plugin,
1810  * expiring those that are past their expiration date.
1811  *
1812  * @param plugin addresses of which plugin should be recomputed?
1813  * @param fresh set to GNUNET_YES if a new address was added
1814  *        and we need to regenerate the HELLO even if nobody
1815  *        expired
1816  */
1817 static void
1818 update_addresses (struct TransportPlugin *plugin, int fresh)
1819 {
1820   static struct GNUNET_TIME_Absolute last_update;
1821   struct GNUNET_TIME_Relative min_remaining;
1822   struct GNUNET_TIME_Relative remaining;
1823   struct GNUNET_TIME_Absolute now;
1824   struct OwnAddressList *pos;
1825   struct OwnAddressList *prev;
1826   struct OwnAddressList *next;
1827   int expired;
1828
1829   if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
1830     GNUNET_SCHEDULER_cancel (plugin->env.sched, plugin->address_update_task);
1831   plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1832   now = GNUNET_TIME_absolute_get ();
1833   min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
1834   expired = (GNUNET_TIME_absolute_get_duration (last_update).value > (HELLO_ADDRESS_EXPIRATION.value / 4));
1835   prev = NULL;
1836   pos = plugin->addresses;
1837   while (pos != NULL)
1838     {
1839       next = pos->next;
1840       if (pos->expires.value < now.value)
1841         {
1842           expired = GNUNET_YES;
1843           if (prev == NULL)
1844             plugin->addresses = pos->next;
1845           else
1846             prev->next = pos->next;  
1847           GNUNET_free (pos);
1848         }
1849       else
1850         {
1851           remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
1852           if (remaining.value < min_remaining.value)
1853             min_remaining = remaining;
1854           prev = pos;
1855         }
1856       pos = next;
1857     }
1858
1859   if (expired || fresh)
1860     {
1861       last_update = now;
1862       refresh_hello ();
1863     }
1864   min_remaining = GNUNET_TIME_relative_min (min_remaining,
1865                                             GNUNET_TIME_relative_divide (HELLO_ADDRESS_EXPIRATION,
1866                                                                          2));
1867   plugin->address_update_task
1868     = GNUNET_SCHEDULER_add_delayed (plugin->env.sched,
1869                                     min_remaining,
1870                                     &expire_address_task, plugin);
1871 }
1872
1873
1874 /**
1875  * Task used to clean up expired addresses for a plugin.
1876  *
1877  * @param cls closure
1878  * @param tc context
1879  */
1880 static void
1881 expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1882 {
1883   struct TransportPlugin *plugin = cls;
1884
1885   plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1886   if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
1887     update_addresses (plugin, GNUNET_NO);
1888 }
1889
1890
1891 /**
1892  * Iterator over hash map entries that NULLs the session of validation
1893  * entries that match the given session.
1894  *
1895  * @param cls closure (the 'struct Session*' to match against)
1896  * @param key current key code (peer ID, not used)
1897  * @param value value in the hash map ('struct ValidationEntry*')
1898  * @return GNUNET_YES (we should continue to iterate)
1899  */
1900 static int 
1901 remove_session_validations (void *cls,
1902                             const GNUNET_HashCode * key,
1903                             void *value)
1904 {
1905   struct Session *session = cls;
1906   struct ValidationEntry *ve = value;
1907
1908   if (session == ve->session)
1909     ve->session = NULL;
1910   return GNUNET_YES;
1911 }
1912
1913
1914 /**
1915  * Function that will be called whenever the plugin internally
1916  * cleans up a session pointer and hence the service needs to
1917  * discard all of those sessions as well.  Plugins that do not
1918  * use sessions can simply omit calling this function and always
1919  * use NULL wherever a session pointer is needed.
1920  * 
1921  * @param cls closure
1922  * @param peer which peer was the session for 
1923  * @param session which session is being destoyed
1924  */
1925 static void
1926 plugin_env_session_end  (void *cls,
1927                          const struct GNUNET_PeerIdentity *peer,
1928                          struct Session *session)
1929 {
1930   struct TransportPlugin *p = cls;
1931   struct NeighbourList *nl;
1932   struct ReadyList *rl;
1933   struct ForeignAddressList *pos;
1934   struct ForeignAddressList *prev;
1935
1936   GNUNET_CONTAINER_multihashmap_iterate (validation_map,
1937                                          &remove_session_validations,
1938                                          session);
1939   nl = find_neighbour (peer);
1940   if (nl == NULL)
1941     return;
1942   rl = nl->plugins;
1943   while (rl != NULL)
1944     {
1945       if (rl->plugin == p)
1946         break;
1947       rl = rl->next;
1948     }
1949   if (rl == NULL)
1950     return;
1951   prev = NULL;
1952   pos = rl->addresses;
1953   while ( (pos != NULL) &&
1954           (pos->session != session) )
1955     {
1956       prev = pos;
1957       pos = pos->next;
1958     }
1959   if (pos == NULL)
1960     return;
1961   pos->session = NULL;
1962   if (pos->addrlen != 0)
1963     return;
1964   if (prev == NULL)
1965     rl->addresses = pos->next;
1966   else
1967     prev->next = pos->next;
1968   if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
1969     {
1970       GNUNET_SCHEDULER_cancel (sched,
1971                                pos->revalidate_task);
1972       pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
1973     }
1974   GNUNET_free (pos);
1975   if (nl->received_pong == GNUNET_NO)
1976     return; /* nothing to do */
1977   /* check if we have any validated addresses left */
1978   pos = rl->addresses;
1979   while (pos != NULL)
1980     {
1981       if (pos->validated)
1982         return;
1983       pos = pos->next;
1984     }
1985   /* no valid addresses left, signal disconnect! */
1986   disconnect_neighbour (nl, GNUNET_NO);  
1987 }
1988
1989
1990 /**
1991  * Function that must be called by each plugin to notify the
1992  * transport service about the addresses under which the transport
1993  * provided by the plugin can be reached.
1994  *
1995  * @param cls closure
1996  * @param name name of the transport that generated the address
1997  * @param addr one of the addresses of the host, NULL for the last address
1998  *        the specific address format depends on the transport
1999  * @param addrlen length of the address
2000  * @param expires when should this address automatically expire?
2001  */
2002 static void
2003 plugin_env_notify_address (void *cls,
2004                            const char *name,
2005                            const void *addr,
2006                            size_t addrlen,
2007                            struct GNUNET_TIME_Relative expires)
2008 {
2009   struct TransportPlugin *p = cls;
2010   struct OwnAddressList *al;
2011   struct GNUNET_TIME_Absolute abex;
2012
2013   GNUNET_assert (addr != NULL);
2014   abex = GNUNET_TIME_relative_to_absolute (expires);
2015   GNUNET_assert (p == find_transport (name));
2016   al = p->addresses;
2017   while (al != NULL)
2018     {
2019       if ((addrlen == al->addrlen) && (0 == memcmp (addr, &al[1], addrlen)))
2020         {
2021           if (al->expires.value < abex.value)
2022             al->expires = abex;
2023           return;
2024         }
2025       al = al->next;
2026     }
2027
2028   al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
2029   al->addr = &al[1];
2030   al->next = p->addresses;
2031   p->addresses = al;
2032   al->expires = abex;
2033   al->addrlen = addrlen;
2034   memcpy (&al[1], addr, addrlen);
2035   update_addresses (p, GNUNET_YES);
2036 }
2037
2038
2039 /**
2040  * Notify all of our clients about a peer connecting.
2041  */
2042 static void
2043 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
2044                         struct GNUNET_TIME_Relative latency,
2045                         uint32_t distance)
2046 {
2047   struct ConnectInfoMessage cim;
2048   struct TransportClient *cpos;
2049
2050 #if DEBUG_TRANSPORT
2051   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2052               "Notifying clients about connection from `%s'\n",
2053               GNUNET_i2s (peer));
2054 #endif
2055   GNUNET_STATISTICS_update (stats,
2056                             gettext_noop ("# peers connected"),
2057                             1,
2058                             GNUNET_NO);
2059   cim.header.size = htons (sizeof (struct ConnectInfoMessage));
2060   cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2061   cim.distance = htonl (distance);
2062   cim.latency = GNUNET_TIME_relative_hton (latency);
2063   memcpy (&cim.id, peer, sizeof (struct GNUNET_PeerIdentity));
2064   cpos = clients;
2065   while (cpos != NULL)
2066     {
2067       transmit_to_client (cpos, &cim.header, GNUNET_NO);
2068       cpos = cpos->next;
2069     }
2070 }
2071
2072
2073 /**
2074  * Notify all of our clients about a peer disconnecting.
2075  */
2076 static void
2077 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
2078 {
2079   struct DisconnectInfoMessage dim;
2080   struct TransportClient *cpos;
2081
2082 #if DEBUG_TRANSPORT
2083   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2084               "Notifying clients about lost connection to `%s'\n",
2085               GNUNET_i2s (peer));
2086 #endif
2087   GNUNET_STATISTICS_update (stats,
2088                             gettext_noop ("# peers connected"),
2089                             -1,
2090                             GNUNET_NO);
2091   dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
2092   dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2093   dim.reserved = htonl (0);
2094   memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
2095   cpos = clients;
2096   while (cpos != NULL)
2097     {
2098       transmit_to_client (cpos, &dim.header, GNUNET_NO);
2099       cpos = cpos->next;
2100     }
2101 }
2102
2103
2104 /**
2105  * Find a ForeignAddressList entry for the given neighbour
2106  * that matches the given address and transport.
2107  *
2108  * @param neighbour which peer we care about
2109  * @param tname name of the transport plugin
2110  * @param session session to look for, NULL for 'any'; otherwise
2111  *        can be used for the service to "learn" this session ID
2112  *        if 'addr' matches
2113  * @param addr binary address
2114  * @param addrlen length of addr
2115  * @return NULL if no such entry exists
2116  */
2117 static struct ForeignAddressList *
2118 find_peer_address(struct NeighbourList *neighbour,
2119                   const char *tname,
2120                   struct Session *session,
2121                   const char *addr,
2122                   size_t addrlen)
2123 {
2124   struct ReadyList *head;
2125   struct ForeignAddressList *pos;
2126
2127   head = neighbour->plugins;
2128   while (head != NULL)
2129     {
2130       if (0 == strcmp (tname, head->plugin->short_name))
2131         break;
2132       head = head->next;
2133     }
2134   if (head == NULL)
2135     return NULL;
2136   pos = head->addresses;
2137   while ( (pos != NULL) &&
2138           ( (pos->addrlen != addrlen) ||
2139             (memcmp(pos->addr, addr, addrlen) != 0) ) )
2140     {
2141       if ( (session != NULL) &&
2142            (pos->session == session) )
2143         return pos;
2144       pos = pos->next;
2145     }
2146   if ( (session != NULL) && (pos != NULL) )
2147     pos->session = session; /* learn it! */
2148   return pos;
2149 }
2150
2151
2152 /**
2153  * Get the peer address struct for the given neighbour and
2154  * address.  If it doesn't yet exist, create it.
2155  *
2156  * @param neighbour which peer we care about
2157  * @param tname name of the transport plugin
2158  * @param session session of the plugin, or NULL for none
2159  * @param addr binary address
2160  * @param addrlen length of addr
2161  * @return NULL if we do not have a transport plugin for 'tname'
2162  */
2163 static struct ForeignAddressList *
2164 add_peer_address (struct NeighbourList *neighbour,
2165                   const char *tname,
2166                   struct Session *session,
2167                   const char *addr, 
2168                   size_t addrlen)
2169 {
2170   struct ReadyList *head;
2171   struct ForeignAddressList *ret;
2172
2173   ret = find_peer_address (neighbour, tname, session, addr, addrlen);
2174   if (ret != NULL)
2175     return ret;
2176   head = neighbour->plugins;
2177
2178   while (head != NULL)
2179     {
2180       if (0 == strcmp (tname, head->plugin->short_name))
2181         break;
2182       head = head->next;
2183     }
2184   if (head == NULL)
2185     return NULL;
2186   ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
2187   ret->session = session;
2188   if (addrlen > 0)
2189     {
2190       ret->addr = (const char*) &ret[1];
2191       memcpy (&ret[1], addr, addrlen);
2192     }
2193   else
2194     {
2195       ret->addr = NULL;
2196     }
2197   ret->addrlen = addrlen;
2198   ret->expires = GNUNET_TIME_relative_to_absolute
2199     (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2200   ret->latency = GNUNET_TIME_relative_get_forever();
2201   ret->distance = -1;
2202   ret->timeout = GNUNET_TIME_relative_to_absolute
2203     (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); 
2204   ret->ready_list = head;
2205   ret->next = head->addresses;
2206   head->addresses = ret;
2207   return ret;
2208 }
2209
2210
2211 /**
2212  * Closure for 'add_validated_address'.
2213  */
2214 struct AddValidatedAddressContext
2215 {
2216   /**
2217    * Entry that has been validated.
2218    */
2219   const struct ValidationEntry *ve;
2220
2221   /**
2222    * Flag set after we have added the address so
2223    * that we terminate the iteration next time.
2224    */
2225   int done;
2226 };
2227
2228
2229 /**
2230  * Callback function used to fill a buffer of max bytes with a list of
2231  * addresses in the format used by HELLOs.  Should use
2232  * "GNUNET_HELLO_add_address" as a helper function.
2233  *
2234  * @param cls the 'struct AddValidatedAddressContext' with the validated address
2235  * @param max maximum number of bytes that can be written to buf
2236  * @param buf where to write the address information
2237  * @return number of bytes written, 0 to signal the
2238  *         end of the iteration.
2239  */
2240 static size_t
2241 add_validated_address (void *cls,
2242                        size_t max, void *buf)
2243 {
2244   struct AddValidatedAddressContext *avac = cls;
2245   const struct ValidationEntry *ve = avac->ve;
2246
2247   if (GNUNET_YES == avac->done)
2248     return 0;
2249   avac->done = GNUNET_YES;
2250   return GNUNET_HELLO_add_address (ve->transport_name,
2251                                    GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION),
2252                                    ve->addr,
2253                                    ve->addrlen,
2254                                    buf,
2255                                    max);
2256 }
2257
2258
2259
2260 /**
2261  * Closure for 'check_address_exists'.
2262  */
2263 struct CheckAddressExistsClosure
2264 {
2265   /**
2266    * Address to check for.
2267    */
2268   const void *addr;
2269
2270   /**
2271    * Name of the transport.
2272    */
2273   const char *tname;
2274
2275   /**
2276    * Session, or NULL.
2277    */
2278   struct Session *session;
2279
2280   /**
2281    * Length of addr.
2282    */
2283   size_t addrlen;
2284
2285   /**
2286    * Set to GNUNET_YES if the address exists.
2287    */
2288   int exists;
2289 };
2290
2291
2292 /**
2293  * Iterator over hash map entries.  Checks if the given
2294  * validation entry is for the same address as what is given
2295  * in the closure.
2296  *
2297  * @param cls the 'struct CheckAddressExistsClosure*'
2298  * @param key current key code (ignored)
2299  * @param value value in the hash map ('struct ValidationEntry')
2300  * @return GNUNET_YES if we should continue to
2301  *         iterate (mismatch), GNUNET_NO if not (entry matched)
2302  */
2303 static int
2304 check_address_exists (void *cls,
2305                       const GNUNET_HashCode * key,
2306                       void *value)
2307 {
2308   struct CheckAddressExistsClosure *caec = cls;
2309   struct ValidationEntry *ve = value;
2310
2311   if ( (0 == strcmp (caec->tname,
2312                      ve->transport_name)) &&
2313        (caec->addrlen == ve->addrlen) &&
2314        (0 == memcmp (caec->addr,
2315                      ve->addr,
2316                      caec->addrlen)) )
2317     {
2318       caec->exists = GNUNET_YES;
2319       return GNUNET_NO;
2320     }
2321   if ( (ve->session != NULL) &&
2322        (caec->session == ve->session) )
2323     {
2324       caec->exists = GNUNET_YES;
2325       return GNUNET_NO;
2326     }
2327   return GNUNET_YES;
2328 }
2329
2330
2331 /**
2332  * HELLO validation cleanup task (validation failed).
2333  *
2334  * @param cls the 'struct ValidationEntry' that failed
2335  * @param tc scheduler context (unused)
2336  */
2337 static void
2338 timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2339 {
2340   struct ValidationEntry *va = cls;
2341   struct GNUNET_PeerIdentity pid;
2342
2343   GNUNET_STATISTICS_update (stats,
2344                             gettext_noop ("# address validation timeouts"),
2345                             1,
2346                             GNUNET_NO);
2347   GNUNET_CRYPTO_hash (&va->publicKey,
2348                       sizeof (struct
2349                               GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2350                       &pid.hashPubKey);
2351   GNUNET_CONTAINER_multihashmap_remove (validation_map,
2352                                         &pid.hashPubKey,
2353                                         va);
2354   GNUNET_free (va->transport_name);
2355   GNUNET_free (va);
2356 }
2357
2358
2359 static void
2360 neighbour_timeout_task (void *cls,
2361                        const struct GNUNET_SCHEDULER_TaskContext *tc)
2362 {
2363   struct NeighbourList *n = cls;
2364
2365 #if DEBUG_TRANSPORT
2366   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2367               "Neighbour `%4s' has timed out!\n", GNUNET_i2s (&n->id));
2368 #endif
2369   GNUNET_STATISTICS_update (stats,
2370                             gettext_noop ("# disconnects due to timeout"),
2371                             1,
2372                             GNUNET_NO);
2373   n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2374   disconnect_neighbour (n, GNUNET_NO);
2375 }
2376
2377
2378 /**
2379  * Schedule the job that will cause us to send a PING to the
2380  * foreign address to evaluate its validity and latency.
2381  *
2382  * @param fal address to PING
2383  */
2384 static void
2385 schedule_next_ping (struct ForeignAddressList *fal);
2386
2387
2388 /**
2389  * Add the given address to the list of foreign addresses
2390  * available for the given peer (check for duplicates).
2391  *
2392  * @param cls the respective 'struct NeighbourList' to update
2393  * @param tname name of the transport
2394  * @param expiration expiration time
2395  * @param addr the address
2396  * @param addrlen length of the address
2397  * @return GNUNET_OK (always)
2398  */
2399 static int
2400 add_to_foreign_address_list (void *cls,
2401                              const char *tname,
2402                              struct GNUNET_TIME_Absolute expiration,
2403                              const void *addr, size_t addrlen)
2404 {
2405   struct NeighbourList *n = cls;
2406   struct ForeignAddressList *fal;
2407   int try;
2408
2409   GNUNET_STATISTICS_update (stats,
2410                             gettext_noop ("# valid peer addresses returned by peerinfo"),
2411                             1,
2412                             GNUNET_NO);      
2413   try = GNUNET_NO;
2414   fal = find_peer_address (n, tname, NULL, addr, addrlen);
2415   if (fal == NULL)
2416     {
2417 #if DEBUG_TRANSPORT
2418       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2419                   "Adding address `%s' (%s) for peer `%4s' due to peerinfo data for %llums.\n",
2420                   GNUNET_a2s (addr, addrlen),
2421                   tname,
2422                   GNUNET_i2s (&n->id),
2423                   expiration.value);
2424 #endif
2425       fal = add_peer_address (n, tname, NULL, addr, addrlen);
2426       if (fal == NULL)
2427         {
2428           GNUNET_STATISTICS_update (stats,
2429                                     gettext_noop ("# previously validated addresses lacking transport"),
2430                                     1,
2431                                     GNUNET_NO); 
2432         }
2433       else
2434         {
2435           fal->expires = GNUNET_TIME_absolute_max (expiration,
2436                                                    fal->expires);
2437           schedule_next_ping (fal);
2438         }
2439       try = GNUNET_YES;
2440     }
2441   else
2442     {
2443       fal->expires = GNUNET_TIME_absolute_max (expiration,
2444                                                fal->expires);
2445     }
2446   if (fal == NULL)
2447     {
2448       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2449                   "Failed to add new address for `%4s'\n",
2450                   GNUNET_i2s (&n->id));
2451       return GNUNET_OK;
2452     }
2453   if (fal->validated == GNUNET_NO)
2454     {
2455       fal->validated = GNUNET_YES;  
2456       GNUNET_STATISTICS_update (stats,
2457                                 gettext_noop ("# peer addresses considered valid"),
2458                                 1,
2459                                 GNUNET_NO);      
2460     }
2461   if (try == GNUNET_YES)
2462     {
2463       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2464                   "Have new addresses, will try to trigger transmissions.\n");
2465       try_transmission_to_peer (n);
2466     }
2467   return GNUNET_OK;
2468 }
2469
2470
2471 /**
2472  * Add addresses in validated HELLO "h" to the set of addresses
2473  * we have for this peer.
2474  *
2475  * @param cls closure ('struct NeighbourList*')
2476  * @param peer id of the peer, NULL for last call
2477  * @param h hello message for the peer (can be NULL)
2478  * @param trust amount of trust we have in the peer (not used)
2479  */
2480 static void
2481 add_hello_for_peer (void *cls,
2482                     const struct GNUNET_PeerIdentity *peer,
2483                     const struct GNUNET_HELLO_Message *h, 
2484                     uint32_t trust)
2485 {
2486   struct NeighbourList *n = cls;
2487
2488   if (peer == NULL)
2489     {
2490       n->piter = NULL;
2491       return;
2492     } 
2493   if (h == NULL)
2494     return; /* no HELLO available */
2495 #if DEBUG_TRANSPORT
2496   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2497               "Peerinfo had `%s' message for peer `%4s', adding existing addresses.\n",
2498               "HELLO",
2499               GNUNET_i2s (peer));
2500 #endif
2501   if (GNUNET_YES != n->public_key_valid)
2502     {
2503       GNUNET_HELLO_get_key (h, &n->publicKey);
2504       n->public_key_valid = GNUNET_YES;
2505     }
2506   GNUNET_HELLO_iterate_addresses (h,
2507                                   GNUNET_NO,
2508                                   &add_to_foreign_address_list,
2509                                   n);
2510 }
2511
2512
2513 /**
2514  * Create a fresh entry in our neighbour list for the given peer.
2515  * Will try to transmit our current HELLO to the new neighbour.
2516  *
2517  * @param peer the peer for which we create the entry
2518  * @return the new neighbour list entry
2519  */
2520 static struct NeighbourList *
2521 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer)
2522 {
2523   struct NeighbourList *n;
2524   struct TransportPlugin *tp;
2525   struct ReadyList *rl;
2526
2527   GNUNET_assert (our_hello != NULL);
2528   GNUNET_STATISTICS_update (stats,
2529                             gettext_noop ("# active neighbours"),
2530                             1,
2531                             GNUNET_NO);
2532   n = GNUNET_malloc (sizeof (struct NeighbourList));
2533   n->next = neighbours;
2534   neighbours = n;
2535   n->id = *peer;
2536   n->peer_timeout =
2537     GNUNET_TIME_relative_to_absolute
2538     (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2539   GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
2540                                  GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
2541                                  MAX_BANDWIDTH_CARRY_S);
2542   tp = plugins;
2543   while (tp != NULL)
2544     {
2545       if ((tp->api->send != NULL) && (!is_blacklisted(peer, tp)))
2546         {
2547           rl = GNUNET_malloc (sizeof (struct ReadyList));
2548           rl->neighbour = n;
2549           rl->next = n->plugins;
2550           n->plugins = rl;
2551           rl->plugin = tp;
2552           rl->addresses = NULL;
2553         }
2554       tp = tp->next;
2555     }
2556   n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
2557   n->distance = -1;
2558   n->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
2559                                                   GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2560                                                   &neighbour_timeout_task, n);
2561   n->piter = GNUNET_PEERINFO_iterate (cfg, sched, peer,
2562                                       0, GNUNET_TIME_UNIT_FOREVER_REL,
2563                                       &add_hello_for_peer, n);
2564   transmit_to_peer (NULL, NULL, 0,
2565                     HELLO_ADDRESS_EXPIRATION,
2566                     (const char *) our_hello, GNUNET_HELLO_size(our_hello),
2567                     GNUNET_NO, n);
2568   return n;
2569 }
2570
2571
2572 /**
2573  * Send periodic PING messages to a give foreign address.
2574  *
2575  * @param cls our 'struct PeriodicValidationContext*'
2576  * @param tc task context
2577  */
2578 static void 
2579 send_periodic_ping (void *cls, 
2580                     const struct GNUNET_SCHEDULER_TaskContext *tc)
2581 {
2582   struct ForeignAddressList *peer_address = cls;
2583   struct TransportPlugin *tp;
2584   struct ValidationEntry *va;
2585   struct NeighbourList *neighbour;
2586   struct TransportPingMessage ping;
2587   struct CheckAddressExistsClosure caec;
2588   char * message_buf;
2589   uint16_t hello_size;
2590   size_t tsize;
2591
2592   peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2593   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
2594     return; 
2595   tp = peer_address->ready_list->plugin;
2596   neighbour = peer_address->ready_list->neighbour;
2597   if (GNUNET_YES != neighbour->public_key_valid)
2598     {
2599       /* no public key yet, try again later */
2600       schedule_next_ping (peer_address);     
2601       return;
2602     }
2603   caec.addr = peer_address->addr;
2604   caec.addrlen = peer_address->addrlen;
2605   caec.tname = tp->short_name;
2606   caec.session = peer_address->session;
2607   caec.exists = GNUNET_NO;
2608   GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2609                                          &check_address_exists,
2610                                          &caec);
2611   if (caec.exists == GNUNET_YES)
2612     {
2613       /* During validation attempts we will likely trigger the other
2614          peer trying to validate our address which in turn will cause
2615          it to send us its HELLO, so we expect to hit this case rather
2616          frequently.  Only print something if we are very verbose. */
2617 #if DEBUG_TRANSPORT > 1
2618       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2619                   "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
2620                   (peer_address->addr != NULL)
2621                   ? GNUNET_a2s (peer_address->addr,
2622                                 peer_address->addrlen)
2623                   : "<inbound>",
2624                   tp->short_name,
2625                   GNUNET_i2s (&neighbour->id));
2626 #endif
2627       schedule_next_ping (peer_address);     
2628       return;
2629     }
2630   va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
2631   va->transport_name = GNUNET_strdup (tp->short_name);
2632   va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2633                                             (unsigned int) -1);
2634   va->send_time = GNUNET_TIME_absolute_get();
2635   va->session = peer_address->session;
2636   if (peer_address->addr != NULL)
2637     {
2638       va->addr = (const void*) &va[1];
2639       memcpy (&va[1], peer_address->addr, peer_address->addrlen);
2640       va->addrlen = peer_address->addrlen;
2641     }
2642   memcpy(&va->publicKey,
2643          &neighbour->publicKey, 
2644          sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
2645
2646   va->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
2647                                                    HELLO_VERIFICATION_TIMEOUT,
2648                                                    &timeout_hello_validation,
2649                                                    va);
2650   GNUNET_CONTAINER_multihashmap_put (validation_map,
2651                                      &neighbour->id.hashPubKey,
2652                                      va,
2653                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2654   hello_size = GNUNET_HELLO_size(our_hello);
2655   tsize = sizeof(struct TransportPingMessage) + hello_size;
2656   message_buf = GNUNET_malloc(tsize);
2657   ping.challenge = htonl(va->challenge);
2658   ping.header.size = htons(sizeof(struct TransportPingMessage));
2659   ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
2660   memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
2661   memcpy(message_buf, our_hello, hello_size);
2662   memcpy(&message_buf[hello_size],
2663          &ping,
2664          sizeof(struct TransportPingMessage));
2665 #if DEBUG_TRANSPORT_REVALIDATION
2666   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2667               "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
2668               (peer_address->addr != NULL) 
2669               ? GNUNET_a2s (peer_address->addr,
2670                             peer_address->addrlen)
2671               : "<inbound>",
2672               tp->short_name,
2673               GNUNET_i2s (&neighbour->id),
2674               "HELLO", hello_size,
2675               "PING", sizeof (struct TransportPingMessage));
2676 #endif
2677   GNUNET_STATISTICS_update (stats,
2678                             gettext_noop ("# PING messages sent for re-validation"),
2679                             1,
2680                             GNUNET_NO);
2681   transmit_to_peer (NULL, peer_address,
2682                     GNUNET_SCHEDULER_PRIORITY_DEFAULT,
2683                     HELLO_VERIFICATION_TIMEOUT,
2684                     message_buf, tsize,
2685                     GNUNET_YES, neighbour);
2686   GNUNET_free(message_buf);
2687   schedule_next_ping (peer_address);
2688 }
2689
2690
2691 /**
2692  * Schedule the job that will cause us to send a PING to the
2693  * foreign address to evaluate its validity and latency.
2694  *
2695  * @param fal address to PING
2696  */
2697 static void
2698 schedule_next_ping (struct ForeignAddressList *fal)
2699 {
2700   struct GNUNET_TIME_Relative delay;
2701
2702   if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
2703     return;
2704   delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
2705   delay.value /= 2; /* do before expiration */
2706   delay = GNUNET_TIME_relative_min (delay,
2707                                     LATENCY_EVALUATION_MAX_DELAY);
2708   if (GNUNET_YES != fal->estimated)
2709     {
2710       delay = GNUNET_TIME_UNIT_ZERO;
2711       fal->estimated = GNUNET_YES;
2712     }                               
2713   if (GNUNET_YES == fal->connected)
2714     {
2715       delay = GNUNET_TIME_relative_min (delay,
2716                                         CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
2717     }  
2718   /* FIXME: also adjust delay based on how close the last
2719      observed latency is to the latency of the best alternative */
2720   /* bound how fast we can go */
2721   delay = GNUNET_TIME_relative_max (delay,
2722                                     GNUNET_TIME_UNIT_SECONDS);
2723   /* randomize a bit (to avoid doing all at the same time) */
2724   delay.value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
2725   fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(sched, 
2726                                                       delay,
2727                                                       &send_periodic_ping, 
2728                                                       fal);
2729 }
2730
2731
2732
2733
2734 /**
2735  * Function that will be called if we receive some payload
2736  * from another peer.
2737  *
2738  * @param message the payload
2739  * @param n peer who claimed to be the sender
2740  */
2741 static void
2742 handle_payload_message (const struct GNUNET_MessageHeader *message,
2743                         struct NeighbourList *n)
2744 {
2745   struct InboundMessage *im;
2746   struct TransportClient *cpos;
2747   uint16_t msize;
2748
2749   msize = ntohs (message->size);
2750   if (n->received_pong == GNUNET_NO)
2751     {
2752       GNUNET_free_non_null (n->pre_connect_message_buffer);
2753       n->pre_connect_message_buffer = GNUNET_malloc (msize);
2754       memcpy (n->pre_connect_message_buffer, message, msize);
2755       return;
2756     }
2757 #if DEBUG_TRANSPORT
2758   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2759               "Received message of type %u from `%4s', sending to all clients.\n",
2760               ntohs (message->type), 
2761               GNUNET_i2s (&n->id));
2762 #endif
2763   if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
2764                                                       (ssize_t) msize))
2765     {
2766       n->quota_violation_count++;
2767 #if DEBUG_TRANSPORT
2768       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,                        
2769                   "Bandwidth quota (%u b/s) violation detected (total of %u).\n", 
2770                   n->in_tracker.available_bytes_per_s__,
2771                   n->quota_violation_count);
2772 #endif
2773       /* Discount 32k per violation */
2774       GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
2775                                         - 32 * 1024);           
2776     }
2777   else 
2778     {
2779       if (n->quota_violation_count > 0)
2780         {
2781           /* try to add 32k back */
2782           GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
2783                                             32 * 1024);
2784           n->quota_violation_count--;
2785         }
2786     }
2787   GNUNET_STATISTICS_update (stats,
2788                             gettext_noop ("# payload received from other peers"),
2789                             msize,
2790                             GNUNET_NO);
2791   /* transmit message to all clients */
2792   im = GNUNET_malloc (sizeof (struct InboundMessage) + msize);
2793   im->header.size = htons (sizeof (struct InboundMessage) + msize);
2794   im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
2795   im->latency = GNUNET_TIME_relative_hton (n->latency);
2796   im->peer = n->id;
2797   memcpy (&im[1], message, msize);
2798   cpos = clients;
2799   while (cpos != NULL)
2800     {
2801       transmit_to_client (cpos, &im->header, GNUNET_YES);
2802       cpos = cpos->next;
2803     }
2804   GNUNET_free (im);
2805 }
2806
2807
2808 /**
2809  * Iterator over hash map entries.  Checks if the given validation
2810  * entry is for the same challenge as what is given in the PONG.
2811  *
2812  * @param cls the 'struct TransportPongMessage*'
2813  * @param key peer identity
2814  * @param value value in the hash map ('struct ValidationEntry')
2815  * @return GNUNET_YES if we should continue to
2816  *         iterate (mismatch), GNUNET_NO if not (entry matched)
2817  */
2818 static int
2819 check_pending_validation (void *cls,
2820                           const GNUNET_HashCode * key,
2821                           void *value)
2822 {
2823   const struct TransportPongMessage *pong = cls;
2824   struct ValidationEntry *ve = value;
2825   struct AddValidatedAddressContext avac;
2826   unsigned int challenge = ntohl(pong->challenge);
2827   struct GNUNET_HELLO_Message *hello;
2828   struct GNUNET_PeerIdentity target;
2829   struct NeighbourList *n;
2830   struct ForeignAddressList *fal;
2831   struct GNUNET_MessageHeader *prem;
2832
2833   if (ve->challenge != challenge)
2834     return GNUNET_YES;
2835   if (GNUNET_OK !=
2836       GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PING,
2837                                 &pong->purpose, 
2838                                 &pong->signature,
2839                                 &ve->publicKey))
2840     {
2841       GNUNET_break_op (0);
2842       return GNUNET_YES;
2843     }
2844
2845 #if DEBUG_TRANSPORT
2846   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2847               "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
2848               GNUNET_h2s (key),
2849               (ve->addr != NULL) 
2850               ? GNUNET_a2s ((const struct sockaddr *) ve->addr,
2851                             ve->addrlen)
2852               : "<inbound>",
2853               ve->transport_name);
2854 #endif
2855   GNUNET_STATISTICS_update (stats,
2856                             gettext_noop ("# address validation successes"),
2857                             1,
2858                             GNUNET_NO);
2859   /* create the updated HELLO */
2860   GNUNET_CRYPTO_hash (&ve->publicKey,
2861                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2862                       &target.hashPubKey);
2863   if (ve->addr != NULL)
2864     {
2865       avac.done = GNUNET_NO;
2866       avac.ve = ve;
2867       hello = GNUNET_HELLO_create (&ve->publicKey,
2868                                    &add_validated_address,
2869                                    &avac);
2870       GNUNET_PEERINFO_add_peer (cfg, sched,
2871                                 &target,
2872                                 hello);
2873       GNUNET_free (hello);
2874     }
2875   n = find_neighbour (&target);
2876   if (n != NULL)
2877     {
2878       n->publicKey = ve->publicKey;
2879       n->public_key_valid = GNUNET_YES;
2880       fal = add_peer_address (n,
2881                               ve->transport_name,
2882                               ve->session,
2883                               ve->addr,
2884                               ve->addrlen);
2885       GNUNET_assert (fal != NULL);
2886       fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
2887       fal->validated = GNUNET_YES;
2888       mark_address_connected (fal);
2889       GNUNET_STATISTICS_update (stats,
2890                                 gettext_noop ("# peer addresses considered valid"),
2891                                 1,
2892                                 GNUNET_NO);      
2893       fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
2894       schedule_next_ping (fal);
2895       if (n->latency.value == GNUNET_TIME_UNIT_FOREVER_REL.value)
2896         n->latency = fal->latency;
2897       else
2898         n->latency.value = (fal->latency.value + n->latency.value) / 2;
2899       n->distance = fal->distance;
2900       if (GNUNET_NO == n->received_pong)
2901         {
2902           n->received_pong = GNUNET_YES;
2903           notify_clients_connect (&target, n->latency, n->distance);
2904           if (NULL != (prem = n->pre_connect_message_buffer))
2905             {
2906               n->pre_connect_message_buffer = NULL;
2907               handle_payload_message (prem, n);
2908               GNUNET_free (prem);
2909             }
2910         }
2911       if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
2912         {
2913           GNUNET_SCHEDULER_cancel (sched,
2914                                    n->retry_task);
2915           n->retry_task = GNUNET_SCHEDULER_NO_TASK;
2916           try_transmission_to_peer (n);
2917         }
2918     }
2919
2920   /* clean up validation entry */
2921   GNUNET_assert (GNUNET_YES ==
2922                  GNUNET_CONTAINER_multihashmap_remove (validation_map,
2923                                                        key,
2924                                                        ve));
2925   GNUNET_SCHEDULER_cancel (sched,
2926                            ve->timeout_task);
2927   GNUNET_free (ve->transport_name);
2928   GNUNET_free (ve);
2929   return GNUNET_NO;
2930 }
2931
2932
2933 /**
2934  * Function that will be called if we receive a validation
2935  * of an address challenge that we transmitted to another
2936  * peer.  Note that the validation should only be considered
2937  * acceptable if the challenge matches AND if the sender
2938  * address is at least a plausible address for this peer
2939  * (otherwise we may be seeing a MiM attack).
2940  *
2941  * @param cls closure
2942  * @param message the pong message
2943  * @param peer who responded to our challenge
2944  * @param sender_address string describing our sender address (as observed
2945  *         by the other peer in binary format)
2946  * @param sender_address_len number of bytes in 'sender_address'
2947  */
2948 static void
2949 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
2950              const struct GNUNET_PeerIdentity *peer,
2951              const char *sender_address,
2952              size_t sender_address_len)
2953 {
2954 #if DEBUG_TRANSPORT > 1
2955   /* we get tons of these that just get discarded, only log
2956      if we are quite verbose */
2957   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2958               "Receiving `%s' message from `%4s'.\n", "PONG",
2959               GNUNET_i2s (peer));
2960 #endif
2961   GNUNET_STATISTICS_update (stats,
2962                             gettext_noop ("# PONG messages received"),
2963                             1,
2964                             GNUNET_NO);
2965   if (GNUNET_SYSERR !=
2966       GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
2967                                                   &peer->hashPubKey,
2968                                                   &check_pending_validation,
2969                                                   (void*) message))
2970     {
2971       /* This is *expected* to happen a lot since we send
2972          PONGs to *all* known addresses of the sender of
2973          the PING, so most likely we get multiple PONGs
2974          per PING, and all but the first PONG will end up
2975          here. So really we should not print anything here
2976          unless we want to be very, very verbose... */
2977 #if DEBUG_TRANSPORT > 2
2978       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2979                   "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
2980                   "PONG",
2981                   GNUNET_i2s (peer),
2982                   "PING");
2983 #endif
2984       return;
2985     }
2986
2987 #if 0
2988   /* FIXME: add given address to potential pool of our addresses
2989      (for voting) */
2990   GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
2991               _("Another peer saw us using the address `%s' via `%s'.\n"),
2992               GNUNET_a2s ((const struct sockaddr *) &pong[1],
2993                           ntohs(pong->addrlen)),
2994               va->transport_name);
2995 #endif
2996 }
2997
2998
2999 /**
3000  * Check if the given address is already being validated; if not,
3001  * append the given address to the list of entries that are being be
3002  * validated and initiate validation.
3003  *
3004  * @param cls closure ('struct CheckHelloValidatedContext *')
3005  * @param tname name of the transport
3006  * @param expiration expiration time
3007  * @param addr the address
3008  * @param addrlen length of the address
3009  * @return GNUNET_OK (always)
3010  */
3011 static int
3012 run_validation (void *cls,
3013                 const char *tname,
3014                 struct GNUNET_TIME_Absolute expiration,
3015                 const void *addr, size_t addrlen)
3016 {
3017   struct CheckHelloValidatedContext *chvc = cls;
3018   struct GNUNET_PeerIdentity id;
3019   struct TransportPlugin *tp;
3020   struct ValidationEntry *va;
3021   struct NeighbourList *neighbour;
3022   struct ForeignAddressList *peer_address;
3023   struct TransportPingMessage ping;
3024   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
3025   struct CheckAddressExistsClosure caec;
3026   char * message_buf;
3027   uint16_t hello_size;
3028   size_t tsize;
3029
3030   GNUNET_assert (addr != NULL);
3031   GNUNET_STATISTICS_update (stats,
3032                             gettext_noop ("# peer addresses scheduled for validation"),
3033                             1,
3034                             GNUNET_NO);      
3035   tp = find_transport (tname);
3036   if (tp == NULL)
3037     {
3038       GNUNET_log (GNUNET_ERROR_TYPE_INFO |
3039                   GNUNET_ERROR_TYPE_BULK,
3040                   _
3041                   ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
3042                   tname);
3043       GNUNET_STATISTICS_update (stats,
3044                                 gettext_noop ("# peer addresses not validated (no applicable transport plugin available)"),
3045                                 1,
3046                                 GNUNET_NO);      
3047       return GNUNET_OK;
3048     }
3049   GNUNET_HELLO_get_key (chvc->hello, &pk);
3050   GNUNET_CRYPTO_hash (&pk,
3051                       sizeof (struct
3052                               GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3053                       &id.hashPubKey);
3054
3055   if (is_blacklisted(&id, tp))
3056     {
3057 #if DEBUG_TRANSPORT
3058       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3059                   _("Attempted to validate blacklisted peer `%s' using `%s'!\n"), GNUNET_i2s(&id), tname);
3060 #endif
3061       return GNUNET_OK;
3062     }
3063
3064   caec.addr = addr;
3065   caec.addrlen = addrlen;
3066   caec.session = NULL;
3067   caec.tname = tname;
3068   caec.exists = GNUNET_NO;
3069   GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3070                                          &check_address_exists,
3071                                          &caec);
3072   if (caec.exists == GNUNET_YES)
3073     {
3074       /* During validation attempts we will likely trigger the other
3075          peer trying to validate our address which in turn will cause
3076          it to send us its HELLO, so we expect to hit this case rather
3077          frequently.  Only print something if we are very verbose. */
3078 #if DEBUG_TRANSPORT > 1
3079       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3080                   "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
3081                   GNUNET_a2s (addr, addrlen),
3082                   tname,
3083                   GNUNET_i2s (&id));
3084 #endif
3085       GNUNET_STATISTICS_update (stats,
3086                                 gettext_noop ("# peer addresses not validated (in progress)"),
3087                                 1,
3088                                 GNUNET_NO);      
3089       return GNUNET_OK;
3090     }
3091   va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
3092   va->transport_name = GNUNET_strdup (tname);
3093   va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
3094                                             (unsigned int) -1);
3095   va->send_time = GNUNET_TIME_absolute_get();
3096   va->addr = (const void*) &va[1];
3097   memcpy (&va[1], addr, addrlen);
3098   va->addrlen = addrlen;
3099   GNUNET_HELLO_get_key (chvc->hello,
3100                         &va->publicKey);
3101   va->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
3102                                                    HELLO_VERIFICATION_TIMEOUT,
3103                                                    &timeout_hello_validation,
3104                                                    va);
3105   GNUNET_CONTAINER_multihashmap_put (validation_map,
3106                                      &id.hashPubKey,
3107                                      va,
3108                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3109   neighbour = find_neighbour(&id);
3110   if (neighbour == NULL)
3111     neighbour = setup_new_neighbour(&id);
3112   neighbour->publicKey = va->publicKey;
3113   neighbour->public_key_valid = GNUNET_YES;
3114   peer_address = add_peer_address (neighbour, tname, NULL, addr, addrlen);
3115   if (peer_address == NULL)
3116     {
3117       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3118                   "Attempted to add peer `%4s' for plugin `%s'\n",
3119                   GNUNET_i2s (&id), tname);
3120     }
3121   GNUNET_assert(peer_address != NULL);
3122   hello_size = GNUNET_HELLO_size(our_hello);
3123   tsize = sizeof(struct TransportPingMessage) + hello_size;
3124   message_buf = GNUNET_malloc(tsize);
3125   ping.challenge = htonl(va->challenge);
3126   ping.header.size = htons(sizeof(struct TransportPingMessage));
3127   ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3128   memcpy(&ping.target, &id, sizeof(struct GNUNET_PeerIdentity));
3129   memcpy(message_buf, our_hello, hello_size);
3130   memcpy(&message_buf[hello_size],
3131          &ping,
3132          sizeof(struct TransportPingMessage));
3133 #if DEBUG_TRANSPORT
3134   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3135               "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
3136               GNUNET_a2s (addr, addrlen),
3137               tname,
3138               GNUNET_i2s (&id),
3139               "HELLO", hello_size,
3140               "PING", sizeof (struct TransportPingMessage));
3141 #endif
3142   GNUNET_STATISTICS_update (stats,
3143                             gettext_noop ("# PING messages sent for initial validation"),
3144                             1,
3145                             GNUNET_NO);      
3146   transmit_to_peer (NULL, peer_address,
3147                     GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3148                     HELLO_VERIFICATION_TIMEOUT,
3149                     message_buf, tsize,
3150                     GNUNET_YES, neighbour);
3151   GNUNET_free(message_buf);
3152   return GNUNET_OK;
3153 }
3154
3155
3156 /**
3157  * Check if addresses in validated hello "h" overlap with
3158  * those in "chvc->hello" and validate the rest.
3159  *
3160  * @param cls closure
3161  * @param peer id of the peer, NULL for last call
3162  * @param h hello message for the peer (can be NULL)
3163  * @param trust amount of trust we have in the peer (not used)
3164  */
3165 static void
3166 check_hello_validated (void *cls,
3167                        const struct GNUNET_PeerIdentity *peer,
3168                        const struct GNUNET_HELLO_Message *h, 
3169                        uint32_t trust)
3170 {
3171   struct CheckHelloValidatedContext *chvc = cls;
3172   struct GNUNET_HELLO_Message *plain_hello;
3173   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
3174   struct GNUNET_PeerIdentity target;
3175   struct NeighbourList *n;
3176
3177   if (peer == NULL)
3178     {
3179       chvc->piter = NULL;
3180       GNUNET_CONTAINER_DLL_remove (chvc_head,
3181                                    chvc_tail,
3182                                    chvc);
3183       if (GNUNET_NO == chvc->hello_known)
3184         {
3185           /* notify PEERINFO about the peer now, so that we at least
3186              have the public key if some other component needs it */
3187           GNUNET_HELLO_get_key (chvc->hello, &pk);
3188           GNUNET_CRYPTO_hash (&pk,
3189                               sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3190                               &target.hashPubKey);
3191           plain_hello = GNUNET_HELLO_create (&pk,
3192                                              NULL, 
3193                                              NULL);
3194           GNUNET_PEERINFO_add_peer (cfg, sched, &target, plain_hello);
3195           GNUNET_free (plain_hello);
3196 #if DEBUG_TRANSPORT
3197           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3198                       "Peerinfo had no `%s' message for peer `%4s', full validation needed.\n",
3199                       "HELLO",
3200                       GNUNET_i2s (&target));
3201 #endif
3202           GNUNET_STATISTICS_update (stats,
3203                                     gettext_noop ("# new HELLOs requiring full validation"),
3204                                     1,
3205                                     GNUNET_NO);      
3206           GNUNET_HELLO_iterate_addresses (chvc->hello,
3207                                           GNUNET_NO, 
3208                                           &run_validation, 
3209                                           chvc);
3210         }
3211       else
3212         {
3213           GNUNET_STATISTICS_update (stats,
3214                                     gettext_noop ("# duplicate HELLO (peer known)"),
3215                                     1,
3216                                     GNUNET_NO);      
3217         }
3218       GNUNET_free (chvc);
3219       return;
3220     } 
3221   if (h == NULL)
3222     return;
3223 #if DEBUG_TRANSPORT
3224   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3225               "Peerinfo had `%s' message for peer `%4s', validating only new addresses.\n",
3226               "HELLO",
3227               GNUNET_i2s (peer));
3228 #endif
3229   chvc->hello_known = GNUNET_YES;
3230   n = find_neighbour (peer);
3231   if (n != NULL)
3232     {
3233       GNUNET_HELLO_iterate_addresses (h,
3234                                       GNUNET_NO,
3235                                       &add_to_foreign_address_list,
3236                                       n);
3237       try_transmission_to_peer (n);
3238     }
3239   else
3240     {
3241       GNUNET_STATISTICS_update (stats,
3242                                 gettext_noop ("# no existing neighbour record (validating HELLO)"),
3243                                 1,
3244                                 GNUNET_NO);      
3245     }
3246   GNUNET_STATISTICS_update (stats,
3247                             gettext_noop ("# HELLO validations (update case)"),
3248                             1,
3249                             GNUNET_NO);      
3250   GNUNET_HELLO_iterate_new_addresses (chvc->hello,
3251                                       h,
3252                                       GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME),
3253                                       &run_validation, 
3254                                       chvc);
3255 }
3256
3257 /**
3258  * Process HELLO-message.
3259  *
3260  * @param plugin transport involved, may be NULL
3261  * @param message the actual message
3262  * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
3263  */
3264 static int
3265 process_hello (struct TransportPlugin *plugin,
3266                const struct GNUNET_MessageHeader *message)
3267 {
3268   uint16_t hsize;
3269   struct GNUNET_PeerIdentity target;
3270   const struct GNUNET_HELLO_Message *hello;
3271   struct CheckHelloValidatedContext *chvc;
3272   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
3273
3274   hsize = ntohs (message->size);
3275   if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
3276       (hsize < sizeof (struct GNUNET_MessageHeader)))
3277     {
3278       GNUNET_break (0);
3279       return GNUNET_SYSERR;
3280     }
3281   GNUNET_STATISTICS_update (stats,
3282                             gettext_noop ("# HELLOs received for validation"),
3283                             1,
3284                             GNUNET_NO);      
3285   /* first, check if load is too high */
3286   if (GNUNET_SCHEDULER_get_load (sched,
3287                                  GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
3288     {
3289       GNUNET_STATISTICS_update (stats,
3290                                 gettext_noop ("# HELLOs ignored due to high load"),
3291                                 1,
3292                                 GNUNET_NO);      
3293       return GNUNET_OK;
3294     }
3295   hello = (const struct GNUNET_HELLO_Message *) message;
3296   if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
3297     {
3298       GNUNET_break_op (0);
3299       return GNUNET_SYSERR;
3300     }
3301   GNUNET_CRYPTO_hash (&publicKey,
3302                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3303                       &target.hashPubKey);
3304   if (0 == memcmp (&my_identity,
3305                    &target,
3306                    sizeof (struct GNUNET_PeerIdentity)))
3307     {
3308       GNUNET_STATISTICS_update (stats,
3309                                 gettext_noop ("# HELLOs ignored for validation (is my own HELLO)"),
3310                                 1,
3311                                 GNUNET_NO);      
3312       return GNUNET_OK;      
3313     }
3314 #if DEBUG_TRANSPORT > 1
3315   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3316               "Processing `%s' message for `%4s' of size %u\n",
3317               "HELLO", 
3318               GNUNET_i2s (&target), 
3319               GNUNET_HELLO_size(hello));
3320 #endif
3321   chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
3322   chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
3323   memcpy (&chvc[1], hello, hsize);
3324   GNUNET_CONTAINER_DLL_insert (chvc_head,
3325                                chvc_tail,
3326                                chvc);
3327   /* finally, check if HELLO was previously validated
3328      (continuation will then schedule actual validation) */
3329   chvc->piter = GNUNET_PEERINFO_iterate (cfg,
3330                                          sched,
3331                                          &target,
3332                                          0,
3333                                          HELLO_VERIFICATION_TIMEOUT,
3334                                          &check_hello_validated, chvc);
3335   return GNUNET_OK;
3336 }
3337
3338
3339 /**
3340  * The peer specified by the given neighbour has timed-out or a plugin
3341  * has disconnected.  We may either need to do nothing (other plugins
3342  * still up), or trigger a full disconnect and clean up.  This
3343  * function updates our state and does the necessary notifications.
3344  * Also notifies our clients that the neighbour is now officially
3345  * gone.
3346  *
3347  * @param n the neighbour list entry for the peer
3348  * @param check should we just check if all plugins
3349  *        disconnected or must we ask all plugins to
3350  *        disconnect?
3351  */
3352 static void
3353 disconnect_neighbour (struct NeighbourList *n, int check)
3354 {
3355   struct ReadyList *rpos;
3356   struct NeighbourList *npos;
3357   struct NeighbourList *nprev;
3358   struct MessageQueue *mq;
3359   struct ForeignAddressList *peer_addresses;
3360   struct ForeignAddressList *peer_pos;
3361
3362   if (GNUNET_YES == check)
3363     {
3364       rpos = n->plugins;
3365       while (NULL != rpos)
3366         {
3367           peer_addresses = rpos->addresses;
3368           while (peer_addresses != NULL)
3369             {
3370               if (GNUNET_YES == peer_addresses->connected)
3371                 return;             /* still connected */
3372               peer_addresses = peer_addresses->next;
3373             }
3374           rpos = rpos->next;
3375         }
3376     }
3377 #if DEBUG_TRANSPORT
3378   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
3379               "Disconnecting from `%4s'\n",
3380               GNUNET_i2s (&n->id));
3381 #endif
3382   /* remove n from neighbours list */
3383   nprev = NULL;
3384   npos = neighbours;
3385   while ((npos != NULL) && (npos != n))
3386     {
3387       nprev = npos;
3388       npos = npos->next;
3389     }
3390   GNUNET_assert (npos != NULL);
3391   if (nprev == NULL)
3392     neighbours = n->next;
3393   else
3394     nprev->next = n->next;
3395
3396   /* notify all clients about disconnect */
3397   if (GNUNET_YES == n->received_pong)
3398     notify_clients_disconnect (&n->id);
3399
3400   /* clean up all plugins, cancel connections and pending transmissions */
3401   while (NULL != (rpos = n->plugins))
3402     {
3403       n->plugins = rpos->next;
3404       rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
3405       while (rpos->addresses != NULL)
3406         {
3407           peer_pos = rpos->addresses;
3408           rpos->addresses = peer_pos->next;
3409           if (peer_pos->connected == GNUNET_YES)
3410             GNUNET_STATISTICS_update (stats,
3411                                       gettext_noop ("# connected addresses"),
3412                                       -1,
3413                                       GNUNET_NO); 
3414           if (GNUNET_YES == peer_pos->validated)
3415             GNUNET_STATISTICS_update (stats,
3416                                       gettext_noop ("# peer addresses considered valid"),
3417                                       -1,
3418                                       GNUNET_NO);      
3419           if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
3420             {
3421               GNUNET_SCHEDULER_cancel (sched,
3422                                        peer_pos->revalidate_task);
3423               peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3424             }
3425           GNUNET_free(peer_pos);
3426         }
3427       GNUNET_free (rpos);
3428     }
3429
3430   /* free all messages on the queue */
3431   while (NULL != (mq = n->messages_head))
3432     {
3433       GNUNET_STATISTICS_update (stats,
3434                                 gettext_noop ("# bytes in message queue for other peers"),
3435                                 - (int64_t) mq->message_buf_size,
3436                                 GNUNET_NO);
3437       GNUNET_STATISTICS_update (stats,
3438                                 gettext_noop ("# bytes discarded due to disconnect"),
3439                                 mq->message_buf_size,
3440                                 GNUNET_NO);
3441       GNUNET_CONTAINER_DLL_remove (n->messages_head,
3442                                    n->messages_tail,
3443                                    mq);
3444       GNUNET_assert (0 == memcmp(&mq->neighbour_id, 
3445                                  &n->id,
3446                                  sizeof(struct GNUNET_PeerIdentity)));
3447       GNUNET_free (mq);
3448     }
3449   if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
3450     {
3451       GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
3452       n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
3453     }
3454   if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
3455     {
3456       GNUNET_SCHEDULER_cancel (sched, n->retry_task);
3457       n->retry_task = GNUNET_SCHEDULER_NO_TASK;
3458     }
3459   if (n->piter != NULL)
3460     {
3461       GNUNET_PEERINFO_iterate_cancel (n->piter);
3462       n->piter = NULL;
3463     }
3464   /* finally, free n itself */
3465   GNUNET_STATISTICS_update (stats,
3466                             gettext_noop ("# active neighbours"),
3467                             -1,
3468                             GNUNET_NO);
3469   GNUNET_free_non_null (n->pre_connect_message_buffer);
3470   GNUNET_free (n);
3471 }
3472
3473
3474 /**
3475  * We have received a PING message from someone.  Need to send a PONG message
3476  * in response to the peer by any means necessary. 
3477  */
3478 static int 
3479 handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
3480             const struct GNUNET_PeerIdentity *peer,
3481             const char *sender_address,
3482             size_t sender_address_len)
3483 {
3484   struct TransportPlugin *plugin = cls;
3485   struct TransportPingMessage *ping;
3486   struct TransportPongMessage *pong;
3487   struct NeighbourList *n;
3488   struct ReadyList *rl;
3489   struct ForeignAddressList *fal;
3490
3491   if (ntohs (message->size) != sizeof (struct TransportPingMessage))
3492     {
3493       GNUNET_break_op (0);
3494       return GNUNET_SYSERR;
3495     }
3496
3497   ping = (struct TransportPingMessage *) message;
3498   if (0 != memcmp (&ping->target,
3499                    plugin->env.my_identity,
3500                    sizeof (struct GNUNET_PeerIdentity)))
3501     {
3502       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3503                   _("Received `%s' message not destined for me!\n"), 
3504                   "PING");
3505       return GNUNET_SYSERR;
3506     }
3507 #if DEBUG_PING_PONG
3508   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
3509               "Processing `%s' from `%s'\n",
3510               "PING", 
3511               (sender_address != NULL) 
3512               ? GNUNET_a2s ((const struct sockaddr *)sender_address, 
3513                             sender_address_len)
3514               : "<inbound>");
3515 #endif
3516   GNUNET_STATISTICS_update (stats,
3517                             gettext_noop ("# PING messages received"),
3518                             1,
3519                             GNUNET_NO);
3520   pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len);
3521   pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len);
3522   pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
3523   pong->purpose.size =
3524     htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
3525            sizeof (uint32_t) +
3526            sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + sender_address_len);
3527   pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PING);
3528   pong->challenge = ping->challenge;
3529   pong->addrlen = htons(sender_address_len);
3530   memcpy(&pong->signer, 
3531          &my_public_key, 
3532          sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3533   if (sender_address != NULL)
3534     memcpy (&pong[1], sender_address, sender_address_len);
3535   GNUNET_assert (GNUNET_OK ==
3536                  GNUNET_CRYPTO_rsa_sign (my_private_key,
3537                                          &pong->purpose, &pong->signature));
3538   n = find_neighbour(peer);
3539   GNUNET_assert (n != NULL);
3540   /* first try reliable response transmission */
3541   rl = n->plugins;
3542   while (rl != NULL)
3543     {
3544       fal = rl->addresses;
3545       while (fal != NULL)
3546         {
3547           if (-1 != rl->plugin->api->send (rl->plugin->api->cls,
3548                                            peer,
3549                                            (const char*) pong,
3550                                            ntohs (pong->header.size),
3551                                            TRANSPORT_PONG_PRIORITY, 
3552                                            HELLO_VERIFICATION_TIMEOUT,
3553                                            fal->session,
3554                                            fal->addr,
3555                                            fal->addrlen,
3556                                            GNUNET_SYSERR,
3557                                            NULL, NULL))
3558             {
3559               /* done! */
3560               GNUNET_STATISTICS_update (stats,
3561                                         gettext_noop ("# PONGs unicast via reliable transport"),
3562                                         1,
3563                                         GNUNET_NO);      
3564               GNUNET_free (pong);
3565               return GNUNET_OK;
3566             }
3567           fal = fal->next;
3568         }
3569       rl = rl->next;
3570     }
3571   /* no reliable method found, do multicast */
3572   GNUNET_STATISTICS_update (stats,
3573                             gettext_noop ("# PONGs multicast to all available addresses"),
3574                             1,
3575                             GNUNET_NO);      
3576   rl = n->plugins;
3577   while (rl != NULL)
3578     {
3579       fal = rl->addresses;
3580       while (fal != NULL)
3581         {
3582           transmit_to_peer(NULL, fal,
3583                            TRANSPORT_PONG_PRIORITY, 
3584                            HELLO_VERIFICATION_TIMEOUT,
3585                            (const char *)pong, 
3586                            ntohs(pong->header.size), 
3587                            GNUNET_YES, 
3588                            n);
3589           fal = fal->next;
3590         }
3591       rl = rl->next;
3592     }
3593   GNUNET_free(pong);
3594   return GNUNET_OK;
3595 }
3596
3597
3598 /**
3599  * Function called by the plugin for each received message.
3600  * Update data volumes, possibly notify plugins about
3601  * reducing the rate at which they read from the socket
3602  * and generally forward to our receive callback.
3603  *
3604  * @param cls the "struct TransportPlugin *" we gave to the plugin
3605  * @param peer (claimed) identity of the other peer
3606  * @param message the message, NULL if we only care about
3607  *                learning about the delay until we should receive again
3608  * @param distance in overlay hops; use 1 unless DV (or 0 if message == NULL)
3609  * @param session identifier used for this session (can be NULL)
3610  * @param sender_address binary address of the sender (if observed)
3611  * @param sender_address_len number of bytes in sender_address
3612  * @return how long the plugin should wait until receiving more data
3613  *         (plugins that do not support this, can ignore the return value)
3614  */
3615 static struct GNUNET_TIME_Relative
3616 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
3617                     const struct GNUNET_MessageHeader *message,
3618                     unsigned int distance,
3619                     struct Session *session,
3620                     const char *sender_address,
3621                     size_t sender_address_len)
3622 {
3623   struct TransportPlugin *plugin = cls;
3624   struct ReadyList *service_context;
3625   struct ForeignAddressList *peer_address;
3626   uint16_t msize;
3627   struct NeighbourList *n;
3628   struct GNUNET_TIME_Relative ret;
3629
3630   if (is_blacklisted(peer, plugin))
3631     return GNUNET_TIME_UNIT_FOREVER_REL;
3632
3633   n = find_neighbour (peer);
3634   if (n == NULL)
3635     n = setup_new_neighbour (peer);
3636   service_context = n->plugins;
3637   while ((service_context != NULL) && (plugin != service_context->plugin))
3638     service_context = service_context->next;
3639   GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
3640   peer_address = NULL;
3641   if (message != NULL)
3642     {
3643       if ( (session != NULL) ||
3644            (sender_address != NULL) )
3645         peer_address = add_peer_address (n, 
3646                                          plugin->short_name,
3647                                          session,
3648                                          sender_address, 
3649                                          sender_address_len);  
3650       if (peer_address != NULL)
3651         {
3652           peer_address->distance = distance;
3653           if (GNUNET_YES == peer_address->validated)
3654             mark_address_connected (peer_address);
3655           peer_address->timeout
3656             =
3657             GNUNET_TIME_relative_to_absolute
3658             (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3659           schedule_next_ping (peer_address);
3660         }
3661       /* update traffic received amount ... */
3662       msize = ntohs (message->size);      
3663       GNUNET_STATISTICS_update (stats,
3664                                 gettext_noop ("# bytes received from other peers"),
3665                                 msize,
3666                                 GNUNET_NO);
3667       n->distance = distance;
3668       n->peer_timeout =
3669         GNUNET_TIME_relative_to_absolute
3670         (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3671       GNUNET_SCHEDULER_cancel (sched,
3672                                n->timeout_task);
3673       n->timeout_task =
3674         GNUNET_SCHEDULER_add_delayed (sched,
3675                                       GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
3676                                       &neighbour_timeout_task, n);
3677       if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
3678         {
3679           /* dropping message due to frequent inbound volume violations! */
3680           GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
3681                       GNUNET_ERROR_TYPE_BULK,
3682                       _
3683                       ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"), 
3684                       n->in_tracker.available_bytes_per_s__,
3685                       n->quota_violation_count);
3686           GNUNET_STATISTICS_update (stats,
3687                                     gettext_noop ("# bandwidth quota violations by other peers"),
3688                                     1,
3689                                     GNUNET_NO);
3690           return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
3691         }
3692 #if DEBUG_PING_PONG
3693           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3694                       "Received message of type %u from `%4s', sending to all clients.\n",
3695                       ntohs (message->type), GNUNET_i2s (peer));
3696 #endif
3697       switch (ntohs (message->type))
3698         {
3699         case GNUNET_MESSAGE_TYPE_HELLO:
3700           GNUNET_STATISTICS_update (stats,
3701                                     gettext_noop ("# HELLO messages received from other peers"),
3702                                     1,
3703                                     GNUNET_NO);
3704           process_hello (plugin, message);
3705           break;
3706         case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
3707           handle_ping (plugin, message, peer, sender_address, sender_address_len);
3708           break;
3709         case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
3710           handle_pong (plugin, message, peer, sender_address, sender_address_len);
3711           break;
3712         default:
3713           handle_payload_message (message, n);
3714           break;
3715         }
3716     }  
3717   ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
3718   if (ret.value > 0)
3719     {
3720       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3721                   "Throttling read (%llu bytes excess at %u b/s), waiting %llums before reading more.\n",
3722                   (unsigned long long) n->in_tracker.consumption_since_last_update__,
3723                   (unsigned int) n->in_tracker.available_bytes_per_s__,
3724                   (unsigned long long) ret.value);
3725       GNUNET_STATISTICS_update (stats,
3726                                 gettext_noop ("# ms throttling suggested"),
3727                                 (int64_t) ret.value,
3728                                 GNUNET_NO);      
3729     }
3730   return ret;
3731 }
3732
3733 /**
3734  * Handle START-message.  This is the first message sent to us
3735  * by any client which causes us to add it to our list.
3736  *
3737  * @param cls closure (always NULL)
3738  * @param client identification of the client
3739  * @param message the actual message
3740  */
3741 static void
3742 handle_start (void *cls,
3743               struct GNUNET_SERVER_Client *client,
3744               const struct GNUNET_MessageHeader *message)
3745 {
3746   struct TransportClient *c;
3747   struct ConnectInfoMessage cim;
3748   struct NeighbourList *n;
3749
3750 #if DEBUG_TRANSPORT
3751   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3752               "Received `%s' request from client\n", "START");
3753 #endif
3754   c = clients;
3755   while (c != NULL)
3756     {
3757       if (c->client == client)
3758         {
3759           /* client already on our list! */
3760           GNUNET_break (0);
3761           GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3762           return;
3763         }
3764       c = c->next;
3765     }
3766   c = GNUNET_malloc (sizeof (struct TransportClient));
3767   c->next = clients;
3768   clients = c;
3769   c->client = client;
3770   if (our_hello != NULL)
3771     {
3772 #if DEBUG_TRANSPORT
3773       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3774                   "Sending our own `%s' to new client\n", "HELLO");
3775 #endif
3776       transmit_to_client (c,
3777                           (const struct GNUNET_MessageHeader *) our_hello,
3778                           GNUNET_NO);
3779       /* tell new client about all existing connections */
3780       cim.header.size = htons (sizeof (struct ConnectInfoMessage));
3781       cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
3782       n = neighbours; 
3783       while (n != NULL)
3784         {
3785           if (GNUNET_YES == n->received_pong)
3786             {
3787               cim.id = n->id;
3788               cim.latency = GNUNET_TIME_relative_hton (n->latency);
3789               cim.distance = htonl (n->distance);
3790               transmit_to_client (c, &cim.header, GNUNET_NO);
3791             }
3792             n = n->next;
3793         }
3794     }
3795   GNUNET_SERVER_receive_done (client, GNUNET_OK);
3796 }
3797
3798
3799 /**
3800  * Handle HELLO-message.
3801  *
3802  * @param cls closure (always NULL)
3803  * @param client identification of the client
3804  * @param message the actual message
3805  */
3806 static void
3807 handle_hello (void *cls,
3808               struct GNUNET_SERVER_Client *client,
3809               const struct GNUNET_MessageHeader *message)
3810 {
3811   int ret;
3812
3813   GNUNET_STATISTICS_update (stats,
3814                             gettext_noop ("# HELLOs received from clients"),
3815                             1,
3816                             GNUNET_NO);      
3817   ret = process_hello (NULL, message);
3818   GNUNET_SERVER_receive_done (client, ret);
3819 }
3820
3821
3822 /**
3823  * Handle SEND-message.
3824  *
3825  * @param cls closure (always NULL)
3826  * @param client identification of the client
3827  * @param message the actual message
3828  */
3829 static void
3830 handle_send (void *cls,
3831              struct GNUNET_SERVER_Client *client,
3832              const struct GNUNET_MessageHeader *message)
3833 {
3834   struct TransportClient *tc;
3835   struct NeighbourList *n;
3836   const struct OutboundMessage *obm;
3837   const struct GNUNET_MessageHeader *obmm;
3838   uint16_t size;
3839   uint16_t msize;
3840
3841   size = ntohs (message->size);
3842   if (size <
3843       sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
3844     {
3845       GNUNET_break (0);
3846       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3847       return;
3848     }
3849   GNUNET_STATISTICS_update (stats,
3850                             gettext_noop ("# payload received for other peers"),
3851                             size,
3852                             GNUNET_NO);      
3853   obm = (const struct OutboundMessage *) message;
3854 #if DEBUG_TRANSPORT
3855   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3856               "Received `%s' request from client with target `%4s'\n",
3857               "SEND", GNUNET_i2s (&obm->peer));
3858 #endif
3859   obmm = (const struct GNUNET_MessageHeader *) &obm[1];
3860   msize = ntohs (obmm->size);
3861   if (size != msize + sizeof (struct OutboundMessage))
3862     {
3863       GNUNET_break (0);
3864       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3865       return;
3866     }
3867   n = find_neighbour (&obm->peer);
3868   if (n == NULL)
3869     n = setup_new_neighbour (&obm->peer);
3870   tc = clients;
3871   while ((tc != NULL) && (tc->client != client))
3872     tc = tc->next;
3873
3874 #if DEBUG_TRANSPORT
3875   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3876               "Client asked to transmit %u-byte message of type %u to `%4s'\n",
3877               ntohs (obmm->size),
3878               ntohs (obmm->type), GNUNET_i2s (&obm->peer));
3879 #endif
3880   transmit_to_peer (tc, NULL, ntohl (obm->priority), 
3881                     GNUNET_TIME_relative_ntoh (obm->timeout),
3882                     (char *)obmm, 
3883                     ntohs (obmm->size), GNUNET_NO, n);
3884   GNUNET_SERVER_receive_done (client, GNUNET_OK);
3885 }
3886
3887
3888 /**
3889  * Handle SET_QUOTA-message.
3890  *
3891  * @param cls closure (always NULL)
3892  * @param client identification of the client
3893  * @param message the actual message
3894  */
3895 static void
3896 handle_set_quota (void *cls,
3897                   struct GNUNET_SERVER_Client *client,
3898                   const struct GNUNET_MessageHeader *message)
3899 {
3900   const struct QuotaSetMessage *qsm =
3901     (const struct QuotaSetMessage *) message;
3902   struct NeighbourList *n;
3903   
3904   GNUNET_STATISTICS_update (stats,
3905                             gettext_noop ("# SET QUOTA messages received"),
3906                             1,
3907                             GNUNET_NO);      
3908   n = find_neighbour (&qsm->peer);
3909   if (n == NULL)
3910     {
3911       GNUNET_SERVER_receive_done (client, GNUNET_OK);
3912       GNUNET_STATISTICS_update (stats,
3913                                 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
3914                                 1,
3915                                 GNUNET_NO);      
3916       return;
3917     }
3918 #if DEBUG_TRANSPORT
3919   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3920               "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
3921               "SET_QUOTA", 
3922               (unsigned int) ntohl (qsm->quota.value__),
3923               (unsigned int) n->in_tracker.available_bytes_per_s__,
3924               GNUNET_i2s (&qsm->peer));
3925 #endif
3926   GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
3927                                          qsm->quota);
3928   if (0 == ntohl (qsm->quota.value__)) 
3929     disconnect_neighbour (n, GNUNET_NO);    
3930   GNUNET_SERVER_receive_done (client, GNUNET_OK);
3931 }
3932
3933
3934 /**
3935  * Take the given address and append it to the set of results send back to
3936  * the client.
3937  * 
3938  * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
3939  * @param address the resolved name, NULL to indicate the last response
3940  */
3941 static void
3942 transmit_address_to_client (void *cls, const char *address)
3943 {
3944   struct GNUNET_SERVER_TransmitContext *tc = cls;
3945   size_t slen;
3946
3947   if (NULL == address)
3948     slen = 0;
3949   else
3950     slen = strlen (address) + 1;
3951   GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
3952                                               GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
3953   if (NULL == address)
3954     GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
3955 }
3956
3957
3958 /**
3959  * Handle AddressLookup-message.
3960  *
3961  * @param cls closure (always NULL)
3962  * @param client identification of the client
3963  * @param message the actual message
3964  */
3965 static void
3966 handle_address_lookup (void *cls,
3967                        struct GNUNET_SERVER_Client *client,
3968                        const struct GNUNET_MessageHeader *message)
3969 {
3970   const struct AddressLookupMessage *alum;
3971   struct TransportPlugin *lsPlugin;
3972   const char *nameTransport;
3973   const char *address;
3974   uint16_t size;
3975   struct GNUNET_SERVER_TransmitContext *tc;
3976   struct GNUNET_TIME_Absolute timeout;
3977   struct GNUNET_TIME_Relative rtimeout;
3978   int32_t numeric;
3979
3980   size = ntohs (message->size);
3981   if (size < sizeof (struct AddressLookupMessage))
3982     {
3983       GNUNET_break_op (0);
3984       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3985       return;
3986     }
3987   alum = (const struct AddressLookupMessage *) message;
3988   uint32_t addressLen = ntohl (alum->addrlen);
3989   if (size <= sizeof (struct AddressLookupMessage) + addressLen)
3990     {
3991       GNUNET_break_op (0);
3992       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3993       return;
3994     }
3995   address = (const char *) &alum[1];
3996   nameTransport = (const char *) &address[addressLen];
3997   if (nameTransport
3998       [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
3999     {
4000       GNUNET_break_op (0);
4001       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
4002       return;
4003     }
4004   timeout = GNUNET_TIME_absolute_ntoh (alum->timeout);
4005   rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
4006   numeric = ntohl (alum->numeric_only);
4007   lsPlugin = find_transport (nameTransport);
4008   if (NULL == lsPlugin)
4009     {
4010       tc = GNUNET_SERVER_transmit_context_create (client);
4011       GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
4012                                                   GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
4013       GNUNET_SERVER_transmit_context_run (tc, rtimeout);
4014       return;
4015     }
4016   tc = GNUNET_SERVER_transmit_context_create (client);
4017   lsPlugin->api->address_pretty_printer (lsPlugin->api->cls,
4018                                          nameTransport,
4019                                          address, addressLen, 
4020                                          numeric,
4021                                          rtimeout,
4022                                          &transmit_address_to_client, tc);
4023 }
4024
4025 /**
4026  * List of handlers for the messages understood by this
4027  * service.
4028  */
4029 static struct GNUNET_SERVER_MessageHandler handlers[] = {
4030   {&handle_start, NULL,
4031    GNUNET_MESSAGE_TYPE_TRANSPORT_START, 0},
4032   {&handle_hello, NULL,
4033    GNUNET_MESSAGE_TYPE_HELLO, 0},
4034   {&handle_send, NULL,
4035    GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
4036   {&handle_set_quota, NULL,
4037    GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
4038   {&handle_address_lookup, NULL,
4039    GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
4040    0},
4041   {NULL, NULL, 0, 0}
4042 };
4043
4044
4045 /**
4046  * Setup the environment for this plugin.
4047  */
4048 static void
4049 create_environment (struct TransportPlugin *plug)
4050 {
4051   plug->env.cfg = cfg;
4052   plug->env.sched = sched;
4053   plug->env.my_identity = &my_identity;
4054   plug->env.cls = plug;
4055   plug->env.receive = &plugin_env_receive;
4056   plug->env.notify_address = &plugin_env_notify_address;
4057   plug->env.session_end = &plugin_env_session_end;
4058   plug->env.max_connections = max_connect_per_transport;
4059   plug->env.stats = stats;
4060 }
4061
4062
4063 /**
4064  * Start the specified transport (load the plugin).
4065  */
4066 static void
4067 start_transport (struct GNUNET_SERVER_Handle *server, 
4068                  const char *name)
4069 {
4070   struct TransportPlugin *plug;
4071   char *libname;
4072
4073   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4074               _("Loading `%s' transport plugin\n"), name);
4075   GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
4076   plug = GNUNET_malloc (sizeof (struct TransportPlugin));
4077   create_environment (plug);
4078   plug->short_name = GNUNET_strdup (name);
4079   plug->lib_name = libname;
4080   plug->next = plugins;
4081   plugins = plug;
4082   plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
4083   if (plug->api == NULL)
4084     {
4085       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4086                   _("Failed to load transport plugin for `%s'\n"), name);
4087       GNUNET_free (plug->short_name);
4088       plugins = plug->next;
4089       GNUNET_free (libname);
4090       GNUNET_free (plug);
4091     }
4092 }
4093
4094
4095 /**
4096  * Called whenever a client is disconnected.  Frees our
4097  * resources associated with that client.
4098  *
4099  * @param cls closure
4100  * @param client identification of the client
4101  */
4102 static void
4103 client_disconnect_notification (void *cls,
4104                                 struct GNUNET_SERVER_Client *client)
4105 {
4106   struct TransportClient *pos;
4107   struct TransportClient *prev;
4108   struct ClientMessageQueueEntry *mqe;
4109
4110   if (client == NULL)
4111     return;
4112 #if DEBUG_TRANSPORT
4113   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4114               "Client disconnected, cleaning up.\n");
4115 #endif
4116   prev = NULL;
4117   pos = clients;
4118   while ((pos != NULL) && (pos->client != client))
4119     {
4120       prev = pos;
4121       pos = pos->next;
4122     }
4123   if (pos == NULL)
4124     return;
4125   while (NULL != (mqe = pos->message_queue_head))
4126     {
4127       GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
4128                                    pos->message_queue_tail,
4129                                    mqe);
4130       pos->message_count--;
4131       GNUNET_free (mqe);
4132     }
4133   if (prev == NULL)
4134     clients = pos->next;
4135   else
4136     prev->next = pos->next;
4137   if (GNUNET_YES == pos->tcs_pending)
4138     {
4139       pos->client = NULL;
4140       return;
4141     }
4142   if (pos->th != NULL)
4143     {
4144       GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
4145       pos->th = NULL;
4146     }
4147   GNUNET_break (0 == pos->message_count);
4148   GNUNET_free (pos);
4149 }
4150
4151
4152 /**
4153  * Iterator to free entries in the validation_map.
4154  *
4155  * @param cls closure (unused)
4156  * @param key current key code
4157  * @param value value in the hash map (validation to abort)
4158  * @return GNUNET_YES (always)
4159  */
4160 static int 
4161 abort_validation (void *cls,
4162                   const GNUNET_HashCode * key,
4163                   void *value)
4164 {
4165   struct ValidationEntry *va = value;
4166
4167   GNUNET_SCHEDULER_cancel (sched, va->timeout_task);
4168   GNUNET_free (va->transport_name);
4169   GNUNET_free (va);
4170   return GNUNET_YES;
4171 }
4172
4173
4174 /**
4175  * Function called when the service shuts down.  Unloads our plugins
4176  * and cancels pending validations.
4177  *
4178  * @param cls closure, unused
4179  * @param tc task context (unused)
4180  */
4181 static void
4182 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
4183 {
4184   struct TransportPlugin *plug;
4185   struct OwnAddressList *al;
4186   struct CheckHelloValidatedContext *chvc;
4187
4188   while (neighbours != NULL)
4189     disconnect_neighbour (neighbours, GNUNET_NO);
4190 #if DEBUG_TRANSPORT
4191   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4192               "Transport service is unloading plugins...\n");
4193 #endif
4194   while (NULL != (plug = plugins))
4195     {
4196       plugins = plug->next;
4197       if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
4198         {
4199           GNUNET_SCHEDULER_cancel (plug->env.sched, 
4200                                    plug->address_update_task);
4201           plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
4202         }
4203       GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
4204       GNUNET_free (plug->lib_name);
4205       GNUNET_free (plug->short_name);
4206       while (NULL != (al = plug->addresses))
4207         {
4208           plug->addresses = al->next;
4209           GNUNET_free (al);
4210         }
4211       GNUNET_free (plug);
4212     }
4213   if (my_private_key != NULL)
4214     GNUNET_CRYPTO_rsa_key_free (my_private_key);
4215   GNUNET_free_non_null (our_hello);
4216
4217   /* free 'chvc' data structure */
4218   while (NULL != (chvc = chvc_head))
4219     {
4220       chvc_head = chvc->next;
4221       GNUNET_PEERINFO_iterate_cancel (chvc->piter);
4222       GNUNET_free (chvc);
4223     }
4224   chvc_tail = NULL;
4225
4226   GNUNET_CONTAINER_multihashmap_iterate (validation_map,
4227                                          &abort_validation,
4228                                          NULL);
4229   GNUNET_CONTAINER_multihashmap_destroy (validation_map);
4230   validation_map = NULL;
4231   if (stats != NULL)
4232     {
4233       GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
4234       stats = NULL;
4235     }
4236 }
4237
4238
4239 /**
4240  * Initiate transport service.
4241  *
4242  * @param cls closure
4243  * @param s scheduler to use
4244  * @param serv the initialized server
4245  * @param c configuration to use
4246  */
4247 static void
4248 run (void *cls,
4249      struct GNUNET_SCHEDULER_Handle *s,
4250      struct GNUNET_SERVER_Handle *serv,
4251      const struct GNUNET_CONFIGURATION_Handle *c)
4252 {
4253   char *plugs;
4254   char *pos;
4255   int no_transports;
4256   unsigned long long tneigh;
4257   char *keyfile;
4258
4259   sched = s;
4260   cfg = c;
4261   stats = GNUNET_STATISTICS_create (sched, "transport", cfg);
4262   validation_map = GNUNET_CONTAINER_multihashmap_create (64);
4263   /* parse configuration */
4264   if ((GNUNET_OK !=
4265        GNUNET_CONFIGURATION_get_value_number (c,
4266                                               "TRANSPORT",
4267                                               "NEIGHBOUR_LIMIT",
4268                                               &tneigh)) ||
4269       (GNUNET_OK !=
4270        GNUNET_CONFIGURATION_get_value_filename (c,
4271                                                 "GNUNETD",
4272                                                 "HOSTKEY", &keyfile)))
4273     {
4274       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4275                   _
4276                   ("Transport service is lacking key configuration settings.  Exiting.\n"));
4277       GNUNET_SCHEDULER_shutdown (s);
4278       if (stats != NULL)
4279         {
4280           GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
4281           stats = NULL;
4282         }
4283       GNUNET_CONTAINER_multihashmap_destroy (validation_map);
4284       validation_map = NULL;
4285       return;
4286     }
4287   max_connect_per_transport = (uint32_t) tneigh;
4288   my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
4289   GNUNET_free (keyfile);
4290   if (my_private_key == NULL)
4291     {
4292       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4293                   _
4294                   ("Transport service could not access hostkey.  Exiting.\n"));
4295       GNUNET_SCHEDULER_shutdown (s);
4296       if (stats != NULL)
4297         {
4298           GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
4299           stats = NULL;
4300         }
4301       GNUNET_CONTAINER_multihashmap_destroy (validation_map);
4302       validation_map = NULL;
4303       return;
4304     }
4305   GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
4306   GNUNET_CRYPTO_hash (&my_public_key,
4307                       sizeof (my_public_key), &my_identity.hashPubKey);
4308   /* setup notification */
4309   server = serv;
4310   GNUNET_SERVER_disconnect_notify (server,
4311                                    &client_disconnect_notification, NULL);
4312   /* load plugins... */
4313   no_transports = 1;
4314   if (GNUNET_OK ==
4315       GNUNET_CONFIGURATION_get_value_string (c,
4316                                              "TRANSPORT", "PLUGINS", &plugs))
4317     {
4318       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4319                   _("Starting transport plugins `%s'\n"), plugs);
4320       pos = strtok (plugs, " ");
4321       while (pos != NULL)
4322         {
4323           start_transport (server, pos);
4324           no_transports = 0;
4325           pos = strtok (NULL, " ");
4326         }
4327       GNUNET_free (plugs);
4328     }
4329   GNUNET_SCHEDULER_add_delayed (sched,
4330                                 GNUNET_TIME_UNIT_FOREVER_REL,
4331                                 &shutdown_task, NULL);
4332   if (no_transports)
4333     refresh_hello ();
4334
4335 #if DEBUG_TRANSPORT
4336   GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
4337 #endif
4338   /* If we have a blacklist file, read from it */
4339   read_blacklist_file(cfg);
4340   /* process client requests */
4341   GNUNET_SERVER_add_handlers (server, handlers);
4342 }
4343
4344
4345 /**
4346  * The main function for the transport service.
4347  *
4348  * @param argc number of arguments from the command line
4349  * @param argv command line arguments
4350  * @return 0 ok, 1 on error
4351  */
4352 int
4353 main (int argc, char *const *argv)
4354 {
4355   return (GNUNET_OK ==
4356           GNUNET_SERVICE_run (argc,
4357                               argv,
4358                               "transport",
4359                               GNUNET_SERVICE_OPTION_NONE,
4360                               &run, NULL)) ? 0 : 1;
4361 }
4362
4363 /* end of gnunet-service-transport.c */