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