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