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