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