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