stuff
[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 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 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.
1934  *
1935  * @param peer the peer for which we create the entry
1936  * @return the new neighbour list entry
1937  */
1938 static struct NeighbourList *
1939 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer)
1940 {
1941   struct NeighbourList *n;
1942   struct TransportPlugin *tp;
1943   struct ReadyList *rl;
1944
1945   GNUNET_assert (our_hello != NULL);
1946   GNUNET_STATISTICS_update (stats,
1947                             gettext_noop ("# active neighbours"),
1948                             1,
1949                             GNUNET_NO);
1950   n = GNUNET_malloc (sizeof (struct NeighbourList));
1951   n->next = neighbours;
1952   neighbours = n;
1953   n->id = *peer;
1954   n->peer_timeout =
1955     GNUNET_TIME_relative_to_absolute
1956     (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1957   GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
1958                                  GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
1959                                  MAX_BANDWIDTH_CARRY_S);
1960   tp = plugins;
1961   while (tp != NULL)
1962     {
1963       if (tp->api->send != NULL)
1964         {
1965           rl = GNUNET_malloc (sizeof (struct ReadyList));
1966           rl->next = n->plugins;
1967           n->plugins = rl;
1968           rl->plugin = tp;
1969           rl->addresses = NULL;
1970         }
1971       tp = tp->next;
1972     }
1973   n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
1974   n->distance = -1;
1975   n->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
1976                                                   GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1977                                                   &neighbour_timeout_task, n);
1978   // FIXME: query PEERINFO for HELLO for this peer & 
1979   // add addresses!?
1980   transmit_to_peer (NULL, NULL, 0,
1981                     HELLO_ADDRESS_EXPIRATION,
1982                     (const char *) our_hello, GNUNET_HELLO_size(our_hello),
1983                     GNUNET_NO, n);
1984   return n;
1985 }
1986
1987
1988 /**
1989  * Send periodic PING messages to a give foreign address.
1990  *
1991  * @param cls our 'struct PeriodicValidationContext*'
1992  * @param tc task context
1993  */
1994 static void 
1995 send_periodic_ping (void *cls, 
1996                     const struct GNUNET_SCHEDULER_TaskContext *tc)
1997 {
1998   struct PeriodicValidationContext *pvc = cls;
1999   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey = pvc->publicKey;
2000   char *tname = pvc->transport;
2001   const void *addr = pvc->foreign_address->addr;
2002   size_t addrlen = pvc->foreign_address->addrlen;
2003   struct GNUNET_PeerIdentity id;
2004   struct TransportPlugin *tp;
2005   struct ValidationEntry *va;
2006   struct NeighbourList *neighbour;
2007   struct ForeignAddressList *peer_address;
2008   struct TransportPingMessage ping;
2009   struct CheckAddressExistsClosure caec;
2010   char * message_buf;
2011   uint16_t hello_size;
2012   size_t tsize;
2013
2014   GNUNET_free (pvc);
2015   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
2016     {
2017       /* We have been shutdown, don't do anything! */
2018       GNUNET_free (tname);
2019       return; 
2020     }
2021   tp = find_transport (tname);
2022   if (tp == NULL)
2023     {
2024       GNUNET_log (GNUNET_ERROR_TYPE_INFO |
2025                   GNUNET_ERROR_TYPE_BULK,
2026                   _
2027                   ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
2028                   tname);
2029       GNUNET_free (tname);
2030       return;
2031     }
2032
2033   GNUNET_CRYPTO_hash (&publicKey,
2034                       sizeof (struct
2035                               GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2036                       &id.hashPubKey);
2037   caec.addr = addr;
2038   caec.addrlen = addrlen;
2039   caec.tname = tname;
2040   caec.exists = GNUNET_NO;
2041   GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2042                                          &check_address_exists,
2043                                          &caec);
2044   if (caec.exists == GNUNET_YES)
2045     {
2046       /* During validation attempts we will likely trigger the other
2047          peer trying to validate our address which in turn will cause
2048          it to send us its HELLO, so we expect to hit this case rather
2049          frequently.  Only print something if we are very verbose. */
2050 #if DEBUG_TRANSPORT > 1
2051       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2052                   "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
2053                   GNUNET_a2s (addr, addrlen),
2054                   tname,
2055                   GNUNET_i2s (&id));
2056 #endif
2057       GNUNET_free (tname);
2058       return;
2059     }
2060   va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
2061   va->transport_name = tname;
2062   va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2063                                             (unsigned int) -1);
2064   va->send_time = GNUNET_TIME_absolute_get();
2065   va->addr = (const void*) &va[1];
2066   memcpy (&va[1], addr, addrlen);
2067   va->addrlen = addrlen;
2068   memcpy(&va->publicKey, &publicKey, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
2069   va->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
2070                                                    HELLO_VERIFICATION_TIMEOUT,
2071                                                    &timeout_hello_validation,
2072                                                    va);
2073   GNUNET_CONTAINER_multihashmap_put (validation_map,
2074                                      &id.hashPubKey,
2075                                      va,
2076                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2077   neighbour = find_neighbour(&id);
2078   /* FIXME: can neighbour be NULL here? (why do we still PING?)?  If so,
2079      should we even do this? */
2080   if (neighbour == NULL)
2081     neighbour = setup_new_neighbour(&id);
2082   peer_address = add_peer_address(neighbour, tname, addr, addrlen);
2083   GNUNET_assert(peer_address != NULL);
2084   hello_size = GNUNET_HELLO_size(our_hello);
2085   tsize = sizeof(struct TransportPingMessage) + hello_size;
2086   message_buf = GNUNET_malloc(tsize);
2087   ping.challenge = htonl(va->challenge);
2088   ping.header.size = htons(sizeof(struct TransportPingMessage));
2089   ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
2090   memcpy(&ping.target, &id, sizeof(struct GNUNET_PeerIdentity));
2091   memcpy(message_buf, our_hello, hello_size);
2092   memcpy(&message_buf[hello_size],
2093          &ping,
2094          sizeof(struct TransportPingMessage));
2095 #if DEBUG_TRANSPORT_REVALIDATION
2096   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2097               "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
2098               GNUNET_a2s (addr, addrlen),
2099               tname,
2100               GNUNET_i2s (&id),
2101               "HELLO", hello_size,
2102               "PING", sizeof (struct TransportPingMessage));
2103 #endif
2104   GNUNET_STATISTICS_update (stats,
2105                             gettext_noop ("# PING messages sent for re-validation"),
2106                             1,
2107                             GNUNET_NO);
2108   transmit_to_peer (NULL, peer_address,
2109                     GNUNET_SCHEDULER_PRIORITY_DEFAULT,
2110                     HELLO_VERIFICATION_TIMEOUT,
2111                     message_buf, tsize,
2112                     GNUNET_YES, neighbour);
2113   GNUNET_free(message_buf);
2114 }
2115
2116
2117 /**
2118  * Iterator over hash map entries.  Checks if the given validation
2119  * entry is for the same challenge as what is given in the PONG.
2120  *
2121  * @param cls the 'struct TransportPongMessage*'
2122  * @param key peer identity
2123  * @param value value in the hash map ('struct ValidationEntry')
2124  * @return GNUNET_YES if we should continue to
2125  *         iterate (mismatch), GNUNET_NO if not (entry matched)
2126  */
2127 static int
2128 check_pending_validation (void *cls,
2129                           const GNUNET_HashCode * key,
2130                           void *value)
2131 {
2132   const struct TransportPongMessage *pong = cls;
2133   struct ValidationEntry *ve = value;
2134   struct AddValidatedAddressContext avac;
2135   unsigned int challenge = ntohl(pong->challenge);
2136   struct GNUNET_HELLO_Message *hello;
2137   struct GNUNET_PeerIdentity target;
2138   struct NeighbourList *n;
2139   struct ForeignAddressList *fal;
2140   struct PeriodicValidationContext *periodic_validation_context;
2141
2142   if (ve->challenge != challenge)
2143     return GNUNET_YES;
2144
2145 #if DEBUG_TRANSPORT
2146   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2147               "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
2148               GNUNET_h2s (key),
2149               GNUNET_a2s ((const struct sockaddr *) ve->addr,
2150                           ve->addrlen),
2151               ve->transport_name);
2152 #endif
2153   GNUNET_STATISTICS_update (stats,
2154                             gettext_noop ("# address validation successes"),
2155                             1,
2156                             GNUNET_NO);
2157   /* create the updated HELLO */
2158   GNUNET_CRYPTO_hash (&ve->publicKey,
2159                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2160                       &target.hashPubKey);
2161   avac.done = GNUNET_NO;
2162   avac.ve = ve;
2163   hello = GNUNET_HELLO_create (&ve->publicKey,
2164                                &add_validated_address,
2165                                &avac);
2166   GNUNET_PEERINFO_add_peer (cfg, sched,
2167                             &target,
2168                             hello);
2169   GNUNET_free (hello);
2170   n = find_neighbour (&target);
2171   if (n != NULL)
2172     {
2173       fal = add_peer_address (n,
2174                               ve->transport_name,
2175                               ve->addr,
2176                               ve->addrlen);
2177       GNUNET_assert (fal != NULL);
2178       fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
2179       fal->validated = GNUNET_YES;
2180       GNUNET_STATISTICS_update (stats,
2181                                 gettext_noop ("# peer addresses considered valid"),
2182                                 1,
2183                                 GNUNET_NO);      
2184       fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
2185       periodic_validation_context = GNUNET_malloc(sizeof(struct PeriodicValidationContext));
2186       periodic_validation_context->foreign_address = fal;
2187       periodic_validation_context->transport = strdup(ve->transport_name);
2188       memcpy(&periodic_validation_context->publicKey, 
2189              &ve->publicKey, 
2190              sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
2191       /* FIXME: this causes all of the revalidation PINGs for the same HELLO
2192          to be transmitted in bulk, which is not nice; also,
2193          triggering these HERE means that revalidations do NOT happen AT ALL
2194          for HELLOs a previous instance of this process validated (since
2195          there is no "initial" validation PING => no revalidation => BUG! */
2196       fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(sched, 
2197                                                           TRANSPORT_DEFAULT_REVALIDATION, 
2198                                                           &send_periodic_ping, 
2199                                                           periodic_validation_context);
2200       if (n->latency.value == GNUNET_TIME_UNIT_FOREVER_REL.value)
2201         n->latency = fal->latency;
2202       else
2203         n->latency.value = (fal->latency.value + n->latency.value) / 2;
2204       n->distance = fal->distance;
2205       if (GNUNET_NO == n->received_pong)
2206         {
2207           notify_clients_connect (&target, n->latency, n->distance);
2208           n->received_pong = GNUNET_YES;
2209         }
2210       if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
2211         {
2212           GNUNET_SCHEDULER_cancel (sched,
2213                                    n->retry_task);
2214           n->retry_task = GNUNET_SCHEDULER_NO_TASK;
2215           try_transmission_to_peer (n);
2216         }
2217     }
2218
2219   /* clean up validation entry */
2220   GNUNET_assert (GNUNET_YES ==
2221                  GNUNET_CONTAINER_multihashmap_remove (validation_map,
2222                                                        key,
2223                                                        ve));
2224   GNUNET_SCHEDULER_cancel (sched,
2225                            ve->timeout_task);
2226   GNUNET_free (ve->transport_name);
2227   GNUNET_free (ve);
2228   return GNUNET_NO;
2229 }
2230
2231
2232 /**
2233  * Function that will be called if we receive a validation
2234  * of an address challenge that we transmitted to another
2235  * peer.  Note that the validation should only be considered
2236  * acceptable if the challenge matches AND if the sender
2237  * address is at least a plausible address for this peer
2238  * (otherwise we may be seeing a MiM attack).
2239  *
2240  * @param cls closure
2241  * @param message the pong message
2242  * @param peer who responded to our challenge
2243  * @param sender_address string describing our sender address (as observed
2244  *         by the other peer in binary format)
2245  * @param sender_address_len number of bytes in 'sender_address'
2246  */
2247 static void
2248 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
2249              const struct GNUNET_PeerIdentity *peer,
2250              const char *sender_address,
2251              size_t sender_address_len)
2252 {
2253 #if DEBUG_TRANSPORT > 1
2254   /* we get tons of these that just get discarded, only log
2255      if we are quite verbose */
2256   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2257               "Receiving `%s' message from `%4s'.\n", "PONG",
2258               GNUNET_i2s (peer));
2259 #endif
2260   GNUNET_STATISTICS_update (stats,
2261                             gettext_noop ("# PONG messages received"),
2262                             1,
2263                             GNUNET_NO);
2264   if (GNUNET_SYSERR !=
2265       GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
2266                                                   &peer->hashPubKey,
2267                                                   &check_pending_validation,
2268                                                   (void*) message))
2269     {
2270       /* This is *expected* to happen a lot since we send
2271          PONGs to *all* known addresses of the sender of
2272          the PING, so most likely we get multiple PONGs
2273          per PING, and all but the first PONG will end up
2274          here. So really we should not print anything here
2275          unless we want to be very, very verbose... */
2276 #if DEBUG_TRANSPORT > 2
2277       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2278                   "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
2279                   "PONG",
2280                   GNUNET_i2s (peer),
2281                   "PING");
2282 #endif
2283       return;
2284     }
2285
2286 #if 0
2287   /* FIXME: add given address to potential pool of our addresses
2288      (for voting) */
2289   GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
2290               _("Another peer saw us using the address `%s' via `%s'.\n"),
2291               GNUNET_a2s ((const struct sockaddr *) &pong[1],
2292                           ntohs(pong->addrlen)),
2293               va->transport_name);
2294 #endif
2295 }
2296
2297
2298 /**
2299  * Check if the given address is already being validated; if not,
2300  * append the given address to the list of entries that are being be
2301  * validated and initiate validation.
2302  *
2303  * @param cls closure ('struct CheckHelloValidatedContext *')
2304  * @param tname name of the transport
2305  * @param expiration expiration time
2306  * @param addr the address
2307  * @param addrlen length of the address
2308  * @return GNUNET_OK (always)
2309  */
2310 static int
2311 run_validation (void *cls,
2312                 const char *tname,
2313                 struct GNUNET_TIME_Absolute expiration,
2314                 const void *addr, size_t addrlen)
2315 {
2316   struct CheckHelloValidatedContext *chvc = cls;
2317   struct GNUNET_PeerIdentity id;
2318   struct TransportPlugin *tp;
2319   struct ValidationEntry *va;
2320   struct NeighbourList *neighbour;
2321   struct ForeignAddressList *peer_address;
2322   struct TransportPingMessage ping;
2323   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
2324   struct CheckAddressExistsClosure caec;
2325   char * message_buf;
2326   uint16_t hello_size;
2327   size_t tsize;
2328
2329   GNUNET_STATISTICS_update (stats,
2330                             gettext_noop ("# peer addresses scheduled for validation"),
2331                             1,
2332                             GNUNET_NO);      
2333   tp = find_transport (tname);
2334   if (tp == NULL)
2335     {
2336       GNUNET_log (GNUNET_ERROR_TYPE_INFO |
2337                   GNUNET_ERROR_TYPE_BULK,
2338                   _
2339                   ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
2340                   tname);
2341       GNUNET_STATISTICS_update (stats,
2342                                 gettext_noop ("# peer addresses not validated (no applicable transport plugin available)"),
2343                                 1,
2344                                 GNUNET_NO);      
2345       return GNUNET_OK;
2346     }
2347   GNUNET_HELLO_get_key (chvc->hello, &pk);
2348   GNUNET_CRYPTO_hash (&pk,
2349                       sizeof (struct
2350                               GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2351                       &id.hashPubKey);
2352   caec.addr = addr;
2353   caec.addrlen = addrlen;
2354   caec.tname = tname;
2355   caec.exists = GNUNET_NO;
2356   GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2357                                          &check_address_exists,
2358                                          &caec);
2359   if (caec.exists == GNUNET_YES)
2360     {
2361       /* During validation attempts we will likely trigger the other
2362          peer trying to validate our address which in turn will cause
2363          it to send us its HELLO, so we expect to hit this case rather
2364          frequently.  Only print something if we are very verbose. */
2365 #if DEBUG_TRANSPORT > 1
2366       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2367                   "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
2368                   GNUNET_a2s (addr, addrlen),
2369                   tname,
2370                   GNUNET_i2s (&id));
2371 #endif
2372       GNUNET_STATISTICS_update (stats,
2373                                 gettext_noop ("# peer addresses not validated (in progress)"),
2374                                 1,
2375                                 GNUNET_NO);      
2376       return GNUNET_OK;
2377     }
2378   va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
2379   va->transport_name = GNUNET_strdup (tname);
2380   va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2381                                             (unsigned int) -1);
2382   va->send_time = GNUNET_TIME_absolute_get();
2383   va->addr = (const void*) &va[1];
2384   memcpy (&va[1], addr, addrlen);
2385   va->addrlen = addrlen;
2386   GNUNET_HELLO_get_key (chvc->hello,
2387                         &va->publicKey);
2388   va->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
2389                                                    HELLO_VERIFICATION_TIMEOUT,
2390                                                    &timeout_hello_validation,
2391                                                    va);
2392   GNUNET_CONTAINER_multihashmap_put (validation_map,
2393                                      &id.hashPubKey,
2394                                      va,
2395                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2396   neighbour = find_neighbour(&id);
2397   if (neighbour == NULL)
2398     neighbour = setup_new_neighbour(&id);
2399   peer_address = add_peer_address(neighbour, tname, addr, addrlen);
2400   GNUNET_assert(peer_address != NULL);
2401   hello_size = GNUNET_HELLO_size(our_hello);
2402   tsize = sizeof(struct TransportPingMessage) + hello_size;
2403   message_buf = GNUNET_malloc(tsize);
2404   ping.challenge = htonl(va->challenge);
2405   ping.header.size = htons(sizeof(struct TransportPingMessage));
2406   ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
2407   memcpy(&ping.target, &id, sizeof(struct GNUNET_PeerIdentity));
2408   memcpy(message_buf, our_hello, hello_size);
2409   memcpy(&message_buf[hello_size],
2410          &ping,
2411          sizeof(struct TransportPingMessage));
2412 #if DEBUG_TRANSPORT
2413   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2414               "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
2415               GNUNET_a2s (addr, addrlen),
2416               tname,
2417               GNUNET_i2s (&id),
2418               "HELLO", hello_size,
2419               "PING", sizeof (struct TransportPingMessage));
2420 #endif
2421   GNUNET_STATISTICS_update (stats,
2422                             gettext_noop ("# PING messages sent for initial validation"),
2423                             1,
2424                             GNUNET_NO);      
2425   transmit_to_peer (NULL, peer_address,
2426                     GNUNET_SCHEDULER_PRIORITY_DEFAULT,
2427                     HELLO_VERIFICATION_TIMEOUT,
2428                     message_buf, tsize,
2429                     GNUNET_YES, neighbour);
2430   GNUNET_free(message_buf);
2431   return GNUNET_OK;
2432 }
2433
2434
2435 /**
2436  * Add the given address to the list of foreign addresses
2437  * available for the given peer (check for duplicates).
2438  *
2439  * @param cls the respective 'struct NeighbourList' to update
2440  * @param tname name of the transport
2441  * @param expiration expiration time
2442  * @param addr the address
2443  * @param addrlen length of the address
2444  * @return GNUNET_OK (always)
2445  */
2446 static int
2447 add_to_foreign_address_list (void *cls,
2448                              const char *tname,
2449                              struct GNUNET_TIME_Absolute expiration,
2450                              const void *addr, size_t addrlen)
2451 {
2452   struct NeighbourList *n = cls;
2453   struct ForeignAddressList *fal;
2454   int try;
2455
2456   GNUNET_STATISTICS_update (stats,
2457                             gettext_noop ("# valid peer addresses returned by peerinfo"),
2458                             1,
2459                             GNUNET_NO);      
2460   try = GNUNET_NO;
2461   fal = find_peer_address (n, tname, addr, addrlen);
2462   if (fal == NULL)
2463     {
2464 #if DEBUG_TRANSPORT
2465       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2466                   "Adding address `%s' (%s) for peer `%4s' due to peerinfo data for %llums.\n",
2467                   GNUNET_a2s (addr, addrlen),
2468                   tname,
2469                   GNUNET_i2s (&n->id),
2470                   expiration.value);
2471 #endif
2472       fal = add_peer_address (n, tname, addr, addrlen);
2473       if (fal == NULL)
2474         {
2475           GNUNET_STATISTICS_update (stats,
2476                                     gettext_noop ("# previously validated addresses lacking transport"),
2477                                     1,
2478                                     GNUNET_NO); 
2479         }
2480       try = GNUNET_YES;
2481     }
2482   if (fal == NULL)
2483     return GNUNET_OK;
2484   fal->expires = GNUNET_TIME_absolute_max (expiration,
2485                                            fal->expires);
2486   if (fal->validated == GNUNET_NO)
2487     {
2488       fal->validated = GNUNET_YES;  
2489       GNUNET_STATISTICS_update (stats,
2490                                 gettext_noop ("# peer addresses considered valid"),
2491                                 1,
2492                                 GNUNET_NO);      
2493     }
2494   if (try == GNUNET_YES)
2495     try_transmission_to_peer (n);
2496   return GNUNET_OK;
2497 }
2498
2499
2500 /**
2501  * Check if addresses in validated hello "h" overlap with
2502  * those in "chvc->hello" and validate the rest.
2503  *
2504  * @param cls closure
2505  * @param peer id of the peer, NULL for last call
2506  * @param h hello message for the peer (can be NULL)
2507  * @param trust amount of trust we have in the peer (not used)
2508  */
2509 static void
2510 check_hello_validated (void *cls,
2511                        const struct GNUNET_PeerIdentity *peer,
2512                        const struct GNUNET_HELLO_Message *h, 
2513                        uint32_t trust)
2514 {
2515   struct CheckHelloValidatedContext *chvc = cls;
2516   struct GNUNET_HELLO_Message *plain_hello;
2517   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
2518   struct GNUNET_PeerIdentity target;
2519   struct NeighbourList *n;
2520
2521   if (peer == NULL)
2522     {
2523       chvc->piter = NULL;
2524       GNUNET_CONTAINER_DLL_remove (chvc_head,
2525                                    chvc_tail,
2526                                    chvc);
2527       if (GNUNET_NO == chvc->hello_known)
2528         {
2529           /* notify PEERINFO about the peer now, so that we at least
2530              have the public key if some other component needs it */
2531           GNUNET_HELLO_get_key (chvc->hello, &pk);
2532           GNUNET_CRYPTO_hash (&pk,
2533                               sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2534                               &target.hashPubKey);
2535           plain_hello = GNUNET_HELLO_create (&pk,
2536                                              NULL, 
2537                                              NULL);
2538           GNUNET_PEERINFO_add_peer (cfg, sched, &target, plain_hello);
2539           GNUNET_free (plain_hello);
2540 #if DEBUG_TRANSPORT
2541           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2542                       "Peerinfo had no `%s' message for peer `%4s', full validation needed.\n",
2543                       "HELLO",
2544                       GNUNET_i2s (&target));
2545 #endif
2546           GNUNET_STATISTICS_update (stats,
2547                                     gettext_noop ("# new HELLOs requiring full validation"),
2548                                     1,
2549                                     GNUNET_NO);      
2550           GNUNET_HELLO_iterate_addresses (chvc->hello,
2551                                           GNUNET_NO, 
2552                                           &run_validation, 
2553                                           chvc);
2554         }
2555       else
2556         {
2557           GNUNET_STATISTICS_update (stats,
2558                                     gettext_noop ("# duplicate HELLO (peer known)"),
2559                                     1,
2560                                     GNUNET_NO);      
2561         }
2562       GNUNET_free (chvc);
2563       return;
2564     } 
2565   if (h == NULL)
2566     return;
2567 #if DEBUG_TRANSPORT
2568   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2569               "Peerinfo had `%s' message for peer `%4s', validating only new addresses.\n",
2570               "HELLO",
2571               GNUNET_i2s (peer));
2572 #endif
2573   chvc->hello_known = GNUNET_YES;
2574   n = find_neighbour (peer);
2575   if (n != NULL)
2576     {
2577       GNUNET_HELLO_iterate_addresses (h,
2578                                       GNUNET_NO,
2579                                       &add_to_foreign_address_list,
2580                                       n);
2581       try_transmission_to_peer (n);
2582     }
2583   else
2584     {
2585       GNUNET_STATISTICS_update (stats,
2586                                 gettext_noop ("# no existing neighbour record while validating HELLO"),
2587                                 1,
2588                                 GNUNET_NO);      
2589     }
2590   GNUNET_STATISTICS_update (stats,
2591                             gettext_noop ("# HELLO validations (update case)"),
2592                             1,
2593                             GNUNET_NO);      
2594   GNUNET_HELLO_iterate_new_addresses (chvc->hello,
2595                                       h,
2596                                       GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME),
2597                                       &run_validation, 
2598                                       chvc);
2599 }
2600
2601 /**
2602  * Process HELLO-message.
2603  *
2604  * @param plugin transport involved, may be NULL
2605  * @param message the actual message
2606  * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
2607  */
2608 static int
2609 process_hello (struct TransportPlugin *plugin,
2610                const struct GNUNET_MessageHeader *message)
2611 {
2612   uint16_t hsize;
2613   struct GNUNET_PeerIdentity target;
2614   const struct GNUNET_HELLO_Message *hello;
2615   struct CheckHelloValidatedContext *chvc;
2616   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
2617
2618   hsize = ntohs (message->size);
2619   if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
2620       (hsize < sizeof (struct GNUNET_MessageHeader)))
2621     {
2622       GNUNET_break (0);
2623       return GNUNET_SYSERR;
2624     }
2625   GNUNET_STATISTICS_update (stats,
2626                             gettext_noop ("# HELLOs received for validation"),
2627                             1,
2628                             GNUNET_NO);      
2629   /* first, check if load is too high */
2630   if (GNUNET_SCHEDULER_get_load (sched,
2631                                  GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
2632     {
2633       GNUNET_STATISTICS_update (stats,
2634                                 gettext_noop ("# HELLOs ignored due to high load"),
2635                                 1,
2636                                 GNUNET_NO);      
2637       return GNUNET_OK;
2638     }
2639   hello = (const struct GNUNET_HELLO_Message *) message;
2640   if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
2641     {
2642       GNUNET_break_op (0);
2643       return GNUNET_SYSERR;
2644     }
2645   GNUNET_CRYPTO_hash (&publicKey,
2646                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2647                       &target.hashPubKey);
2648   if (0 == memcmp (&my_identity,
2649                    &target,
2650                    sizeof (struct GNUNET_PeerIdentity)))
2651     {
2652       GNUNET_STATISTICS_update (stats,
2653                                 gettext_noop ("# HELLOs ignored for validation (is my own HELLO)"),
2654                                 1,
2655                                 GNUNET_NO);      
2656       return GNUNET_OK;      
2657     }
2658 #if DEBUG_TRANSPORT > 1
2659   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2660               "Processing `%s' message for `%4s' of size %u\n",
2661               "HELLO", 
2662               GNUNET_i2s (&target), 
2663               GNUNET_HELLO_size(hello));
2664 #endif
2665   chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
2666   chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
2667   memcpy (&chvc[1], hello, hsize);
2668   GNUNET_CONTAINER_DLL_insert (chvc_head,
2669                                chvc_tail,
2670                                chvc);
2671   /* finally, check if HELLO was previously validated
2672      (continuation will then schedule actual validation) */
2673   chvc->piter = GNUNET_PEERINFO_iterate (cfg,
2674                                          sched,
2675                                          &target,
2676                                          0,
2677                                          HELLO_VERIFICATION_TIMEOUT,
2678                                          &check_hello_validated, chvc);
2679   return GNUNET_OK;
2680 }
2681
2682
2683 /**
2684  * The peer specified by the given neighbour has timed-out or a plugin
2685  * has disconnected.  We may either need to do nothing (other plugins
2686  * still up), or trigger a full disconnect and clean up.  This
2687  * function updates our state and does the necessary notifications.
2688  * Also notifies our clients that the neighbour is now officially
2689  * gone.
2690  *
2691  * @param n the neighbour list entry for the peer
2692  * @param check should we just check if all plugins
2693  *        disconnected or must we ask all plugins to
2694  *        disconnect?
2695  */
2696 static void
2697 disconnect_neighbour (struct NeighbourList *n, int check)
2698 {
2699   struct ReadyList *rpos;
2700   struct NeighbourList *npos;
2701   struct NeighbourList *nprev;
2702   struct MessageQueue *mq;
2703   struct ForeignAddressList *peer_addresses;
2704   struct ForeignAddressList *peer_pos;
2705
2706   if (GNUNET_YES == check)
2707     {
2708       rpos = n->plugins;
2709       while (NULL != rpos)
2710         {
2711           peer_addresses = rpos->addresses;
2712           while (peer_addresses != NULL)
2713             {
2714               if (GNUNET_YES == peer_addresses->connected)
2715                 return;             /* still connected */
2716               peer_addresses = peer_addresses->next;
2717             }
2718           rpos = rpos->next;
2719         }
2720     }
2721 #if DEBUG_TRANSPORT
2722   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2723               "Disconnecting from `%4s'\n",
2724               GNUNET_i2s (&n->id));
2725 #endif
2726   /* remove n from neighbours list */
2727   nprev = NULL;
2728   npos = neighbours;
2729   while ((npos != NULL) && (npos != n))
2730     {
2731       nprev = npos;
2732       npos = npos->next;
2733     }
2734   GNUNET_assert (npos != NULL);
2735   if (nprev == NULL)
2736     neighbours = n->next;
2737   else
2738     nprev->next = n->next;
2739
2740   /* notify all clients about disconnect */
2741   if (GNUNET_YES == n->received_pong)
2742     notify_clients_disconnect (&n->id);
2743
2744   /* clean up all plugins, cancel connections and pending transmissions */
2745   while (NULL != (rpos = n->plugins))
2746     {
2747       n->plugins = rpos->next;
2748       rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
2749       while (rpos->addresses != NULL)
2750         {
2751           peer_pos = rpos->addresses;
2752           rpos->addresses = peer_pos->next;
2753           if (peer_pos->connected == GNUNET_YES)
2754             GNUNET_STATISTICS_update (stats,
2755                                       gettext_noop ("# connected addresses"),
2756                                       -1,
2757                                       GNUNET_NO); 
2758           if (GNUNET_YES == peer_pos->validated)
2759             GNUNET_STATISTICS_update (stats,
2760                                       gettext_noop ("# peer addresses considered valid"),
2761                                       -1,
2762                                       GNUNET_NO);      
2763           GNUNET_free(peer_pos);
2764         }
2765       GNUNET_free (rpos);
2766     }
2767
2768   /* free all messages on the queue */
2769   while (NULL != (mq = n->messages_head))
2770     {
2771       GNUNET_STATISTICS_update (stats,
2772                                 gettext_noop ("# bytes in message queue for other peers"),
2773                                 -mq->message_buf_size,
2774                                 GNUNET_NO);
2775       GNUNET_STATISTICS_update (stats,
2776                                 gettext_noop ("# bytes discarded due to disconnect"),
2777                                 mq->message_buf_size,
2778                                 GNUNET_NO);
2779       GNUNET_CONTAINER_DLL_remove (n->messages_head,
2780                                    n->messages_tail,
2781                                    mq);
2782       GNUNET_assert (0 == memcmp(&mq->neighbour_id, 
2783                                  &n->id,
2784                                  sizeof(struct GNUNET_PeerIdentity)));
2785       GNUNET_free (mq);
2786     }
2787   if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
2788     {
2789       GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
2790       n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2791     }
2792   if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
2793     {
2794       GNUNET_SCHEDULER_cancel (sched, n->retry_task);
2795       n->retry_task = GNUNET_SCHEDULER_NO_TASK;
2796     }
2797   /* finally, free n itself */
2798   GNUNET_STATISTICS_update (stats,
2799                             gettext_noop ("# active neighbours"),
2800                             -1,
2801                             GNUNET_NO);
2802   GNUNET_free (n);
2803 }
2804
2805
2806 /**
2807  * We have received a PING message from someone.  Need to send a PONG message
2808  * in response to the peer by any means necessary. 
2809  *
2810  * FIXME: With something like TCP where a connection exists, we may
2811  * want to send it that way.  But the current API does not seem to
2812  * allow us to do so (can't tell this to the transport!)
2813  */
2814 static int 
2815 handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
2816             const struct GNUNET_PeerIdentity *peer,
2817             const char *sender_address,
2818             size_t sender_address_len)
2819 {
2820   struct TransportPlugin *plugin = cls;
2821   struct TransportPingMessage *ping;
2822   struct TransportPongMessage *pong;
2823   struct NeighbourList *n;
2824   struct ReadyList *rl;
2825   struct ForeignAddressList *fal;
2826
2827   if (ntohs (message->size) != sizeof (struct TransportPingMessage))
2828     {
2829       GNUNET_break_op (0);
2830       return GNUNET_SYSERR;
2831     }
2832   ping = (struct TransportPingMessage *) message;
2833   if (0 != memcmp (&ping->target,
2834                    plugin->env.my_identity,
2835                    sizeof (struct GNUNET_PeerIdentity)))
2836     {
2837       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2838                   _("Received `%s' message not destined for me!\n"), 
2839                   "PING");
2840       return GNUNET_SYSERR;
2841     }
2842 #if DEBUG_TRANSPORT
2843   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2844               "Processing `%s' from `%s'\n",
2845               "PING", 
2846               GNUNET_a2s ((const struct sockaddr *)sender_address, 
2847                           sender_address_len));
2848 #endif
2849   GNUNET_STATISTICS_update (stats,
2850                             gettext_noop ("# PING messages received"),
2851                             1,
2852                             GNUNET_NO);
2853   pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len);
2854   pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len);
2855   pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
2856   pong->purpose.size =
2857     htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
2858            sizeof (uint32_t) +
2859            sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + sender_address_len);
2860   pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_TCP_PING);
2861   pong->challenge = ping->challenge;
2862   pong->addrlen = htons(sender_address_len);
2863   memcpy(&pong->signer, 
2864          &my_public_key, 
2865          sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
2866   memcpy (&pong[1], sender_address, sender_address_len);
2867   GNUNET_assert (GNUNET_OK ==
2868                  GNUNET_CRYPTO_rsa_sign (my_private_key,
2869                                          &pong->purpose, &pong->signature));
2870
2871   n = find_neighbour(peer);
2872   if (n == NULL)
2873     n = setup_new_neighbour(peer);
2874   /* broadcast 'PONG' to all available addresses */
2875   rl = n->plugins;
2876   while (rl != NULL)
2877     {
2878       fal = rl->addresses;
2879       while (fal != NULL)
2880         {
2881           transmit_to_peer(NULL, fal,
2882                            TRANSPORT_PONG_PRIORITY, 
2883                            HELLO_VERIFICATION_TIMEOUT,
2884                            (const char *)pong, 
2885                            ntohs(pong->header.size), 
2886                            GNUNET_YES, 
2887                            n);
2888           fal = fal->next;
2889         }
2890       rl = rl->next;
2891     }
2892   GNUNET_free(pong);
2893   return GNUNET_OK;
2894 }
2895
2896
2897 /**
2898  * Function called by the plugin for each received message.
2899  * Update data volumes, possibly notify plugins about
2900  * reducing the rate at which they read from the socket
2901  * and generally forward to our receive callback.
2902  *
2903  * @param cls the "struct TransportPlugin *" we gave to the plugin
2904  * @param peer (claimed) identity of the other peer
2905  * @param message the message, NULL if we only care about
2906  *                learning about the delay until we should receive again
2907  * @param distance in overlay hops; use 1 unless DV (or 0 if message == NULL)
2908  * @param sender_address binary address of the sender (if observed)
2909  * @param sender_address_len number of bytes in sender_address
2910  * @return how long the plugin should wait until receiving more data
2911  *         (plugins that do not support this, can ignore the return value)
2912  */
2913 static struct GNUNET_TIME_Relative
2914 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
2915                     const struct GNUNET_MessageHeader *message,
2916                     unsigned int distance, const char *sender_address,
2917                     size_t sender_address_len)
2918 {
2919   struct ReadyList *service_context;
2920   struct TransportPlugin *plugin = cls;
2921   struct TransportClient *cpos;
2922   struct InboundMessage *im;
2923   struct ForeignAddressList *peer_address;
2924   uint16_t msize;
2925   struct NeighbourList *n;
2926   struct GNUNET_TIME_Relative ret;
2927
2928   n = find_neighbour (peer);
2929   if (n == NULL)
2930     n = setup_new_neighbour (peer);    
2931   service_context = n->plugins;
2932   while ((service_context != NULL) && (plugin != service_context->plugin))
2933     service_context = service_context->next;
2934   GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
2935   if (message != NULL)
2936     {
2937       peer_address = add_peer_address(n, 
2938                                       plugin->short_name,
2939                                       sender_address, 
2940                                       sender_address_len);  
2941       if (peer_address != NULL)
2942         {
2943           peer_address->distance = distance;
2944           if (peer_address->connected == GNUNET_NO)
2945             {
2946               peer_address->connected = GNUNET_YES;
2947               peer_address->connect_attempts++;
2948               GNUNET_STATISTICS_update (stats,
2949                                         gettext_noop ("# connected addresses"),
2950                                         1,
2951                                         GNUNET_NO);
2952             }
2953           peer_address->timeout
2954             =
2955             GNUNET_TIME_relative_to_absolute
2956             (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2957         }
2958       /* update traffic received amount ... */
2959       msize = ntohs (message->size);      
2960       GNUNET_STATISTICS_update (stats,
2961                                 gettext_noop ("# bytes received from other peers"),
2962                                 msize,
2963                                 GNUNET_NO);
2964       n->distance = distance;
2965       n->peer_timeout =
2966         GNUNET_TIME_relative_to_absolute
2967         (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2968       GNUNET_SCHEDULER_cancel (sched,
2969                                n->timeout_task);
2970       n->timeout_task =
2971         GNUNET_SCHEDULER_add_delayed (sched,
2972                                       GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2973                                       &neighbour_timeout_task, n);
2974       if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
2975         {
2976           /* dropping message due to frequent inbound volume violations! */
2977           GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
2978                       GNUNET_ERROR_TYPE_BULK,
2979                       _
2980                       ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"), 
2981                       n->in_tracker.available_bytes_per_s__,
2982                       n->quota_violation_count);
2983           GNUNET_STATISTICS_update (stats,
2984                                     gettext_noop ("# bandwidth quota violations by other peers"),
2985                                     1,
2986                                     GNUNET_NO);
2987           return GNUNET_TIME_UNIT_MINUTES; /* minimum penalty, likely ignored (UDP...) */
2988         }
2989       switch (ntohs (message->type))
2990         {
2991         case GNUNET_MESSAGE_TYPE_HELLO:
2992           GNUNET_STATISTICS_update (stats,
2993                                     gettext_noop ("# HELLO messages received from other peers"),
2994                                     1,
2995                                     GNUNET_NO);
2996           process_hello (plugin, message);
2997           break;
2998         case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
2999           handle_ping(plugin, message, peer, sender_address, sender_address_len);
3000           break;
3001         case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
3002           handle_pong(plugin, message, peer, sender_address, sender_address_len);
3003           break;
3004         default:
3005 #if DEBUG_TRANSPORT
3006           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3007                       "Received message of type %u from `%4s', sending to all clients.\n",
3008                       ntohs (message->type), GNUNET_i2s (peer));
3009 #endif
3010           if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3011                                                               msize))
3012             n->quota_violation_count++;
3013           else 
3014             n->quota_violation_count = 0; /* back within limits */
3015           GNUNET_STATISTICS_update (stats,
3016                                     gettext_noop ("# payload received from other peers"),
3017                                     msize,
3018                                     GNUNET_NO);
3019           /* transmit message to all clients */
3020           im = GNUNET_malloc (sizeof (struct InboundMessage) + msize);
3021           im->header.size = htons (sizeof (struct InboundMessage) + msize);
3022           im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
3023           im->latency = GNUNET_TIME_relative_hton (n->latency);
3024           im->peer = *peer;
3025           memcpy (&im[1], message, msize);
3026           cpos = clients;
3027           while (cpos != NULL)
3028             {
3029               transmit_to_client (cpos, &im->header, GNUNET_YES);
3030               cpos = cpos->next;
3031             }
3032           GNUNET_free (im);
3033         }
3034     }  
3035   ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
3036   if (ret.value > 0)
3037     {
3038       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3039                   "Throttling read (%llu bytes excess at %u b/s), waiting %llums before reading more.\n",
3040                   (unsigned long long) n->in_tracker.consumption_since_last_update__,
3041                   (unsigned int) n->in_tracker.available_bytes_per_s__,
3042                   (unsigned long long) ret.value);
3043       GNUNET_STATISTICS_update (stats,
3044                                 gettext_noop ("# ms throttling suggested"),
3045                                 (int64_t) ret.value,
3046                                 GNUNET_NO);      
3047     }
3048   return ret;
3049 }
3050
3051
3052 /**
3053  * Handle START-message.  This is the first message sent to us
3054  * by any client which causes us to add it to our list.
3055  *
3056  * @param cls closure (always NULL)
3057  * @param client identification of the client
3058  * @param message the actual message
3059  */
3060 static void
3061 handle_start (void *cls,
3062               struct GNUNET_SERVER_Client *client,
3063               const struct GNUNET_MessageHeader *message)
3064 {
3065   struct TransportClient *c;
3066   struct ConnectInfoMessage cim;
3067   struct NeighbourList *n;
3068
3069 #if DEBUG_TRANSPORT
3070   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3071               "Received `%s' request from client\n", "START");
3072 #endif
3073   c = clients;
3074   while (c != NULL)
3075     {
3076       if (c->client == client)
3077         {
3078           /* client already on our list! */
3079           GNUNET_break (0);
3080           GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3081           return;
3082         }
3083       c = c->next;
3084     }
3085   c = GNUNET_malloc (sizeof (struct TransportClient));
3086   c->next = clients;
3087   clients = c;
3088   c->client = client;
3089   if (our_hello != NULL)
3090     {
3091 #if DEBUG_TRANSPORT
3092       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3093                   "Sending our own `%s' to new client\n", "HELLO");
3094 #endif
3095       transmit_to_client (c,
3096                           (const struct GNUNET_MessageHeader *) our_hello,
3097                           GNUNET_NO);
3098       /* tell new client about all existing connections */
3099       cim.header.size = htons (sizeof (struct ConnectInfoMessage));
3100       cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
3101       n = neighbours; 
3102       while (n != NULL)
3103         {
3104           if (GNUNET_YES == n->received_pong)
3105             {
3106               cim.id = n->id;
3107               cim.latency = GNUNET_TIME_relative_hton (n->latency);
3108               cim.distance = htonl (n->distance);
3109               transmit_to_client (c, &cim.header, GNUNET_NO);
3110             }
3111             n = n->next;
3112         }
3113     }
3114   GNUNET_SERVER_receive_done (client, GNUNET_OK);
3115 }
3116
3117
3118 /**
3119  * Handle HELLO-message.
3120  *
3121  * @param cls closure (always NULL)
3122  * @param client identification of the client
3123  * @param message the actual message
3124  */
3125 static void
3126 handle_hello (void *cls,
3127               struct GNUNET_SERVER_Client *client,
3128               const struct GNUNET_MessageHeader *message)
3129 {
3130   int ret;
3131
3132   GNUNET_STATISTICS_update (stats,
3133                             gettext_noop ("# HELLOs received from clients"),
3134                             1,
3135                             GNUNET_NO);      
3136   ret = process_hello (NULL, message);
3137   GNUNET_SERVER_receive_done (client, ret);
3138 }
3139
3140
3141 /**
3142  * Handle SEND-message.
3143  *
3144  * @param cls closure (always NULL)
3145  * @param client identification of the client
3146  * @param message the actual message
3147  */
3148 static void
3149 handle_send (void *cls,
3150              struct GNUNET_SERVER_Client *client,
3151              const struct GNUNET_MessageHeader *message)
3152 {
3153   struct TransportClient *tc;
3154   struct NeighbourList *n;
3155   const struct OutboundMessage *obm;
3156   const struct GNUNET_MessageHeader *obmm;
3157   uint16_t size;
3158   uint16_t msize;
3159
3160   size = ntohs (message->size);
3161   if (size <
3162       sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
3163     {
3164       GNUNET_break (0);
3165       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3166       return;
3167     }
3168   GNUNET_STATISTICS_update (stats,
3169                             gettext_noop ("# payload received for other peers"),
3170                             size,
3171                             GNUNET_NO);      
3172   obm = (const struct OutboundMessage *) message;
3173 #if DEBUG_TRANSPORT
3174   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3175               "Received `%s' request from client with target `%4s'\n",
3176               "SEND", GNUNET_i2s (&obm->peer));
3177 #endif
3178   obmm = (const struct GNUNET_MessageHeader *) &obm[1];
3179   msize = ntohs (obmm->size);
3180   if (size != msize + sizeof (struct OutboundMessage))
3181     {
3182       GNUNET_break (0);
3183       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3184       return;
3185     }
3186   n = find_neighbour (&obm->peer);
3187   if (n == NULL)
3188     n = setup_new_neighbour (&obm->peer);
3189   tc = clients;
3190   while ((tc != NULL) && (tc->client != client))
3191     tc = tc->next;
3192
3193 #if DEBUG_TRANSPORT
3194   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3195               "Client asked to transmit %u-byte message of type %u to `%4s'\n",
3196               ntohs (obmm->size),
3197               ntohs (obmm->type), GNUNET_i2s (&obm->peer));
3198 #endif
3199   transmit_to_peer (tc, NULL, ntohl (obm->priority), 
3200                     GNUNET_TIME_relative_ntoh (obm->timeout),
3201                     (char *)obmm, 
3202                     ntohs (obmm->size), GNUNET_NO, n);
3203   GNUNET_SERVER_receive_done (client, GNUNET_OK);
3204 }
3205
3206
3207 /**
3208  * Handle SET_QUOTA-message.
3209  *
3210  * @param cls closure (always NULL)
3211  * @param client identification of the client
3212  * @param message the actual message
3213  */
3214 static void
3215 handle_set_quota (void *cls,
3216                   struct GNUNET_SERVER_Client *client,
3217                   const struct GNUNET_MessageHeader *message)
3218 {
3219   const struct QuotaSetMessage *qsm =
3220     (const struct QuotaSetMessage *) message;
3221   struct NeighbourList *n;
3222   
3223   GNUNET_STATISTICS_update (stats,
3224                             gettext_noop ("# SET QUOTA messages received"),
3225                             1,
3226                             GNUNET_NO);      
3227   n = find_neighbour (&qsm->peer);
3228   if (n == NULL)
3229     {
3230       GNUNET_SERVER_receive_done (client, GNUNET_OK);
3231       GNUNET_STATISTICS_update (stats,
3232                                 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
3233                                 1,
3234                                 GNUNET_NO);      
3235       return;
3236     }
3237 #if DEBUG_TRANSPORT
3238   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3239               "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
3240               "SET_QUOTA", 
3241               (unsigned int) ntohl (qsm->quota.value__),
3242               (unsigned int) n->in_tracker.available_bytes_per_s__,
3243               GNUNET_i2s (&qsm->peer));
3244 #endif
3245   GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
3246                                          qsm->quota);
3247   if (0 == ntohl (qsm->quota.value__)) 
3248     disconnect_neighbour (n, GNUNET_NO);    
3249   GNUNET_SERVER_receive_done (client, GNUNET_OK);
3250 }
3251
3252
3253 static void
3254 transmit_address_to_client (void *cls, const char *address)
3255 {
3256   struct GNUNET_SERVER_TransmitContext *tc = cls;
3257   size_t slen;
3258
3259   if (NULL == address)
3260     slen = 0;
3261   else
3262     slen = strlen (address) + 1;
3263   GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
3264                                               GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
3265   if (NULL == address)
3266     GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
3267 }
3268
3269
3270 /**
3271  * Handle AddressLookup-message.
3272  *
3273  * @param cls closure (always NULL)
3274  * @param client identification of the client
3275  * @param message the actual message
3276  */
3277 static void
3278 handle_address_lookup (void *cls,
3279                        struct GNUNET_SERVER_Client *client,
3280                        const struct GNUNET_MessageHeader *message)
3281 {
3282   const struct AddressLookupMessage *alum;
3283   struct TransportPlugin *lsPlugin;
3284   const char *nameTransport;
3285   const char *address;
3286   uint16_t size;
3287   struct GNUNET_SERVER_TransmitContext *tc;
3288
3289   size = ntohs (message->size);
3290   if (size < sizeof (struct AddressLookupMessage))
3291     {
3292       GNUNET_break_op (0);
3293       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3294       return;
3295     }
3296   alum = (const struct AddressLookupMessage *) message;
3297   uint32_t addressLen = ntohl (alum->addrlen);
3298   if (size <= sizeof (struct AddressLookupMessage) + addressLen)
3299     {
3300       GNUNET_break_op (0);
3301       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3302       return;
3303     }
3304   address = (const char *) &alum[1];
3305   nameTransport = (const char *) &address[addressLen];
3306   if (nameTransport
3307       [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
3308     {
3309       GNUNET_break_op (0);
3310       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3311       return;
3312     }
3313   struct GNUNET_TIME_Absolute timeout =
3314     GNUNET_TIME_absolute_ntoh (alum->timeout);
3315   struct GNUNET_TIME_Relative rtimeout =
3316     GNUNET_TIME_absolute_get_remaining (timeout);
3317   lsPlugin = find_transport (nameTransport);
3318   if (NULL == lsPlugin)
3319     {
3320       tc = GNUNET_SERVER_transmit_context_create (client);
3321       GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
3322                                                   GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
3323       GNUNET_SERVER_transmit_context_run (tc, rtimeout);
3324       return;
3325     }
3326   tc = GNUNET_SERVER_transmit_context_create (client);
3327   lsPlugin->api->address_pretty_printer (cls, nameTransport,
3328                                          address, addressLen, GNUNET_YES,
3329                                          rtimeout,
3330                                          &transmit_address_to_client, tc);
3331 }
3332
3333 /**
3334  * List of handlers for the messages understood by this
3335  * service.
3336  */
3337 static struct GNUNET_SERVER_MessageHandler handlers[] = {
3338   {&handle_start, NULL,
3339    GNUNET_MESSAGE_TYPE_TRANSPORT_START, 0},
3340   {&handle_hello, NULL,
3341    GNUNET_MESSAGE_TYPE_HELLO, 0},
3342   {&handle_send, NULL,
3343    GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
3344   {&handle_set_quota, NULL,
3345    GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
3346   {&handle_address_lookup, NULL,
3347    GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
3348    0},
3349   {NULL, NULL, 0, 0}
3350 };
3351
3352
3353 /**
3354  * Setup the environment for this plugin.
3355  */
3356 static void
3357 create_environment (struct TransportPlugin *plug)
3358 {
3359   plug->env.cfg = cfg;
3360   plug->env.sched = sched;
3361   plug->env.my_identity = &my_identity;
3362   plug->env.cls = plug;
3363   plug->env.receive = &plugin_env_receive;
3364   plug->env.notify_address = &plugin_env_notify_address;
3365   plug->env.max_connections = max_connect_per_transport;
3366   plug->env.stats = stats;
3367 }
3368
3369
3370 /**
3371  * Start the specified transport (load the plugin).
3372  */
3373 static void
3374 start_transport (struct GNUNET_SERVER_Handle *server, const char *name)
3375 {
3376   struct TransportPlugin *plug;
3377   char *libname;
3378
3379   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3380               _("Loading `%s' transport plugin\n"), name);
3381   GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
3382   plug = GNUNET_malloc (sizeof (struct TransportPlugin));
3383   create_environment (plug);
3384   plug->short_name = GNUNET_strdup (name);
3385   plug->lib_name = libname;
3386   plug->next = plugins;
3387   plugins = plug;
3388   plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
3389   if (plug->api == NULL)
3390     {
3391       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3392                   _("Failed to load transport plugin for `%s'\n"), name);
3393       GNUNET_free (plug->short_name);
3394       plugins = plug->next;
3395       GNUNET_free (libname);
3396       GNUNET_free (plug);
3397     }
3398 }
3399
3400
3401 /**
3402  * Called whenever a client is disconnected.  Frees our
3403  * resources associated with that client.
3404  *
3405  * @param cls closure
3406  * @param client identification of the client
3407  */
3408 static void
3409 client_disconnect_notification (void *cls,
3410                                 struct GNUNET_SERVER_Client *client)
3411 {
3412   struct TransportClient *pos;
3413   struct TransportClient *prev;
3414   struct ClientMessageQueueEntry *mqe;
3415
3416   if (client == NULL)
3417     return;
3418 #if DEBUG_TRANSPORT
3419   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
3420               "Client disconnected, cleaning up.\n");
3421 #endif
3422   prev = NULL;
3423   pos = clients;
3424   while ((pos != NULL) && (pos->client != client))
3425     {
3426       prev = pos;
3427       pos = pos->next;
3428     }
3429   if (pos == NULL)
3430     return;
3431   while (NULL != (mqe = pos->message_queue_head))
3432     {
3433       GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
3434                                    pos->message_queue_tail,
3435                                    mqe);
3436       pos->message_count--;
3437       GNUNET_free (mqe);
3438     }
3439   if (prev == NULL)
3440     clients = pos->next;
3441   else
3442     prev->next = pos->next;
3443   if (GNUNET_YES == pos->tcs_pending)
3444     {
3445       pos->client = NULL;
3446       return;
3447     }
3448   if (pos->th != NULL)
3449     {
3450       GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
3451       pos->th = NULL;
3452     }
3453   GNUNET_break (0 == pos->message_count);
3454   GNUNET_free (pos);
3455 }
3456
3457
3458 /**
3459  * Iterator to free entries in the validation_map.
3460  *
3461  * @param cls closure (unused)
3462  * @param key current key code
3463  * @param value value in the hash map (validation to abort)
3464  * @return GNUNET_YES (always)
3465  */
3466 static int 
3467 abort_validation (void *cls,
3468                   const GNUNET_HashCode * key,
3469                   void *value)
3470 {
3471   struct ValidationEntry *va = value;
3472
3473   GNUNET_SCHEDULER_cancel (sched, va->timeout_task);
3474   GNUNET_free (va->transport_name);
3475   GNUNET_free (va);
3476   return GNUNET_YES;
3477 }
3478
3479
3480 /**
3481  * Function called when the service shuts down.  Unloads our plugins
3482  * and cancels pending validations.
3483  *
3484  * @param cls closure, unused
3485  * @param tc task context (unused)
3486  */
3487 static void
3488 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
3489 {
3490   struct TransportPlugin *plug;
3491   struct OwnAddressList *al;
3492   struct CheckHelloValidatedContext *chvc;
3493
3494   while (neighbours != NULL)
3495     disconnect_neighbour (neighbours, GNUNET_NO);
3496 #if DEBUG_TRANSPORT
3497   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3498               "Transport service is unloading plugins...\n");
3499 #endif
3500   while (NULL != (plug = plugins))
3501     {
3502       plugins = plug->next;
3503       GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
3504       GNUNET_free (plug->lib_name);
3505       GNUNET_free (plug->short_name);
3506       while (NULL != (al = plug->addresses))
3507         {
3508           plug->addresses = al->next;
3509           GNUNET_free (al);
3510         }
3511       GNUNET_free (plug);
3512     }
3513   if (my_private_key != NULL)
3514     GNUNET_CRYPTO_rsa_key_free (my_private_key);
3515   GNUNET_free_non_null (our_hello);
3516
3517   /* free 'chvc' data structure */
3518   while (NULL != (chvc = chvc_head))
3519     {
3520       chvc_head = chvc->next;
3521       GNUNET_PEERINFO_iterate_cancel (chvc->piter);
3522       GNUNET_free (chvc);
3523     }
3524   chvc_tail = NULL;
3525
3526   GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3527                                          &abort_validation,
3528                                          NULL);
3529   GNUNET_CONTAINER_multihashmap_destroy (validation_map);
3530   validation_map = NULL;
3531   if (stats != NULL)
3532     {
3533       GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
3534       stats = NULL;
3535     }
3536 }
3537
3538
3539 /**
3540  * Initiate transport service.
3541  *
3542  * @param cls closure
3543  * @param s scheduler to use
3544  * @param serv the initialized server
3545  * @param c configuration to use
3546  */
3547 static void
3548 run (void *cls,
3549      struct GNUNET_SCHEDULER_Handle *s,
3550      struct GNUNET_SERVER_Handle *serv,
3551      const struct GNUNET_CONFIGURATION_Handle *c)
3552 {
3553   char *plugs;
3554   char *pos;
3555   int no_transports;
3556   unsigned long long tneigh;
3557   char *keyfile;
3558
3559   sched = s;
3560   cfg = c;
3561   stats = GNUNET_STATISTICS_create (sched, "transport", cfg);
3562   validation_map = GNUNET_CONTAINER_multihashmap_create (64);
3563   /* parse configuration */
3564   if ((GNUNET_OK !=
3565        GNUNET_CONFIGURATION_get_value_number (c,
3566                                               "TRANSPORT",
3567                                               "NEIGHBOUR_LIMIT",
3568                                               &tneigh)) ||
3569       (GNUNET_OK !=
3570        GNUNET_CONFIGURATION_get_value_filename (c,
3571                                                 "GNUNETD",
3572                                                 "HOSTKEY", &keyfile)))
3573     {
3574       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3575                   _
3576                   ("Transport service is lacking key configuration settings.  Exiting.\n"));
3577       GNUNET_SCHEDULER_shutdown (s);
3578       if (stats != NULL)
3579         {
3580           GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
3581           stats = NULL;
3582         }
3583       GNUNET_CONTAINER_multihashmap_destroy (validation_map);
3584       validation_map = NULL;
3585       return;
3586     }
3587   max_connect_per_transport = (uint32_t) tneigh;
3588   my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
3589   GNUNET_free (keyfile);
3590   if (my_private_key == NULL)
3591     {
3592       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3593                   _
3594                   ("Transport service could not access hostkey.  Exiting.\n"));
3595       GNUNET_SCHEDULER_shutdown (s);
3596       if (stats != NULL)
3597         {
3598           GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
3599           stats = NULL;
3600         }
3601       GNUNET_CONTAINER_multihashmap_destroy (validation_map);
3602       validation_map = NULL;
3603       return;
3604     }
3605   GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
3606   GNUNET_CRYPTO_hash (&my_public_key,
3607                       sizeof (my_public_key), &my_identity.hashPubKey);
3608   /* setup notification */
3609   server = serv;
3610   GNUNET_SERVER_disconnect_notify (server,
3611                                    &client_disconnect_notification, NULL);
3612   /* load plugins... */
3613   no_transports = 1;
3614   if (GNUNET_OK ==
3615       GNUNET_CONFIGURATION_get_value_string (c,
3616                                              "TRANSPORT", "PLUGINS", &plugs))
3617     {
3618       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3619                   _("Starting transport plugins `%s'\n"), plugs);
3620       pos = strtok (plugs, " ");
3621       while (pos != NULL)
3622         {
3623           start_transport (server, pos);
3624           no_transports = 0;
3625           pos = strtok (NULL, " ");
3626         }
3627       GNUNET_free (plugs);
3628     }
3629   GNUNET_SCHEDULER_add_delayed (sched,
3630                                 GNUNET_TIME_UNIT_FOREVER_REL,
3631                                 &shutdown_task, NULL);
3632   if (no_transports)
3633     refresh_hello ();
3634
3635 #if DEBUG_TRANSPORT
3636   GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
3637 #endif
3638   /* process client requests */
3639   GNUNET_SERVER_add_handlers (server, handlers);
3640 }
3641
3642
3643 /**
3644  * The main function for the transport service.
3645  *
3646  * @param argc number of arguments from the command line
3647  * @param argv command line arguments
3648  * @return 0 ok, 1 on error
3649  */
3650 int
3651 main (int argc, char *const *argv)
3652 {
3653   return (GNUNET_OK ==
3654           GNUNET_SERVICE_run (argc,
3655                               argv,
3656                               "transport",
3657                               GNUNET_SERVICE_OPTION_NONE,
3658                               &run, NULL)) ? 0 : 1;
3659 }
3660
3661 /* end of gnunet-service-transport.c */