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