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