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