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