wip
[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   if (nl->received_pong == GNUNET_NO)
2531     return; /* nothing to do, never connected... */
2532   /* check if we have any validated addresses left */
2533   pos = rl->addresses;
2534   while (pos != NULL)
2535     {
2536       if (pos->validated)
2537         {
2538           try_fast_reconnect (p, nl);
2539           return;
2540         }
2541       pos = pos->next;
2542     }
2543   /* no valid addresses left, signal disconnect! */
2544
2545   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2546             "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&nl->id),
2547             "plugin_env_session_end");
2548   /* FIXME: This doesn't mean there are no addresses left for this PEER,
2549    * it means there aren't any left for this PLUGIN/PEER combination! So
2550    * calling disconnect_neighbor here with GNUNET_NO forces disconnect
2551    * when it isn't necessary. Using GNUNET_YES at least checks to see
2552    * if there are any addresses that work first, so as not to overdo it.
2553    * --NE
2554    */
2555   disconnect_neighbour (nl, GNUNET_YES);
2556 }
2557
2558
2559 /**
2560  * Function that must be called by each plugin to notify the
2561  * transport service about the addresses under which the transport
2562  * provided by the plugin can be reached.
2563  *
2564  * @param cls closure
2565  * @param name name of the transport that generated the address
2566  * @param addr one of the addresses of the host, NULL for the last address
2567  *        the specific address format depends on the transport
2568  * @param addrlen length of the address
2569  * @param expires when should this address automatically expire?
2570  */
2571 static void
2572 plugin_env_notify_address (void *cls,
2573                            const char *name,
2574                            const void *addr,
2575                            uint16_t addrlen,
2576                            struct GNUNET_TIME_Relative expires)
2577 {
2578   struct TransportPlugin *p = cls;
2579   struct OwnAddressList *al;
2580   struct GNUNET_TIME_Absolute abex;
2581
2582   GNUNET_assert (addr != NULL);
2583   abex = GNUNET_TIME_relative_to_absolute (expires);
2584   GNUNET_assert (p == find_transport (name));
2585   al = p->addresses;
2586   while (al != NULL)
2587     {
2588       if ( (addrlen == al->addrlen) &&
2589            (0 == memcmp (addr, &al[1], addrlen)) )
2590         {
2591           al->expires = abex;
2592           update_addresses (p, GNUNET_NO);
2593           return;
2594         }
2595       al = al->next;
2596     }
2597   al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
2598   al->next = p->addresses;
2599   p->addresses = al;
2600   al->expires = abex;
2601   al->addrlen = addrlen;
2602   memcpy (&al[1], addr, addrlen);
2603   update_addresses (p, GNUNET_YES);
2604 }
2605
2606
2607 /**
2608  * Notify all of our clients about a peer connecting.
2609  */
2610 static void
2611 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
2612                         struct GNUNET_TIME_Relative latency,
2613                         uint32_t distance)
2614 {
2615   struct ConnectInfoMessage * cim;
2616   struct TransportClient *cpos;
2617   uint32_t ats_count;
2618   size_t size;
2619
2620 #if DEBUG_TRANSPORT
2621   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2622               "Notifying clients about connection from `%s'\n",
2623               GNUNET_i2s (peer));
2624 #endif
2625   GNUNET_STATISTICS_update (stats,
2626                             gettext_noop ("# peers connected"),
2627                             1,
2628                             GNUNET_NO);
2629
2630   ats_count = 2;
2631   size  = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
2632   if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
2633   {
2634           GNUNET_break(0);
2635   }
2636   cim = GNUNET_malloc (size);
2637
2638   cim->header.size = htons (size);
2639   cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2640   cim->ats_count = htonl(2);
2641   (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
2642   (&(cim->ats))[0].value = htonl (distance);
2643   (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
2644   (&(cim->ats))[1].value = htonl ((uint32_t) latency.rel_value);
2645   (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
2646   (&(cim->ats))[2].value = htonl (0);
2647   memcpy (&cim->id, peer, sizeof (struct GNUNET_PeerIdentity));
2648
2649   /* notify ats about connecting peer */
2650   ats_notify_peer_connect (peer, &(cim->ats), 2);
2651
2652   cpos = clients;
2653   while (cpos != NULL)
2654     {
2655       transmit_to_client (cpos, &(cim->header), GNUNET_NO);
2656       cpos = cpos->next;
2657     }
2658
2659   GNUNET_free (cim);
2660 }
2661
2662
2663 /**
2664  * Notify all of our clients about a peer disconnecting.
2665  */
2666 static void
2667 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
2668 {
2669   struct DisconnectInfoMessage dim;
2670   struct TransportClient *cpos;
2671
2672 #if DEBUG_TRANSPORT
2673   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2674               "Notifying clients about lost connection to `%s'\n",
2675               GNUNET_i2s (peer));
2676 #endif
2677   GNUNET_STATISTICS_update (stats,
2678                             gettext_noop ("# peers connected"),
2679                             -1,
2680                             GNUNET_NO);
2681   dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
2682   dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
2683   dim.reserved = htonl (0);
2684   memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
2685
2686   /* notify ats about connecting peer */
2687   ats_notify_peer_disconnect (peer);
2688
2689   cpos = clients;
2690   while (cpos != NULL)
2691     {
2692       transmit_to_client (cpos, &dim.header, GNUNET_NO);
2693       cpos = cpos->next;
2694     }
2695 }
2696
2697
2698 /**
2699  * Find a ForeignAddressList entry for the given neighbour
2700  * that matches the given address and transport.
2701  *
2702  * @param neighbour which peer we care about
2703  * @param tname name of the transport plugin
2704  * @param session session to look for, NULL for 'any'; otherwise
2705  *        can be used for the service to "learn" this session ID
2706  *        if 'addr' matches
2707  * @param addr binary address
2708  * @param addrlen length of addr
2709  * @return NULL if no such entry exists
2710  */
2711 static struct ForeignAddressList *
2712 find_peer_address(struct NeighbourList *neighbour,
2713                   const char *tname,
2714                   struct Session *session,
2715                   const char *addr,
2716                   uint16_t addrlen)
2717 {
2718   struct ReadyList *head;
2719   struct ForeignAddressList *pos;
2720
2721   head = neighbour->plugins;
2722   while (head != NULL)
2723     {
2724       if (0 == strcmp (tname, head->plugin->short_name))
2725         break;
2726       head = head->next;
2727     }
2728   if (head == NULL)
2729     return NULL;
2730   pos = head->addresses;
2731   while ( (pos != NULL) &&
2732           ( (pos->addrlen != addrlen) ||
2733             (memcmp(pos->addr, addr, addrlen) != 0) ) )
2734     {
2735       if ( (session != NULL) &&
2736            (pos->session == session) )
2737         return pos;
2738       pos = pos->next;
2739     }
2740   if ( (session != NULL) && (pos != NULL) )
2741     pos->session = session; /* learn it! */
2742   return pos;
2743 }
2744
2745
2746 /**
2747  * Get the peer address struct for the given neighbour and
2748  * address.  If it doesn't yet exist, create it.
2749  *
2750  * @param neighbour which peer we care about
2751  * @param tname name of the transport plugin
2752  * @param session session of the plugin, or NULL for none
2753  * @param addr binary address
2754  * @param addrlen length of addr
2755  * @return NULL if we do not have a transport plugin for 'tname'
2756  */
2757 static struct ForeignAddressList *
2758 add_peer_address (struct NeighbourList *neighbour,
2759                   const char *tname,
2760                   struct Session *session,
2761                   const char *addr,
2762                   uint16_t addrlen)
2763 {
2764   struct ReadyList *head;
2765   struct ForeignAddressList *ret;
2766   int c;
2767
2768   ret = find_peer_address (neighbour, tname, session, addr, addrlen);
2769   if (ret != NULL)
2770     return ret;
2771   head = neighbour->plugins;
2772
2773   while (head != NULL)
2774     {
2775       if (0 == strcmp (tname, head->plugin->short_name))
2776         break;
2777       head = head->next;
2778     }
2779   if (head == NULL)
2780     return NULL;
2781   ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
2782   ret->session = session;
2783   if ((addrlen > 0) && (addr != NULL))
2784     {
2785       ret->addr = (const char*) &ret[1];
2786       memcpy (&ret[1], addr, addrlen);
2787     }
2788   else
2789     {
2790       ret->addr = NULL;
2791     }
2792
2793   ret->ressources = GNUNET_malloc(available_ressources * sizeof (struct ATS_ressource_entry));
2794   int plugin;
2795   for (c=0; c<available_ressources; c++)
2796   {
2797           struct ATS_ressource_entry *r = ret->ressources;
2798           r[c].index = c;
2799           r[c].atis_index = ressources[c].atis_index;
2800           if (0 == strcmp(neighbour->plugins->plugin->short_name,"unix"))
2801           {
2802                   r[c].c = ressources[c].c_unix;
2803                   plugin = 1;
2804           }
2805           else if (0 == strcmp(neighbour->plugins->plugin->short_name,"udp"))
2806           {
2807                   r[c].c = ressources[c].c_udp;
2808                   plugin = 2;
2809           }
2810           else if (0 == strcmp(neighbour->plugins->plugin->short_name,"tcp"))
2811           {
2812                   r[c].c = ressources[c].c_tcp;
2813                   plugin = 3;
2814           }
2815           else if (0 == strcmp(neighbour->plugins->plugin->short_name,"http"))
2816           {
2817                   r[c].c = ressources[c].c_http;
2818                   plugin = 4;
2819           }
2820           else if (0 == strcmp(neighbour->plugins->plugin->short_name,"https"))
2821           {
2822                   r[c].c = ressources[c].c_https;
2823                   plugin = 5;
2824           }
2825           else if (0 == strcmp(neighbour->plugins->plugin->short_name,"wlan"))
2826           {
2827                   r[c].c = ressources[c].c_wlan;
2828                   plugin = 6;
2829           }
2830           else
2831           {
2832                 plugin = -1;
2833                 r[c].c = ressources[c].c_default;
2834                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,"Assigning default cost to peer `%s' addr plugin `%s'! This should not happen!",
2835                                 GNUNET_i2s(&neighbour->peer), neighbour->plugins->plugin->short_name);
2836           }
2837   }
2838
2839   ret->quality = GNUNET_malloc (available_quality_metrics * sizeof (struct ATS_quality_entry));
2840   ret->addrlen = addrlen;
2841   ret->expires = GNUNET_TIME_relative_to_absolute
2842     (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2843   ret->latency = GNUNET_TIME_relative_get_forever();
2844   ret->distance = -1;
2845   ret->timeout = GNUNET_TIME_relative_to_absolute
2846     (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2847   ret->ready_list = head;
2848   ret->next = head->addresses;
2849   head->addresses = ret;
2850   return ret;
2851 }
2852
2853
2854 /**
2855  * Closure for 'add_validated_address'.
2856  */
2857 struct AddValidatedAddressContext
2858 {
2859   /**
2860    * Entry that has been validated.
2861    */
2862   const struct ValidationEntry *ve;
2863
2864   /**
2865    * Flag set after we have added the address so
2866    * that we terminate the iteration next time.
2867    */
2868   int done;
2869 };
2870
2871
2872 /**
2873  * Callback function used to fill a buffer of max bytes with a list of
2874  * addresses in the format used by HELLOs.  Should use
2875  * "GNUNET_HELLO_add_address" as a helper function.
2876  *
2877  * @param cls the 'struct AddValidatedAddressContext' with the validated address
2878  * @param max maximum number of bytes that can be written to buf
2879  * @param buf where to write the address information
2880  * @return number of bytes written, 0 to signal the
2881  *         end of the iteration.
2882  */
2883 static size_t
2884 add_validated_address (void *cls,
2885                        size_t max, void *buf)
2886 {
2887   struct AddValidatedAddressContext *avac = cls;
2888   const struct ValidationEntry *ve = avac->ve;
2889
2890   if (GNUNET_YES == avac->done)
2891     return 0;
2892   avac->done = GNUNET_YES;
2893   return GNUNET_HELLO_add_address (ve->transport_name,
2894                                    GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION),
2895                                    ve->addr,
2896                                    ve->addrlen,
2897                                    buf,
2898                                    max);
2899 }
2900
2901
2902
2903 /**
2904  * Closure for 'check_address_exists'.
2905  */
2906 struct CheckAddressExistsClosure
2907 {
2908   /**
2909    * Address to check for.
2910    */
2911   const void *addr;
2912
2913   /**
2914    * Name of the transport.
2915    */
2916   const char *tname;
2917
2918   /**
2919    * Session, or NULL.
2920    */
2921   struct Session *session;
2922
2923   /**
2924    * Set to GNUNET_YES if the address exists.
2925    */
2926   int exists;
2927
2928   /**
2929    * Length of addr.
2930    */
2931   uint16_t addrlen;
2932
2933 };
2934
2935
2936 /**
2937  * Iterator over hash map entries.  Checks if the given
2938  * validation entry is for the same address as what is given
2939  * in the closure.
2940  *
2941  * @param cls the 'struct CheckAddressExistsClosure*'
2942  * @param key current key code (ignored)
2943  * @param value value in the hash map ('struct ValidationEntry')
2944  * @return GNUNET_YES if we should continue to
2945  *         iterate (mismatch), GNUNET_NO if not (entry matched)
2946  */
2947 static int
2948 check_address_exists (void *cls,
2949                       const GNUNET_HashCode * key,
2950                       void *value)
2951 {
2952   struct CheckAddressExistsClosure *caec = cls;
2953   struct ValidationEntry *ve = value;
2954
2955   if ( (0 == strcmp (caec->tname,
2956                      ve->transport_name)) &&
2957        (caec->addrlen == ve->addrlen) &&
2958        (0 == memcmp (caec->addr,
2959                      ve->addr,
2960                      caec->addrlen)) )
2961     {
2962       caec->exists = GNUNET_YES;
2963       return GNUNET_NO;
2964     }
2965   if ( (ve->session != NULL) &&
2966        (caec->session == ve->session) )
2967     {
2968       caec->exists = GNUNET_YES;
2969       return GNUNET_NO;
2970     }
2971   return GNUNET_YES;
2972 }
2973
2974
2975
2976 /**
2977  * Iterator to free entries in the validation_map.
2978  *
2979  * @param cls closure (unused)
2980  * @param key current key code
2981  * @param value value in the hash map (validation to abort)
2982  * @return GNUNET_YES (always)
2983  */
2984 static int
2985 abort_validation (void *cls,
2986                   const GNUNET_HashCode * key,
2987                   void *value)
2988 {
2989   struct ValidationEntry *va = value;
2990
2991   if (GNUNET_SCHEDULER_NO_TASK != va->timeout_task)
2992     GNUNET_SCHEDULER_cancel (va->timeout_task);
2993   GNUNET_free (va->transport_name);
2994   if (va->chvc != NULL)
2995     {
2996       va->chvc->ve_count--;
2997       if (va->chvc->ve_count == 0)
2998         {
2999           GNUNET_CONTAINER_DLL_remove (chvc_head,
3000                                        chvc_tail,
3001                                        va->chvc);
3002           GNUNET_free (va->chvc);
3003         }
3004       va->chvc = NULL;
3005     }
3006   GNUNET_free (va);
3007   return GNUNET_YES;
3008 }
3009
3010
3011 /**
3012  * HELLO validation cleanup task (validation failed).
3013  *
3014  * @param cls the 'struct ValidationEntry' that failed
3015  * @param tc scheduler context (unused)
3016  */
3017 static void
3018 timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
3019 {
3020   struct ValidationEntry *va = cls;
3021   struct GNUNET_PeerIdentity pid;
3022
3023   va->timeout_task = GNUNET_SCHEDULER_NO_TASK;
3024   GNUNET_STATISTICS_update (stats,
3025                             gettext_noop ("# address validation timeouts"),
3026                             1,
3027                             GNUNET_NO);
3028   GNUNET_CRYPTO_hash (&va->publicKey,
3029                       sizeof (struct
3030                               GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
3031                       &pid.hashPubKey);
3032   GNUNET_break (GNUNET_OK ==
3033                 GNUNET_CONTAINER_multihashmap_remove (validation_map,
3034                                                       &pid.hashPubKey,
3035                                                       va));
3036   abort_validation (NULL, NULL, va);
3037 }
3038
3039
3040 static void
3041 neighbour_timeout_task (void *cls,
3042                        const struct GNUNET_SCHEDULER_TaskContext *tc)
3043 {
3044   struct NeighbourList *n = cls;
3045
3046 #if DEBUG_TRANSPORT
3047   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
3048               "Neighbour `%4s' has timed out!\n", GNUNET_i2s (&n->id));
3049 #endif
3050   GNUNET_STATISTICS_update (stats,
3051                             gettext_noop ("# disconnects due to timeout"),
3052                             1,
3053                             GNUNET_NO);
3054   n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
3055   disconnect_neighbour (n, GNUNET_NO);
3056 }
3057
3058
3059 /**
3060  * Schedule the job that will cause us to send a PING to the
3061  * foreign address to evaluate its validity and latency.
3062  *
3063  * @param fal address to PING
3064  */
3065 static void
3066 schedule_next_ping (struct ForeignAddressList *fal);
3067
3068
3069 /**
3070  * Add the given address to the list of foreign addresses
3071  * available for the given peer (check for duplicates).
3072  *
3073  * @param cls the respective 'struct NeighbourList' to update
3074  * @param tname name of the transport
3075  * @param expiration expiration time
3076  * @param addr the address
3077  * @param addrlen length of the address
3078  * @return GNUNET_OK (always)
3079  */
3080 static int
3081 add_to_foreign_address_list (void *cls,
3082                              const char *tname,
3083                              struct GNUNET_TIME_Absolute expiration,
3084                              const void *addr,
3085                              uint16_t addrlen)
3086 {
3087   struct NeighbourList *n = cls;
3088   struct ForeignAddressList *fal;
3089   int try;
3090
3091   GNUNET_STATISTICS_update (stats,
3092                             gettext_noop ("# valid peer addresses returned by PEERINFO"),
3093                             1,
3094                             GNUNET_NO);
3095   try = GNUNET_NO;
3096   fal = find_peer_address (n, tname, NULL, addr, addrlen);
3097   if (fal == NULL)
3098     {
3099 #if DEBUG_TRANSPORT_HELLO
3100       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3101                   "Adding address `%s' (%s) for peer `%4s' due to PEERINFO data for %llums.\n",
3102                   a2s (tname, addr, addrlen),
3103                   tname,
3104                   GNUNET_i2s (&n->id),
3105                   expiration.abs_value);
3106 #endif
3107       fal = add_peer_address (n, tname, NULL, addr, addrlen);
3108       if (fal == NULL)
3109         {
3110           GNUNET_STATISTICS_update (stats,
3111                                     gettext_noop ("# previously validated addresses lacking transport"),
3112                                     1,
3113                                     GNUNET_NO);
3114         }
3115       else
3116         {
3117           fal->expires = GNUNET_TIME_absolute_max (expiration,
3118                                                    fal->expires);
3119           schedule_next_ping (fal);
3120         }
3121       try = GNUNET_YES;
3122     }
3123   else
3124     {
3125       fal->expires = GNUNET_TIME_absolute_max (expiration,
3126                                                fal->expires);
3127     }
3128   if (fal == NULL)
3129     {
3130       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3131                   "Failed to add new address for `%4s'\n",
3132                   GNUNET_i2s (&n->id));
3133       return GNUNET_OK;
3134     }
3135   if (fal->validated == GNUNET_NO)
3136     {
3137       fal->validated = GNUNET_YES;
3138       GNUNET_STATISTICS_update (stats,
3139                                 gettext_noop ("# peer addresses considered valid"),
3140                                 1,
3141                                 GNUNET_NO);
3142     }
3143   if (try == GNUNET_YES)
3144     {
3145       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3146                   "Have new addresses, will try to trigger transmissions.\n");
3147       try_transmission_to_peer (n);
3148     }
3149   return GNUNET_OK;
3150 }
3151
3152
3153 /**
3154  * Add addresses in validated HELLO "h" to the set of addresses
3155  * we have for this peer.
3156  *
3157  * @param cls closure ('struct NeighbourList*')
3158  * @param peer id of the peer, NULL for last call
3159  * @param h hello message for the peer (can be NULL)
3160  * @param err_msg NULL if successful, otherwise contains error message
3161  */
3162 static void
3163 add_hello_for_peer (void *cls,
3164                     const struct GNUNET_PeerIdentity *peer,
3165                     const struct GNUNET_HELLO_Message *h,
3166                     const char *err_msg)
3167 {
3168   struct NeighbourList *n = cls;
3169
3170   if (err_msg != NULL)
3171   {
3172           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3173                       _("Error in communication with PEERINFO service\n"));
3174         /* return; */
3175   }
3176   if ((peer == NULL))
3177     {
3178       GNUNET_STATISTICS_update (stats,
3179                                 gettext_noop ("# outstanding peerinfo iterate requests"),
3180                                 -1,
3181                                 GNUNET_NO);
3182       n->piter = NULL;
3183       return;
3184     }
3185   if (h == NULL)
3186     return; /* no HELLO available */
3187 #if DEBUG_TRANSPORT
3188   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3189               "Peerinfo had `%s' message for peer `%4s', adding existing addresses.\n",
3190               "HELLO",
3191               GNUNET_i2s (peer));
3192 #endif
3193   if (GNUNET_YES != n->public_key_valid)
3194     {
3195       GNUNET_HELLO_get_key (h, &n->publicKey);
3196       n->public_key_valid = GNUNET_YES;
3197     }
3198   GNUNET_HELLO_iterate_addresses (h,
3199                                   GNUNET_NO,
3200                                   &add_to_foreign_address_list,
3201                                   n);
3202 }
3203
3204
3205 /**
3206  * Create a fresh entry in our neighbour list for the given peer.
3207  * Will try to transmit our current HELLO to the new neighbour.
3208  * Do not call this function directly, use 'setup_peer_check_blacklist.
3209  *
3210  * @param peer the peer for which we create the entry
3211  * @param do_hello should we schedule transmitting a HELLO
3212  * @return the new neighbour list entry
3213  */
3214 static struct NeighbourList *
3215 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer,
3216                      int do_hello)
3217 {
3218   struct NeighbourList *n;
3219   struct TransportPlugin *tp;
3220   struct ReadyList *rl;
3221
3222 #if DEBUG_TRANSPORT
3223   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3224               "Setting up state for neighbour `%4s'\n",
3225               GNUNET_i2s (peer));
3226 #endif
3227   GNUNET_assert (our_hello != NULL);
3228   GNUNET_STATISTICS_update (stats,
3229                             gettext_noop ("# active neighbours"),
3230                             1,
3231                             GNUNET_NO);
3232   n = GNUNET_malloc (sizeof (struct NeighbourList));
3233   n->next = neighbours;
3234   neighbours = n;
3235   n->id = *peer;
3236   n->peer_timeout =
3237     GNUNET_TIME_relative_to_absolute
3238     (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3239   GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
3240                                  GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
3241                                  MAX_BANDWIDTH_CARRY_S);
3242   tp = plugins;
3243   while (tp != NULL)
3244     {
3245       if ((tp->api->send != NULL) && (!is_blacklisted(peer, tp)))
3246         {
3247           rl = GNUNET_malloc (sizeof (struct ReadyList));
3248           rl->neighbour = n;
3249           rl->next = n->plugins;
3250           n->plugins = rl;
3251           rl->plugin = tp;
3252           rl->addresses = NULL;
3253         }
3254       tp = tp->next;
3255     }
3256   n->latency = GNUNET_TIME_UNIT_FOREVER_REL;
3257   n->distance = -1;
3258   n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
3259                                                   &neighbour_timeout_task, n);
3260   if (do_hello)
3261     {
3262       GNUNET_STATISTICS_update (stats,
3263                                 gettext_noop ("# peerinfo new neighbor iterate requests"),
3264                                 1,
3265                                 GNUNET_NO);
3266       GNUNET_STATISTICS_update (stats,
3267                                 gettext_noop ("# outstanding peerinfo iterate requests"),
3268                                 1,
3269                                 GNUNET_NO);
3270       n->piter = GNUNET_PEERINFO_iterate (peerinfo, peer,
3271                                           GNUNET_TIME_UNIT_FOREVER_REL,
3272                                           &add_hello_for_peer, n);
3273
3274       GNUNET_STATISTICS_update (stats,
3275                                 gettext_noop ("# HELLO's sent to new neighbors"),
3276                                 1,
3277                                 GNUNET_NO);
3278       transmit_to_peer (NULL, NULL, 0,
3279                         HELLO_ADDRESS_EXPIRATION,
3280                         (const char *) our_hello, GNUNET_HELLO_size(our_hello),
3281                         GNUNET_NO, n);
3282     }
3283   return n;
3284 }
3285
3286
3287 /**
3288  * Function called after we have checked if communicating
3289  * with a given peer is acceptable.
3290  *
3291  * @param cls closure
3292  * @param n NULL if communication is not acceptable
3293  */
3294 typedef void (*SetupContinuation)(void *cls,
3295                                   struct NeighbourList *n);
3296
3297
3298 /**
3299  * Information kept for each client registered to perform
3300  * blacklisting.
3301  */
3302 struct Blacklisters
3303 {
3304   /**
3305    * This is a linked list.
3306    */
3307   struct Blacklisters *next;
3308
3309   /**
3310    * This is a linked list.
3311    */
3312   struct Blacklisters *prev;
3313
3314   /**
3315    * Client responsible for this entry.
3316    */
3317   struct GNUNET_SERVER_Client *client;
3318
3319   /**
3320    * Blacklist check that we're currently performing.
3321    */
3322   struct BlacklistCheck *bc;
3323
3324 };
3325
3326
3327 /**
3328  * Head of DLL of blacklisting clients.
3329  */
3330 static struct Blacklisters *bl_head;
3331
3332 /**
3333  * Tail of DLL of blacklisting clients.
3334  */
3335 static struct Blacklisters *bl_tail;
3336
3337
3338 /**
3339  * Context we use when performing a blacklist check.
3340  */
3341 struct BlacklistCheck
3342 {
3343
3344   /**
3345    * This is a linked list.
3346    */
3347   struct BlacklistCheck *next;
3348
3349   /**
3350    * This is a linked list.
3351    */
3352   struct BlacklistCheck *prev;
3353
3354   /**
3355    * Peer being checked.
3356    */
3357   struct GNUNET_PeerIdentity peer;
3358
3359   /**
3360    * Option for setup neighbour afterwards.
3361    */
3362   int do_hello;
3363
3364   /**
3365    * Continuation to call with the result.
3366    */
3367   SetupContinuation cont;
3368
3369   /**
3370    * Closure for cont.
3371    */
3372   void *cont_cls;
3373
3374   /**
3375    * Current transmission request handle for this client, or NULL if no
3376    * request is pending.
3377    */
3378   struct GNUNET_CONNECTION_TransmitHandle *th;
3379
3380   /**
3381    * Our current position in the blacklisters list.
3382    */
3383   struct Blacklisters *bl_pos;
3384
3385   /**
3386    * Current task performing the check.
3387    */
3388   GNUNET_SCHEDULER_TaskIdentifier task;
3389
3390 };
3391
3392 /**
3393  * Head of DLL of active blacklisting queries.
3394  */
3395 static struct BlacklistCheck *bc_head;
3396
3397 /**
3398  * Tail of DLL of active blacklisting queries.
3399  */
3400 static struct BlacklistCheck *bc_tail;
3401
3402
3403 /**
3404  * Perform next action in the blacklist check.
3405  *
3406  * @param cls the 'struct BlacklistCheck*'
3407  * @param tc unused
3408  */
3409 static void
3410 do_blacklist_check (void *cls,
3411                     const struct GNUNET_SCHEDULER_TaskContext *tc);
3412
3413 /**
3414  * Transmit blacklist query to the client.
3415  *
3416  * @param cls the 'struct BlacklistCheck'
3417  * @param size number of bytes allowed
3418  * @param buf where to copy the message
3419  * @return number of bytes copied to buf
3420  */
3421 static size_t
3422 transmit_blacklist_message (void *cls,
3423                             size_t size,
3424                             void *buf)
3425 {
3426   struct BlacklistCheck *bc = cls;
3427   struct Blacklisters *bl;
3428   struct BlacklistMessage bm;
3429
3430   bc->th = NULL;
3431   if (size == 0)
3432     {
3433       GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK);
3434       bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3435                                            bc);
3436       return 0;
3437     }
3438   bl = bc->bl_pos;
3439   bm.header.size = htons (sizeof (struct BlacklistMessage));
3440   bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
3441   bm.is_allowed = htonl (0);
3442   bm.peer = bc->peer;
3443   memcpy (buf, &bm, sizeof (bm));
3444   GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
3445   return sizeof (bm);
3446 }
3447
3448
3449 /**
3450  * Perform next action in the blacklist check.
3451  *
3452  * @param cls the 'struct BlacklistCheck*'
3453  * @param tc unused
3454  */
3455 static void
3456 do_blacklist_check (void *cls,
3457                     const struct GNUNET_SCHEDULER_TaskContext *tc)
3458 {
3459   struct BlacklistCheck *bc = cls;
3460   struct Blacklisters *bl;
3461
3462   bc->task = GNUNET_SCHEDULER_NO_TASK;
3463   bl = bc->bl_pos;
3464   if (bl == NULL)
3465     {
3466       bc->cont (bc->cont_cls,
3467                 setup_new_neighbour (&bc->peer, bc->do_hello));
3468       GNUNET_free (bc);
3469       return;
3470     }
3471   if (bl->bc == NULL)
3472     {
3473       bl->bc = bc;
3474       bc->th = GNUNET_SERVER_notify_transmit_ready (bl->client,
3475                                                     sizeof (struct BlacklistMessage),
3476                                                     GNUNET_TIME_UNIT_FOREVER_REL,
3477                                                     &transmit_blacklist_message,
3478                                                     bc);
3479     }
3480 }
3481
3482
3483 /**
3484  * Obtain a 'struct NeighbourList' for the given peer.  If such an entry
3485  * does not yet exist, check the blacklist.  If the blacklist says creating
3486  * one is acceptable, create one and call the continuation; otherwise
3487  * call the continuation with NULL.
3488  *
3489  * @param peer peer to setup or look up a struct NeighbourList for
3490  * @param do_hello should we also schedule sending our HELLO to the peer
3491  *        if this is a new record
3492  * @param cont function to call with the 'struct NeigbhbourList*'
3493  * @param cont_cls closure for cont
3494  */
3495 static void
3496 setup_peer_check_blacklist (const struct GNUNET_PeerIdentity *peer,
3497                             int do_hello,
3498                             SetupContinuation cont,
3499                             void *cont_cls)
3500 {
3501   struct NeighbourList *n;
3502   struct BlacklistCheck *bc;
3503
3504   n = find_neighbour(peer);
3505   if (n != NULL)
3506     {
3507       if (cont != NULL)
3508         cont (cont_cls, n);
3509       return;
3510     }
3511   if (bl_head == NULL)
3512     {
3513       if (cont != NULL)
3514         cont (cont_cls, setup_new_neighbour (peer, do_hello));
3515       else
3516         setup_new_neighbour(peer, do_hello);
3517       return;
3518     }
3519   bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3520   GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3521   bc->peer = *peer;
3522   bc->do_hello = do_hello;
3523   bc->cont = cont;
3524   bc->cont_cls = cont_cls;
3525   bc->bl_pos = bl_head;
3526   bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3527                                        bc);
3528 }
3529
3530
3531 /**
3532  * Function called with the result of querying a new blacklister about
3533  * it being allowed (or not) to continue to talk to an existing neighbour.
3534  *
3535  * @param cls the original 'struct NeighbourList'
3536  * @param n NULL if we need to disconnect
3537  */
3538 static void
3539 confirm_or_drop_neighbour (void *cls,
3540                            struct NeighbourList *n)
3541 {
3542   struct NeighbourList * orig = cls;
3543
3544   if (n == NULL)
3545     {
3546       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3547               "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&orig->id),
3548               "confirm_or_drop_neighboUr");
3549       disconnect_neighbour (orig, GNUNET_NO);
3550     }
3551 }
3552
3553
3554 /**
3555  * Handle a request to start a blacklist.
3556  *
3557  * @param cls closure (always NULL)
3558  * @param client identification of the client
3559  * @param message the actual message
3560  */
3561 static void
3562 handle_blacklist_init (void *cls,
3563                        struct GNUNET_SERVER_Client *client,
3564                        const struct GNUNET_MessageHeader *message)
3565 {
3566   struct Blacklisters *bl;
3567   struct BlacklistCheck *bc;
3568   struct NeighbourList *n;
3569
3570   bl = bl_head;
3571   while (bl != NULL)
3572     {
3573       if (bl->client == client)
3574         {
3575           GNUNET_break (0);
3576           GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3577           return;
3578         }
3579       bl = bl->next;
3580     }
3581   bl = GNUNET_malloc (sizeof (struct Blacklisters));
3582   bl->client = client;
3583   GNUNET_SERVER_client_keep (client);
3584   GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
3585   /* confirm that all existing connections are OK! */
3586   n = neighbours;
3587   while (NULL != n)
3588     {
3589       bc = GNUNET_malloc (sizeof (struct BlacklistCheck));
3590       GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
3591       bc->peer = n->id;
3592       bc->do_hello = GNUNET_NO;
3593       bc->cont = &confirm_or_drop_neighbour;
3594       bc->cont_cls = n;
3595       bc->bl_pos = bl;
3596       if (n == neighbours) /* all would wait for the same client, no need to
3597                               create more than just the first task right now */
3598         bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3599                                              bc);
3600       n = n->next;
3601     }
3602 }
3603
3604
3605 /**
3606  * Handle a request to blacklist a peer.
3607  *
3608  * @param cls closure (always NULL)
3609  * @param client identification of the client
3610  * @param message the actual message
3611  */
3612 static void
3613 handle_blacklist_reply (void *cls,
3614                         struct GNUNET_SERVER_Client *client,
3615                         const struct GNUNET_MessageHeader *message)
3616 {
3617   const struct BlacklistMessage *msg = (const struct BlacklistMessage*) message;
3618   struct Blacklisters *bl;
3619   struct BlacklistCheck *bc;
3620
3621   bl = bl_head;
3622   while ( (bl != NULL) &&
3623           (bl->client != client) )
3624     bl = bl->next;
3625   if (bl == NULL)
3626     {
3627       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
3628       return;
3629     }
3630   bc = bl->bc;
3631   bl->bc = NULL;
3632   if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
3633     {
3634       bc->cont (bc->cont_cls, NULL);
3635       GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
3636       GNUNET_free (bc);
3637     }
3638   else
3639     {
3640       bc->bl_pos = bc->bl_pos->next;
3641       bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3642                                            bc);
3643     }
3644   /* check if any other bc's are waiting for this blacklister */
3645   bc = bc_head;
3646   while (bc != NULL)
3647     {
3648       if ( (bc->bl_pos == bl) &&
3649            (GNUNET_SCHEDULER_NO_TASK == bc->task) )
3650         bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
3651                                              bc);
3652       bc = bc->next;
3653     }
3654 }
3655
3656
3657 /**
3658  * Send periodic PING messages to a given foreign address.
3659  *
3660  * @param cls our 'struct PeriodicValidationContext*'
3661  * @param tc task context
3662  */
3663 static void
3664 send_periodic_ping (void *cls,
3665                     const struct GNUNET_SCHEDULER_TaskContext *tc)
3666 {
3667   struct ForeignAddressList *peer_address = cls;
3668   struct TransportPlugin *tp;
3669   struct ValidationEntry *va;
3670   struct NeighbourList *neighbour;
3671   struct TransportPingMessage ping;
3672   struct CheckAddressExistsClosure caec;
3673   char * message_buf;
3674   uint16_t hello_size;
3675   size_t slen;
3676   size_t tsize;
3677
3678   peer_address->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
3679   if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
3680     return;
3681   tp = peer_address->ready_list->plugin;
3682   neighbour = peer_address->ready_list->neighbour;
3683   if (GNUNET_YES != neighbour->public_key_valid)
3684     {
3685       /* no public key yet, try again later */
3686       schedule_next_ping (peer_address);
3687       return;
3688     }
3689   caec.addr = peer_address->addr;
3690   caec.addrlen = peer_address->addrlen;
3691   caec.tname = tp->short_name;
3692   caec.session = peer_address->session;
3693   caec.exists = GNUNET_NO;
3694   GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3695                                          &check_address_exists,
3696                                          &caec);
3697   if (caec.exists == GNUNET_YES)
3698     {
3699       /* During validation attempts we will likely trigger the other
3700          peer trying to validate our address which in turn will cause
3701          it to send us its HELLO, so we expect to hit this case rather
3702          frequently.  Only print something if we are very verbose. */
3703 #if DEBUG_TRANSPORT > 1
3704       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3705                   "Some validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
3706                   (peer_address->addr != NULL)
3707                   ? a2s (tp->short_name,
3708                          peer_address->addr,
3709                          peer_address->addrlen)
3710                   : "<inbound>",
3711                   tp->short_name,
3712                   GNUNET_i2s (&neighbour->id));
3713 #endif
3714       schedule_next_ping (peer_address);
3715       return;
3716     }
3717   va = GNUNET_malloc (sizeof (struct ValidationEntry) + peer_address->addrlen);
3718   va->transport_name = GNUNET_strdup (tp->short_name);
3719   va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
3720                                             UINT_MAX);
3721   va->send_time = GNUNET_TIME_absolute_get();
3722   va->session = peer_address->session;
3723   if (peer_address->addr != NULL)
3724     {
3725       va->addr = (const void*) &va[1];
3726       memcpy (&va[1], peer_address->addr, peer_address->addrlen);
3727       va->addrlen = peer_address->addrlen;
3728     }
3729   memcpy(&va->publicKey,
3730          &neighbour->publicKey,
3731          sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
3732
3733   va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
3734                                                    &timeout_hello_validation,
3735                                                    va);
3736   GNUNET_CONTAINER_multihashmap_put (validation_map,
3737                                      &neighbour->id.hashPubKey,
3738                                      va,
3739                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3740
3741   if (peer_address->validated != GNUNET_YES)
3742     hello_size = GNUNET_HELLO_size(our_hello);
3743   else
3744     hello_size = 0;
3745
3746   tsize = sizeof(struct TransportPingMessage) + hello_size;
3747
3748   if (peer_address->addr != NULL)
3749     {
3750       slen = strlen (tp->short_name) + 1;
3751       tsize += slen + peer_address->addrlen;
3752     }
3753   else
3754     {
3755       slen = 0; /* make gcc happy */
3756     }
3757   message_buf = GNUNET_malloc(tsize);
3758   ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
3759   ping.challenge = htonl(va->challenge);
3760   memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
3761   if (peer_address->validated != GNUNET_YES)
3762     {
3763       memcpy(message_buf, our_hello, hello_size);
3764     }
3765
3766   if (peer_address->addr != NULL)
3767     {
3768       ping.header.size = htons(sizeof(struct TransportPingMessage) +
3769                                peer_address->addrlen +
3770                                slen);
3771       memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
3772              tp->short_name,
3773              slen);
3774       memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
3775              peer_address->addr,
3776              peer_address->addrlen);
3777     }
3778   else
3779     {
3780       ping.header.size = htons(sizeof(struct TransportPingMessage));
3781     }
3782
3783   memcpy(&message_buf[hello_size],
3784          &ping,
3785          sizeof(struct TransportPingMessage));
3786
3787 #if DEBUG_TRANSPORT_REVALIDATION
3788   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3789               "Performing re-validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s'\n",
3790               (peer_address->addr != NULL)
3791               ? a2s (peer_address->plugin->short_name,
3792                      peer_address->addr,
3793                      peer_address->addrlen)
3794               : "<inbound>",
3795               tp->short_name,
3796               GNUNET_i2s (&neighbour->id),
3797               "HELLO", hello_size,
3798               "PING");
3799 #endif
3800   if (peer_address->validated != GNUNET_YES)
3801     GNUNET_STATISTICS_update (stats,
3802                               gettext_noop ("# PING with HELLO messages sent"),
3803                               1,
3804                               GNUNET_NO);
3805   else
3806     GNUNET_STATISTICS_update (stats,
3807                               gettext_noop ("# PING without HELLO messages sent"),
3808                               1,
3809                               GNUNET_NO);
3810   GNUNET_STATISTICS_update (stats,
3811                             gettext_noop ("# PING messages sent for re-validation"),
3812                             1,
3813                             GNUNET_NO);
3814   transmit_to_peer (NULL, peer_address,
3815                     GNUNET_SCHEDULER_PRIORITY_DEFAULT,
3816                     HELLO_VERIFICATION_TIMEOUT,
3817                     message_buf, tsize,
3818                     GNUNET_YES, neighbour);
3819   GNUNET_free(message_buf);
3820   schedule_next_ping (peer_address);
3821 }
3822
3823
3824 /**
3825  * Schedule the job that will cause us to send a PING to the
3826  * foreign address to evaluate its validity and latency.
3827  *
3828  * @param fal address to PING
3829  */
3830 static void
3831 schedule_next_ping (struct ForeignAddressList *fal)
3832 {
3833   struct GNUNET_TIME_Relative delay;
3834
3835   if (fal->revalidate_task != GNUNET_SCHEDULER_NO_TASK)
3836     return;
3837   delay = GNUNET_TIME_absolute_get_remaining (fal->expires);
3838   delay.rel_value /= 2; /* do before expiration */
3839   delay = GNUNET_TIME_relative_min (delay,
3840                                     LATENCY_EVALUATION_MAX_DELAY);
3841   if (GNUNET_YES != fal->estimated)
3842     {
3843       delay = GNUNET_TIME_UNIT_ZERO;
3844       fal->estimated = GNUNET_YES;
3845     }
3846   if (GNUNET_YES == fal->connected)
3847     {
3848       delay = GNUNET_TIME_relative_min (delay,
3849                                         CONNECTED_LATENCY_EVALUATION_MAX_DELAY);
3850     }
3851   /* FIXME: also adjust delay based on how close the last
3852      observed latency is to the latency of the best alternative */
3853   /* bound how fast we can go */
3854   delay = GNUNET_TIME_relative_max (delay,
3855                                     GNUNET_TIME_UNIT_SECONDS);
3856   /* randomize a bit (to avoid doing all at the same time) */
3857   delay.rel_value += GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 1000);
3858   fal->revalidate_task = GNUNET_SCHEDULER_add_delayed(delay,
3859                                                       &send_periodic_ping,
3860                                                       fal);
3861 }
3862
3863
3864
3865
3866 /**
3867  * Function that will be called if we receive some payload
3868  * from another peer.
3869  *
3870  * @param message the payload
3871  * @param n peer who claimed to be the sender
3872  */
3873 static void
3874 handle_payload_message (const struct GNUNET_MessageHeader *message,
3875                                                 struct NeighbourList *n)
3876 {
3877   struct InboundMessage *im;
3878   struct TransportClient *cpos;
3879   uint16_t msize;
3880
3881   msize = ntohs (message->size);
3882   if (n->received_pong == GNUNET_NO)
3883     {
3884       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3885                   "Received message of type %u and size %u from `%4s', but no pong yet!!\n",
3886                   ntohs (message->type),
3887                   ntohs (message->size),
3888                   GNUNET_i2s (&n->id));
3889       GNUNET_free_non_null (n->pre_connect_message_buffer);
3890       n->pre_connect_message_buffer = GNUNET_malloc (msize);
3891       memcpy (n->pre_connect_message_buffer, message, msize);
3892       return;
3893     }
3894
3895 #if DEBUG_TRANSPORT
3896   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3897               "Received message of type %u and size %u from `%4s', sending to all clients.\n",
3898               ntohs (message->type),
3899               ntohs (message->size),
3900               GNUNET_i2s (&n->id));
3901 #endif
3902   if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3903                                                       (ssize_t) msize))
3904     {
3905       n->quota_violation_count++;
3906 #if DEBUG_TRANSPORT
3907       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3908                   "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
3909                   n->in_tracker.available_bytes_per_s__,
3910                   n->quota_violation_count);
3911 #endif
3912       /* Discount 32k per violation */
3913       GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3914                                         - 32 * 1024);
3915     }
3916   else
3917     {
3918       if (n->quota_violation_count > 0)
3919         {
3920           /* try to add 32k back */
3921           GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker,
3922                                             32 * 1024);
3923           n->quota_violation_count--;
3924         }
3925     }
3926   GNUNET_STATISTICS_update (stats,
3927                             gettext_noop ("# payload received from other peers"),
3928                             msize,
3929                             GNUNET_NO);
3930   /* transmit message to all clients */
3931   uint32_t ats_count = 2;
3932   size_t size = sizeof (struct InboundMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information) + msize;
3933   if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
3934           GNUNET_break(0);
3935
3936   im = GNUNET_malloc (size);
3937   im->header.size = htons (size);
3938   im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
3939   im->peer = n->id;
3940   im->ats_count = htonl(ats_count);
3941   /* Setting ATS data */
3942   (&(im->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
3943   (&(im->ats))[0].value = htonl (n->distance);
3944   (&(im->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
3945   (&(im->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
3946   (&(im->ats))[ats_count].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
3947   (&(im->ats))[ats_count].value = htonl (0);
3948
3949   memcpy (&((&(im->ats))[ats_count+1]), message, msize);
3950   cpos = clients;
3951   while (cpos != NULL)
3952     {
3953       transmit_to_client (cpos, &im->header, GNUNET_YES);
3954       cpos = cpos->next;
3955     }
3956   GNUNET_free (im);
3957 }
3958
3959
3960 /**
3961  * Iterator over hash map entries.  Checks if the given validation
3962  * entry is for the same challenge as what is given in the PONG.
3963  *
3964  * @param cls the 'struct TransportPongMessage*'
3965  * @param key peer identity
3966  * @param value value in the hash map ('struct ValidationEntry')
3967  * @return GNUNET_YES if we should continue to
3968  *         iterate (mismatch), GNUNET_NO if not (entry matched)
3969  */
3970 static int
3971 check_pending_validation (void *cls,
3972                           const GNUNET_HashCode * key,
3973                           void *value)
3974 {
3975   const struct TransportPongMessage *pong = cls;
3976   struct ValidationEntry *ve = value;
3977   struct AddValidatedAddressContext avac;
3978   unsigned int challenge = ntohl(pong->challenge);
3979   struct GNUNET_HELLO_Message *hello;
3980   struct GNUNET_PeerIdentity target;
3981   struct NeighbourList *n;
3982   struct ForeignAddressList *fal;
3983   struct OwnAddressList *oal;
3984   struct TransportPlugin *tp;
3985   struct GNUNET_MessageHeader *prem;
3986   uint16_t ps;
3987   const char *addr;
3988   size_t slen;
3989   size_t alen;
3990
3991   ps = ntohs (pong->header.size);
3992   if (ps < sizeof (struct TransportPongMessage))
3993     {
3994       GNUNET_break_op (0);
3995       return GNUNET_NO;
3996     }
3997   addr = (const char*) &pong[1];
3998   slen = strlen (ve->transport_name) + 1;
3999   if ( (ps - sizeof (struct TransportPongMessage) < slen) ||
4000        (ve->challenge != challenge) ||
4001        (addr[slen-1] != '\0') ||
4002        (0 != strcmp (addr, ve->transport_name)) ||
4003        (ntohl (pong->purpose.size)
4004         != sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4005         sizeof (uint32_t) +
4006         sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4007         sizeof (struct GNUNET_PeerIdentity) + ps - sizeof (struct TransportPongMessage)) )
4008     {
4009       return GNUNET_YES;
4010     }
4011
4012   alen = ps - sizeof (struct TransportPongMessage) - slen;
4013   switch (ntohl (pong->purpose.purpose))
4014     {
4015     case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN:
4016       if ( (ve->addrlen + slen != ntohl (pong->addrlen)) ||
4017            (0 != memcmp (&addr[slen],
4018                          ve->addr,
4019                          ve->addrlen)) )
4020         {
4021           return GNUNET_YES; /* different entry, keep trying! */
4022         }
4023       if (0 != memcmp (&pong->pid,
4024                        key,
4025                        sizeof (struct GNUNET_PeerIdentity)))
4026         {
4027           GNUNET_break_op (0);
4028           return GNUNET_NO;
4029         }
4030       if (GNUNET_OK !=
4031           GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
4032                                     &pong->purpose,
4033                                     &pong->signature,
4034                                     &ve->publicKey))
4035         {
4036           GNUNET_break_op (0);
4037           return GNUNET_NO;
4038         }
4039
4040 #if DEBUG_TRANSPORT
4041       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4042                   "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
4043                   GNUNET_h2s (key),
4044                   a2s (ve->transport_name,
4045                        (const struct sockaddr *) ve->addr,
4046                        ve->addrlen),
4047                   ve->transport_name);
4048 #endif
4049       break;
4050     case GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING:
4051       if (0 != memcmp (&pong->pid,
4052                          &my_identity,
4053                          sizeof (struct GNUNET_PeerIdentity)))
4054         {
4055           GNUNET_break_op (0);
4056           return GNUNET_NO;
4057         }
4058       if (ve->addrlen != 0)
4059         {
4060           /* must have been for a different validation entry */
4061           return GNUNET_YES;
4062         }
4063       tp = find_transport (ve->transport_name);
4064       if (tp == NULL)
4065         {
4066           GNUNET_break (0);
4067           return GNUNET_YES;
4068         }
4069       oal = tp->addresses;
4070       while (NULL != oal)
4071         {
4072           if ( (oal->addrlen == alen) &&
4073                (0 == memcmp (&oal[1],
4074                              &addr[slen],
4075                              alen)) )
4076             break;
4077           oal = oal->next;
4078         }
4079       if (oal == NULL)
4080         {
4081           GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4082                       _("Not accepting PONG with address `%s' since I cannot confirm having this address.\n"),
4083                       a2s (ve->transport_name,
4084                            &addr[slen],
4085                            alen));
4086           return GNUNET_NO;
4087         }
4088       if (GNUNET_OK !=
4089           GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING,
4090                                     &pong->purpose,
4091                                     &pong->signature,
4092                                     &ve->publicKey))
4093         {
4094           GNUNET_break_op (0);
4095           return GNUNET_NO;
4096         }
4097
4098 #if DEBUG_TRANSPORT
4099       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4100                   "Confirmed that peer `%4s' is talking to us using address `%s' (%s) for us.\n",
4101                   GNUNET_h2s (key),
4102                   a2s (ve->transport_name,
4103                        &addr[slen],
4104                        alen),
4105                   ve->transport_name);
4106 #endif
4107       break;
4108     default:
4109       GNUNET_break_op (0);
4110       return GNUNET_NO;
4111     }
4112   if (GNUNET_TIME_absolute_get_remaining (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value == 0)
4113     {
4114       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4115                   _("Received expired signature.  Check system time.\n"));
4116       return GNUNET_NO;
4117     }
4118   GNUNET_STATISTICS_update (stats,
4119                             gettext_noop ("# address validation successes"),
4120                             1,
4121                             GNUNET_NO);
4122   /* create the updated HELLO */
4123   GNUNET_CRYPTO_hash (&ve->publicKey,
4124                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4125                       &target.hashPubKey);
4126   if (ve->addr != NULL)
4127     {
4128       avac.done = GNUNET_NO;
4129       avac.ve = ve;
4130       hello = GNUNET_HELLO_create (&ve->publicKey,
4131                                    &add_validated_address,
4132                                    &avac);
4133       GNUNET_PEERINFO_add_peer (peerinfo,
4134                                 hello);
4135       GNUNET_free (hello);
4136     }
4137   n = find_neighbour (&target);
4138   if (n != NULL)
4139     {
4140       n->publicKey = ve->publicKey;
4141       n->public_key_valid = GNUNET_YES;
4142       fal = add_peer_address (n,
4143                               ve->transport_name,
4144                               ve->session,
4145                               ve->addr,
4146                               ve->addrlen);
4147       GNUNET_assert (fal != NULL);
4148       fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
4149       fal->validated = GNUNET_YES;
4150       mark_address_connected (fal);
4151       GNUNET_STATISTICS_update (stats,
4152                                 gettext_noop ("# peer addresses considered valid"),
4153                                 1,
4154                                 GNUNET_NO);
4155       fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
4156       update_addr_value (fal, GNUNET_TIME_absolute_get_duration (ve->send_time).rel_value, GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
4157
4158       schedule_next_ping (fal);
4159       if (n->latency.rel_value == GNUNET_TIME_UNIT_FOREVER_REL.rel_value)
4160         n->latency = fal->latency;
4161       else
4162         n->latency.rel_value = (fal->latency.rel_value + n->latency.rel_value) / 2;
4163
4164       n->distance = fal->distance;
4165       if (GNUNET_NO == n->received_pong)
4166         {
4167           n->received_pong = GNUNET_YES;
4168
4169           notify_clients_connect (&target, n->latency, n->distance);
4170           if (NULL != (prem = n->pre_connect_message_buffer))
4171             {
4172               n->pre_connect_message_buffer = NULL;
4173               handle_payload_message (prem, n);
4174               GNUNET_free (prem);
4175             }
4176         }
4177       if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4178         {
4179           GNUNET_SCHEDULER_cancel (n->retry_task);
4180           n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4181           try_transmission_to_peer (n);
4182         }
4183     }
4184
4185   /* clean up validation entry */
4186   GNUNET_assert (GNUNET_YES ==
4187                  GNUNET_CONTAINER_multihashmap_remove (validation_map,
4188                                                        key,
4189                                                        ve));
4190   abort_validation (NULL, NULL, ve);
4191   return GNUNET_NO;
4192 }
4193
4194
4195 /**
4196  * Function that will be called if we receive a validation
4197  * of an address challenge that we transmitted to another
4198  * peer.  Note that the validation should only be considered
4199  * acceptable if the challenge matches AND if the sender
4200  * address is at least a plausible address for this peer
4201  * (otherwise we may be seeing a MiM attack).
4202  *
4203  * @param cls closure
4204  * @param message the pong message
4205  * @param peer who responded to our challenge
4206  * @param sender_address string describing our sender address (as observed
4207  *         by the other peer in binary format)
4208  * @param sender_address_len number of bytes in 'sender_address'
4209  */
4210 static void
4211 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
4212              const struct GNUNET_PeerIdentity *peer,
4213              const char *sender_address,
4214              size_t sender_address_len)
4215 {
4216 #if DEBUG_TRANSPORT > 1
4217   /* we get tons of these that just get discarded, only log
4218      if we are quite verbose */
4219   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4220               "Receiving `%s' message from `%4s'.\n", "PONG",
4221               GNUNET_i2s (peer));
4222 #endif
4223   GNUNET_STATISTICS_update (stats,
4224                             gettext_noop ("# PONG messages received"),
4225                             1,
4226                             GNUNET_NO);
4227   if (GNUNET_SYSERR !=
4228       GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
4229                                                   &peer->hashPubKey,
4230                                                   &check_pending_validation,
4231                                                   (void*) message))
4232     {
4233       /* This is *expected* to happen a lot since we send
4234          PONGs to *all* known addresses of the sender of
4235          the PING, so most likely we get multiple PONGs
4236          per PING, and all but the first PONG will end up
4237          here. So really we should not print anything here
4238          unless we want to be very, very verbose... */
4239 #if DEBUG_TRANSPORT > 2
4240       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4241                   "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
4242                   "PONG",
4243                   GNUNET_i2s (peer),
4244                   "PING");
4245 #endif
4246       return;
4247     }
4248
4249 }
4250
4251
4252 /**
4253  * Try to validate a neighbour's address by sending him our HELLO and a PING.
4254  *
4255  * @param cls the 'struct ValidationEntry*'
4256  * @param neighbour neighbour to validate, NULL if validation failed
4257  */
4258 static void
4259 transmit_hello_and_ping (void *cls,
4260                          struct NeighbourList *neighbour)
4261 {
4262   struct ValidationEntry *va = cls;
4263   struct ForeignAddressList *peer_address;
4264   struct TransportPingMessage ping;
4265   uint16_t hello_size;
4266   size_t tsize;
4267   char * message_buf;
4268   struct GNUNET_PeerIdentity id;
4269   size_t slen;
4270
4271   GNUNET_CRYPTO_hash (&va->publicKey,
4272                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4273                       &id.hashPubKey);
4274   if (neighbour == NULL)
4275     {
4276       /* FIXME: stats... */
4277       GNUNET_break (GNUNET_OK ==
4278                     GNUNET_CONTAINER_multihashmap_remove (validation_map,
4279                                                           &id.hashPubKey,
4280                                                           va));
4281       abort_validation (NULL, NULL, va);
4282       return;
4283     }
4284   neighbour->publicKey = va->publicKey;
4285   neighbour->public_key_valid = GNUNET_YES;
4286   peer_address = add_peer_address (neighbour,
4287                                    va->transport_name, NULL,
4288                                    (const void*) &va[1],
4289                                    va->addrlen);
4290   if (peer_address == NULL)
4291     {
4292       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
4293                   "Failed to add peer `%4s' for plugin `%s'\n",
4294                   GNUNET_i2s (&neighbour->id),
4295                   va->transport_name);
4296       GNUNET_break (GNUNET_OK ==
4297                     GNUNET_CONTAINER_multihashmap_remove (validation_map,
4298                                                           &id.hashPubKey,
4299                                                           va));
4300       abort_validation (NULL, NULL, va);
4301       return;
4302     }
4303   hello_size = GNUNET_HELLO_size(our_hello);
4304   slen = strlen(va->transport_name) + 1;
4305   tsize = sizeof(struct TransportPingMessage) + hello_size + va->addrlen + slen;
4306   message_buf = GNUNET_malloc(tsize);
4307   ping.challenge = htonl(va->challenge);
4308   ping.header.size = htons(sizeof(struct TransportPingMessage) + slen + va->addrlen);
4309   ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
4310   memcpy(&ping.target, &neighbour->id, sizeof(struct GNUNET_PeerIdentity));
4311   memcpy(message_buf, our_hello, hello_size);
4312   memcpy(&message_buf[hello_size],
4313          &ping,
4314          sizeof(struct TransportPingMessage));
4315   memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage)],
4316          va->transport_name,
4317          slen);
4318   memcpy(&message_buf[hello_size + sizeof (struct TransportPingMessage) + slen],
4319          &va[1],
4320          va->addrlen);
4321 #if DEBUG_TRANSPORT
4322   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4323               "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
4324               (va->addrlen == 0)
4325               ? "<inbound>"
4326               : a2s (va->transport_name,
4327                      (const void*) &va[1], va->addrlen),
4328               va->transport_name,
4329               GNUNET_i2s (&neighbour->id),
4330               "HELLO", hello_size,
4331               "PING", sizeof (struct TransportPingMessage) + va->addrlen + slen);
4332 #endif
4333
4334   GNUNET_STATISTICS_update (stats,
4335                             gettext_noop ("# PING messages sent for initial validation"),
4336                             1,
4337                             GNUNET_NO);
4338   transmit_to_peer (NULL, peer_address,
4339                     GNUNET_SCHEDULER_PRIORITY_DEFAULT,
4340                     HELLO_VERIFICATION_TIMEOUT,
4341                     message_buf, tsize,
4342                     GNUNET_YES, neighbour);
4343   GNUNET_free(message_buf);
4344 }
4345
4346
4347 /**
4348  * Check if the given address is already being validated; if not,
4349  * append the given address to the list of entries that are being be
4350  * validated and initiate validation.
4351  *
4352  * @param cls closure ('struct CheckHelloValidatedContext *')
4353  * @param tname name of the transport
4354  * @param expiration expiration time
4355  * @param addr the address
4356  * @param addrlen length of the address
4357  * @return GNUNET_OK (always)
4358  */
4359 static int
4360 run_validation (void *cls,
4361                 const char *tname,
4362                 struct GNUNET_TIME_Absolute expiration,
4363                 const void *addr,
4364                 uint16_t addrlen)
4365 {
4366   struct CheckHelloValidatedContext *chvc = cls;
4367   struct GNUNET_PeerIdentity id;
4368   struct TransportPlugin *tp;
4369   struct ValidationEntry *va;
4370   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4371   struct CheckAddressExistsClosure caec;
4372   struct OwnAddressList *oal;
4373
4374   GNUNET_assert (addr != NULL);
4375
4376   GNUNET_STATISTICS_update (stats,
4377                             gettext_noop ("# peer addresses scheduled for validation"),
4378                             1,
4379                             GNUNET_NO);
4380   tp = find_transport (tname);
4381   if (tp == NULL)
4382     {
4383       GNUNET_log (GNUNET_ERROR_TYPE_INFO |
4384                   GNUNET_ERROR_TYPE_BULK,
4385                   _
4386                   ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
4387                   tname);
4388       GNUNET_STATISTICS_update (stats,
4389                                 gettext_noop ("# peer addresses not validated (plugin not available)"),
4390                                 1,
4391                                 GNUNET_NO);
4392       return GNUNET_OK;
4393     }
4394   /* check if this is one of our own addresses */
4395   oal = tp->addresses;
4396   while (NULL != oal)
4397     {
4398       if ( (oal->addrlen == addrlen) &&
4399            (0 == memcmp (&oal[1],
4400                          addr,
4401                          addrlen)) )
4402         {
4403           /* not plausible, this address is equivalent to our own address! */
4404           GNUNET_STATISTICS_update (stats,
4405                                     gettext_noop ("# peer addresses not validated (loopback)"),
4406                                     1,
4407                                     GNUNET_NO);
4408           return GNUNET_OK;
4409         }
4410       oal = oal->next;
4411     }
4412   GNUNET_HELLO_get_key (chvc->hello, &pk);
4413   GNUNET_CRYPTO_hash (&pk,
4414                       sizeof (struct
4415                               GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4416                       &id.hashPubKey);
4417
4418   if (is_blacklisted(&id, tp))
4419     {
4420 #if DEBUG_TRANSPORT
4421       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4422                   "Attempted to validate blacklisted peer `%s' using `%s'!\n",
4423                   GNUNET_i2s(&id),
4424                   tname);
4425 #endif
4426       return GNUNET_OK;
4427     }
4428
4429   caec.addr = addr;
4430   caec.addrlen = addrlen;
4431   caec.session = NULL;
4432   caec.tname = tname;
4433   caec.exists = GNUNET_NO;
4434   GNUNET_CONTAINER_multihashmap_iterate (validation_map,
4435                                          &check_address_exists,
4436                                          &caec);
4437   if (caec.exists == GNUNET_YES)
4438     {
4439       /* During validation attempts we will likely trigger the other
4440          peer trying to validate our address which in turn will cause
4441          it to send us its HELLO, so we expect to hit this case rather
4442          frequently.  Only print something if we are very verbose. */
4443 #if DEBUG_TRANSPORT > 1
4444       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4445                   "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
4446                   a2s (tname, addr, addrlen),
4447                   tname,
4448                   GNUNET_i2s (&id));
4449 #endif
4450       GNUNET_STATISTICS_update (stats,
4451                                 gettext_noop ("# peer addresses not validated (in progress)"),
4452                                 1,
4453                                 GNUNET_NO);
4454       return GNUNET_OK;
4455     }
4456   va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
4457   va->chvc = chvc;
4458   chvc->ve_count++;
4459   va->transport_name = GNUNET_strdup (tname);
4460   va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE,
4461                                             UINT_MAX);
4462   va->send_time = GNUNET_TIME_absolute_get();
4463   va->addr = (const void*) &va[1];
4464   memcpy (&va[1], addr, addrlen);
4465   va->addrlen = addrlen;
4466   GNUNET_HELLO_get_key (chvc->hello,
4467                         &va->publicKey);
4468   va->timeout_task = GNUNET_SCHEDULER_add_delayed (HELLO_VERIFICATION_TIMEOUT,
4469                                                    &timeout_hello_validation,
4470                                                    va);
4471   GNUNET_CONTAINER_multihashmap_put (validation_map,
4472                                      &id.hashPubKey,
4473                                      va,
4474                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
4475   setup_peer_check_blacklist (&id, GNUNET_NO,
4476                               &transmit_hello_and_ping,
4477                               va);
4478   return GNUNET_OK;
4479 }
4480
4481
4482 /**
4483  * Check if addresses in validated hello "h" overlap with
4484  * those in "chvc->hello" and validate the rest.
4485  *
4486  * @param cls closure
4487  * @param peer id of the peer, NULL for last call
4488  * @param h hello message for the peer (can be NULL)
4489  * @param err_msg NULL if successful, otherwise contains error message
4490  */
4491 static void
4492 check_hello_validated (void *cls,
4493                        const struct GNUNET_PeerIdentity *peer,
4494                        const struct GNUNET_HELLO_Message *h,
4495                        const char *err_msg)
4496 {
4497   struct CheckHelloValidatedContext *chvc = cls;
4498   struct GNUNET_HELLO_Message *plain_hello;
4499   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
4500   struct GNUNET_PeerIdentity target;
4501   struct NeighbourList *n;
4502
4503   if (err_msg != NULL)
4504   {
4505     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4506                 _("Error in communication with PEERINFO service\n"));
4507    /* return; */
4508   }
4509
4510   if (peer == NULL)
4511     {
4512       GNUNET_STATISTICS_update (stats,
4513                                 gettext_noop ("# outstanding peerinfo iterate requests"),
4514                                 -1,
4515                                 GNUNET_NO);
4516       chvc->piter = NULL;
4517       if (GNUNET_NO == chvc->hello_known)
4518         {
4519           /* notify PEERINFO about the peer now, so that we at least
4520              have the public key if some other component needs it */
4521           GNUNET_HELLO_get_key (chvc->hello, &pk);
4522           GNUNET_CRYPTO_hash (&pk,
4523                               sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4524                               &target.hashPubKey);
4525           plain_hello = GNUNET_HELLO_create (&pk,
4526                                              NULL,
4527                                              NULL);
4528           GNUNET_PEERINFO_add_peer (peerinfo, plain_hello);
4529           GNUNET_free (plain_hello);
4530 #if DEBUG_TRANSPORT_HELLO
4531           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4532                       "PEERINFO had no `%s' message for peer `%4s', full validation needed.\n",
4533                       "HELLO",
4534                       GNUNET_i2s (&target));
4535 #endif
4536           GNUNET_STATISTICS_update (stats,
4537                                     gettext_noop ("# new HELLOs requiring full validation"),
4538                                     1,
4539                                     GNUNET_NO);
4540           GNUNET_HELLO_iterate_addresses (chvc->hello,
4541                                           GNUNET_NO,
4542                                           &run_validation,
4543                                           chvc);
4544         }
4545       else
4546         {
4547           GNUNET_STATISTICS_update (stats,
4548                                     gettext_noop ("# duplicate HELLO (peer known)"),
4549                                     1,
4550                                     GNUNET_NO);
4551         }
4552       chvc->ve_count--;
4553       if (chvc->ve_count == 0)
4554         {
4555           GNUNET_CONTAINER_DLL_remove (chvc_head,
4556                                        chvc_tail,
4557                                        chvc);
4558           GNUNET_free (chvc);
4559         }
4560       return;
4561     }
4562   if (h == NULL)
4563     return;
4564 #if DEBUG_TRANSPORT_HELLO
4565   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4566               "PEERINFO had `%s' message for peer `%4s', validating only new addresses.\n",
4567               "HELLO",
4568               GNUNET_i2s (peer));
4569 #endif
4570   chvc->hello_known = GNUNET_YES;
4571   n = find_neighbour (peer);
4572   if (n != NULL)
4573     {
4574 #if DEBUG_TRANSPORT_HELLO
4575       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4576                   "Calling hello_iterate_addresses for %s!\n",
4577                   GNUNET_i2s (peer));
4578 #endif
4579       GNUNET_HELLO_iterate_addresses (h,
4580                                       GNUNET_NO,
4581                                       &add_to_foreign_address_list,
4582                                       n);
4583       try_transmission_to_peer (n);
4584     }
4585   else
4586     {
4587 #if DEBUG_TRANSPORT_HELLO
4588       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4589                   "No existing neighbor record for %s!\n",
4590                   GNUNET_i2s (peer));
4591 #endif
4592       GNUNET_STATISTICS_update (stats,
4593                                 gettext_noop ("# no existing neighbour record (validating HELLO)"),
4594                                 1,
4595                                 GNUNET_NO);
4596     }
4597   GNUNET_STATISTICS_update (stats,
4598                             gettext_noop ("# HELLO validations (update case)"),
4599                             1,
4600                             GNUNET_NO);
4601   GNUNET_HELLO_iterate_new_addresses (chvc->hello,
4602                                       h,
4603                                       GNUNET_TIME_relative_to_absolute (HELLO_REVALIDATION_START_TIME),
4604                                       &run_validation,
4605                                       chvc);
4606 }
4607
4608
4609 /**
4610  * Process HELLO-message.
4611  *
4612  * @param plugin transport involved, may be NULL
4613  * @param message the actual message
4614  * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
4615  */
4616 static int
4617 process_hello (struct TransportPlugin *plugin,
4618                const struct GNUNET_MessageHeader *message)
4619 {
4620   uint16_t hsize;
4621   struct GNUNET_PeerIdentity target;
4622   const struct GNUNET_HELLO_Message *hello;
4623   struct CheckHelloValidatedContext *chvc;
4624   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
4625 #if DEBUG_TRANSPORT_HELLO > 2
4626   char *my_id;
4627 #endif
4628   hsize = ntohs (message->size);
4629   if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
4630       (hsize < sizeof (struct GNUNET_MessageHeader)))
4631     {
4632       GNUNET_break (0);
4633       return GNUNET_SYSERR;
4634     }
4635   GNUNET_STATISTICS_update (stats,
4636                             gettext_noop ("# HELLOs received for validation"),
4637                             1,
4638                             GNUNET_NO);
4639
4640   /* first, check if load is too high */
4641   if (GNUNET_SCHEDULER_get_load (GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
4642     {
4643       GNUNET_STATISTICS_update (stats,
4644                                 gettext_noop ("# HELLOs ignored due to high load"),
4645                                 1,
4646                                 GNUNET_NO);
4647 #if DEBUG_TRANSPORT_HELLO
4648       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4649                   "Ignoring `%s' for `%4s', load too high.\n",
4650                   "HELLO",
4651                   GNUNET_i2s (&target));
4652 #endif
4653       return GNUNET_OK;
4654     }
4655   hello = (const struct GNUNET_HELLO_Message *) message;
4656   if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
4657     {
4658 #if DEBUG_TRANSPORT_HELLO
4659       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4660                   "Unable to get public key from `%s' for `%4s'!\n",
4661                   "HELLO",
4662                   GNUNET_i2s (&target));
4663 #endif
4664       GNUNET_break_op (0);
4665       return GNUNET_SYSERR;
4666     }
4667
4668   GNUNET_CRYPTO_hash (&publicKey,
4669                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
4670                       &target.hashPubKey);
4671
4672 #if DEBUG_TRANSPORT_HELLO
4673   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4674               "Received `%s' message for `%4s'\n",
4675               "HELLO",
4676               GNUNET_i2s (&target));
4677 #endif
4678
4679   if (0 == memcmp (&my_identity,
4680                    &target,
4681                    sizeof (struct GNUNET_PeerIdentity)))
4682     {
4683       GNUNET_STATISTICS_update (stats,
4684                                 gettext_noop ("# HELLOs ignored for validation (is my own HELLO)"),
4685                                 1,
4686                                 GNUNET_NO);
4687       return GNUNET_OK;
4688     }
4689   chvc = chvc_head;
4690   while (NULL != chvc)
4691     {
4692       if (GNUNET_HELLO_equals (hello,
4693                                chvc->hello,
4694                                GNUNET_TIME_absolute_get ()).abs_value > 0)
4695         {
4696 #if DEBUG_TRANSPORT_HELLO > 2
4697           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4698                       "Received duplicate `%s' message for `%4s'; ignored\n",
4699                       "HELLO",
4700                       GNUNET_i2s (&target));
4701 #endif
4702           return GNUNET_OK; /* validation already pending */
4703         }
4704       if (GNUNET_HELLO_size(hello) == GNUNET_HELLO_size (chvc->hello))
4705         GNUNET_break (0 != memcmp (hello, chvc->hello,
4706                                    GNUNET_HELLO_size(hello)));
4707       chvc = chvc->next;
4708     }
4709
4710 #if BREAK_TESTS
4711   struct NeighbourList *temp_neighbor = find_neighbour(&target);
4712   if ((NULL != temp_neighbor))
4713     {
4714       fprintf(stderr, "Already know peer, ignoring hello\n");
4715       return GNUNET_OK;
4716     }
4717 #endif
4718
4719 #if DEBUG_TRANSPORT_HELLO > 2
4720   if (plugin != NULL)
4721     {
4722       my_id = GNUNET_strdup(GNUNET_i2s(plugin->env.my_identity));
4723       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4724                   "%s: Starting validation of `%s' message for `%4s' via '%s' of size %u\n",
4725                   my_id,
4726                   "HELLO",
4727                   GNUNET_i2s (&target),
4728                   plugin->short_name,
4729                   GNUNET_HELLO_size(hello));
4730       GNUNET_free(my_id);
4731     }
4732 #endif
4733   chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
4734   chvc->ve_count = 1;
4735   chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
4736   memcpy (&chvc[1], hello, hsize);
4737   GNUNET_CONTAINER_DLL_insert (chvc_head,
4738                                chvc_tail,
4739                                chvc);
4740   /* finally, check if HELLO was previously validated
4741      (continuation will then schedule actual validation) */
4742   GNUNET_STATISTICS_update (stats,
4743                             gettext_noop ("# peerinfo process hello iterate requests"),
4744                             1,
4745                             GNUNET_NO);
4746   GNUNET_STATISTICS_update (stats,
4747                             gettext_noop ("# outstanding peerinfo iterate requests"),
4748                             1,
4749                             GNUNET_NO);
4750   chvc->piter = GNUNET_PEERINFO_iterate (peerinfo,
4751                                          &target,
4752                                          HELLO_VERIFICATION_TIMEOUT,
4753                                          &check_hello_validated, chvc);
4754   return GNUNET_OK;
4755 }
4756
4757
4758 /**
4759  * The peer specified by the given neighbour has timed-out or a plugin
4760  * has disconnected.  We may either need to do nothing (other plugins
4761  * still up), or trigger a full disconnect and clean up.  This
4762  * function updates our state and does the necessary notifications.
4763  * Also notifies our clients that the neighbour is now officially
4764  * gone.
4765  *
4766  * @param n the neighbour list entry for the peer
4767  * @param check GNUNET_YES to check if ALL addresses for this peer
4768  *              are gone, GNUNET_NO to force a disconnect of the peer
4769  *              regardless of whether other addresses exist.
4770  */
4771 static void
4772 disconnect_neighbour (struct NeighbourList *n, int check)
4773 {
4774   struct ReadyList *rpos;
4775   struct NeighbourList *npos;
4776   struct NeighbourList *nprev;
4777   struct MessageQueue *mq;
4778   struct ForeignAddressList *peer_addresses;
4779   struct ForeignAddressList *peer_pos;
4780
4781   if (GNUNET_YES == check)
4782     {
4783       rpos = n->plugins;
4784       while (NULL != rpos)
4785         {
4786           peer_addresses = rpos->addresses;
4787           while (peer_addresses != NULL)
4788             {
4789               if (GNUNET_YES == peer_addresses->connected)
4790                 {
4791                   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4792                             "NOT Disconnecting from `%4s', still have live addresses!\n",
4793                             GNUNET_i2s (&n->id));
4794                   return;             /* still connected */
4795                 }
4796               peer_addresses = peer_addresses->next;
4797             }
4798           rpos = rpos->next;
4799         }
4800     }
4801 #if DEBUG_TRANSPORT
4802   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4803               "Disconnecting from `%4s'\n",
4804               GNUNET_i2s (&n->id));
4805 #endif
4806   /* remove n from neighbours list */
4807   nprev = NULL;
4808   npos = neighbours;
4809   while ((npos != NULL) && (npos != n))
4810     {
4811       nprev = npos;
4812       npos = npos->next;
4813     }
4814   GNUNET_assert (npos != NULL);
4815   if (nprev == NULL)
4816     neighbours = n->next;
4817   else
4818     nprev->next = n->next;
4819
4820   /* notify all clients about disconnect */
4821   if (GNUNET_YES == n->received_pong)
4822     notify_clients_disconnect (&n->id);
4823
4824   /* clean up all plugins, cancel connections and pending transmissions */
4825   while (NULL != (rpos = n->plugins))
4826     {
4827       n->plugins = rpos->next;
4828       rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
4829       while (rpos->addresses != NULL)
4830         {
4831           peer_pos = rpos->addresses;
4832           rpos->addresses = peer_pos->next;
4833           if (peer_pos->connected == GNUNET_YES)
4834             GNUNET_STATISTICS_update (stats,
4835                                       gettext_noop ("# connected addresses"),
4836                                       -1,
4837                                       GNUNET_NO);
4838           if (GNUNET_YES == peer_pos->validated)
4839             GNUNET_STATISTICS_update (stats,
4840                                       gettext_noop ("# peer addresses considered valid"),
4841                                       -1,
4842                                       GNUNET_NO);
4843           if (GNUNET_SCHEDULER_NO_TASK != peer_pos->revalidate_task)
4844             {
4845               GNUNET_SCHEDULER_cancel (peer_pos->revalidate_task);
4846               peer_pos->revalidate_task = GNUNET_SCHEDULER_NO_TASK;
4847             }
4848                   GNUNET_free(peer_pos->ressources);
4849                   peer_pos->ressources = NULL;
4850                   GNUNET_free(peer_pos->quality);
4851                   peer_pos->ressources = NULL;
4852                   GNUNET_free(peer_pos);
4853         }
4854       GNUNET_free (rpos);
4855     }
4856
4857   /* free all messages on the queue */
4858   while (NULL != (mq = n->messages_head))
4859     {
4860       GNUNET_STATISTICS_update (stats,
4861                                 gettext_noop ("# bytes in message queue for other peers"),
4862                                 - (int64_t) mq->message_buf_size,
4863                                 GNUNET_NO);
4864       GNUNET_STATISTICS_update (stats,
4865                                 gettext_noop ("# bytes discarded due to disconnect"),
4866                                 mq->message_buf_size,
4867                                 GNUNET_NO);
4868       GNUNET_CONTAINER_DLL_remove (n->messages_head,
4869                                    n->messages_tail,
4870                                    mq);
4871       GNUNET_assert (0 == memcmp(&mq->neighbour_id,
4872                                  &n->id,
4873                                  sizeof(struct GNUNET_PeerIdentity)));
4874       GNUNET_free (mq);
4875     }
4876   if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
4877     {
4878       GNUNET_SCHEDULER_cancel (n->timeout_task);
4879       n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
4880     }
4881   if (n->retry_task != GNUNET_SCHEDULER_NO_TASK)
4882     {
4883       GNUNET_SCHEDULER_cancel (n->retry_task);
4884       n->retry_task = GNUNET_SCHEDULER_NO_TASK;
4885     }
4886   if (n->piter != NULL)
4887     {
4888       GNUNET_PEERINFO_iterate_cancel (n->piter);
4889       GNUNET_STATISTICS_update (stats,
4890                                 gettext_noop ("# outstanding peerinfo iterate requests"),
4891                                 -1,
4892                                 GNUNET_NO);
4893       n->piter = NULL;
4894     }
4895   /* finally, free n itself */
4896   GNUNET_STATISTICS_update (stats,
4897                             gettext_noop ("# active neighbours"),
4898                             -1,
4899                             GNUNET_NO);
4900   GNUNET_free_non_null (n->pre_connect_message_buffer);
4901   GNUNET_free (n);
4902 }
4903
4904
4905 /**
4906  * We have received a PING message from someone.  Need to send a PONG message
4907  * in response to the peer by any means necessary.
4908  */
4909 static int
4910 handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
4911             const struct GNUNET_PeerIdentity *peer,
4912             struct Session *session,
4913             const char *sender_address,
4914             uint16_t sender_address_len)
4915 {
4916   struct TransportPlugin *plugin = cls;
4917   struct SessionHeader *session_header = (struct SessionHeader*) session;
4918   struct TransportPingMessage *ping;
4919   struct TransportPongMessage *pong;
4920   struct NeighbourList *n;
4921   struct ReadyList *rl;
4922   struct ForeignAddressList *fal;
4923   struct OwnAddressList *oal;
4924   const char *addr;
4925   size_t alen;
4926   size_t slen;
4927
4928   if (ntohs (message->size) < sizeof (struct TransportPingMessage))
4929     {
4930       GNUNET_break_op (0);
4931       return GNUNET_SYSERR;
4932     }
4933
4934   ping = (struct TransportPingMessage *) message;
4935   if (0 != memcmp (&ping->target,
4936                    plugin->env.my_identity,
4937                    sizeof (struct GNUNET_PeerIdentity)))
4938     {
4939       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4940                   _("Received `%s' message from `%s' destined for `%s' which is not me!\n"),
4941                   "PING",
4942                   (sender_address != NULL)
4943                   ? a2s (plugin->short_name,
4944                          (const struct sockaddr *)sender_address,
4945                          sender_address_len)
4946                   : "<inbound>",
4947                   GNUNET_i2s (&ping->target));
4948       return GNUNET_SYSERR;
4949     }
4950 #if DEBUG_PING_PONG
4951   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
4952               "Processing `%s' from `%s'\n",
4953               "PING",
4954               (sender_address != NULL)
4955               ? a2s (plugin->short_name,
4956                      (const struct sockaddr *)sender_address,
4957                      sender_address_len)
4958               : "<inbound>");
4959 #endif
4960   GNUNET_STATISTICS_update (stats,
4961                             gettext_noop ("# PING messages received"),
4962                             1,
4963                             GNUNET_NO);
4964   addr = (const char*) &ping[1];
4965   alen = ntohs (message->size) - sizeof (struct TransportPingMessage);
4966   slen = strlen (plugin->short_name) + 1;
4967   if (alen == 0)
4968     {
4969       /* peer wants to confirm that we have an outbound connection to him */
4970       if (session == NULL)
4971         {
4972           GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4973                       _("Refusing to create PONG since I do not have a session with `%s'.\n"),
4974                       GNUNET_i2s (peer));
4975           return GNUNET_SYSERR;
4976         }
4977       pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len + slen);
4978       pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len + slen);
4979       pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
4980       pong->purpose.size =
4981         htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
4982                sizeof (uint32_t) +
4983                sizeof (struct GNUNET_TIME_AbsoluteNBO) +
4984                sizeof (struct GNUNET_PeerIdentity) + sender_address_len + slen);
4985       pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_USING);
4986       pong->challenge = ping->challenge;
4987       pong->addrlen = htonl(sender_address_len + slen);
4988       memcpy(&pong->pid,
4989              peer,
4990              sizeof(struct GNUNET_PeerIdentity));
4991       memcpy (&pong[1],
4992               plugin->short_name,
4993               slen);
4994       if ((sender_address!=NULL) && (sender_address_len > 0))
4995                   memcpy (&((char*)&pong[1])[slen],
4996                           sender_address,
4997                           sender_address_len);
4998       if (GNUNET_TIME_absolute_get_remaining (session_header->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4)
4999         {
5000           /* create / update cached sig */
5001 #if DEBUG_TRANSPORT
5002           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5003                       "Creating PONG signature to indicate active connection.\n");
5004 #endif
5005           session_header->pong_sig_expires = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
5006           pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
5007           GNUNET_assert (GNUNET_OK ==
5008                          GNUNET_CRYPTO_rsa_sign (my_private_key,
5009                                                  &pong->purpose,
5010                                                  &session_header->pong_signature));
5011         }
5012       else
5013         {
5014           pong->expiration = GNUNET_TIME_absolute_hton (session_header->pong_sig_expires);
5015         }
5016       memcpy (&pong->signature,
5017               &session_header->pong_signature,
5018               sizeof (struct GNUNET_CRYPTO_RsaSignature));
5019
5020
5021     }
5022   else
5023     {
5024       /* peer wants to confirm that this is one of our addresses */
5025       addr += slen;
5026       alen -= slen;
5027       if (GNUNET_OK !=
5028           plugin->api->check_address (plugin->api->cls,
5029                                       addr,
5030                                       alen))
5031         {
5032           GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5033                       _("Not confirming PING with address `%s' since I cannot confirm having this address.\n"),
5034                       a2s (plugin->short_name,
5035                            addr,
5036                            alen));
5037           return GNUNET_NO;
5038         }
5039       oal = plugin->addresses;
5040       while (NULL != oal)
5041         {
5042           if ( (oal->addrlen == alen) &&
5043                (0 == memcmp (addr,
5044                              &oal[1],
5045                              alen)) )
5046             break;
5047           oal = oal->next;
5048         }
5049       pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + alen + slen);
5050       pong->header.size = htons (sizeof (struct TransportPongMessage) + alen + slen);
5051       pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
5052       pong->purpose.size =
5053         htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
5054                sizeof (uint32_t) +
5055                sizeof (struct GNUNET_TIME_AbsoluteNBO) +
5056                sizeof (struct GNUNET_PeerIdentity) + alen + slen);
5057       pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN);
5058       pong->challenge = ping->challenge;
5059       pong->addrlen = htonl(alen + slen);
5060       memcpy(&pong->pid,
5061              &my_identity,
5062              sizeof(struct GNUNET_PeerIdentity));
5063       memcpy (&pong[1], plugin->short_name, slen);
5064       memcpy (&((char*)&pong[1])[slen], addr, alen);
5065       if ( (oal != NULL) &&
5066            (GNUNET_TIME_absolute_get_remaining (oal->pong_sig_expires).rel_value < PONG_SIGNATURE_LIFETIME.rel_value / 4) )
5067         {
5068           /* create / update cached sig */
5069 #if DEBUG_TRANSPORT
5070           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5071                       "Creating PONG signature to indicate ownership.\n");
5072 #endif
5073           oal->pong_sig_expires = GNUNET_TIME_absolute_min (oal->expires,
5074                                                             GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
5075           pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
5076           GNUNET_assert (GNUNET_OK ==
5077                          GNUNET_CRYPTO_rsa_sign (my_private_key,
5078                                                  &pong->purpose,
5079                                                  &oal->pong_signature));
5080           memcpy (&pong->signature,
5081                   &oal->pong_signature,
5082                   sizeof (struct GNUNET_CRYPTO_RsaSignature));
5083         }
5084       else if (oal == NULL)
5085         {
5086           /* not using cache (typically DV-only) */
5087           pong->expiration = GNUNET_TIME_absolute_hton (GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME));
5088           GNUNET_assert (GNUNET_OK ==
5089                          GNUNET_CRYPTO_rsa_sign (my_private_key,
5090                                                  &pong->purpose,
5091                                                  &pong->signature));
5092         }
5093       else
5094         {
5095           /* can used cached version */
5096           pong->expiration = GNUNET_TIME_absolute_hton (oal->pong_sig_expires);
5097           memcpy (&pong->signature,
5098                   &oal->pong_signature,
5099                   sizeof (struct GNUNET_CRYPTO_RsaSignature));
5100         }
5101     }
5102   n = find_neighbour(peer);
5103   GNUNET_assert (n != NULL);
5104   /* first try reliable response transmission */
5105   rl = n->plugins;
5106   while (rl != NULL)
5107     {
5108       fal = rl->addresses;
5109       while (fal != NULL)
5110         {
5111           if (-1 != rl->plugin->api->send (rl->plugin->api->cls,
5112                                            peer,
5113                                            (const char*) pong,
5114                                            ntohs (pong->header.size),
5115                                            TRANSPORT_PONG_PRIORITY,
5116                                            HELLO_VERIFICATION_TIMEOUT,
5117                                            fal->session,
5118                                            fal->addr,
5119                                            fal->addrlen,
5120                                            GNUNET_SYSERR,
5121                                            NULL, NULL))
5122             {
5123               /* done! */
5124               GNUNET_STATISTICS_update (stats,
5125                                         gettext_noop ("# PONGs unicast via reliable transport"),
5126                                         1,
5127                                         GNUNET_NO);
5128               GNUNET_free (pong);
5129               return GNUNET_OK;
5130             }
5131           fal = fal->next;
5132         }
5133       rl = rl->next;
5134     }
5135   /* no reliable method found, do multicast */
5136   GNUNET_STATISTICS_update (stats,
5137                             gettext_noop ("# PONGs multicast to all available addresses"),
5138                             1,
5139                             GNUNET_NO);
5140   rl = n->plugins;
5141   while (rl != NULL)
5142     {
5143       fal = rl->addresses;
5144       while (fal != NULL)
5145         {
5146           transmit_to_peer(NULL, fal,
5147                            TRANSPORT_PONG_PRIORITY,
5148                            HELLO_VERIFICATION_TIMEOUT,
5149                            (const char *)pong,
5150                            ntohs(pong->header.size),
5151                            GNUNET_YES,
5152                            n);
5153           fal = fal->next;
5154         }
5155       rl = rl->next;
5156     }
5157   GNUNET_free(pong);
5158   return GNUNET_OK;
5159 }
5160
5161
5162
5163
5164
5165 /**
5166  * Function called by the plugin for each received message.
5167  * Update data volumes, possibly notify plugins about
5168  * reducing the rate at which they read from the socket
5169  * and generally forward to our receive callback.
5170  *
5171  * @param cls the "struct TransportPlugin *" we gave to the plugin
5172  * @param peer (claimed) identity of the other peer
5173  * @param message the message, NULL if we only care about
5174  *                learning about the delay until we should receive again
5175  * @param ats_data information for automatic transport selection
5176  * @param ats_count number of elements in ats not including 0-terminator
5177  * @param session identifier used for this session (can be NULL)
5178  * @param sender_address binary address of the sender (if observed)
5179  * @param sender_address_len number of bytes in sender_address
5180  * @return how long in ms the plugin should wait until receiving more data
5181  *         (plugins that do not support this, can ignore the return value)
5182  */
5183 static struct GNUNET_TIME_Relative
5184 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
5185                     const struct GNUNET_MessageHeader *message,
5186                     const struct GNUNET_TRANSPORT_ATS_Information *ats_data,
5187                     uint32_t ats_count,
5188                     struct Session *session,
5189                     const char *sender_address,
5190                     uint16_t sender_address_len)
5191 {
5192   struct TransportPlugin *plugin = cls;
5193   struct ReadyList *service_context;
5194   struct ForeignAddressList *peer_address;
5195   uint16_t msize;
5196   struct NeighbourList *n;
5197   struct GNUNET_TIME_Relative ret;
5198   if (is_blacklisted (peer, plugin))
5199     return GNUNET_TIME_UNIT_FOREVER_REL;
5200   uint32_t distance;
5201   int c;
5202
5203   n = find_neighbour (peer);
5204   if (n == NULL)
5205     n = setup_new_neighbour (peer, GNUNET_YES);
5206   service_context = n->plugins;
5207   while ((service_context != NULL) && (plugin != service_context->plugin))
5208     service_context = service_context->next;
5209   GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
5210   peer_address = NULL;
5211   distance = 1;
5212
5213   for (c=0; c<ats_count; c++)
5214   {
5215           if (ntohl(ats_data[c].type) == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
5216           {
5217                   distance = ntohl(ats_data[c].value);
5218           }
5219   }
5220
5221   /* notify ATS about incoming data */
5222   //ats_notify_ats_data(peer, ats_data);
5223
5224
5225   if (message != NULL)
5226     {
5227       if ( (session != NULL) ||
5228            (sender_address != NULL) )
5229         peer_address = add_peer_address (n,
5230                                          plugin->short_name,
5231                                          session,
5232                                          sender_address,
5233                                          sender_address_len);
5234       if (peer_address != NULL)
5235         {
5236
5237       update_addr_ats(peer_address, ats_data, ats_count);
5238       update_addr_value(peer_address, distance, GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5239
5240       peer_address->distance = distance;
5241           if (GNUNET_YES == peer_address->validated)
5242             mark_address_connected (peer_address);
5243           peer_address->timeout
5244             =
5245             GNUNET_TIME_relative_to_absolute
5246             (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5247           schedule_next_ping (peer_address);
5248         }
5249       /* update traffic received amount ... */
5250       msize = ntohs (message->size);
5251
5252       GNUNET_STATISTICS_update (stats,
5253                                 gettext_noop ("# bytes received from other peers"),
5254                                 msize,
5255                                 GNUNET_NO);
5256       n->distance = distance;
5257       n->peer_timeout =
5258         GNUNET_TIME_relative_to_absolute
5259         (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
5260       GNUNET_SCHEDULER_cancel (n->timeout_task);
5261       n->timeout_task =
5262         GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
5263                                       &neighbour_timeout_task, n);
5264       if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
5265         {
5266           /* dropping message due to frequent inbound volume violations! */
5267           GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
5268                       GNUNET_ERROR_TYPE_BULK,
5269                       _
5270                       ("Dropping incoming message due to repeated bandwidth quota (%u b/s) violations (total of %u).\n"),
5271                       n->in_tracker.available_bytes_per_s__,
5272                       n->quota_violation_count);
5273           GNUNET_STATISTICS_update (stats,
5274                                     gettext_noop ("# bandwidth quota violations by other peers"),
5275                                     1,
5276                                     GNUNET_NO);
5277           return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
5278         }
5279     if ((ntohs(message->type) == GNUNET_MESSAGE_TYPE_TRANSPORT_ATS) &&
5280         (ntohs(message->size) == (sizeof (struct GNUNET_MessageHeader) + sizeof (uint32_t))))
5281     {
5282         uint32_t value =  ntohl(*((uint32_t *) &message[1]));
5283         //GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "GNUNET_MESSAGE_TYPE_TRANSPORT_ATS: %i \n", value);
5284         /* Force ressource and quality update */
5285         if (value == 4)
5286         {
5287                 ats->modified_resources = GNUNET_YES;
5288                 ats->modified_quality = GNUNET_YES;
5289         }
5290         /* Force cost update */
5291         if (value == 3)
5292                 ats->modified_resources = GNUNET_YES;
5293         /* Force quality update */
5294         if (value == 2)
5295                 ats->modified_quality = GNUNET_YES;
5296         /* Force full rebuild */
5297         if (value == 1)
5298                 ats->modified_addr = GNUNET_YES;
5299     }
5300
5301 #if DEBUG_PING_PONG
5302           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5303                       "Received message of type %u and size %u from `%4s', sending to all clients.\n",
5304                       ntohs (message->type),
5305                       ntohs (message->size),
5306                       GNUNET_i2s (peer));
5307 #endif
5308       switch (ntohs (message->type))
5309         {
5310         case GNUNET_MESSAGE_TYPE_HELLO:
5311           GNUNET_STATISTICS_update (stats,
5312                                     gettext_noop ("# HELLO messages received from other peers"),
5313                                     1,
5314                                     GNUNET_NO);
5315           process_hello (plugin, message);
5316           break;
5317         case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
5318           handle_ping (plugin, message, peer, session, sender_address, sender_address_len);
5319           break;
5320         case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
5321           handle_pong (plugin, message, peer, sender_address, sender_address_len);
5322           break;
5323         case GNUNET_MESSAGE_TYPE_TRANSPORT_ATS:
5324           break;
5325         default:
5326           handle_payload_message (message, n);
5327           break;
5328         }
5329     }
5330   ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 0);
5331   if (ret.rel_value > 0)
5332     {
5333       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5334                   "Throttling read (%llu bytes excess at %u b/s), waiting %llums before reading more.\n",
5335                   (unsigned long long) n->in_tracker.consumption_since_last_update__,
5336                   (unsigned int) n->in_tracker.available_bytes_per_s__,
5337                   (unsigned long long) ret.rel_value);
5338       GNUNET_STATISTICS_update (stats,
5339                                 gettext_noop ("# ms throttling suggested"),
5340                                 (int64_t) ret.rel_value,
5341                                 GNUNET_NO);
5342     }
5343   return ret;
5344 }
5345
5346 /**
5347  * Handle START-message.  This is the first message sent to us
5348  * by any client which causes us to add it to our list.
5349  *
5350  * @param cls closure (always NULL)
5351  * @param client identification of the client
5352  * @param message the actual message
5353  */
5354 static void
5355 handle_start (void *cls,
5356               struct GNUNET_SERVER_Client *client,
5357               const struct GNUNET_MessageHeader *message)
5358 {
5359   const struct StartMessage *start;
5360   struct TransportClient *c;
5361   struct ConnectInfoMessage * cim;
5362   struct NeighbourList *n;
5363   uint32_t ats_count;
5364   size_t size;
5365
5366   start = (const struct StartMessage*) message;
5367 #if DEBUG_TRANSPORT
5368   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5369               "Received `%s' request from client\n", "START");
5370 #endif
5371   c = clients;
5372   while (c != NULL)
5373     {
5374       if (c->client == client)
5375         {
5376           /* client already on our list! */
5377           GNUNET_break (0);
5378           GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5379           return;
5380         }
5381       c = c->next;
5382     }
5383   if ( (GNUNET_NO != ntohl (start->do_check)) &&
5384        (0 != memcmp (&start->self,
5385                      &my_identity,
5386                      sizeof (struct GNUNET_PeerIdentity))) )
5387     {
5388       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5389                   _("Rejecting control connection from peer `%s', which is not me!\n"),
5390                   GNUNET_i2s (&start->self));
5391       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5392       return;
5393     }
5394   c = GNUNET_malloc (sizeof (struct TransportClient));
5395   c->next = clients;
5396   clients = c;
5397   c->client = client;
5398   if (our_hello != NULL)
5399   {
5400 #if DEBUG_TRANSPORT
5401       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5402                   "Sending our own `%s' to new client\n", "HELLO");
5403 #endif
5404       transmit_to_client (c,
5405                           (const struct GNUNET_MessageHeader *) our_hello,
5406                           GNUNET_NO);
5407       /* tell new client about all existing connections */
5408       ats_count = 2;
5409       size  = sizeof (struct ConnectInfoMessage) + ats_count * sizeof (struct GNUNET_TRANSPORT_ATS_Information);
5410       if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE)
5411       {
5412           GNUNET_break(0);
5413       }
5414       cim = GNUNET_malloc (size);
5415       cim->header.size = htons (size);
5416       cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
5417       cim->ats_count = htonl(ats_count);
5418       (&(cim->ats))[2].type = htonl (GNUNET_TRANSPORT_ATS_ARRAY_TERMINATOR);
5419       (&(cim->ats))[2].value = htonl (0);
5420       n = neighbours;
5421       while (n != NULL)
5422           {
5423                   if (GNUNET_YES == n->received_pong)
5424                   {
5425                           (&(cim->ats))[0].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE);
5426                           (&(cim->ats))[0].value = htonl (n->distance);
5427                           (&(cim->ats))[1].type = htonl (GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY);
5428                           (&(cim->ats))[1].value = htonl ((uint32_t) n->latency.rel_value);
5429                           cim->id = n->id;
5430                           transmit_to_client (c, &cim->header, GNUNET_NO);
5431                   }
5432             n = n->next;
5433       }
5434       GNUNET_free (cim);
5435   }
5436   GNUNET_SERVER_receive_done (client, GNUNET_OK);
5437 }
5438
5439
5440 /**
5441  * Handle HELLO-message.
5442  *
5443  * @param cls closure (always NULL)
5444  * @param client identification of the client
5445  * @param message the actual message
5446  */
5447 static void
5448 handle_hello (void *cls,
5449               struct GNUNET_SERVER_Client *client,
5450               const struct GNUNET_MessageHeader *message)
5451 {
5452   int ret;
5453
5454   GNUNET_STATISTICS_update (stats,
5455                             gettext_noop ("# HELLOs received from clients"),
5456                             1,
5457                             GNUNET_NO);
5458   ret = process_hello (NULL, message);
5459   GNUNET_SERVER_receive_done (client, ret);
5460 }
5461
5462
5463 /**
5464  * Closure for 'transmit_client_message'; followed by
5465  * 'msize' bytes of the actual message.
5466  */
5467 struct TransmitClientMessageContext
5468 {
5469   /**
5470    * Client on whom's behalf we are sending.
5471    */
5472   struct GNUNET_SERVER_Client *client;
5473
5474   /**
5475    * Timeout for the transmission.
5476    */
5477   struct GNUNET_TIME_Absolute timeout;
5478
5479   /**
5480    * Message priority.
5481    */
5482   uint32_t priority;
5483
5484   /**
5485    * Size of the message in bytes.
5486    */
5487   uint16_t msize;
5488 };
5489
5490
5491 /**
5492  * Schedule transmission of a message we got from a client to a peer.
5493  *
5494  * @param cls the 'struct TransmitClientMessageContext*'
5495  * @param n destination, or NULL on error (in that case, drop the message)
5496  */
5497 static void
5498 transmit_client_message (void *cls,
5499                          struct NeighbourList *n)
5500 {
5501   struct TransmitClientMessageContext *tcmc = cls;
5502   struct TransportClient *tc;
5503
5504   tc = clients;
5505   while ((tc != NULL) && (tc->client != tcmc->client))
5506     tc = tc->next;
5507
5508   if (n != NULL)
5509     {
5510       transmit_to_peer (tc, NULL, tcmc->priority,
5511                         GNUNET_TIME_absolute_get_remaining (tcmc->timeout),
5512                         (char *)&tcmc[1],
5513                         tcmc->msize, GNUNET_NO, n);
5514     }
5515   GNUNET_SERVER_receive_done (tcmc->client, GNUNET_OK);
5516   GNUNET_SERVER_client_drop (tcmc->client);
5517   GNUNET_free (tcmc);
5518 }
5519
5520
5521 /**
5522  * Handle SEND-message.
5523  *
5524  * @param cls closure (always NULL)
5525  * @param client identification of the client
5526  * @param message the actual message
5527  */
5528 static void
5529 handle_send (void *cls,
5530              struct GNUNET_SERVER_Client *client,
5531              const struct GNUNET_MessageHeader *message)
5532 {
5533   const struct OutboundMessage *obm;
5534   const struct GNUNET_MessageHeader *obmm;
5535   struct TransmitClientMessageContext *tcmc;
5536   uint16_t size;
5537   uint16_t msize;
5538
5539   size = ntohs (message->size);
5540   if (size <
5541       sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
5542     {
5543       GNUNET_break (0);
5544       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5545       return;
5546     }
5547   GNUNET_STATISTICS_update (stats,
5548                             gettext_noop ("# payload received for other peers"),
5549                             size,
5550                             GNUNET_NO);
5551   obm = (const struct OutboundMessage *) message;
5552   obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5553   msize = size - sizeof (struct OutboundMessage);
5554
5555   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5556               "Received `%s' request from client with target `%4s' and message of type %u and size %u\n",
5557               "SEND", GNUNET_i2s (&obm->peer),
5558               ntohs (obmm->type),
5559               msize);
5560
5561   tcmc = GNUNET_malloc (sizeof (struct TransmitClientMessageContext) + msize);
5562   tcmc->client = client;
5563   tcmc->priority = ntohl (obm->priority);
5564   tcmc->timeout = GNUNET_TIME_relative_to_absolute (GNUNET_TIME_relative_ntoh (obm->timeout));
5565   tcmc->msize = msize;
5566   /* FIXME: this memcpy can be up to 7% of our total runtime */
5567   memcpy (&tcmc[1], obmm, msize);
5568   GNUNET_SERVER_client_keep (client);
5569   setup_peer_check_blacklist (&obm->peer, GNUNET_YES,
5570                               &transmit_client_message,
5571                               tcmc);
5572 }
5573
5574
5575 /**
5576  * Handle request connect message
5577  *
5578  * @param cls closure (always NULL)
5579  * @param client identification of the client
5580  * @param message the actual message
5581  */
5582 static void
5583 handle_request_connect (void *cls,
5584                         struct GNUNET_SERVER_Client *client,
5585                         const struct GNUNET_MessageHeader *message)
5586 {
5587   const struct TransportRequestConnectMessage *trcm =
5588     (const struct TransportRequestConnectMessage *) message;
5589
5590   GNUNET_STATISTICS_update (stats,
5591                             gettext_noop ("# REQUEST CONNECT messages received"),
5592                             1,
5593                             GNUNET_NO);
5594   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "Received a request connect message for peer %s\n", GNUNET_i2s(&trcm->peer));
5595   setup_peer_check_blacklist (&trcm->peer, GNUNET_YES,
5596                               NULL, NULL);
5597   GNUNET_SERVER_receive_done (client, GNUNET_OK);
5598 }
5599
5600 /**
5601  * Handle SET_QUOTA-message.
5602  *
5603  * @param cls closure (always NULL)
5604  * @param client identification of the client
5605  * @param message the actual message
5606  */
5607 static void
5608 handle_set_quota (void *cls,
5609                   struct GNUNET_SERVER_Client *client,
5610                   const struct GNUNET_MessageHeader *message)
5611 {
5612   const struct QuotaSetMessage *qsm =
5613     (const struct QuotaSetMessage *) message;
5614   struct NeighbourList *n;
5615
5616   GNUNET_STATISTICS_update (stats,
5617                             gettext_noop ("# SET QUOTA messages received"),
5618                             1,
5619                             GNUNET_NO);
5620   n = find_neighbour (&qsm->peer);
5621   if (n == NULL)
5622     {
5623       GNUNET_SERVER_receive_done (client, GNUNET_OK);
5624       GNUNET_STATISTICS_update (stats,
5625                                 gettext_noop ("# SET QUOTA messages ignored (no such peer)"),
5626                                 1,
5627                                 GNUNET_NO);
5628       return;
5629     }
5630 #if DEBUG_TRANSPORT
5631   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5632               "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
5633               "SET_QUOTA",
5634               (unsigned int) ntohl (qsm->quota.value__),
5635               (unsigned int) n->in_tracker.available_bytes_per_s__,
5636               GNUNET_i2s (&qsm->peer));
5637 #endif
5638   GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker,
5639                                          qsm->quota);
5640   if (0 == ntohl (qsm->quota.value__))
5641     {
5642       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5643                 "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&n->id),
5644                 "SET_QUOTA");
5645       disconnect_neighbour (n, GNUNET_NO);
5646     }
5647   GNUNET_SERVER_receive_done (client, GNUNET_OK);
5648 }
5649
5650
5651 /**
5652  * Take the given address and append it to the set of results sent back to
5653  * the client.
5654  *
5655  * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
5656  * @param address the resolved name, NULL to indicate the last response
5657  */
5658 static void
5659 transmit_address_to_client (void *cls, const char *address)
5660 {
5661   struct GNUNET_SERVER_TransmitContext *tc = cls;
5662   size_t slen;
5663
5664   if (NULL == address)
5665     slen = 0;
5666   else
5667     slen = strlen (address) + 1;
5668
5669   GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
5670                                               GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5671   if (NULL == address)
5672     GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
5673 }
5674
5675
5676 /**
5677  * Handle AddressLookup-message.
5678  *
5679  * @param cls closure (always NULL)
5680  * @param client identification of the client
5681  * @param message the actual message
5682  */
5683 static void
5684 handle_address_lookup (void *cls,
5685                        struct GNUNET_SERVER_Client *client,
5686                        const struct GNUNET_MessageHeader *message)
5687 {
5688   const struct AddressLookupMessage *alum;
5689   struct TransportPlugin *lsPlugin;
5690   const char *nameTransport;
5691   const char *address;
5692   uint16_t size;
5693   struct GNUNET_SERVER_TransmitContext *tc;
5694   struct GNUNET_TIME_Absolute timeout;
5695   struct GNUNET_TIME_Relative rtimeout;
5696   int32_t numeric;
5697
5698   size = ntohs (message->size);
5699   if (size < sizeof (struct AddressLookupMessage))
5700     {
5701       GNUNET_break_op (0);
5702       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5703       return;
5704     }
5705   alum = (const struct AddressLookupMessage *) message;
5706   uint32_t addressLen = ntohl (alum->addrlen);
5707   if (size <= sizeof (struct AddressLookupMessage) + addressLen)
5708     {
5709       GNUNET_break_op (0);
5710       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5711       return;
5712     }
5713   address = (const char *) &alum[1];
5714   nameTransport = (const char *) &address[addressLen];
5715   if (nameTransport
5716       [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
5717     {
5718       GNUNET_break_op (0);
5719       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
5720       return;
5721     }
5722   timeout = GNUNET_TIME_absolute_ntoh (alum->timeout);
5723   rtimeout = GNUNET_TIME_absolute_get_remaining (timeout);
5724   numeric = ntohl (alum->numeric_only);
5725   lsPlugin = find_transport (nameTransport);
5726   if (NULL == lsPlugin)
5727     {
5728       tc = GNUNET_SERVER_transmit_context_create (client);
5729       GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
5730                                                   GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
5731       GNUNET_SERVER_transmit_context_run (tc, rtimeout);
5732       return;
5733     }
5734   tc = GNUNET_SERVER_transmit_context_create (client);
5735   lsPlugin->api->address_pretty_printer (lsPlugin->api->cls,
5736                                          nameTransport,
5737                                          address, addressLen,
5738                                          numeric,
5739                                          rtimeout,
5740                                          &transmit_address_to_client, tc);
5741 }
5742
5743
5744 /**
5745  * Setup the environment for this plugin.
5746  */
5747 static void
5748 create_environment (struct TransportPlugin *plug)
5749 {
5750   plug->env.cfg = cfg;
5751   plug->env.my_identity = &my_identity;
5752   plug->env.our_hello = &our_hello;
5753   plug->env.cls = plug;
5754   plug->env.receive = &plugin_env_receive;
5755   plug->env.notify_address = &plugin_env_notify_address;
5756   plug->env.session_end = &plugin_env_session_end;
5757   plug->env.max_connections = max_connect_per_transport;
5758   plug->env.stats = stats;
5759 }
5760
5761
5762 /**
5763  * Start the specified transport (load the plugin).
5764  */
5765 static void
5766 start_transport (struct GNUNET_SERVER_Handle *server,
5767                  const char *name)
5768 {
5769   struct TransportPlugin *plug;
5770   char *libname;
5771
5772   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5773               _("Loading `%s' transport plugin\n"), name);
5774   GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
5775   plug = GNUNET_malloc (sizeof (struct TransportPlugin));
5776   create_environment (plug);
5777   plug->short_name = GNUNET_strdup (name);
5778   plug->lib_name = libname;
5779   plug->next = plugins;
5780   plugins = plug;
5781   plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
5782   if (plug->api == NULL)
5783     {
5784       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5785                   _("Failed to load transport plugin for `%s'\n"), name);
5786       GNUNET_free (plug->short_name);
5787       plugins = plug->next;
5788       GNUNET_free (libname);
5789       GNUNET_free (plug);
5790     }
5791 }
5792
5793
5794 /**
5795  * Called whenever a client is disconnected.  Frees our
5796  * resources associated with that client.
5797  *
5798  * @param cls closure
5799  * @param client identification of the client
5800  */
5801 static void
5802 client_disconnect_notification (void *cls,
5803                                 struct GNUNET_SERVER_Client *client)
5804 {
5805   struct TransportClient *pos;
5806   struct TransportClient *prev;
5807   struct ClientMessageQueueEntry *mqe;
5808   struct Blacklisters *bl;
5809   struct BlacklistCheck *bc;
5810
5811   if (client == NULL)
5812     return;
5813 #if DEBUG_TRANSPORT
5814   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
5815               "Client disconnected, cleaning up.\n");
5816 #endif
5817   /* clean up blacklister */
5818   bl = bl_head;
5819   while (bl != NULL)
5820     {
5821       if (bl->client == client)
5822         {
5823           bc = bc_head;
5824           while (bc != NULL)
5825             {
5826               if (bc->bl_pos == bl)
5827                 {
5828                   bc->bl_pos = bl->next;
5829                   if (bc->th != NULL)
5830                     {
5831                       GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th);
5832                       bc->th = NULL;
5833                     }
5834                   if (bc->task == GNUNET_SCHEDULER_NO_TASK)
5835                     bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check,
5836                                                          bc);
5837                   break;
5838                 }
5839               bc = bc->next;
5840             }
5841           GNUNET_CONTAINER_DLL_remove (bl_head,
5842                                        bl_tail,
5843                                        bl);
5844           GNUNET_SERVER_client_drop (bl->client);
5845           GNUNET_free (bl);
5846           break;
5847         }
5848       bl = bl->next;
5849     }
5850   /* clean up 'normal' clients */
5851   prev = NULL;
5852   pos = clients;
5853   while ((pos != NULL) && (pos->client != client))
5854     {
5855       prev = pos;
5856       pos = pos->next;
5857     }
5858   if (pos == NULL)
5859     return;
5860   while (NULL != (mqe = pos->message_queue_head))
5861     {
5862       GNUNET_CONTAINER_DLL_remove (pos->message_queue_head,
5863                                    pos->message_queue_tail,
5864                                    mqe);
5865       pos->message_count--;
5866       GNUNET_free (mqe);
5867     }
5868   if (prev == NULL)
5869     clients = pos->next;
5870   else
5871     prev->next = pos->next;
5872   if (GNUNET_YES == pos->tcs_pending)
5873     {
5874       pos->client = NULL;
5875       return;
5876     }
5877   if (pos->th != NULL)
5878     {
5879       GNUNET_CONNECTION_notify_transmit_ready_cancel (pos->th);
5880       pos->th = NULL;
5881     }
5882   GNUNET_break (0 == pos->message_count);
5883   GNUNET_free (pos);
5884 }
5885
5886
5887 /**
5888  * Function called when the service shuts down.  Unloads our plugins
5889  * and cancels pending validations.
5890  *
5891  * @param cls closure, unused
5892  * @param tc task context (unused)
5893  */
5894 static void
5895 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
5896 {
5897   struct TransportPlugin *plug;
5898   struct OwnAddressList *al;
5899   struct CheckHelloValidatedContext *chvc;
5900
5901   while (neighbours != NULL)
5902     {
5903       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5904               "Disconnecting peer `%4s', %s\n", GNUNET_i2s(&neighbours->id),
5905               "SHUTDOWN_TASK");
5906       disconnect_neighbour (neighbours, GNUNET_NO);
5907     }
5908 #if DEBUG_TRANSPORT
5909   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5910               "Transport service is unloading plugins...\n");
5911 #endif
5912   while (NULL != (plug = plugins))
5913     {
5914       plugins = plug->next;
5915       if (plug->address_update_task != GNUNET_SCHEDULER_NO_TASK)
5916         {
5917           GNUNET_SCHEDULER_cancel (plug->address_update_task);
5918           plug->address_update_task = GNUNET_SCHEDULER_NO_TASK;
5919         }
5920       GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
5921       GNUNET_free (plug->lib_name);
5922       GNUNET_free (plug->short_name);
5923       while (NULL != (al = plug->addresses))
5924         {
5925           plug->addresses = al->next;
5926           GNUNET_free (al);
5927         }
5928       GNUNET_free (plug);
5929     }
5930   if (my_private_key != NULL)
5931     GNUNET_CRYPTO_rsa_key_free (my_private_key);
5932   GNUNET_free_non_null (our_hello);
5933
5934   GNUNET_CONTAINER_multihashmap_iterate (validation_map,
5935                                          &abort_validation,
5936                                          NULL);
5937   GNUNET_CONTAINER_multihashmap_destroy (validation_map);
5938   validation_map = NULL;
5939
5940   ats_shutdown(ats);
5941
5942   /* free 'chvc' data structure */
5943   while (NULL != (chvc = chvc_head))
5944     {
5945       chvc_head = chvc->next;
5946       if (chvc->piter != NULL)
5947         {
5948           GNUNET_PEERINFO_iterate_cancel (chvc->piter);
5949           GNUNET_STATISTICS_update (stats,
5950                                     gettext_noop ("# outstanding peerinfo iterate requests"),
5951                                     -1,
5952                                     GNUNET_NO);
5953         }
5954       else
5955         GNUNET_break (0);
5956       GNUNET_assert (chvc->ve_count == 0);
5957       GNUNET_free (chvc);
5958     }
5959   chvc_tail = NULL;
5960
5961   if (stats != NULL)
5962     {
5963       GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
5964       stats = NULL;
5965     }
5966   if (peerinfo != NULL)
5967     {
5968       GNUNET_PEERINFO_disconnect (peerinfo);
5969       peerinfo = NULL;
5970     }
5971   /* Can we assume those are gone by now, or do we need to clean up
5972      explicitly!? */
5973   GNUNET_break (bl_head == NULL);
5974   GNUNET_break (bc_head == NULL);
5975 }
5976
5977 #if HAVE_LIBGLPK
5978 static int ats_evaluate_results (int result, int solution, char * problem)
5979 {
5980         int cont = GNUNET_NO;
5981         int error_kind = GNUNET_ERROR_TYPE_DEBUG;
5982 #if DEBUG_ATS
5983         error_kind = GNUNET_ERROR_TYPE_ERROR;
5984 #endif
5985
5986         switch (result) {
5987         case GLP_ESTOP  :    /* search terminated by application */
5988                 GNUNET_log (error_kind, "%s , Search terminated by application ", problem);
5989                 break;
5990         case GLP_EITLIM :    /* iteration limit exceeded */
5991                 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "%s Iteration limit exceeded ", problem);
5992                 break;
5993         break;
5994         case GLP_ETMLIM :    /* time limit exceeded */
5995                 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "%s Time limit exceeded ", problem);
5996         break;
5997         case GLP_ENOPFS :    /* no primal feasible solution */
5998         case GLP_ENODFS :    /* no dual feasible solution */
5999                 GNUNET_log (error_kind, "%s No feasible solution", problem);
6000         break;
6001
6002         case GLP_EBADB  :    /* invalid basis */
6003         case GLP_ESING  :    /* singular matrix */
6004         case GLP_ECOND  :    /* ill-conditioned matrix */
6005         case GLP_EBOUND :    /* invalid bounds */
6006         case GLP_EFAIL  :    /* solver failed */
6007         case GLP_EOBJLL :    /* objective lower limit reached */
6008         case GLP_EOBJUL :    /* objective upper limit reached */
6009         case GLP_EROOT  :    /* root LP optimum not provided */
6010                 GNUNET_log (error_kind, "%s Invalid Input data: %i\n", problem, result);
6011         break;
6012
6013         case 0:
6014                         GNUNET_log (error_kind, "%s Problem has been solved\n", problem);
6015         break;
6016         }
6017
6018         switch (solution) {
6019                 case GLP_UNDEF:
6020                         GNUNET_log (error_kind, "%s solution is undefined\n", problem);
6021                         break;
6022                 case GLP_OPT:
6023                         GNUNET_log (error_kind, "%s solution is optimal\n", problem);
6024                         cont=GNUNET_YES;
6025                         break;
6026                 case GLP_FEAS:
6027                         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"));
6028                         cont=GNUNET_YES;
6029                         break;
6030                 case GLP_NOFEAS:
6031                         GNUNET_log (error_kind, "%s problem has no %sfeasible solution\n", problem,  (0==strcmp(problem,"LP")?"":"integer "));
6032                         break;
6033                 case GLP_INFEAS:
6034                         GNUNET_log (error_kind, "%s problem is infeasible \n", problem);
6035                         break;
6036                 case GLP_UNBND:
6037                         GNUNET_log (error_kind, "%s problem is unbounded \n", problem);
6038                 default:
6039                         break;
6040         }
6041 return cont;
6042 }
6043
6044 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)
6045 {
6046         int result;
6047         int lp_solution;
6048         int mlp_solution;
6049
6050         // Solving simplex
6051
6052         glp_smcp opt_lp;
6053         glp_init_smcp(&opt_lp);
6054 #if VERBOSE_ATS
6055         opt_lp.msg_lev = GLP_MSG_ALL;
6056 #else
6057         opt_lp.msg_lev = GLP_MSG_OFF;
6058 #endif
6059
6060         // setting iteration limit
6061         opt_lp.it_lim = max_it;
6062         // maximum duration
6063         opt_lp.tm_lim = max_dur;
6064
6065         if (ats->modified_addr == GNUNET_YES)
6066                 opt_lp.presolve = GLP_ON;
6067         result = glp_simplex(ats->prob, &opt_lp);
6068         lp_solution =  glp_get_status (ats->prob);
6069
6070         if ((result == GLP_ETMLIM) || (result == GLP_ETMLIM))
6071         {
6072                 ats->stat.valid = GNUNET_NO;
6073                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ATS exceeded time or iteration limit!\n");
6074                 return;
6075         }
6076
6077         if (ats_evaluate_results(result, lp_solution, "LP") == GNUNET_YES)
6078         {
6079                         stat->valid = GNUNET_YES;
6080         }
6081         else
6082         {
6083                 ats->simplex_rerun_required = GNUNET_YES;
6084                 opt_lp.presolve = GLP_ON;
6085                 result = glp_simplex(ats->prob, &opt_lp);
6086                 lp_solution =  glp_get_status (ats->prob);
6087
6088                 // TODO: Remove if this does not appear until release
6089                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "EXECUTED SIMPLEX WITH PRESOLVER! %i", lp_solution);
6090
6091                 if (ats_evaluate_results(result, lp_solution, "LP") != GNUNET_YES)
6092                 {
6093                         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "After execution simplex with presolver: STILL INVALID!\n");
6094                         char * filename;
6095                         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);
6096                         glp_write_lp (ats->prob, NULL, filename);
6097                         GNUNET_free (filename);
6098                         stat->valid = GNUNET_NO;
6099                         return;
6100                 }
6101                 stat->valid = GNUNET_YES;
6102         }
6103
6104         // Solving mlp
6105         glp_iocp opt_mlp;
6106         glp_init_iocp(&opt_mlp);
6107         // maximum duration
6108         opt_mlp.tm_lim = max_dur;
6109         // output level
6110 #if VERBOSE_ATS
6111         opt_mlp.msg_lev = GLP_MSG_ALL;
6112 #else
6113         opt_mlp.msg_lev = GLP_MSG_OFF;
6114 #endif
6115
6116         result = glp_intopt (ats->prob, &opt_mlp);
6117         mlp_solution =  glp_mip_status (ats->prob);
6118         stat->solution = mlp_solution;
6119
6120         if (ats_evaluate_results(result, mlp_solution, "MLP") == GNUNET_YES)
6121         {
6122                 stat->valid = GNUNET_YES;
6123         }
6124         else
6125         {
6126                 // TODO: Remove if this does not appear until release
6127                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,  "MLP SOLUTION INVALID: %i\n", lp_solution);
6128                 stat->valid = GNUNET_NO;
6129         }
6130
6131 /*
6132         int check;
6133         int error = GNUNET_NO;
6134         double bw;
6135         struct ATS_mechanism *t = NULL;
6136         for (c=1; c<= (c_peers); c++ )
6137         {
6138                 check = GNUNET_NO;
6139                 t = peers[c].m_head;
6140                 while (t!=NULL)
6141                 {
6142                         bw = glp_get_col_prim(prob, t->col_index);
6143                         if (bw > 1.0)
6144                         {
6145 #if VERBOSE_ATS
6146                                 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);
6147 #endif
6148                                 if (check ==GNUNET_YES)
6149                                 {
6150                                         glp_write_sol(prob, "invalid_solution.mlp");
6151                                         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Invalid solution, check invalid_solution.mlp");
6152                                         GNUNET_STATISTICS_update (stats, "ATS invalid solutions", 1, GNUNET_NO);
6153                                         error = GNUNET_YES;
6154                                 }
6155                                 if (check ==GNUNET_NO)
6156                                         check = GNUNET_YES;
6157                         }
6158                         t = t->next;
6159                 }
6160         }*/
6161
6162 #if VERBOSE_ATS
6163         if (glp_get_col_prim(ats->prob,2*c_mechs+1) != 1)
6164         {
6165         int c;
6166         for (c=1; c<= available_quality_metrics; c++ )
6167         {
6168                 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));
6169         }
6170         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));
6171         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));
6172         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));
6173         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "objective value:  %f\n", glp_mip_obj_val(ats->prob));
6174         }
6175 #endif
6176 }
6177
6178 static void ats_delete_problem ()
6179 {
6180         int c;
6181
6182         for (c=0; c< (ats->stat).c_mechs; c++)
6183                 GNUNET_free_non_null (ats->mechanisms[c].rc);
6184
6185         if (ats->mechanisms!=NULL)
6186         {
6187                 GNUNET_free(ats->mechanisms);
6188                 ats->mechanisms = NULL;
6189         }
6190         if (ats->peers!=NULL)
6191         {
6192                 GNUNET_free(ats->peers);
6193                 ats->peers = NULL;
6194         }
6195
6196         if (ats->prob != NULL)
6197         {
6198                 glp_delete_prob(ats->prob);
6199                 ats->prob = NULL;
6200         }
6201
6202         ats->stat.begin_cr = GNUNET_SYSERR;
6203         ats->stat.begin_qm = GNUNET_SYSERR;
6204         ats->stat.c_mechs = 0;
6205         ats->stat.c_peers = 0;
6206         ats->stat.end_cr = GNUNET_SYSERR;
6207         ats->stat.end_qm = GNUNET_SYSERR;
6208         ats->stat.solution = GNUNET_SYSERR;
6209         ats->stat.valid = GNUNET_SYSERR;
6210 }
6211
6212
6213 static void ats_update_problem_qm ()
6214 {
6215         int array_index;
6216         int row_index;
6217         int c, c2;
6218         int c_q_metrics = available_quality_metrics;
6219
6220         int *ja    = GNUNET_malloc ((1 + ats->stat.c_mechs*2 + 3 + available_quality_metrics) * sizeof (int));
6221         double *ar = GNUNET_malloc ((1 + ats->stat.c_mechs*2 + 3 + available_quality_metrics) * sizeof (double));
6222 #if DEBUG_ATS
6223                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Updating problem quality metrics\n");
6224 #endif
6225         row_index = ats->stat.begin_qm;
6226
6227         for (c=1; c <= c_q_metrics; c++)
6228         {
6229                 array_index = 1;
6230                 double value = 1;
6231 #if VERBOSE_ATS
6232                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6233 #endif
6234
6235                 glp_set_row_bnds(ats->prob, row_index, GLP_FX, 0.0, 0.0);
6236                 for (c2=1; c2<=ats->stat.c_mechs; c2++)
6237                 {
6238                         ja[array_index] = c2;
6239
6240                         if (qm[c-1].atis_index  == GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY)
6241                         {
6242                                 double v0, v1, v2;
6243                                 v0 = ats->mechanisms[c2].addr->quality[c-1].values[0];
6244                                 if (v1 < 1) v0 = 0.1;
6245                                 v1 = ats->mechanisms[c2].addr->quality[c-1].values[1];
6246                                 if (v1 < 1) v0 = 0.1;
6247                                 v2 = ats->mechanisms[c2].addr->quality[c-1].values[2];
6248                                 if (v1 < 1) v0 = 0.1;
6249                                 value = 100.0 / ((v0 + 2 * v1 + 3 * v2) / 6.0);
6250                                 //value = 1;
6251                         }
6252                         if (qm[c-1].atis_index  == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
6253                         {
6254                                 double v0, v1, v2;
6255                                 v0 = ats->mechanisms[c2].addr->quality[c-1].values[0];
6256                                 if (v0 < 1) v0 = 1;
6257                                 v1 = ats->mechanisms[c2].addr->quality[c-1].values[1];
6258                                 if (v1 < 1) v1 = 1;
6259                                 v2 = ats->mechanisms[c2].addr->quality[c-1].values[2];
6260                                 if (v2 < 1) v2 = 1;
6261                                 value =  (v0 + 2 * v1 + 3 * v2) / 6.0;
6262                                 if (value >= 1)
6263                                         value =  (double) 10 / value;
6264                                 else
6265                                         value = 10;
6266                         }
6267                         ar[array_index] = (ats->mechanisms[c2].peer->f) * value;
6268 #if VERBOSE_ATS
6269                         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]);
6270 #endif
6271                         array_index++;
6272                 }
6273                 ja[array_index] = ats->stat.col_qm + c - 1;
6274                 ar[array_index] = -1;
6275
6276 #if VERBOSE_ATS
6277                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, row_index, ja[array_index], ar[array_index]);
6278                 #endif
6279                 glp_set_mat_row (ats->prob, row_index, array_index, ja, ar);
6280
6281                 array_index = 1;
6282                 row_index++;
6283         }
6284
6285         GNUNET_free_non_null (ja);
6286         GNUNET_free_non_null (ar);
6287 }
6288
6289
6290 static void ats_update_problem_cr ()
6291 {
6292
6293         int array_index;
6294         int row_index;
6295         int c, c2;
6296         double ct_max, ct_min;
6297
6298         int *ja    = GNUNET_malloc ((1 + ats->stat.c_mechs*2 + 3 + available_quality_metrics) * sizeof (int));
6299         double *ar = GNUNET_malloc ((1 + ats->stat.c_mechs*2 + 3 + available_quality_metrics) * sizeof (double));
6300
6301         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Updating problem quality metrics\n");
6302         row_index = ats->stat.begin_cr;
6303
6304         for (c=0; c<available_ressources; c++)
6305         {
6306                 ct_max = ressources[c].c_max;
6307                 ct_min = ressources[c].c_min;
6308 #if VERBOSE_ATS
6309                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] %f..%f\n",row_index, ct_min, ct_max);
6310 #endif
6311                 glp_set_row_bnds(ats->prob, row_index, GLP_DB, ct_min, ct_max);
6312
6313                 for (c2=1; c2<=ats->stat.c_mechs; c2++)
6314                 {
6315                         double value = 0;
6316                         ja[array_index] = c2;
6317                         value = ats->mechanisms[c2].addr->ressources[c].c;
6318                         ar[array_index] = value;
6319 #if VERBOSE_ATS
6320                         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, row_index, ja[array_index], ar[array_index]);
6321 #endif
6322                         array_index++;
6323                 }
6324                 glp_set_mat_row (ats->prob, row_index, array_index, ja, ar);
6325
6326                 row_index ++;
6327         }
6328
6329
6330         GNUNET_free_non_null (ja);
6331         GNUNET_free_non_null (ar);
6332 }
6333
6334
6335 #if 0
6336 static void ats_update_problem_qm_TEST ()
6337 {
6338         int row_index;
6339         int c, c2;
6340
6341         int old_ja[ats->stat.c_mechs + 2];
6342         double old_ar[ats->stat.c_mechs + 2];
6343         int c_old;
6344         int changed = 0;
6345
6346         int *ja    = GNUNET_malloc ((1 + ats->stat.c_mechs*2 + 3 + available_quality_metrics) * sizeof (int));
6347         double *ar = GNUNET_malloc ((1 + ats->stat.c_mechs*2 + 3 + available_quality_metrics) * sizeof (double));
6348 #if DEBUG_ATS
6349         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Updating problem quality metrics TEST\n");
6350 #endif
6351         if (ats->stat.begin_qm >0)
6352                 row_index = ats->stat.begin_qm;
6353         else
6354                 return;
6355
6356
6357         for (c=0; c<available_quality_metrics; c++)
6358         {
6359
6360                 c_old = glp_get_mat_row (ats->prob, row_index, old_ja, old_ar);
6361
6362                 glp_set_row_bnds(ats->prob, row_index, GLP_FX, 0.0, 0.0);
6363
6364                 for (c2=1; c2<=c_old; c2++)
6365                 {
6366                         ja[c2] = old_ja[c2];
6367                         if ((changed < 3) && (c2>2) && (old_ar[c2] != -1))
6368                         {
6369                                 ar[c2] = old_ar[c2] + 5 - changed;
6370                                 changed ++;
6371                         }
6372                         else
6373                                 ar[c2] = old_ar[c2];
6374 #if VERBOSE_ATS
6375                         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]);
6376 #endif
6377                 }
6378                 glp_set_mat_row (ats->prob, row_index, c_old, ja, ar);
6379
6380                 row_index ++;
6381         }
6382
6383         GNUNET_free_non_null (ja);
6384         GNUNET_free_non_null (ar);
6385 }
6386 #endif
6387
6388
6389 /** solve the bandwidth distribution problem
6390  * @param max_it maximum iterations
6391  * @param max_dur maximum duration in ms
6392  * @param D     weight for diversity
6393  * @param U weight for utility
6394  * @param R weight for relativity
6395  * @param v_b_min minimal bandwidth per peer
6396  * @param v_n_min minimum number of connections
6397  * @param stat result struct
6398  * @return GNUNET_SYSERR if glpk is not available, number of mechanisms used
6399  */
6400 static int ats_create_problem (double D, double U, double R, int v_b_min, int v_n_min, struct ATS_stat *stat)
6401 {
6402         if (ats->prob != NULL)
6403                 glp_delete_prob(ats->prob);
6404
6405         ats->prob = glp_create_prob();
6406
6407         int c;
6408         int c_peers = 0;
6409         int c_mechs = 0;
6410
6411         int c_c_ressources = available_ressources;
6412         int c_q_metrics = available_quality_metrics;
6413
6414         double M = VERY_BIG_DOUBLE_VALUE;
6415         double Q[c_q_metrics+1];
6416         for (c=1; c<=c_q_metrics; c++)
6417         {
6418                 Q[c] = 1;
6419         }
6420
6421         struct NeighbourList *next = neighbours;
6422         while (next!=NULL)
6423         {
6424                 struct ReadyList *r_next = next->plugins;
6425                 while (r_next != NULL)
6426                 {
6427                         struct ForeignAddressList * a_next = r_next->addresses;
6428                         while (a_next != NULL)
6429                         {
6430                                 c_mechs++;
6431                                 a_next = a_next->next;
6432                         }
6433                         r_next = r_next->next;
6434                 }
6435                 next = next->next;
6436                 c_peers++;
6437         }
6438
6439         if (c_mechs==0)
6440         {
6441 #if DEBUG_ATS
6442                 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No addresses for bw distribution available\n", c_peers);
6443 #endif
6444                 stat->valid = GNUNET_NO;
6445                 stat->c_peers = 0;
6446                 stat->c_mechs = 0;
6447                 return GNUNET_SYSERR;
6448         }
6449
6450         ats->mechanisms = GNUNET_malloc((1+c_mechs) * sizeof (struct ATS_mechanism));
6451         ats->peers =  GNUNET_malloc((1+c_peers) * sizeof (struct ATS_peer));
6452
6453         struct ATS_mechanism * mechanisms = ats->mechanisms;
6454         struct ATS_peer * peers = ats->peers;
6455
6456         c_mechs = 1;
6457         c_peers = 1;
6458         next = neighbours;
6459         while (next!=NULL)
6460         {
6461                 peers[c_peers].peer = next->id;
6462                 peers[c_peers].m_head = NULL;
6463                 peers[c_peers].m_tail = NULL;
6464                 // FIXME
6465                 peers[c_peers].f = 1.0 / c_mechs;
6466
6467                 struct ReadyList *r_next = next->plugins;
6468                 while (r_next != NULL)
6469                 {
6470                         struct ForeignAddressList * a_next = r_next->addresses;
6471                         while (a_next != NULL)
6472                         {
6473                                 mechanisms[c_mechs].addr = a_next;
6474                                 mechanisms[c_mechs].col_index = c_mechs;
6475                                 mechanisms[c_mechs].peer = &peers[c_peers];
6476                                 mechanisms[c_mechs].next = NULL;
6477                                 mechanisms[c_mechs].plugin = r_next->plugin;
6478
6479                                 GNUNET_CONTAINER_DLL_insert_tail(peers[c_peers].m_head, peers[c_peers].m_tail, &mechanisms[c_mechs]);
6480                                 c_mechs++;
6481                                 a_next = a_next->next;
6482                         }
6483                         r_next = r_next->next;
6484                 }
6485                 c_peers++;
6486                 next = next->next;
6487         }
6488         c_mechs--;
6489         c_peers--;
6490
6491         if (v_n_min > c_peers)
6492                 v_n_min = c_peers;
6493
6494 #if VERBOSE_ATS
6495         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);
6496 #endif
6497
6498         int size =  1 + 3 + 10 *c_mechs + c_peers + (c_q_metrics*c_mechs)+ c_q_metrics + c_c_ressources * c_mechs ;
6499         int row_index;
6500         int array_index=1;
6501         int * ia = GNUNET_malloc (size * sizeof (int));
6502         int * ja = GNUNET_malloc (size * sizeof (int));
6503         double * ar = GNUNET_malloc(size* sizeof (double));
6504
6505         glp_set_prob_name(ats->prob, "gnunet ats bandwidth distribution");
6506         glp_set_obj_dir(ats->prob, GLP_MAX);
6507
6508         /* adding columns */
6509         char * name;
6510         glp_add_cols(ats->prob, 2 * c_mechs);
6511         /* adding b_t cols */
6512         for (c=1; c <= c_mechs; c++)
6513         {
6514
6515                 GNUNET_asprintf(&name, "p_%s_b%i",GNUNET_i2s(&(mechanisms[c].peer->peer)), c);
6516                 glp_set_col_name(ats->prob, c, name);
6517                 GNUNET_free (name);
6518                 glp_set_col_bnds(ats->prob, c, GLP_LO, 0.0, 0.0);
6519                 glp_set_obj_coef(ats->prob, c, 0);
6520
6521         }
6522         /* adding n_t cols */
6523         for (c=c_mechs+1; c <= 2*c_mechs; c++)
6524         {
6525                 GNUNET_asprintf(&name, "p_%s_n%i",GNUNET_i2s(&(mechanisms[c-c_mechs].peer->peer)),(c-c_mechs));
6526                 glp_set_col_name(ats->prob, c, name);
6527                 GNUNET_free (name);
6528                 glp_set_col_bnds(ats->prob, c, GLP_DB, 0.0, 1.0);
6529                 glp_set_col_kind(ats->prob, c, GLP_IV);
6530                 glp_set_obj_coef(ats->prob, c, 0);
6531         }
6532
6533         /* feasibility constraints */
6534         /* Constraint 1: one address per peer*/
6535         row_index = 1;
6536         glp_add_rows(ats->prob, c_peers);
6537         for (c=1; c<=c_peers; c++)
6538         {
6539                 glp_set_row_bnds(ats->prob, row_index, GLP_FX, 1.0, 1.0);
6540
6541                 struct ATS_mechanism *m = peers[c].m_head;
6542                 while (m!=NULL)
6543                 {
6544                         ia[array_index] = row_index;
6545                         ja[array_index] = (c_mechs + m->col_index);
6546                         ar[array_index] = 1;
6547 #if VERBOSE_ATS
6548                         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6549 #endif
6550                         array_index++;
6551                         m = m->next;
6552                 }
6553                 row_index++;
6554         }
6555
6556         /* Constraint 2: only active mechanism gets bandwidth assigned */
6557         glp_add_rows(ats->prob, c_mechs);
6558         for (c=1; c<=c_mechs; c++)
6559         {
6560                 /* b_t - n_t * M <= 0 */
6561 #if VERBOSE_ATS
6562                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6563 #endif
6564                 glp_set_row_bnds(ats->prob, row_index, GLP_UP, 0.0, 0.0);
6565
6566                 ia[array_index] = row_index;
6567                 ja[array_index] = mechanisms[c].col_index;
6568                 ar[array_index] = 1;
6569 #if VERBOSE_ATS
6570                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6571 #endif
6572                 array_index++;
6573                 ia[array_index] = row_index;
6574                 ja[array_index] = c_mechs + mechanisms[c].col_index;
6575                 ar[array_index] = -M;
6576 #if VERBOSE_ATS
6577                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6578 #endif
6579                 array_index++;
6580                 row_index ++;
6581         }
6582
6583         /* Constraint 3: minimum bandwidth*/
6584         glp_add_rows(ats->prob, c_mechs);
6585         for (c=1; c<=c_mechs; c++)
6586         {
6587                 /* b_t - n_t * b_min <= 0 */
6588 #if VERBOSE_ATS
6589                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6590 #endif
6591                 glp_set_row_bnds(ats->prob, row_index, GLP_LO, 0.0, 0.0);
6592
6593                 ia[array_index] = row_index;
6594                 ja[array_index] = mechanisms[c].col_index;
6595                 ar[array_index] = 1;
6596 #if VERBOSE_ATS
6597                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6598 #endif
6599                 array_index++;
6600                 ia[array_index] = row_index;
6601                 ja[array_index] = c_mechs + mechanisms[c].col_index;
6602                 ar[array_index] = -v_b_min;
6603 #if VERBOSE_ATS
6604                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6605 #endif
6606                 array_index++;
6607                 row_index ++;
6608         }
6609         int c2;
6610         /* Constraint 4: max ressource capacity */
6611         /* V cr: bt * ct_r <= cr_max
6612          * */
6613         glp_add_rows(ats->prob, available_ressources);
6614         double ct_max = VERY_BIG_DOUBLE_VALUE;
6615         double ct_min = 0.0;
6616
6617         stat->begin_cr = array_index;
6618
6619         for (c=0; c<available_ressources; c++)
6620         {
6621                 ct_max = ressources[c].c_max;
6622                 ct_min = ressources[c].c_min;
6623 #if VERBOSE_ATS
6624                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] %f..%f\n",row_index, ct_min, ct_max);
6625 #endif
6626                 glp_set_row_bnds(ats->prob, row_index, GLP_DB, ct_min, ct_max);
6627
6628                 for (c2=1; c2<=c_mechs; c2++)
6629                 {
6630                         double value = 0;
6631                         ia[array_index] = row_index;
6632                         ja[array_index] = c2;
6633                         value = mechanisms[c2].addr->ressources[c].c;
6634                         ar[array_index] = value;
6635 #if VERBOSE_ATS
6636                         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6637 #endif
6638                         array_index++;
6639                 }
6640                 row_index ++;
6641         }
6642         stat->end_cr = array_index--;
6643
6644         /* Constraint 5: min number of connections*/
6645         glp_add_rows(ats->prob, 1);
6646         for (c=1; c<=c_mechs; c++)
6647         {
6648                 // b_t - n_t * b_min >= 0
6649 #if VERBOSE_ATS
6650                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6651 #endif
6652                 glp_set_row_bnds(ats->prob, row_index, GLP_LO, v_n_min, 0.0);
6653
6654                 ia[array_index] = row_index;
6655                 ja[array_index] = c_mechs + mechanisms[c].col_index;
6656                 ar[array_index] = 1;
6657 #if VERBOSE_ATS
6658                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6659 #endif
6660                 array_index++;
6661         }
6662         row_index ++;
6663
6664         // optimisation constraints
6665
6666         // adding columns
6667
6668         // Constraint 6: optimize for diversity
6669         int col_d;
6670         col_d = glp_add_cols(ats->prob, 1);
6671         stat->col_d = col_d;
6672         //GNUNET_assert (col_d == (2*c_mechs) + 1);
6673         glp_set_col_name(ats->prob, col_d, "d");
6674         glp_set_obj_coef(ats->prob, col_d, D);
6675         glp_set_col_bnds(ats->prob, col_d, GLP_LO, 0.0, 0.0);
6676         glp_add_rows(ats->prob, 1);
6677 #if VERBOSE_ATS
6678         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6679 #endif
6680         glp_set_row_bnds(ats->prob, row_index, GLP_FX, 0.0, 0.0);
6681         for (c=1; c<=c_mechs; c++)
6682         {
6683                 // b_t - n_t * b_min >= 0
6684                 ia[array_index] = row_index;
6685                 ja[array_index] = c_mechs + mechanisms[c].col_index;
6686                 ar[array_index] = 1;
6687 #if VERBOSE_ATS
6688                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6689 #endif
6690                 array_index++;
6691         }
6692         ia[array_index] = row_index;
6693         ja[array_index] = col_d;
6694         ar[array_index] = -1;
6695 #if VERBOSE_ATS
6696         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6697 #endif
6698         array_index++;
6699         row_index ++;
6700
6701
6702         // Constraint 7: optimize for quality
6703         int col_qm;
6704         col_qm = glp_add_cols(ats->prob, c_q_metrics);
6705         stat->col_qm = col_qm;
6706         //GNUNET_assert (col_qm == (2*c_mechs) + 3 + 1);
6707         for (c=0; c< c_q_metrics; c++)
6708         {
6709                 GNUNET_asprintf(&name, "Q_%s",qm[c].name);
6710                 glp_set_col_name(ats->prob, col_qm + c, name);
6711                 glp_set_col_bnds(ats->prob, col_qm + c, GLP_LO, 0.0, 0.0);
6712                 GNUNET_free (name);
6713                 glp_set_obj_coef(ats->prob, col_qm + c, Q[c]);
6714         }
6715     glp_add_rows(ats->prob, available_quality_metrics);
6716         stat->begin_qm = row_index;
6717         for (c=1; c <= c_q_metrics; c++)
6718         {
6719 #if VERBOSE_ATS
6720                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6721 #endif
6722                 double value = 1;
6723                 glp_set_row_bnds(ats->prob, row_index, GLP_FX, 0.0, 0.0);
6724                 for (c2=1; c2<=c_mechs; c2++)
6725                 {
6726
6727                         ia[array_index] = row_index;
6728                         ja[array_index] = c2;
6729                         if (qm[c-1].atis_index  == GNUNET_TRANSPORT_ATS_QUALITY_NET_DELAY)
6730                         {
6731                                 double v0, v1, v2;
6732                                 v0 = mechanisms[c2].addr->quality[c-1].values[0];
6733                                 if (v1 < 1) v0 = 0.1;
6734                                 v1 = mechanisms[c2].addr->quality[c-1].values[1];
6735                                 if (v1 < 1) v0 = 0.1;
6736                                 v2 = mechanisms[c2].addr->quality[c-1].values[2];
6737                                 if (v1 < 1) v0 = 0.1;
6738                                 value = 100.0 / ((v0 + 2 * v1 + 3 * v2) / 6.0);
6739                                 value = 1;
6740                         }
6741                         if (qm[c-1].atis_index  == GNUNET_TRANSPORT_ATS_QUALITY_NET_DISTANCE)
6742                         {
6743                                 double v0, v1, v2;
6744                                 v0 = mechanisms[c2].addr->quality[c-1].values[0];
6745                                 if (v0 < 1) v0 = 1;
6746                                 v1 = mechanisms[c2].addr->quality[c-1].values[1];
6747                                 if (v1 < 1) v1 = 1;
6748                                 v2 = mechanisms[c2].addr->quality[c-1].values[2];
6749                                 if (v2 < 1) v2 = 1;
6750                                 value =  (v0 + 2 * v1 + 3 * v2) / 6.0;
6751                                 if (value >= 1)
6752                                         value =  (double) 10 / value;
6753                                 else
6754                                         value = 10;
6755                         }
6756                         ar[array_index] = (mechanisms[c2].peer->f) * value ;
6757 #if VERBOSE_ATS
6758                         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]);
6759 #endif
6760                         array_index++;
6761                 }
6762
6763                 ia[array_index] = row_index;
6764                 ja[array_index] = col_qm + c - 1;
6765                 ar[array_index] = -1;
6766 #if VERBOSE_ATS
6767                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6768 #endif
6769                 array_index++;
6770                 row_index++;
6771         }
6772         stat->end_qm = row_index-1;
6773
6774         // Constraint 8: optimize bandwidth utility
6775         int col_u;
6776         col_u = glp_add_cols(ats->prob, 1);
6777         stat->col_u = col_u;
6778         //GNUNET_assert (col_u == (2*c_mechs) + 2);
6779         glp_set_col_name(ats->prob, col_u, "u");
6780         glp_set_obj_coef(ats->prob, col_u, U);
6781         glp_set_col_bnds(ats->prob, col_u, GLP_LO, 0.0, 0.0);
6782         glp_add_rows(ats->prob, 1);
6783 #if VERBOSE_ATS
6784         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "bounds [row]=[%i] \n",row_index);
6785 #endif
6786         glp_set_row_bnds(ats->prob, row_index, GLP_FX, 0.0, 0.0);
6787         for (c=1; c<=c_mechs; c++)
6788         {
6789                 ia[array_index] = row_index;
6790                 ja[array_index] = c;
6791                 ar[array_index] = mechanisms[c].peer->f;
6792 #if VERBOSE_ATS
6793                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6794 #endif
6795                 array_index++;
6796         }
6797         ia[array_index] = row_index;
6798         ja[array_index] = col_u;
6799         ar[array_index] = -1;
6800 #if VERBOSE_ATS
6801         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6802 #endif
6803
6804         array_index++;
6805         row_index ++;
6806
6807         // Constraint 9: optimize relativity
6808         int col_r;
6809         col_r = glp_add_cols(ats->prob, 1);
6810         stat->col_r = col_r;
6811         //GNUNET_assert (col_r == (2*c_mechs) + 3);
6812         glp_set_col_name(ats->prob, col_r, "r");
6813         glp_set_obj_coef(ats->prob, col_r, R);
6814         glp_set_col_bnds(ats->prob, col_r, GLP_LO, 0.0, 0.0);
6815         glp_add_rows(ats->prob, c_peers);
6816         for (c=1; c<=c_peers; c++)
6817         {
6818                 glp_set_row_bnds(ats->prob, row_index, GLP_LO, 0.0, 0.0);
6819
6820                 struct ATS_mechanism *m = peers[c].m_head;
6821                 while (m!=NULL)
6822                 {
6823                         ia[array_index] = row_index;
6824                         ja[array_index] = m->col_index;
6825                         ar[array_index] = 1 / mechanisms[c].peer->f;
6826 #if VERBOSE_ATS
6827                         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6828 #endif
6829                         array_index++;
6830                         m = m->next;
6831                 }
6832                 ia[array_index] = row_index;
6833                 ja[array_index] = col_r;
6834                 ar[array_index] = -1;
6835 #if VERBOSE_ATS
6836                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "[index]=[%i]: [%i,%i]=%f \n",array_index, ia[array_index], ja[array_index], ar[array_index]);
6837 #endif
6838                 array_index++;
6839
6840                 row_index++;
6841         }
6842
6843         /* Loading the matrix */
6844         glp_load_matrix(ats->prob, array_index-1, ia, ja, ar);
6845
6846         stat->c_mechs = c_mechs;
6847         stat->c_peers = c_peers;
6848         stat->solution = 0;
6849         stat->valid = GNUNET_YES;
6850
6851         /* clean up */
6852
6853         GNUNET_free (ja);
6854         GNUNET_free (ia);
6855         GNUNET_free (ar);
6856
6857         return GNUNET_OK;
6858
6859 }
6860
6861 void ats_notify_ats_data (
6862                 const struct GNUNET_PeerIdentity *peer,
6863                 const struct GNUNET_TRANSPORT_ATS_Information *ats_data)
6864 {
6865 #if DEBUG_ATS
6866         GNUNET_log (GNUNET_ERROR_TYPE_BULK, "ATS_notify_ats_data: %s\n",GNUNET_i2s(peer));
6867 #endif
6868         ats_calculate_bandwidth_distribution();
6869 }
6870 #endif //END: HAVE_LIBGLPK
6871
6872 static void
6873 ats_calculate_bandwidth_distribution ()
6874 {
6875 #if HAVE_LIBGLPK
6876         struct GNUNET_TIME_Absolute start;
6877         struct GNUNET_TIME_Relative creation;
6878         struct GNUNET_TIME_Relative solving;
6879         char *text = "unmodified";
6880
6881         struct GNUNET_TIME_Relative delta = GNUNET_TIME_absolute_get_difference (ats->last, GNUNET_TIME_absolute_get());
6882         if (delta.rel_value < ats->min_delta.rel_value)
6883         {
6884 #if DEBUG_ATS
6885                 GNUNET_log (GNUNET_ERROR_TYPE_BULK, "Minimum time between cycles not reached\n");
6886 #endif
6887                 return;
6888         }
6889
6890         int dur = 500;
6891         if (INT_MAX < ats->max_exec_duration.rel_value)
6892                 dur = INT_MAX;
6893         else
6894                 dur = (int) ats->max_exec_duration.rel_value;
6895         ats->simplex_rerun_required = GNUNET_NO;
6896
6897         start = GNUNET_TIME_absolute_get();
6898         if ((ats->modified_addr == GNUNET_YES) || (ats->prob==NULL))
6899         {
6900                 text = "new";
6901                 ats->modified_addr = GNUNET_YES;
6902                 ats_delete_problem ();
6903                 ats_create_problem (ats->D, ats->U, ats->R, ats->v_b_min, ats->v_n_min, &ats->stat);
6904 #if DEBUG_ATS
6905                 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);
6906 #endif
6907         }
6908         else if ((ats->modified_addr == GNUNET_NO) && (ats->modified_resources == GNUNET_YES) && (ats->stat.valid == GNUNET_YES))
6909         {
6910                 ats_update_problem_cr();
6911                 text = "modified resources";
6912         }
6913         else if ((ats->modified_addr == GNUNET_NO) && (ats->modified_quality == GNUNET_YES) && (ats->stat.valid == GNUNET_YES))
6914         {
6915                 ats_update_problem_qm();
6916                 //ats_update_problem_qm_TEST ();
6917                 text = "modified quality";
6918         }
6919 #if DEBUG_ATS
6920         else GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Problem is unmodified\n");
6921 #endif
6922
6923         creation = GNUNET_TIME_absolute_get_difference(start,GNUNET_TIME_absolute_get());
6924         start = GNUNET_TIME_absolute_get();
6925
6926         if (ats->stat.valid == GNUNET_YES)
6927         {
6928                 ats->stat.solution = GNUNET_SYSERR;
6929                 ats_solve_problem(ats->max_iterations, ats->max_exec_duration.rel_value, ats->stat.c_peers, ats->stat.c_mechs, &ats->stat);
6930         }
6931         solving = GNUNET_TIME_absolute_get_difference(start,GNUNET_TIME_absolute_get());
6932
6933         if (ats->stat.valid == GNUNET_YES)
6934         {
6935 #if DEBUG_ATS
6936                         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",
6937                                         text, creation.rel_value, solving.rel_value,
6938                                         ats->stat.c_mechs,
6939                                         (ats->simplex_rerun_required == GNUNET_NO) ? " NO" : "YES");
6940 #endif
6941                 GNUNET_STATISTICS_set (stats, "ATS duration", solving.rel_value + creation.rel_value, GNUNET_NO);
6942                 GNUNET_STATISTICS_set (stats, "ATS mechanisms", ats->stat.c_mechs, GNUNET_NO);
6943                 GNUNET_STATISTICS_set (stats, "ATS peers", ats->stat.c_peers, GNUNET_NO);
6944                 GNUNET_STATISTICS_set (stats, "ATS solution", ats->stat.solution, GNUNET_NO);
6945                 GNUNET_STATISTICS_set (stats, "ATS timestamp", start.abs_value, GNUNET_NO);
6946
6947                 if ((ats->modified_addr == GNUNET_YES) || (ats->prob==NULL))
6948                         GNUNET_STATISTICS_set (stats, "ATS state",ATS_NEW, GNUNET_NO);
6949                 else if ((ats->modified_resources == GNUNET_YES) &&
6950                                 (ats->modified_quality == GNUNET_NO))
6951                         GNUNET_STATISTICS_set (stats, "ATS state", ATS_C_UPDATED, GNUNET_NO);
6952                 else if ((ats->modified_resources == GNUNET_NO) &&
6953                                 (ats->modified_quality == GNUNET_YES) &&
6954                                 (ats->simplex_rerun_required == GNUNET_NO))
6955                         GNUNET_STATISTICS_set (stats, "ATS state", ATS_Q_UPDATED, GNUNET_NO);
6956                 else if ((ats->modified_resources == GNUNET_YES) &&
6957                                 (ats->modified_quality == GNUNET_YES) &&
6958                                 (ats->simplex_rerun_required == GNUNET_NO))
6959                         GNUNET_STATISTICS_set (stats, "ATS state", ATS_QC_UPDATED, GNUNET_NO);
6960                 else if (ats->simplex_rerun_required == GNUNET_NO)
6961                         GNUNET_STATISTICS_set (stats, "ATS state", ATS_UNMODIFIED, GNUNET_NO);
6962         }
6963
6964         if ((ats->save_mlp == GNUNET_YES) && (ats->stat.c_mechs >= ats->dump_min_peers) && (ats->stat.c_mechs >= ats->dump_min_addr))
6965         {
6966                 char * filename;
6967                 if (ats->dump_overwrite == GNUNET_NO)
6968                 {
6969                         GNUNET_asprintf (&filename, "ats_mlp_p%i_m%i_%s_%llu.mlp",
6970                         ats->stat.c_peers, ats->stat.c_mechs, text, GNUNET_TIME_absolute_get().abs_value);
6971                         glp_write_lp (ats->prob, NULL, filename);
6972                 }
6973                 else
6974                 {
6975                         GNUNET_asprintf (&filename, "ats_mlp_p%i_m%i.mlp",
6976                         ats->stat.c_peers, ats->stat.c_mechs );
6977                         glp_write_lp (ats->prob, NULL, filename);
6978                 }
6979                 GNUNET_free (filename);
6980         }
6981         if ((ats->save_solution == GNUNET_YES) && (ats->stat.c_mechs >= ats->dump_min_peers) && (ats->stat.c_mechs >= ats->dump_min_addr))
6982         {
6983                 char * filename;
6984                 if (ats->dump_overwrite == GNUNET_NO)
6985                 {
6986                         GNUNET_asprintf (&filename, "ats_mlp_p%i_m%i_%s_%llu.sol",
6987                         ats->stat.c_peers, ats->stat.c_mechs, text, GNUNET_TIME_absolute_get().abs_value);
6988                         glp_print_sol (ats->prob, filename);
6989                 }
6990                 else
6991                 {
6992                         GNUNET_asprintf (&filename, "ats_mlp_p%i_m%i.sol",
6993                         ats->stat.c_peers, ats->stat.c_mechs);
6994                         glp_print_sol (ats->prob, filename);
6995                 }
6996                 GNUNET_free (filename);
6997         }
6998         ats->last = GNUNET_TIME_absolute_get();
6999         ats->modified_addr = GNUNET_NO;
7000         ats->modified_resources = GNUNET_NO;
7001         ats->modified_quality = GNUNET_NO;
7002 #endif
7003 }
7004
7005 static void
7006 ats_schedule_calculation (void *cls,
7007                           const struct GNUNET_SCHEDULER_TaskContext *tc)
7008 {
7009         struct ATS_info *ats = (struct ATS_info *) cls;
7010         if (ats==NULL) return;
7011
7012         ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
7013         if ( (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
7014             return;
7015
7016 #if DEBUG_ATS
7017         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Running scheduled calculation\n");
7018 #endif
7019
7020         ats_calculate_bandwidth_distribution (ats);
7021
7022         ats->ats_task = GNUNET_SCHEDULER_add_delayed (ats->exec_interval,
7023                                         &ats_schedule_calculation, ats);
7024 }
7025
7026 void ats_init ()
7027 {
7028         int c = 0;
7029         unsigned long long  value;
7030         char * section;
7031
7032         ats = GNUNET_malloc(sizeof (struct ATS_info));
7033
7034         ats->min_delta = ATS_MIN_INTERVAL;
7035         ats->exec_interval = ATS_EXEC_INTERVAL;
7036         ats->max_exec_duration = ATS_MAX_EXEC_DURATION;
7037         ats->max_iterations = ATS_MAX_ITERATIONS;
7038         ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
7039
7040 #if !HAVE_LIBGLPK
7041         GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "GLPK not installed, ATS not active\n");
7042         return;
7043 #endif
7044
7045         ats->D = 1.0;
7046         ats->U = 1.0;
7047         ats->R = 1.0;
7048         ats->v_b_min = 64000;
7049         ats->v_n_min = 10;
7050         ats->dump_min_peers = 1;
7051         ats->dump_min_addr = 1;
7052         ats->dump_overwrite = GNUNET_NO;
7053
7054 #if HAVE_LIBGLPK
7055         ats->prob = NULL;
7056 #endif
7057
7058         /* loading cost ressources */
7059         for (c=0; c<available_ressources; c++)
7060         {
7061                 GNUNET_asprintf(&section,"%s_UP",ressources[c].cfg_param);
7062                 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
7063                 {
7064                         if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg, "transport",section, &value))
7065                         {
7066 #if DEBUG_ATS
7067                                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found ressource cost: [%s] = %llu\n", section, value);
7068 #endif
7069                                 ressources[c].c_max = value;
7070                         }
7071                 }
7072                 GNUNET_free (section);
7073                 GNUNET_asprintf(&section,"%s_DOWN",ressources[c].cfg_param);
7074                 if (GNUNET_CONFIGURATION_have_value(cfg, "transport", section))
7075                 {
7076                         if (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number(cfg, "transport",section, &value))
7077                         {
7078 #if DEBUG_ATS
7079                                 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Found ressource cost: [%s] = %llu\n", section, value);
7080 #endif
7081                                 ressources[c].c_min = value;
7082                         }
7083                 }
7084                 GNUNET_free (section);
7085         }
7086
7087         if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_MLP"))
7088                 ats->save_mlp = GNUNET_CONFIGURATION_get_value_yesno (cfg, "transport","DUMP_MLP");
7089
7090         if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_SOLUTION"))
7091                 ats->save_solution = GNUNET_CONFIGURATION_get_value_yesno (cfg, "transport","DUMP_SOLUTION");
7092         if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_OVERWRITE"))
7093                 ats->dump_overwrite = GNUNET_CONFIGURATION_get_value_yesno (cfg, "transport","DUMP_OVERWRITE");
7094         if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_MIN_PEERS"))
7095         {
7096                 GNUNET_CONFIGURATION_get_value_number(cfg, "transport","DUMP_MIN_PEERS", &value);
7097                 ats->dump_min_peers= value;
7098         }
7099         if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_MIN_ADDRS"))
7100         {
7101                 GNUNET_CONFIGURATION_get_value_number(cfg, "transport","DUMP_MIN_ADDRS", &value);
7102                 ats->dump_min_addr= value;
7103         }
7104         if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "DUMP_OVERWRITE"))
7105         {
7106                 GNUNET_CONFIGURATION_get_value_number(cfg, "transport","DUMP_OVERWRITE", &value);
7107                 ats->min_delta.rel_value = value;
7108         }
7109
7110         if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "ATS_MIN_INTERVAL"))
7111         {
7112                 GNUNET_CONFIGURATION_get_value_number(cfg, "transport","ATS_MIN_INTERVAL", &value);
7113                 ats->min_delta.rel_value = value;
7114         }
7115
7116         if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "ATS_EXEC_INTERVAL"))
7117         {
7118                 GNUNET_CONFIGURATION_get_value_number(cfg, "transport","ATS_EXEC_INTERVAL", &value);
7119                 ats->exec_interval.rel_value = value;
7120         }
7121         if (GNUNET_CONFIGURATION_have_value(cfg, "transport", "ATS_MIN_INTERVAL"))
7122         {
7123                 GNUNET_CONFIGURATION_get_value_number(cfg, "transport","ATS_MIN_INTERVAL", &value);
7124                 ats->min_delta.rel_value = value;
7125         }
7126
7127         ats->ats_task = GNUNET_SCHEDULER_add_now(&ats_schedule_calculation, ats);
7128 }
7129
7130
7131 static void ats_shutdown ()
7132 {
7133 #if DEBUG_ATS
7134         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_destroy\n");
7135 #endif
7136         if (ats->ats_task != GNUNET_SCHEDULER_NO_TASK)
7137                 GNUNET_SCHEDULER_cancel(ats->ats_task);
7138         ats->ats_task = GNUNET_SCHEDULER_NO_TASK;
7139 #if HAVE_LIBGLPK
7140         ats_delete_problem ();
7141 #endif
7142         GNUNET_free (ats);
7143 }
7144
7145
7146 void ats_notify_peer_connect (
7147                 const struct GNUNET_PeerIdentity *peer,
7148                 const struct GNUNET_TRANSPORT_ATS_Information *ats_data, int ats_count)
7149 {
7150 #if DEBUG_ATS
7151         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_notify_peer_connect: %s\n",GNUNET_i2s(peer));
7152 #endif
7153
7154         //update_addr_ats();
7155         ats->modified_addr = GNUNET_YES;
7156
7157         ats_calculate_bandwidth_distribution(ats);
7158 }
7159
7160 void ats_notify_peer_disconnect (
7161                 const struct GNUNET_PeerIdentity *peer)
7162 {
7163 #if DEBUG_ATS
7164         GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "ats_notify_peer_disconnect: %s\n",GNUNET_i2s(peer));
7165 #endif
7166
7167         ats->modified_addr = GNUNET_YES;
7168
7169         ats_calculate_bandwidth_distribution (ats);
7170 }
7171
7172 struct ForeignAddressList * ats_get_preferred_address (
7173                 struct NeighbourList *n)
7174 {
7175 #if DEBUG_ATS
7176         //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "ats_get_prefered_transport for peer: %s\n",GNUNET_i2s(&n->id));
7177 #endif
7178         struct ReadyList *next = n->plugins;
7179         while (next != NULL)
7180         {
7181 #if DEBUG_ATS
7182                 //GNUNET_log (GNUNET_ERROR_TYPE_BULK, "plugin: %s %i\n",next->plugin->short_name,strcmp(next->plugin->short_name,"unix"));
7183 #endif
7184                 next = next->next;
7185         }
7186         return find_ready_address(n);
7187 }
7188
7189 /**
7190  * Initiate transport service.
7191  *
7192  * @param cls closure
7193  * @param server the initialized server
7194  * @param c configuration to use
7195  */
7196 static void
7197 run (void *cls,
7198      struct GNUNET_SERVER_Handle *server,
7199      const struct GNUNET_CONFIGURATION_Handle *c)
7200 {
7201   static const struct GNUNET_SERVER_MessageHandler handlers[] = {
7202     {&handle_start, NULL,
7203      GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)},
7204     {&handle_hello, NULL,
7205      GNUNET_MESSAGE_TYPE_HELLO, 0},
7206     {&handle_send, NULL,
7207      GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
7208     {&handle_request_connect, NULL,
7209      GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT, sizeof(struct TransportRequestConnectMessage)},
7210     {&handle_set_quota, NULL,
7211      GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
7212     {&handle_address_lookup, NULL,
7213      GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
7214      0},
7215     {&handle_blacklist_init, NULL,
7216      GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT, sizeof (struct GNUNET_MessageHeader)},
7217     {&handle_blacklist_reply, NULL,
7218      GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY, sizeof (struct BlacklistMessage)},
7219     {NULL, NULL, 0, 0}
7220   };
7221   char *plugs;
7222   char *pos;
7223   int no_transports;
7224   unsigned long long tneigh;
7225   char *keyfile;
7226
7227   cfg = c;
7228   stats = GNUNET_STATISTICS_create ("transport", cfg);
7229   validation_map = GNUNET_CONTAINER_multihashmap_create (64);
7230   /* parse configuration */
7231   if ((GNUNET_OK !=
7232        GNUNET_CONFIGURATION_get_value_number (c,
7233                                               "TRANSPORT",
7234                                               "NEIGHBOUR_LIMIT",
7235                                               &tneigh)) ||
7236       (GNUNET_OK !=
7237        GNUNET_CONFIGURATION_get_value_filename (c,
7238                                                 "GNUNETD",
7239                                                 "HOSTKEY", &keyfile)))
7240     {
7241       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
7242                   _
7243                   ("Transport service is lacking key configuration settings.  Exiting.\n"));
7244       GNUNET_SCHEDULER_shutdown ();
7245       if (stats != NULL)
7246         {
7247           GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
7248           stats = NULL;
7249         }
7250       GNUNET_CONTAINER_multihashmap_destroy (validation_map);
7251       validation_map = NULL;
7252       return;
7253     }
7254
7255   max_connect_per_transport = (uint32_t) tneigh;
7256   peerinfo = GNUNET_PEERINFO_connect (cfg);
7257   if (peerinfo == NULL)
7258     {
7259       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
7260                   _("Could not access PEERINFO service.  Exiting.\n"));
7261       GNUNET_SCHEDULER_shutdown ();
7262       if (stats != NULL)
7263         {
7264           GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
7265           stats = NULL;
7266         }
7267       GNUNET_CONTAINER_multihashmap_destroy (validation_map);
7268       validation_map = NULL;
7269       GNUNET_free (keyfile);
7270       return;
7271     }
7272   my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
7273   GNUNET_free (keyfile);
7274   if (my_private_key == NULL)
7275     {
7276       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
7277                   _
7278                   ("Transport service could not access hostkey.  Exiting.\n"));
7279       GNUNET_SCHEDULER_shutdown ();
7280       if (stats != NULL)
7281         {
7282           GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
7283           stats = NULL;
7284         }
7285       GNUNET_CONTAINER_multihashmap_destroy (validation_map);
7286       validation_map = NULL;
7287       return;
7288     }
7289   GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
7290   GNUNET_CRYPTO_hash (&my_public_key,
7291                       sizeof (my_public_key), &my_identity.hashPubKey);
7292   /* setup notification */
7293   GNUNET_SERVER_disconnect_notify (server,
7294                                    &client_disconnect_notification, NULL);
7295   /* load plugins... */
7296   no_transports = 1;
7297   if (GNUNET_OK ==
7298       GNUNET_CONFIGURATION_get_value_string (c,
7299                                              "TRANSPORT", "PLUGINS", &plugs))
7300     {
7301       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
7302                   _("Starting transport plugins `%s'\n"), plugs);
7303       pos = strtok (plugs, " ");
7304       while (pos != NULL)
7305         {
7306           start_transport (server, pos);
7307           no_transports = 0;
7308           pos = strtok (NULL, " ");
7309         }
7310       GNUNET_free (plugs);
7311     }
7312   GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
7313                                 &shutdown_task, NULL);
7314   if (no_transports)
7315     refresh_hello ();
7316
7317   ats_init();
7318
7319 #if DEBUG_TRANSPORT
7320   GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
7321 #endif
7322   /* If we have a blacklist file, read from it */
7323   read_blacklist_file(cfg);
7324   /* process client requests */
7325   GNUNET_SERVER_add_handlers (server, handlers);
7326 }
7327
7328
7329 /**
7330  * The main function for the transport service.
7331  *
7332  * @param argc number of arguments from the command line
7333  * @param argv command line arguments
7334  * @return 0 ok, 1 on error
7335  */
7336 int
7337 main (int argc, char *const *argv)
7338 {
7339   a2s (NULL, NULL, 0); /* make compiler happy */
7340   return (GNUNET_OK ==
7341           GNUNET_SERVICE_run (argc,
7342                               argv,
7343                               "transport",
7344                               GNUNET_SERVICE_OPTION_NONE,
7345                               &run, NULL)) ? 0 : 1;
7346 }
7347
7348 /* end of gnunet-service-transport.c */