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