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