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