(no commit message)
[oweals/gnunet.git] / src / transport / gnunet-service-transport.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009, 2010 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 3, 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  */
27 #include "platform.h"
28 #include "gnunet_client_lib.h"
29 #include "gnunet_container_lib.h"
30 #include "gnunet_constants.h"
31 #include "gnunet_getopt_lib.h"
32 #include "gnunet_hello_lib.h"
33 #include "gnunet_os_lib.h"
34 #include "gnunet_peerinfo_service.h"
35 #include "gnunet_plugin_lib.h"
36 #include "gnunet_protocols.h"
37 #include "gnunet_service_lib.h"
38 #include "gnunet_signatures.h"
39 #include "gnunet_transport_plugin.h"
40 #include "transport.h"
41 #if HAVE_LIBGLPK
42 #include <glpk.h>
43 #endif
44
45 #define DEBUG_BLACKLIST GNUNET_NO
46
47 #define DEBUG_PING_PONG GNUNET_NO
48
49 #define DEBUG_TRANSPORT_HELLO GNUNET_NO
50
51 /**
52  * Should we do some additional checks (to validate behavior
53  * of clients)?
54  */
55 #define EXTRA_CHECKS GNUNET_YES
56
57 /**
58  * How many messages can we have pending for a given client process
59  * before we start to drop incoming messages?  We typically should
60  * have only one client and so this would be the primary buffer for
61   * messages, so the number should be chosen rather generously.
62  *
63  * The expectation here is that most of the time the queue is large
64  * enough so that a drop is virtually never required.  Note that
65  * this value must be about as large as 'TOTAL_MSGS' in the
66  * 'test_transport_api_reliability.c', otherwise that testcase may
67  * fail.
68  */
69 #define MAX_PENDING (128 * 1024)
70
71 /**
72  * Size of the per-transport blacklist hash maps.
73  */
74 #define TRANSPORT_BLACKLIST_HT_SIZE 16
75
76 /**
77  * How often should we try to reconnect to a peer using a particular
78  * transport plugin before giving up?  Note that the plugin may be
79  * added back to the list after PLUGIN_RETRY_FREQUENCY expires.
80  */
81 #define MAX_CONNECT_RETRY 3
82
83 /**
84  * Limit on the number of ready-to-run tasks when validating
85  * HELLOs.  If more tasks are ready to run, we will drop
86  * HELLOs instead of validating them.
87  */
88 #define MAX_HELLO_LOAD 4
89
90 /**
91  * How often must a peer violate bandwidth quotas before we start
92  * to simply drop its messages?
93  */
94 #define QUOTA_VIOLATION_DROP_THRESHOLD 10
95
96 /**
97  * How long until a HELLO verification attempt should time out?
98  * Must be rather small, otherwise a partially successful HELLO
99  * validation (some addresses working) might not be available
100  * before a client's request for a connection fails for good.
101  * Besides, if a single request to an address takes a long time,
102  * then the peer is unlikely worthwhile anyway.
103  */
104 #define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
105
106 /**
107  * How long is a PONG signature valid?  We'll recycle a signature until
108  * 1/4 of this time is remaining.  PONGs should expire so that if our
109  * external addresses change an adversary cannot replay them indefinitely.
110  * OTOH, we don't want to spend too much time generating PONG signatures,
111  * so they must have some lifetime to reduce our CPU usage.
112  */
113 #define PONG_SIGNATURE_LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
114
115 /**
116  * Priority to use for PONG messages.
117  */
118 #define TRANSPORT_PONG_PRIORITY 4
119
120 /**
121  * How often do we re-add (cheaper) plugins to our list of plugins
122  * to try for a given connected peer?
123  */
124 #define PLUGIN_RETRY_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
125
126 /**
127  * After how long do we expire an address in a HELLO that we just
128  * validated?  This value is also used for our own addresses when we
129  * create a HELLO.
130  */
131 #define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
132
133
134 /**
135  * How long before an existing address expires should we again try to
136  * validate it?  Must be (significantly) smaller than
137  * HELLO_ADDRESS_EXPIRATION.
138  */
139 #define HELLO_REVALIDATION_START_TIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
140
141 /**
142  * Maximum frequency for re-evaluating latencies for all transport addresses.
143  */
144 #define LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
145
146 /**
147  * Maximum frequency for re-evaluating latencies for connected addresses.
148  */
149 #define CONNECTED_LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
150
151 #define VERY_BIG_DOUBLE_VALUE 100000000000LL
152
153 /**
154  * List of addresses of other peers
155  */
156 struct ForeignAddressList
157 {
158   /**
159    * This is a linked list.
160    */
161   struct ForeignAddressList *next;
162
163   /**
164    * Which ready list does this entry belong to.
165    */
166   struct ReadyList *ready_list;
167
168   /**
169    * How long until we auto-expire this address (unless it is
170    * re-confirmed by the transport)?
171    */
172   struct GNUNET_TIME_Absolute expires;
173
174   /**
175    * Task used to re-validate addresses, updates latencies and
176    * verifies liveness.
177    */
178   GNUNET_SCHEDULER_TaskIdentifier revalidate_task;
179
180   /**
181    * The address.
182    */
183   const void *addr;
184
185   /**
186    * Session (or NULL if no valid session currently exists or if the
187    * plugin does not use sessions).
188    */
189   struct Session *session;
190
191   struct ATS_ressource_entry * ressources;
192
193   /**
194    * What was the last latency observed for this address, plugin and peer?
195    */
196   struct GNUNET_TIME_Relative latency;
197
198   /**
199    * If we did not successfully transmit a message to the given peer
200    * via this connection during the specified time, we should consider
201    * the connection to be dead.  This is used in the case that a TCP
202    * transport simply stalls writing to the stream but does not
203    * formerly get a signal that the other peer died.
204    */
205   struct GNUNET_TIME_Absolute timeout;
206
207   /**
208    * How often have we tried to connect using this plugin?  Used to
209    * discriminate against addresses that do not work well.
210    * FIXME: not yet used, but should be!
211    */
212   unsigned int connect_attempts;
213
214   /**
215    * DV distance to this peer (1 if no DV is used).
216    * FIXME: need to set this from transport plugins!
217    */
218   uint32_t distance;
219
220   /**
221    * Length of addr.
222    */
223   uint16_t addrlen;
224
225   /**
226    * Have we ever estimated the latency of this address?  Used to
227    * ensure that the first time we add an address, we immediately
228    * probe its latency.
229    */
230   int8_t estimated;
231
232   /**
233    * Are we currently connected via this address?  The first time we
234    * successfully transmit or receive data to a peer via a particular
235    * address, we set this to GNUNET_YES.  If we later get an error
236    * (disconnect notification, transmission failure, timeout), we set
237    * it back to GNUNET_NO.
238    */
239   int8_t connected;
240
241   /**
242    * Is this plugin currently busy transmitting to the specific target?
243    * GNUNET_NO if not (initial, default state is GNUNET_NO).   Internal
244    * messages do not count as 'in transmit'.
245    */
246   int8_t in_transmit;
247
248   /**
249    * Has this address been validated yet?
250    */
251   int8_t validated;
252
253 };
254
255
256 /**
257  * Entry in linked list of network addresses for ourselves.  Also
258  * includes a cached signature for 'struct TransportPongMessage's.
259  */
260 struct OwnAddressList
261 {
262   /**
263    * This is a linked list.
264    */
265   struct OwnAddressList *next;
266
267   /**
268    * How long until we actually auto-expire this address (unless it is
269    * re-confirmed by the transport)?
270    */
271   struct GNUNET_TIME_Absolute expires;
272
273   /**
274    * How long until the current signature expires? (ZERO if the
275    * signature was never created).
276    */
277   struct GNUNET_TIME_Absolute pong_sig_expires;
278
279   /**
280    * Signature for a 'struct TransportPongMessage' for this address.
281    */
282   struct GNUNET_CRYPTO_RsaSignature pong_signature;
283
284   /**
285    * Length of addr.
286    */
287   uint32_t addrlen;
288
289 };
290
291
292 /**
293  * Entry in linked list of all of our plugins.
294  */
295 struct TransportPlugin
296 {
297
298   /**
299    * This is a linked list.
300    */
301   struct TransportPlugin *next;
302
303   /**
304    * API of the transport as returned by the plugin's
305    * initialization function.
306    */
307   struct GNUNET_TRANSPORT_PluginFunctions *api;
308
309   /**
310    * Short name for the plugin (i.e. "tcp").
311    */
312   char *short_name;
313
314   /**
315    * Name of the library (i.e. "gnunet_plugin_transport_tcp").
316    */
317   char *lib_name;
318
319   /**
320    * List of our known addresses for this transport.
321    */
322   struct OwnAddressList *addresses;
323
324   /**
325    * Environment this transport service is using
326    * for this plugin.
327    */
328   struct GNUNET_TRANSPORT_PluginEnvironment env;
329
330   /**
331    * ID of task that is used to clean up expired addresses.
332    */
333   GNUNET_SCHEDULER_TaskIdentifier address_update_task;
334
335   /**
336    * Set to GNUNET_YES if we need to scrap the existing list of
337    * "addresses" and start fresh when we receive the next address
338    * update from a transport.  Set to GNUNET_NO if we should just add
339    * the new address to the list and wait for the commit call.
340    */
341   int rebuild;
342
343   struct ATS_plugin * rc;
344
345   /**
346    * Hashmap of blacklisted peers for this particular transport.
347    */
348   struct GNUNET_CONTAINER_MultiHashMap *blacklist;
349 };
350
351 struct NeighbourList;
352
353 /**
354  * For each neighbour we keep a list of messages
355  * that we still want to transmit to the neighbour.
356  */
357 struct MessageQueue
358 {
359
360   /**
361    * This is a doubly linked list.
362    */
363   struct MessageQueue *next;
364
365   /**
366    * This is a doubly linked list.
367    */
368   struct MessageQueue *prev;
369
370   /**
371    * The message(s) we want to transmit, GNUNET_MessageHeader(s)
372    * stuck together in memory.  Allocated at the end of this struct.
373    */
374   const char *message_buf;
375
376   /**
377    * Size of the message buf
378    */
379   size_t message_buf_size;
380
381   /**
382    * Client responsible for queueing the message;
383    * used to check that a client has no two messages
384    * pending for the same target.  Can be NULL.
385    */
386   struct TransportClient *client;
387
388   /**
389    * Using which specific address should we send this message?
390    */
391   struct ForeignAddressList *specific_address;
392
393   /**
394    * Peer ID of the Neighbour this entry belongs to.
395    */
396   struct GNUNET_PeerIdentity neighbour_id;
397
398   /**
399    * Plugin that we used for the transmission.
400    * NULL until we scheduled a transmission.
401    */
402   struct TransportPlugin *plugin;
403
404   /**
405    * At what time should we fail?
406    */
407   struct GNUNET_TIME_Absolute timeout;
408
409   /**
410    * Internal message of the transport system that should not be
411    * included in the usual SEND-SEND_OK transmission confirmation
412    * traffic management scheme.  Typically, "internal_msg" will
413    * be set whenever "client" is NULL (but it is not strictly
414    * required).
415    */
416   int internal_msg;
417
418   /**
419    * How important is the message?
420    */
421   unsigned int priority;
422
423 };
424
425
426 /**
427  * For a given Neighbour, which plugins are available
428  * to talk to this peer and what are their costs?
429  */
430 struct ReadyList
431 {
432   /**
433    * This is a linked list.
434    */
435   struct ReadyList *next;
436
437   /**
438    * Which of our transport plugins does this entry
439    * represent?
440    */
441   struct TransportPlugin *plugin;
442
443   /**
444    * Transport addresses, latency, and readiness for
445    * this particular plugin.
446    */
447   struct ForeignAddressList *addresses;
448
449   /**
450    * To which neighbour does this ready list belong to?
451    */
452   struct NeighbourList *neighbour;
453 };
454
455
456 /**
457  * Entry in linked list of all of our current neighbours.
458  */
459 struct NeighbourList
460 {
461
462   /**
463    * This is a linked list.
464    */
465   struct NeighbourList *next;
466
467   /**
468    * Which of our transports is connected to this peer
469    * and what is their status?
470    */
471   struct ReadyList *plugins;
472
473   /**
474    * Head of list of messages we would like to send to this peer;
475    * must contain at most one message per client.
476    */
477   struct MessageQueue *messages_head;
478
479   /**
480    * Tail of list of messages we would like to send to this peer; must
481    * contain at most one message per client.
482    */
483   struct MessageQueue *messages_tail;
484
485   /**
486    * Buffer for at most one payload message used when we receive
487    * payload data before our PING-PONG has succeeded.  We then
488    * store such messages in this intermediary buffer until the
489    * connection is fully up.
490    */
491   struct GNUNET_MessageHeader *pre_connect_message_buffer;
492
493   /**
494    * Context for peerinfo iteration.
495    * NULL after we are done processing peerinfo's information.
496    */
497   struct GNUNET_PEERINFO_IteratorContext *piter;
498
499   /**
500    * Public key for this peer.   Valid only if the respective flag is set below.
501    */
502   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
503
504   /**
505    * Identity of this neighbour.
506    */
507   struct GNUNET_PeerIdentity id;
508
509   /**
510    * ID of task scheduled to run when this peer is about to
511    * time out (will free resources associated with the peer).
512    */
513   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
514
515   /**
516    * ID of task scheduled to run when we should retry transmitting
517    * the head of the message queue.  Actually triggered when the
518    * transmission is timing out (we trigger instantly when we have
519    * a chance of success).
520    */
521   GNUNET_SCHEDULER_TaskIdentifier retry_task;
522
523   /**
524    * How long until we should consider this peer dead
525    * (if we don't receive another message in the
526    * meantime)?
527    */
528   struct GNUNET_TIME_Absolute peer_timeout;
529
530   /**
531    * Tracker for inbound bandwidth.
532    */
533   struct GNUNET_BANDWIDTH_Tracker in_tracker;
534
535   /**
536    * The latency we have seen for this particular address for
537    * this particular peer.  This latency may have been calculated
538    * over multiple transports.  This value reflects how long it took
539    * us to receive a response when SENDING via this particular
540    * transport/neighbour/address combination!
541    *
542    * FIXME: we need to periodically send PINGs to update this
543    * latency (at least more often than the current "huge" (11h?)
544    * update interval).
545    */
546   struct GNUNET_TIME_Relative latency;
547
548   /**
549    * How often has the other peer (recently) violated the
550    * inbound traffic limit?  Incremented by 10 per violation,
551    * decremented by 1 per non-violation (for each
552    * time interval).
553    */
554   unsigned int quota_violation_count;
555
556   /**
557    * DV distance to this peer (1 if no DV is used).
558    */
559   uint32_t distance;
560
561   /**
562    * Have we seen an PONG from this neighbour in the past (and
563    * not had a disconnect since)?
564    */
565   int received_pong;
566
567   /**
568    * Do we have a valid public key for this neighbour?
569    */
570   int public_key_valid;
571
572   /**
573    * Performance data for the peer.
574    */
575   struct GNUNET_TRANSPORT_ATS_Information *ats;
576
577   /**
578    * Identity of the neighbour.
579    */
580   struct GNUNET_PeerIdentity peer;
581
582 };
583
584 /**
585  * Message used to ask a peer to validate receipt (to check an address
586  * from a HELLO).  Followed by the address we are trying to validate,
587  * or an empty address if we are just sending a PING to confirm that a
588  * connection which the receiver (of the PING) initiated is still valid.
589  */
590 struct TransportPingMessage
591 {
592
593   /**
594    * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
595    */
596   struct GNUNET_MessageHeader header;
597
598   /**
599    * Challenge code (to ensure fresh reply).
600    */
601   uint32_t challenge GNUNET_PACKED;
602
603   /**
604    * Who is the intended recipient?
605    */
606   struct GNUNET_PeerIdentity target;
607
608 };
609
610
611 /**
612  * Message used to validate a HELLO.  The challenge is included in the
613  * confirmation to make matching of replies to requests possible.  The
614  * signature signs our public key, an expiration time and our address.<p>
615  *
616  * This message is followed by our transport address that the PING tried
617  * to confirm (if we liked it).  The address can be empty (zero bytes)
618  * if the PING had not address either (and we received the request via
619  * a connection that we initiated).
620  */
621 struct TransportPongMessage
622 {
623
624   /**
625    * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
626    */
627   struct GNUNET_MessageHeader header;
628
629   /**
630    * Challenge code from PING (showing freshness).  Not part of what
631    * is signed so that we can re-use signatures.
632    */
633   uint32_t challenge GNUNET_PACKED;
634
635   /**
636    * Signature.
637    */
638   struct GNUNET_CRYPTO_RsaSignature signature;
639
640   /**
641    * What are we signing and why?  Two possible reason codes can be here:
642    * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN to confirm that this is a
643    * plausible address for this peer (pid is set to identity of signer); or
644    * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING to confirm that this is
645    * an address we used to connect to the peer with the given pid.
646    */
647   struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
648
649   /**
650    * When does this signature expire?
651    */
652   struct GNUNET_TIME_AbsoluteNBO expiration;
653
654   /**
655    * Either the identity of the peer Who signed this message, or the
656    * identity of the peer that we're connected to using the given
657    * address (depending on purpose.type).
658    */
659   struct GNUNET_PeerIdentity pid;
660
661   /**
662    * Size of address appended to this message (part of what is
663    * being signed, hence not redundant).
664    */
665   uint32_t addrlen;
666
667 };
668
669
670 /**
671  * Linked list of messages to be transmitted to the client.  Each
672  * entry is followed by the actual message.
673  */
674 struct ClientMessageQueueEntry
675 {
676   /**
677    * This is a doubly-linked list.
678    */
679   struct ClientMessageQueueEntry *next;
680
681   /**
682    * This is a doubly-linked list.
683    */
684   struct ClientMessageQueueEntry *prev;
685 };
686
687
688 /**
689  * Client connected to the transport service.
690  */
691 struct TransportClient
692 {
693
694   /**
695    * This is a linked list.
696    */
697   struct TransportClient *next;
698
699   /**
700    * Handle to the client.
701    */
702   struct GNUNET_SERVER_Client *client;
703
704   /**
705    * Linked list of messages yet to be transmitted to
706    * the client.
707    */
708   struct ClientMessageQueueEntry *message_queue_head;
709
710   /**
711    * Tail of linked list of messages yet to be transmitted to the
712    * client.
713    */
714   struct ClientMessageQueueEntry *message_queue_tail;
715
716   /**
717    * Current transmit request handle.
718    */
719   struct GNUNET_CONNECTION_TransmitHandle *th;
720
721   /**
722    * Is a call to "transmit_send_continuation" pending?  If so, we
723    * must not free this struct (even if the corresponding client
724    * disconnects) and instead only remove it from the linked list and
725    * set the "client" field to NULL.
726    */
727   int tcs_pending;
728
729   /**
730    * Length of the list of messages pending for this client.
731    */
732   unsigned int message_count;
733
734 };
735
736
737 /**
738  * Context of currently active requests to peerinfo
739  * for validation of HELLOs.
740  */
741 struct CheckHelloValidatedContext;
742
743
744 /**
745  * Entry in map of all HELLOs awaiting validation.
746  */
747 struct ValidationEntry
748 {
749
750   /**
751    * NULL if this entry is not part of a larger HELLO validation.
752    */
753   struct CheckHelloValidatedContext *chvc;
754
755   /**
756    * The address, actually a pointer to the end
757    * of this struct.  Do not free!
758    */
759   const void *addr;
760
761   /**
762    * Name of the transport.
763    */
764   char *transport_name;
765
766   /**
767    * The public key of the peer.
768    */
769   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
770
771   /**
772    * ID of task that will clean up this entry if we don't succeed
773    * with the validation first.
774    */
775   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
776
777   /**
778    * At what time did we send this validation?
779    */
780   struct GNUNET_TIME_Absolute send_time;
781
782   /**
783    * Session being validated (or NULL for none).
784    */
785   struct Session *session;
786
787   /**
788    * Challenge number we used.
789    */
790   uint32_t challenge;
791
792   /**
793    * Length of addr.
794    */
795   uint16_t addrlen;
796
797 };
798
799
800 /**
801  * Context of currently active requests to peerinfo
802  * for validation of HELLOs.
803  */
804 struct CheckHelloValidatedContext
805 {
806
807   /**
808    * This is a doubly-linked list.
809    */
810   struct CheckHelloValidatedContext *next;
811
812   /**
813    * This is a doubly-linked list.
814    */
815   struct CheckHelloValidatedContext *prev;
816
817   /**
818    * Hello that we are validating.
819    */
820   const struct GNUNET_HELLO_Message *hello;
821
822   /**
823    * Context for peerinfo iteration.
824    * NULL after we are done processing peerinfo's information.
825    */
826   struct GNUNET_PEERINFO_IteratorContext *piter;
827
828   /**
829    * Was a HELLO known for this peer to peerinfo?
830    */
831   int hello_known;
832
833   /**
834    * Number of validation entries currently referring to this
835    * CHVC.
836    */
837   unsigned int ve_count;
838 };
839
840 struct ATS_quality_metric
841 {
842         int index;
843         int atis_index;
844         char * name;
845 };
846
847 struct ATS_mechanism
848 {
849         struct ATS_mechanism * prev;
850         struct ATS_mechanism * next;
851         struct ForeignAddressList * addr;
852         struct TransportPlugin * plugin;
853         struct ATS_peer * peer;
854         int col_index;
855         int     id;
856         struct ATS_ressource_cost * rc;
857 };
858
859 struct ATS_peer
860 {
861         int id;
862         struct GNUNET_PeerIdentity peer;
863         struct NeighbourList * n;
864         struct ATS_mechanism * m_head;
865         struct ATS_mechanism * m_tail;
866
867         /* preference value f */
868         double f;
869         int     t;
870 };
871
872 struct ATS_result
873 {
874         int c_mechs;
875         int c_peers;
876         int solution;
877 };
878
879 struct ATS_ressource_entry
880 {
881         /* index in ressources array */
882         int index;
883         /* depending ATSi parameter to calculcate limits */
884         int atis_index;
885         /* lower bound */
886         double c;
887 };
888
889
890 struct ATS_ressource
891 {
892         /* index in ressources array */
893         int index;
894         /* depending ATSi parameter to calculcate limits */
895         int atis_index;
896         /* cfg option to load limits */
897         char * cfg_param;
898         /* lower bound */
899         double c_min;
900         /* upper bound */
901         double c_max;
902
903         /* cofficients for the specific plugins */
904         double c_unix;
905         double c_tcp;
906         double c_udp;
907         double c_http;
908         double c_https;
909         double c_wlan;
910         double c_default;
911 };
912
913 static struct ATS_ressource ressources[] =
914 {
915                 /* FIXME: the coefficients for the specific plugins */
916                 {1, 7, "LAN_BW_LIMIT", 0, VERY_BIG_DOUBLE_VALUE, 0, 1, 1, 2, 2, 1, 3},
917                 {2, 7, "WAN_BW_LIMIT", 0, VERY_BIG_DOUBLE_VALUE, 0, 1, 1, 2, 2, 2, 3},
918                 {3, 4, "WLAN_ENERGY_LIMIT", 0, VERY_BIG_DOUBLE_VALUE, 0, 0, 0, 0, 0, 2, 1}
919 /*
920                 {4, 4, "COST_ENERGY_CONSUMPTION", VERY_BIG_DOUBLE_VALUE},
921                 {5, 5, "COST_CONNECT", VERY_BIG_DOUBLE_VALUE},
922                 {6, 6, "COST_BANDWITH_AVAILABLE", VERY_BIG_DOUBLE_VALUE},
923                 {7, 7, "COST_NETWORK_OVERHEAD", VERY_BIG_DOUBLE_VALUE},*/
924 };
925
926 static int available_ressources = 3;
927
928
929
930 struct ATS_info
931 {
932
933         /**
934          * Time of last execution
935          */
936         struct GNUNET_TIME_Absolute last;
937         /**
938          * Minimum intervall between two executions
939          */
940         struct GNUNET_TIME_Relative min_delta;
941         /**
942          * Regular intervall when execution is triggered
943          */
944         struct GNUNET_TIME_Relative exec_intervall;
945         /**
946          * Maximum execution time per calculation
947          */
948         struct GNUNET_TIME_Relative max_exec_duration;
949         /**
950          * Maximum number of LP iterations per calculation
951          */
952         int max_iterations;
953
954         GNUNET_SCHEDULER_TaskIdentifier ats_task;
955
956         struct ATS_plugin * head;
957         struct ATS_plugin * tail;
958 };
959
960
961 /**
962  * Our HELLO message.
963  */
964 static struct GNUNET_HELLO_Message *our_hello;
965
966 /**
967  * Our public key.
968  */
969 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
970
971 /**
972  * Our identity.
973  */
974 static struct GNUNET_PeerIdentity my_identity;
975
976 /**
977  * Our private key.
978  */
979 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
980
981 /**
982  * Our configuration.
983  */
984 const struct GNUNET_CONFIGURATION_Handle *cfg;
985
986 /**
987  * Linked list of all clients to this service.
988  */
989 static struct TransportClient *clients;
990
991 /**
992  * All loaded plugins.
993  */
994 static struct TransportPlugin *plugins;
995
996 /**
997  * Handle to peerinfo service.
998  */
999 static struct GNUNET_PEERINFO_Handle *peerinfo;
1000
1001 /**
1002  * All known neighbours and their HELLOs.
1003  */
1004 static struct NeighbourList *neighbours;
1005
1006 /**
1007  * Number of neighbours we'd like to have.
1008  */
1009 static uint32_t max_connect_per_transport;
1010
1011 /**
1012  * Head of linked list.
1013  */
1014 static struct CheckHelloValidatedContext *chvc_head;
1015
1016 /**
1017  * Tail of linked list.
1018  */
1019 static struct CheckHelloValidatedContext *chvc_tail;
1020
1021 /**
1022  * Map of PeerIdentities to 'struct ValidationEntry*'s (addresses
1023  * of the given peer that we are currently validating).
1024  */
1025 static struct GNUNET_CONTAINER_MultiHashMap *validation_map;
1026
1027 /**
1028  * Handle for reporting statistics.
1029  */
1030 static struct GNUNET_STATISTICS_Handle *stats;
1031
1032 /**
1033  * Handle for ats information
1034  */
1035 static struct ATS_info *ats;
1036
1037 #if HAVE_LIBGLPK
1038 static struct ATS_quality_metric qm[] =
1039 {
1040                 {1, 1028, "QUALITY_NET_DISTANCE"},
1041                 {2, 1034, "QUALITY_NET_DELAY"},
1042 };
1043 static int available_quality_metrics = 2;
1044 #endif
1045
1046 /**
1047  * The peer specified by the given neighbour has timed-out or a plugin
1048  * has disconnected.  We may either need to do nothing (other plugins
1049  * still up), or trigger a full disconnect and clean up.  This
1050  * function updates our state and do the necessary notifications.
1051  * Also notifies our clients that the neighbour is now officially
1052  * gone.
1053  *
1054  * @param n the neighbour list entry for the peer
1055  * @param check should we just check if all plugins
1056  *        disconnected or must we ask all plugins to
1057  *        disconnect?
1058  */
1059 static void disconnect_neighbour (struct NeighbourList *n, int check);
1060
1061 /**
1062  * Check the ready list for the given neighbour and if a plugin is
1063  * ready for transmission (and if we have a message), do so!
1064  *
1065  * @param nexi target peer for which to transmit
1066  */
1067 static void try_transmission_to_peer (struct NeighbourList *n);
1068
1069
1070 void ats_init ();
1071
1072 void ats_shutdown ( );
1073
1074 void ats_notify_peer_connect (
1075                 const struct GNUNET_PeerIdentity *peer,
1076                 const struct GNUNET_TRANSPORT_ATS_Information *ats_data);
1077
1078 void ats_notify_peer_disconnect (
1079                 const struct GNUNET_PeerIdentity *peer);
1080
1081 void ats_notify_ats_data (
1082                 const struct GNUNET_PeerIdentity *peer,
1083                 const struct GNUNET_TRANSPORT_ATS_Information *ats_data);
1084
1085 struct ForeignAddressList * ats_get_preferred_address (
1086                 struct NeighbourList *n);
1087
1088 /**
1089  * Find an entry in the neighbour list for a particular peer.
1090  *
1091  * @return NULL if not found.
1092  */
1093 static struct NeighbourList *
1094 find_neighbour (const struct GNUNET_PeerIdentity *key)
1095 {
1096   struct NeighbourList *head = neighbours;
1097
1098   while ((head != NULL) &&
1099         (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
1100     head = head->next;
1101   return head;
1102 }
1103
1104
1105 /**
1106  * Find an entry in the transport list for a particular transport.
1107  *
1108  * @return NULL if not found.
1109  */
1110 static struct TransportPlugin *
1111 find_transport (const char *short_name)
1112 {
1113   struct TransportPlugin *head = plugins;
1114   while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
1115     head = head->next;
1116   return head;
1117 }
1118
1119 /**
1120  * Is a particular peer blacklisted for a particular transport?
1121  *
1122  * @param peer the peer to check for
1123  * @param plugin the plugin used to connect to the peer
1124  *
1125  * @return GNUNET_YES if the peer is blacklisted, GNUNET_NO if not
1126  */
1127 static int
1128 is_blacklisted (const struct GNUNET_PeerIdentity *peer, struct TransportPlugin *plugin)
1129 {
1130
1131   if (plugin->blacklist != NULL)
1132     {
1133       if (GNUNET_CONTAINER_multihashmap_contains (plugin->blacklist, &peer->hashPubKey) == GNUNET_YES)
1134         {
1135 #if DEBUG_BLACKLIST
1136           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1137                       "Peer `%s:%s' is blacklisted!\n",
1138                       plugin->short_name, GNUNET_i2s (peer));
1139 #endif
1140           if (stats != NULL)
1141             GNUNET_STATISTICS_update (stats, "# blacklisted peers refused", 1, GNUNET_NO);
1142           return GNUNET_YES;
1143         }
1144     }
1145
1146   return GNUNET_NO;
1147 }
1148
1149
1150 static void
1151 add_peer_to_blacklist (struct GNUNET_PeerIdentity *peer, char *transport_name)
1152 {
1153   struct TransportPlugin *plugin;
1154
1155   plugin = find_transport(transport_name);
1156   if (plugin == NULL) /* Nothing to do */
1157     return;
1158   if (plugin->blacklist == NULL)
1159     plugin->blacklist = GNUNET_CONTAINER_multihashmap_create(TRANSPORT_BLACKLIST_HT_SIZE);
1160   GNUNET_assert(plugin->blacklist != NULL);
1161   GNUNET_CONTAINER_multihashmap_put(plugin->blacklist, &peer->hashPubKey,
1162                                     NULL,
1163                                     GNUNET_CONTAINER_MULTIHASHMAPOPTION_REPLACE);
1164 }
1165
1166
1167 /**
1168  * Read the blacklist file, containing transport:peer entries.
1169  * Provided the transport is loaded, set up hashmap with these
1170  * entries to blacklist peers by transport.
1171  *
1172  */
1173 static void
1174 read_blacklist_file (const struct GNUNET_CONFIGURATION_Handle *cfg)
1175 {
1176   char *fn;
1177   char *data;
1178   size_t pos;
1179   size_t colon_pos;
1180   int tsize;
1181   struct GNUNET_PeerIdentity pid;
1182   struct stat frstat;
1183   struct GNUNET_CRYPTO_HashAsciiEncoded enc;
1184   unsigned int entries_found;
1185   char *transport_name;
1186
1187   if (GNUNET_OK !=
1188       GNUNET_CONFIGURATION_get_value_filename (cfg,
1189                                                "TRANSPORT",
1190                                                "BLACKLIST_FILE",
1191                                                &fn))
1192     {
1193 #if DEBUG_TRANSPORT
1194       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1195                   "Option `%s' in section `%s' not specified!\n",
1196                   "BLACKLIST_FILE",
1197                   "TRANSPORT");
1198 #endif
1199       return;
1200     }
1201   if (GNUNET_OK != GNUNET_DISK_file_test (fn))
1202     GNUNET_DISK_fn_write (fn, NULL, 0, GNUNET_DISK_PERM_USER_READ
1203         | GNUNET_DISK_PERM_USER_WRITE);
1204   if (0 != STAT (fn, &frstat))
1205     {
1206       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1207                   _("Could not read blacklist file `%s'\n"), fn);
1208       GNUNET_free (fn);
1209       return;
1210     }
1211   if (frstat.st_size == 0)
1212     {
1213 #if DEBUG_TRANSPORT
1214       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1215                   _("Blacklist file `%s' is empty.\n"),
1216                   fn);
1217 #endif
1218       GNUNET_free (fn);
1219       return;
1220     }
1221   /* FIXME: use mmap */
1222   data = GNUNET_malloc_large (frstat.st_size);
1223   GNUNET_assert(data != NULL);
1224   if (frstat.st_size !=
1225       GNUNET_DISK_fn_read (fn, data, frstat.st_size))
1226     {
1227       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1228                   _("Failed to read blacklist from `%s'\n"), fn);
1229       GNUNET_free (fn);
1230       GNUNET_free (data);
1231       return;
1232     }
1233   entries_found = 0;
1234   pos = 0;
1235   while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1236     pos++;
1237   while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) &&
1238          (pos <= frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
1239     {
1240       colon_pos = pos;
1241       while ((colon_pos < frstat.st_size) && (data[colon_pos] != ':') && !isspace ( (unsigned char) data[colon_pos]))
1242         colon_pos++;
1243
1244       if (colon_pos >= frstat.st_size)
1245         {
1246           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1247                       _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1248                       (unsigned long long) colon_pos);
1249           GNUNET_free (fn);
1250           GNUNET_free (data);
1251           return;
1252         }
1253
1254       if (isspace( (unsigned char) data[colon_pos]))
1255       {
1256         GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1257                     _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1258                     (unsigned long long) colon_pos);
1259         pos = colon_pos;
1260         while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1261           pos++;
1262         continue;
1263       }
1264       tsize = colon_pos - pos;
1265       if ((pos >= frstat.st_size) || (pos + tsize >= frstat.st_size) || (tsize == 0))
1266         {
1267           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1268                       _("Syntax error in blacklist file at offset %llu, giving up!\n"),
1269                       (unsigned long long) colon_pos);
1270           GNUNET_free (fn);
1271           GNUNET_free (data);
1272           return;
1273         }
1274
1275       if (tsize < 1)
1276         continue;
1277
1278       transport_name = GNUNET_malloc(tsize + 1);
1279       memcpy(transport_name, &data[pos], tsize);
1280       pos = colon_pos + 1;
1281 #if DEBUG_TRANSPORT
1282       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1283                   "Read transport name %s in blacklist file.\n",
1284                   transport_name);
1285 #endif
1286       memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
1287       if (!isspace ( (unsigned char) enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
1288         {
1289           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1290                       _("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
1291                       (unsigned long long) pos);
1292           pos++;
1293           while ((pos < frstat.st_size) && (!isspace ( (unsigned char) data[pos])))
1294             pos++;
1295           GNUNET_free_non_null(transport_name);
1296           continue;
1297         }
1298       enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
1299       if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string ((char *) &enc, &pid.hashPubKey))
1300         {
1301           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1302                       _("Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n"),
1303                       (unsigned long long) pos,
1304                       &enc);
1305         }
1306       else
1307         {
1308           if (0 != memcmp (&pid,
1309                            &my_identity,
1310                            sizeof (struct GNUNET_PeerIdentity)))
1311             {
1312               entries_found++;
1313               add_peer_to_blacklist (&pid,
1314                                      transport_name);
1315             }
1316           else
1317             {
1318               GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1319                           _("Found myself `%s' in blacklist (useless, ignored)\n"),
1320                           GNUNET_i2s (&pid));
1321             }
1322         }
1323       pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
1324       GNUNET_free_non_null(transport_name);
1325       while ((pos < frstat.st_size) && isspace ( (unsigned char) data[pos]))
1326         pos++;
1327     }
1328   GNUNET_STATISTICS_update (stats, "# Transport entries blacklisted", entries_found, GNUNET_NO);
1329   GNUNET_free (data);
1330   GNUNET_free (fn);
1331 }
1332
1333
1334 /**
1335  * Function called to notify a client about the socket being ready to
1336  * queue more data.  "buf" will be NULL and "size" zero if the socket
1337  * was closed for writing in the meantime.
1338  *
1339  * @param cls closure
1340  * @param size number of bytes available in buf
1341  * @param buf where the callee should write the message
1342  * @return number of bytes written to buf
1343  */
1344 static size_t
1345 transmit_to_client_callback (void *cls, size_t size, void *buf)
1346 {
1347   struct TransportClient *client = cls;
1348   struct ClientMessageQueueEntry *q;
1349   uint16_t msize;
1350   size_t tsize;
1351   const struct GNUNET_MessageHeader *msg;
1352   char *cbuf;
1353
1354   client->th = NULL;
1355   if (buf == NULL)
1356     {
1357 #if DEBUG_TRANSPORT
1358       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1359                   "Transmission to client failed, closing connection.\n");
1360 #endif
1361       /* fatal error with client, free message queue! */
1362       while (NULL != (q = client->message_queue_head))
1363         {
1364           GNUNET_STATISTICS_update (stats,
1365                                     gettext_noop ("# bytes discarded (could not transmit to client)"),
1366                                     ntohs (((const struct GNUNET_MessageHeader*)&q[1])->size),
1367                                     GNUNET_NO);
1368           GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1369                                        client->message_queue_tail,
1370                                        q);
1371           GNUNET_free (q);
1372         }
1373       client->message_count = 0;
1374       return 0;
1375     }
1376   cbuf = buf;
1377   tsize = 0;
1378   while (NULL != (q = client->message_queue_head))
1379     {
1380       msg = (const struct GNUNET_MessageHeader *) &q[1];
1381       msize = ntohs (msg->size);
1382       if (msize + tsize > size)
1383         break;
1384 #if DEBUG_TRANSPORT
1385       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1386                   "Transmitting message of type %u to client.\n",
1387                   ntohs (msg->type));
1388 #endif
1389       GNUNET_CONTAINER_DLL_remove (client->message_queue_head,
1390                                    client->message_queue_tail,
1391                                    q);
1392       memcpy (&cbuf[tsize], msg, msize);
1393       tsize += msize;
1394       GNUNET_free (q);
1395       client->message_count--;
1396     }
1397   if (NULL != q)
1398     {
1399       GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1400       client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1401                                                         msize,
1402                                                         GNUNET_TIME_UNIT_FOREVER_REL,
1403                                                         &transmit_to_client_callback,
1404                                                         client);
1405       GNUNET_assert (client->th != NULL);
1406     }
1407   return tsize;
1408 }
1409
1410
1411 /**
1412  * Convert an address to a string.
1413  *
1414  * @param plugin name of the plugin responsible for the address
1415  * @param addr binary address
1416  * @param addr_len number of bytes in addr
1417  * @return NULL on error, otherwise address string
1418  */
1419 static const char*
1420 a2s (const char *plugin,
1421      const void *addr,
1422      uint16_t addr_len)
1423 {
1424   struct TransportPlugin *p;
1425
1426   if (plugin == NULL)
1427     return NULL;
1428   p = find_transport (plugin);
1429   if (p == NULL)
1430     return NULL;
1431   return p->api->address_to_string (p->api->cls,
1432                                     addr,
1433                                     addr_len);
1434 }
1435
1436
1437 /**
1438  * Mark the given FAL entry as 'connected' (and hence preferred for
1439  * sending); also mark all others for the same peer as 'not connected'
1440  * (since only one can be preferred).
1441  *
1442  * @param fal address to set to 'connected'
1443  */
1444 static void
1445 mark_address_connected (struct ForeignAddressList *fal)
1446 {
1447   struct ForeignAddressList *pos;
1448   int cnt;
1449
1450   GNUNET_assert (GNUNET_YES == fal->validated);
1451   if (fal->connected == GNUNET_YES)
1452     return; /* nothing to do */
1453   cnt = GNUNET_YES;
1454   pos = fal->ready_list->addresses;
1455   while (pos != NULL)
1456     {
1457       if (GNUNET_YES == pos->connected)
1458         {
1459 #if DEBUG_TRANSPORT
1460           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1461                       "Marking address `%s' as no longer connected (due to connect on other address)\n",
1462                       a2s (pos->ready_list->plugin->short_name,
1463                            pos->addr,
1464                            pos->addrlen));
1465 #endif
1466           GNUNET_break (cnt == GNUNET_YES);
1467           cnt = GNUNET_NO;
1468           pos->connected = GNUNET_NO;
1469           GNUNET_STATISTICS_update (stats,
1470                                     gettext_noop ("# connected addresses"),
1471                                     -1,
1472                                     GNUNET_NO);
1473         }
1474       pos = pos->next;
1475     }
1476   fal->connected = GNUNET_YES;
1477   if (GNUNET_YES == cnt)
1478     {
1479       GNUNET_STATISTICS_update (stats,
1480                                 gettext_noop ("# connected addresses"),
1481                                 1,
1482                                 GNUNET_NO);
1483     }
1484 }
1485
1486
1487 /**
1488  * Send the specified message to the specified client.  Since multiple
1489  * messages may be pending for the same client at a time, this code
1490  * makes sure that no message is lost.
1491  *
1492  * @param client client to transmit the message to
1493  * @param msg the message to send
1494  * @param may_drop can this message be dropped if the
1495  *        message queue for this client is getting far too large?
1496  */
1497 static void
1498 transmit_to_client (struct TransportClient *client,
1499                     const struct GNUNET_MessageHeader *msg, int may_drop)
1500 {
1501   struct ClientMessageQueueEntry *q;
1502   uint16_t msize;
1503
1504   if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
1505     {
1506       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1507                   _
1508                   ("Dropping message of type %u and size %u, have %u messages pending (%u is the soft limit)\n"),
1509                   ntohs (msg->type),
1510                   ntohs (msg->size),
1511                   client->message_count,
1512                   MAX_PENDING);
1513       GNUNET_STATISTICS_update (stats,
1514                                 gettext_noop ("# messages dropped due to slow client"),
1515                                 1,
1516                                 GNUNET_NO);
1517       return;
1518     }
1519   msize = ntohs (msg->size);
1520   GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
1521   q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
1522   memcpy (&q[1], msg, msize);
1523   GNUNET_CONTAINER_DLL_insert_after (client->message_queue_head,
1524                                      client->message_queue_tail,
1525                                      client->message_queue_tail,
1526                                      q);                                
1527   client->message_count++;
1528   if (client->th == NULL)
1529     {
1530       client->th = GNUNET_SERVER_notify_transmit_ready (client->client,
1531                                                         msize,
1532                                                         GNUNET_TIME_UNIT_FOREVER_REL,
1533                                                         &transmit_to_client_callback,
1534                                                         client);
1535       GNUNET_assert (client->th != NULL);
1536     }
1537 }
1538
1539
1540 /**
1541  * Transmit a 'SEND_OK' notification to the given client for the
1542  * given neighbour.
1543  *
1544  * @param client who to notify
1545  * @param n neighbour to notify about, can be NULL (on failure)
1546  * @param target target of the transmission
1547  * @param result status code for the transmission request
1548  */
1549 static void
1550 transmit_send_ok (struct TransportClient *client,
1551                   struct NeighbourList *n,
1552                   const struct GNUNET_PeerIdentity *target,
1553                   int result)
1554 {
1555   struct SendOkMessage send_ok_msg;
1556
1557   send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1558   send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1559   send_ok_msg.success = htonl (result);
1560   if (n != NULL)
1561     send_ok_msg.latency = GNUNET_TIME_relative_hton (n->latency);
1562   else
1563     send_ok_msg.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_FOREVER_REL);
1564   send_ok_msg.peer = *target;
1565   transmit_to_client (client, &send_ok_msg.header, GNUNET_NO);
1566 }
1567
1568
1569 /**
1570  * Function called by the GNUNET_TRANSPORT_TransmitFunction
1571  * upon "completion" of a send request.  This tells the API
1572  * that it is now legal to send another message to the given
1573  * peer.
1574  *
1575  * @param cls closure, identifies the entry on the
1576  *            message queue that was transmitted and the
1577  *            client responsible for queuing the message
1578  * @param target the peer receiving the message
1579  * @param result GNUNET_OK on success, if the transmission
1580  *           failed, we should not tell the client to transmit
1581  *           more messages
1582  */
1583 static void
1584 transmit_send_continuation (void *cls,
1585                             const struct GNUNET_PeerIdentity *target,
1586                             int result)
1587 {
1588   struct MessageQueue *mq = cls;
1589   struct NeighbourList *n;
1590
1591   GNUNET_STATISTICS_update (stats,
1592                             gettext_noop ("# bytes pending with plugins"),
1593                             - (int64_t) mq->message_buf_size,
1594                             GNUNET_NO);
1595   if (result == GNUNET_OK)
1596     {
1597       GNUNET_STATISTICS_update (stats,
1598                                 gettext_noop ("# bytes successfully transmitted by plugins"),
1599                                 mq->message_buf_size,
1600                                 GNUNET_NO);
1601     }
1602   else
1603     {
1604       GNUNET_STATISTICS_update (stats,
1605                                 gettext_noop ("# bytes with transmission failure by plugins"),
1606                                 mq->message_buf_size,
1607                                 GNUNET_NO);
1608     }
1609   if (mq->specific_address != NULL)
1610     {
1611       if (result == GNUNET_OK)
1612         {
1613           mq->specific_address->timeout =
1614             GNUNET_TIME_relative_to_absolute
1615             (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1616           if (mq->specific_address->validated == GNUNET_YES)
1617             mark_address_connected (mq->specific_address);
1618         }
1619       else
1620         {
1621           if (mq->specific_address->connected != GNUNET_NO)
1622             {
1623 #if DEBUG_TRANSPORT
1624               GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1625                           "Marking address `%s' as no longer connected (due to transmission problem)\n",
1626                           a2s (mq->specific_address->ready_list->plugin->short_name,
1627                                mq->specific_address->addr,
1628                                mq->specific_address->addrlen));
1629 #endif
1630               GNUNET_STATISTICS_update (stats,
1631                                         gettext_noop ("# connected addresses"),
1632                                         -1,
1633                                         GNUNET_NO);
1634               mq->specific_address->connected = GNUNET_NO;
1635             }
1636         }
1637       if (! mq->internal_msg)
1638         mq->specific_address->in_transmit = GNUNET_NO;
1639     }
1640   n = find_neighbour(&mq->neighbour_id);
1641   if (mq->client != NULL)
1642     transmit_send_ok (mq->client, n, target, result);
1643   GNUNET_free (mq);
1644   if (n != NULL)
1645     try_transmission_to_peer (n);
1646 }
1647
1648
1649 /**
1650  * Find an address in any of the available transports for
1651  * the given neighbour that would be good for message
1652  * transmission.  This is essentially the transport selection
1653  * routine.
1654  *
1655  * @param neighbour for whom to select an address
1656  * @return selected address, NULL if we have none
1657  */
1658 struct ForeignAddressList *
1659 find_ready_address(struct NeighbourList *neighbour)
1660 {
1661   struct ReadyList *head = neighbour->plugins;
1662   struct ForeignAddressList *addresses;
1663   struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1664   struct ForeignAddressList *best_address;
1665
1666   /* Hack to prefer unix domain sockets */
1667   struct ForeignAddressList *unix_address = NULL;
1668
1669   best_address = NULL;
1670   while (head != NULL)
1671     {
1672       addresses = head->addresses;
1673       while (addresses != NULL)
1674         {
1675           if ( (addresses->timeout.abs_value < now.abs_value) &&
1676                (addresses->connected == GNUNET_YES) )
1677             {
1678 #if DEBUG_TRANSPORT
1679               GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1680                           "Marking long-time inactive connection to `%4s' as down.\n",
1681                           GNUNET_i2s (&neighbour->id));
1682 #endif
1683               GNUNET_STATISTICS_update (stats,
1684                                         gettext_noop ("# connected addresses"),
1685                                         -1,
1686                                         GNUNET_NO);
1687               addresses->connected = GNUNET_NO;
1688             }
1689           addresses = addresses->next;
1690         }
1691
1692       addresses = head->addresses;
1693       while (addresses != NULL)
1694         {
1695 #if DEBUG_TRANSPORT > 1
1696           if (addresses->addr != NULL)
1697             GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1698                         "Have address `%s' for peer `%4s' (status: %d, %d, %d, %u, %llums, %u)\n",
1699                         a2s (head->plugin->short_name,
1700                              addresses->addr,
1701                              addresses->addrlen),
1702                         GNUNET_i2s (&neighbour->id),
1703                         addresses->connected,
1704                         addresses->in_transmit,
1705                         addresses->validated,
1706                         addresses->connect_attempts,
1707                         (unsigned long long) addresses->timeout.abs_value,
1708                         (unsigned int) addresses->distance);
1709 #endif
1710                  if (0==strcmp(head->plugin->short_name,"unix"))
1711                  {
1712                          if ((unix_address == NULL) || ((unix_address != NULL) &&
1713                                  (addresses->latency.rel_value < unix_address->latency.rel_value)))
1714                                 unix_address = addresses;
1715                  }
1716           if ( ( (best_address == NULL) ||
1717                  (addresses->connected == GNUNET_YES) ||
1718                  (best_address->connected == GNUNET_NO) ) &&
1719                (addresses->in_transmit == GNUNET_NO) &&
1720                ( (best_address == NULL) ||
1721                  (addresses->latency.rel_value < best_address->latency.rel_value)) )
1722             best_address = addresses;
1723           /* FIXME: also give lower-latency addresses that are not
1724              connected a chance some times... */
1725           addresses = addresses->next;
1726         }
1727       if (unix_address != NULL)
1728           break;
1729       head = head->next;
1730     }
1731   if (unix_address != NULL)
1732   {
1733           best_address = unix_address;
1734 #if DEBUG_TRANSPORT
1735           GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found unix address, forced this address\n");
1736 #endif
1737   }
1738   if (best_address != NULL)
1739     {
1740 #if DEBUG_TRANSPORT
1741
1742           GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1743                   "Best address found (`%s') has latency of %llu ms.\n",
1744                   (best_address->addrlen > 0)
1745                   ? a2s (best_address->ready_list->plugin->short_name,
1746                        best_address->addr,
1747                        best_address->addrlen)
1748                   : "<inbound>",
1749                   best_address->latency.rel_value);
1750 #endif
1751     }
1752   else
1753     {
1754       GNUNET_STATISTICS_update (stats,
1755                                 gettext_noop ("# transmission attempts failed (no address)"),
1756                                 1,
1757                                 GNUNET_NO);
1758     }
1759
1760   return best_address;
1761
1762 }
1763
1764
1765 /**
1766  * We should re-try transmitting to the given peer,
1767  * hopefully we've learned something in the meantime.
1768  */
1769 static void
1770 retry_transmission_task (void *cls,
1771                          const struct GNUNET_SCHEDULER_TaskContext *tc)
1772 {
1773   struct NeighbourList *n = cls;
1774
1775   n->retry_task = GNUNET_SCHEDULER_NO_TASK;
1776   try_transmission_to_peer (n);
1777 }
1778
1779
1780 /**
1781  * Check the ready list for the given neighbour and if a plugin is
1782  * ready for transmission (and if we have a message), do so!
1783  *
1784  * @param neighbour target peer for which to transmit
1785  */
1786 static void
1787 try_transmission_to_peer (struct NeighbourList *n)
1788 {
1789   struct ReadyList *rl;
1790   struct MessageQueue *mq;
1791   struct GNUNET_TIME_Relative timeout;
1792   ssize_t ret;
1793   int force_address;
1794
1795   if (n->messages_head == NULL)
1796     {
1797 #if DEBUG_TRANSPORT
1798       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1799                   "Transmission queue for `%4s' is empty\n",
1800                   GNUNET_i2s (&neighbour->id));
1801 #endif
1802       return;                     /* nothing to do */
1803     }
1804   rl = NULL;
1805   mq = n->messages_head;
1806   force_address = GNUNET_YES;
1807   if (mq->specific_address == NULL)
1808     {
1809           /* TODO: ADD ATS */
1810       mq->specific_address = ats_get_preferred_address(n);
1811       GNUNET_STATISTICS_update (stats,
1812                                 gettext_noop ("# transport selected peer address freely"),
1813                                 1,
1814                                 GNUNET_NO);
1815       force_address = GNUNET_NO;
1816     }
1817   if (mq->specific_address == NULL)
1818     {
1819       GNUNET_STATISTICS_update (stats,
1820                                 gettext_noop ("# transport failed to selected peer address"),
1821                                 1,
1822                                 GNUNET_NO);
1823       timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
1824       if (timeout.rel_value == 0)
1825         {
1826 #if DEBUG_TRANSPORT
1827           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1828                       "No destination address available to transmit message of size %u to peer `%4s'\n",
1829                       mq->message_buf_size,
1830                       GNUNET_i2s (&mq->neighbour_id));
1831 #endif
1832           GNUNET_STATISTICS_update (stats,
1833                                     gettext_noop ("# bytes in message queue for other peers"),
1834                                     - (int64_t) mq->message_buf_size,
1835                                     GNUNET_NO);
1836           GNUNET_STATISTICS_update (stats,
1837                                     gettext_noop ("# bytes discarded (no destination address available)"),
1838                                     mq->message_buf_size,
1839                                     GNUNET_NO);
1840           if (mq->client != NULL)
1841             transmit_send_ok (mq->client, n, &n->id, GNUNET_NO);
1842           GNUNET_CONTAINER_DLL_remove (n->messages_head,
1843                                        n->messages_tail,
1844                                        mq);
1845           GNUNET_free (mq);
1846           return;               /* nobody ready */
1847         }
1848       GNUNET_STATISTICS_update (stats,
1849                                 gettext_noop ("# message delivery deferred (no address)"),
1850                                 1,
1851                                 GNUNET_NO);
1852       if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
1853         GNUNET_SCHEDULER_cancel (n->retry_task);
1854       n->retry_task = GNUNET_SCHEDULER_add_delayed (timeout,
1855                                                             &retry_transmission_task,
1856                                                             n);
1857 #if DEBUG_TRANSPORT
1858       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1859                   "No validated destination address available to transmit message of size %u to peer `%4s', will wait %llums to find an address.\n",
1860                   mq->message_buf_size,
1861                   GNUNET_i2s (&mq->neighbour_id),
1862                   timeout.rel_value);
1863 #endif
1864       /* FIXME: might want to trigger peerinfo lookup here
1865          (unless that's already pending...) */
1866       return;
1867     }
1868   GNUNET_CONTAINER_DLL_remove (n->messages_head,
1869                                n->messages_tail,
1870                                mq);
1871   if (mq->specific_address->connected == GNUNET_NO)
1872     mq->specific_address->connect_attempts++;
1873   rl = mq->specific_address->ready_list;
1874   mq->plugin = rl->plugin;
1875   if (!mq->internal_msg)
1876     mq->specific_address->in_transmit = GNUNET_YES;
1877 #if DEBUG_TRANSPORT
1878   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1879               "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
1880               mq->message_buf_size,
1881               GNUNET_i2s (&neighbour->id),
1882               (mq->specific_address->addr != NULL)
1883               ? a2s (mq->plugin->short_name,
1884                      mq->specific_address->addr,
1885                      mq->specific_address->addrlen)
1886               : "<inbound>",
1887               rl->plugin->short_name);
1888 #endif
1889   GNUNET_STATISTICS_update (stats,
1890                             gettext_noop ("# bytes in message queue for other peers"),
1891                             - (int64_t) mq->message_buf_size,
1892                             GNUNET_NO);
1893   GNUNET_STATISTICS_update (stats,
1894                             gettext_noop ("# bytes pending with plugins"),
1895                             mq->message_buf_size,
1896                             GNUNET_NO);
1897   ret = rl->plugin->api->send (rl->plugin->api->cls,
1898                                &mq->neighbour_id,
1899                                mq->message_buf,
1900                                mq->message_buf_size,
1901                                mq->priority,
1902                                GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1903                                mq->specific_address->session,
1904                                mq->specific_address->addr,
1905                                mq->specific_address->addrlen,
1906                                force_address,
1907                                &transmit_send_continuation, mq);
1908   if (ret == -1)
1909     {
1910       /* failure, but 'send' would not call continuation in this case,
1911          so we need to do it here! */
1912       transmit_send_continuation (mq,
1913                                   &mq->neighbour_id,
1914                                   GNUNET_SYSERR);
1915     }
1916 }
1917
1918
1919 /**
1920  * Send the specified message to the specified peer.
1921  *
1922  * @param client source of the transmission request (can be NULL)
1923  * @param peer_address ForeignAddressList where we should send this message
1924  * @param priority how important is the message
1925  * @param timeout how long do we have to transmit?
1926  * @param message_buf message(s) to send GNUNET_MessageHeader(s)
1927  * @param message_buf_size total size of all messages in message_buf
1928  * @param is_internal is this an internal message; these are pre-pended and
1929  *                    also do not count for plugins being "ready" to transmit
1930  * @param neighbour handle to the neighbour for transmission
1931  */
1932 static void
1933 transmit_to_peer (struct TransportClient *client,
1934                   struct ForeignAddressList *peer_address,
1935                   unsigned int priority,
1936                   struct GNUNET_TIME_Relative timeout,
1937                   const char *message_buf,
1938                   size_t message_buf_size,
1939                   int is_internal, struct NeighbourList *neighbour)
1940 {
1941   struct MessageQueue *mq;
1942
1943 #if EXTRA_CHECKS
1944   if (client != NULL)
1945     {
1946       /* check for duplicate submission */
1947       mq = neighbour->messages_head;
1948       while (NULL != mq)
1949         {
1950           if (mq->client == client)
1951             {
1952               /* client transmitted to same peer twice
1953                  before getting SEND_OK! */
1954               GNUNET_break (0);
1955               return;
1956             }
1957           mq = mq->next;
1958         }
1959     }
1960 #endif
1961   GNUNET_STATISTICS_update (stats,
1962                             gettext_noop ("# bytes in message queue for other peers"),
1963                             message_buf_size,
1964                             GNUNET_NO);
1965   mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
1966   mq->specific_address = peer_address;
1967   mq->client = client;
1968   /* FIXME: this memcpy can be up to 7% of our total runtime! */
1969   memcpy (&mq[1], message_buf, message_buf_size);
1970   mq->message_buf = (const char*) &mq[1];
1971   mq->message_buf_size = message_buf_size;
1972   memcpy(&mq->neighbour_id, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
1973   mq->internal_msg = is_internal;
1974   mq->priority = priority;
1975   mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1976   if (is_internal)
1977     GNUNET_CONTAINER_DLL_insert (neighbour->messages_head,
1978                                  neighbour->messages_tail,
1979                                  mq);
1980   else
1981     GNUNET_CONTAINER_DLL_insert_after (neighbour->messages_head,
1982                                        neighbour->messages_tail,
1983                                        neighbour->messages_tail,
1984                                        mq);
1985   try_transmission_to_peer (neighbour);
1986 }
1987
1988
1989 /**
1990  * FIXME: document.
1991  */
1992 struct GeneratorContext
1993 {
1994   struct TransportPlugin *plug_pos;
1995   struct OwnAddressList *addr_pos;
1996   struct GNUNET_TIME_Absolute expiration;
1997 };
1998
1999
2000 /**
2001  * FIXME: document.
2002  */
2003 static size_t
2004 address_generator (void *cls, size_t max, void *buf)
2005 {
2006   struct GeneratorContext *gc = cls;
2007   size_t ret;
2008
2009   while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
2010     {
2011       gc->plug_pos = gc->plug_pos->next;
2012       gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
2013     }
2014   if (NULL == gc->plug_pos)
2015     {
2016
2017       return 0;
2018     }
2019   ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
2020                                   gc->expiration,
2021                                   &gc->addr_pos[1],
2022                                   gc->addr_pos->addrlen, buf, max);
2023   gc->addr_pos = gc->addr_pos->next;
2024   return ret;
2025 }
2026
2027
2028 /**
2029  * Construct our HELLO message from all of the addresses of
2030  * all of the transports.
2031  */
2032 static void
2033 refresh_hello ()
2034 {
2035   struct GNUNET_HELLO_Message *hello;
2036   struct TransportClient *cpos;
2037   struct NeighbourList *npos;
2038   struct GeneratorContext gc;
2039
2040   gc.plug_pos = plugins;
2041   gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
2042   gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
2043   hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
2044 #if DEBUG_TRANSPORT
2045   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2046               "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
2047 #endif
2048   GNUNET_STATISTICS_update (stats,
2049                             gettext_noop ("# refreshed my HELLO"),
2050                             1,
2051                             GNUNET_NO);
2052   cpos = clients;
2053   while (cpos != NULL)
2054     {
2055       transmit_to_client (cpos,
2056                           (const struct GNUNET_MessageHeader *) hello,
2057                           GNUNET_NO);
2058       cpos = cpos->next;
2059     }
2060
2061   GNUNET_free_non_null (our_hello);
2062   our_hello = hello;
2063   GNUNET_PEERINFO_add_peer (peerinfo, our_hello);
2064   npos = neighbours;
2065   while (npos != NULL)
2066     {
2067 #if DEBUG_TRANSPORT
2068       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2069                   "Transmitting updated `%s' to neighbour `%4s'\n",
2070                   "HELLO", GNUNET_i2s (&npos->id));
2071 #endif
2072       GNUNET_STATISTICS_update (stats,
2073                                 gettext_noop ("# transmitted my HELLO to other peers"),
2074                                 1,
2075                                 GNUNET_NO);
2076       transmit_to_peer (NULL, NULL, 0,
2077                         HELLO_ADDRESS_EXPIRATION,
2078                         (const char *) our_hello,
2079                         GNUNET_HELLO_size(our_hello),
2080                         GNUNET_NO, npos);
2081       npos = npos->next;
2082     }
2083 }
2084
2085
2086 /**
2087  * Task used to clean up expired addresses for a plugin.
2088  *
2089  * @param cls closure
2090  * @param tc context
2091  */
2092 static void
2093 expire_address_task (void *cls,
2094                      const struct GNUNET_SCHEDULER_TaskContext *tc);
2095
2096
2097 /**
2098  * Update the list of addresses for this plugin,
2099  * expiring those that are past their expiration date.
2100  *
2101  * @param plugin addresses of which plugin should be recomputed?
2102  * @param fresh set to GNUNET_YES if a new address was added
2103  *        and we need to regenerate the HELLO even if nobody
2104  *        expired
2105  */
2106 static void
2107 update_addresses (struct TransportPlugin *plugin, 
2108                   int fresh)
2109 {
2110   static struct GNUNET_TIME_Absolute last_update;
2111   struct GNUNET_TIME_Relative min_remaining;
2112   struct GNUNET_TIME_Relative remaining;
2113   struct GNUNET_TIME_Absolute now;
2114   struct OwnAddressList *pos;
2115   struct OwnAddressList *prev;
2116   struct OwnAddressList *next;
2117   int expired;
2118
2119   if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
2120     GNUNET_SCHEDULER_cancel (plugin->address_update_task);
2121   plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
2122   now = GNUNET_TIME_absolute_get ();
2123   min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
2124   expired = (GNUNET_TIME_absolute_get_duration (last_update).rel_value > (HELLO_ADDRESS_EXPIRATION.rel_value / 4));
2125   prev = NULL;
2126   pos = plugin->addresses;
2127   while (pos != NULL)
2128     {
2129       next = pos->next;
2130       if (pos->expires.abs_value < now.abs_value)
2131         {
2132           expired = GNUNET_YES;
2133           if (prev == NULL)
2134             plugin->addresses = pos->next;
2135           else
2136             prev->next = pos->next;
2137           GNUNET_free (pos);
2138         }
2139       else
2140         {
2141           remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
2142           if (remaining.rel_value < min_remaining.rel_value)
2143             min_remaining = remaining;
2144           prev = pos;
2145         }
2146       pos = next;
2147     }
2148
2149   if (expired || fresh)
2150     {
2151       last_update = now;
2152       refresh_hello ();
2153     }
2154   min_remaining = GNUNET_TIME_relative_min (min_remaining,
2155                                             GNUNET_TIME_relative_divide (HELLO_ADDRESS_EXPIRATION,
2156                                                                          2));
2157   plugin->address_update_task
2158     = GNUNET_SCHEDULER_add_delayed (min_remaining,
2159                                     &expire_address_task, plugin);
2160 }
2161
2162
2163 /**
2164  * Task used to clean up expired addresses for a plugin.
2165  *
2166  * @param cls closure
2167  * @param tc context
2168  */
2169 static void
2170 expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2171 {
2172   struct TransportPlugin *plugin = cls;
2173
2174   plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
2175   if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
2176     update_addresses (plugin, GNUNET_NO);
2177 }
2178
2179
2180 /**
2181  * Iterator over hash map entries that NULLs the session of validation
2182  * entries that match the given session.
2183  *
2184  * @param cls closure (the 'struct Session*' to match against)
2185  * @param key current key code (peer ID, not used)
2186  * @param value value in the hash map ('struct ValidationEntry*')
2187  * @return GNUNET_YES (we should continue to iterate)
2188  */
2189 static int
2190 remove_session_validations (void *cls,
2191                             const GNUNET_HashCode * key,
2192                             void *value)
2193 {
2194   struct Session *session = cls;
2195   struct ValidationEntry *ve = value;
2196
2197   if (session == ve->session)
2198     ve->session = NULL;
2199   return GNUNET_YES;
2200 }
2201
2202
2203 /**
2204  * We've been disconnected from the other peer (for some
2205  * connection-oriented transport).  Either quickly
2206  * re-establish the connection or signal the disconnect
2207  * to the CORE.
2208  *
2209  * Only signal CORE level disconnect if ALL addresses
2210  * for the peer are exhausted.
2211  *
2212  * @param p overall plugin context
2213  * @param nl neighbour that was disconnected
2214  */
2215 static void
2216 try_fast_reconnect (struct TransportPlugin *p,
2217                     struct NeighbourList *nl)
2218 {
2219   /* FIXME-MW: fast reconnect / transport switching not implemented... */
2220   /* Note: the idea here is to hide problems with transports (or
2221      switching between plugins) from the core to eliminate the need to
2222      re-negotiate session keys and the like; OTOH, we should tell core
2223      quickly (much faster than timeout) `if a connection was lost and
2224      could not be re-established (i.e. other peer went down or is
2225      unable / refuses to communicate);
2226
2227      So we should consider:
2228      1) ideally: our own willingness / need to connect
2229      2) prior failures to connect to this peer (by plugin)
2230      3) ideally: reasons why other peer terminated (as far as knowable)
2231
2232      Most importantly, it must be POSSIBLE for another peer to terminate
2233      a connection for a while (without us instantly re-establishing it).
2234      Similarly, if another peer is gone we should quickly notify CORE.
2235      OTOH, if there was a minor glitch (i.e. crash of gnunet-service-transport
2236      on the other end), we should reconnect in such a way that BOTH CORE
2237      services never even notice.
2238      Furthermore, the same mechanism (or small variation) could be used
2239      to switch to a better-performing plugin (ATS).
2240
2241      Finally, this needs to be tested throughly... */                                                           
2242
2243   /*
2244    * GNUNET_NO in the call below makes transport disconnect the peer,
2245    * even if only a single address (out of say, six) went away.  This
2246    * function must be careful to ONLY disconnect if the peer is gone,
2247    * not just a specifi address.
2248    *
2249    * More specifically, half the places it was used had it WRONG.
2250    */
2251
2252   /* No reconnect, signal disconnect instead! */
2253   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2254             "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2255             "try_fast_reconnect");
2256   disconnect_neighbour (nl, GNUNET_YES);
2257 }
2258
2259
2260 /**
2261  * Function that will be called whenever the plugin internally
2262  * cleans up a session pointer and hence the service needs to
2263  * discard all of those sessions as well.  Plugins that do not
2264  * use sessions can simply omit calling this function and always
2265  * use NULL wherever a session pointer is needed.
2266  *
2267  * @param cls closure
2268  * @param peer which peer was the session for
2269  * @param session which session is being destoyed
2270  */
2271 static void
2272 plugin_env_session_end  (void *cls,
2273                          const struct GNUNET_PeerIdentity *peer,
2274                          struct Session *session)
2275 {
2276   struct TransportPlugin *p = cls;
2277   struct NeighbourList *nl;
2278   struct ReadyList *rl;
2279   struct ForeignAddressList *pos;
2280   struct ForeignAddressList *prev;
2281
2282   GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2283                                          &remove_session_validations,
2284                                          session);
2285   nl = find_neighbour (peer);
2286   if (nl == NULL)
2287     return; /* was never marked as connected */
2288   rl = nl->plugins;
2289   while (rl != NULL)
2290     {
2291       if (rl->plugin == p)
2292         break;
2293       rl = rl->next;
2294     }
2295   if (rl == NULL)
2296     return; /* was never marked as connected */
2297   prev = NULL;
2298   pos = rl->addresses;
2299   while ( (pos != NULL) &&
2300           (pos->session != session) )
2301     {
2302       prev = pos;
2303       pos = pos->next;
2304     }
2305   if (pos == NULL)
2306     return; /* was never marked as connected */
2307   pos->session = NULL;
2308   if (pos->addrlen != 0)
2309     {
2310       if (nl->received_pong != GNUNET_NO)
2311         try_fast_reconnect (p, nl);
2312       return;
2313     }
2314   /* was inbound connection, free 'pos' */
2315   if (prev == NULL)
2316     rl->addresses = pos->next;
2317   else
2318     prev->next = pos->next;
2319   if (GNUNET_SCHEDULER_NO_TASK != pos->revalidate_task)
2320     {
2321       GNUNET_SCHEDULER_cancel (pos->revalidate_task);
2322       pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
2323     }
2324   GNUNET_free (pos);
2325   if (nl->received_pong == GNUNET_NO)
2326     return; /* nothing to do, never connected... */
2327   /* check if we have any validated addresses left */
2328   pos = rl->addresses;
2329   while (pos != NULL)
2330     {
2331       if (pos->validated)
2332         {
2333           try_fast_reconnect (p, nl);
2334           return;
2335         }
2336       pos = pos->next;
2337     }
2338   /* no valid addresses left, signal disconnect! */
2339
2340   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2341             "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2342             "plugin_env_session_end");
2343   /* FIXME: This doesn't mean there are no addresses left for this PEER,
2344    * it means there aren't any left for this PLUGIN/PEER combination! So
2345    * calling disconnect_neighbor here with GNUNET_NO forces disconnect
2346    * when it isn't necessary. Using GNUNET_YES at least checks to see
2347    * if there are any addresses that work first, so as not to overdo it.
2348    * --NE
2349    */
2350   disconnect_neighbour (nl, GNUNET_YES);
2351 }
2352
2353
2354 /**
2355  * Function that must be called by each plugin to notify the
2356  * transport service about the addresses under which the transport
2357  * provided by the plugin can be reached.
2358  *
2359  * @param cls closure
2360  * @param name name of the transport that generated the address
2361  * @param addr one of the addresses of the host, NULL for the last address
2362  *        the specific address format depends on the transport
2363  * @param addrlen length of the address
2364  * @param expires when should this address automatically expire?
2365  */
2366 static void
2367 plugin_env_notify_address (void *cls,
2368                            const char *name,
2369                            const void *addr,
2370                            uint16_t addrlen,
2371                            struct GNUNET_TIME_Relative expires)
2372 {
2373   struct TransportPlugin *p = cls;
2374   struct OwnAddressList *al;
2375   struct GNUNET_TIME_Absolute abex;
2376
2377   GNUNET_assert (addr != NULL);
2378   abex = GNUNET_TIME_relative_to_absolute (expires);
2379   GNUNET_assert (p == find_transport (name));
2380   al = p->addresses;
2381   while (al != NULL)
2382     {
2383       if ( (addrlen == al->addrlen) && 
2384            (0 == memcmp (addr, &al[1], addrlen)) )
2385         {             
2386           al->expires = abex;
2387           update_addresses (p, GNUNET_NO);
2388           return;
2389         }
2390       al = al->next;
2391     }
2392   al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
2393   al->next = p->addresses;
2394   p->addresses = al;
2395   al->expires = abex;
2396   al->addrlen = addrlen;
2397   memcpy (&al[1], addr, addrlen);
2398   update_addresses (p, GNUNET_YES);
2399 }
2400
2401
2402 /**
2403  * Notify all of our clients about a peer connecting.
2404  */
2405 static void
2406 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
2407                         struct GNUNET_TIME_Relative latency,
2408                         uint32_t distance)
2409 {
2410   struct ConnectInfoMessage * cim;
2411   struct TransportClient *cpos;
2412   uint32_t ats_count;
2413   size_t size;
2414
2415 #if DEBUG_TRANSPORT
2416   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2417               "Notifying clients about connection from `%s'\n",
2418               GNUNET_i2s (peer));
2419 #endif
2420   GNUNET_STATISTICS_update (stats,
2421                             gettext_noop ("# peers connected"),
2422                             1,
2423                             GNUNET_NO);
2424
2425   ats_count = 2;
2426   size  = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
2427   if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
2428   {
2429           GNUNET_break(0);
2430   }
2431   cim = GNUNET_malloc (size);
2432
2433   cim->header.size = htons (size);
2434   cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2435   cim->ats_count = htonl(2);
2436   (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
2437   (&(cim->ats))[0].value = htonl (distance);
2438   (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
2439   (&(cim->ats))[1].value = htonl ((uint32_t) latency.rel_value);
2440   (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
2441   (&(cim->ats))[2].value = htonl (0);
2442   memcpy (&cim->id, peer, sizeof (struct GNUNET_PeerIdentity));
2443
2444   /* notify ats about connecting peer */
2445   ats_notify_peer_connect (peer, &(cim->ats));
2446
2447   cpos = clients;
2448   while (cpos != NULL)
2449     {
2450       transmit_to_client (cpos, &(cim->header), GNUNET_NO);
2451       cpos = cpos->next;
2452     }
2453
2454   GNUNET_free (cim);
2455 }
2456
2457
2458 /**
2459  * Notify all of our clients about a peer disconnecting.
2460  */
2461 static void
2462 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
2463 {
2464   struct DisconnectInfoMessage dim;
2465   struct TransportClient *cpos;
2466
2467 #if DEBUG_TRANSPORT
2468   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2469               "Notifying clients about lost connection to `%s'\n",
2470               GNUNET_i2s (peer));
2471 #endif
2472   GNUNET_STATISTICS_update (stats,
2473                             gettext_noop ("# peers connected"),
2474                             -1,
2475                             GNUNET_NO);
2476   dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
2477   dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2478   dim.reserved = htonl (0);
2479   memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
2480
2481   /* notify ats about connecting peer */
2482   ats_notify_peer_disconnect (peer);
2483
2484   cpos = clients;
2485   while (cpos != NULL)
2486     {
2487       transmit_to_client (cpos, &dim.header, GNUNET_NO);
2488       cpos = cpos->next;
2489     }
2490 }
2491
2492
2493 /**
2494  * Find a ForeignAddressList entry for the given neighbour
2495  * that matches the given address and transport.
2496  *
2497  * @param neighbour which peer we care about
2498  * @param tname name of the transport plugin
2499  * @param session session to look for, NULL for 'any'; otherwise
2500  *        can be used for the service to "learn" this session ID
2501  *        if 'addr' matches
2502  * @param addr binary address
2503  * @param addrlen length of addr
2504  * @return NULL if no such entry exists
2505  */
2506 static struct ForeignAddressList *
2507 find_peer_address(struct NeighbourList *neighbour,
2508                   const char *tname,
2509                   struct Session *session,
2510                   const char *addr,
2511                   uint16_t addrlen)
2512 {
2513   struct ReadyList *head;
2514   struct ForeignAddressList *pos;
2515
2516   head = neighbour->plugins;
2517   while (head != NULL)
2518     {
2519       if (0 == strcmp (tname, head->plugin->short_name))
2520         break;
2521       head = head->next;
2522     }
2523   if (head == NULL)
2524     return NULL;
2525   pos = head->addresses;
2526   while ( (pos != NULL) &&
2527           ( (pos->addrlen != addrlen) ||
2528             (memcmp(pos->addr, addr, addrlen) != 0) ) )
2529     {
2530       if ( (session != NULL) &&
2531            (pos->session == session) )
2532         return pos;
2533       pos = pos->next;
2534     }
2535   if ( (session != NULL) && (pos != NULL) )
2536     pos->session = session; /* learn it! */
2537   return pos;
2538 }
2539
2540
2541 /**
2542  * Get the peer address struct for the given neighbour and
2543  * address.  If it doesn't yet exist, create it.
2544  *
2545  * @param neighbour which peer we care about
2546  * @param tname name of the transport plugin
2547  * @param session session of the plugin, or NULL for none
2548  * @param addr binary address
2549  * @param addrlen length of addr
2550  * @return NULL if we do not have a transport plugin for 'tname'
2551  */
2552 static struct ForeignAddressList *
2553 add_peer_address (struct NeighbourList *neighbour,
2554                   const char *tname,
2555                   struct Session *session,
2556                   const char *addr,
2557                   uint16_t addrlen)
2558 {
2559   struct ReadyList *head;
2560   struct ForeignAddressList *ret;
2561   int c;
2562
2563   ret = find_peer_address (neighbour, tname, session, addr, addrlen);
2564   if (ret != NULL)
2565     return ret;
2566   head = neighbour->plugins;
2567
2568   while (head != NULL)
2569     {
2570       if (0 == strcmp (tname, head->plugin->short_name))
2571         break;
2572       head = head->next;
2573     }
2574   if (head == NULL)
2575     return NULL;
2576   ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
2577   ret->session = session;
2578   if (addrlen > 0)
2579     {
2580       ret->addr = (const char*) &ret[1];
2581       memcpy (&ret[1], addr, addrlen);
2582     }
2583   else
2584     {
2585       ret->addr = NULL;
2586     }
2587
2588   ret->ressources = GNUNET_malloc(available_ressources * sizeof (struct ATS_ressource_entry));
2589   int plugin;
2590   for (c=0; c<available_ressources; c++)
2591   {
2592           struct ATS_ressource_entry *r = ret->ressources;
2593           r[c].index = c;
2594           r[c].atis_index = ressources[c].atis_index;
2595           if (0 == strcmp(neighbour->plugins->plugin->short_name,"unix"))
2596           {
2597                   r[c].c = ressources[c].c_unix;
2598                   plugin = 1;
2599           }
2600           else if (0 == strcmp(neighbour->plugins->plugin->short_name,"udp"))
2601           {
2602                   r[c].c = ressources[c].c_udp;
2603                   plugin = 2;
2604           }
2605           else if (0 == strcmp(neighbour->plugins->plugin->short_name,"tcp"))
2606           {
2607                   r[c].c = ressources[c].c_tcp;
2608                   plugin = 3;
2609           }
2610           else if (0 == strcmp(neighbour->plugins->plugin->short_name,"http"))
2611           {
2612                   r[c].c = ressources[c].c_http;
2613                   plugin = 4;
2614           }
2615           else if (0 == strcmp(neighbour->plugins->plugin->short_name,"https"))
2616           {
2617                   r[c].c = ressources[c].c_https;
2618                   plugin = 5;
2619           }
2620           else if (0 == strcmp(neighbour->plugins->plugin->short_name,"wlan"))
2621           {
2622                   r[c].c = ressources[c].c_wlan;
2623                   plugin = 6;
2624           }
2625           else
2626           {
2627                 plugin = -1;
2628                 r[c].c = ressources[c].c_default;
2629                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,"Assigning default cost to peer `%s' addr plugin `%s'! This should not happen!",
2630                                 GNUNET_i2s(&neighbour->peer), neighbour->plugins->plugin->short_name);
2631           }
2632   }
2633
2634   ret->addrlen = addrlen;
2635   ret->expires = GNUNET_TIME_relative_to_absolute
2636     (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2637   ret->latency = GNUNET_TIME_relative_get_forever();
2638   ret->distance = -1;
2639   ret->timeout = GNUNET_TIME_relative_to_absolute
2640     (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2641   ret->ready_list = head;
2642   ret->next = head->addresses;
2643   head->addresses = ret;
2644   return ret;
2645 }
2646
2647
2648 /**
2649  * Closure for 'add_validated_address'.
2650  */
2651 struct AddValidatedAddressContext
2652 {
2653   /**
2654    * Entry that has been validated.
2655    */
2656   const struct ValidationEntry *ve;
2657
2658   /**
2659    * Flag set after we have added the address so
2660    * that we terminate the iteration next time.
2661    */
2662   int done;
2663 };
2664
2665
2666 /**
2667  * Callback function used to fill a buffer of max bytes with a list of
2668  * addresses in the format used by HELLOs.  Should use
2669  * "GNUNET_HELLO_add_address" as a helper function.
2670  *
2671  * @param cls the 'struct AddValidatedAddressContext' with the validated address
2672  * @param max maximum number of bytes that can be written to buf
2673  * @param buf where to write the address information
2674  * @return number of bytes written, 0 to signal the
2675  *         end of the iteration.
2676  */
2677 static size_t
2678 add_validated_address (void *cls,
2679                        size_t max, void *buf)
2680 {
2681   struct AddValidatedAddressContext *avac = cls;
2682   const struct ValidationEntry *ve = avac->ve;
2683
2684   if (GNUNET_YES == avac->done)
2685     return 0;
2686   avac->done = GNUNET_YES;
2687   return GNUNET_HELLO_add_address (ve->transport_name,
2688                                    GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION),
2689                                    ve->addr,
2690                                    ve->addrlen,
2691                                    buf,
2692                                    max);
2693 }
2694
2695
2696
2697 /**
2698  * Closure for 'check_address_exists'.
2699  */
2700 struct CheckAddressExistsClosure
2701 {
2702   /**
2703    * Address to check for.
2704    */
2705   const void *addr;
2706
2707   /**
2708    * Name of the transport.
2709    */
2710   const char *tname;
2711
2712   /**
2713    * Session, or NULL.
2714    */
2715   struct Session *session;
2716
2717   /**
2718    * Set to GNUNET_YES if the address exists.
2719    */
2720   int exists;
2721
2722   /**
2723    * Length of addr.
2724    */
2725   uint16_t addrlen;
2726
2727 };
2728
2729
2730 /**
2731  * Iterator over hash map entries.  Checks if the given
2732  * validation entry is for the same address as what is given
2733  * in the closure.
2734  *
2735  * @param cls the 'struct CheckAddressExistsClosure*'
2736  * @param key current key code (ignored)
2737  * @param value value in the hash map ('struct ValidationEntry')
2738  * @return GNUNET_YES if we should continue to
2739  *         iterate (mismatch), GNUNET_NO if not (entry matched)
2740  */
2741 static int
2742 check_address_exists (void *cls,
2743                       const GNUNET_HashCode * key,
2744                       void *value)
2745 {
2746   struct CheckAddressExistsClosure *caec = cls;
2747   struct ValidationEntry *ve = value;
2748
2749   if ( (0 == strcmp (caec->tname,
2750                      ve->transport_name)) &&
2751        (caec->addrlen == ve->addrlen) &&
2752        (0 == memcmp (caec->addr,
2753                      ve->addr,
2754                      caec->addrlen)) )
2755     {
2756       caec->exists = GNUNET_YES;
2757       return GNUNET_NO;
2758     }
2759   if ( (ve->session != NULL) &&
2760        (caec->session == ve->session) )
2761     {
2762       caec->exists = GNUNET_YES;
2763       return GNUNET_NO;
2764     }
2765   return GNUNET_YES;
2766 }
2767
2768
2769
2770 /**
2771  * Iterator to free entries in the validation_map.
2772  *
2773  * @param cls closure (unused)
2774  * @param key current key code
2775  * @param value value in the hash map (validation to abort)
2776  * @return GNUNET_YES (always)
2777  */
2778 static int
2779 abort_validation (void *cls,
2780                   const GNUNET_HashCode * key,
2781                   void *value)
2782 {
2783   struct ValidationEntry *va = value;
2784
2785   if (GNUNET_SCHEDULER_NO_TASK != va->timeout_task)
2786     GNUNET_SCHEDULER_cancel (va->timeout_task);
2787   GNUNET_free (va->transport_name);
2788   if (va->chvc != NULL)
2789     {
2790       va->chvc->ve_count--;
2791       if (va->chvc->ve_count == 0)
2792         {
2793           GNUNET_CONTAINER_DLL_remove (chvc_head,
2794                                        chvc_tail,
2795                                        va->chvc);
2796           GNUNET_free (va->chvc);
2797         }
2798       va->chvc = NULL;
2799     }
2800   GNUNET_free (va);
2801   return GNUNET_YES;
2802 }
2803
2804
2805 /**
2806  * HELLO validation cleanup task (validation failed).
2807  *
2808  * @param cls the 'struct ValidationEntry' that failed
2809  * @param tc scheduler context (unused)
2810  */
2811 static void
2812 timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2813 {
2814   struct ValidationEntry *va = cls;
2815   struct GNUNET_PeerIdentity pid;
2816
2817   va->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2818   GNUNET_STATISTICS_update (stats,
2819                             gettext_noop ("# address validation timeouts"),
2820                             1,
2821                             GNUNET_NO);
2822   GNUNET_CRYPTO_hash (&va->publicKey,
2823                       sizeof (struct
2824                               GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2825                       &pid.hashPubKey);
2826   GNUNET_break (GNUNET_OK ==
2827                 GNUNET_CONTAINER_multihashmap_remove (validation_map,
2828                                                       &pid.hashPubKey,
2829                                                       va));
2830   abort_validation (NULL, NULL, va);
2831 }
2832
2833
2834 static void
2835 neighbour_timeout_task (void *cls,
2836                        const struct GNUNET_SCHEDULER_TaskContext *tc)
2837 {
2838   struct NeighbourList *n = cls;
2839
2840 #if DEBUG_TRANSPORT
2841   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2842               "Neighbour `%4s' has timed out!\n", GNUNET_i2s (&n->id));
2843 #endif
2844   GNUNET_STATISTICS_update (stats,
2845                             gettext_noop ("# disconnects due to timeout"),
2846                             1,
2847                             GNUNET_NO);
2848   n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
2849   disconnect_neighbour (n, GNUNET_NO);
2850 }
2851
2852
2853 /**
2854  * Schedule the job that will cause us to send a PING to the
2855  * foreign address to evaluate its validity and latency.
2856  *
2857  * @param fal address to PING
2858  */
2859 static void
2860 schedule_next_ping (struct ForeignAddressList *fal);
2861
2862
2863 /**
2864  * Add the given address to the list of foreign addresses
2865  * available for the given peer (check for duplicates).
2866  *
2867  * @param cls the respective 'struct NeighbourList' to update
2868  * @param tname name of the transport
2869  * @param expiration expiration time
2870  * @param addr the address
2871  * @param addrlen length of the address
2872  * @return GNUNET_OK (always)
2873  */
2874 static int
2875 add_to_foreign_address_list (void *cls,
2876                              const char *tname,
2877                              struct GNUNET_TIME_Absolute expiration,
2878                              const void *addr,
2879                              uint16_t addrlen)
2880 {
2881   struct NeighbourList *n = cls;
2882   struct ForeignAddressList *fal;
2883   int try;
2884
2885   GNUNET_STATISTICS_update (stats,
2886                             gettext_noop ("# valid peer addresses returned by PEERINFO"),
2887                             1,
2888                             GNUNET_NO);
2889   try = GNUNET_NO;
2890   fal = find_peer_address (n, tname, NULL, addr, addrlen);
2891   if (fal == NULL)
2892     {
2893 #if DEBUG_TRANSPORT_HELLO
2894       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2895                   "Adding address `%s' (%s) for peer `%4s' due to PEERINFO data for %llums.\n",
2896                   a2s (tname, addr, addrlen),
2897                   tname,
2898                   GNUNET_i2s (&n->id),
2899                   expiration.abs_value);
2900 #endif
2901       fal = add_peer_address (n, tname, NULL, addr, addrlen);
2902       if (fal == NULL)
2903         {
2904           GNUNET_STATISTICS_update (stats,
2905                                     gettext_noop ("# previously validated addresses lacking transport"),
2906                                     1,
2907                                     GNUNET_NO);
2908         }
2909       else
2910         {
2911           fal->expires = GNUNET_TIME_absolute_max (expiration,
2912                                                    fal->expires);
2913           schedule_next_ping (fal);
2914         }
2915       try = GNUNET_YES;
2916     }
2917   else
2918     {
2919       fal->expires = GNUNET_TIME_absolute_max (expiration,
2920                                                fal->expires);
2921     }
2922   if (fal == NULL)
2923     {
2924       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2925                   "Failed to add new address for `%4s'\n",
2926                   GNUNET_i2s (&n->id));
2927       return GNUNET_OK;
2928     }
2929   if (fal->validated == GNUNET_NO)
2930     {
2931       fal->validated = GNUNET_YES;
2932       GNUNET_STATISTICS_update (stats,
2933                                 gettext_noop ("# peer addresses considered valid"),
2934                                 1,
2935                                 GNUNET_NO);
2936     }
2937   if (try == GNUNET_YES)
2938     {
2939       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2940                   "Have new addresses, will try to trigger transmissions.\n");
2941       try_transmission_to_peer (n);
2942     }
2943   return GNUNET_OK;
2944 }
2945
2946
2947 /**
2948  * Add addresses in validated HELLO "h" to the set of addresses
2949  * we have for this peer.
2950  *
2951  * @param cls closure ('struct NeighbourList*')
2952  * @param peer id of the peer, NULL for last call
2953  * @param h hello message for the peer (can be NULL)
2954  * @param err_msg NULL if successful, otherwise contains error message
2955  */
2956 static void
2957 add_hello_for_peer (void *cls,
2958                     const struct GNUNET_PeerIdentity *peer,
2959                     const struct GNUNET_HELLO_Message *h,
2960                     const char *err_msg)
2961 {
2962   struct NeighbourList *n = cls;
2963
2964   if (err_msg != NULL)
2965   {
2966           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2967                       _("Error in communication with PEERINFO service\n"));
2968         /* return; */
2969   }
2970   if ((peer == NULL))
2971     {
2972       GNUNET_STATISTICS_update (stats,
2973                                 gettext_noop ("# outstanding peerinfo iterate requests"),
2974                                 -1,
2975                                 GNUNET_NO);
2976       n->piter = NULL;
2977       return;
2978     }
2979   if (h == NULL)
2980     return; /* no HELLO available */
2981 #if DEBUG_TRANSPORT
2982   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2983               "Peerinfo had `%s' message for peer `%4s', adding existing addresses.\n",
2984               "HELLO",
2985               GNUNET_i2s (peer));
2986 #endif
2987   if (GNUNET_YES != n->public_key_valid)
2988     {
2989       GNUNET_HELLO_get_key (h, &n->publicKey);
2990       n->public_key_valid = GNUNET_YES;
2991     }
2992   GNUNET_HELLO_iterate_addresses (h,
2993                                   GNUNET_NO,
2994                                   &add_to_foreign_address_list,
2995                                   n);
2996 }
2997
2998
2999 /**
3000  * Create a fresh entry in our neighbour list for the given peer.
3001  * Will try to transmit our current HELLO to the new neighbour.
3002  * Do not call this function directly, use 'setup_peer_check_blacklist.
3003  *
3004  * @param peer the peer for which we create the entry
3005  * @param do_hello should we schedule transmitting a HELLO
3006  * @return the new neighbour list entry
3007  */
3008 static struct NeighbourList *
3009 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer,
3010                      int do_hello)
3011 {
3012   struct NeighbourList *n;
3013   struct TransportPlugin *tp;
3014   struct ReadyList *rl;
3015
3016 #if DEBUG_TRANSPORT
3017   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3018               "Setting up state for neighbour `%4s'\n",
3019               GNUNET_i2s (peer));
3020 #endif
3021   GNUNET_assert (our_hello != NULL);
3022   GNUNET_STATISTICS_update (stats,
3023                             gettext_noop ("# active neighbours"),
3024                             1,
3025                             GNUNET_NO);
3026   n = GNUNET_malloc (sizeof (struct NeighbourList));
3027   n->next = neighbours;
3028   neighbours = n;
3029   n->id = *peer;
3030   n->peer_timeout =
3031     GNUNET_TIME_relative_to_absolute
3032     (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3033   GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
3034                                  GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
3035                                  MAX_BANDWIDTH_CARRY_S);
3036   tp = plugins;
3037   while (tp != NULL)
3038     {
3039       if ((tp->api->send != NULL) && (!is_blacklisted(peer, tp)))
3040         {
3041           rl = GNUNET_malloc (sizeof (struct ReadyList));
3042           rl->neighbour = n;
3043           rl->next = n->plugins;
3044           n->plugins = rl;
3045           rl->plugin = tp;
3046           rl->addresses = NULL;
3047         }
3048       tp = tp->next;
3049     }
3050   n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
3051   n->distance = -1;
3052   n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
3053                                                   &neighbour_timeout_task, n);
3054   if (do_hello)
3055     {
3056       GNUNET_STATISTICS_update (stats,
3057                                 gettext_noop ("# peerinfo new neighbor iterate requests"),
3058                                 1,
3059                                 GNUNET_NO);
3060       GNUNET_STATISTICS_update (stats,
3061                                 gettext_noop ("# outstanding peerinfo iterate requests"),
3062                                 1,
3063                                 GNUNET_NO);
3064       n->piter = GNUNET_PEERINFO_iterate (peerinfo, peer,
3065                                           GNUNET_TIME_UNIT_FOREVER_REL,
3066                                           &add_hello_for_peer, n);
3067
3068       GNUNET_STATISTICS_update (stats,
3069                                 gettext_noop ("# HELLO's sent to new neighbors"),
3070                                 1,
3071                                 GNUNET_NO);
3072       transmit_to_peer (NULL, NULL, 0,
3073                         HELLO_ADDRESS_EXPIRATION,
3074                         (const char *) our_hello, GNUNET_HELLO_size(our_hello),
3075                         GNUNET_NO, n);
3076     }
3077   return n;
3078 }
3079
3080
3081 /**
3082  * Function called after we have checked if communicating
3083  * with a given peer is acceptable.
3084  *
3085  * @param cls closure
3086  * @param n NULL if communication is not acceptable
3087  */
3088 typedef void (*SetupContinuation)(void *cls,
3089                                   struct NeighbourList *n);
3090
3091
3092 /**
3093  * Information kept for each client registered to perform
3094  * blacklisting.
3095  */
3096 struct Blacklisters
3097 {
3098   /**
3099    * This is a linked list.
3100    */
3101   struct Blacklisters *next;
3102
3103   /**
3104    * This is a linked list.
3105    */
3106   struct Blacklisters *prev;
3107
3108   /**
3109    * Client responsible for this entry.
3110    */
3111   struct GNUNET_SERVER_Client *client;
3112
3113   /**
3114    * Blacklist check that we're currently performing.
3115    */
3116   struct BlacklistCheck *bc;
3117
3118 };
3119
3120
3121 /**
3122  * Head of DLL of blacklisting clients.
3123  */
3124 static struct Blacklisters *bl_head;
3125
3126 /**
3127  * Tail of DLL of blacklisting clients.
3128  */
3129 static struct Blacklisters *bl_tail;
3130
3131
3132 /**
3133  * Context we use when performing a blacklist check.
3134  */
3135 struct BlacklistCheck
3136 {
3137
3138   /**
3139    * This is a linked list.
3140    */
3141   struct BlacklistCheck *next;
3142
3143   /**
3144    * This is a linked list.
3145    */
3146   struct BlacklistCheck *prev;
3147
3148   /**
3149    * Peer being checked.
3150    */
3151   struct GNUNET_PeerIdentity peer;
3152
3153   /**
3154    * Option for setup neighbour afterwards.
3155    */
3156   int do_hello;
3157
3158   /**
3159    * Continuation to call with the result.
3160    */
3161   SetupContinuation cont;
3162
3163   /**
3164    * Closure for cont.
3165    */
3166   void *cont_cls;
3167
3168   /**
3169    * Current transmission request handle for this client, or NULL if no
3170    * request is pending.
3171    */
3172   struct GNUNET_CONNECTION_TransmitHandle *th;
3173
3174   /**
3175    * Our current position in the blacklisters list.
3176    */
3177   struct Blacklisters *bl_pos;
3178
3179   /**
3180    * Current task performing the check.
3181    */
3182   GNUNET_SCHEDULER_TaskIdentifier task;
3183
3184 };
3185
3186 /**
3187  * Head of DLL of active blacklisting queries.
3188  */
3189 static struct BlacklistCheck *bc_head;
3190
3191 /**
3192  * Tail of DLL of active blacklisting queries.
3193  */
3194 static struct BlacklistCheck *bc_tail;
3195
3196
3197 /**
3198  * Perform next action in the blacklist check.
3199  *
3200  * @param cls the 'struct BlacklistCheck*'
3201  * @param tc unused
3202  */
3203 static void
3204 do_blacklist_check (void *cls,
3205                     const struct GNUNET_SCHEDULER_TaskContext *tc);
3206
3207 /**
3208  * Transmit blacklist query to the client.
3209  *
3210  * @param cls the 'struct BlacklistCheck'
3211  * @param size number of bytes allowed
3212  * @param buf where to copy the message
3213  * @return number of bytes copied to buf
3214  */
3215 static size_t
3216 transmit_blacklist_message (void *cls,
3217                             size_t size,
3218                             void *buf)
3219 {
3220   struct BlacklistCheck *bc = cls;
3221   struct Blacklisters *bl;
3222   struct BlacklistMessage bm;
3223
3224   bc->th = NULL;
3225   if (size == 0)
3226     {
3227       GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK);
3228       bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3229                                            bc);
3230       return 0;
3231     }
3232   bl = bc->bl_pos;
3233   bm.header.size = htons (sizeof (struct BlacklistMessage));
3234   bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
3235   bm.is_allowed = htonl (0);
3236   bm.peer = bc->peer;
3237   memcpy (buf, &bm, sizeof (bm));
3238   GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
3239   return sizeof (bm);
3240 }
3241
3242
3243 /**
3244  * Perform next action in the blacklist check.
3245  *
3246  * @param cls the 'struct BlacklistCheck*'
3247  * @param tc unused
3248  */
3249 static void
3250 do_blacklist_check (void *cls,
3251                     const struct GNUNET_SCHEDULER_TaskContext *tc)
3252 {
3253   struct BlacklistCheck *bc = cls;
3254   struct Blacklisters *bl;
3255
3256   bc->task = GNUNET_SCHEDULER_NO_TASK;
3257   bl = bc->bl_pos;
3258   if (bl == NULL)
3259     {
3260       bc->cont (bc->cont_cls,
3261                 setup_new_neighbour (&bc->peer, bc->do_hello));         
3262       GNUNET_free (bc);
3263       return;
3264     }
3265   if (bl->bc == NULL)
3266     {
3267       bl->bc = bc;
3268       bc->th = GNUNET_SERVER_notify_transmit_ready (bl->client,
3269                                                     sizeof (struct BlacklistMessage),
3270                                                     GNUNET_TIME_UNIT_FOREVER_REL,
3271                                                     &transmit_blacklist_message,
3272                                                     bc);
3273     }
3274 }
3275
3276
3277 /**
3278  * Obtain a 'struct NeighbourList' for the given peer.  If such an entry
3279  * does not yet exist, check the blacklist.  If the blacklist says creating
3280  * one is acceptable, create one and call the continuation; otherwise
3281  * call the continuation with NULL.
3282  *
3283  * @param peer peer to setup or look up a struct NeighbourList for
3284  * @param do_hello should we also schedule sending our HELLO to the peer
3285  *        if this is a new record
3286  * @param cont function to call with the 'struct NeigbhbourList*'
3287  * @param cont_cls closure for cont
3288  */
3289 static void
3290 setup_peer_check_blacklist (const struct GNUNET_PeerIdentity *peer,
3291                             int do_hello,
3292                             SetupContinuation cont,
3293                             void *cont_cls)
3294 {
3295   struct NeighbourList *n;
3296   struct BlacklistCheck *bc;
3297
3298   n = find_neighbour(peer);
3299   if (n != NULL)
3300     {
3301       if (cont != NULL)
3302         cont (cont_cls, n);
3303       return;
3304     }
3305   if (bl_head == NULL)
3306     {
3307       if (cont != NULL)
3308         cont (cont_cls, setup_new_neighbour (peer, do_hello));
3309       else
3310         setup_new_neighbour(peer, do_hello);
3311       return;
3312     }
3313   bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3314   GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3315   bc->peer = *peer;
3316   bc->do_hello = do_hello;
3317   bc->cont = cont;
3318   bc->cont_cls = cont_cls;
3319   bc->bl_pos = bl_head;
3320   bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3321                                        bc);
3322 }
3323
3324
3325 /**
3326  * Function called with the result of querying a new blacklister about
3327  * it being allowed (or not) to continue to talk to an existing neighbour.
3328  *
3329  * @param cls the original 'struct NeighbourList'
3330  * @param n NULL if we need to disconnect
3331  */
3332 static void
3333 confirm_or_drop_neighbour (void *cls,
3334                            struct NeighbourList *n)
3335 {
3336   struct NeighbourList * orig = cls;
3337
3338   if (n == NULL)
3339     {
3340       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3341               "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&orig->id),
3342               "confirm_or_drop_neighboUr");
3343       disconnect_neighbour (orig, GNUNET_NO);
3344     }
3345 }
3346
3347
3348 /**
3349  * Handle a request to start a blacklist.
3350  *
3351  * @param cls closure (always NULL)
3352  * @param client identification of the client
3353  * @param message the actual message
3354  */
3355 static void
3356 handle_blacklist_init (void *cls,
3357                        struct GNUNET_SERVER_Client *client,
3358                        const struct GNUNET_MessageHeader *message)
3359 {
3360   struct Blacklisters *bl;
3361   struct BlacklistCheck *bc;
3362   struct NeighbourList *n;
3363
3364   bl = bl_head;
3365   while (bl != NULL)
3366     {
3367       if (bl->client == client)
3368         {
3369           GNUNET_break (0);
3370           GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3371           return;
3372         }
3373       bl = bl->next;
3374     }
3375   bl = GNUNET_malloc (sizeof (struct Blacklisters));
3376   bl->client = client;
3377   GNUNET_SERVER_client_keep (client);
3378   GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
3379   /* confirm that all existing connections are OK! */
3380   n = neighbours;
3381   while (NULL != n)
3382     {
3383       bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3384       GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3385       bc->peer = n->id;
3386       bc->do_hello = GNUNET_NO;
3387       bc->cont = &confirm_or_drop_neighbour;
3388       bc->cont_cls = n;
3389       bc->bl_pos = bl;
3390       if (n == neighbours) /* all would wait for the same client, no need to
3391                               create more than just the first task right now */
3392         bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3393                                              bc);
3394       n = n->next;
3395     }
3396 }
3397
3398
3399 /**
3400  * Handle a request to blacklist a peer.
3401  *
3402  * @param cls closure (always NULL)
3403  * @param client identification of the client
3404  * @param message the actual message
3405  */
3406 static void
3407 handle_blacklist_reply (void *cls,
3408                         struct GNUNET_SERVER_Client *client,
3409                         const struct GNUNET_MessageHeader *message)
3410 {
3411   const struct BlacklistMessage *msg = (const struct BlacklistMessage*) message;
3412   struct Blacklisters *bl;
3413   struct BlacklistCheck *bc;
3414
3415   bl = bl_head;
3416   while ( (bl != NULL) &&
3417           (bl->client != client) )
3418     bl = bl->next;
3419   if (bl == NULL)
3420     {
3421       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3422       return;
3423     }
3424   bc = bl->bc;
3425   bl->bc = NULL;
3426   if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
3427     {
3428       bc->cont (bc->cont_cls, NULL);
3429       GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
3430       GNUNET_free (bc);
3431     }
3432   else
3433     {
3434       bc->bl_pos = bc->bl_pos->next;
3435       bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3436                                            bc);
3437     }
3438   /* check if any other bc's are waiting for this blacklister */
3439   bc = bc_head;
3440   while (bc != NULL)
3441     {
3442       if ( (bc->bl_pos == bl) &&
3443            (GNUNET_SCHEDULER_NO_TASK == bc->task) )
3444         bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3445                                              bc);
3446       bc = bc->next;
3447     }
3448 }
3449
3450
3451 /**
3452  * Send periodic PING messages to a given foreign address.
3453  *
3454  * @param cls our 'struct PeriodicValidationContext*'
3455  * @param tc task context
3456  */
3457 static void
3458 send_periodic_ping (void *cls,
3459                     const struct GNUNET_SCHEDULER_TaskContext *tc)
3460 {
3461   struct ForeignAddressList *peer_address = cls;
3462   struct TransportPlugin *tp;
3463   struct ValidationEntry *va;
3464   struct NeighbourList *neighbour;
3465   struct TransportPingMessage ping;
3466   struct CheckAddressExistsClosure caec;
3467   char * message_buf;
3468   uint16_t hello_size;
3469   size_t slen;
3470   size_t tsize;
3471
3472   peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3473   if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
3474     return;
3475   tp = peer_address->ready_list->plugin;
3476   neighbour = peer_address->ready_list->neighbour;
3477   if (GNUNET_YES != neighbour->public_key_valid)
3478     {
3479       /* no public key yet, try again later */
3480       schedule_next_ping (peer_address);
3481       return;
3482     }
3483   caec.addr = peer_address->addr;
3484   caec.addrlen = peer_address->addrlen;
3485   caec.tname = tp->short_name;
3486   caec.session = peer_address->session;
3487   caec.exists = GNUNET_NO;
3488   GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3489                                          &check_address_exists,
3490                                          &caec);
3491   if (caec.exists == GNUNET_YES)
3492     {
3493       /* During validation attempts we will likely trigger the other
3494          peer trying to validate our address which in turn will cause
3495          it to send us its HELLO, so we expect to hit this case rather
3496          frequently.  Only print something if we are very verbose. */
3497 #if DEBUG_TRANSPORT > 1
3498       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3499                   "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
3500                   (peer_address->addr != NULL)
3501                   ? a2s (tp->short_name,
3502                          peer_address->addr,
3503                          peer_address->addrlen)
3504                   : "<inbound>",
3505                   tp->short_name,
3506                   GNUNET_i2s (&neighbour->id));
3507 #endif
3508       schedule_next_ping (peer_address);
3509       return;
3510     }
3511   va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
3512   va->transport_name = GNUNET_strdup (tp->short_name);
3513   va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
3514                                             UINT_MAX);
3515   va->send_time = GNUNET_TIME_absolute_get();
3516   va->session = peer_address->session;
3517   if (peer_address->addr != NULL)
3518     {
3519       va->addr = (const void*) &va[1];
3520       memcpy (&va[1], peer_address->addr, peer_address->addrlen);
3521       va->addrlen = peer_address->addrlen;
3522     }
3523   memcpy(&va->publicKey,
3524          &neighbour->publicKey,
3525          sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3526
3527   va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
3528                                                    &timeout_hello_validation,
3529                                                    va);
3530   GNUNET_CONTAINER_multihashmap_put (validation_map,
3531                                      &neighbour->id.hashPubKey,
3532                                      va,
3533                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3534
3535   if (peer_address->validated != GNUNET_YES)
3536     hello_size = GNUNET_HELLO_size(our_hello);
3537   else
3538     hello_size = 0;
3539
3540   tsize = sizeof(struct TransportPingMessage) + hello_size;
3541
3542   if (peer_address->addr != NULL)
3543     {
3544       slen = strlen (tp->short_name) + 1;
3545       tsize += slen + peer_address->addrlen;
3546     }
3547   else
3548     {
3549       slen = 0; /* make gcc happy */
3550     }
3551   message_buf = GNUNET_malloc(tsize);
3552   ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3553   ping.challenge = htonl(va->challenge);
3554   memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
3555   if (peer_address->validated != GNUNET_YES)
3556     {
3557       memcpy(message_buf, our_hello, hello_size);
3558     }
3559
3560   if (peer_address->addr != NULL)
3561     {
3562       ping.header.size = htons(sizeof(struct TransportPingMessage) +
3563                                peer_address->addrlen +
3564                                slen);
3565       memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
3566              tp->short_name,
3567              slen);
3568       memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
3569              peer_address->addr,
3570              peer_address->addrlen);
3571     }
3572   else
3573     {
3574       ping.header.size = htons(sizeof(struct TransportPingMessage));
3575     }
3576
3577   memcpy(&message_buf[hello_size],
3578          &ping,
3579          sizeof(struct TransportPingMessage));
3580
3581 #if DEBUG_TRANSPORT_REVALIDATION
3582   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3583               "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s'\n",
3584               (peer_address->addr != NULL)
3585               ? a2s (peer_address->plugin->short_name,
3586                      peer_address->addr,
3587                      peer_address->addrlen)
3588               : "<inbound>",
3589               tp->short_name,
3590               GNUNET_i2s (&neighbour->id),
3591               "HELLO", hello_size,
3592               "PING");
3593 #endif
3594   if (peer_address->validated != GNUNET_YES)
3595     GNUNET_STATISTICS_update (stats,
3596                               gettext_noop ("# PING with HELLO messages sent"),
3597                               1,
3598                               GNUNET_NO);
3599   else
3600     GNUNET_STATISTICS_update (stats,
3601                               gettext_noop ("# PING without HELLO messages sent"),
3602                               1,
3603                               GNUNET_NO);
3604   GNUNET_STATISTICS_update (stats,
3605                             gettext_noop ("# PING messages sent for re-validation"),
3606                             1,
3607                             GNUNET_NO);
3608   transmit_to_peer (NULL, peer_address,
3609                     GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3610                     HELLO_VERIFICATION_TIMEOUT,
3611                     message_buf, tsize,
3612                     GNUNET_YES, neighbour);
3613   GNUNET_free(message_buf);
3614   schedule_next_ping (peer_address);
3615 }
3616
3617
3618 /**
3619  * Schedule the job that will cause us to send a PING to the
3620  * foreign address to evaluate its validity and latency.
3621  *
3622  * @param fal address to PING
3623  */
3624 static void
3625 schedule_next_ping (struct ForeignAddressList *fal)
3626 {
3627   struct GNUNET_TIME_Relative delay;
3628
3629   if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
3630     return;
3631   delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
3632   delay.rel_value /= 2; /* do before expiration */
3633   delay = GNUNET_TIME_relative_min (delay,
3634                                     LATENCY_EVALUATION_MAX_DELAY);
3635   if (GNUNET_YES != fal->estimated)
3636     {
3637       delay = GNUNET_TIME_UNIT_ZERO;
3638       fal->estimated = GNUNET_YES;
3639     }                           
3640   if (GNUNET_YES == fal->connected)
3641     {
3642       delay = GNUNET_TIME_relative_min (delay,
3643                                         CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
3644     }
3645   /* FIXME: also adjust delay based on how close the last
3646      observed latency is to the latency of the best alternative */
3647   /* bound how fast we can go */
3648   delay = GNUNET_TIME_relative_max (delay,
3649                                     GNUNET_TIME_UNIT_SECONDS);
3650   /* randomize a bit (to avoid doing all at the same time) */
3651   delay.rel_value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
3652   fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(delay,
3653                                                       &send_periodic_ping,
3654                                                       fal);
3655 }
3656
3657
3658
3659
3660 /**
3661  * Function that will be called if we receive some payload
3662  * from another peer.
3663  *
3664  * @param message the payload
3665  * @param n peer who claimed to be the sender
3666  */
3667 static void
3668 handle_payload_message (const struct GNUNET_MessageHeader *message,
3669                                                 struct NeighbourList *n)
3670 {
3671   struct InboundMessage *im;
3672   struct TransportClient *cpos;
3673   uint16_t msize;
3674
3675   msize = ntohs (message->size);
3676   if (n->received_pong == GNUNET_NO)
3677     {
3678       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3679                   "Received message of type %u and size %u from `%4s', but no pong yet!!\n",
3680                   ntohs (message->type),
3681                   ntohs (message->size),
3682                   GNUNET_i2s (&n->id));
3683       GNUNET_free_non_null (n->pre_connect_message_buffer);
3684       n->pre_connect_message_buffer = GNUNET_malloc (msize);
3685       memcpy (n->pre_connect_message_buffer, message, msize);
3686       return;
3687     }
3688
3689 #if DEBUG_TRANSPORT
3690   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3691               "Received message of type %u and size %u from `%4s', sending to all clients.\n",
3692               ntohs (message->type),
3693               ntohs (message->size),
3694               GNUNET_i2s (&n->id));
3695 #endif
3696   if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3697                                                       (ssize_t) msize))
3698     {
3699       n->quota_violation_count++;
3700 #if DEBUG_TRANSPORT
3701       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,                      
3702                   "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
3703                   n->in_tracker.available_bytes_per_s__,
3704                   n->quota_violation_count);
3705 #endif
3706       /* Discount 32k per violation */
3707       GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3708                                         - 32 * 1024);           
3709     }
3710   else
3711     {
3712       if (n->quota_violation_count > 0)
3713         {
3714           /* try to add 32k back */
3715           GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3716                                             32 * 1024);
3717           n->quota_violation_count--;
3718         }
3719     }
3720   GNUNET_STATISTICS_update (stats,
3721                             gettext_noop ("# payload received from other peers"),
3722                             msize,
3723                             GNUNET_NO);
3724   /* transmit message to all clients */
3725   uint32_t ats_count = 2;
3726   size_t size = sizeof (struct InboundMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information) + msize;
3727   if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
3728           GNUNET_break(0);
3729
3730   im = GNUNET_malloc (size);
3731   im->header.size = htons (size);
3732   im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
3733   im->peer = n->id;
3734   im->ats_count = htonl(ats_count);
3735   /* Setting ATS data */
3736   (&(im->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
3737   (&(im->ats))[0].value = htonl (n->distance);
3738   (&(im->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
3739   (&(im->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
3740   (&(im->ats))[ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
3741   (&(im->ats))[ats_count].value = htonl (0);
3742
3743   memcpy (&((&(im->ats))[ats_count+1]), message, msize);
3744   cpos = clients;
3745   while (cpos != NULL)
3746     {
3747       transmit_to_client (cpos, &im->header, GNUNET_YES);
3748       cpos = cpos->next;
3749     }
3750   GNUNET_free (im);
3751 }
3752
3753
3754 /**
3755  * Iterator over hash map entries.  Checks if the given validation
3756  * entry is for the same challenge as what is given in the PONG.
3757  *
3758  * @param cls the 'struct TransportPongMessage*'
3759  * @param key peer identity
3760  * @param value value in the hash map ('struct ValidationEntry')
3761  * @return GNUNET_YES if we should continue to
3762  *         iterate (mismatch), GNUNET_NO if not (entry matched)
3763  */
3764 static int
3765 check_pending_validation (void *cls,
3766                           const GNUNET_HashCode * key,
3767                           void *value)
3768 {
3769   const struct TransportPongMessage *pong = cls;
3770   struct ValidationEntry *ve = value;
3771   struct AddValidatedAddressContext avac;
3772   unsigned int challenge = ntohl(pong->challenge);
3773   struct GNUNET_HELLO_Message *hello;
3774   struct GNUNET_PeerIdentity target;
3775   struct NeighbourList *n;
3776   struct ForeignAddressList *fal;
3777   struct OwnAddressList *oal;
3778   struct TransportPlugin *tp;
3779   struct GNUNET_MessageHeader *prem;
3780   uint16_t ps;
3781   const char *addr;
3782   size_t slen;
3783   size_t alen;
3784
3785   ps = ntohs (pong->header.size);
3786   if (ps < sizeof (struct TransportPongMessage))
3787     {
3788       GNUNET_break_op (0);
3789       return GNUNET_NO;
3790     }
3791   addr = (const char*) &pong[1];
3792   slen = strlen (ve->transport_name) + 1;
3793   if ( (ps - sizeof (struct TransportPongMessage) < slen) ||
3794        (ve->challenge != challenge) ||
3795        (addr[slen-1] != '\0') ||
3796        (0 != strcmp (addr, ve->transport_name)) ||
3797        (ntohl (pong->purpose.size)
3798         != sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
3799         sizeof (uint32_t) +
3800         sizeof (struct GNUNET_TIME_AbsoluteNBO) +
3801         sizeof (struct GNUNET_PeerIdentity) + ps - sizeof (struct TransportPongMessage)) )
3802     {
3803       return GNUNET_YES;
3804     }
3805
3806   alen = ps - sizeof (struct TransportPongMessage) - slen;
3807   switch (ntohl (pong->purpose.purpose))
3808     {
3809     case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN:
3810       if ( (ve->addrlen + slen != ntohl (pong->addrlen)) ||
3811            (0 != memcmp (&addr[slen],
3812                          ve->addr,
3813                          ve->addrlen)) )
3814         {
3815           return GNUNET_YES; /* different entry, keep trying! */
3816         }
3817       if (0 != memcmp (&pong->pid,
3818                        key,
3819                        sizeof (struct GNUNET_PeerIdentity)))
3820         {
3821           GNUNET_break_op (0);
3822           return GNUNET_NO;
3823         }
3824       if (GNUNET_OK !=
3825           GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
3826                                     &pong->purpose,
3827                                     &pong->signature,
3828                                     &ve->publicKey))
3829         {
3830           GNUNET_break_op (0);
3831           return GNUNET_NO;
3832         }
3833
3834 #if DEBUG_TRANSPORT
3835       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3836                   "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
3837                   GNUNET_h2s (key),
3838                   a2s (ve->transport_name,
3839                        (const struct sockaddr *) ve->addr,
3840                        ve->addrlen),
3841                   ve->transport_name);
3842 #endif
3843       break;
3844     case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING:
3845       if (0 != memcmp (&pong->pid,
3846                          &my_identity,
3847                          sizeof (struct GNUNET_PeerIdentity)))
3848         {
3849           GNUNET_break_op (0);
3850           return GNUNET_NO;
3851         }
3852       if (ve->addrlen != 0)
3853         {
3854           /* must have been for a different validation entry */
3855           return GNUNET_YES;
3856         }
3857       tp = find_transport (ve->transport_name);
3858       if (tp == NULL)
3859         {
3860           GNUNET_break (0);
3861           return GNUNET_YES;
3862         }
3863       oal = tp->addresses;
3864       while (NULL != oal)
3865         {
3866           if ( (oal->addrlen == alen) &&
3867                (0 == memcmp (&oal[1],
3868                              &addr[slen],
3869                              alen)) )
3870             break;
3871           oal = oal->next;
3872         }
3873       if (oal == NULL)
3874         {
3875           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3876                       _("Not accepting PONG with address `%s' since I cannot confirm having this address.\n"),
3877                       a2s (ve->transport_name,
3878                            &addr[slen],
3879                            alen));
3880           return GNUNET_NO;     
3881         }
3882       if (GNUNET_OK !=
3883           GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING,
3884                                     &pong->purpose,
3885                                     &pong->signature,
3886                                     &ve->publicKey))
3887         {
3888           GNUNET_break_op (0);
3889           return GNUNET_NO;
3890         }
3891
3892 #if DEBUG_TRANSPORT
3893       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3894                   "Confirmed that peer `%4s' is talking to us using address `%s' (%s) for us.\n",
3895                   GNUNET_h2s (key),
3896                   a2s (ve->transport_name,
3897                        &addr[slen],
3898                        alen),
3899                   ve->transport_name);
3900 #endif
3901       break;
3902     default:
3903       GNUNET_break_op (0);
3904       return GNUNET_NO;
3905     }
3906   if (GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value == 0)
3907     {
3908       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3909                   _("Received expired signature.  Check system time.\n"));
3910       return GNUNET_NO;
3911     }
3912   GNUNET_STATISTICS_update (stats,
3913                             gettext_noop ("# address validation successes"),
3914                             1,
3915                             GNUNET_NO);
3916   /* create the updated HELLO */
3917   GNUNET_CRYPTO_hash (&ve->publicKey,
3918                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3919                       &target.hashPubKey);
3920   if (ve->addr != NULL)
3921     {
3922       avac.done = GNUNET_NO;
3923       avac.ve = ve;
3924       hello = GNUNET_HELLO_create (&ve->publicKey,
3925                                    &add_validated_address,
3926                                    &avac);
3927       GNUNET_PEERINFO_add_peer (peerinfo,
3928                                 hello);
3929       GNUNET_free (hello);
3930     }
3931   n = find_neighbour (&target);
3932   if (n != NULL)
3933     {
3934       n->publicKey = ve->publicKey;
3935       n->public_key_valid = GNUNET_YES;
3936       fal = add_peer_address (n,
3937                               ve->transport_name,
3938                               ve->session,
3939                               ve->addr,
3940                               ve->addrlen);
3941       GNUNET_assert (fal != NULL);
3942       fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
3943       fal->validated = GNUNET_YES;
3944       mark_address_connected (fal);
3945       GNUNET_STATISTICS_update (stats,
3946                                 gettext_noop ("# peer addresses considered valid"),
3947                                 1,
3948                                 GNUNET_NO);
3949       fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
3950       schedule_next_ping (fal);
3951       if (n->latency.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
3952         n->latency = fal->latency;
3953       else
3954         n->latency.rel_value = (fal->latency.rel_value + n->latency.rel_value) / 2;
3955
3956       n->distance = fal->distance;
3957       if (GNUNET_NO == n->received_pong)
3958         {
3959           n->received_pong = GNUNET_YES;
3960
3961           notify_clients_connect (&target, n->latency, n->distance);
3962           if (NULL != (prem = n->pre_connect_message_buffer))
3963             {
3964               n->pre_connect_message_buffer = NULL;
3965               handle_payload_message (prem, n);
3966               GNUNET_free (prem);
3967             }
3968         }
3969       if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
3970         {
3971           GNUNET_SCHEDULER_cancel (n->retry_task);
3972           n->retry_task = GNUNET_SCHEDULER_NO_TASK;
3973           try_transmission_to_peer (n);
3974         }
3975     }
3976
3977   /* clean up validation entry */
3978   GNUNET_assert (GNUNET_YES ==
3979                  GNUNET_CONTAINER_multihashmap_remove (validation_map,
3980                                                        key,
3981                                                        ve));
3982   abort_validation (NULL, NULL, ve);
3983   return GNUNET_NO;
3984 }
3985
3986
3987 /**
3988  * Function that will be called if we receive a validation
3989  * of an address challenge that we transmitted to another
3990  * peer.  Note that the validation should only be considered
3991  * acceptable if the challenge matches AND if the sender
3992  * address is at least a plausible address for this peer
3993  * (otherwise we may be seeing a MiM attack).
3994  *
3995  * @param cls closure
3996  * @param message the pong message
3997  * @param peer who responded to our challenge
3998  * @param sender_address string describing our sender address (as observed
3999  *         by the other peer in binary format)
4000  * @param sender_address_len number of bytes in 'sender_address'
4001  */
4002 static void
4003 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
4004              const struct GNUNET_PeerIdentity *peer,
4005              const char *sender_address,
4006              size_t sender_address_len)
4007 {
4008 #if DEBUG_TRANSPORT > 1
4009   /* we get tons of these that just get discarded, only log
4010      if we are quite verbose */
4011   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4012               "Receiving `%s' message from `%4s'.\n", "PONG",
4013               GNUNET_i2s (peer));
4014 #endif
4015   GNUNET_STATISTICS_update (stats,
4016                             gettext_noop ("# PONG messages received"),
4017                             1,
4018                             GNUNET_NO);
4019   if (GNUNET_SYSERR !=
4020       GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
4021                                                   &peer->hashPubKey,
4022                                                   &check_pending_validation,
4023                                                   (void*) message))
4024     {
4025       /* This is *expected* to happen a lot since we send
4026          PONGs to *all* known addresses of the sender of
4027          the PING, so most likely we get multiple PONGs
4028          per PING, and all but the first PONG will end up
4029          here. So really we should not print anything here
4030          unless we want to be very, very verbose... */
4031 #if DEBUG_TRANSPORT > 2
4032       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4033                   "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
4034                   "PONG",
4035                   GNUNET_i2s (peer),
4036                   "PING");
4037 #endif
4038       return;
4039     }
4040
4041 }
4042
4043
4044 /**
4045  * Try to validate a neighbour's address by sending him our HELLO and a PING.
4046  *
4047  * @param cls the 'struct ValidationEntry*'
4048  * @param neighbour neighbour to validate, NULL if validation failed
4049  */
4050 static void
4051 transmit_hello_and_ping (void *cls,
4052                          struct NeighbourList *neighbour)
4053 {
4054   struct ValidationEntry *va = cls;
4055   struct ForeignAddressList *peer_address;
4056   struct TransportPingMessage ping;
4057   uint16_t hello_size;
4058   size_t tsize;
4059   char * message_buf;
4060   struct GNUNET_PeerIdentity id;
4061   size_t slen;
4062
4063   GNUNET_CRYPTO_hash (&va->publicKey,
4064                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4065                       &id.hashPubKey);
4066   if (neighbour == NULL)
4067     {
4068       /* FIXME: stats... */
4069       GNUNET_break (GNUNET_OK ==
4070                     GNUNET_CONTAINER_multihashmap_remove (validation_map,
4071                                                           &id.hashPubKey,
4072                                                           va));
4073       abort_validation (NULL, NULL, va);
4074       return;
4075     }
4076   neighbour->publicKey = va->publicKey;
4077   neighbour->public_key_valid = GNUNET_YES;
4078   peer_address = add_peer_address (neighbour,
4079                                    va->transport_name, NULL,
4080                                    (const void*) &va[1],
4081                                    va->addrlen);
4082   if (peer_address == NULL)
4083     {
4084       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4085                   "Failed to add peer `%4s' for plugin `%s'\n",
4086                   GNUNET_i2s (&neighbour->id),
4087                   va->transport_name);
4088       GNUNET_break (GNUNET_OK ==
4089                     GNUNET_CONTAINER_multihashmap_remove (validation_map,
4090                                                           &id.hashPubKey,
4091                                                           va));
4092       abort_validation (NULL, NULL, va);
4093       return;
4094     }
4095   hello_size = GNUNET_HELLO_size(our_hello);
4096   slen = strlen(va->transport_name) + 1;
4097   tsize = sizeof(struct TransportPingMessage) + hello_size + va->addrlen + slen;
4098   message_buf = GNUNET_malloc(tsize);
4099   ping.challenge = htonl(va->challenge);
4100   ping.header.size = htons(sizeof(struct TransportPingMessage) + slen + va->addrlen);
4101   ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
4102   memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
4103   memcpy(message_buf, our_hello, hello_size);
4104   memcpy(&message_buf[hello_size],
4105          &ping,
4106          sizeof(struct TransportPingMessage));
4107   memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
4108          va->transport_name,
4109          slen);
4110   memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
4111          &va[1],
4112          va->addrlen);
4113 #if DEBUG_TRANSPORT
4114   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4115               "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
4116               (va->addrlen == 0)
4117               ? "<inbound>"
4118               : a2s (va->transport_name,
4119                      (const void*) &va[1], va->addrlen),
4120               va->transport_name,
4121               GNUNET_i2s (&neighbour->id),
4122               "HELLO", hello_size,
4123               "PING", sizeof (struct TransportPingMessage) + va->addrlen + slen);
4124 #endif
4125
4126   GNUNET_STATISTICS_update (stats,
4127                             gettext_noop ("# PING messages sent for initial validation"),
4128                             1,
4129                             GNUNET_NO);
4130   transmit_to_peer (NULL, peer_address,
4131                     GNUNET_SCHEDULER_PRIORITY_DEFAULT,
4132                     HELLO_VERIFICATION_TIMEOUT,
4133                     message_buf, tsize,
4134                     GNUNET_YES, neighbour);
4135   GNUNET_free(message_buf);
4136 }
4137
4138
4139 /**
4140  * Check if the given address is already being validated; if not,
4141  * append the given address to the list of entries that are being be
4142  * validated and initiate validation.
4143  *
4144  * @param cls closure ('struct CheckHelloValidatedContext *')
4145  * @param tname name of the transport
4146  * @param expiration expiration time
4147  * @param addr the address
4148  * @param addrlen length of the address
4149  * @return GNUNET_OK (always)
4150  */
4151 static int
4152 run_validation (void *cls,
4153                 const char *tname,
4154                 struct GNUNET_TIME_Absolute expiration,
4155                 const void *addr,
4156                 uint16_t addrlen)
4157 {
4158   struct CheckHelloValidatedContext *chvc = cls;
4159   struct GNUNET_PeerIdentity id;
4160   struct TransportPlugin *tp;
4161   struct ValidationEntry *va;
4162   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4163   struct CheckAddressExistsClosure caec;
4164   struct OwnAddressList *oal;
4165
4166   GNUNET_assert (addr != NULL);
4167
4168   GNUNET_STATISTICS_update (stats,
4169                             gettext_noop ("# peer addresses scheduled for validation"),
4170                             1,
4171                             GNUNET_NO);
4172   tp = find_transport (tname);
4173   if (tp == NULL)
4174     {
4175       GNUNET_log (GNUNET_ERROR_TYPE_INFO |
4176                   GNUNET_ERROR_TYPE_BULK,
4177                   _
4178                   ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
4179                   tname);
4180       GNUNET_STATISTICS_update (stats,
4181                                 gettext_noop ("# peer addresses not validated (plugin not available)"),
4182                                 1,
4183                                 GNUNET_NO);
4184       return GNUNET_OK;
4185     }
4186   /* check if this is one of our own addresses */
4187   oal = tp->addresses;
4188   while (NULL != oal)
4189     {
4190       if ( (oal->addrlen == addrlen) &&
4191            (0 == memcmp (&oal[1],
4192                          addr,
4193                          addrlen)) )
4194         {
4195           /* not plausible, this address is equivalent to our own address! */
4196           GNUNET_STATISTICS_update (stats,
4197                                     gettext_noop ("# peer addresses not validated (loopback)"),
4198                                     1,
4199                                     GNUNET_NO);
4200           return GNUNET_OK;
4201         }
4202       oal = oal->next;
4203     }
4204   GNUNET_HELLO_get_key (chvc->hello, &pk);
4205   GNUNET_CRYPTO_hash (&pk,
4206                       sizeof (struct
4207                               GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4208                       &id.hashPubKey);
4209
4210   if (is_blacklisted(&id, tp))
4211     {
4212 #if DEBUG_TRANSPORT
4213       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4214                   "Attempted to validate blacklisted peer `%s' using `%s'!\n",
4215                   GNUNET_i2s(&id),
4216                   tname);
4217 #endif
4218       return GNUNET_OK;
4219     }
4220
4221   caec.addr = addr;
4222   caec.addrlen = addrlen;
4223   caec.session = NULL;
4224   caec.tname = tname;
4225   caec.exists = GNUNET_NO;
4226   GNUNET_CONTAINER_multihashmap_iterate (validation_map,
4227                                          &check_address_exists,
4228                                          &caec);
4229   if (caec.exists == GNUNET_YES)
4230     {
4231       /* During validation attempts we will likely trigger the other
4232          peer trying to validate our address which in turn will cause
4233          it to send us its HELLO, so we expect to hit this case rather
4234          frequently.  Only print something if we are very verbose. */
4235 #if DEBUG_TRANSPORT > 1
4236       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4237                   "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
4238                   a2s (tname, addr, addrlen),
4239                   tname,
4240                   GNUNET_i2s (&id));
4241 #endif
4242       GNUNET_STATISTICS_update (stats,
4243                                 gettext_noop ("# peer addresses not validated (in progress)"),
4244                                 1,
4245                                 GNUNET_NO);
4246       return GNUNET_OK;
4247     }
4248   va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
4249   va->chvc = chvc;
4250   chvc->ve_count++;
4251   va->transport_name = GNUNET_strdup (tname);
4252   va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
4253                                             UINT_MAX);
4254   va->send_time = GNUNET_TIME_absolute_get();
4255   va->addr = (const void*) &va[1];
4256   memcpy (&va[1], addr, addrlen);
4257   va->addrlen = addrlen;
4258   GNUNET_HELLO_get_key (chvc->hello,
4259                         &va->publicKey);
4260   va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
4261                                                    &timeout_hello_validation,
4262                                                    va);
4263   GNUNET_CONTAINER_multihashmap_put (validation_map,
4264                                      &id.hashPubKey,
4265                                      va,
4266                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
4267   setup_peer_check_blacklist (&id, GNUNET_NO,
4268                               &transmit_hello_and_ping,
4269                               va);
4270   return GNUNET_OK;
4271 }
4272
4273
4274 /**
4275  * Check if addresses in validated hello "h" overlap with
4276  * those in "chvc->hello" and validate the rest.
4277  *
4278  * @param cls closure
4279  * @param peer id of the peer, NULL for last call
4280  * @param h hello message for the peer (can be NULL)
4281  * @param err_msg NULL if successful, otherwise contains error message
4282  */
4283 static void
4284 check_hello_validated (void *cls,
4285                        const struct GNUNET_PeerIdentity *peer,
4286                        const struct GNUNET_HELLO_Message *h,
4287                        const char *err_msg)
4288 {
4289   struct CheckHelloValidatedContext *chvc = cls;
4290   struct GNUNET_HELLO_Message *plain_hello;
4291   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4292   struct GNUNET_PeerIdentity target;
4293   struct NeighbourList *n;
4294
4295   if (err_msg != NULL)
4296   {
4297     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4298                 _("Error in communication with PEERINFO service\n"));
4299    /* return; */
4300   }
4301
4302   if (peer == NULL)
4303     {
4304       GNUNET_STATISTICS_update (stats,
4305                                 gettext_noop ("# outstanding peerinfo iterate requests"),
4306                                 -1,
4307                                 GNUNET_NO);
4308       chvc->piter = NULL;
4309       if (GNUNET_NO == chvc->hello_known)
4310         {
4311           /* notify PEERINFO about the peer now, so that we at least
4312              have the public key if some other component needs it */
4313           GNUNET_HELLO_get_key (chvc->hello, &pk);
4314           GNUNET_CRYPTO_hash (&pk,
4315                               sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4316                               &target.hashPubKey);
4317           plain_hello = GNUNET_HELLO_create (&pk,
4318                                              NULL,
4319                                              NULL);
4320           GNUNET_PEERINFO_add_peer (peerinfo, plain_hello);
4321           GNUNET_free (plain_hello);
4322 #if DEBUG_TRANSPORT_HELLO
4323           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4324                       "PEERINFO had no `%s' message for peer `%4s', full validation needed.\n",
4325                       "HELLO",
4326                       GNUNET_i2s (&target));
4327 #endif
4328           GNUNET_STATISTICS_update (stats,
4329                                     gettext_noop ("# new HELLOs requiring full validation"),
4330                                     1,
4331                                     GNUNET_NO);
4332           GNUNET_HELLO_iterate_addresses (chvc->hello,
4333                                           GNUNET_NO,
4334                                           &run_validation,
4335                                           chvc);
4336         }
4337       else
4338         {
4339           GNUNET_STATISTICS_update (stats,
4340                                     gettext_noop ("# duplicate HELLO (peer known)"),
4341                                     1,
4342                                     GNUNET_NO);
4343         }
4344       chvc->ve_count--;
4345       if (chvc->ve_count == 0)
4346         {
4347           GNUNET_CONTAINER_DLL_remove (chvc_head,
4348                                        chvc_tail,
4349                                        chvc);
4350           GNUNET_free (chvc);   
4351         }
4352       return;
4353     }
4354   if (h == NULL)
4355     return;
4356 #if DEBUG_TRANSPORT_HELLO
4357   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4358               "PEERINFO had `%s' message for peer `%4s', validating only new addresses.\n",
4359               "HELLO",
4360               GNUNET_i2s (peer));
4361 #endif
4362   chvc->hello_known = GNUNET_YES;
4363   n = find_neighbour (peer);
4364   if (n != NULL)
4365     {
4366 #if DEBUG_TRANSPORT_HELLO
4367       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4368                   "Calling hello_iterate_addresses for %s!\n",
4369                   GNUNET_i2s (peer));
4370 #endif
4371       GNUNET_HELLO_iterate_addresses (h,
4372                                       GNUNET_NO,
4373                                       &add_to_foreign_address_list,
4374                                       n);
4375       try_transmission_to_peer (n);
4376     }
4377   else
4378     {
4379 #if DEBUG_TRANSPORT_HELLO
4380       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4381                   "No existing neighbor record for %s!\n",
4382                   GNUNET_i2s (peer));
4383 #endif
4384       GNUNET_STATISTICS_update (stats,
4385                                 gettext_noop ("# no existing neighbour record (validating HELLO)"),
4386                                 1,
4387                                 GNUNET_NO);
4388     }
4389   GNUNET_STATISTICS_update (stats,
4390                             gettext_noop ("# HELLO validations (update case)"),
4391                             1,
4392                             GNUNET_NO);
4393   GNUNET_HELLO_iterate_new_addresses (chvc->hello,
4394                                       h,
4395                                       GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME),
4396                                       &run_validation,
4397                                       chvc);
4398 }
4399
4400
4401 /**
4402  * Process HELLO-message.
4403  *
4404  * @param plugin transport involved, may be NULL
4405  * @param message the actual message
4406  * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
4407  */
4408 static int
4409 process_hello (struct TransportPlugin *plugin,
4410                const struct GNUNET_MessageHeader *message)
4411 {
4412   uint16_t hsize;
4413   struct GNUNET_PeerIdentity target;
4414   const struct GNUNET_HELLO_Message *hello;
4415   struct CheckHelloValidatedContext *chvc;
4416   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
4417 #if DEBUG_TRANSPORT_HELLO > 2
4418   char *my_id;
4419 #endif
4420   hsize = ntohs (message->size);
4421   if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
4422       (hsize < sizeof (struct GNUNET_MessageHeader)))
4423     {
4424       GNUNET_break (0);
4425       return GNUNET_SYSERR;
4426     }
4427   GNUNET_STATISTICS_update (stats,
4428                             gettext_noop ("# HELLOs received for validation"),
4429                             1,
4430                             GNUNET_NO);
4431
4432   /* first, check if load is too high */
4433   if (GNUNET_SCHEDULER_get_load (GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
4434     {
4435       GNUNET_STATISTICS_update (stats,
4436                                 gettext_noop ("# HELLOs ignored due to high load"),
4437                                 1,
4438                                 GNUNET_NO);
4439 #if DEBUG_TRANSPORT_HELLO
4440       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4441                   "Ignoring `%s' for `%4s', load too high.\n",
4442                   "HELLO",
4443                   GNUNET_i2s (&target));
4444 #endif
4445       return GNUNET_OK;
4446     }
4447   hello = (const struct GNUNET_HELLO_Message *) message;
4448   if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
4449     {
4450 #if DEBUG_TRANSPORT_HELLO
4451       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4452                   "Unable to get public key from `%s' for `%4s'!\n",
4453                   "HELLO",
4454                   GNUNET_i2s (&target));
4455 #endif
4456       GNUNET_break_op (0);
4457       return GNUNET_SYSERR;
4458     }
4459
4460   GNUNET_CRYPTO_hash (&publicKey,
4461                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4462                       &target.hashPubKey);
4463
4464 #if DEBUG_TRANSPORT_HELLO
4465   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4466               "Received `%s' message for `%4s'\n",
4467               "HELLO",
4468               GNUNET_i2s (&target));
4469 #endif
4470
4471   if (0 == memcmp (&my_identity,
4472                    &target,
4473                    sizeof (struct GNUNET_PeerIdentity)))
4474     {
4475       GNUNET_STATISTICS_update (stats,
4476                                 gettext_noop ("# HELLOs ignored for validation (is my own HELLO)"),
4477                                 1,
4478                                 GNUNET_NO);
4479       return GNUNET_OK;
4480     }
4481   chvc = chvc_head;
4482   while (NULL != chvc)
4483     {
4484       if (GNUNET_HELLO_equals (hello,
4485                                chvc->hello,
4486                                GNUNET_TIME_absolute_get ()).abs_value > 0)
4487         {
4488 #if DEBUG_TRANSPORT_HELLO > 2
4489           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4490                       "Received duplicate `%s' message for `%4s'; ignored\n",
4491                       "HELLO",
4492                       GNUNET_i2s (&target));
4493 #endif
4494           return GNUNET_OK; /* validation already pending */
4495         }
4496       if (GNUNET_HELLO_size(hello) == GNUNET_HELLO_size (chvc->hello))
4497         GNUNET_break (0 != memcmp (hello, chvc->hello,
4498                                    GNUNET_HELLO_size(hello)));
4499       chvc = chvc->next;
4500     }
4501
4502 #if BREAK_TESTS
4503   struct NeighbourList *temp_neighbor = find_neighbour(&target);
4504   if ((NULL != temp_neighbor))
4505     {
4506       fprintf(stderr, "Already know peer, ignoring hello\n");
4507       return GNUNET_OK;
4508     }
4509 #endif
4510
4511 #if DEBUG_TRANSPORT_HELLO > 2
4512   if (plugin != NULL)
4513     {
4514       my_id = GNUNET_strdup(GNUNET_i2s(plugin->env.my_identity));
4515       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4516                   "%s: Starting validation of `%s' message for `%4s' via '%s' of size %u\n",
4517                   my_id,
4518                   "HELLO",
4519                   GNUNET_i2s (&target),
4520                   plugin->short_name,
4521                   GNUNET_HELLO_size(hello));
4522       GNUNET_free(my_id);
4523     }
4524 #endif
4525   chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
4526   chvc->ve_count = 1;
4527   chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
4528   memcpy (&chvc[1], hello, hsize);
4529   GNUNET_CONTAINER_DLL_insert (chvc_head,
4530                                chvc_tail,
4531                                chvc);
4532   /* finally, check if HELLO was previously validated
4533      (continuation will then schedule actual validation) */
4534   GNUNET_STATISTICS_update (stats,
4535                             gettext_noop ("# peerinfo process hello iterate requests"),
4536                             1,
4537                             GNUNET_NO);
4538   GNUNET_STATISTICS_update (stats,
4539                             gettext_noop ("# outstanding peerinfo iterate requests"),
4540                             1,
4541                             GNUNET_NO);
4542   chvc->piter = GNUNET_PEERINFO_iterate (peerinfo,
4543                                          &target,
4544                                          HELLO_VERIFICATION_TIMEOUT,
4545                                          &check_hello_validated, chvc);
4546   return GNUNET_OK;
4547 }
4548
4549
4550 /**
4551  * The peer specified by the given neighbour has timed-out or a plugin
4552  * has disconnected.  We may either need to do nothing (other plugins
4553  * still up), or trigger a full disconnect and clean up.  This
4554  * function updates our state and does the necessary notifications.
4555  * Also notifies our clients that the neighbour is now officially
4556  * gone.
4557  *
4558  * @param n the neighbour list entry for the peer
4559  * @param check GNUNET_YES to check if ALL addresses for this peer
4560  *              are gone, GNUNET_NO to force a disconnect of the peer
4561  *              regardless of whether other addresses exist.
4562  */
4563 static void
4564 disconnect_neighbour (struct NeighbourList *n, int check)
4565 {
4566   struct ReadyList *rpos;
4567   struct NeighbourList *npos;
4568   struct NeighbourList *nprev;
4569   struct MessageQueue *mq;
4570   struct ForeignAddressList *peer_addresses;
4571   struct ForeignAddressList *peer_pos;
4572
4573   if (GNUNET_YES == check)
4574     {
4575       rpos = n->plugins;
4576       while (NULL != rpos)
4577         {
4578           peer_addresses = rpos->addresses;
4579           while (peer_addresses != NULL)
4580             {
4581               if (GNUNET_YES == peer_addresses->connected)
4582                 {
4583                   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4584                             "NOT Disconnecting from `%4s', still have live addresses!\n",
4585                             GNUNET_i2s (&n->id));
4586                   return;             /* still connected */
4587                 }
4588               peer_addresses = peer_addresses->next;
4589             }
4590           rpos = rpos->next;
4591         }
4592     }
4593 #if DEBUG_TRANSPORT
4594   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4595               "Disconnecting from `%4s'\n",
4596               GNUNET_i2s (&n->id));
4597 #endif
4598   /* remove n from neighbours list */
4599   nprev = NULL;
4600   npos = neighbours;
4601   while ((npos != NULL) && (npos != n))
4602     {
4603       nprev = npos;
4604       npos = npos->next;
4605     }
4606   GNUNET_assert (npos != NULL);
4607   if (nprev == NULL)
4608     neighbours = n->next;
4609   else
4610     nprev->next = n->next;
4611
4612   /* notify all clients about disconnect */
4613   if (GNUNET_YES == n->received_pong)
4614     notify_clients_disconnect (&n->id);
4615
4616   /* clean up all plugins, cancel connections and pending transmissions */
4617   while (NULL != (rpos = n->plugins))
4618     {
4619       n->plugins = rpos->next;
4620       rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
4621       while (rpos->addresses != NULL)
4622         {
4623           peer_pos = rpos->addresses;
4624           rpos->addresses = peer_pos->next;
4625           if (peer_pos->connected == GNUNET_YES)
4626             GNUNET_STATISTICS_update (stats,
4627                                       gettext_noop ("# connected addresses"),
4628                                       -1,
4629                                       GNUNET_NO);
4630           if (GNUNET_YES == peer_pos->validated)
4631             GNUNET_STATISTICS_update (stats,
4632                                       gettext_noop ("# peer addresses considered valid"),
4633                                       -1,
4634                                       GNUNET_NO);
4635           if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
4636             {
4637               GNUNET_SCHEDULER_cancel (peer_pos->revalidate_task);
4638               peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
4639             }
4640                   GNUNET_free(peer_pos->ressources);
4641           GNUNET_free(peer_pos);
4642         }
4643       GNUNET_free (rpos);
4644     }
4645
4646   /* free all messages on the queue */
4647   while (NULL != (mq = n->messages_head))
4648     {
4649       GNUNET_STATISTICS_update (stats,
4650                                 gettext_noop ("# bytes in message queue for other peers"),
4651                                 - (int64_t) mq->message_buf_size,
4652                                 GNUNET_NO);
4653       GNUNET_STATISTICS_update (stats,
4654                                 gettext_noop ("# bytes discarded due to disconnect"),
4655                                 mq->message_buf_size,
4656                                 GNUNET_NO);
4657       GNUNET_CONTAINER_DLL_remove (n->messages_head,
4658                                    n->messages_tail,
4659                                    mq);
4660       GNUNET_assert (0 == memcmp(&mq->neighbour_id,
4661                                  &n->id,
4662                                  sizeof(struct GNUNET_PeerIdentity)));
4663       GNUNET_free (mq);
4664     }
4665   if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
4666     {
4667       GNUNET_SCHEDULER_cancel (n->timeout_task);
4668       n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
4669     }
4670   if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4671     {
4672       GNUNET_SCHEDULER_cancel (n->retry_task);
4673       n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4674     }
4675   if (n->piter != NULL)
4676     {
4677       GNUNET_PEERINFO_iterate_cancel (n->piter);
4678       GNUNET_STATISTICS_update (stats,
4679                                 gettext_noop ("# outstanding peerinfo iterate requests"),
4680                                 -1,
4681                                 GNUNET_NO);
4682       n->piter = NULL;
4683     }
4684   /* finally, free n itself */
4685   GNUNET_STATISTICS_update (stats,
4686                             gettext_noop ("# active neighbours"),
4687                             -1,
4688                             GNUNET_NO);
4689   GNUNET_free_non_null (n->pre_connect_message_buffer);
4690   GNUNET_free (n);
4691 }
4692
4693
4694 /**
4695  * We have received a PING message from someone.  Need to send a PONG message
4696  * in response to the peer by any means necessary.
4697  */
4698 static int
4699 handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
4700             const struct GNUNET_PeerIdentity *peer,
4701             struct Session *session,
4702             const char *sender_address,
4703             uint16_t sender_address_len)
4704 {
4705   struct TransportPlugin *plugin = cls;
4706   struct SessionHeader *session_header = (struct SessionHeader*) session;
4707   struct TransportPingMessage *ping;
4708   struct TransportPongMessage *pong;
4709   struct NeighbourList *n;
4710   struct ReadyList *rl;
4711   struct ForeignAddressList *fal;
4712   struct OwnAddressList *oal;
4713   const char *addr;
4714   size_t alen;
4715   size_t slen;
4716
4717   if (ntohs (message->size) < sizeof (struct TransportPingMessage))
4718     {
4719       GNUNET_break_op (0);
4720       return GNUNET_SYSERR;
4721     }
4722
4723   ping = (struct TransportPingMessage *) message;
4724   if (0 != memcmp (&ping->target,
4725                    plugin->env.my_identity,
4726                    sizeof (struct GNUNET_PeerIdentity)))
4727     {
4728       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4729                   _("Received `%s' message from `%s' destined for `%s' which is not me!\n"),
4730                   "PING",
4731                   (sender_address != NULL)
4732                   ? a2s (plugin->short_name,
4733                          (const struct sockaddr *)sender_address,
4734                          sender_address_len)
4735                   : "<inbound>",
4736                   GNUNET_i2s (&ping->target));
4737       return GNUNET_SYSERR;
4738     }
4739 #if DEBUG_PING_PONG
4740   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4741               "Processing `%s' from `%s'\n",
4742               "PING",
4743               (sender_address != NULL)
4744               ? a2s (plugin->short_name,
4745                      (const struct sockaddr *)sender_address,
4746                      sender_address_len)
4747               : "<inbound>");
4748 #endif
4749   GNUNET_STATISTICS_update (stats,
4750                             gettext_noop ("# PING messages received"),
4751                             1,
4752                             GNUNET_NO);
4753   addr = (const char*) &ping[1];
4754   alen = ntohs (message->size) - sizeof (struct TransportPingMessage);
4755   slen = strlen (plugin->short_name) + 1;
4756   if (alen == 0)
4757     {
4758       /* peer wants to confirm that we have an outbound connection to him */
4759       if (session == NULL)
4760         {
4761           GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4762                       _("Refusing to create PONG since I do not have a session with `%s'.\n"),
4763                       GNUNET_i2s (peer));
4764           return GNUNET_SYSERR;
4765         }
4766       pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len + slen);
4767       pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len + slen);
4768       pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
4769       pong->purpose.size =
4770         htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4771                sizeof (uint32_t) +
4772                sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4773                sizeof (struct GNUNET_PeerIdentity) + sender_address_len + slen);
4774       pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING);
4775       pong->challenge = ping->challenge;
4776       pong->addrlen = htonl(sender_address_len + slen);
4777       memcpy(&pong->pid,
4778              peer,
4779              sizeof(struct GNUNET_PeerIdentity));
4780       memcpy (&pong[1],
4781               plugin->short_name,
4782               slen);
4783       if ((sender_address!=NULL) && (sender_address_len > 0))
4784                   memcpy (&((char*)&pong[1])[slen],
4785                           sender_address,
4786                           sender_address_len);
4787       if (GNUNET_TIME_absolute_get_remaining (session_header->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4)
4788         {
4789           /* create / update cached sig */
4790 #if DEBUG_TRANSPORT
4791           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4792                       "Creating PONG signature to indicate active connection.\n");
4793 #endif
4794           session_header->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
4795           pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
4796           GNUNET_assert (GNUNET_OK ==
4797                          GNUNET_CRYPTO_rsa_sign (my_private_key,
4798                                                  &pong->purpose,
4799                                                  &session_header->pong_signature));
4800         }
4801       else
4802         {
4803           pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
4804         }
4805       memcpy (&pong->signature,
4806               &session_header->pong_signature,
4807               sizeof (struct GNUNET_CRYPTO_RsaSignature));
4808
4809
4810     }
4811   else
4812     {
4813       /* peer wants to confirm that this is one of our addresses */
4814       addr += slen;
4815       alen -= slen;
4816       if (GNUNET_OK !=
4817           plugin->api->check_address (plugin->api->cls,
4818                                       addr,
4819                                       alen))
4820         {
4821           GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4822                       _("Not confirming PING with address `%s' since I cannot confirm having this address.\n"),
4823                       a2s (plugin->short_name,
4824                            addr,
4825                            alen));
4826           return GNUNET_NO;
4827         }
4828       oal = plugin->addresses;
4829       while (NULL != oal)
4830         {
4831           if ( (oal->addrlen == alen) &&
4832                (0 == memcmp (addr,
4833                              &oal[1],
4834                              alen)) )
4835             break;
4836           oal = oal->next;
4837         }
4838       pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + alen + slen);
4839       pong->header.size = htons (sizeof (struct TransportPongMessage) + alen + slen);
4840       pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
4841       pong->purpose.size =
4842         htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4843                sizeof (uint32_t) +
4844                sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4845                sizeof (struct GNUNET_PeerIdentity) + alen + slen);
4846       pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN);
4847       pong->challenge = ping->challenge;
4848       pong->addrlen = htonl(alen + slen);
4849       memcpy(&pong->pid,
4850              &my_identity,
4851              sizeof(struct GNUNET_PeerIdentity));
4852       memcpy (&pong[1], plugin->short_name, slen);
4853       memcpy (&((char*)&pong[1])[slen], addr, alen);
4854       if ( (oal != NULL) &&
4855            (GNUNET_TIME_absolute_get_remaining (oal->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4) )
4856         {
4857           /* create / update cached sig */
4858 #if DEBUG_TRANSPORT
4859           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4860                       "Creating PONG signature to indicate ownership.\n");
4861 #endif
4862           oal->pong_sig_expires = GNUNET_TIME_absolute_min (oal->expires,
4863                                                             GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
4864           pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
4865           GNUNET_assert (GNUNET_OK ==
4866                          GNUNET_CRYPTO_rsa_sign (my_private_key,
4867                                                  &pong->purpose,
4868                                                  &oal->pong_signature));        
4869           memcpy (&pong->signature,
4870                   &oal->pong_signature,
4871                   sizeof (struct GNUNET_CRYPTO_RsaSignature));
4872         }
4873       else if (oal == NULL)
4874         {
4875           /* not using cache (typically DV-only) */
4876           pong->expiration = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
4877           GNUNET_assert (GNUNET_OK ==
4878                          GNUNET_CRYPTO_rsa_sign (my_private_key,
4879                                                  &pong->purpose,
4880                                                  &pong->signature));    
4881         }
4882       else
4883         {
4884           /* can used cached version */
4885           pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
4886           memcpy (&pong->signature,
4887                   &oal->pong_signature,
4888                   sizeof (struct GNUNET_CRYPTO_RsaSignature));
4889         }
4890     }
4891   n = find_neighbour(peer);
4892   GNUNET_assert (n != NULL);
4893   /* first try reliable response transmission */
4894   rl = n->plugins;
4895   while (rl != NULL)
4896     {
4897       fal = rl->addresses;
4898       while (fal != NULL)
4899         {
4900           if (-1 != rl->plugin->api->send (rl->plugin->api->cls,
4901                                            peer,
4902                                            (const char*) pong,
4903                                            ntohs (pong->header.size),
4904                                            TRANSPORT_PONG_PRIORITY,
4905                                            HELLO_VERIFICATION_TIMEOUT,
4906                                            fal->session,
4907                                            fal->addr,
4908                                            fal->addrlen,
4909                                            GNUNET_SYSERR,
4910                                            NULL, NULL))
4911             {
4912               /* done! */
4913               GNUNET_STATISTICS_update (stats,
4914                                         gettext_noop ("# PONGs unicast via reliable transport"),
4915                                         1,
4916                                         GNUNET_NO);
4917               GNUNET_free (pong);
4918               return GNUNET_OK;
4919             }
4920           fal = fal->next;
4921         }
4922       rl = rl->next;
4923     }
4924   /* no reliable method found, do multicast */
4925   GNUNET_STATISTICS_update (stats,
4926                             gettext_noop ("# PONGs multicast to all available addresses"),
4927                             1,
4928                             GNUNET_NO);
4929   rl = n->plugins;
4930   while (rl != NULL)
4931     {
4932       fal = rl->addresses;
4933       while (fal != NULL)
4934         {
4935           transmit_to_peer(NULL, fal,
4936                            TRANSPORT_PONG_PRIORITY,
4937                            HELLO_VERIFICATION_TIMEOUT,
4938                            (const char *)pong,
4939                            ntohs(pong->header.size),
4940                            GNUNET_YES,
4941                            n);
4942           fal = fal->next;
4943         }
4944       rl = rl->next;
4945     }
4946   GNUNET_free(pong);
4947   return GNUNET_OK;
4948 }
4949
4950
4951 /**
4952  * Function called by the plugin for each received message.
4953  * Update data volumes, possibly notify plugins about
4954  * reducing the rate at which they read from the socket
4955  * and generally forward to our receive callback.
4956  *
4957  * @param cls the "struct TransportPlugin *" we gave to the plugin
4958  * @param peer (claimed) identity of the other peer
4959  * @param message the message, NULL if we only care about
4960  *                learning about the delay until we should receive again
4961  * @param ats_data information for automatic transport selection
4962  * @param ats_count number of elements in ats not including 0-terminator
4963  * @param session identifier used for this session (can be NULL)
4964  * @param sender_address binary address of the sender (if observed)
4965  * @param sender_address_len number of bytes in sender_address
4966  * @return how long in ms the plugin should wait until receiving more data
4967  *         (plugins that do not support this, can ignore the return value)
4968  */
4969 static struct GNUNET_TIME_Relative
4970 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
4971                     const struct GNUNET_MessageHeader *message,
4972                     const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
4973                     uint32_t ats_count,
4974                     struct Session *session,
4975                     const char *sender_address,
4976                     uint16_t sender_address_len)
4977 {
4978   struct TransportPlugin *plugin = cls;
4979   struct ReadyList *service_context;
4980   struct ForeignAddressList *peer_address;
4981   uint16_t msize;
4982   struct NeighbourList *n;
4983   struct GNUNET_TIME_Relative ret;
4984   if (is_blacklisted (peer, plugin))
4985     return GNUNET_TIME_UNIT_FOREVER_REL;
4986   uint32_t distance;
4987   int c;
4988
4989   n = find_neighbour (peer);
4990   if (n == NULL)
4991     n = setup_new_neighbour (peer, GNUNET_YES);
4992   service_context = n->plugins;
4993   while ((service_context != NULL) && (plugin != service_context->plugin))
4994     service_context = service_context->next;
4995   GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
4996   peer_address = NULL;
4997   distance = 1;
4998   for (c=0; c<ats_count; c++)
4999   {
5000           if (ntohl(ats_data[c].type) == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
5001           {
5002                   distance = ntohl(ats_data[c].value);
5003           }
5004   }
5005   /* notify ATS about incoming data */
5006   ats_notify_ats_data(peer, ats_data);
5007
5008   if (message != NULL)
5009     {
5010       if ( (session != NULL) ||
5011            (sender_address != NULL) )
5012         peer_address = add_peer_address (n,
5013                                          plugin->short_name,
5014                                          session,
5015                                          sender_address,
5016                                          sender_address_len);
5017       if (peer_address != NULL)
5018         {
5019           peer_address->distance = distance;
5020           if (GNUNET_YES == peer_address->validated)
5021             mark_address_connected (peer_address);
5022           peer_address->timeout
5023             =
5024             GNUNET_TIME_relative_to_absolute
5025             (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5026           schedule_next_ping (peer_address);
5027         }
5028       /* update traffic received amount ... */
5029       msize = ntohs (message->size);
5030       GNUNET_STATISTICS_update (stats,
5031                                 gettext_noop ("# bytes received from other peers"),
5032                                 msize,
5033                                 GNUNET_NO);
5034       n->distance = distance;
5035       n->peer_timeout =
5036         GNUNET_TIME_relative_to_absolute
5037         (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5038       GNUNET_SCHEDULER_cancel (n->timeout_task);
5039       n->timeout_task =
5040         GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
5041                                       &neighbour_timeout_task, n);
5042       if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
5043         {
5044           /* dropping message due to frequent inbound volume violations! */
5045           GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
5046                       GNUNET_ERROR_TYPE_BULK,
5047                       _
5048                       ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
5049                       n->in_tracker.available_bytes_per_s__,
5050                       n->quota_violation_count);
5051           GNUNET_STATISTICS_update (stats,
5052                                     gettext_noop ("# bandwidth quota violations by other peers"),
5053                                     1,
5054                                     GNUNET_NO);
5055           return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
5056         }
5057
5058 #if DEBUG_PING_PONG
5059           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5060                       "Received message of type %u and size %u from `%4s', sending to all clients.\n",
5061                       ntohs (message->type),
5062                       ntohs (message->size),
5063                       GNUNET_i2s (peer));
5064 #endif
5065       switch (ntohs (message->type))
5066         {
5067         case GNUNET_MESSAGE_TYPE_HELLO:
5068           GNUNET_STATISTICS_update (stats,
5069                                     gettext_noop ("# HELLO messages received from other peers"),
5070                                     1,
5071                                     GNUNET_NO);
5072           process_hello (plugin, message);
5073           break;
5074         case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
5075           handle_ping (plugin, message, peer, session, sender_address, sender_address_len);
5076           break;
5077         case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
5078           handle_pong (plugin, message, peer, sender_address, sender_address_len);
5079           break;
5080         default:
5081           handle_payload_message (message, n);
5082           break;
5083         }
5084     }
5085   ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
5086   if (ret.rel_value > 0)
5087     {
5088       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5089                   "Throttling read (%llu bytes excess at %u b/s), waiting %llums before reading more.\n",
5090                   (unsigned long long) n->in_tracker.consumption_since_last_update__,
5091                   (unsigned int) n->in_tracker.available_bytes_per_s__,
5092                   (unsigned long long) ret.rel_value);
5093       GNUNET_STATISTICS_update (stats,
5094                                 gettext_noop ("# ms throttling suggested"),
5095                                 (int64_t) ret.rel_value,
5096                                 GNUNET_NO);
5097     }
5098   return ret;
5099 }
5100
5101 /**
5102  * Handle START-message.  This is the first message sent to us
5103  * by any client which causes us to add it to our list.
5104  *
5105  * @param cls closure (always NULL)
5106  * @param client identification of the client
5107  * @param message the actual message
5108  */
5109 static void
5110 handle_start (void *cls,
5111               struct GNUNET_SERVER_Client *client,
5112               const struct GNUNET_MessageHeader *message)
5113 {
5114   const struct StartMessage *start;
5115   struct TransportClient *c;
5116   struct ConnectInfoMessage * cim;
5117   struct NeighbourList *n;
5118   uint32_t ats_count;
5119   size_t size;
5120
5121   start = (const struct StartMessage*) message;
5122 #if DEBUG_TRANSPORT
5123   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5124               "Received `%s' request from client\n", "START");
5125 #endif
5126   c = clients;
5127   while (c != NULL)
5128     {
5129       if (c->client == client)
5130         {
5131           /* client already on our list! */
5132           GNUNET_break (0);
5133           GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5134           return;
5135         }
5136       c = c->next;
5137     }
5138   if ( (GNUNET_NO != ntohl (start->do_check)) &&
5139        (0 != memcmp (&start->self,
5140                      &my_identity,
5141                      sizeof (struct GNUNET_PeerIdentity))) )
5142     {
5143       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5144                   _("Rejecting control connection from peer `%s', which is not me!\n"),
5145                   GNUNET_i2s (&start->self));
5146       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5147       return;
5148     }
5149   c = GNUNET_malloc (sizeof (struct TransportClient));
5150   c->next = clients;
5151   clients = c;
5152   c->client = client;
5153   if (our_hello != NULL)
5154   {
5155 #if DEBUG_TRANSPORT
5156       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5157                   "Sending our own `%s' to new client\n", "HELLO");
5158 #endif
5159       transmit_to_client (c,
5160                           (const struct GNUNET_MessageHeader *) our_hello,
5161                           GNUNET_NO);
5162       /* tell new client about all existing connections */
5163       ats_count = 2;
5164       size  = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
5165       if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
5166       {
5167           GNUNET_break(0);
5168       }
5169       cim = GNUNET_malloc (size);
5170       cim->header.size = htons (size);
5171       cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
5172       cim->ats_count = htonl(ats_count);
5173       (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
5174       (&(cim->ats))[2].value = htonl (0);
5175       n = neighbours;
5176       while (n != NULL)
5177           {
5178                   if (GNUNET_YES == n->received_pong)
5179                   {
5180                           (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5181                           (&(cim->ats))[0].value = htonl (n->distance);
5182                           (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
5183                           (&(cim->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
5184                           cim->id = n->id;
5185                           transmit_to_client (c, &cim->header, GNUNET_NO);
5186                   }
5187             n = n->next;
5188       }
5189       GNUNET_free (cim);
5190   }
5191   GNUNET_SERVER_receive_done (client, GNUNET_OK);
5192 }
5193
5194
5195 /**
5196  * Handle HELLO-message.
5197  *
5198  * @param cls closure (always NULL)
5199  * @param client identification of the client
5200  * @param message the actual message
5201  */
5202 static void
5203 handle_hello (void *cls,
5204               struct GNUNET_SERVER_Client *client,
5205               const struct GNUNET_MessageHeader *message)
5206 {
5207   int ret;
5208
5209   GNUNET_STATISTICS_update (stats,
5210                             gettext_noop ("# HELLOs received from clients"),
5211                             1,
5212                             GNUNET_NO);
5213   ret = process_hello (NULL, message);
5214   GNUNET_SERVER_receive_done (client, ret);
5215 }
5216
5217
5218 /**
5219  * Closure for 'transmit_client_message'; followed by
5220  * 'msize' bytes of the actual message.
5221  */
5222 struct TransmitClientMessageContext
5223 {
5224   /**
5225    * Client on whom's behalf we are sending.
5226    */
5227   struct GNUNET_SERVER_Client *client;
5228
5229   /**
5230    * Timeout for the transmission.
5231    */
5232   struct GNUNET_TIME_Absolute timeout;
5233
5234   /**
5235    * Message priority.
5236    */
5237   uint32_t priority;
5238
5239   /**
5240    * Size of the message in bytes.
5241    */
5242   uint16_t msize;
5243 };
5244
5245
5246 /**
5247  * Schedule transmission of a message we got from a client to a peer.
5248  *
5249  * @param cls the 'struct TransmitClientMessageContext*'
5250  * @param n destination, or NULL on error (in that case, drop the message)
5251  */
5252 static void
5253 transmit_client_message (void *cls,
5254                          struct NeighbourList *n)
5255 {
5256   struct TransmitClientMessageContext *tcmc = cls;
5257   struct TransportClient *tc;
5258
5259   tc = clients;
5260   while ((tc != NULL) && (tc->client != tcmc->client))
5261     tc = tc->next;
5262
5263   if (n != NULL)
5264     {
5265       transmit_to_peer (tc, NULL, tcmc->priority,
5266                         GNUNET_TIME_absolute_get_remaining (tcmc->timeout),
5267                         (char *)&tcmc[1],
5268                         tcmc->msize, GNUNET_NO, n);
5269     }
5270   GNUNET_SERVER_receive_done (tcmc->client, GNUNET_OK);
5271   GNUNET_SERVER_client_drop (tcmc->client);
5272   GNUNET_free (tcmc);
5273 }
5274
5275
5276 /**
5277  * Handle SEND-message.
5278  *
5279  * @param cls closure (always NULL)
5280  * @param client identification of the client
5281  * @param message the actual message
5282  */
5283 static void
5284 handle_send (void *cls,
5285              struct GNUNET_SERVER_Client *client,
5286              const struct GNUNET_MessageHeader *message)
5287 {
5288   const struct OutboundMessage *obm;
5289   const struct GNUNET_MessageHeader *obmm;
5290   struct TransmitClientMessageContext *tcmc;
5291   uint16_t size;
5292   uint16_t msize;
5293
5294   size = ntohs (message->size);
5295   if (size <
5296       sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
5297     {
5298       GNUNET_break (0);
5299       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5300       return;
5301     }
5302   GNUNET_STATISTICS_update (stats,
5303                             gettext_noop ("# payload received for other peers"),
5304                             size,
5305                             GNUNET_NO);
5306   obm = (const struct OutboundMessage *) message;
5307   obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5308   msize = size - sizeof (struct OutboundMessage);
5309
5310   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5311               "Received `%s' request from client with target `%4s' and message of type %u and size %u\n",
5312               "SEND", GNUNET_i2s (&obm->peer),
5313               ntohs (obmm->type),
5314               msize);
5315
5316   tcmc = GNUNET_malloc (sizeof (struct TransmitClientMessageContext) + msize);
5317   tcmc->client = client;
5318   tcmc->priority = ntohl (obm->priority);
5319   tcmc->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
5320   tcmc->msize = msize;
5321   /* FIXME: this memcpy can be up to 7% of our total runtime */
5322   memcpy (&tcmc[1], obmm, msize);
5323   GNUNET_SERVER_client_keep (client);
5324   setup_peer_check_blacklist (&obm->peer, GNUNET_YES,
5325                               &transmit_client_message,
5326                               tcmc);
5327 }
5328
5329
5330 /**
5331  * Handle request connect message
5332  *
5333  * @param cls closure (always NULL)
5334  * @param client identification of the client
5335  * @param message the actual message
5336  */
5337 static void
5338 handle_request_connect (void *cls,
5339                         struct GNUNET_SERVER_Client *client,
5340                         const struct GNUNET_MessageHeader *message)
5341 {
5342   const struct TransportRequestConnectMessage *trcm =
5343     (const struct TransportRequestConnectMessage *) message;
5344
5345   GNUNET_STATISTICS_update (stats,
5346                             gettext_noop ("# REQUEST CONNECT messages received"),
5347                             1,
5348                             GNUNET_NO);
5349   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Received a request connect message for peer %s\n", GNUNET_i2s(&trcm->peer));
5350   setup_peer_check_blacklist (&trcm->peer, GNUNET_YES,
5351                               NULL, NULL);
5352   GNUNET_SERVER_receive_done (client, GNUNET_OK);
5353 }
5354
5355 /**
5356  * Handle SET_QUOTA-message.
5357  *
5358  * @param cls closure (always NULL)
5359  * @param client identification of the client
5360  * @param message the actual message
5361  */
5362 static void
5363 handle_set_quota (void *cls,
5364                   struct GNUNET_SERVER_Client *client,
5365                   const struct GNUNET_MessageHeader *message)
5366 {
5367   const struct QuotaSetMessage *qsm =
5368     (const struct QuotaSetMessage *) message;
5369   struct NeighbourList *n;
5370
5371   GNUNET_STATISTICS_update (stats,
5372                             gettext_noop ("# SET QUOTA messages received"),
5373                             1,
5374                             GNUNET_NO);
5375   n = find_neighbour (&qsm->peer);
5376   if (n == NULL)
5377     {
5378       GNUNET_SERVER_receive_done (client, GNUNET_OK);
5379       GNUNET_STATISTICS_update (stats,
5380                                 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
5381                                 1,
5382                                 GNUNET_NO);
5383       return;
5384     }
5385 #if DEBUG_TRANSPORT
5386   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5387               "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
5388               "SET_QUOTA",
5389               (unsigned int) ntohl (qsm->quota.value__),
5390               (unsigned int) n->in_tracker.available_bytes_per_s__,
5391               GNUNET_i2s (&qsm->peer));
5392 #endif
5393   GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
5394                                          qsm->quota);
5395   if (0 == ntohl (qsm->quota.value__))
5396     {
5397       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5398                 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&n->id),
5399                 "SET_QUOTA");
5400       disconnect_neighbour (n, GNUNET_NO);
5401     }
5402   GNUNET_SERVER_receive_done (client, GNUNET_OK);
5403 }
5404
5405
5406 /**
5407  * Take the given address and append it to the set of results sent back to
5408  * the client.
5409  *
5410  * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
5411  * @param address the resolved name, NULL to indicate the last response
5412  */
5413 static void
5414 transmit_address_to_client (void *cls, const char *address)
5415 {
5416   struct GNUNET_SERVER_TransmitContext *tc = cls;
5417   size_t slen;
5418
5419   if (NULL == address)
5420     slen = 0;
5421   else
5422     slen = strlen (address) + 1;
5423
5424   GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
5425                                               GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5426   if (NULL == address)
5427     GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5428 }
5429
5430
5431 /**
5432  * Handle AddressLookup-message.
5433  *
5434  * @param cls closure (always NULL)
5435  * @param client identification of the client
5436  * @param message the actual message
5437  */
5438 static void
5439 handle_address_lookup (void *cls,
5440                        struct GNUNET_SERVER_Client *client,
5441                        const struct GNUNET_MessageHeader *message)
5442 {
5443   const struct AddressLookupMessage *alum;
5444   struct TransportPlugin *lsPlugin;
5445   const char *nameTransport;
5446   const char *address;
5447   uint16_t size;
5448   struct GNUNET_SERVER_TransmitContext *tc;
5449   struct GNUNET_TIME_Absolute timeout;
5450   struct GNUNET_TIME_Relative rtimeout;
5451   int32_t numeric;
5452
5453   size = ntohs (message->size);
5454   if (size < sizeof (struct AddressLookupMessage))
5455     {
5456       GNUNET_break_op (0);
5457       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5458       return;
5459     }
5460   alum = (const struct AddressLookupMessage *) message;
5461   uint32_t addressLen = ntohl (alum->addrlen);
5462   if (size <= sizeof (struct AddressLookupMessage) + addressLen)
5463     {
5464       GNUNET_break_op (0);
5465       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5466       return;
5467     }
5468   address = (const char *) &alum[1];
5469   nameTransport = (const char *) &address[addressLen];
5470   if (nameTransport
5471       [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
5472     {
5473       GNUNET_break_op (0);
5474       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5475       return;
5476     }
5477   timeout = GNUNET_TIME_absolute_ntoh (alum->timeout);
5478   rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
5479   numeric = ntohl (alum->numeric_only);
5480   lsPlugin = find_transport (nameTransport);
5481   if (NULL == lsPlugin)
5482     {
5483       tc = GNUNET_SERVER_transmit_context_create (client);
5484       GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5485                                                   GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5486       GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5487       return;
5488     }
5489   tc = GNUNET_SERVER_transmit_context_create (client);
5490   lsPlugin->api->address_pretty_printer (lsPlugin->api->cls,
5491                                          nameTransport,
5492                                          address, addressLen,
5493                                          numeric,
5494                                          rtimeout,
5495                                          &transmit_address_to_client, tc);
5496 }
5497
5498
5499 /**
5500  * Setup the environment for this plugin.
5501  */
5502 static void
5503 create_environment (struct TransportPlugin *plug)
5504 {
5505   plug->env.cfg = cfg;
5506   plug->env.my_identity = &my_identity;
5507   plug->env.our_hello = &our_hello;
5508   plug->env.cls = plug;
5509   plug->env.receive = &plugin_env_receive;
5510   plug->env.notify_address = &plugin_env_notify_address;
5511   plug->env.session_end = &plugin_env_session_end;
5512   plug->env.max_connections = max_connect_per_transport;
5513   plug->env.stats = stats;
5514 }
5515
5516
5517 /**
5518  * Start the specified transport (load the plugin).
5519  */
5520 static void
5521 start_transport (struct GNUNET_SERVER_Handle *server,
5522                  const char *name)
5523 {
5524   struct TransportPlugin *plug;
5525   char *libname;
5526
5527   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5528               _("Loading `%s' transport plugin\n"), name);
5529   GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
5530   plug = GNUNET_malloc (sizeof (struct TransportPlugin));
5531   create_environment (plug);
5532   plug->short_name = GNUNET_strdup (name);
5533   plug->lib_name = libname;
5534   plug->next = plugins;
5535   plugins = plug;
5536   plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
5537   if (plug->api == NULL)
5538     {
5539       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5540                   _("Failed to load transport plugin for `%s'\n"), name);
5541       GNUNET_free (plug->short_name);
5542       plugins = plug->next;
5543       GNUNET_free (libname);
5544       GNUNET_free (plug);
5545     }
5546 }
5547
5548
5549 /**
5550  * Called whenever a client is disconnected.  Frees our
5551  * resources associated with that client.
5552  *
5553  * @param cls closure
5554  * @param client identification of the client
5555  */
5556 static void
5557 client_disconnect_notification (void *cls,
5558                                 struct GNUNET_SERVER_Client *client)
5559 {
5560   struct TransportClient *pos;
5561   struct TransportClient *prev;
5562   struct ClientMessageQueueEntry *mqe;
5563   struct Blacklisters *bl;
5564   struct BlacklistCheck *bc;
5565
5566   if (client == NULL)
5567     return;
5568 #if DEBUG_TRANSPORT
5569   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
5570               "Client disconnected, cleaning up.\n");
5571 #endif
5572   /* clean up blacklister */
5573   bl = bl_head;
5574   while (bl != NULL)
5575     {
5576       if (bl->client == client)
5577         {
5578           bc = bc_head;
5579           while (bc != NULL)
5580             {
5581               if (bc->bl_pos == bl)
5582                 {
5583                   bc->bl_pos = bl->next;
5584                   if (bc->th != NULL)
5585                     {
5586                       GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th);
5587                       bc->th = NULL;            
5588                     }
5589                   if (bc->task == GNUNET_SCHEDULER_NO_TASK)
5590                     bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
5591                                                          bc);
5592                   break;
5593                 }
5594               bc = bc->next;
5595             }
5596           GNUNET_CONTAINER_DLL_remove (bl_head,
5597                                        bl_tail,
5598                                        bl);
5599           GNUNET_SERVER_client_drop (bl->client);
5600           GNUNET_free (bl);
5601           break;
5602         }
5603       bl = bl->next;
5604     }
5605   /* clean up 'normal' clients */
5606   prev = NULL;
5607   pos = clients;
5608   while ((pos != NULL) && (pos->client != client))
5609     {
5610       prev = pos;
5611       pos = pos->next;
5612     }
5613   if (pos == NULL)
5614     return;
5615   while (NULL != (mqe = pos->message_queue_head))
5616     {
5617       GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
5618                                    pos->message_queue_tail,
5619                                    mqe);
5620       pos->message_count--;
5621       GNUNET_free (mqe);
5622     }
5623   if (prev == NULL)
5624     clients = pos->next;
5625   else
5626     prev->next = pos->next;
5627   if (GNUNET_YES == pos->tcs_pending)
5628     {
5629       pos->client = NULL;
5630       return;
5631     }
5632   if (pos->th != NULL)
5633     {
5634       GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
5635       pos->th = NULL;
5636     }
5637   GNUNET_break (0 == pos->message_count);
5638   GNUNET_free (pos);
5639 }
5640
5641
5642 /**
5643  * Function called when the service shuts down.  Unloads our plugins
5644  * and cancels pending validations.
5645  *
5646  * @param cls closure, unused
5647  * @param tc task context (unused)
5648  */
5649 static void
5650 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
5651 {
5652   struct TransportPlugin *plug;
5653   struct OwnAddressList *al;
5654   struct CheckHelloValidatedContext *chvc;
5655
5656   while (neighbours != NULL)
5657     {
5658       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5659               "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&neighbours->id),
5660               "SHUTDOWN_TASK");
5661       disconnect_neighbour (neighbours, GNUNET_NO);
5662     }
5663 #if DEBUG_TRANSPORT
5664   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5665               "Transport service is unloading plugins...\n");
5666 #endif
5667   while (NULL != (plug = plugins))
5668     {
5669       plugins = plug->next;
5670       if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
5671         {
5672           GNUNET_SCHEDULER_cancel (plug->address_update_task);
5673           plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
5674         }
5675       GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
5676       GNUNET_free (plug->lib_name);
5677       GNUNET_free (plug->short_name);
5678       while (NULL != (al = plug->addresses))
5679         {
5680           plug->addresses = al->next;
5681           GNUNET_free (al);
5682         }
5683       GNUNET_free (plug);
5684     }
5685   if (my_private_key != NULL)
5686     GNUNET_CRYPTO_rsa_key_free (my_private_key);
5687   GNUNET_free_non_null (our_hello);
5688
5689   GNUNET_CONTAINER_multihashmap_iterate (validation_map,
5690                                          &abort_validation,
5691                                          NULL);
5692   GNUNET_CONTAINER_multihashmap_destroy (validation_map);
5693   validation_map = NULL;
5694
5695   ats_shutdown(ats);
5696
5697   /* free 'chvc' data structure */
5698   while (NULL != (chvc = chvc_head))
5699     {
5700       chvc_head = chvc->next;
5701       if (chvc->piter != NULL)
5702         {
5703           GNUNET_PEERINFO_iterate_cancel (chvc->piter);
5704           GNUNET_STATISTICS_update (stats,
5705                                     gettext_noop ("# outstanding peerinfo iterate requests"),
5706                                     -1,
5707                                     GNUNET_NO);
5708         }
5709       else
5710         GNUNET_break (0);
5711       GNUNET_assert (chvc->ve_count == 0);
5712       GNUNET_free (chvc);
5713     }
5714   chvc_tail = NULL;
5715
5716   if (stats != NULL)
5717     {
5718       GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
5719       stats = NULL;
5720     }
5721   if (peerinfo != NULL)
5722     {
5723       GNUNET_PEERINFO_disconnect (peerinfo);
5724       peerinfo = NULL;
5725     }
5726   /* Can we assume those are gone by now, or do we need to clean up
5727      explicitly!? */
5728   GNUNET_break (bl_head == NULL);
5729   GNUNET_break (bc_head == NULL);
5730 }
5731
5732
5733
5734 #define DEBUG_ATS GNUNET_NO
5735 #define VERBOSE_ATS GNUNET_NO
5736
5737
5738 /** solve the bandwidth distribution problem
5739  * @param max_it maximum iterations
5740  * @param max_dur maximum duration in ms
5741  * @param D     weight for diversity
5742  * @param U weight for utility
5743  * @param R weight for relativity
5744  * @param v_b_min minimal bandwidth per peer
5745  * @param v_n_min minimum number of connections
5746  * @param res result struct
5747  * @return GNUNET_SYSERR if glpk is not available, number of mechanisms used
5748  */
5749 static int ats_solve_problem (int max_it, int max_dur , double D, double U, double R, int v_b_min, int v_n_min, struct ATS_result *res)
5750 {
5751 #if !HAVE_LIBGLPK
5752         if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "no glpk installed\n");
5753         return GNUNET_SYSERR;
5754 #else
5755         if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "glpk installed\n");
5756
5757         glp_prob *prob;
5758
5759         int c;
5760         int c_peers = 0;
5761         int c_mechs = 0;
5762         int result;
5763         int solution;
5764
5765         int c_c_ressources = available_ressources;
5766         int c_q_metrics = available_quality_metrics;
5767
5768         //double M = 10000000000; // ~10 GB
5769         //double M = VERY_BIG_DOUBLE_VALUE;
5770         double M = 100000;
5771         double Q[c_q_metrics+1];
5772         for (c=1; c<=c_q_metrics; c++)
5773         {
5774                 Q[c] = 1;
5775         }
5776
5777         struct NeighbourList *next = neighbours;
5778         while (next!=NULL)
5779         {
5780                 struct ReadyList *r_next = next->plugins;
5781                 while (r_next != NULL)
5782                 {
5783                         struct ForeignAddressList * a_next = r_next->addresses;
5784                         while (a_next != NULL)
5785                         {
5786                                 c_mechs++;
5787                                 a_next = a_next->next;
5788                         }
5789                         r_next = r_next->next;
5790                 }
5791                 next = next->next;
5792                 c_peers++;
5793         }
5794
5795         if (c_mechs==0)
5796         {
5797                 if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No addresses for bw distribution available\n", c_peers);
5798                 return 0;
5799         }
5800
5801         struct ATS_mechanism * mechanisms = GNUNET_malloc((1+c_mechs) * sizeof (struct ATS_mechanism));
5802         struct ATS_peer * peers = GNUNET_malloc((1+c_peers) * sizeof (struct ATS_peer));
5803
5804         if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found mechanisms: %i\n", c_mechs);
5805         c_mechs = 1;
5806         c_peers = 1;
5807         next = neighbours;
5808         while (next!=NULL)
5809         {
5810                 peers[c_peers].peer = next->id;
5811                 peers[c_peers].m_head = NULL;
5812                 peers[c_peers].m_tail = NULL;
5813                 // FIXME
5814                 peers[c_peers].f = 1.0 / c_mechs;
5815
5816                 struct ReadyList *r_next = next->plugins;
5817                 while (r_next != NULL)
5818                 {
5819                         struct ForeignAddressList * a_next = r_next->addresses;
5820                         while (a_next != NULL)
5821                         {
5822                                 if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%i Peer: `%s' plugin `%s' %x:\n", c_mechs, GNUNET_i2s(&next->id), r_next->plugin->short_name, a_next);
5823                                 mechanisms[c_mechs].addr = a_next;
5824                                 mechanisms[c_mechs].col_index = c_mechs;
5825                                 mechanisms[c_mechs].peer = &peers[c_peers];
5826                                 mechanisms[c_mechs].next = NULL;
5827                                 mechanisms[c_mechs].plugin = r_next->plugin;
5828
5829                                 GNUNET_CONTAINER_DLL_insert_tail(peers[c_peers].m_head, peers[c_peers].m_tail, &mechanisms[c_mechs]);
5830                                 c_mechs++;
5831                                 a_next = a_next->next;
5832                         }
5833                         r_next = r_next->next;
5834                 }
5835                 c_peers++;
5836                 next = next->next;
5837         }
5838         c_mechs--;
5839         c_peers--;
5840
5841         if (v_n_min > c_peers)
5842                 v_n_min = c_peers;
5843
5844         /* number of variables == coloumns */
5845         //int c_cols = 2 * c_mechs + 3 + c_q_metrics;
5846         /* number of constraints == rows */
5847         //int c_rows = 2 * c_peers + 2 * c_mechs + c_c_ressources + c_q_metrics + 3;
5848
5849         if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Creating problem with: %i peers, %i mechanisms, %i resource entries, %i quality metrics \n", c_peers, c_mechs, c_c_ressources, c_q_metrics);
5850
5851         int size = 1 + 3 + 10 *c_mechs + c_peers + (c_q_metrics*c_mechs)+ c_q_metrics + c_c_ressources + 1000;
5852         //int size = 1 + 8 *c_mechs +2 + c_mechs + c_peers + (c_q_metrics*c_mechs)+c_q_metrics + c_c_ressources ;
5853         int row_index;
5854         int array_index=1;
5855         int * ia = GNUNET_malloc (size * sizeof (int));
5856         int * ja = GNUNET_malloc (size * sizeof (int));
5857         double * ar = GNUNET_malloc(size* sizeof (double));
5858
5859         prob = glp_create_prob();
5860         glp_set_prob_name(prob, "gnunet ats bandwidth distribution");
5861         glp_set_obj_dir(prob, GLP_MAX);
5862
5863         /* adding columns */
5864         char * name;
5865         glp_add_cols(prob, 2 * c_mechs);
5866         /* adding b_t cols */
5867         for (c=1; c <= c_mechs; c++)
5868         {
5869                 GNUNET_asprintf(&name, "b%i",c);
5870                 glp_set_col_name(prob, c, name);
5871                 GNUNET_free (name);
5872                 glp_set_col_bnds(prob, c, GLP_LO, 0.0, 0.0);
5873                 glp_set_obj_coef(prob, c, 1);
5874
5875         }
5876         /* adding n_t cols */
5877         for (c=c_mechs+1; c <= 2*c_mechs; c++)
5878         {
5879                 GNUNET_asprintf(&name, "n%i",(c-c_mechs));
5880                 glp_set_col_name(prob, c, name);
5881                 GNUNET_free (name);
5882                 glp_set_col_bnds(prob, c, GLP_DB, 0.0, 1.0);
5883                 glp_set_col_kind(prob, c, GLP_IV);
5884                 glp_set_obj_coef(prob, c, 0);
5885         }
5886
5887         /* feasibility constraints */
5888         /* Constraint 1: one address per peer*/
5889         if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 1\n");
5890         row_index = 1;
5891         glp_add_rows(prob, c_peers);
5892         for (c=1; c<=c_peers; c++)
5893         {
5894                 glp_set_row_bnds(prob, row_index, GLP_FX, 1.0, 1.0);
5895
5896                 struct ATS_mechanism *m = peers[c].m_head;
5897                 while (m!=NULL)
5898                 {
5899                         ia[array_index] = row_index;
5900                         ja[array_index] = (c_mechs + m->col_index);
5901                         ar[array_index] = 1;
5902                         if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
5903                         array_index++;
5904                         m = m->next;
5905                 }
5906                 row_index++;
5907         }
5908
5909         /* Constraint 2: only active mechanism gets bandwidth assigned */
5910         if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 2\n");
5911         glp_add_rows(prob, c_mechs);
5912         for (c=1; c<=c_mechs; c++)
5913         {
5914                 /* b_t - n_t * M <= 0 */
5915                 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
5916                 glp_set_row_bnds(prob, row_index, GLP_UP, 0.0, 0.0);
5917
5918                 ia[array_index] = row_index;
5919                 ja[array_index] = mechanisms[c].col_index;
5920                 ar[array_index] = 1;
5921                 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
5922                 array_index++;
5923                 ia[array_index] = row_index;
5924                 ja[array_index] = c_mechs + mechanisms[c].col_index;
5925                 ar[array_index] = -M;
5926                 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
5927                 array_index++;
5928                 row_index ++;
5929         }
5930
5931         /* Constraint 3: minimum bandwidth*/
5932         if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 3\n");
5933         glp_add_rows(prob, c_mechs);
5934         for (c=1; c<=c_mechs; c++)
5935         {
5936                 /* b_t - n_t * b_min <= 0 */
5937                 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
5938                 glp_set_row_bnds(prob, row_index, GLP_LO, 0.0, 0.0);
5939
5940                 ia[array_index] = row_index;
5941                 ja[array_index] = mechanisms[c].col_index;
5942                 ar[array_index] = 1;
5943                 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
5944                 array_index++;
5945                 ia[array_index] = row_index;
5946                 ja[array_index] = c_mechs + mechanisms[c].col_index;
5947                 ar[array_index] = -v_b_min;
5948                 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
5949                 array_index++;
5950                 row_index ++;
5951         }
5952         int c2;
5953         /* Constraint 4: max ressource capacity */
5954         /* V cr: bt * ct_r <= cr_max
5955          * */
5956
5957         if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 4\n");
5958         glp_add_rows(prob, available_ressources);
5959         double ct_max = VERY_BIG_DOUBLE_VALUE;
5960         double ct_min = 0.0;
5961
5962         for (c=0; c<available_ressources; c++)
5963         {
5964                 ct_max = ressources[c].c_max;
5965                 ct_min = ressources[c].c_min;
5966                 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] %f..%f\n",row_index, ct_min, ct_max);
5967                 glp_set_row_bnds(prob, row_index, GLP_DB, ct_min, ct_max);
5968
5969                 for (c2=1; c2<=c_mechs; c2++)
5970                 {
5971                         double value = 0;
5972                         ia[array_index] = row_index;
5973                         ja[array_index] = c2;
5974                         value = mechanisms[c2].addr->ressources[c].c;
5975                         ar[array_index] = value;
5976                         if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
5977                         array_index++;
5978                 }
5979                 row_index ++;
5980         }
5981
5982         /* Constraint 5: min number of connections*/
5983         if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 5\n");
5984         glp_add_rows(prob, 1);
5985         for (c=1; c<=c_mechs; c++)
5986         {
5987                 // b_t - n_t * b_min >= 0
5988                 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
5989                 glp_set_row_bnds(prob, row_index, GLP_LO, v_n_min, 0.0);
5990
5991                 ia[array_index] = row_index;
5992                 ja[array_index] = c_mechs + mechanisms[c].col_index;
5993                 ar[array_index] = 1;
5994                 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
5995                 array_index++;
5996         }
5997         row_index ++;
5998
5999         /* optimisation constraints*/
6000
6001         /* adding columns */
6002         glp_add_cols(prob, 3 + c_q_metrics);
6003
6004         glp_set_col_name(prob, (2*c_mechs) + 1, "d");
6005         glp_set_obj_coef(prob, (2*c_mechs) + 1, D);
6006         glp_set_col_bnds(prob, (2*c_mechs) + 1, GLP_LO, 0.0, 0.0);
6007         glp_set_col_name(prob, (2*c_mechs) + 2, "u");
6008         glp_set_obj_coef(prob, (2*c_mechs) + 2, U);
6009         glp_set_col_bnds(prob, (2*c_mechs) + 2, GLP_LO, 0.0, 0.0);
6010         glp_set_col_name(prob, (2*c_mechs) + 3, "r");
6011         glp_set_obj_coef(prob, (2*c_mechs) + 3, R);
6012         glp_set_col_bnds(prob, (2*c_mechs) + 3, GLP_LO, 0.0, 0.0);
6013
6014         for (c=1; c<= c_q_metrics; c++)
6015         {
6016                 GNUNET_asprintf(&name, "Q_%s",qm[c-1].name);
6017                 glp_set_col_name(prob, (2*c_mechs) + 3 + c, name);
6018                 glp_set_col_bnds(prob, (2*c_mechs) + 3 + c, GLP_LO, 0.0, 0.0);
6019                 GNUNET_free (name);
6020                 glp_set_obj_coef(prob, (2*c_mechs) + 3 + c, Q[c]);
6021         }
6022
6023         // Constraint 6: optimize for diversity
6024         if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 6\n");
6025         glp_add_rows(prob, 1);
6026         if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6027         glp_set_row_bnds(prob, row_index, GLP_FX, 0.0, 0.0);
6028         //glp_set_row_bnds(prob, row_index, GLP_UP, 0.0, 0.0);
6029         for (c=1; c<=c_mechs; c++)
6030         {
6031                 // b_t - n_t * b_min >= 0
6032                 ia[array_index] = row_index;
6033                 ja[array_index] = c_mechs + mechanisms[c].col_index;
6034                 ar[array_index] = 1;
6035                 //if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6036                 array_index++;
6037         }
6038         ia[array_index] = row_index;
6039         ja[array_index] = (2*c_mechs) + 1;
6040         ar[array_index] = -1;
6041         //if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6042         array_index++;
6043         row_index ++;
6044
6045
6046         // Constraint 7: optimize for quality
6047
6048         if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 7\n");
6049     glp_add_rows(prob, available_quality_metrics);
6050         for (c=1; c <= c_q_metrics; c++)
6051         {
6052                 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6053                 glp_set_row_bnds(prob, row_index, GLP_FX, 0.0, 0.0);
6054
6055                 for (c2=1; c2<=c_mechs; c2++)
6056                 {
6057                         double value = 0;
6058                         ia[array_index] = row_index;
6059                         ja[array_index] = c2;
6060                         if (qm[c-1].atis_index  == GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY)
6061                         {
6062                                 if (mechanisms[c2].addr->latency.rel_value == -1)
6063                                         value = 0;
6064                                 if (mechanisms[c2].addr->latency.rel_value == 0)
6065                                         value = 0 ;
6066                                 else
6067                                         value = 100 / (double) mechanisms[c2].addr->latency.rel_value;
6068
6069                                 //if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "DELAY VALUE %f %llu\n",value, mechanisms[c2].addr->latency.rel_value);
6070                         }
6071                         if (qm[c-1].atis_index  == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
6072                         {
6073                                 if (mechanisms[c2].addr->distance == -1)
6074                                         value = 0;
6075                                 else if (mechanisms[c2].addr->distance == 0)
6076                                         value = 0;
6077                                 else value =  (double) 10 / mechanisms[c2].addr->distance;
6078                                 //if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "DISTANCE VALUE %f %lli\n",value,  mechanisms[c2].addr->distance);
6079                         }
6080                         ar[array_index] = (mechanisms[c2].peer->f) * value ;
6081                         //if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: %s [%i,%i]=%f \n",array_index, qm[c-1].name, ia[array_index], ja[array_index], ar[array_index]);
6082                         array_index++;
6083                 }
6084
6085                 ia[array_index] = row_index;
6086                 ja[array_index] = (2*c_mechs) + 3 +c;
6087                 ar[array_index] = -1;
6088                 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6089                 array_index++;
6090                 row_index++;
6091         }
6092
6093         // Constraint 8: optimize bandwidth utility
6094         if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 8\n");
6095         glp_add_rows(prob, 1);
6096         if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6097         glp_set_row_bnds(prob, row_index, GLP_FX, 0.0, 0.0);
6098         for (c=1; c<=c_mechs; c++)
6099         {
6100                 ia[array_index] = row_index;
6101                 ja[array_index] = c;
6102                 ar[array_index] = mechanisms[c].peer->f;
6103                 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6104                 array_index++;
6105         }
6106         ia[array_index] = row_index;
6107         ja[array_index] = (2*c_mechs) + 2;
6108         ar[array_index] = -1;
6109 #if VERBOSE_ATS
6110         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6111 #endif
6112
6113         array_index++;
6114         row_index ++;
6115
6116         // Constraint 9: optimize relativity
6117         if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Constraint 9\n");
6118         glp_add_rows(prob, c_peers);
6119         for (c=1; c<=c_peers; c++)
6120         {
6121                 glp_set_row_bnds(prob, row_index, GLP_LO, 0.0, 0.0);
6122
6123                 struct ATS_mechanism *m = peers[c].m_head;
6124                 while (m!=NULL)
6125                 {
6126                         ia[array_index] = row_index;
6127                         ja[array_index] = m->col_index;
6128                         ar[array_index] = 1;
6129                         //if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6130                         array_index++;
6131                         m = m->next;
6132                 }
6133                 ia[array_index] = row_index;
6134                 ja[array_index] = (2*c_mechs) + 3;
6135                 ar[array_index] = -1;
6136                 //if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6137                 array_index++;
6138
6139                 row_index++;
6140         }
6141         glp_load_matrix(prob, array_index-1, ia, ja, ar);
6142
6143         glp_smcp opt_lp;
6144         glp_init_smcp(&opt_lp);
6145         if (VERBOSE_ATS)
6146                 opt_lp.msg_lev = GLP_MSG_ALL;
6147         else
6148                 opt_lp.msg_lev = GLP_MSG_OFF;
6149         result = glp_simplex(prob, &opt_lp);
6150
6151         glp_iocp opt_mlp;
6152         glp_init_iocp(&opt_mlp);
6153         /* maximum duration */
6154         opt_mlp.tm_lim = max_dur;
6155         /* output level */
6156         if (VERBOSE_ATS)
6157                 opt_mlp.msg_lev = GLP_MSG_ALL;
6158         else
6159                 opt_mlp.msg_lev = GLP_MSG_OFF;
6160
6161         result = glp_intopt (prob, &opt_mlp);
6162         solution =  glp_mip_status (prob);
6163
6164 #if WRITE_MLP
6165         if (c_peers > 1)
6166         {
6167                 char * filename;
6168
6169                 GNUNET_asprintf (&filename, "ats_mlp_p%i_m%i.mlp",c_peers, c_mechs);
6170                 if (GNUNET_NO == GNUNET_DISK_file_test(filename))
6171                         glp_write_lp (prob, NULL, filename);
6172                 GNUNET_free (filename);
6173         }
6174 #endif
6175 #if VERBOSE_ATS
6176
6177
6178
6179         switch (result) {
6180         case GLP_ESTOP  :    /* search terminated by application */
6181                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Search terminated by application ");
6182                 break;
6183         case GLP_EITLIM :    /* iteration limit exceeded */
6184                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Iteration limit exceeded ");
6185                 break;
6186         break;
6187         case GLP_ETMLIM :    /* time limit exceeded */
6188                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Time limit exceeded ");
6189         break;
6190         case GLP_ENOPFS :    /* no primal feasible solution */
6191         case GLP_ENODFS :    /* no dual feasible solution */
6192                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "No feasible solution");
6193         break;
6194
6195         case GLP_EBADB  :    /* invalid basis */
6196         case GLP_ESING  :    /* singular matrix */
6197         case GLP_ECOND  :    /* ill-conditioned matrix */
6198         case GLP_EBOUND :    /* invalid bounds */
6199         case GLP_EFAIL  :    /* solver failed */
6200         case GLP_EOBJLL :    /* objective lower limit reached */
6201         case GLP_EOBJUL :    /* objective upper limit reached */
6202         case GLP_EROOT  :    /* root LP optimum not provided */
6203                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid Input data: %i\n", result);
6204         break;
6205
6206         break;
6207                 default:
6208                         GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Problem has been solved\n");
6209         break;
6210         }
6211
6212         switch (solution) {
6213                 case GLP_UNDEF:
6214                         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MIP solution is undefined\n");
6215                         break;
6216                 case GLP_OPT:
6217                         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MIP solution is integer optimal\n");
6218                         break;
6219                 case GLP_FEAS:
6220                         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MIP solution is integer feasible, however, its optimality (or non-optimality) has not been proven, \n");
6221                         break;
6222                 case GLP_NOFEAS:
6223                         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MI problem has no integer feasible solution\n");
6224                         break;
6225                         break;
6226                 default:
6227                         break;
6228         }
6229 #endif
6230         int check;
6231         int error = GNUNET_NO;
6232         double bw;
6233         struct ATS_mechanism *t = NULL;
6234         for (c=1; c<= (c_peers); c++ )
6235         {
6236                 check = GNUNET_NO;
6237                 t = peers[c].m_head;
6238                 while (t!=NULL)
6239                 {
6240                         bw = glp_get_col_prim(prob, t->col_index);
6241                         if (bw > 1.0)
6242                         {
6243                                 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[%i][%i] `%s' %s %s %f\n", c, t->col_index, GNUNET_h2s(&peers[c].peer.hashPubKey), t->plugin->short_name, glp_get_col_name(prob,t->col_index), bw);
6244                                 if (check ==GNUNET_YES)
6245                                         error = GNUNET_YES;
6246                                 if (check ==GNUNET_NO)
6247                                         check = GNUNET_YES;
6248                         }
6249                         GNUNET_assert (error != GNUNET_YES);
6250                         t = t->next;
6251                 }
6252         }
6253
6254         for (c=1; c<= c_q_metrics; c++ )
6255         {
6256                 if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s %f\n", glp_get_col_name(prob,2*c_mechs+3+c), glp_get_col_prim(prob,2*c_mechs+3+c));
6257         }
6258         if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s %f\n", glp_get_col_name(prob,2*c_mechs+1), glp_get_col_prim(prob,2*c_mechs+1));
6259         if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s %f\n", glp_get_col_name(prob,2*c_mechs+2), glp_get_col_prim(prob,2*c_mechs+2));
6260         if (VERBOSE_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "%s %f\n", glp_get_col_name(prob,2*c_mechs+3), glp_get_col_prim(prob,2*c_mechs+3));
6261
6262         res->c_mechs = c_mechs;
6263         res->c_peers = c_peers;
6264         res->solution = solution;
6265
6266         /* clean up */
6267
6268
6269         glp_delete_prob(prob);
6270
6271         GNUNET_free (ja);
6272         GNUNET_free (ia);
6273         GNUNET_free (ar);
6274
6275         for (c=0; c<c_mechs; c++)
6276         {
6277                 GNUNET_free_non_null (mechanisms[c].rc);
6278         }
6279
6280         GNUNET_free(mechanisms);
6281         GNUNET_free(peers);
6282
6283         return c_mechs;
6284 #endif
6285 }
6286
6287 void ats_calculate_bandwidth_distribution ()
6288 {
6289         static int glpk = GNUNET_YES;
6290         struct GNUNET_TIME_Absolute start;
6291         struct GNUNET_TIME_Relative duration;
6292         struct ATS_result result;
6293         int c_mechs = 0;
6294
6295         struct GNUNET_TIME_Relative delta = GNUNET_TIME_absolute_get_difference(ats->last,GNUNET_TIME_absolute_get());
6296         if (delta.rel_value < ats->min_delta.rel_value)
6297         {
6298 #if DEBUG_ATS
6299                 //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "Minimum time between cycles not reached\n");
6300 #endif
6301                 return;
6302         }
6303
6304         int dur = 500;
6305         if (INT_MAX < ats->max_exec_duration.rel_value)
6306                 dur = INT_MAX;
6307         else
6308                 dur = (int) ats->max_exec_duration.rel_value;
6309
6310         start = GNUNET_TIME_absolute_get();
6311
6312         if (glpk==GNUNET_YES)
6313         {
6314                 start = GNUNET_TIME_absolute_get();
6315                 c_mechs = ats_solve_problem(5000, 5000, 1.0, 1.0, 1.0, 1000, 5, &result);
6316                 duration = GNUNET_TIME_absolute_get_difference(start,GNUNET_TIME_absolute_get());
6317
6318                 if (c_mechs > 0)
6319                 {
6320                         if (DEBUG_ATS) {GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MLP execution time in [ms] for %i mechanisms: %llu\n", c_mechs, duration.rel_value);}
6321                         GNUNET_STATISTICS_set (stats, "ATS duration", duration.rel_value, GNUNET_NO);
6322                         GNUNET_STATISTICS_set (stats, "ATS mechanisms", result.c_mechs, GNUNET_NO);
6323                         GNUNET_STATISTICS_set (stats, "ATS peers", result.c_peers, GNUNET_NO);
6324                         GNUNET_STATISTICS_set (stats, "ATS solution", result.solution, GNUNET_NO);
6325                         GNUNET_STATISTICS_set (stats, "ATS timestamp", start.abs_value, GNUNET_NO);
6326                 }
6327                 else if (c_mechs == 0)
6328                 {
6329                         if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "MLP not executed: no addresses\n");
6330                 }
6331                 else glpk = GNUNET_NO;
6332         }
6333         ats->last = GNUNET_TIME_absolute_get();
6334 }
6335
6336
6337
6338 void
6339 ats_schedule_calculation (void *cls,
6340                           const struct GNUNET_SCHEDULER_TaskContext *tc)
6341 {
6342         struct ATS_info *ats = (struct ATS_info *) cls;
6343         if (ats==NULL)
6344                 return;
6345
6346         ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
6347         if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
6348             return;
6349
6350 #if DEBUG_ATS
6351         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Running scheduled calculation\n");
6352 #endif
6353         ats_calculate_bandwidth_distribution (ats);
6354
6355         ats->ats_task = GNUNET_SCHEDULER_add_delayed (ats->exec_intervall,
6356                                         &ats_schedule_calculation, ats);
6357 }
6358
6359 void ats_init ()
6360 {
6361         ats = GNUNET_malloc(sizeof (struct ATS_info));
6362
6363         ats->min_delta = ATS_MIN_INTERVAL;
6364         ats->exec_intervall = ATS_EXEC_INTERVAL;
6365         ats->max_exec_duration = ATS_MAX_EXEC_DURATION;
6366         ats->max_iterations = ATS_MAX_ITERATIONS;
6367         ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
6368
6369         int c = 0;
6370         unsigned long long  value;
6371         char * section;
6372         /* loading cost ressources */
6373         for (c=0; c<available_ressources; c++)
6374         {
6375                 GNUNET_asprintf(&section,"%s_UP",ressources[c].cfg_param);
6376                 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
6377                 {
6378                         GNUNET_CONFIGURATION_get_value_number(cfg, "transport",section, &value);
6379                         if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found ressource cost: [%s] = %llu\n", section, value);
6380                         ressources[c].c_max = value;
6381                 }
6382                 GNUNET_free (section);
6383                 GNUNET_asprintf(&section,"%s_DOWN",ressources[c].cfg_param);
6384                 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
6385                 {
6386                         GNUNET_CONFIGURATION_get_value_number(cfg, "transport",section, &value);
6387                         if (DEBUG_ATS) GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found ressource cost: [%s] = %llu\n", section, value);
6388                         ressources[c].c_min = value;
6389                 }
6390                 GNUNET_free (section);
6391         }
6392
6393         ats->ats_task = GNUNET_SCHEDULER_add_now(&ats_schedule_calculation, ats);
6394 }
6395
6396
6397 void ats_shutdown ()
6398 {
6399 #if DEBUG_ATS
6400         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_destroy\n");
6401 #endif
6402         if (ats->ats_task != GNUNET_SCHEDULER_NO_TASK)
6403                 GNUNET_SCHEDULER_cancel(ats->ats_task);
6404         ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
6405 /*
6406         struct ATS_plugin * p;
6407         struct ATS_ressource_cost * rc;
6408
6409         p = ats->head;
6410         {
6411                 GNUNET_CONTAINER_DLL_remove (ats->head,ats->tail, p);
6412                 rc = p->head;
6413                 while (p != NULL)
6414                 {
6415                         GNUNET_CONTAINER_DLL_remove (p->head,p->tail, rc);
6416                         GNUNET_free(rc);
6417                         rc = p->head;
6418                 }
6419                 GNUNET_free(p->short_name);
6420                 GNUNET_free(p);
6421                 p = ats->head;
6422         }
6423 */
6424         GNUNET_free (ats);
6425 }
6426
6427
6428 void ats_notify_peer_connect (
6429                 const struct GNUNET_PeerIdentity *peer,
6430                 const struct GNUNET_TRANSPORT_ATS_Information *ats_data)
6431 {
6432         int c = 0;
6433 #if DEBUG_ATS
6434         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_notify_peer_connect: %s\n",GNUNET_i2s(peer));
6435 #endif
6436
6437         while (ntohl(ats_data[c].type)!=0)
6438         {
6439 #if DEBUG_ATS
6440                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats type [%i]: %i\n",ntohl(ats_data[c].type), ntohl(ats_data[c].value));
6441 #endif
6442                 c++;
6443         }
6444         ats_calculate_bandwidth_distribution(ats);
6445 }
6446
6447 void ats_notify_peer_disconnect (
6448                 const struct GNUNET_PeerIdentity *peer)
6449 {
6450 #if DEBUG_ATS
6451         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_notify_peer_disconnect: %s\n",GNUNET_i2s(peer));
6452 #endif
6453         ats_calculate_bandwidth_distribution (ats);
6454 }
6455
6456
6457 void ats_notify_ats_data (
6458                 const struct GNUNET_PeerIdentity *peer,
6459                 const struct GNUNET_TRANSPORT_ATS_Information *ats_data)
6460 {
6461 #if DEBUG_ATS
6462         GNUNET_log (GNUNET_ERROR_TYPE_BULK, "ATS_notify_ats_data: %s\n",GNUNET_i2s(peer));
6463 #endif
6464         ats_calculate_bandwidth_distribution(ats);
6465 }
6466
6467 struct ForeignAddressList * ats_get_preferred_address (
6468                 struct NeighbourList *n)
6469 {
6470 #if DEBUG_ATS
6471         //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "ats_get_prefered_transport for peer: %s\n",GNUNET_i2s(&n->id));
6472 #endif
6473         struct ReadyList *next = n->plugins;
6474         while (next != NULL)
6475         {
6476 #if DEBUG_ATS
6477                 //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "plugin: %s %i\n",next->plugin->short_name,strcmp(next->plugin->short_name,"unix"));
6478 #endif
6479                 next = next->next;
6480         }
6481         return find_ready_address(n);
6482 }
6483
6484 /**
6485  * Initiate transport service.
6486  *
6487  * @param cls closure
6488  * @param server the initialized server
6489  * @param c configuration to use
6490  */
6491 static void
6492 run (void *cls,
6493      struct GNUNET_SERVER_Handle *server,
6494      const struct GNUNET_CONFIGURATION_Handle *c)
6495 {
6496   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
6497     {&handle_start, NULL,
6498      GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)},
6499     {&handle_hello, NULL,
6500      GNUNET_MESSAGE_TYPE_HELLO, 0},
6501     {&handle_send, NULL,
6502      GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
6503     {&handle_request_connect, NULL,
6504      GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT, sizeof(struct TransportRequestConnectMessage)},
6505     {&handle_set_quota, NULL,
6506      GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
6507     {&handle_address_lookup, NULL,
6508      GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
6509      0},
6510     {&handle_blacklist_init, NULL,
6511      GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT, sizeof (struct GNUNET_MessageHeader)},
6512     {&handle_blacklist_reply, NULL,
6513      GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY, sizeof (struct BlacklistMessage)},
6514     {NULL, NULL, 0, 0}
6515   };
6516   char *plugs;
6517   char *pos;
6518   int no_transports;
6519   unsigned long long tneigh;
6520   char *keyfile;
6521
6522   cfg = c;
6523   stats = GNUNET_STATISTICS_create ("transport", cfg);
6524   validation_map = GNUNET_CONTAINER_multihashmap_create (64);
6525   /* parse configuration */
6526   if ((GNUNET_OK !=
6527        GNUNET_CONFIGURATION_get_value_number (c,
6528                                               "TRANSPORT",
6529                                               "NEIGHBOUR_LIMIT",
6530                                               &tneigh)) ||
6531       (GNUNET_OK !=
6532        GNUNET_CONFIGURATION_get_value_filename (c,
6533                                                 "GNUNETD",
6534                                                 "HOSTKEY", &keyfile)))
6535     {
6536       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6537                   _
6538                   ("Transport service is lacking key configuration settings.  Exiting.\n"));
6539       GNUNET_SCHEDULER_shutdown ();
6540       if (stats != NULL)
6541         {
6542           GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6543           stats = NULL;
6544         }
6545       GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6546       validation_map = NULL;
6547       return;
6548     }
6549
6550   max_connect_per_transport = (uint32_t) tneigh;
6551   peerinfo = GNUNET_PEERINFO_connect (cfg);
6552   if (peerinfo == NULL)
6553     {
6554       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6555                   _("Could not access PEERINFO service.  Exiting.\n")); 
6556       GNUNET_SCHEDULER_shutdown ();
6557       if (stats != NULL)
6558         {
6559           GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6560           stats = NULL;
6561         }
6562       GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6563       validation_map = NULL;
6564       GNUNET_free (keyfile);
6565       return;
6566     }
6567   my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
6568   GNUNET_free (keyfile);
6569   if (my_private_key == NULL)
6570     {
6571       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6572                   _
6573                   ("Transport service could not access hostkey.  Exiting.\n"));
6574       GNUNET_SCHEDULER_shutdown ();
6575       if (stats != NULL)
6576         {
6577           GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
6578           stats = NULL;
6579         }
6580       GNUNET_CONTAINER_multihashmap_destroy (validation_map);
6581       validation_map = NULL;
6582       return;
6583     }
6584   GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
6585   GNUNET_CRYPTO_hash (&my_public_key,
6586                       sizeof (my_public_key), &my_identity.hashPubKey);
6587   /* setup notification */
6588   GNUNET_SERVER_disconnect_notify (server,
6589                                    &client_disconnect_notification, NULL);
6590   /* load plugins... */
6591   no_transports = 1;
6592   if (GNUNET_OK ==
6593       GNUNET_CONFIGURATION_get_value_string (c,
6594                                              "TRANSPORT", "PLUGINS", &plugs))
6595     {
6596       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6597                   _("Starting transport plugins `%s'\n"), plugs);
6598       pos = strtok (plugs, " ");
6599       while (pos != NULL)
6600         {
6601           start_transport (server, pos);
6602           no_transports = 0;
6603           pos = strtok (NULL, " ");
6604         }
6605       GNUNET_free (plugs);
6606     }
6607   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
6608                                 &shutdown_task, NULL);
6609   if (no_transports)
6610     refresh_hello ();
6611
6612   ats_init();
6613
6614 #if DEBUG_TRANSPORT
6615   GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
6616 #endif
6617   /* If we have a blacklist file, read from it */
6618   read_blacklist_file(cfg);
6619   /* process client requests */
6620   GNUNET_SERVER_add_handlers (server, handlers);
6621 }
6622
6623
6624 /**
6625  * The main function for the transport service.
6626  *
6627  * @param argc number of arguments from the command line
6628  * @param argv command line arguments
6629  * @return 0 ok, 1 on error
6630  */
6631 int
6632 main (int argc, char *const *argv)
6633 {
6634   a2s (NULL, NULL, 0); /* make compiler happy */
6635   return (GNUNET_OK ==
6636           GNUNET_SERVICE_run (argc,
6637                               argv,
6638                               "transport",
6639                               GNUNET_SERVICE_OPTION_NONE,
6640                               &run, NULL)) ? 0 : 1;
6641 }
6642
6643 /* end of gnunet-service-transport.c */