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