towards better working transport code
[oweals/gnunet.git] / src / transport / gnunet-service-transport.c
1 /*
2      This file is part of GNUnet.
3      (C) 2009 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 2, 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  * NOTE:
27  * - This code uses 'GNUNET_a2s' for debug printing in many places,
28  *   which is technically wrong since it assumes we have IP+Port 
29  *   (v4/v6) addresses.  Once we add transports like http or smtp
30  *   this will have to be changed!
31  */
32 #include "platform.h"
33 #include "gnunet_client_lib.h"
34 #include "gnunet_container_lib.h"
35 #include "gnunet_constants.h"
36 #include "gnunet_getopt_lib.h"
37 #include "gnunet_hello_lib.h"
38 #include "gnunet_os_lib.h"
39 #include "gnunet_peerinfo_service.h"
40 #include "gnunet_plugin_lib.h"
41 #include "gnunet_protocols.h"
42 #include "gnunet_service_lib.h"
43 #include "gnunet_signatures.h"
44 #include "plugin_transport.h"
45 #include "transport.h"
46
47 /**
48  * How many messages can we have pending for a given client process
49  * before we start to drop incoming messages?  We typically should
50  * have only one client and so this would be the primary buffer for
51  * messages, so the number should be chosen rather generously.
52  *
53  * The expectation here is that most of the time the queue is large
54  * enough so that a drop is virtually never required.
55  */
56 #define MAX_PENDING 128
57
58 /**
59  * How often should we try to reconnect to a peer using a particular
60  * transport plugin before giving up?  Note that the plugin may be
61  * added back to the list after PLUGIN_RETRY_FREQUENCY expires.
62  */
63 #define MAX_CONNECT_RETRY 3
64
65 /**
66  * Limit on the number of ready-to-run tasks when validating 
67  * HELLOs.  If more tasks are ready to run, we will drop 
68  * HELLOs instead of validating them.
69  */
70 #define MAX_HELLO_LOAD 4
71
72 /**
73  * How often must a peer violate bandwidth quotas before we start
74  * to simply drop its messages?
75  */
76 #define QUOTA_VIOLATION_DROP_THRESHOLD 100
77
78 /**
79  * How long until a HELLO verification attempt should time out?
80  * Must be rather small, otherwise a partially successful HELLO
81  * validation (some addresses working) might not be available
82  * before a client's request for a connection fails for good.
83  * Besides, if a single request to an address takes a long time,
84  * then the peer is unlikely worthwhile anyway.
85  */
86 #define HELLO_VERIFICATION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
87
88 /**
89  * How long will we allow sending of a ping to be delayed?
90  */
91 #define TRANSPORT_DEFAULT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
92
93 /**
94  * FIXME: document!
95  */
96 #define TRANSPORT_DEFAULT_PRIORITY 4
97
98 /**
99  * How often do we re-add (cheaper) plugins to our list of plugins
100  * to try for a given connected peer?
101  */
102 #define PLUGIN_RETRY_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
103
104 /**
105  * After how long do we expire an address in a HELLO that we just
106  * validated?  This value is also used for our own addresses when we
107  * create a HELLO.
108  */
109 #define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
110
111
112 /**
113  * List of addresses of other peers
114  */
115 struct ForeignAddressList
116 {
117   /**
118    * This is a linked list.
119    */
120   struct ForeignAddressList *next;
121
122   /**
123    * Which ready list does this entry belong to.
124    */
125   struct ReadyList *ready_list;
126
127   /**
128    * How long until we auto-expire this address (unless it is
129    * re-confirmed by the transport)?
130    */
131   struct GNUNET_TIME_Absolute expires;
132
133   /**
134    * Length of addr.
135    */
136   size_t addrlen;
137
138   /**
139    * The address.
140    */
141   const void *addr;
142
143   /**
144    * What was the last latency observed for this plugin
145    * and peer?  Invalid if connected is GNUNET_NO.
146    */
147   struct GNUNET_TIME_Relative latency;
148
149   /**
150    * If we did not successfully transmit a message to the given peer
151    * via this connection during the specified time, we should consider
152    * the connection to be dead.  This is used in the case that a TCP
153    * transport simply stalls writing to the stream but does not
154    * formerly get a signal that the other peer died.
155    */
156   /* FIXME: Do we need this? */
157   struct GNUNET_TIME_Absolute timeout;
158
159   /**
160    * Is this plugin currently connected?  The first time we transmit
161    * or send data to a peer via a particular plugin, we set this to
162    * GNUNET_YES.  If we later get an error (disconnect notification or
163    * transmission failure), we set it back to GNUNET_NO.  Each time
164    * the value is set to GNUNET_YES, we increment the
165    * "connect_attempts" counter.  If that one reaches a particular
166    * threshold, we consider the address to not be working properly at
167    * this time and remove it from the eligible list.
168    */
169   int connected;
170
171   /**
172    * Is this plugin ready to transmit to the specific target?
173    * GNUNET_NO if not.  Initially, all plugins are marked ready.  If a
174    * transmission is in progress, "transmit_ready" is set to
175    * GNUNET_NO.
176    */
177   int transmit_ready;
178
179   /**
180    * Has this address been validated yet?
181    */
182   int validated;
183
184   /**
185    * How often have we tried to connect using this plugin?
186    */
187   unsigned int connect_attempts;
188
189 };
190
191
192 /**
193  * Entry in linked list of network addresses for ourselves.
194  */
195 struct OwnAddressList
196 {
197   /**
198    * This is a linked list.
199    */
200   struct OwnAddressList *next;
201
202   /**
203    * The address, actually a pointer to the end
204    * of this struct.  Do not free!
205    */
206   const void *addr;
207   
208   /**
209    * How long until we auto-expire this address (unless it is
210    * re-confirmed by the transport)?
211    */
212   struct GNUNET_TIME_Absolute expires;
213
214   /**
215    * Length of addr.
216    */
217   size_t addrlen;
218
219 };
220
221
222 /**
223  * Entry in linked list of all of our plugins.
224  */
225 struct TransportPlugin
226 {
227
228   /**
229    * This is a linked list.
230    */
231   struct TransportPlugin *next;
232
233   /**
234    * API of the transport as returned by the plugin's
235    * initialization function.
236    */
237   struct GNUNET_TRANSPORT_PluginFunctions *api;
238
239   /**
240    * Short name for the plugin (i.e. "tcp").
241    */
242   char *short_name;
243
244   /**
245    * Name of the library (i.e. "gnunet_plugin_transport_tcp").
246    */
247   char *lib_name;
248
249   /**
250    * List of our known addresses for this transport.
251    */
252   struct OwnAddressList *addresses;
253
254   /**
255    * Environment this transport service is using
256    * for this plugin.
257    */
258   struct GNUNET_TRANSPORT_PluginEnvironment env;
259
260   /**
261    * ID of task that is used to clean up expired addresses.
262    */
263   GNUNET_SCHEDULER_TaskIdentifier address_update_task;
264
265   /**
266    * Set to GNUNET_YES if we need to scrap the existing
267    * list of "addresses" and start fresh when we receive
268    * the next address update from a transport.  Set to
269    * GNUNET_NO if we should just add the new address
270    * to the list and wait for the commit call.
271    */
272   int rebuild;
273
274 };
275
276 struct NeighborList;
277
278 /**
279  * For each neighbor we keep a list of messages
280  * that we still want to transmit to the neighbor.
281  */
282 struct MessageQueue
283 {
284
285   /**
286    * This is a linked list.
287    */
288   struct MessageQueue *next;
289
290   /**
291    * The message(s) we want to transmit, GNUNET_MessageHeader(s)
292    * stuck together in memory.  Allocated at the end of this struct.
293    */
294   const char *message_buf;
295
296   /**
297    * Size of the message buf
298    */
299   size_t message_buf_size;
300
301   /**
302    * Client responsible for queueing the message;
303    * used to check that a client has no two messages
304    * pending for the same target.  Can be NULL.
305    */
306   struct TransportClient *client;
307
308   /**
309    * Using which specific address should we send this message?
310    */
311   struct ForeignAddressList *specific_address;
312
313   /**
314    * Peer ID of the Neighbor this entry belongs to.
315    */
316   struct GNUNET_PeerIdentity neighbor_id;
317
318   /**
319    * Plugin that we used for the transmission.
320    * NULL until we scheduled a transmission.
321    */
322   struct TransportPlugin *plugin;
323
324   /**
325    * Internal message of the transport system that should not be
326    * included in the usual SEND-SEND_OK transmission confirmation
327    * traffic management scheme.  Typically, "internal_msg" will
328    * be set whenever "client" is NULL (but it is not strictly
329    * required).
330    */
331   int internal_msg;
332
333   /**
334    * How important is the message?
335    */
336   unsigned int priority;
337
338 };
339
340
341 /**
342  * For a given Neighbor, which plugins are available
343  * to talk to this peer and what are their costs?
344  */
345 struct ReadyList
346 {
347   /**
348    * This is a linked list.
349    */
350   struct ReadyList *next;
351
352   /**
353    * Which of our transport plugins does this entry
354    * represent?
355    */
356   struct TransportPlugin *plugin;
357
358   /**
359    * Transport addresses, latency, and readiness for
360    * this particular plugin.
361    */
362   struct ForeignAddressList *addresses;
363
364   /**
365    * Is this plugin ready to transmit to the specific target?
366    * GNUNET_NO if not.  Initially, all plugins are marked ready.  If a
367    * transmission is in progress, "transmit_ready" is set to
368    * GNUNET_NO.
369    */
370   // FIXME: is this dead?
371   int plugin_transmit_ready;
372
373   /**
374    * Is the plugin represented by this entry currently connected to
375    * the respective peer?
376    */
377   int connected;
378
379 };
380
381
382 /**
383  * Entry in linked list of all of our current neighbors.
384  */
385 struct NeighborList
386 {
387
388   /**
389    * This is a linked list.
390    */
391   struct NeighborList *next;
392
393   /**
394    * Which of our transports is connected to this peer
395    * and what is their status?
396    */
397   struct ReadyList *plugins;
398
399   /**
400    * List of messages we would like to send to this peer;
401    * must contain at most one message per client.
402    */
403   struct MessageQueue *messages;
404
405   /**
406    * Identity of this neighbor.
407    */
408   struct GNUNET_PeerIdentity id;
409
410   /**
411    * ID of task scheduled to run when this peer is about to
412    * time out (will free resources associated with the peer).
413    */
414   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
415
416   /**
417    * How long until we should consider this peer dead
418    * (if we don't receive another message in the
419    * meantime)?
420    */
421   struct GNUNET_TIME_Absolute peer_timeout;
422
423   /**
424    * At what time did we reset last_received last?
425    */
426   struct GNUNET_TIME_Absolute last_quota_update;
427
428   /**
429    * The latency we have seen for this particular address for
430    * this particular peer.  This latency may have been calculated
431    * over multiple transports.  This value reflects how long it took
432    * us to receive a response when SENDING via this particular
433    * transport/neighbor/address combination!
434    * FIXME: why is this NBO?
435    */
436   struct GNUNET_TIME_RelativeNBO latency;
437
438   /**
439    * How many bytes have we received since the "last_quota_update"
440    * timestamp?
441    */
442   uint64_t last_received;
443
444   /**
445    * Global quota for inbound traffic for the neighbor in bytes/ms.
446    */
447   uint32_t quota_in;
448
449   /**
450    * How often has the other peer (recently) violated the
451    * inbound traffic limit?  Incremented by 10 per violation,
452    * decremented by 1 per non-violation (for each
453    * time interval).
454    */
455   unsigned int quota_violation_count;
456
457   /**
458    * Have we seen an ACK from this neighbor in the past?
459    * (used to make up a fake ACK for clients connecting after
460    * the neighbor connected to us).
461    */
462   int received_pong;
463
464 };
465
466 /**
467  * Message used to ask a peer to validate receipt (to check an address
468  * from a HELLO).  Followed by the address used.  Note that the
469  * recipients response does not affirm that he has this address,
470  * only that he got the challenge message.
471  */
472 struct TransportPingMessage
473 {
474
475   /**
476    * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
477    */
478   struct GNUNET_MessageHeader header;
479
480   /**
481    * Random challenge number (in network byte order).
482    */
483   uint32_t challenge GNUNET_PACKED;
484
485   /**
486    * Who is the intended recipient?
487    */
488   struct GNUNET_PeerIdentity target;
489
490 };
491
492
493 /**
494  * Message used to validate a HELLO.  The challenge is included in the
495  * confirmation to make matching of replies to requests possible.  The
496  * signature signs the original challenge number, our public key, the
497  * sender's address (so that the sender can check that the address we
498  * saw is plausible for him and possibly detect a MiM attack) and a
499  * timestamp (to limit replay).<p>
500  *
501  * This message is followed by the address of the
502  * client that we are observing (which is part of what
503  * is being signed).
504  */
505 struct TransportPongMessage
506 {
507
508   /**
509    * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
510    */
511   struct GNUNET_MessageHeader header;
512
513   /**
514    * For padding, always zero.
515    */
516   uint32_t reserved GNUNET_PACKED;
517
518   /**
519    * Signature.
520    */
521   struct GNUNET_CRYPTO_RsaSignature signature;
522
523   /**
524    * What are we signing and why?
525    */
526   struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
527
528   /**
529    * Random challenge number (in network byte order).
530    */
531   uint32_t challenge GNUNET_PACKED;
532
533   /**
534    * Who signed this message?
535    */
536   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded signer;
537
538   /**
539    * Size of address appended to this message
540    */
541   size_t addrlen;
542
543 };
544
545 /**
546  * Linked list of messages to be transmitted to
547  * the client.  Each entry is followed by the
548  * actual message.
549  */
550 struct ClientMessageQueueEntry
551 {
552   /**
553    * This is a linked list.
554    */
555   struct ClientMessageQueueEntry *next;
556 };
557
558
559 /**
560  * Client connected to the transport service.
561  */
562 struct TransportClient
563 {
564
565   /**
566    * This is a linked list.
567    */
568   struct TransportClient *next;
569
570   /**
571    * Handle to the client.
572    */
573   struct GNUNET_SERVER_Client *client;
574
575   /**
576    * Linked list of messages yet to be transmitted to
577    * the client.
578    */
579   struct ClientMessageQueueEntry *message_queue_head;
580
581   /**
582    * Tail of linked list of messages yet to be transmitted to the
583    * client.
584    */
585   struct ClientMessageQueueEntry *message_queue_tail;
586
587   /**
588    * Is a call to "transmit_send_continuation" pending?  If so, we
589    * must not free this struct (even if the corresponding client
590    * disconnects) and instead only remove it from the linked list and
591    * set the "client" field to NULL.
592    */
593   int tcs_pending;
594
595   /**
596    * Length of the list of messages pending for this client.
597    */
598   unsigned int message_count;
599
600 };
601
602
603 /**
604  * Entry in map of all HELLOs awaiting validation.
605  */
606 struct ValidationEntry
607 {
608
609   /**
610    * The address, actually a pointer to the end
611    * of this struct.  Do not free!
612    */
613   const void *addr;
614
615   /**
616    * Name of the transport.
617    */
618   char *transport_name;
619
620   /**
621    * The public key of the peer.
622    */
623   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
624
625   /**
626    * ID of task that will clean up this entry if we don't succeed
627    * with the validation first.
628    */
629   GNUNET_SCHEDULER_TaskIdentifier timeout_task;
630
631   /**
632    * At what time did we send this validation?
633    */
634   struct GNUNET_TIME_Absolute send_time;
635
636   /**
637    * Length of addr.
638    */
639   size_t addrlen;
640
641   /**
642    * Challenge number we used.
643    */
644   uint32_t challenge;
645
646 };
647
648
649 /**
650  * Context of currently active requests to peerinfo
651  * for validation of HELLOs.
652  */
653 struct CheckHelloValidatedContext
654 {
655
656   /**
657    * This is a doubly-linked list.
658    */
659   struct CheckHelloValidatedContext *next;
660
661   /**
662    * This is a doubly-linked list.
663    */
664   struct CheckHelloValidatedContext *prev;
665
666   /**
667    * Hello that we are validating.
668    */
669   const struct GNUNET_HELLO_Message *hello;
670
671   /**
672    * Context for peerinfo iteration.
673    * NULL after we are done processing peerinfo's information.
674    */
675   struct GNUNET_PEERINFO_IteratorContext *piter;
676   
677   /**
678    * Was a HELLO known for this peer to peerinfo?
679    */
680   int hello_known;
681
682 };
683
684
685 /**
686  * Our HELLO message.
687  */
688 static struct GNUNET_HELLO_Message *our_hello;
689
690 /**
691  * "version" of "our_hello".  Used to see if a given neighbor has
692  * already been sent the latest version of our HELLO message.
693  */
694 static unsigned int our_hello_version;
695
696 /**
697  * Our public key.
698  */
699 static struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded my_public_key;
700
701 /**
702  * Our identity.
703  */
704 static struct GNUNET_PeerIdentity my_identity;
705
706 /**
707  * Our private key.
708  */
709 static struct GNUNET_CRYPTO_RsaPrivateKey *my_private_key;
710
711 /**
712  * Our scheduler.
713  */
714 struct GNUNET_SCHEDULER_Handle *sched;
715
716 /**
717  * Our configuration.
718  */
719 const struct GNUNET_CONFIGURATION_Handle *cfg;
720
721 /**
722  * Linked list of all clients to this service.
723  */
724 static struct TransportClient *clients;
725
726 /**
727  * All loaded plugins.
728  */
729 static struct TransportPlugin *plugins;
730
731 /**
732  * Our server.
733  */
734 static struct GNUNET_SERVER_Handle *server;
735
736 /**
737  * All known neighbors and their HELLOs.
738  */
739 static struct NeighborList *neighbors;
740
741 /**
742  * Number of neighbors we'd like to have.
743  */
744 static uint32_t max_connect_per_transport;
745
746 /**
747  * Head of linked list.
748  */
749 static struct CheckHelloValidatedContext *chvc_head;
750
751 /**
752  * Tail of linked list.
753  */
754 static struct CheckHelloValidatedContext *chvc_tail;
755
756
757 /**
758  * Map of PeerIdentities to 'struct ValidationEntry*'s (addresses
759  * of the given peer that we are currently validating).
760  */
761 static struct GNUNET_CONTAINER_MultiHashMap *validation_map;
762
763
764
765 /**
766  * The peer specified by the given neighbor has timed-out or a plugin
767  * has disconnected.  We may either need to do nothing (other plugins
768  * still up), or trigger a full disconnect and clean up.  This
769  * function updates our state and do the necessary notifications.
770  * Also notifies our clients that the neighbor is now officially
771  * gone.
772  *
773  * @param n the neighbor list entry for the peer
774  * @param check should we just check if all plugins
775  *        disconnected or must we ask all plugins to
776  *        disconnect?
777  */
778 static void disconnect_neighbor (struct NeighborList *n, int check);
779
780 /**
781  * Check the ready list for the given neighbor and if a plugin is
782  * ready for transmission (and if we have a message), do so!
783  *
784  * @param neighbor target peer for which to transmit
785  */
786 static void try_transmission_to_peer (struct NeighborList *neighbor);
787
788
789 /**
790  * Find an entry in the neighbor list for a particular peer.
791  * if sender_address is not specified (NULL) then return the
792  * first matching entry.  If sender_address is specified, then
793  * make sure that the address and address_len also matches.
794  *
795  * @return NULL if not found.
796  */
797 static struct NeighborList *
798 find_neighbor (const struct GNUNET_PeerIdentity *key)
799 {
800   struct NeighborList *head = neighbors;
801
802   while ((head != NULL) &&
803         (0 != memcmp (key, &head->id, sizeof (struct GNUNET_PeerIdentity))))
804     head = head->next;
805   return head;
806 }
807
808
809 /**
810  * Find an entry in the transport list for a particular transport.
811  *
812  * @return NULL if not found.
813  */
814 static struct TransportPlugin *
815 find_transport (const char *short_name)
816 {
817   struct TransportPlugin *head = plugins;
818   while ((head != NULL) && (0 != strcmp (short_name, head->short_name)))
819     head = head->next;
820   return head;
821 }
822
823
824 /**
825  * Update the quota values for the given neighbor now.
826  */
827 static void
828 update_quota (struct NeighborList *n)
829 {
830   struct GNUNET_TIME_Relative delta;
831   uint64_t allowed;
832   uint64_t remaining;
833
834   delta = GNUNET_TIME_absolute_get_duration (n->last_quota_update);
835   if (delta.value < MIN_QUOTA_REFRESH_TIME)
836     return;                     /* not enough time passed for doing quota update */
837   allowed = delta.value * n->quota_in;
838
839   if (n->last_received < allowed)
840     {
841       remaining = allowed - n->last_received;
842       if (n->quota_in > 0)
843         remaining /= n->quota_in;
844       else
845         remaining = 0;
846       if (remaining > MAX_BANDWIDTH_CARRY)
847         remaining = MAX_BANDWIDTH_CARRY;
848       n->last_received = 0;
849       n->last_quota_update = GNUNET_TIME_absolute_get ();
850       n->last_quota_update.value -= remaining;
851       if (n->quota_violation_count > 0)
852         n->quota_violation_count--;
853     }
854   else
855     {
856       n->last_received -= allowed;
857       n->last_quota_update = GNUNET_TIME_absolute_get ();
858       if (n->last_received > allowed)
859         {
860           /* more than twice the allowed rate! */
861           n->quota_violation_count += 10;
862         }
863     }
864 }
865
866
867 /**
868  * Function called to notify a client about the socket being ready to
869  * queue more data.  "buf" will be NULL and "size" zero if the socket
870  * was closed for writing in the meantime.
871  *
872  * @param cls closure
873  * @param size number of bytes available in buf
874  * @param buf where the callee should write the message
875  * @return number of bytes written to buf
876  */
877 static size_t
878 transmit_to_client_callback (void *cls, size_t size, void *buf)
879 {
880   struct TransportClient *client = cls;
881   struct ClientMessageQueueEntry *q;
882   uint16_t msize;
883   size_t tsize;
884   const struct GNUNET_MessageHeader *msg;
885   struct GNUNET_CONNECTION_TransmitHandle *th;
886   char *cbuf;
887
888   if (buf == NULL)
889     {
890       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
891                   "Transmission to client failed, closing connection.\n");
892       /* fatal error with client, free message queue! */
893       while (NULL != (q = client->message_queue_head))
894         {
895           client->message_queue_head = q->next;
896           GNUNET_free (q);
897         }
898       client->message_queue_tail = NULL;
899       client->message_count = 0;
900       return 0;
901     }
902   cbuf = buf;
903   tsize = 0;
904   while (NULL != (q = client->message_queue_head))
905     {
906       msg = (const struct GNUNET_MessageHeader *) &q[1];
907       msize = ntohs (msg->size);
908       if (msize + tsize > size)
909         break;
910 #if DEBUG_TRANSPORT
911       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
912                   "Transmitting message of type %u to client.\n",
913                   ntohs (msg->type));
914 #endif
915       client->message_queue_head = q->next;
916       if (q->next == NULL)
917         client->message_queue_tail = NULL;
918       memcpy (&cbuf[tsize], msg, msize);
919       tsize += msize;
920       GNUNET_free (q);
921       client->message_count--;
922     }
923   if (NULL != q)
924     {
925       GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
926       th = GNUNET_SERVER_notify_transmit_ready (client->client,
927                                                 msize,
928                                                 GNUNET_TIME_UNIT_FOREVER_REL,
929                                                 &transmit_to_client_callback,
930                                                 client);
931       GNUNET_assert (th != NULL);
932     }
933   return tsize;
934 }
935
936
937 /**
938  * Send the specified message to the specified client.  Since multiple
939  * messages may be pending for the same client at a time, this code
940  * makes sure that no message is lost.
941  *
942  * @param client client to transmit the message to
943  * @param msg the message to send
944  * @param may_drop can this message be dropped if the
945  *        message queue for this client is getting far too large?
946  */
947 static void
948 transmit_to_client (struct TransportClient *client,
949                     const struct GNUNET_MessageHeader *msg, int may_drop)
950 {
951   struct ClientMessageQueueEntry *q;
952   uint16_t msize;
953   struct GNUNET_CONNECTION_TransmitHandle *th;
954
955   if ((client->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
956     {
957       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
958                   _
959                   ("Dropping message, have %u messages pending (%u is the soft limit)\n"),
960                   client->message_count, MAX_PENDING);
961       /* TODO: call to statistics... */
962       return;
963     }
964   client->message_count++;
965   msize = ntohs (msg->size);
966   GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
967   q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
968   memcpy (&q[1], msg, msize);
969   /* append to message queue */
970   if (client->message_queue_tail == NULL)
971     {
972       client->message_queue_tail = q;
973     }
974   else
975     {
976       client->message_queue_tail->next = q;
977       client->message_queue_tail = q;
978     }
979   if (client->message_queue_head == NULL)
980     {
981       client->message_queue_head = q;
982       th = GNUNET_SERVER_notify_transmit_ready (client->client,
983                                                 msize,
984                                                 GNUNET_TIME_UNIT_FOREVER_REL,
985                                                 &transmit_to_client_callback,
986                                                 client);
987       GNUNET_assert (th != NULL);
988     }
989 }
990
991
992 /**
993  * Function called by the GNUNET_TRANSPORT_TransmitFunction
994  * upon "completion" of a send request.  This tells the API
995  * that it is now legal to send another message to the given
996  * peer.
997  *
998  * @param cls closure, identifies the entry on the
999  *            message queue that was transmitted and the
1000  *            client responsible for queueing the message
1001  * @param target the peer receiving the message
1002  * @param result GNUNET_OK on success, if the transmission
1003  *           failed, we should not tell the client to transmit
1004  *           more messages
1005  */
1006 static void
1007 transmit_send_continuation (void *cls,
1008                             const struct GNUNET_PeerIdentity *target,
1009                             int result)
1010 {
1011   struct MessageQueue *mq = cls;
1012   /*struct ReadyList *rl;*/ /* We no longer use the ReadyList for anything here, safe to remove? */
1013   struct SendOkMessage send_ok_msg;
1014   struct NeighborList *n;
1015
1016   GNUNET_assert (mq != NULL);
1017   n = find_neighbor(&mq->neighbor_id);
1018   if (n == NULL) /* Neighbor must have been removed asynchronously! */
1019     return;
1020
1021   /* Otherwise, let's make sure we've got the right peer */
1022   GNUNET_assert (0 ==
1023                  memcmp (&n->id, target,
1024                          sizeof (struct GNUNET_PeerIdentity)));
1025
1026   if (result == GNUNET_OK)
1027     {
1028       mq->specific_address->timeout =
1029         GNUNET_TIME_relative_to_absolute
1030         (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1031     }
1032   else
1033     {
1034       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1035                   "Transmission to peer `%s' failed, marking connection as down.\n",
1036                   GNUNET_i2s (target));
1037       mq->specific_address->connected = GNUNET_NO;
1038     }
1039   if (!mq->internal_msg)
1040     {
1041 #if DEBUG_TRANSPORT
1042       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1043                   "Setting transmit_ready on transport!\n");
1044 #endif
1045       mq->specific_address->transmit_ready = GNUNET_YES;
1046     }
1047
1048   if (mq->client != NULL)
1049     {
1050       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1051                   "Notifying client %p about transmission to peer `%4s'.\n",
1052                   mq->client, GNUNET_i2s (target));
1053       send_ok_msg.header.size = htons (sizeof (send_ok_msg));
1054       send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
1055       send_ok_msg.success = htonl (result);
1056       send_ok_msg.peer = n->id;
1057       transmit_to_client (mq->client, &send_ok_msg.header, GNUNET_NO);
1058     }
1059   GNUNET_free (mq);
1060   /* one plugin just became ready again, try transmitting
1061      another message (if available) */
1062   if (result == GNUNET_OK)
1063     try_transmission_to_peer (n);
1064   else
1065     disconnect_neighbor (n, GNUNET_YES);
1066 }
1067
1068
1069 /**
1070  * Find an address in any of the available transports for
1071  * the given neighbor that would be good for message
1072  * transmission.  This is essentially the transport selection
1073  * routine.
1074  *
1075  * @param neighbor for whom to select an address
1076  * @return selected address, NULL if we have none
1077  */
1078 struct ForeignAddressList *
1079 find_ready_address(struct NeighborList *neighbor)
1080 {
1081   struct ReadyList *head = neighbor->plugins;
1082   struct ForeignAddressList *addresses;
1083   struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
1084   struct ForeignAddressList *best_address;
1085
1086   best_address = NULL;
1087   while (head != NULL)
1088     {
1089       addresses = head->addresses;
1090       while (addresses != NULL)
1091         {
1092           if ( (addresses->timeout.value < now.value) && 
1093                (addresses->connected == GNUNET_YES) )
1094             {
1095 #if DEBUG_TRANSPORT
1096               GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1097                           "Marking long-time inactive connection to `%4s' as down.\n",
1098                           GNUNET_i2s (&neighbor->id));
1099 #endif
1100               addresses->connected = GNUNET_NO;
1101             }
1102           addresses = addresses->next;
1103         }
1104
1105       addresses = head->addresses;
1106       while (addresses != NULL)
1107         {
1108           if ( ( (best_address == NULL) || 
1109                  (addresses->connected == GNUNET_YES) ||
1110                  (best_address->connected == GNUNET_NO) ) &&
1111                (addresses->transmit_ready == GNUNET_YES) &&
1112                ( (best_address == NULL) || 
1113                  (addresses->latency.value < best_address->latency.value)) )
1114             best_address = addresses;            
1115           /* FIXME: also give lower-latency addresses that are not
1116              connected a chance some times... */
1117           addresses = addresses->next;
1118         }
1119       head = head->next;
1120     }
1121 #if DEBUG_TRANSPORT
1122   if (best_address != NULL)
1123     {
1124       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1125                   "Best address found has latency of %llu ms.\n",
1126                   best_address->latency.value);
1127     }
1128 #endif
1129   return best_address;
1130
1131 }
1132
1133
1134 /**
1135  * Check the ready list for the given neighbor and if a plugin is
1136  * ready for transmission (and if we have a message), do so!
1137  *
1138  * @param neighbor target peer for which to transmit
1139  */
1140 static void
1141 try_transmission_to_peer (struct NeighborList *neighbor)
1142 {
1143   struct GNUNET_TIME_Relative min_latency;
1144   struct ReadyList *rl;
1145   struct MessageQueue *mq;
1146
1147   if (neighbor->messages == NULL)
1148     return;                     /* nothing to do */
1149   min_latency = GNUNET_TIME_UNIT_FOREVER_REL;
1150   rl = NULL;
1151   mq = neighbor->messages;
1152   if (mq->specific_address == NULL)
1153     mq->specific_address = find_ready_address(neighbor); 
1154   if (mq->specific_address == NULL)
1155     {
1156 #if DEBUG_TRANSPORT
1157       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1158                   "No destination address available to transmit message of size %u to peer `%4s'\n",
1159                   mq->message_buf_size,
1160                   GNUNET_i2s (&mq->neighbor_id));
1161 #endif
1162       return;                   /* nobody ready */
1163     }
1164   rl = mq->specific_address->ready_list;
1165   neighbor->messages = mq->next;
1166   mq->plugin = rl->plugin;
1167   if (!mq->internal_msg)
1168     mq->specific_address->transmit_ready = GNUNET_NO;
1169 #if DEBUG_TRANSPORT
1170   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1171               "Sending message of size %u for `%4s' to `%s' via plugin `%s'\n",
1172               mq->message_buf_size,
1173               GNUNET_i2s (&neighbor->id), 
1174               GNUNET_a2s (mq->specific_address->addr,
1175                           mq->specific_address->addrlen),
1176               rl->plugin->short_name);
1177 #endif
1178   rl->plugin->api->send (rl->plugin->api->cls,
1179                          &mq->neighbor_id,
1180                          mq->message_buf,
1181                          mq->message_buf_size,
1182                          mq->priority,
1183                          GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1184                          mq->specific_address->addr,
1185                          mq->specific_address->addrlen,
1186                          GNUNET_YES /* FIXME: sometimes, we want to be more tolerant here! */,
1187                          &transmit_send_continuation, mq);
1188 }
1189
1190
1191 /**
1192  * Send the specified message to the specified peer.
1193  *
1194  * @param client source of the transmission request (can be NULL)
1195  * @param peer_address ForeignAddressList where we should send this message
1196  * @param priority how important is the message
1197  * @param message_buf message(s) to send GNUNET_MessageHeader(s)
1198  * @param message_buf_size total size of all messages in message_buf
1199  * @param is_internal is this an internal message
1200  * @param neighbor handle to the neighbor for transmission
1201  */
1202 static void
1203 transmit_to_peer (struct TransportClient *client,
1204                   struct ForeignAddressList *peer_address,
1205                   unsigned int priority,
1206                   const char *message_buf,
1207                   size_t message_buf_size,
1208                   int is_internal, struct NeighborList *neighbor)
1209 {
1210   struct MessageQueue *mq;
1211   struct MessageQueue *mqe;
1212
1213   if (client != NULL)
1214     {
1215       /* check for duplicate submission */
1216       mq = neighbor->messages;
1217       while (NULL != mq)
1218         {
1219           if (mq->client == client)
1220             {
1221               /* client transmitted to same peer twice
1222                  before getting SendOk! */
1223               GNUNET_break (0);
1224               return;
1225             }
1226           mq = mq->next;
1227         }
1228     }
1229   mq = GNUNET_malloc (sizeof (struct MessageQueue) + message_buf_size);
1230   mq->specific_address = peer_address;
1231   mq->client = client;
1232   memcpy (&mq[1], message_buf, message_buf_size);
1233   mq->message_buf = (const char*) &mq[1];
1234   mq->message_buf_size = message_buf_size;
1235   memcpy(&mq->neighbor_id, &neighbor->id, sizeof(struct GNUNET_PeerIdentity));
1236   mq->internal_msg = is_internal;
1237   mq->priority = priority;
1238
1239   if (is_internal)
1240     {
1241       /* append at head */
1242       mq->next = neighbor->messages;
1243       neighbor->messages = mq;
1244     }
1245   else
1246     {
1247       /* find tail */
1248       mqe = neighbor->messages;
1249       if (mqe != NULL)
1250         while (mqe->next != NULL)
1251           mqe = mqe->next;
1252       if (mqe == NULL)
1253         {
1254           /* new head */
1255           neighbor->messages = mq;
1256         }
1257       else
1258         {
1259           /* append */
1260           mqe->next = mq;
1261         }
1262     }
1263   try_transmission_to_peer (neighbor);
1264 }
1265
1266
1267 /**
1268  * FIXME: document.
1269  */
1270 struct GeneratorContext
1271 {
1272   struct TransportPlugin *plug_pos;
1273   struct OwnAddressList *addr_pos;
1274   struct GNUNET_TIME_Absolute expiration;
1275 };
1276
1277
1278 /**
1279  * FIXME: document.
1280  */
1281 static size_t
1282 address_generator (void *cls, size_t max, void *buf)
1283 {
1284   struct GeneratorContext *gc = cls;
1285   size_t ret;
1286
1287   while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
1288     {
1289       gc->plug_pos = gc->plug_pos->next;
1290       gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
1291     }
1292   if (NULL == gc->plug_pos)
1293     {
1294
1295       return 0;
1296     }
1297   ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
1298                                   gc->expiration,
1299                                   gc->addr_pos->addr,
1300                                   gc->addr_pos->addrlen, buf, max);
1301   gc->addr_pos = gc->addr_pos->next;
1302   return ret;
1303 }
1304
1305
1306 /**
1307  * Construct our HELLO message from all of the addresses of
1308  * all of the transports.
1309  */
1310 static void
1311 refresh_hello ()
1312 {
1313   struct GNUNET_HELLO_Message *hello;
1314   struct TransportClient *cpos;
1315   struct NeighborList *npos;
1316   struct GeneratorContext gc;
1317
1318   gc.plug_pos = plugins;
1319   gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
1320   gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1321   hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
1322 #if DEBUG_TRANSPORT
1323   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1324               "Refreshed my `%s', new size is %d\n", "HELLO", GNUNET_HELLO_size(hello));
1325 #endif
1326   cpos = clients;
1327   while (cpos != NULL)
1328     {
1329       transmit_to_client (cpos,
1330                           (const struct GNUNET_MessageHeader *) hello,
1331                           GNUNET_NO);
1332       cpos = cpos->next;
1333     }
1334
1335   GNUNET_free_non_null (our_hello);
1336   our_hello = hello;
1337   our_hello_version++;
1338   GNUNET_PEERINFO_add_peer (cfg, sched, &my_identity, our_hello);
1339   npos = neighbors;
1340   while (npos != NULL)
1341     {
1342 #if DEBUG_TRANSPORT
1343       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1344                   "Transmitting updated `%s' to neighbor `%4s'\n",
1345                   "HELLO", GNUNET_i2s (&npos->id));
1346 #endif
1347       transmit_to_peer (NULL, NULL, 0,
1348                         (const char *) our_hello, 
1349                         GNUNET_HELLO_size(our_hello),
1350                         GNUNET_NO, npos);
1351       npos = npos->next;
1352     }
1353 }
1354
1355
1356 /**
1357  * Task used to clean up expired addresses for a plugin.
1358  *
1359  * @param cls closure
1360  * @param tc context
1361  */
1362 static void
1363 expire_address_task (void *cls,
1364                      const struct GNUNET_SCHEDULER_TaskContext *tc);
1365
1366
1367 /**
1368  * Update the list of addresses for this plugin,
1369  * expiring those that are past their expiration date.
1370  *
1371  * @param plugin addresses of which plugin should be recomputed?
1372  * @param fresh set to GNUNET_YES if a new address was added
1373  *        and we need to regenerate the HELLO even if nobody
1374  *        expired
1375  */
1376 static void
1377 update_addresses (struct TransportPlugin *plugin, int fresh)
1378 {
1379   struct GNUNET_TIME_Relative min_remaining;
1380   struct GNUNET_TIME_Relative remaining;
1381   struct GNUNET_TIME_Absolute now;
1382   struct OwnAddressList *pos;
1383   struct OwnAddressList *prev;
1384   struct OwnAddressList *next;
1385   int expired;
1386
1387   if (plugin->address_update_task != GNUNET_SCHEDULER_NO_TASK)
1388     GNUNET_SCHEDULER_cancel (plugin->env.sched, plugin->address_update_task);
1389   plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1390   now = GNUNET_TIME_absolute_get ();
1391   min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
1392   expired = GNUNET_NO;
1393   prev = NULL;
1394   pos = plugin->addresses;
1395   while (pos != NULL)
1396     {
1397       next = pos->next;
1398       if (pos->expires.value < now.value)
1399         {
1400           expired = GNUNET_YES;
1401           if (prev == NULL)
1402             plugin->addresses = pos->next;
1403           else
1404             prev->next = pos->next;
1405           GNUNET_free (pos);
1406         }
1407       else
1408         {
1409           remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
1410           if (remaining.value < min_remaining.value)
1411             min_remaining = remaining;
1412           prev = pos;
1413         }
1414       pos = next;
1415     }
1416
1417   if (expired || fresh)
1418     refresh_hello ();
1419   if (min_remaining.value < GNUNET_TIME_UNIT_FOREVER_REL.value)
1420     plugin->address_update_task
1421       = GNUNET_SCHEDULER_add_delayed (plugin->env.sched,
1422                                       min_remaining,
1423                                       &expire_address_task, plugin);
1424
1425 }
1426
1427
1428 /**
1429  * Task used to clean up expired addresses for a plugin.
1430  *
1431  * @param cls closure
1432  * @param tc context
1433  */
1434 static void
1435 expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1436 {
1437   struct TransportPlugin *plugin = cls;
1438   plugin->address_update_task = GNUNET_SCHEDULER_NO_TASK;
1439   update_addresses (plugin, GNUNET_NO);
1440 }
1441
1442
1443 /**
1444  * Function that must be called by each plugin to notify the
1445  * transport service about the addresses under which the transport
1446  * provided by the plugin can be reached.
1447  *
1448  * @param cls closure
1449  * @param name name of the transport that generated the address
1450  * @param addr one of the addresses of the host, NULL for the last address
1451  *        the specific address format depends on the transport
1452  * @param addrlen length of the address
1453  * @param expires when should this address automatically expire?
1454  */
1455 static void
1456 plugin_env_notify_address (void *cls,
1457                            const char *name,
1458                            const void *addr,
1459                            size_t addrlen,
1460                            struct GNUNET_TIME_Relative expires)
1461 {
1462   struct TransportPlugin *p = cls;
1463   struct OwnAddressList *al;
1464   struct GNUNET_TIME_Absolute abex;
1465
1466   abex = GNUNET_TIME_relative_to_absolute (expires);
1467   GNUNET_assert (p == find_transport (name));
1468
1469   al = p->addresses;
1470   while (al != NULL)
1471     {
1472       if ((addrlen == al->addrlen) && (0 == memcmp (addr, &al[1], addrlen)))
1473         {
1474           if (al->expires.value < abex.value)
1475             al->expires = abex;
1476           return;
1477         }
1478       al = al->next;
1479     }
1480
1481   al = GNUNET_malloc (sizeof (struct OwnAddressList) + addrlen);
1482   al->addr = &al[1];
1483   al->next = p->addresses;
1484   p->addresses = al;
1485   al->expires = abex;
1486   al->addrlen = addrlen;
1487   memcpy (&al[1], addr, addrlen);
1488   update_addresses (p, GNUNET_YES);
1489 }
1490
1491
1492 /**
1493  * Notify all of our clients about a peer connecting.
1494  */
1495 static void
1496 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
1497                         struct GNUNET_TIME_Relative latency)
1498 {
1499   struct ConnectInfoMessage cim;
1500   struct TransportClient *cpos;
1501
1502   cim.header.size = htons (sizeof (struct ConnectInfoMessage));
1503   cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
1504   cim.quota_out = htonl (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT / (60 * 1000));
1505   cim.latency = GNUNET_TIME_relative_hton (latency);
1506   memcpy (&cim.id, peer, sizeof (struct GNUNET_PeerIdentity));
1507   cpos = clients;
1508   while (cpos != NULL)
1509     {
1510       transmit_to_client (cpos, &cim.header, GNUNET_NO);
1511       cpos = cpos->next;
1512     }
1513 }
1514
1515
1516 /**
1517  * Notify all of our clients about a peer disconnecting.
1518  */
1519 static void
1520 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
1521 {
1522   struct DisconnectInfoMessage dim;
1523   struct TransportClient *cpos;
1524
1525   dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
1526   dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
1527   dim.reserved = htonl (0);
1528   memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
1529   cpos = clients;
1530   while (cpos != NULL)
1531     {
1532       transmit_to_client (cpos, &dim.header, GNUNET_NO);
1533       cpos = cpos->next;
1534     }
1535 }
1536
1537
1538 /**
1539  * Find a ForeignAddressList entry for the given neighbour
1540  * that matches the given address and transport.
1541  *
1542  * @param neighbor which peer we care about
1543  * @param tname name of the transport plugin
1544  * @param addr binary address
1545  * @param addrlen length of addr
1546  * @return NULL if no such entry exists
1547  */
1548 static struct ForeignAddressList *
1549 find_peer_address(struct NeighborList *neighbor,
1550                   const char *tname,
1551                   const char *addr,
1552                   size_t addrlen)
1553 {
1554   struct ReadyList *head;
1555   struct ForeignAddressList *address_head;
1556
1557   head = neighbor->plugins;
1558   while (head != NULL)
1559     {
1560       if (0 == strcmp (tname, head->plugin->short_name))
1561         break;
1562       head = head->next;
1563     }
1564   if (head == NULL)
1565     return NULL;
1566
1567   address_head = head->addresses;
1568   while ( (address_head != NULL) &&
1569           ( (address_head->addrlen != addrlen) ||
1570             (memcmp(address_head->addr, addr, addrlen) != 0) ) )
1571     address_head = address_head->next;
1572   return address_head;
1573 }
1574
1575
1576 /**
1577  * Get the peer address struct for the given neighbor and
1578  * address.  If it doesn't yet exist, create it.
1579  *
1580  * @param neighbor which peer we care about
1581  * @param tname name of the transport plugin
1582  * @param addr binary address
1583  * @param addrlen length of addr
1584  * @return NULL if we do not have a transport plugin for 'tname'
1585  */
1586 static struct ForeignAddressList *
1587 add_peer_address(struct NeighborList *neighbor,
1588                  const char *tname,
1589                  const char *addr, 
1590                  size_t addrlen)
1591 {
1592   struct ReadyList *head;
1593   struct ForeignAddressList *ret;
1594
1595   ret = find_peer_address (neighbor, tname, addr, addrlen);
1596   if (ret != NULL)
1597     return ret;
1598   head = neighbor->plugins;
1599   while (head != NULL)
1600     {
1601       if (0 == strcmp (tname, head->plugin->short_name))
1602         break;
1603       head = head->next;
1604     }
1605   if (head == NULL)
1606     return NULL;
1607   ret = GNUNET_malloc(sizeof(struct ForeignAddressList) + addrlen);
1608   ret->addr = (const char*) &ret[1];
1609   memcpy (&ret[1], addr, addrlen);
1610   ret->addrlen = addrlen;
1611   ret->expires = GNUNET_TIME_relative_to_absolute
1612     (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1613   ret->latency = GNUNET_TIME_relative_get_forever();
1614   ret->transmit_ready = GNUNET_YES;
1615   ret->timeout = GNUNET_TIME_relative_to_absolute
1616     (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); 
1617   ret->ready_list = head;
1618   ret->next = head->addresses;
1619   head->addresses = ret;
1620   return ret;
1621 }
1622
1623
1624 /**
1625  * Closure for 'add_validated_address'.
1626  */
1627 struct AddValidatedAddressContext
1628 {
1629   /**
1630    * Entry that has been validated.
1631    */
1632   const struct ValidationEntry *ve;
1633
1634   /**
1635    * Flag set after we have added the address so
1636    * that we terminate the iteration next time.
1637    */
1638   int done;
1639 };
1640
1641
1642 /**
1643  * Callback function used to fill a buffer of max bytes with a list of
1644  * addresses in the format used by HELLOs.  Should use
1645  * "GNUNET_HELLO_add_address" as a helper function.
1646  *
1647  * @param cls the 'struct AddValidatedAddressContext' with the validated address
1648  * @param max maximum number of bytes that can be written to buf
1649  * @param buf where to write the address information
1650  * @return number of bytes written, 0 to signal the
1651  *         end of the iteration.
1652  */
1653 static size_t
1654 add_validated_address (void *cls,
1655                        size_t max, void *buf)
1656 {
1657   struct AddValidatedAddressContext *avac = cls;
1658   const struct ValidationEntry *ve = avac->ve;
1659
1660   if (GNUNET_YES == avac->done)
1661     return 0;
1662   avac->done = GNUNET_YES;
1663   return GNUNET_HELLO_add_address (ve->transport_name,
1664                                    GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION),
1665                                    ve->addr,
1666                                    ve->addrlen,
1667                                    buf,
1668                                    max);
1669 }
1670
1671
1672 /**
1673  * Iterator over hash map entries.  Checks if the given
1674  * validation entry is for the same challenge as what
1675  * is given in the PONG.
1676  *
1677  * @param cls the 'struct TransportPongMessage*'
1678  * @param key peer identity 
1679  * @param value value in the hash map ('struct ValidationEntry')
1680  * @return GNUNET_YES if we should continue to
1681  *         iterate (mismatch), GNUNET_NO if not (entry matched)
1682  */
1683 static int
1684 check_pending_validation (void *cls,
1685                           const GNUNET_HashCode * key,
1686                           void *value)
1687 {
1688   const struct TransportPongMessage *pong = cls;
1689   struct ValidationEntry *ve = value;
1690   struct AddValidatedAddressContext avac;
1691   unsigned int challenge = ntohl(pong->challenge);
1692   struct GNUNET_HELLO_Message *hello;
1693   struct GNUNET_PeerIdentity target;
1694   struct NeighborList *n;
1695   struct ForeignAddressList *fal;
1696
1697   if (ve->challenge != challenge)
1698     return GNUNET_YES;
1699   
1700 #if DEBUG_TRANSPORT
1701   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1702               "Confirmed validity of address, peer `%4s' has address `%s' (%s).\n",
1703               GNUNET_h2s (key),
1704               GNUNET_a2s ((const struct sockaddr *) ve->addr,
1705                           ve->addrlen),
1706               ve->transport_name);
1707 #endif
1708   /* create the updated HELLO */
1709   GNUNET_CRYPTO_hash (&ve->publicKey,
1710                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1711                       &target.hashPubKey);
1712   avac.done = GNUNET_NO;
1713   avac.ve = ve;
1714   hello = GNUNET_HELLO_create (&ve->publicKey,
1715                                &add_validated_address,
1716                                &avac);
1717   GNUNET_PEERINFO_add_peer (cfg, sched,
1718                             &target, 
1719                             hello);
1720   GNUNET_free (hello);
1721   n = find_neighbor (&target);
1722   if (n != NULL)
1723     {
1724       fal = add_peer_address (n, ve->transport_name, 
1725                               ve->addr,
1726                               ve->addrlen);
1727       fal->expires = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1728       fal->validated = GNUNET_YES;
1729       fal->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
1730     }
1731
1732   /* clean up validation entry */
1733   GNUNET_assert (GNUNET_YES ==
1734                  GNUNET_CONTAINER_multihashmap_remove (validation_map,
1735                                                        key,
1736                                                        ve));
1737   GNUNET_SCHEDULER_cancel (sched,
1738                            ve->timeout_task);
1739   GNUNET_free (ve->transport_name);
1740   GNUNET_free (ve);
1741   return GNUNET_NO;
1742 }
1743
1744
1745 /**
1746  * Function that will be called if we receive a validation
1747  * of an address challenge that we transmitted to another
1748  * peer.  Note that the validation should only be considered
1749  * acceptable if the challenge matches AND if the sender
1750  * address is at least a plausible address for this peer
1751  * (otherwise we may be seeing a MiM attack).
1752  *
1753  * @param cls closure
1754  * @param name name of the transport that generated the address
1755  * @param peer who responded to our challenge
1756  * @param challenge the challenge number we presumably used
1757  * @param sender_addr string describing our sender address (as observed
1758  *         by the other peer in human-readable format)
1759  */
1760 static void
1761 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
1762              const struct GNUNET_PeerIdentity *peer,
1763              const char *sender_address,
1764              size_t sender_address_len)
1765 {
1766 #if DEBUG_TRANSPORT
1767   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1768               "Receiving `%s' message from `%4s'.\n", "PONG",
1769               GNUNET_i2s (peer));
1770 #endif
1771   if (GNUNET_SYSERR != 
1772       GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
1773                                                   &peer->hashPubKey,
1774                                                   &check_pending_validation,
1775                                                   (void*) message))
1776     {
1777       /* This is *expected* to happen a lot since we send
1778          PONGs to *all* known addresses of the sender of
1779          the PING, so most likely we get multiple PONGs
1780          per PING, and all but the first PONG will end up
1781          here. So really we should not print anything here
1782          unless we want to be very, very verbose... */
1783 #if DEBUG_TRANSPORT > 1
1784       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1785                   "Received `%s' message from `%4s' but have no record of a matching `%s' message. Ignoring.\n",
1786                   "PONG",
1787                   GNUNET_i2s (peer),
1788                   "PING");
1789 #endif
1790       return;
1791     }
1792 #if 0
1793   /* FIXME: add given address to potential pool of our addresses
1794      (for voting) */
1795   GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
1796               _("Another peer saw us using the address `%s' via `%s'.\n"),
1797               GNUNET_a2s ((const struct sockaddr *) &pong[1],
1798                           ntohs(pong->addrlen)), 
1799               va->transport_name);  
1800 #endif
1801 }
1802
1803
1804 static void
1805 neighbor_timeout_task (void *cls,
1806                         const struct GNUNET_SCHEDULER_TaskContext *tc)
1807 {
1808   struct NeighborList *n = cls;
1809
1810 #if DEBUG_TRANSPORT
1811   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1812               "Neighbor `%4s' has timed out!\n", GNUNET_i2s (&n->id));
1813 #endif
1814   n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1815   disconnect_neighbor (n, GNUNET_NO);
1816 }
1817
1818
1819 /**
1820  * Create a fresh entry in our neighbor list for the given peer.
1821  * Will try to transmit our current HELLO to the new neighbor.  Also
1822  * notifies our clients about the new "connection".
1823  *
1824  * @param peer the peer for which we create the entry
1825  * @return the new neighbor list entry
1826  */
1827 static struct NeighborList *
1828 setup_new_neighbor (const struct GNUNET_PeerIdentity *peer)
1829 {
1830   struct NeighborList *n;
1831   struct TransportPlugin *tp;
1832   struct ReadyList *rl;
1833
1834   GNUNET_assert (our_hello != NULL);
1835   n = GNUNET_malloc (sizeof (struct NeighborList));
1836   n->next = neighbors;
1837   neighbors = n;
1838   n->id = *peer;
1839   n->last_quota_update = GNUNET_TIME_absolute_get ();
1840   n->peer_timeout =
1841     GNUNET_TIME_relative_to_absolute
1842     (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1843   n->quota_in = (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000);
1844   tp = plugins;
1845   while (tp != NULL)
1846     {
1847       if (tp->api->send != NULL)
1848         {
1849           rl = GNUNET_malloc (sizeof (struct ReadyList));
1850           rl->next = n->plugins;
1851           n->plugins = rl;
1852           rl->plugin = tp;
1853           rl->addresses = NULL;
1854         }
1855       tp = tp->next;
1856     }
1857   n->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
1858                                                   GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1859                                                   &neighbor_timeout_task, n);
1860   transmit_to_peer (NULL, NULL, 0,
1861                     (const char *) our_hello, GNUNET_HELLO_size(our_hello),
1862                     GNUNET_NO, n);
1863   notify_clients_connect (peer, GNUNET_TIME_UNIT_FOREVER_REL);
1864   return n;
1865 }
1866
1867
1868 /**
1869  * Closure for 'check_address_exists'.
1870  */
1871 struct CheckAddressExistsClosure
1872 {
1873   /**
1874    * Address to check for.
1875    */
1876   const void *addr;
1877
1878   /**
1879    * Name of the transport.
1880    */
1881   const char *tname;
1882
1883   /**
1884    * Length of addr.
1885    */
1886   size_t addrlen;
1887
1888   /**
1889    * Set to GNUNET_YES if the address exists.
1890    */
1891   int exists;
1892 };
1893
1894
1895 /**
1896  * Iterator over hash map entries.  Checks if the given
1897  * validation entry is for the same address as what is given
1898  * in the closure.
1899  *
1900  * @param cls the 'struct CheckAddressExistsClosure*'
1901  * @param key current key code (ignored)
1902  * @param value value in the hash map ('struct ValidationEntry')
1903  * @return GNUNET_YES if we should continue to
1904  *         iterate (mismatch), GNUNET_NO if not (entry matched)
1905  */
1906 static int
1907 check_address_exists (void *cls,
1908                       const GNUNET_HashCode * key,
1909                       void *value)
1910 {
1911   struct CheckAddressExistsClosure *caec = cls;
1912   struct ValidationEntry *ve = value;
1913   if ( (0 == strcmp (caec->tname,
1914                      ve->transport_name)) &&
1915        (caec->addrlen == ve->addrlen) &&
1916        (0 == memcmp (caec->addr,
1917                      ve->addr,
1918                      caec->addrlen)) )
1919     {
1920       caec->exists = GNUNET_YES;
1921       return GNUNET_NO;
1922     }
1923   return GNUNET_YES;
1924 }
1925
1926
1927 /**
1928  * HELLO validation cleanup task (validation failed).
1929  *
1930  * @param cls the 'struct ValidationEntry' that failed
1931  * @param tc scheduler context (unused)
1932  */
1933 static void
1934 timeout_hello_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1935 {
1936   struct ValidationEntry *va = cls;
1937   struct GNUNET_PeerIdentity pid;
1938
1939   GNUNET_CRYPTO_hash (&va->publicKey,
1940                       sizeof (struct
1941                               GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1942                       &pid.hashPubKey);
1943   GNUNET_CONTAINER_multihashmap_remove (validation_map,
1944                                         &pid.hashPubKey,
1945                                         va);
1946   GNUNET_free (va->transport_name);
1947   GNUNET_free (va);
1948 }
1949
1950
1951 /**
1952  * Check if the given address is already being validated; if not,
1953  * append the given address to the list of entries that are being be
1954  * validated and initiate validation.
1955  *
1956  * @param cls closure ('struct CheckHelloValidatedContext *')
1957  * @param tname name of the transport
1958  * @param expiration expiration time
1959  * @param addr the address
1960  * @param addrlen length of the address
1961  * @return GNUNET_OK (always)
1962  */
1963 static int
1964 run_validation (void *cls,
1965                 const char *tname,
1966                 struct GNUNET_TIME_Absolute expiration,
1967                 const void *addr, size_t addrlen)
1968 {
1969   struct CheckHelloValidatedContext *chvc = cls;
1970   struct GNUNET_PeerIdentity id;
1971   struct TransportPlugin *tp;
1972   struct ValidationEntry *va;
1973   struct NeighborList *neighbor;
1974   struct ForeignAddressList *peer_address;
1975   struct TransportPingMessage ping;
1976   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
1977   struct CheckAddressExistsClosure caec;
1978   char * message_buf;
1979   uint16_t hello_size;
1980   size_t tsize;
1981
1982   tp = find_transport (tname);
1983   if (tp == NULL)
1984     {
1985       GNUNET_log (GNUNET_ERROR_TYPE_INFO |
1986                   GNUNET_ERROR_TYPE_BULK,
1987                   _
1988                   ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
1989                   tname);
1990       return GNUNET_OK;
1991     }
1992   GNUNET_HELLO_get_key (chvc->hello, &pk);
1993   GNUNET_CRYPTO_hash (&pk,
1994                       sizeof (struct
1995                               GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1996                       &id.hashPubKey);
1997   caec.addr = addr;
1998   caec.addrlen = addrlen;
1999   caec.tname = tname;
2000   caec.exists = GNUNET_NO;
2001   GNUNET_CONTAINER_multihashmap_iterate (validation_map,
2002                                          &check_address_exists,
2003                                          &caec);
2004   if (caec.exists == GNUNET_YES)
2005     {
2006       /* During validation attempts we will likely trigger the other
2007          peer trying to validate our address which in turn will cause
2008          it to send us its HELLO, so we expect to hit this case rather
2009          frequently.  Only print something if we are very verbose. */
2010 #if DEBUG_TRANSPORT > 1
2011       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2012                   "Validation of address `%s' via `%s' for peer `%4s' already in progress.\n",
2013                   GNUNET_a2s (addr, addrlen), 
2014                   tname, 
2015                   GNUNET_i2s (&id));
2016 #endif
2017       return GNUNET_OK;
2018     } 
2019   va = GNUNET_malloc (sizeof (struct ValidationEntry) + addrlen);
2020   va->transport_name = GNUNET_strdup (tname);
2021   va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
2022                                             (unsigned int) -1);
2023   va->send_time = GNUNET_TIME_absolute_get();
2024   va->addr = (const void*) &va[1];
2025   memcpy (&va[1], addr, addrlen);
2026   va->addrlen = addrlen;
2027   GNUNET_HELLO_get_key (chvc->hello,
2028                         &va->publicKey);
2029   va->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
2030                                                    HELLO_VERIFICATION_TIMEOUT,
2031                                                    &timeout_hello_validation,
2032                                                    va);  
2033   GNUNET_CONTAINER_multihashmap_put (validation_map,
2034                                      &id.hashPubKey,
2035                                      va,
2036                                      GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2037   neighbor = find_neighbor(&id);  
2038   if (neighbor == NULL)
2039     neighbor = setup_new_neighbor(&id);
2040   peer_address = add_peer_address(neighbor, tname, addr, addrlen);    
2041   GNUNET_assert(peer_address != NULL);
2042   hello_size = GNUNET_HELLO_size(our_hello);
2043   tsize = sizeof(struct TransportPingMessage) + hello_size;
2044   message_buf = GNUNET_malloc(tsize);
2045   ping.challenge = htonl(va->challenge);
2046   ping.header.size = htons(sizeof(struct TransportPingMessage));
2047   ping.header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
2048   memcpy(&ping.target, &id, sizeof(struct GNUNET_PeerIdentity));
2049   memcpy(message_buf, our_hello, hello_size);
2050   memcpy(&message_buf[hello_size], 
2051          &ping, 
2052          sizeof(struct TransportPingMessage));
2053 #if DEBUG_TRANSPORT
2054   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2055               "Performing validation of address `%s' via `%s' for peer `%4s' sending `%s' (%u bytes) and `%s' (%u bytes)\n",
2056               GNUNET_a2s (addr, addrlen), 
2057               tname, 
2058               GNUNET_i2s (&id),
2059               "HELLO", hello_size,
2060               "PING", sizeof (struct TransportPingMessage));
2061 #endif
2062   transmit_to_peer(NULL, peer_address, 
2063                    GNUNET_SCHEDULER_PRIORITY_DEFAULT,
2064                    message_buf, tsize, 
2065                    GNUNET_YES, neighbor);
2066   GNUNET_free(message_buf);
2067   return GNUNET_OK;
2068 }
2069
2070
2071 /**
2072  * Add the given address to the list of foreign addresses
2073  * available for the given peer (check for duplicates).
2074  *
2075  * @param cls the respective 'struct NeighborList' to update
2076  * @param tname name of the transport
2077  * @param expiration expiration time
2078  * @param addr the address
2079  * @param addrlen length of the address
2080  * @return GNUNET_OK (always)
2081  */
2082 static int
2083 add_to_foreign_address_list (void *cls,
2084                              const char *tname,
2085                              struct GNUNET_TIME_Absolute expiration,
2086                              const void *addr, size_t addrlen)
2087 {
2088   struct NeighborList *n = cls;
2089   struct ForeignAddressList *fal;
2090
2091   fal = find_peer_address (n, tname, addr, addrlen);
2092   if (fal == NULL)
2093     {
2094 #if DEBUG_TRANSPORT
2095       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2096                   "Adding address `%s' (%s) for peer `%4s' due to peerinfo data.\n",
2097                   GNUNET_a2s (addr, addrlen),
2098                   tname,
2099                   GNUNET_i2s (&n->id));
2100 #endif
2101       fal = add_peer_address (n, tname, addr, addrlen);
2102     }
2103   fal->expires = GNUNET_TIME_absolute_max (expiration,
2104                                            fal->expires);
2105   fal->validated = GNUNET_YES;
2106   return GNUNET_OK;
2107 }
2108
2109
2110 /**
2111  * Check if addresses in validated hello "h" overlap with
2112  * those in "chvc->hello" and validate the rest.
2113  *
2114  * @param cls closure
2115  * @param peer id of the peer, NULL for last call
2116  * @param hello hello message for the peer (can be NULL)
2117  * @param trust amount of trust we have in the peer (not used)
2118  */
2119 static void
2120 check_hello_validated (void *cls,
2121                        const struct GNUNET_PeerIdentity *peer,
2122                        const struct GNUNET_HELLO_Message *h, 
2123                        uint32_t trust)
2124 {
2125   struct CheckHelloValidatedContext *chvc = cls;
2126   struct GNUNET_HELLO_Message *plain_hello;
2127   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded pk;
2128   struct GNUNET_PeerIdentity target;
2129   struct NeighborList *n;
2130
2131   if (peer == NULL)
2132     {
2133       chvc->piter = NULL;
2134       GNUNET_CONTAINER_DLL_remove (chvc_head,
2135                                    chvc_tail,
2136                                    chvc);
2137       if (GNUNET_NO == chvc->hello_known)
2138         {
2139           /* notify PEERINFO about the peer now, so that we at least
2140              have the public key if some other component needs it */
2141           GNUNET_HELLO_get_key (chvc->hello, &pk);
2142           GNUNET_CRYPTO_hash (&pk,
2143                               sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2144                               &target.hashPubKey);
2145           plain_hello = GNUNET_HELLO_create (&pk,
2146                                              NULL, 
2147                                              NULL);
2148           GNUNET_PEERINFO_add_peer (cfg, sched, &target, plain_hello);
2149           GNUNET_free (plain_hello);
2150 #if DEBUG_TRANSPORT
2151           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2152                       "Peerinfo had no `%s' message for peer `%4s', full validation needed.\n",
2153                       "HELLO",
2154                       GNUNET_i2s (&target));
2155 #endif
2156           GNUNET_HELLO_iterate_addresses (chvc->hello,
2157                                           GNUNET_NO, 
2158                                           &run_validation, 
2159                                           chvc);
2160         }
2161       GNUNET_free (chvc);
2162       return;
2163     }
2164   if (h == NULL)
2165     return;
2166   chvc->hello_known = GNUNET_YES;
2167   n = find_neighbor (peer);
2168   if (n != NULL)
2169     GNUNET_HELLO_iterate_addresses (h,
2170                                     GNUNET_NO,
2171                                     &add_to_foreign_address_list,
2172                                     n);
2173   GNUNET_HELLO_iterate_new_addresses (chvc->hello,
2174                                       h,
2175                                       GNUNET_TIME_absolute_get (),
2176                                       &run_validation, 
2177                                       chvc);
2178 }
2179
2180 /**
2181  * Process HELLO-message.
2182  *
2183  * @param plugin transport involved, may be NULL
2184  * @param message the actual message
2185  * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
2186  */
2187 static int
2188 process_hello (struct TransportPlugin *plugin,
2189                const struct GNUNET_MessageHeader *message)
2190 {
2191   uint16_t hsize;
2192   struct GNUNET_PeerIdentity target;
2193   const struct GNUNET_HELLO_Message *hello;
2194   struct CheckHelloValidatedContext *chvc;
2195   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
2196
2197   hsize = ntohs (message->size);
2198   if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
2199       (hsize < sizeof (struct GNUNET_MessageHeader)))
2200     {
2201       GNUNET_break (0);
2202       return GNUNET_SYSERR;
2203     }
2204   /* first, check if load is too high */
2205   if (GNUNET_SCHEDULER_get_load (sched,
2206                                  GNUNET_SCHEDULER_PRIORITY_BACKGROUND) > MAX_HELLO_LOAD)
2207     {
2208       /* TODO: call to stats? */
2209       return GNUNET_OK;
2210     }
2211   hello = (const struct GNUNET_HELLO_Message *) message;
2212   if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
2213     {
2214       GNUNET_break_op (0);
2215       return GNUNET_SYSERR;
2216     }
2217   GNUNET_CRYPTO_hash (&publicKey,
2218                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2219                       &target.hashPubKey);
2220 #if DEBUG_TRANSPORT
2221   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2222               "Processing `%s' message for `%4s' of size %u\n",
2223               "HELLO", 
2224               GNUNET_i2s (&target), 
2225               GNUNET_HELLO_size(hello));
2226 #endif
2227
2228   chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
2229   chvc->hello = (const struct GNUNET_HELLO_Message *) &chvc[1];
2230   memcpy (&chvc[1], hello, hsize);
2231   GNUNET_CONTAINER_DLL_insert (chvc_head,
2232                                chvc_tail,
2233                                chvc);
2234   /* finally, check if HELLO was previously validated
2235      (continuation will then schedule actual validation) */
2236   chvc->piter = GNUNET_PEERINFO_iterate (cfg,
2237                                          sched,
2238                                          &target,
2239                                          0,
2240                                          HELLO_VERIFICATION_TIMEOUT,
2241                                          &check_hello_validated, chvc);
2242   return GNUNET_OK;
2243 }
2244
2245
2246 /**
2247  * The peer specified by the given neighbor has timed-out or a plugin
2248  * has disconnected.  We may either need to do nothing (other plugins
2249  * still up), or trigger a full disconnect and clean up.  This
2250  * function updates our state and does the necessary notifications.
2251  * Also notifies our clients that the neighbor is now officially
2252  * gone.
2253  *
2254  * @param n the neighbor list entry for the peer
2255  * @param check should we just check if all plugins
2256  *        disconnected or must we ask all plugins to
2257  *        disconnect?
2258  */
2259 static void
2260 disconnect_neighbor (struct NeighborList *current_handle, int check)
2261 {
2262   struct ReadyList *rpos;
2263   struct NeighborList *npos;
2264   struct NeighborList *nprev;
2265   struct NeighborList *n;
2266   struct MessageQueue *mq;
2267   struct ForeignAddressList *peer_addresses;
2268   struct ForeignAddressList *peer_pos;
2269
2270   if (neighbors == NULL)
2271     return; /* We don't have any neighbors, so client has an already removed handle! */
2272
2273   npos = neighbors;
2274   while ((npos != NULL) && (current_handle != npos))
2275     npos = npos->next;
2276
2277   if (npos == NULL)
2278     return; /* Couldn't find neighbor in existing list, must have been already removed! */
2279   else
2280     n = npos;
2281
2282   if (GNUNET_YES == check)
2283     {
2284       rpos = n->plugins;
2285       while (NULL != rpos)
2286         {
2287           peer_addresses = rpos->addresses;
2288           while (peer_addresses != NULL)
2289             {
2290               if (GNUNET_YES == peer_addresses->connected)
2291                 return;             /* still connected */
2292               peer_addresses = peer_addresses->next;
2293             }
2294           rpos = rpos->next;
2295         }
2296     }
2297
2298 #if DEBUG_TRANSPORT
2299   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2300               "Disconnecting from `%4s'\n", GNUNET_i2s (&n->id));
2301 #endif
2302   /* remove n from neighbors list */
2303   nprev = NULL;
2304   npos = neighbors;
2305   while ((npos != NULL) && (npos != n))
2306     {
2307       nprev = npos;
2308       npos = npos->next;
2309     }
2310   GNUNET_assert (npos != NULL);
2311   if (nprev == NULL)
2312     neighbors = n->next;
2313   else
2314     nprev->next = n->next;
2315
2316   /* notify all clients about disconnect */
2317   notify_clients_disconnect (&n->id);
2318
2319   /* clean up all plugins, cancel connections and pending transmissions */
2320   while (NULL != (rpos = n->plugins))
2321     {
2322       n->plugins = rpos->next;
2323       if (GNUNET_YES == rpos->connected)
2324         rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
2325
2326       while (rpos->addresses != NULL)
2327         {
2328           peer_pos = rpos->addresses;
2329           rpos->addresses = peer_pos->next;
2330           GNUNET_free(peer_pos);
2331         }
2332       GNUNET_free (rpos);
2333     }
2334
2335   /* free all messages on the queue */
2336   while (NULL != (mq = n->messages))
2337     {
2338       n->messages = mq->next;
2339       GNUNET_assert (0 == memcmp(&mq->neighbor_id, 
2340                                  &n->id,
2341                                  sizeof(struct GNUNET_PeerIdentity)));
2342       GNUNET_free (mq);
2343     }
2344   if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
2345     GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
2346   /* finally, free n itself */
2347   GNUNET_free (n);
2348 }
2349
2350
2351 /**
2352  * We have received a PING message from someone.  Need to send a PONG message
2353  * in response to the peer by any means necessary. 
2354  *
2355  * FIXME: With something like TCP where a connection exists, we may
2356  * want to send it that way.  But the current API does not seem to
2357  * allow us to do so (can't tell this to the transport!)
2358  */
2359 static int 
2360 handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
2361             const struct GNUNET_PeerIdentity *peer,
2362             const char *sender_address,
2363             size_t sender_address_len)
2364 {
2365   struct TransportPlugin *plugin = cls;
2366   struct TransportPingMessage *ping;
2367   struct TransportPongMessage *pong;
2368   uint16_t msize;
2369   struct NeighborList *n;
2370   struct ReadyList *rl;
2371   struct ForeignAddressList *fal;
2372
2373   msize = ntohs (message->size);
2374   if (msize < sizeof (struct TransportPingMessage))
2375     {
2376       GNUNET_break_op (0);
2377       return GNUNET_SYSERR;
2378     }
2379   ping = (struct TransportPingMessage *) message;
2380   if (0 != memcmp (&ping->target,
2381                    plugin->env.my_identity,
2382                    sizeof (struct GNUNET_PeerIdentity)))
2383     {
2384       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2385                   _("Received `%s' message not destined for me!\n"), 
2386                   "PING");
2387       return GNUNET_SYSERR;
2388     }
2389 #if DEBUG_TRANSPORT
2390   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2391               "Processing `%s' from `%s'\n",
2392               "PING", 
2393               GNUNET_a2s ((const struct sockaddr *)sender_address, 
2394                           sender_address_len));
2395 #endif
2396   msize -= sizeof (struct TransportPingMessage);
2397   pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len);
2398   pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len);
2399   pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
2400   pong->purpose.size =
2401     htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
2402            sizeof (uint32_t) +
2403            sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + sender_address_len);
2404   pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_TCP_PING);
2405   pong->challenge = ping->challenge;
2406   pong->addrlen = htons(sender_address_len);
2407   memcpy(&pong->signer, 
2408          &my_public_key, 
2409          sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
2410   memcpy (&pong[1], sender_address, sender_address_len);
2411   GNUNET_assert (GNUNET_OK ==
2412                  GNUNET_CRYPTO_rsa_sign (my_private_key,
2413                                          &pong->purpose, &pong->signature));
2414
2415   n = find_neighbor(peer);
2416   if (n == NULL)
2417     n = setup_new_neighbor(peer);
2418   /* broadcast 'PONG' to all available addresses */
2419   rl = n->plugins;
2420   while (rl != NULL)
2421     {
2422       fal = rl->addresses;
2423       while (fal != NULL)
2424         {
2425           transmit_to_peer(NULL, fal,
2426                            TRANSPORT_DEFAULT_PRIORITY, 
2427                            (const char *)pong, 
2428                            ntohs(pong->header.size), 
2429                            GNUNET_YES, 
2430                            n);
2431           fal = fal->next;
2432         }
2433       rl = rl->next;
2434     }
2435   GNUNET_free(pong);
2436   return GNUNET_OK;
2437 }
2438
2439
2440 /**
2441  * Function called by the plugin for each received message.
2442  * Update data volumes, possibly notify plugins about
2443  * reducing the rate at which they read from the socket
2444  * and generally forward to our receive callback.
2445  *
2446  * @param cls the "struct TransportPlugin *" we gave to the plugin
2447  * @param message the message, NULL if peer was disconnected
2448  * @param distance the transport cost to this peer (not latency!)
2449  * @param sender_address the address that the sender reported
2450  *        (opaque to transport service)
2451  * @param sender_address_len the length of the sender address
2452  * @param peer (claimed) identity of the other peer
2453  * @return the new service_context that the plugin should use
2454  *         for future receive calls for messages from this
2455  *         particular peer
2456  *
2457  */
2458 static void
2459 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
2460                     const struct GNUNET_MessageHeader *message,
2461                     unsigned int distance, const char *sender_address,
2462                     size_t sender_address_len)
2463 {
2464   struct ReadyList *service_context;
2465   struct TransportPlugin *plugin = cls;
2466   struct TransportClient *cpos;
2467   struct InboundMessage *im;
2468   struct ForeignAddressList *peer_address;
2469   uint16_t msize;
2470   struct NeighborList *n;
2471
2472   n = find_neighbor (peer);
2473   if (n == NULL)
2474     {
2475       if (message == NULL)
2476         return;                 /* disconnect of peer already marked down */
2477       n = setup_new_neighbor (peer);
2478
2479     }
2480   service_context = n->plugins;
2481   while ((service_context != NULL) && (plugin != service_context->plugin))
2482     service_context = service_context->next;
2483   GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
2484   if (message == NULL)
2485     {
2486 #if DEBUG_TRANSPORT
2487       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2488                   "Receive failed from `%4s', triggering disconnect\n",
2489                   GNUNET_i2s (&n->id));
2490 #endif
2491       /* TODO: call stats */
2492       if (service_context != NULL)
2493         service_context->connected = GNUNET_NO;
2494       disconnect_neighbor (n, GNUNET_YES);
2495       return;
2496     }
2497   peer_address = add_peer_address(n, 
2498                                   plugin->short_name,
2499                                   sender_address, 
2500                                   sender_address_len);
2501   if (service_context != NULL)
2502     {
2503       if (service_context->connected == GNUNET_NO)
2504         {
2505           service_context->connected = GNUNET_YES;
2506           /* FIXME: What to do here?  Should we use these as well, 
2507              to specify some Address in the AddressList should be
2508              available? */
2509           peer_address->transmit_ready = GNUNET_YES;
2510           peer_address->connect_attempts++;
2511         }
2512       peer_address->timeout
2513         =
2514         GNUNET_TIME_relative_to_absolute
2515         (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2516     }
2517   /* update traffic received amount ... */
2518   msize = ntohs (message->size);
2519   n->last_received += msize;
2520   GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
2521   n->peer_timeout =
2522     GNUNET_TIME_relative_to_absolute
2523     (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2524   n->timeout_task =
2525     GNUNET_SCHEDULER_add_delayed (sched,
2526                                   GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2527                                   &neighbor_timeout_task, n);
2528   update_quota (n);
2529   if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
2530     {
2531       /* dropping message due to frequent inbound volume violations! */
2532       GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
2533                   GNUNET_ERROR_TYPE_BULK,
2534                   _
2535                   ("Dropping incoming message due to repeated bandwidth quota violations (total of %u).\n"), n->quota_violation_count);
2536       /* TODO: call stats */
2537       return;
2538     }
2539   switch (ntohs (message->type))
2540     {
2541     case GNUNET_MESSAGE_TYPE_HELLO:
2542       process_hello (plugin, message);
2543       break;
2544     case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
2545       handle_ping(plugin, message, peer, sender_address, sender_address_len);
2546       break;
2547     case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
2548       handle_pong(plugin, message, peer, sender_address, sender_address_len);
2549       break;
2550     default:
2551 #if DEBUG_TRANSPORT
2552       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2553                   "Received message of type %u from `%4s', sending to all clients.\n",
2554                   ntohs (message->type), GNUNET_i2s (peer));
2555 #endif
2556       /* transmit message to all clients */
2557       im = GNUNET_malloc (sizeof (struct InboundMessage) + msize);
2558       im->header.size = htons (sizeof (struct InboundMessage) + msize);
2559       im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
2560       im->latency = n->latency;
2561       im->peer = *peer;
2562       memcpy (&im[1], message, msize);
2563
2564       cpos = clients;
2565       while (cpos != NULL)
2566         {
2567           transmit_to_client (cpos, &im->header, GNUNET_YES);
2568           cpos = cpos->next;
2569         }
2570       GNUNET_free (im);
2571     }
2572 }
2573
2574
2575 /**
2576  * Handle START-message.  This is the first message sent to us
2577  * by any client which causes us to add it to our list.
2578  *
2579  * @param cls closure (always NULL)
2580  * @param client identification of the client
2581  * @param message the actual message
2582  */
2583 static void
2584 handle_start (void *cls,
2585               struct GNUNET_SERVER_Client *client,
2586               const struct GNUNET_MessageHeader *message)
2587 {
2588   struct TransportClient *c;
2589   struct ConnectInfoMessage cim;
2590   struct NeighborList *n;
2591   struct InboundMessage *im;
2592   struct GNUNET_MessageHeader *ack;
2593
2594 #if DEBUG_TRANSPORT
2595   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2596               "Received `%s' request from client\n", "START");
2597 #endif
2598   c = clients;
2599   while (c != NULL)
2600     {
2601       if (c->client == client)
2602         {
2603           /* client already on our list! */
2604           GNUNET_break (0);
2605           GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2606           return;
2607         }
2608       c = c->next;
2609     }
2610   c = GNUNET_malloc (sizeof (struct TransportClient));
2611   c->next = clients;
2612   clients = c;
2613   c->client = client;
2614   if (our_hello != NULL)
2615     {
2616 #if DEBUG_TRANSPORT
2617       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2618                   "Sending our own `%s' to new client\n", "HELLO");
2619 #endif
2620       transmit_to_client (c,
2621                           (const struct GNUNET_MessageHeader *) our_hello,
2622                           GNUNET_NO);
2623       /* tell new client about all existing connections */
2624       cim.header.size = htons (sizeof (struct ConnectInfoMessage));
2625       cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2626       cim.quota_out =
2627         htonl (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT / (60 * 1000));
2628       cim.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO);  /* FIXME? */
2629       im = GNUNET_malloc (sizeof (struct InboundMessage) +
2630                           sizeof (struct GNUNET_MessageHeader));
2631       im->header.size = htons (sizeof (struct InboundMessage) +
2632                                sizeof (struct GNUNET_MessageHeader));
2633       im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
2634       im->latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO);  /* FIXME? */
2635       ack = (struct GNUNET_MessageHeader *) &im[1];
2636       ack->size = htons (sizeof (struct GNUNET_MessageHeader));
2637       ack->type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ACK);
2638       for (n = neighbors; n != NULL; n = n->next)
2639         {
2640           cim.id = n->id;
2641           transmit_to_client (c, &cim.header, GNUNET_NO);
2642           if (n->received_pong)
2643             {
2644               im->peer = n->id;
2645               transmit_to_client (c, &im->header, GNUNET_NO);
2646             }
2647         }
2648       GNUNET_free (im);
2649     }
2650   else
2651     {
2652       fprintf(stderr, "Our hello is NULL!\n");
2653     }
2654   GNUNET_SERVER_receive_done (client, GNUNET_OK);
2655 }
2656
2657
2658 /**
2659  * Handle HELLO-message.
2660  *
2661  * @param cls closure (always NULL)
2662  * @param client identification of the client
2663  * @param message the actual message
2664  */
2665 static void
2666 handle_hello (void *cls,
2667               struct GNUNET_SERVER_Client *client,
2668               const struct GNUNET_MessageHeader *message)
2669 {
2670   int ret;
2671
2672 #if DEBUG_TRANSPORT
2673   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2674               "Received `%s' request from client\n", "HELLO");
2675 #endif
2676   ret = process_hello (NULL, message);
2677   GNUNET_SERVER_receive_done (client, ret);
2678 }
2679
2680
2681 /**
2682  * Handle SEND-message.
2683  *
2684  * @param cls closure (always NULL)
2685  * @param client identification of the client
2686  * @param message the actual message
2687  */
2688 static void
2689 handle_send (void *cls,
2690              struct GNUNET_SERVER_Client *client,
2691              const struct GNUNET_MessageHeader *message)
2692 {
2693   struct TransportClient *tc;
2694   struct NeighborList *n;
2695   const struct OutboundMessage *obm;
2696   const struct GNUNET_MessageHeader *obmm;
2697   uint16_t size;
2698   uint16_t msize;
2699
2700   size = ntohs (message->size);
2701   if (size <
2702       sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
2703     {
2704       GNUNET_break (0);
2705       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2706       return;
2707     }
2708   obm = (const struct OutboundMessage *) message;
2709 #if DEBUG_TRANSPORT
2710   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2711               "Received `%s' request from client with target `%4s'\n",
2712               "SEND", GNUNET_i2s (&obm->peer));
2713 #endif
2714   obmm = (const struct GNUNET_MessageHeader *) &obm[1];
2715   msize = ntohs (obmm->size);
2716   if (size != msize + sizeof (struct OutboundMessage))
2717     {
2718       GNUNET_break (0);
2719       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2720       return;
2721     }
2722   n = find_neighbor (&obm->peer);
2723   if (n == NULL)
2724     n = setup_new_neighbor (&obm->peer); /* But won't ever add address, we have none! */
2725   tc = clients;
2726   while ((tc != NULL) && (tc->client != client))
2727     tc = tc->next;
2728
2729 #if DEBUG_TRANSPORT
2730   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2731               "Client asked to transmit %u-byte message of type %u to `%4s'\n",
2732               ntohs (obmm->size),
2733               ntohs (obmm->type), GNUNET_i2s (&obm->peer));
2734 #endif
2735   transmit_to_peer (tc, NULL, ntohl (obm->priority), (char *)obmm, 
2736                     ntohs (obmm->size), GNUNET_NO, n);
2737   GNUNET_SERVER_receive_done (client, GNUNET_OK);
2738 }
2739
2740
2741 /**
2742  * Handle SET_QUOTA-message.
2743  *
2744  * @param cls closure (always NULL)
2745  * @param client identification of the client
2746  * @param message the actual message
2747  */
2748 static void
2749 handle_set_quota (void *cls,
2750                   struct GNUNET_SERVER_Client *client,
2751                   const struct GNUNET_MessageHeader *message)
2752 {
2753   const struct QuotaSetMessage *qsm =
2754     (const struct QuotaSetMessage *) message;
2755   struct NeighborList *n;
2756   struct TransportPlugin *p;
2757   struct ReadyList *rl;
2758
2759   n = find_neighbor (&qsm->peer);
2760   if (n == NULL)
2761     {
2762       GNUNET_SERVER_receive_done (client, GNUNET_OK);
2763       return;
2764     }
2765
2766 #if DEBUG_TRANSPORT
2767   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2768               "Received `%s' request (new quota %u, old quota %u) from client for peer `%4s'\n",
2769               "SET_QUOTA", ntohl(qsm->quota_in), n->quota_in, GNUNET_i2s (&qsm->peer));
2770 #endif
2771
2772   update_quota (n);
2773   if (n->quota_in < ntohl (qsm->quota_in))
2774     n->last_quota_update = GNUNET_TIME_absolute_get ();
2775   n->quota_in = ntohl (qsm->quota_in);
2776   rl = n->plugins;
2777   while (rl != NULL)
2778     {
2779       p = rl->plugin;
2780       p->api->set_receive_quota (p->api->cls,
2781                                  &qsm->peer, ntohl (qsm->quota_in));
2782       rl = rl->next;
2783     }
2784   GNUNET_SERVER_receive_done (client, GNUNET_OK);
2785 }
2786
2787
2788 /**
2789  * Handle TRY_CONNECT-message.
2790  *
2791  * @param cls closure (always NULL)
2792  * @param client identification of the client
2793  * @param message the actual message
2794  */
2795 static void
2796 handle_try_connect (void *cls,
2797                     struct GNUNET_SERVER_Client *client,
2798                     const struct GNUNET_MessageHeader *message)
2799 {
2800   const struct TryConnectMessage *tcm;
2801   struct NeighborList *neighbor;
2802   tcm = (const struct TryConnectMessage *) message;
2803 #if DEBUG_TRANSPORT
2804   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2805               "Received `%s' request from client %p asking to connect to `%4s'\n",
2806               "TRY_CONNECT", client, GNUNET_i2s (&tcm->peer));
2807 #endif
2808   neighbor = find_neighbor(&tcm->peer);
2809   if (neighbor == NULL)
2810     setup_new_neighbor (&tcm->peer);
2811   GNUNET_SERVER_receive_done (client, GNUNET_OK);
2812 }
2813
2814
2815 static void
2816 transmit_address_to_client (void *cls, const char *address)
2817 {
2818   struct GNUNET_SERVER_TransmitContext *tc = cls;
2819   size_t slen;
2820
2821   if (NULL == address)
2822     slen = 0;
2823   else
2824     slen = strlen (address) + 1;
2825   GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
2826                                               GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
2827   if (NULL == address)
2828     GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
2829 }
2830
2831
2832 /**
2833  * Handle AddressLookup-message.
2834  *
2835  * @param cls closure (always NULL)
2836  * @param client identification of the client
2837  * @param message the actual message
2838  */
2839 static void
2840 handle_address_lookup (void *cls,
2841                        struct GNUNET_SERVER_Client *client,
2842                        const struct GNUNET_MessageHeader *message)
2843 {
2844   const struct AddressLookupMessage *alum;
2845   struct TransportPlugin *lsPlugin;
2846   const char *nameTransport;
2847   const char *address;
2848   uint16_t size;
2849   struct GNUNET_SERVER_TransmitContext *tc;
2850
2851   size = ntohs (message->size);
2852   if (size < sizeof (struct AddressLookupMessage))
2853     {
2854       GNUNET_break_op (0);
2855       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2856       return;
2857     }
2858   alum = (const struct AddressLookupMessage *) message;
2859   uint32_t addressLen = ntohl (alum->addrlen);
2860   if (size <= sizeof (struct AddressLookupMessage) + addressLen)
2861     {
2862       GNUNET_break_op (0);
2863       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2864       return;
2865     }
2866   address = (const char *) &alum[1];
2867   nameTransport = (const char *) &address[addressLen];
2868   if (nameTransport
2869       [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
2870     {
2871       GNUNET_break_op (0);
2872       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2873       return;
2874     }
2875   struct GNUNET_TIME_Absolute timeout =
2876     GNUNET_TIME_absolute_ntoh (alum->timeout);
2877   struct GNUNET_TIME_Relative rtimeout =
2878     GNUNET_TIME_absolute_get_remaining (timeout);
2879   lsPlugin = find_transport (nameTransport);
2880   if (NULL == lsPlugin)
2881     {
2882       tc = GNUNET_SERVER_transmit_context_create (client);
2883       GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
2884                                                   GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
2885       GNUNET_SERVER_transmit_context_run (tc, rtimeout);
2886       return;
2887     }
2888   tc = GNUNET_SERVER_transmit_context_create (client);
2889   lsPlugin->api->address_pretty_printer (cls, nameTransport,
2890                                          address, addressLen, GNUNET_YES,
2891                                          rtimeout,
2892                                          &transmit_address_to_client, tc);
2893 }
2894
2895 /**
2896  * List of handlers for the messages understood by this
2897  * service.
2898  */
2899 static struct GNUNET_SERVER_MessageHandler handlers[] = {
2900   {&handle_start, NULL,
2901    GNUNET_MESSAGE_TYPE_TRANSPORT_START, 0},
2902   {&handle_hello, NULL,
2903    GNUNET_MESSAGE_TYPE_HELLO, 0},
2904   {&handle_send, NULL,
2905    GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
2906   {&handle_set_quota, NULL,
2907    GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
2908   {&handle_try_connect, NULL,
2909    GNUNET_MESSAGE_TYPE_TRANSPORT_TRY_CONNECT,
2910    sizeof (struct TryConnectMessage)},
2911   {&handle_address_lookup, NULL,
2912    GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
2913    0},
2914   {NULL, NULL, 0, 0}
2915 };
2916
2917
2918 /**
2919  * Setup the environment for this plugin.
2920  */
2921 static void
2922 create_environment (struct TransportPlugin *plug)
2923 {
2924   plug->env.cfg = cfg;
2925   plug->env.sched = sched;
2926   plug->env.my_identity = &my_identity;
2927   plug->env.cls = plug;
2928   plug->env.receive = &plugin_env_receive;
2929   plug->env.notify_address = &plugin_env_notify_address;
2930   plug->env.default_quota_in =
2931     (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000);
2932   plug->env.max_connections = max_connect_per_transport;
2933 }
2934
2935
2936 /**
2937  * Start the specified transport (load the plugin).
2938  */
2939 static void
2940 start_transport (struct GNUNET_SERVER_Handle *server, const char *name)
2941 {
2942   struct TransportPlugin *plug;
2943   char *libname;
2944
2945   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2946               _("Loading `%s' transport plugin\n"), name);
2947   GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
2948   plug = GNUNET_malloc (sizeof (struct TransportPlugin));
2949   create_environment (plug);
2950   plug->short_name = GNUNET_strdup (name);
2951   plug->lib_name = libname;
2952   plug->next = plugins;
2953   plugins = plug;
2954   plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
2955   if (plug->api == NULL)
2956     {
2957       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2958                   _("Failed to load transport plugin for `%s'\n"), name);
2959       GNUNET_free (plug->short_name);
2960       plugins = plug->next;
2961       GNUNET_free (libname);
2962       GNUNET_free (plug);
2963     }
2964 }
2965
2966
2967 /**
2968  * Called whenever a client is disconnected.  Frees our
2969  * resources associated with that client.
2970  *
2971  * @param cls closure
2972  * @param client identification of the client
2973  */
2974 static void
2975 client_disconnect_notification (void *cls,
2976                                 struct GNUNET_SERVER_Client *client)
2977 {
2978   struct TransportClient *pos;
2979   struct TransportClient *prev;
2980   struct ClientMessageQueueEntry *mqe;
2981
2982   if (client == NULL)
2983     return;
2984 #if DEBUG_TRANSPORT
2985   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2986               "Client disconnected, cleaning up.\n");
2987 #endif
2988   prev = NULL;
2989   pos = clients;
2990   while ((pos != NULL) && (pos->client != client))
2991     {
2992       prev = pos;
2993       pos = pos->next;
2994     }
2995   if (pos == NULL)
2996     return;
2997   while (NULL != (mqe = pos->message_queue_head))
2998     {
2999       pos->message_queue_head = mqe->next;
3000       GNUNET_free (mqe);
3001     }
3002   pos->message_queue_head = NULL;
3003   if (prev == NULL)
3004     clients = pos->next;
3005   else
3006     prev->next = pos->next;
3007   if (GNUNET_YES == pos->tcs_pending)
3008     {
3009       pos->client = NULL;
3010       return;
3011     }
3012   GNUNET_free (pos);
3013 }
3014
3015
3016 /**
3017  * Iterator to free entries in the validation_map.
3018  *
3019  * @param cls closure (unused)
3020  * @param key current key code
3021  * @param value value in the hash map (validation to abort)
3022  * @return GNUNET_YES (always)
3023  */
3024 static int 
3025 abort_validation (void *cls,
3026                   const GNUNET_HashCode * key,
3027                   void *value)
3028 {
3029   struct ValidationEntry *va = value;
3030
3031   GNUNET_SCHEDULER_cancel (sched, va->timeout_task);
3032   GNUNET_free (va->transport_name);
3033   GNUNET_free (va);
3034   return GNUNET_YES;
3035 }
3036
3037
3038 /**
3039  * Function called when the service shuts down.  Unloads our plugins
3040  * and cancels pending validations.
3041  *
3042  * @param cls closure, unused
3043  * @param tc task context (unused)
3044  */
3045 static void
3046 shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
3047 {
3048   struct TransportPlugin *plug;
3049   struct OwnAddressList *al;
3050   struct CheckHelloValidatedContext *chvc;
3051
3052 #if DEBUG_TRANSPORT
3053   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3054               "Transport service is unloading plugins...\n");
3055 #endif
3056   while (NULL != (plug = plugins))
3057     {
3058       plugins = plug->next;
3059       GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
3060       GNUNET_free (plug->lib_name);
3061       GNUNET_free (plug->short_name);
3062       while (NULL != (al = plug->addresses))
3063         {
3064           plug->addresses = al->next;
3065           GNUNET_free (al);
3066         }
3067       GNUNET_free (plug);
3068     }
3069   if (my_private_key != NULL)
3070     GNUNET_CRYPTO_rsa_key_free (my_private_key);
3071   GNUNET_free_non_null (our_hello);
3072
3073   /* free 'chvc' data structure */
3074   while (NULL != (chvc = chvc_head))
3075     {
3076       chvc_head = chvc->next;
3077       GNUNET_PEERINFO_iterate_cancel (chvc->piter);
3078       GNUNET_free (chvc);
3079     }
3080   chvc_tail = NULL;
3081
3082   GNUNET_CONTAINER_multihashmap_iterate (validation_map,
3083                                          &abort_validation,
3084                                          NULL);
3085   GNUNET_CONTAINER_multihashmap_destroy (validation_map);
3086 }
3087
3088
3089 /**
3090  * Initiate transport service.
3091  *
3092  * @param cls closure
3093  * @param s scheduler to use
3094  * @param serv the initialized server
3095  * @param c configuration to use
3096  */
3097 static void
3098 run (void *cls,
3099      struct GNUNET_SCHEDULER_Handle *s,
3100      struct GNUNET_SERVER_Handle *serv,
3101      const struct GNUNET_CONFIGURATION_Handle *c)
3102 {
3103   char *plugs;
3104   char *pos;
3105   int no_transports;
3106   unsigned long long tneigh;
3107   char *keyfile;
3108
3109   sched = s;
3110   cfg = c;
3111   validation_map = GNUNET_CONTAINER_multihashmap_create (64);
3112   /* parse configuration */
3113   if ((GNUNET_OK !=
3114        GNUNET_CONFIGURATION_get_value_number (c,
3115                                               "TRANSPORT",
3116                                               "NEIGHBOUR_LIMIT",
3117                                               &tneigh)) ||
3118       (GNUNET_OK !=
3119        GNUNET_CONFIGURATION_get_value_filename (c,
3120                                                 "GNUNETD",
3121                                                 "HOSTKEY", &keyfile)))
3122     {
3123       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3124                   _
3125                   ("Transport service is lacking key configuration settings.  Exiting.\n"));
3126       GNUNET_SCHEDULER_shutdown (s);
3127       return;
3128     }
3129   max_connect_per_transport = (uint32_t) tneigh;
3130   my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
3131   GNUNET_free (keyfile);
3132   if (my_private_key == NULL)
3133     {
3134       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3135                   _
3136                   ("Transport service could not access hostkey.  Exiting.\n"));
3137       GNUNET_SCHEDULER_shutdown (s);
3138       return;
3139     }
3140   GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
3141   GNUNET_CRYPTO_hash (&my_public_key,
3142                       sizeof (my_public_key), &my_identity.hashPubKey);
3143   /* setup notification */
3144   server = serv;
3145   GNUNET_SERVER_disconnect_notify (server,
3146                                    &client_disconnect_notification, NULL);
3147   /* load plugins... */
3148   no_transports = 1;
3149   if (GNUNET_OK ==
3150       GNUNET_CONFIGURATION_get_value_string (c,
3151                                              "TRANSPORT", "PLUGINS", &plugs))
3152     {
3153       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3154                   _("Starting transport plugins `%s'\n"), plugs);
3155       pos = strtok (plugs, " ");
3156       while (pos != NULL)
3157         {
3158           start_transport (server, pos);
3159           no_transports = 0;
3160           pos = strtok (NULL, " ");
3161         }
3162       GNUNET_free (plugs);
3163     }
3164   GNUNET_SCHEDULER_add_delayed (sched,
3165                                 GNUNET_TIME_UNIT_FOREVER_REL,
3166                                 &shutdown_task, NULL);
3167   if (no_transports)
3168     refresh_hello ();
3169
3170 #if DEBUG_TRANSPORT
3171   GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
3172 #endif
3173   /* process client requests */
3174   GNUNET_SERVER_add_handlers (server, handlers);
3175 }
3176
3177
3178 /**
3179  * The main function for the transport service.
3180  *
3181  * @param argc number of arguments from the command line
3182  * @param argv command line arguments
3183  * @return 0 ok, 1 on error
3184  */
3185 int
3186 main (int argc, char *const *argv)
3187 {
3188   return (GNUNET_OK ==
3189           GNUNET_SERVICE_run (argc,
3190                               argv,
3191                               "transport",
3192                               GNUNET_SERVICE_OPTION_NONE,
3193                               &run, NULL)) ? 0 : 1;
3194 }
3195
3196 /* end of gnunet-service-transport.c */