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