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