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