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