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