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