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