hopefully partially fixing non worky problems on various machines. but since I haven...
[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       GNUNET_SCHEDULER_add_delayed (sched,
1674                                     GNUNET_TIME_absolute_get_remaining
1675                                     (first), &cleanup_validation, NULL);
1676     }
1677 }
1678
1679
1680 /**
1681  * Function that will be called if we receive a validation
1682  * of an address challenge that we transmitted to another
1683  * peer.  Note that the validation should only be considered
1684  * acceptable if the challenge matches AND if the sender
1685  * address is at least a plausible address for this peer
1686  * (otherwise we may be seeing a MiM attack).
1687  *
1688  * @param cls closure
1689  * @param name name of the transport that generated the address
1690  * @param peer who responded to our challenge
1691  * @param challenge the challenge number we presumably used
1692  * @param sender_addr string describing our sender address (as observed
1693  *         by the other peer in human-readable format)
1694  */
1695 static void
1696 handle_pong (void *cls, const struct GNUNET_MessageHeader *message,
1697              const struct GNUNET_PeerIdentity *peer,
1698              const char *sender_address,
1699              size_t sender_address_len)
1700 {
1701   unsigned int not_done;
1702   int matched;
1703   struct ValidationList *pos;
1704   struct ValidationAddress *va;
1705   struct GNUNET_PeerIdentity id;
1706   struct TransportPongMessage *pong = (struct TransportPongMessage *)message;
1707   int count = 0;
1708   unsigned int challenge = ntohl(pong->challenge);
1709   pos = pending_validations;
1710
1711   while (pos != NULL)
1712     {
1713       GNUNET_CRYPTO_hash (&pos->publicKey,
1714                           sizeof (struct
1715                                   GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1716                           &id.hashPubKey);
1717       if (0 == memcmp (peer, &id, sizeof (struct GNUNET_PeerIdentity)))
1718         break;
1719       pos = pos->next;
1720       count++;
1721     }
1722   if (pos == NULL)
1723     {
1724       /* TODO: call statistics (unmatched PONG) */
1725       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1726                   _
1727                   ("Received validation response but have no record of any validation request for `%4s' (out of %d). Ignoring.\n"),
1728                   GNUNET_i2s (peer), count);
1729       return;
1730     }
1731   not_done = 0;
1732   matched = GNUNET_NO;
1733   va = pos->addresses;
1734   while (va != NULL)
1735     {
1736       if (va->challenge == challenge)
1737         {
1738 #if DEBUG_TRANSPORT
1739           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1740                       "Confirmed validity of address, peer `%4s' has address `%s'.\n",
1741                       GNUNET_i2s (peer),
1742                       GNUNET_a2s ((const struct sockaddr *) sender_address,
1743                                   sender_address_len));
1744 #endif
1745           GNUNET_log (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
1746                       _
1747                       ("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"),
1748                       GNUNET_a2s ((const struct sockaddr *) &pong[1],
1749                                                            ntohs(pong->addrlen)), va->transport_name);
1750           va->ok = GNUNET_YES;
1751           va->expiration =
1752             GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1753           matched = GNUNET_YES;
1754           va->peer_address->connected = GNUNET_YES;
1755           va->peer_address->latency = GNUNET_TIME_absolute_get_difference(va->peer_address->validation->send_time, GNUNET_TIME_absolute_get());
1756 #if DEBUG_TRANSPORT
1757           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1758                       "Confirmed validity of address, peer `%4s' has address `%s', latency of %llu\n",
1759                       GNUNET_i2s (peer),
1760                       GNUNET_a2s ((const struct sockaddr *) sender_address,
1761                                   sender_address_len), (unsigned long long)va->peer_address->latency.value);
1762 #endif
1763           va->peer_address->transmit_ready = GNUNET_YES;
1764           va->peer_address->expires = GNUNET_TIME_relative_to_absolute
1765               (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1766         }
1767       if (va->ok != GNUNET_YES)
1768         not_done++;
1769       va = va->next;
1770     }
1771   if (GNUNET_NO == matched)
1772     {
1773       /* TODO: call statistics (unmatched PONG) */
1774       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1775                   _
1776                   ("Received `%s' message but have no record of a matching `%s' message. Ignoring.\n"),
1777                   "PONG", "PING");
1778     }
1779   if (0 == not_done)
1780     {
1781 #if DEBUG_TRANSPORT
1782       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1783                   "All addresses validated, will now construct `%s' for `%4s'.\n",
1784                   "HELLO", GNUNET_i2s (peer));
1785 #endif
1786       pos->timeout.value = 0;
1787       GNUNET_SCHEDULER_add_with_priority (sched,
1788                                           GNUNET_SCHEDULER_PRIORITY_IDLE,
1789                                           &cleanup_validation, NULL);
1790     }
1791
1792 }
1793
1794 /**
1795  * Add an entry for each of our transport plugins
1796  * (that are able to send) to the list of plugins
1797  * for this neighbor.
1798  *
1799  * @param neighbor to initialize
1800  */
1801 static void
1802 add_plugins (struct NeighborList *neighbor)
1803 {
1804   struct TransportPlugin *tp;
1805   struct ReadyList *rl;
1806
1807   neighbor->retry_plugins_time
1808     = GNUNET_TIME_relative_to_absolute (PLUGIN_RETRY_FREQUENCY);
1809   tp = plugins;
1810   while (tp != NULL)
1811     {
1812       if (tp->api->send != NULL)
1813         {
1814           rl = GNUNET_malloc (sizeof (struct ReadyList));
1815           rl->next = neighbor->plugins;
1816           neighbor->plugins = rl;
1817           rl->plugin = tp;
1818           rl->neighbor = neighbor;
1819           rl->addresses = NULL;
1820         }
1821       tp = tp->next;
1822     }
1823 }
1824
1825 static void
1826 neighbor_timeout_task (void *cls,
1827                         const struct GNUNET_SCHEDULER_TaskContext *tc)
1828 {
1829   struct NeighborList *n = cls;
1830
1831 #if DEBUG_TRANSPORT
1832   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1833               "Neighbor `%4s' has timed out!\n", GNUNET_i2s (&n->id));
1834 #endif
1835   n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
1836   disconnect_neighbor (n, GNUNET_NO);
1837 }
1838
1839 /**
1840  * Create a fresh entry in our neighbor list for the given peer.
1841  * Will try to transmit our current HELLO to the new neighbor.  Also
1842  * notifies our clients about the new "connection".
1843  *
1844  * @param peer the peer for which we create the entry
1845  * @return the new neighbor list entry
1846  */
1847 static struct NeighborList *
1848 setup_new_neighbor (const struct GNUNET_PeerIdentity *peer)
1849 {
1850   struct NeighborList *n;
1851
1852   GNUNET_assert (our_hello != NULL);
1853   n = GNUNET_malloc (sizeof (struct NeighborList));
1854   n->next = neighbors;
1855   neighbors = n;
1856   n->id = *peer;
1857   n->last_quota_update = GNUNET_TIME_absolute_get ();
1858   n->peer_timeout =
1859     GNUNET_TIME_relative_to_absolute
1860     (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1861   n->quota_in = (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000);
1862   add_plugins (n);
1863   n->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
1864                                                   GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1865                                                   &neighbor_timeout_task, n);
1866   transmit_to_peer (NULL, NULL, 0,
1867                     (const char *) our_hello, GNUNET_HELLO_size(our_hello),
1868                     GNUNET_YES, n);
1869   notify_clients_connect (peer, GNUNET_TIME_UNIT_FOREVER_REL);
1870   return n;
1871 }
1872
1873 static struct PeerAddressList *
1874 add_peer_address(struct NeighborList *neighbor, const char *addr, size_t addrlen)
1875 {
1876   /* FIXME: should return a list of PeerAddressLists, support for multiple transports! */
1877   struct ReadyList *head = neighbor->plugins;
1878   struct PeerAddressList * new_address;
1879
1880   GNUNET_assert(addr != NULL);
1881
1882   while (head != NULL)
1883     {
1884       new_address = GNUNET_malloc(sizeof(struct PeerAddressList));
1885       new_address->addr = GNUNET_malloc(addrlen);
1886       memcpy(new_address->addr, addr, addrlen);
1887       new_address->addrlen = addrlen;
1888       new_address->connect_attempts = 0;
1889       new_address->connected = GNUNET_YES; /* Set connected to GNUNET_YES, assuming that we're good */
1890       new_address->expires = GNUNET_TIME_relative_to_absolute
1891           (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1892       new_address->latency = GNUNET_TIME_relative_get_forever();
1893       new_address->neighbor = neighbor;
1894       new_address->plugin = head->plugin;
1895       new_address->transmit_ready = GNUNET_YES;
1896       new_address->timeout = GNUNET_TIME_relative_to_absolute
1897           (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT); /* FIXME: Do we need this? */
1898       new_address->ready_list = head;
1899       new_address->next = head->addresses;
1900       head->addresses = new_address;
1901       head = head->next;
1902     }
1903
1904   return new_address;
1905 }
1906
1907 static struct PeerAddressList *
1908 find_peer_address(struct NeighborList *neighbor, const char *addr, size_t addrlen)
1909 {
1910   struct ReadyList *head = neighbor->plugins;
1911   struct PeerAddressList *address_head;
1912   while (head != NULL)
1913     {
1914       address_head = head->addresses;
1915       while ((address_head != NULL) &&
1916               (address_head->addrlen != addrlen) &&
1917               (memcmp(address_head->addr, addr, addrlen) != 0))
1918         {
1919           address_head = address_head->next;
1920         }
1921       if (address_head != NULL)
1922         return address_head;
1923
1924       head = head->next;
1925     }
1926   return NULL;
1927 }
1928
1929 /**
1930  * Append the given address to the list of entries
1931  * that need to be validated.
1932  */
1933 static int
1934 run_validation (void *cls,
1935                 const char *tname,
1936                 struct GNUNET_TIME_Absolute expiration,
1937                 const void *addr, size_t addrlen)
1938 {
1939   struct ValidationList *e = cls;
1940   struct TransportPlugin *tp;
1941   struct ValidationAddress *va;
1942   struct GNUNET_PeerIdentity id;
1943   struct NeighborList *neighbor;
1944   struct PeerAddressList *peer_address;
1945   int sent;
1946   struct TransportPingMessage *ping;
1947   char * message_buf;
1948   int hello_size;
1949   int tsize;
1950
1951   tp = find_transport (tname);
1952   if (tp == NULL)
1953     {
1954       GNUNET_log (GNUNET_ERROR_TYPE_INFO |
1955                   GNUNET_ERROR_TYPE_BULK,
1956                   _
1957                   ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
1958                   tname);
1959       return GNUNET_OK;
1960     }
1961   GNUNET_CRYPTO_hash (&e->publicKey,
1962                       sizeof (struct
1963                               GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1964                       &id.hashPubKey);
1965 #if DEBUG_TRANSPORT
1966   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1967               "Scheduling validation of address `%s' via `%s' for `%4s'\n",
1968               GNUNET_a2s (addr, addrlen), tname, GNUNET_i2s (&id));
1969 #endif
1970   va = GNUNET_malloc (sizeof (struct ValidationAddress));
1971   va->next = e->addresses;
1972   e->addresses = va;
1973   va->transport_name = GNUNET_strdup (tname);
1974   va->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1975                                             (unsigned int) -1);
1976   va->send_time = GNUNET_TIME_absolute_get();
1977
1978   neighbor = find_neighbor(&id);
1979
1980   if (neighbor == NULL)
1981     neighbor = setup_new_neighbor(&id);
1982
1983   peer_address = find_peer_address(neighbor, addr, addrlen);
1984   if (peer_address == NULL)
1985     {
1986       peer_address = add_peer_address(neighbor, addr, addrlen);
1987     }
1988
1989   GNUNET_assert(peer_address != NULL);
1990
1991   va->peer_address = peer_address; /* Back pointer FIXME: remove this nonsense! */
1992   peer_address->validation = va;
1993
1994   hello_size = GNUNET_HELLO_size(our_hello);
1995   tsize = sizeof(struct TransportPingMessage) + hello_size;
1996
1997   message_buf = GNUNET_malloc(tsize);
1998
1999   ping = GNUNET_malloc(sizeof(struct TransportPingMessage));
2000   ping->challenge = htonl(va->challenge);
2001   ping->header.size = htons(sizeof(struct TransportPingMessage));
2002   ping->header.type = htons(GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
2003   memcpy(&ping->target, &id, sizeof(struct GNUNET_PeerIdentity));
2004
2005 #if DEBUG_TRANSPORT
2006   GNUNET_log(GNUNET_ERROR_TYPE_DEBUG, "hello size is %d, ping size is %d, total size is %d", hello_size, sizeof(struct TransportPingMessage), tsize);
2007 #endif
2008   memcpy(message_buf, our_hello, hello_size);
2009   memcpy(&message_buf[hello_size], ping, sizeof(struct TransportPingMessage));
2010
2011 #if DEBUG_TRANSPORT
2012   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending ping message of size %d to address `%s' via `%s' for `%4s'\n",
2013                 tsize, GNUNET_a2s (addr, addrlen), tname, GNUNET_i2s (&id));
2014 #endif
2015   sent = transmit_to_peer(NULL, peer_address, GNUNET_SCHEDULER_PRIORITY_DEFAULT,
2016                    message_buf, tsize, GNUNET_NO, neighbor);
2017
2018 #if DEBUG_TRANSPORT
2019   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transport returned %d from send!\n", sent);
2020 #endif
2021
2022   GNUNET_free(ping);
2023   GNUNET_free(message_buf);
2024   return GNUNET_OK;
2025 }
2026
2027 #if WHY
2028 /*
2029  * @param cls handle to the plugin (for sending)
2030  * @param target the peer identity of the peer we are sending to
2031  * @param challenge the challenge number
2032  * @param timeout how long to await validation?
2033  * @param addr the address to validate
2034  * @param addrlen the length of the address
2035  *
2036  * Perform address validation, which means sending a PING PONG to
2037  * the address via the transport plugin.  If not validated, then
2038  * do not count this as a good peer/address...
2039  *
2040  * Currently this function is not used, ping/pongs get sent from the
2041  * run_validation function.  Haven't decided yet how to do this.
2042  */
2043 static void
2044 validate_address (void *cls, struct ValidationAddress *va,
2045                   const struct GNUNET_PeerIdentity *target,
2046                   struct GNUNET_TIME_Relative timeout,
2047                   const void *addr, size_t addrlen)
2048 {
2049   /* struct Plugin *plugin = cls;
2050   int challenge = va->challenge; */
2051
2052
2053   return;
2054 }
2055 #endif
2056
2057 /**
2058  * Check if addresses in validated hello "h" overlap with
2059  * those in "chvc->hello" and update "chvc->hello" accordingly,
2060  * removing those addresses that have already been validated.
2061  */
2062 static void
2063 check_hello_validated (void *cls,
2064                        const struct GNUNET_PeerIdentity *peer,
2065                        const struct GNUNET_HELLO_Message *h, uint32_t trust)
2066 {
2067   struct CheckHelloValidatedContext *chvc = cls;
2068   struct ValidationAddress *va;
2069   struct TransportPlugin *tp;
2070   int first_call;
2071   int count;
2072   struct GNUNET_PeerIdentity apeer;
2073
2074   first_call = GNUNET_NO;
2075   if (chvc->e == NULL)
2076     {
2077       chvc->piter = NULL;
2078       first_call = GNUNET_YES;
2079       chvc->e = GNUNET_malloc (sizeof (struct ValidationList));
2080       GNUNET_assert (GNUNET_OK ==
2081                      GNUNET_HELLO_get_key (h != NULL ? h : chvc->hello,
2082                                            &chvc->e->publicKey));
2083       chvc->e->timeout =
2084         GNUNET_TIME_relative_to_absolute (HELLO_VERIFICATION_TIMEOUT);
2085       chvc->e->next = pending_validations;
2086       pending_validations = chvc->e;
2087     }
2088
2089   if (h != NULL)
2090     {
2091       GNUNET_HELLO_iterate_new_addresses (chvc->hello,
2092                                           h,
2093                                           GNUNET_TIME_absolute_get (),
2094                                           &run_validation, chvc->e);
2095     }
2096   else if (GNUNET_YES == first_call)
2097     {
2098       /* no existing HELLO, all addresses are new */
2099       GNUNET_HELLO_iterate_addresses (chvc->hello,
2100                                       GNUNET_NO, &run_validation, chvc->e);
2101     }
2102
2103   if (h != NULL)
2104     return;                     /* wait for next call */
2105   /* finally, transmit validation attempts */
2106   GNUNET_assert (GNUNET_OK == GNUNET_HELLO_get_id (chvc->hello, &apeer));
2107
2108   va = chvc->e->addresses;
2109   count = 0;
2110   while (va != NULL)
2111     {
2112 #if DEBUG_TRANSPORT
2113       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2114                   "Establishing `%s' connection to validate `%s' address `%s' of `%4s'\n",
2115                   va->transport_name,
2116                   "HELLO",
2117                   GNUNET_a2s ((const struct sockaddr *) va->peer_address->addr,
2118                               va->peer_address->addrlen), GNUNET_i2s (&apeer));
2119 #endif
2120       tp = find_transport (va->transport_name);
2121       GNUNET_assert (tp != NULL);
2122       /* This validation should happen inside the transport, not from the plugin! */
2123       va->ok = GNUNET_SYSERR;
2124       va = va->next;
2125       count++;
2126     }
2127
2128   GNUNET_SCHEDULER_add_delayed (sched,
2129                                 GNUNET_TIME_absolute_get_remaining (chvc->
2130                                                                     e->timeout),
2131                                 &cleanup_validation, NULL);
2132   GNUNET_free (chvc);
2133 }
2134
2135
2136 /**
2137  * Process HELLO-message.
2138  *
2139  * @param plugin transport involved, may be NULL
2140  * @param message the actual message
2141  * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
2142  */
2143 static int
2144 process_hello (struct TransportPlugin *plugin,
2145                const struct GNUNET_MessageHeader *message)
2146 {
2147   struct ValidationList *e;
2148   uint16_t hsize;
2149   struct GNUNET_PeerIdentity target;
2150   const struct GNUNET_HELLO_Message *hello;
2151   struct CheckHelloValidatedContext *chvc;
2152   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
2153
2154   hsize = ntohs (message->size);
2155   if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
2156       (hsize < sizeof (struct GNUNET_MessageHeader)))
2157     {
2158       GNUNET_break (0);
2159       return GNUNET_SYSERR;
2160     }
2161   /* first, check if load is too high */
2162   if (GNUNET_OS_load_cpu_get (cfg) > 100)
2163     {
2164       /* TODO: call to stats? */
2165       return GNUNET_OK;
2166     }
2167   hello = (const struct GNUNET_HELLO_Message *) message;
2168   if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
2169     {
2170       GNUNET_break_op (0);
2171       return GNUNET_SYSERR;
2172     }
2173   GNUNET_CRYPTO_hash (&publicKey,
2174                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
2175                       &target.hashPubKey);
2176 #if DEBUG_TRANSPORT
2177   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2178               "Processing `%s' message for `%4s' of size %d (hsize is %d)\n",
2179               "HELLO", GNUNET_i2s (&target), GNUNET_HELLO_size(hello), hsize);
2180 #endif
2181   /* check if a HELLO for this peer is already on the validation list */
2182   e = pending_validations;
2183   while (e != NULL)
2184     {
2185       if (0 == memcmp (&e->publicKey,
2186                        &publicKey,
2187                        sizeof (struct
2188                                GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)))
2189         {
2190           /* TODO: call to stats? */
2191 #if DEBUG_TRANSPORT
2192           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2193                       "`%s' message for peer `%4s' is already pending; ignoring new message\n",
2194                       "HELLO", GNUNET_i2s (&target));
2195 #endif
2196           return GNUNET_OK;
2197         }
2198       e = e->next;
2199     }
2200   chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
2201   chvc->plugin = plugin;
2202   chvc->hello = (struct GNUNET_HELLO_Message *) &chvc[1];
2203   chvc->e = NULL;
2204   memcpy (chvc->hello, hello, hsize);
2205   /* finally, check if HELLO was previously validated
2206      (continuation will then schedule actual validation) */
2207   chvc->piter = GNUNET_PEERINFO_iterate (cfg,
2208                                          sched,
2209                                          &target,
2210                                          0,
2211                                          HELLO_VERIFICATION_TIMEOUT,
2212                                          &check_hello_validated, chvc);
2213   return GNUNET_OK;
2214 }
2215
2216
2217 /**
2218  * The peer specified by the given neighbor has timed-out or a plugin
2219  * has disconnected.  We may either need to do nothing (other plugins
2220  * still up), or trigger a full disconnect and clean up.  This
2221  * function updates our state and does the necessary notifications.
2222  * Also notifies our clients that the neighbor is now officially
2223  * gone.
2224  *
2225  * @param n the neighbor list entry for the peer
2226  * @param check should we just check if all plugins
2227  *        disconnected or must we ask all plugins to
2228  *        disconnect?
2229  */
2230 static void
2231 disconnect_neighbor (struct NeighborList *current_handle, int check)
2232 {
2233   struct ReadyList *rpos;
2234   struct NeighborList *npos;
2235   struct NeighborList *nprev;
2236   struct NeighborList *n;
2237   struct MessageQueue *mq;
2238   struct PeerAddressList *peer_addresses;
2239
2240   if (neighbors == NULL)
2241     return; /* We don't have any neighbors, so client has an already removed handle! */
2242
2243   npos = neighbors;
2244   while ((npos != NULL) && (current_handle != npos))
2245     npos = npos->next;
2246
2247   if (npos == NULL)
2248     return; /* Couldn't find neighbor in existing list, must have been already removed! */
2249   else
2250     n = npos;
2251
2252   if (GNUNET_YES == check)
2253     {
2254       rpos = n->plugins;
2255       while (NULL != rpos)
2256         {
2257           peer_addresses = rpos->addresses;
2258           while (peer_addresses != NULL)
2259             {
2260               if (GNUNET_YES == peer_addresses->connected)
2261                 return;             /* still connected */
2262               peer_addresses = peer_addresses->next;
2263             }
2264           rpos = rpos->next;
2265         }
2266     }
2267
2268 #if DEBUG_TRANSPORT
2269   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2270               "Disconnecting from `%4s'\n", GNUNET_i2s (&n->id));
2271 #endif
2272   /* remove n from neighbors list */
2273   nprev = NULL;
2274   npos = neighbors;
2275   while ((npos != NULL) && (npos != n))
2276     {
2277       nprev = npos;
2278       npos = npos->next;
2279     }
2280   GNUNET_assert (npos != NULL);
2281   if (nprev == NULL)
2282     neighbors = n->next;
2283   else
2284     nprev->next = n->next;
2285
2286   /* notify all clients about disconnect */
2287   notify_clients_disconnect (&n->id);
2288
2289   /* clean up all plugins, cancel connections and pending transmissions */
2290   while (NULL != (rpos = n->plugins))
2291     {
2292       n->plugins = rpos->next;
2293       GNUNET_assert (rpos->neighbor == n);
2294       if (GNUNET_YES == rpos->connected)
2295         rpos->plugin->api->disconnect (rpos->plugin->api->cls, &n->id);
2296       GNUNET_free (rpos);
2297     }
2298
2299   /* free all messages on the queue */
2300   while (NULL != (mq = n->messages))
2301     {
2302       n->messages = mq->next;
2303       GNUNET_assert (mq->neighbor == n);
2304       GNUNET_free (mq);
2305     }
2306   if (n->timeout_task != GNUNET_SCHEDULER_NO_TASK)
2307     GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
2308   /* finally, free n itself */
2309   GNUNET_free (n);
2310 }
2311
2312
2313 /*
2314  * We have received a PING message from someone.  Need to send a PONG message
2315  * in response to the peer by any means necessary.  Of course, with something
2316  * like TCP where a connection exists, we may want to send it that way.  But
2317  * we may not be able to make that distinction...
2318  */
2319 static int handle_ping(void *cls, const struct GNUNET_MessageHeader *message,
2320                        const struct GNUNET_PeerIdentity *peer,
2321                        const char *sender_address,
2322                        size_t sender_address_len)
2323 {
2324   struct TransportPlugin *plugin = cls;
2325   struct TransportPingMessage *ping;
2326   struct TransportPongMessage *pong;
2327   struct PeerAddressList *peer_address;
2328   uint16_t msize;
2329   struct NeighborList *n;
2330   pong = GNUNET_malloc(sizeof(struct TransportPongMessage));
2331
2332 #if DEBUG_TRANSPORT
2333     GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2334                 "Processing `%s' from `%s'\n",
2335                "PING", GNUNET_a2s ((const struct sockaddr *)sender_address, sender_address_len));
2336 #endif
2337
2338   msize = ntohs (message->size);
2339   if (msize < sizeof (struct TransportPingMessage))
2340     {
2341       GNUNET_break_op (0);
2342       return GNUNET_SYSERR;
2343     }
2344   ping = (struct TransportPingMessage *) message;
2345   if (0 != memcmp (&ping->target,
2346                    plugin->env.my_identity,
2347                    sizeof (struct GNUNET_PeerIdentity)))
2348     {
2349       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2350                   _("Received `%s' message not destined for me!\n"), "PING");
2351       return GNUNET_SYSERR;
2352     }
2353
2354   msize -= sizeof (struct TransportPingMessage);
2355
2356   pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + sender_address_len);
2357   pong->header.size = htons (sizeof (struct TransportPongMessage) + sender_address_len);
2358   pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
2359   pong->purpose.size =
2360     htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
2361            sizeof (uint32_t) +
2362            sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) + sender_address_len);
2363   pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_TCP_PING);
2364   pong->challenge = ping->challenge;
2365   pong->addrlen = htons(sender_address_len);
2366
2367   memcpy(&pong->signer, &my_public_key, sizeof(struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded));
2368   memcpy (&pong[1], sender_address, sender_address_len);
2369   GNUNET_assert (GNUNET_OK ==
2370                  GNUNET_CRYPTO_rsa_sign (my_private_key,
2371                                          &pong->purpose, &pong->signature));
2372
2373   n = find_neighbor(peer);
2374   if (n == NULL)
2375     n = setup_new_neighbor(peer);
2376
2377   peer_address = find_peer_address(n, sender_address, sender_address_len);
2378   if (peer_address == NULL)
2379     peer_address = add_peer_address(n, sender_address, sender_address_len);
2380
2381   transmit_to_peer(NULL, NULL, TRANSPORT_DEFAULT_PRIORITY, (char *)pong, ntohs(pong->header.size), GNUNET_NO, n);
2382
2383   GNUNET_free(pong);
2384   return GNUNET_OK;
2385 }
2386
2387 /**
2388  * Function called by the plugin for each received message.
2389  * Update data volumes, possibly notify plugins about
2390  * reducing the rate at which they read from the socket
2391  * and generally forward to our receive callback.
2392  *
2393  * @param cls the "struct TransportPlugin *" we gave to the plugin
2394  * @param message the message, NULL if peer was disconnected
2395  * @param distance the transport cost to this peer (not latency!)
2396  * @param sender_address the address that the sender reported
2397  *        (opaque to transport service)
2398  * @param sender_address_len the length of the sender address
2399  * @param peer (claimed) identity of the other peer
2400  * @return the new service_context that the plugin should use
2401  *         for future receive calls for messages from this
2402  *         particular peer
2403  *
2404  */
2405 static void
2406 plugin_env_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
2407                     const struct GNUNET_MessageHeader *message,
2408                     unsigned int distance, const char *sender_address,
2409                     size_t sender_address_len)
2410 {
2411   struct ReadyList *service_context;
2412   struct TransportPlugin *plugin = cls;
2413   struct TransportClient *cpos;
2414   struct InboundMessage *im;
2415   struct PeerAddressList *peer_address;
2416   uint16_t msize;
2417   struct NeighborList *n;
2418
2419   n = find_neighbor (peer);
2420   if (n == NULL)
2421     {
2422       if (message == NULL)
2423         return;                 /* disconnect of peer already marked down */
2424       n = setup_new_neighbor (peer);
2425
2426     }
2427
2428   peer_address = find_peer_address(n, sender_address, sender_address_len);
2429   if (peer_address == NULL)
2430     peer_address = add_peer_address(n, sender_address, sender_address_len);
2431
2432   service_context = n->plugins;
2433   while ((service_context != NULL) && (plugin != service_context->plugin))
2434     service_context = service_context->next;
2435   GNUNET_assert ((plugin->api->send == NULL) || (service_context != NULL));
2436   if (message == NULL)
2437     {
2438 #if DEBUG_TRANSPORT
2439       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2440                   "Receive failed from `%4s', triggering disconnect\n",
2441                   GNUNET_i2s (&n->id));
2442 #endif
2443       /* TODO: call stats */
2444       if (service_context != NULL)
2445         service_context->connected = GNUNET_NO;
2446       disconnect_neighbor (n, GNUNET_YES);
2447       return;
2448     }
2449 #if DEBUG_TRANSPORT
2450   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2451               "Processing message of type `%u' received by plugin...\n",
2452               ntohs (message->type));
2453 #endif
2454   if (service_context != NULL)
2455     {
2456       if (service_context->connected == GNUNET_NO)
2457         {
2458           /*service_context->connected = GNUNET_YES;*/
2459           /* FIXME: What to do here?  Should we use these as well, to specify some Address
2460            * in the AddressList should be available?
2461            */
2462           peer_address->transmit_ready = GNUNET_YES;
2463           peer_address->connect_attempts++;
2464         }
2465       peer_address->timeout
2466         =
2467         GNUNET_TIME_relative_to_absolute
2468         (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2469     }
2470   /* update traffic received amount ... */
2471   msize = ntohs (message->size);
2472   n->last_received += msize;
2473   GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
2474   n->peer_timeout =
2475     GNUNET_TIME_relative_to_absolute
2476     (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2477   n->timeout_task =
2478     GNUNET_SCHEDULER_add_delayed (sched,
2479                                   GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2480                                   &neighbor_timeout_task, n);
2481   update_quota (n);
2482   if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
2483     {
2484       /* dropping message due to frequent inbound volume violations! */
2485       GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
2486                   GNUNET_ERROR_TYPE_BULK,
2487                   _
2488                   ("Dropping incoming message due to repeated bandwidth quota violations.\n"));
2489       /* TODO: call stats */
2490       GNUNET_assert ((service_context == NULL) ||
2491                      (NULL != service_context->neighbor));
2492       return;
2493     }
2494   switch (ntohs (message->type))
2495     {
2496     case GNUNET_MESSAGE_TYPE_HELLO:
2497 #if DEBUG_TRANSPORT
2498       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2499                   "Receiving `%s' message from `%4s'.\n", "HELLO",
2500                   GNUNET_i2s (peer));
2501 #endif
2502       process_hello (plugin, message);
2503       break;
2504     case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
2505       handle_ping(plugin, message, peer, sender_address, sender_address_len);
2506       break;
2507     case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
2508       handle_pong(plugin, message, peer, sender_address, sender_address_len);
2509       break;
2510     default:
2511 #if DEBUG_TRANSPORT
2512       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2513                   "Received REAL MESSAGE type %u from `%4s', sending to all clients.\n",
2514                   ntohs (message->type), GNUNET_i2s (peer));
2515 #endif
2516       /* transmit message to all clients */
2517       im = GNUNET_malloc (sizeof (struct InboundMessage) + msize);
2518       im->header.size = htons (sizeof (struct InboundMessage) + msize);
2519       im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
2520       im->latency = n->latency;
2521       im->peer = *peer;
2522       memcpy (&im[1], message, msize);
2523
2524       cpos = clients;
2525       while (cpos != NULL)
2526         {
2527           transmit_to_client (cpos, &im->header, GNUNET_YES);
2528           cpos = cpos->next;
2529         }
2530       GNUNET_free (im);
2531     }
2532   GNUNET_assert ((service_context == NULL) ||
2533                  (NULL != service_context->neighbor));
2534 }
2535
2536
2537 /**
2538  * Handle START-message.  This is the first message sent to us
2539  * by any client which causes us to add it to our list.
2540  *
2541  * @param cls closure (always NULL)
2542  * @param client identification of the client
2543  * @param message the actual message
2544  */
2545 static void
2546 handle_start (void *cls,
2547               struct GNUNET_SERVER_Client *client,
2548               const struct GNUNET_MessageHeader *message)
2549 {
2550   struct TransportClient *c;
2551   struct ConnectInfoMessage cim;
2552   struct NeighborList *n;
2553   struct InboundMessage *im;
2554   struct GNUNET_MessageHeader *ack;
2555
2556 #if DEBUG_TRANSPORT
2557   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2558               "Received `%s' request from client\n", "START");
2559 #endif
2560   c = clients;
2561   while (c != NULL)
2562     {
2563       if (c->client == client)
2564         {
2565           /* client already on our list! */
2566           GNUNET_break (0);
2567           GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2568           return;
2569         }
2570       c = c->next;
2571     }
2572   c = GNUNET_malloc (sizeof (struct TransportClient));
2573   c->next = clients;
2574   clients = c;
2575   c->client = client;
2576   if (our_hello != NULL)
2577     {
2578 #if DEBUG_TRANSPORT
2579       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2580                   "Sending our own `%s' to new client\n", "HELLO");
2581 #endif
2582       transmit_to_client (c,
2583                           (const struct GNUNET_MessageHeader *) our_hello,
2584                           GNUNET_NO);
2585       /* tell new client about all existing connections */
2586       cim.header.size = htons (sizeof (struct ConnectInfoMessage));
2587       cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2588       cim.quota_out =
2589         htonl (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT / (60 * 1000));
2590       cim.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO);  /* FIXME? */
2591       im = GNUNET_malloc (sizeof (struct InboundMessage) +
2592                           sizeof (struct GNUNET_MessageHeader));
2593       im->header.size = htons (sizeof (struct InboundMessage) +
2594                                sizeof (struct GNUNET_MessageHeader));
2595       im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
2596       im->latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO);  /* FIXME? */
2597       ack = (struct GNUNET_MessageHeader *) &im[1];
2598       ack->size = htons (sizeof (struct GNUNET_MessageHeader));
2599       ack->type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ACK);
2600       for (n = neighbors; n != NULL; n = n->next)
2601         {
2602           cim.id = n->id;
2603           transmit_to_client (c, &cim.header, GNUNET_NO);
2604           if (n->received_pong)
2605             {
2606               im->peer = n->id;
2607               transmit_to_client (c, &im->header, GNUNET_NO);
2608             }
2609         }
2610       GNUNET_free (im);
2611     }
2612   else
2613     {
2614       fprintf(stderr, "Our hello is NULL!\n");
2615     }
2616   GNUNET_SERVER_receive_done (client, GNUNET_OK);
2617 }
2618
2619
2620 /**
2621  * Handle HELLO-message.
2622  *
2623  * @param cls closure (always NULL)
2624  * @param client identification of the client
2625  * @param message the actual message
2626  */
2627 static void
2628 handle_hello (void *cls,
2629               struct GNUNET_SERVER_Client *client,
2630               const struct GNUNET_MessageHeader *message)
2631 {
2632   int ret;
2633
2634 #if DEBUG_TRANSPORT
2635   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2636               "Received `%s' request from client\n", "HELLO");
2637 #endif
2638   ret = process_hello (NULL, message);
2639   GNUNET_SERVER_receive_done (client, ret);
2640 }
2641
2642
2643 /**
2644  * Handle SEND-message.
2645  *
2646  * @param cls closure (always NULL)
2647  * @param client identification of the client
2648  * @param message the actual message
2649  */
2650 static void
2651 handle_send (void *cls,
2652              struct GNUNET_SERVER_Client *client,
2653              const struct GNUNET_MessageHeader *message)
2654 {
2655   struct TransportClient *tc;
2656   struct NeighborList *n;
2657   const struct OutboundMessage *obm;
2658   const struct GNUNET_MessageHeader *obmm;
2659   uint16_t size;
2660   uint16_t msize;
2661
2662   size = ntohs (message->size);
2663   if (size <
2664       sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
2665     {
2666       GNUNET_break (0);
2667       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2668       return;
2669     }
2670   obm = (const struct OutboundMessage *) message;
2671 #if DEBUG_TRANSPORT
2672   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2673               "Received `%s' request from client with target `%4s'\n",
2674               "SEND", GNUNET_i2s (&obm->peer));
2675 #endif
2676   obmm = (const struct GNUNET_MessageHeader *) &obm[1];
2677   msize = ntohs (obmm->size);
2678   if (size != msize + sizeof (struct OutboundMessage))
2679     {
2680       GNUNET_break (0);
2681       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2682       return;
2683     }
2684   n = find_neighbor (&obm->peer);
2685   if (n == NULL)
2686     n = setup_new_neighbor (&obm->peer); /* But won't ever add address, we have none! */
2687   tc = clients;
2688   while ((tc != NULL) && (tc->client != client))
2689     tc = tc->next;
2690
2691 #if DEBUG_TRANSPORT
2692   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2693               "Client asked to transmit %u-byte message of type %u to `%4s'\n",
2694               ntohs (obmm->size),
2695               ntohs (obmm->type), GNUNET_i2s (&obm->peer));
2696 #endif
2697   transmit_to_peer (tc, NULL, ntohl (obm->priority), (char *)obmm, ntohs (obmm->size), GNUNET_NO, n);
2698   GNUNET_SERVER_receive_done (client, GNUNET_OK);
2699 }
2700
2701
2702 /**
2703  * Handle SET_QUOTA-message.
2704  *
2705  * @param cls closure (always NULL)
2706  * @param client identification of the client
2707  * @param message the actual message
2708  */
2709 static void
2710 handle_set_quota (void *cls,
2711                   struct GNUNET_SERVER_Client *client,
2712                   const struct GNUNET_MessageHeader *message)
2713 {
2714   const struct QuotaSetMessage *qsm =
2715     (const struct QuotaSetMessage *) message;
2716   struct NeighborList *n;
2717   struct TransportPlugin *p;
2718   struct ReadyList *rl;
2719
2720 #if DEBUG_TRANSPORT
2721   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2722               "Received `%s' request from client for peer `%4s'\n",
2723               "SET_QUOTA", GNUNET_i2s (&qsm->peer));
2724 #endif
2725   n = find_neighbor (&qsm->peer);
2726   if (n == NULL)
2727     {
2728       GNUNET_SERVER_receive_done (client, GNUNET_OK);
2729       return;
2730     }
2731   update_quota (n);
2732   if (n->quota_in < ntohl (qsm->quota_in))
2733     n->last_quota_update = GNUNET_TIME_absolute_get ();
2734   n->quota_in = ntohl (qsm->quota_in);
2735   rl = n->plugins;
2736   while (rl != NULL)
2737     {
2738       p = rl->plugin;
2739       p->api->set_receive_quota (p->api->cls,
2740                                  &qsm->peer, ntohl (qsm->quota_in));
2741       rl = rl->next;
2742     }
2743   GNUNET_SERVER_receive_done (client, GNUNET_OK);
2744 }
2745
2746
2747 /**
2748  * Handle TRY_CONNECT-message.
2749  *
2750  * @param cls closure (always NULL)
2751  * @param client identification of the client
2752  * @param message the actual message
2753  */
2754 static void
2755 handle_try_connect (void *cls,
2756                     struct GNUNET_SERVER_Client *client,
2757                     const struct GNUNET_MessageHeader *message)
2758 {
2759   const struct TryConnectMessage *tcm;
2760   struct NeighborList *neighbor;
2761   tcm = (const struct TryConnectMessage *) message;
2762 #if DEBUG_TRANSPORT
2763   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2764               "Received `%s' request from client %p asking to connect to `%4s'\n",
2765               "TRY_CONNECT", client, GNUNET_i2s (&tcm->peer));
2766 #endif
2767   neighbor = find_neighbor(&tcm->peer);
2768
2769   if (neighbor == NULL)
2770     setup_new_neighbor (&tcm->peer);
2771   else
2772     {
2773 #if DEBUG_TRANSPORT
2774       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2775                   "Client asked to connect to `%4s', but connection already exists\n",
2776                   "TRY_CONNECT", GNUNET_i2s (&tcm->peer));
2777 #endif
2778       transmit_to_peer (NULL, NULL, 0,
2779                         (const char *) our_hello, GNUNET_HELLO_size(our_hello),
2780                         GNUNET_YES, neighbor);
2781       notify_clients_connect (&tcm->peer, GNUNET_TIME_UNIT_FOREVER_REL);
2782     }
2783   GNUNET_SERVER_receive_done (client, GNUNET_OK);
2784 }
2785
2786 static void
2787 transmit_address_to_client (void *cls, const char *address)
2788 {
2789   struct GNUNET_SERVER_TransmitContext *tc = cls;
2790   size_t slen;
2791
2792   if (NULL == address)
2793     slen = 0;
2794   else
2795     slen = strlen (address) + 1;
2796   GNUNET_SERVER_transmit_context_append_data (tc, address, slen,
2797                                               GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
2798   if (NULL == address)
2799     GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
2800 }
2801
2802 /**
2803  * Handle AddressLookup-message.
2804  *
2805  * @param cls closure (always NULL)
2806  * @param client identification of the client
2807  * @param message the actual message
2808  */
2809 static void
2810 handle_address_lookup (void *cls,
2811                        struct GNUNET_SERVER_Client *client,
2812                        const struct GNUNET_MessageHeader *message)
2813 {
2814   const struct AddressLookupMessage *alum;
2815   struct TransportPlugin *lsPlugin;
2816   const char *nameTransport;
2817   const char *address;
2818   uint16_t size;
2819   struct GNUNET_SERVER_TransmitContext *tc;
2820
2821   size = ntohs (message->size);
2822   if (size < sizeof (struct AddressLookupMessage))
2823     {
2824       GNUNET_break_op (0);
2825       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2826       return;
2827     }
2828   alum = (const struct AddressLookupMessage *) message;
2829   uint32_t addressLen = ntohl (alum->addrlen);
2830   if (size <= sizeof (struct AddressLookupMessage) + addressLen)
2831     {
2832       GNUNET_break_op (0);
2833       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2834       return;
2835     }
2836   address = (const char *) &alum[1];
2837   nameTransport = (const char *) &address[addressLen];
2838   if (nameTransport
2839       [size - sizeof (struct AddressLookupMessage) - addressLen - 1] != '\0')
2840     {
2841       GNUNET_break_op (0);
2842       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2843       return;
2844     }
2845   struct GNUNET_TIME_Absolute timeout =
2846     GNUNET_TIME_absolute_ntoh (alum->timeout);
2847   struct GNUNET_TIME_Relative rtimeout =
2848     GNUNET_TIME_absolute_get_remaining (timeout);
2849   lsPlugin = find_transport (nameTransport);
2850   if (NULL == lsPlugin)
2851     {
2852       tc = GNUNET_SERVER_transmit_context_create (client);
2853       GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
2854                                                   GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
2855       GNUNET_SERVER_transmit_context_run (tc, rtimeout);
2856       return;
2857     }
2858   tc = GNUNET_SERVER_transmit_context_create (client);
2859   lsPlugin->api->address_pretty_printer (cls, nameTransport,
2860                                          address, addressLen, GNUNET_YES,
2861                                          rtimeout,
2862                                          &transmit_address_to_client, tc);
2863 }
2864
2865 /**
2866  * List of handlers for the messages understood by this
2867  * service.
2868  */
2869 static struct GNUNET_SERVER_MessageHandler handlers[] = {
2870   {&handle_start, NULL,
2871    GNUNET_MESSAGE_TYPE_TRANSPORT_START, 0},
2872   {&handle_hello, NULL,
2873    GNUNET_MESSAGE_TYPE_HELLO, 0},
2874   {&handle_send, NULL,
2875    GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
2876   {&handle_set_quota, NULL,
2877    GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
2878   {&handle_try_connect, NULL,
2879    GNUNET_MESSAGE_TYPE_TRANSPORT_TRY_CONNECT,
2880    sizeof (struct TryConnectMessage)},
2881   {&handle_address_lookup, NULL,
2882    GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
2883    0},
2884   {NULL, NULL, 0, 0}
2885 };
2886
2887
2888 /**
2889  * Setup the environment for this plugin.
2890  */
2891 static void
2892 create_environment (struct TransportPlugin *plug)
2893 {
2894   plug->env.cfg = cfg;
2895   plug->env.sched = sched;
2896   plug->env.my_identity = &my_identity;
2897   plug->env.cls = plug;
2898   plug->env.receive = &plugin_env_receive;
2899   plug->env.notify_address = &plugin_env_notify_address;
2900   plug->env.default_quota_in =
2901     (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000);
2902   plug->env.max_connections = max_connect_per_transport;
2903 }
2904
2905
2906 /**
2907  * Start the specified transport (load the plugin).
2908  */
2909 static void
2910 start_transport (struct GNUNET_SERVER_Handle *server, const char *name)
2911 {
2912   struct TransportPlugin *plug;
2913   char *libname;
2914
2915   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2916               _("Loading `%s' transport plugin\n"), name);
2917   GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
2918   plug = GNUNET_malloc (sizeof (struct TransportPlugin));
2919   create_environment (plug);
2920   plug->short_name = GNUNET_strdup (name);
2921   plug->lib_name = libname;
2922   plug->next = plugins;
2923   plugins = plug;
2924   plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
2925   if (plug->api == NULL)
2926     {
2927       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2928                   _("Failed to load transport plugin for `%s'\n"), name);
2929       GNUNET_free (plug->short_name);
2930       plugins = plug->next;
2931       GNUNET_free (libname);
2932       GNUNET_free (plug);
2933     }
2934 }
2935
2936
2937 /**
2938  * Called whenever a client is disconnected.  Frees our
2939  * resources associated with that client.
2940  *
2941  * @param cls closure
2942  * @param client identification of the client
2943  */
2944 static void
2945 client_disconnect_notification (void *cls,
2946                                 struct GNUNET_SERVER_Client *client)
2947 {
2948   struct TransportClient *pos;
2949   struct TransportClient *prev;
2950   struct ClientMessageQueueEntry *mqe;
2951
2952   if (client == NULL)
2953     return;
2954 #if DEBUG_TRANSPORT
2955   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2956               "Client disconnected, cleaning up.\n");
2957 #endif
2958   prev = NULL;
2959   pos = clients;
2960   while ((pos != NULL) && (pos->client != client))
2961     {
2962       prev = pos;
2963       pos = pos->next;
2964     }
2965   if (pos == NULL)
2966     return;
2967   while (NULL != (mqe = pos->message_queue_head))
2968     {
2969       pos->message_queue_head = mqe->next;
2970       GNUNET_free (mqe);
2971     }
2972   pos->message_queue_head = NULL;
2973   if (prev == NULL)
2974     clients = pos->next;
2975   else
2976     prev->next = pos->next;
2977   if (GNUNET_YES == pos->tcs_pending)
2978     {
2979       pos->client = NULL;
2980       return;
2981     }
2982   GNUNET_free (pos);
2983 }
2984
2985
2986 /**
2987  * Function called when the service shuts down.  Unloads our plugins.
2988  *
2989  * @param cls closure, unused
2990  * @param tc task context (unused)
2991  */
2992 static void
2993 unload_plugins (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
2994 {
2995   struct TransportPlugin *plug;
2996   struct AddressList *al;
2997
2998 #if DEBUG_TRANSPORT
2999   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3000               "Transport service is unloading plugins...\n");
3001 #endif
3002   while (NULL != (plug = plugins))
3003     {
3004       plugins = plug->next;
3005       GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
3006       GNUNET_free (plug->lib_name);
3007       GNUNET_free (plug->short_name);
3008       while (NULL != (al = plug->addresses))
3009         {
3010           plug->addresses = al->next;
3011           GNUNET_free (al);
3012         }
3013       GNUNET_free (plug);
3014     }
3015   if (my_private_key != NULL)
3016     GNUNET_CRYPTO_rsa_key_free (my_private_key);
3017   GNUNET_free_non_null (our_hello);
3018 }
3019
3020
3021 /**
3022  * Initiate transport service.
3023  *
3024  * @param cls closure
3025  * @param s scheduler to use
3026  * @param serv the initialized server
3027  * @param c configuration to use
3028  */
3029 static void
3030 run (void *cls,
3031      struct GNUNET_SCHEDULER_Handle *s,
3032      struct GNUNET_SERVER_Handle *serv,
3033      const struct GNUNET_CONFIGURATION_Handle *c)
3034 {
3035   char *plugs;
3036   char *pos;
3037   int no_transports;
3038   unsigned long long tneigh;
3039   char *keyfile;
3040
3041   sched = s;
3042   cfg = c;
3043   /* parse configuration */
3044   if ((GNUNET_OK !=
3045        GNUNET_CONFIGURATION_get_value_number (c,
3046                                               "TRANSPORT",
3047                                               "NEIGHBOUR_LIMIT",
3048                                               &tneigh)) ||
3049       (GNUNET_OK !=
3050        GNUNET_CONFIGURATION_get_value_filename (c,
3051                                                 "GNUNETD",
3052                                                 "HOSTKEY", &keyfile)))
3053     {
3054       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3055                   _
3056                   ("Transport service is lacking key configuration settings.  Exiting.\n"));
3057       GNUNET_SCHEDULER_shutdown (s);
3058       return;
3059     }
3060   max_connect_per_transport = (uint32_t) tneigh;
3061   my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
3062   GNUNET_free (keyfile);
3063   if (my_private_key == NULL)
3064     {
3065       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3066                   _
3067                   ("Transport service could not access hostkey.  Exiting.\n"));
3068       GNUNET_SCHEDULER_shutdown (s);
3069       return;
3070     }
3071   GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
3072   GNUNET_CRYPTO_hash (&my_public_key,
3073                       sizeof (my_public_key), &my_identity.hashPubKey);
3074   /* setup notification */
3075   server = serv;
3076   GNUNET_SERVER_disconnect_notify (server,
3077                                    &client_disconnect_notification, NULL);
3078   /* load plugins... */
3079   no_transports = 1;
3080   if (GNUNET_OK ==
3081       GNUNET_CONFIGURATION_get_value_string (c,
3082                                              "TRANSPORT", "PLUGINS", &plugs))
3083     {
3084       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3085                   _("Starting transport plugins `%s'\n"), plugs);
3086       pos = strtok (plugs, " ");
3087       while (pos != NULL)
3088         {
3089           start_transport (server, pos);
3090           no_transports = 0;
3091           pos = strtok (NULL, " ");
3092         }
3093       GNUNET_free (plugs);
3094     }
3095   GNUNET_SCHEDULER_add_delayed (sched,
3096                                 GNUNET_TIME_UNIT_FOREVER_REL,
3097                                 &unload_plugins, NULL);
3098   if (no_transports)
3099     refresh_hello ();
3100
3101 #if DEBUG_TRANSPORT
3102   GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Transport service ready.\n"));
3103 #endif
3104   /* process client requests */
3105   GNUNET_SERVER_add_handlers (server, handlers);
3106 }
3107
3108
3109 /**
3110  * The main function for the transport service.
3111  *
3112  * @param argc number of arguments from the command line
3113  * @param argv command line arguments
3114  * @return 0 ok, 1 on error
3115  */
3116 int
3117 main (int argc, char *const *argv)
3118 {
3119   return (GNUNET_OK ==
3120           GNUNET_SERVICE_run (argc,
3121                               argv,
3122                               "transport",
3123                               GNUNET_SERVICE_OPTION_NONE,
3124                               &run, NULL)) ? 0 : 1;
3125 }
3126
3127 /* end of gnunet-service-transport.c */