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