52eaf5656337e4b7fe3f1d6997cdee3d129bd71a
[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     }
1111   neighbour->messages = mq->next;
1112   mq->plugin = rl->plugin;
1113   if (!mq->internal_msg)
1114     rl->transmit_ready = GNUNET_NO;
1115 #if DEBUG_TRANSPORT
1116   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1117               "Giving message of type `%u' for `%4s' to plugin `%s'\n",
1118               ntohs (mq->message->type),
1119               GNUNET_i2s (&neighbour->id), rl->plugin->short_name);
1120 #endif
1121   rl->plugin_handle
1122     = rl->plugin->api->send (rl->plugin->api->cls,
1123                              rl->plugin_handle,
1124                              rl,
1125                              &neighbour->id,
1126                              mq->priority,
1127                              mq->message,
1128                              GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1129                              &transmit_send_continuation, mq);
1130 }
1131
1132
1133 /**
1134  * Send the specified message to the specified peer.
1135  *
1136  * @param client source of the transmission request (can be NULL)
1137  * @param priority how important is the message
1138  * @param msg message to send
1139  * @param is_internal is this an internal message
1140  * @param neighbour handle to the neighbour for transmission
1141  */
1142 static void
1143 transmit_to_peer (struct TransportClient *client,
1144                   unsigned int priority,
1145                   const struct GNUNET_MessageHeader *msg,
1146                   int is_internal, struct NeighbourList *neighbour)
1147 {
1148   struct MessageQueue *mq;
1149   struct MessageQueue *mqe;
1150   struct GNUNET_MessageHeader *m;
1151
1152 #if DEBUG_TRANSPORT
1153   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1154               _("Sending message of type %u to peer `%4s'\n"),
1155               ntohs (msg->type), GNUNET_i2s (&neighbour->id));
1156 #endif
1157   if (client != NULL)
1158     {
1159       /* check for duplicate submission */
1160       mq = neighbour->messages;
1161       while (NULL != mq)
1162         {
1163           if (mq->client == client)
1164             {
1165               /* client transmitted to same peer twice
1166                  before getting SendOk! */
1167               GNUNET_break (0);
1168               return;
1169             }
1170           mq = mq->next;
1171         }
1172     }
1173   mq = GNUNET_malloc (sizeof (struct MessageQueue));
1174   mq->client = client;
1175   m = GNUNET_malloc (ntohs (msg->size));
1176   memcpy (m, msg, ntohs (msg->size));
1177   mq->message = m;
1178   mq->neighbour = neighbour;
1179   mq->internal_msg = is_internal;
1180   mq->priority = priority;
1181
1182   /* find tail */
1183   mqe = neighbour->messages;
1184   if (mqe != NULL)
1185     while (mqe->next != NULL)
1186       mqe = mqe->next;
1187   if (mqe == NULL)
1188     {
1189       /* new head */
1190       neighbour->messages = mq;
1191       try_transmission_to_peer (neighbour);
1192     }
1193   else
1194     {
1195       /* append */
1196       mqe->next = mq;
1197     }
1198 }
1199
1200
1201 struct GeneratorContext
1202 {
1203   struct TransportPlugin *plug_pos;
1204   struct AddressList *addr_pos;
1205   struct GNUNET_TIME_Absolute expiration;
1206 };
1207
1208
1209 static size_t
1210 address_generator (void *cls, size_t max, void *buf)
1211 {
1212   struct GeneratorContext *gc = cls;
1213   size_t ret;
1214
1215   while ((gc->addr_pos == NULL) && (gc->plug_pos != NULL))
1216     {
1217       gc->plug_pos = gc->plug_pos->next;
1218       gc->addr_pos = (gc->plug_pos != NULL) ? gc->plug_pos->addresses : NULL;
1219     }
1220   if (NULL == gc->plug_pos)
1221     return 0;
1222   ret = GNUNET_HELLO_add_address (gc->plug_pos->short_name,
1223                                   gc->expiration,
1224                                   gc->addr_pos->addr,
1225                                   gc->addr_pos->addrlen, buf, max);
1226   gc->addr_pos = gc->addr_pos->next;
1227   return ret;
1228 }
1229
1230
1231 /**
1232  * Construct our HELLO message from all of the addresses of
1233  * all of the transports.
1234  */
1235 static void
1236 refresh_hello ()
1237 {
1238   struct GNUNET_HELLO_Message *hello;
1239   struct TransportClient *cpos;
1240   struct NeighbourList *npos;
1241   struct GeneratorContext gc;
1242
1243 #if DEBUG_TRANSPORT
1244   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1245               "Refreshing my HELLO\n");
1246 #endif
1247   gc.plug_pos = plugins;
1248   gc.addr_pos = plugins != NULL ? plugins->addresses : NULL;
1249   gc.expiration = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
1250   hello = GNUNET_HELLO_create (&my_public_key, &address_generator, &gc);
1251   cpos = clients;
1252   while (cpos != NULL)
1253     {
1254       transmit_to_client (cpos,
1255                           (const struct GNUNET_MessageHeader *) hello,
1256                           GNUNET_NO);
1257       cpos = cpos->next;
1258     }
1259
1260   GNUNET_free_non_null (our_hello);
1261   our_hello = hello;
1262   our_hello_version++;
1263   npos = neighbours;
1264   while (npos != NULL)
1265     {
1266       transmit_to_peer (NULL, 0,
1267                         (const struct GNUNET_MessageHeader *) our_hello,
1268                         GNUNET_YES, npos);
1269       npos = npos->next;
1270     }
1271 }
1272
1273
1274 /**
1275  * Task used to clean up expired addresses for a plugin.
1276  *
1277  * @param cls closure
1278  * @param tc context
1279  */
1280 static void
1281 expire_address_task (void *cls,
1282                      const struct GNUNET_SCHEDULER_TaskContext *tc);
1283
1284
1285 /**
1286  * Update the list of addresses for this plugin,
1287  * expiring those that are past their expiration date.
1288  *
1289  * @param plugin addresses of which plugin should be recomputed?
1290  * @param fresh set to GNUNET_YES if a new address was added
1291  *        and we need to regenerate the HELLO even if nobody
1292  *        expired
1293  */
1294 static void
1295 update_addresses (struct TransportPlugin *plugin, int fresh)
1296 {
1297   struct GNUNET_TIME_Relative min_remaining;
1298   struct GNUNET_TIME_Relative remaining;
1299   struct GNUNET_TIME_Absolute now;
1300   struct AddressList *pos;
1301   struct AddressList *prev;
1302   struct AddressList *next;
1303   int expired;
1304
1305   if (plugin->address_update_task != GNUNET_SCHEDULER_NO_PREREQUISITE_TASK)
1306     GNUNET_SCHEDULER_cancel (plugin->env.sched, plugin->address_update_task);
1307   plugin->address_update_task = GNUNET_SCHEDULER_NO_PREREQUISITE_TASK;
1308   now = GNUNET_TIME_absolute_get ();
1309   min_remaining = GNUNET_TIME_UNIT_FOREVER_REL;
1310   expired = GNUNET_NO;
1311   prev = NULL;
1312   pos = plugin->addresses;
1313   while (pos != NULL)
1314     {
1315       next = pos->next;
1316       if (pos->expires.value < now.value)
1317         {
1318           expired = GNUNET_YES;
1319           if (prev == NULL)
1320             plugin->addresses = pos->next;
1321           else
1322             prev->next = pos->next;
1323           GNUNET_free (pos);
1324         }
1325       else
1326         {
1327           remaining = GNUNET_TIME_absolute_get_remaining (pos->expires);
1328           if (remaining.value < min_remaining.value)
1329             min_remaining = remaining;
1330           prev = pos;
1331         }
1332       pos = next;
1333     }
1334
1335   if (expired || fresh)
1336     refresh_hello ();
1337   if (min_remaining.value < GNUNET_TIME_UNIT_FOREVER_REL.value)
1338     plugin->address_update_task
1339       = GNUNET_SCHEDULER_add_delayed (plugin->env.sched,
1340                                       GNUNET_NO,
1341                                       GNUNET_SCHEDULER_PRIORITY_IDLE,
1342                                       GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
1343                                       min_remaining,
1344                                       &expire_address_task, plugin);
1345
1346 }
1347
1348
1349 /**
1350  * Task used to clean up expired addresses for a plugin.
1351  *
1352  * @param cls closure
1353  * @param tc context
1354  */
1355 static void
1356 expire_address_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1357 {
1358   struct TransportPlugin *plugin = cls;
1359   plugin->address_update_task = GNUNET_SCHEDULER_NO_PREREQUISITE_TASK;
1360   update_addresses (plugin, GNUNET_NO);
1361 }
1362
1363
1364 /**
1365  * Function that must be called by each plugin to notify the
1366  * transport service about the addresses under which the transport
1367  * provided by the plugin can be reached.
1368  *
1369  * @param cls closure
1370  * @param name name of the transport that generated the address
1371  * @param addr one of the addresses of the host, NULL for the last address
1372  *        the specific address format depends on the transport
1373  * @param addrlen length of the address
1374  * @param expires when should this address automatically expire?
1375  */
1376 static void
1377 plugin_env_notify_address (void *cls,
1378                            const char *name,
1379                            const void *addr,
1380                            size_t addrlen,
1381                            struct GNUNET_TIME_Relative expires)
1382 {
1383   struct TransportPlugin *p = cls;
1384   struct AddressList *al;
1385   struct GNUNET_TIME_Absolute abex;
1386
1387 #if DEBUG_TRANSPORT
1388   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1389               "Plugin `%s' informs us about a new address `%s'\n", name,
1390               GNUNET_a2s(addr, addrlen));
1391 #endif
1392   abex = GNUNET_TIME_relative_to_absolute (expires);
1393   GNUNET_assert (p == find_transport (name));
1394
1395   al = p->addresses;
1396   while (al != NULL)
1397     {
1398       if ((addrlen == al->addrlen) && (0 == memcmp (addr, &al[1], addrlen)))
1399         {
1400           if (al->expires.value < abex.value)
1401             al->expires = abex;
1402           return;
1403         }
1404       al = al->next;
1405     }
1406   al = GNUNET_malloc (sizeof (struct AddressList) + addrlen);
1407   al->addr = &al[1];
1408   al->next = p->addresses;
1409   p->addresses = al;
1410   al->expires = abex;
1411   al->addrlen = addrlen;
1412   memcpy (&al[1], addr, addrlen);
1413   update_addresses (p, GNUNET_YES);
1414 }
1415
1416
1417 struct LookupHelloContext
1418 {
1419   GNUNET_TRANSPORT_AddressCallback iterator;
1420
1421   void *iterator_cls;
1422 };
1423
1424
1425 static int
1426 lookup_address_callback (void *cls,
1427                          const char *tname,
1428                          struct GNUNET_TIME_Absolute expiration,
1429                          const void *addr, size_t addrlen)
1430 {
1431   struct LookupHelloContext *lhc = cls;
1432   lhc->iterator (lhc->iterator_cls, tname, addr, addrlen);
1433   return GNUNET_OK;
1434 }
1435
1436
1437 static void
1438 lookup_hello_callback (void *cls,
1439                        const struct GNUNET_PeerIdentity *peer,
1440                        const struct GNUNET_HELLO_Message *h, uint32_t trust)
1441 {
1442   struct LookupHelloContext *lhc = cls;
1443
1444   if (peer == NULL)
1445     {
1446       lhc->iterator (lhc->iterator_cls, NULL, NULL, 0);
1447       GNUNET_free (lhc);
1448       return;
1449     }
1450   if (h == NULL)
1451     return;
1452   GNUNET_HELLO_iterate_addresses (h,
1453                                   GNUNET_NO, &lookup_address_callback, lhc);
1454 }
1455
1456
1457 /**
1458  * Function that allows a transport to query the known
1459  * network addresses for a given peer.
1460  *
1461  * @param cls closure
1462  * @param timeout after how long should we time out?
1463  * @param target which peer are we looking for?
1464  * @param iter function to call for each known address
1465  * @param iter_cls closure for iter
1466  */
1467 static void
1468 plugin_env_lookup_address (void *cls,
1469                            struct GNUNET_TIME_Relative timeout,
1470                            const struct GNUNET_PeerIdentity *target,
1471                            GNUNET_TRANSPORT_AddressCallback iter,
1472                            void *iter_cls)
1473 {
1474   struct LookupHelloContext *lhc;
1475
1476   lhc = GNUNET_malloc (sizeof (struct LookupHelloContext));
1477   lhc->iterator = iter;
1478   lhc->iterator_cls = iter_cls;
1479   GNUNET_PEERINFO_for_all (cfg,
1480                            sched,
1481                            target, 0, timeout, &lookup_hello_callback, &lhc);
1482 }
1483
1484
1485 /**
1486  * Notify all of our clients about a peer connecting.
1487  */
1488 static void
1489 notify_clients_connect (const struct GNUNET_PeerIdentity *peer,
1490                         struct GNUNET_TIME_Relative latency)
1491 {
1492   struct ConnectInfoMessage cim;
1493   struct TransportClient *cpos;
1494
1495 #if DEBUG_TRANSPORT
1496   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1497               "Informing clients about peer `%4s' connecting to us\n",
1498               GNUNET_i2s (peer));
1499 #endif
1500   cim.header.size = htons (sizeof (struct ConnectInfoMessage));
1501   cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
1502   cim.quota_out = htonl (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT / (60*1000));
1503   cim.latency = GNUNET_TIME_relative_hton (latency);
1504   memcpy (&cim.id, peer, sizeof (struct GNUNET_PeerIdentity));
1505   cpos = clients;
1506   while (cpos != NULL)
1507     {
1508       transmit_to_client (cpos, &cim.header, GNUNET_NO);
1509       cpos = cpos->next;
1510     }
1511 }
1512
1513
1514 /**
1515  * Notify all of our clients about a peer disconnecting.
1516  */
1517 static void
1518 notify_clients_disconnect (const struct GNUNET_PeerIdentity *peer)
1519 {
1520   struct DisconnectInfoMessage dim;
1521   struct TransportClient *cpos;
1522
1523 #if DEBUG_TRANSPORT
1524   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1525               "Informing clients about peer `%4s' disconnecting\n",
1526               GNUNET_i2s (peer));
1527 #endif
1528   dim.header.size = htons (sizeof (struct DisconnectInfoMessage));
1529   dim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
1530   dim.reserved = htonl (0);
1531   memcpy (&dim.peer, peer, sizeof (struct GNUNET_PeerIdentity));
1532   cpos = clients;
1533   while (cpos != NULL)
1534     {
1535       transmit_to_client (cpos, &dim.header, GNUNET_NO);
1536       cpos = cpos->next;
1537     }
1538 }
1539
1540
1541 /**
1542  * Copy any validated addresses to buf.
1543  *
1544  * @return 0 once all addresses have been
1545  *         returned
1546  */
1547 static size_t
1548 list_validated_addresses (void *cls, size_t max, void *buf)
1549 {
1550   struct ValidationAddress **va = cls;
1551   size_t ret;
1552
1553   while ((NULL != *va) && ((*va)->ok != GNUNET_YES))
1554     *va = (*va)->next;
1555   if (NULL == *va)
1556     return 0;
1557   ret = GNUNET_HELLO_add_address ((*va)->transport_name,
1558                                   (*va)->expiration,
1559                                   &(*va)->msg[1], (*va)->addr_len, buf, max);
1560   *va = (*va)->next;
1561   return ret;
1562 }
1563
1564
1565 /**
1566  * HELLO validation cleanup task.
1567  */
1568 static void
1569 cleanup_validation (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1570 {
1571   struct ValidationAddress *va;
1572   struct ValidationList *pos;
1573   struct ValidationList *prev;
1574   struct GNUNET_TIME_Absolute now;
1575   struct GNUNET_HELLO_Message *hello;
1576   struct GNUNET_PeerIdentity pid;
1577
1578 #if DEBUG_TRANSPORT
1579   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1580               "HELLO validation cleanup background task running...\n");
1581 #endif
1582   now = GNUNET_TIME_absolute_get ();
1583   prev = NULL;
1584   pos = pending_validations;
1585   while (pos != NULL)
1586     {
1587       if (pos->timeout.value < now.value)
1588         {
1589           if (prev == NULL)
1590             pending_validations = pos->next;
1591           else
1592             prev->next = pos->next;
1593           va = pos->addresses;
1594           hello = GNUNET_HELLO_create (&pos->publicKey,
1595                                        &list_validated_addresses, &va);
1596           GNUNET_CRYPTO_hash (&pos->publicKey,
1597                               sizeof (struct
1598                                       GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1599                               &pid.hashPubKey);
1600 #if DEBUG_TRANSPORT
1601           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1602                       "Creating persistent `%s' message for peer `%4s' based on confirmed addresses.\n",
1603                       "HELLO", GNUNET_i2s (&pid));
1604 #endif
1605           GNUNET_PEERINFO_add_peer (cfg, sched, &pid, hello);
1606           GNUNET_free (hello);
1607           while (NULL != (va = pos->addresses))
1608             {
1609               pos->addresses = va->next;
1610               GNUNET_free (va->transport_name);
1611               GNUNET_free (va);
1612             }
1613           GNUNET_free (pos);
1614           if (prev == NULL)
1615             pos = pending_validations;
1616           else
1617             pos = prev->next;
1618           continue;
1619         }
1620       prev = pos;
1621       pos = pos->next;
1622     }
1623
1624   /* finally, reschedule cleanup if needed; list is
1625      ordered by timeout, so we need the last element... */
1626   pos = pending_validations;
1627   while ((pos != NULL) && (pos->next != NULL))
1628     pos = pos->next;
1629   if (NULL != pos)
1630     GNUNET_SCHEDULER_add_delayed (sched,
1631                                   GNUNET_NO,
1632                                   GNUNET_SCHEDULER_PRIORITY_IDLE,
1633                                   GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
1634                                   GNUNET_TIME_absolute_get_remaining
1635                                   (pos->timeout), &cleanup_validation, NULL);
1636 }
1637
1638
1639 struct CheckHelloValidatedContext
1640 {
1641   /**
1642    * Plugin for which we are validating.
1643    */
1644   struct TransportPlugin *plugin;
1645
1646   /**
1647    * Hello that we are validating.
1648    */
1649   struct GNUNET_HELLO_Message *hello;
1650
1651   /**
1652    * Validation list being build.
1653    */
1654   struct ValidationList *e;
1655
1656 };
1657
1658
1659 /**
1660  * Append the given address to the list of entries
1661  * that need to be validated.
1662  */
1663 static int
1664 run_validation (void *cls,
1665                 const char *tname,
1666                 struct GNUNET_TIME_Absolute expiration,
1667                 const void *addr, size_t addrlen)
1668 {
1669   struct ValidationList *e = cls;
1670   struct TransportPlugin *tp;
1671   struct ValidationAddress *va;
1672   struct ValidationChallengeMessage *vcm;
1673   struct GNUNET_PeerIdentity id;
1674
1675   tp = find_transport (tname);
1676   if (tp == NULL)
1677     {
1678       GNUNET_log (GNUNET_ERROR_TYPE_INFO |
1679                   GNUNET_ERROR_TYPE_BULK,
1680                   _
1681                   ("Transport `%s' not loaded, will not try to validate peer address using this transport.\n"),
1682                   tname);
1683       return GNUNET_OK;
1684     }
1685   GNUNET_CRYPTO_hash (&e->publicKey,
1686                       sizeof (struct
1687                               GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1688                       &id.hashPubKey);
1689   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1690               "Scheduling validation of address `%s' via `%s' for `%4s'\n",
1691               GNUNET_a2s(addr, addrlen),
1692               tname,
1693               GNUNET_i2s(&id));
1694
1695   va = GNUNET_malloc (sizeof (struct ValidationAddress) +
1696                       sizeof (struct ValidationChallengeMessage) + addrlen);
1697   va->next = e->addresses;
1698   e->addresses = va;
1699   vcm = (struct ValidationChallengeMessage *) &va[1];
1700   va->msg = vcm;
1701   va->transport_name = GNUNET_strdup (tname);
1702   va->addr_len = addrlen;
1703   vcm->header.size =
1704     htons (sizeof (struct ValidationChallengeMessage) + addrlen);
1705   vcm->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
1706   vcm->purpose.size =
1707     htonl (sizeof (struct ValidationChallengeMessage) + addrlen -
1708            sizeof (struct GNUNET_MessageHeader));
1709   vcm->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_HELLO);
1710   vcm->challenge = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1711                                              (unsigned int) -1);
1712   vcm->target = id;
1713   memcpy (&vcm[1], addr, addrlen);
1714   return GNUNET_OK;
1715 }
1716
1717
1718 /**
1719  * Check if addresses in validated hello "h" overlap with
1720  * those in "chvc->hello" and update "chvc->hello" accordingly,
1721  * removing those addresses that have already been validated.
1722  */
1723 static void
1724 check_hello_validated (void *cls,
1725                        const struct GNUNET_PeerIdentity *peer,
1726                        const struct GNUNET_HELLO_Message *h, uint32_t trust)
1727 {
1728   struct CheckHelloValidatedContext *chvc = cls;
1729   struct ValidationAddress *va;
1730   struct TransportPlugin *tp;
1731   int first_call;
1732
1733   first_call = GNUNET_NO;
1734   if (chvc->e == NULL)
1735     {
1736       first_call = GNUNET_YES;
1737       chvc->e = GNUNET_malloc (sizeof (struct ValidationList));
1738       GNUNET_assert (GNUNET_OK ==
1739                      GNUNET_HELLO_get_key (h != NULL ? h : chvc->hello,
1740                                            &chvc->e->publicKey));
1741       chvc->e->timeout =
1742         GNUNET_TIME_relative_to_absolute (HELLO_VERIFICATION_TIMEOUT);
1743       chvc->e->next = pending_validations;
1744       pending_validations = chvc->e;
1745     }
1746   if (h != NULL)
1747     {
1748       GNUNET_HELLO_iterate_new_addresses (chvc->hello,
1749                                           h,
1750                                           GNUNET_TIME_absolute_get (),
1751                                           &run_validation, chvc->e);
1752     }
1753   else if (GNUNET_YES == first_call)
1754     {
1755       /* no existing HELLO, all addresses are new */
1756       GNUNET_HELLO_iterate_addresses (chvc->hello,
1757                                       GNUNET_NO, &run_validation, chvc->e);
1758     }
1759   if (h != NULL)
1760     return;                     /* wait for next call */
1761   /* finally, transmit validation attempts */
1762   va = chvc->e->addresses;
1763   while (va != NULL)
1764     {
1765 #if DEBUG_TRANSPORT
1766       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1767                   "Establishing `%s' connection to validate `%s' of `%4s' (sending our `%s')\n",
1768                   va->transport_name,
1769                   "HELLO", GNUNET_i2s (&va->msg->target), "HELLO");
1770 #endif
1771       tp = find_transport (va->transport_name);
1772       GNUNET_assert (tp != NULL);
1773       if (NULL ==
1774           tp->api->send_to (tp->api->cls,
1775                             &va->msg->target,
1776                             0,
1777                             (const struct GNUNET_MessageHeader *) our_hello,
1778                             &va->msg->header,
1779                             HELLO_VERIFICATION_TIMEOUT,
1780                             &va->msg[1], va->addr_len))
1781         va->ok = GNUNET_SYSERR;
1782       va = va->next;
1783     }
1784   if (chvc->e->next == NULL)
1785     GNUNET_SCHEDULER_add_delayed (sched,
1786                                   GNUNET_NO,
1787                                   GNUNET_SCHEDULER_PRIORITY_IDLE,
1788                                   GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
1789                                   GNUNET_TIME_absolute_get_remaining
1790                                   (chvc->e->timeout), &cleanup_validation,
1791                                   NULL);
1792   GNUNET_free (chvc);
1793 }
1794
1795
1796 /**
1797  * Process HELLO-message.
1798  *
1799  * @param plugin transport involved, may be NULL
1800  * @param message the actual message
1801  * @return GNUNET_OK if the HELLO was well-formed, GNUNET_SYSERR otherwise
1802  */
1803 static int
1804 process_hello (struct TransportPlugin *plugin,
1805                const struct GNUNET_MessageHeader *message)
1806 {
1807   struct ValidationList *e;
1808   uint16_t hsize;
1809   struct GNUNET_PeerIdentity target;
1810   const struct GNUNET_HELLO_Message *hello;
1811   struct CheckHelloValidatedContext *chvc;
1812   struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded publicKey;
1813
1814   hsize = ntohs (message->size);
1815   if ((ntohs (message->type) != GNUNET_MESSAGE_TYPE_HELLO) ||
1816       (hsize < sizeof (struct GNUNET_MessageHeader)))
1817     {
1818       GNUNET_break (0);
1819       return GNUNET_SYSERR;
1820     }
1821   /* first, check if load is too high */
1822   if (GNUNET_OS_load_cpu_get (cfg) > 100)
1823     {
1824       /* TODO: call to stats? */
1825       return GNUNET_OK;
1826     }
1827   hello = (const struct GNUNET_HELLO_Message *) message;
1828   if (GNUNET_OK != GNUNET_HELLO_get_key (hello, &publicKey))
1829     {
1830       GNUNET_break_op (0);
1831       return GNUNET_SYSERR;
1832     }
1833   GNUNET_CRYPTO_hash (&publicKey,
1834                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1835                       &target.hashPubKey);
1836 #if DEBUG_TRANSPORT
1837   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1838               "Processing `%s' message for `%4s'\n",
1839               "HELLO", GNUNET_i2s (&target));
1840 #endif
1841   /* check if a HELLO for this peer is already on the validation list */
1842   e = pending_validations;
1843   while (e != NULL)
1844     {
1845       if (0 == memcmp (&e->publicKey,
1846                        &publicKey,
1847                        sizeof (struct
1848                                GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded)))
1849         {
1850           /* TODO: call to stats? */
1851 #if DEBUG_TRANSPORT
1852           GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1853                       "`%s' message for peer `%4s' is already pending; ignoring new message\n",
1854                       "HELLO", GNUNET_i2s (&target));
1855 #endif    
1856           return GNUNET_OK;
1857         }
1858       e = e->next;
1859     }
1860   chvc = GNUNET_malloc (sizeof (struct CheckHelloValidatedContext) + hsize);
1861   chvc->plugin = plugin;
1862   chvc->hello = (struct GNUNET_HELLO_Message *) &chvc[1];
1863   memcpy (chvc->hello, hello, hsize);
1864   /* finally, check if HELLO was previously validated
1865      (continuation will then schedule actual validation) */
1866   GNUNET_PEERINFO_for_all (cfg,
1867                            sched,
1868                            &target,
1869                            0,
1870                            HELLO_VERIFICATION_TIMEOUT,
1871                            &check_hello_validated, chvc);
1872   return GNUNET_OK;
1873 }
1874
1875
1876 /**
1877  * Handle PING-message.  If the plugin that gave us the message is
1878  * able to queue the PONG immediately, we only queue one PONG.
1879  * Otherwise we send at most TWO PONG messages, one via an unconfirmed
1880  * transport and one via a confirmed transport.  Both addresses are
1881  * selected randomly among those available.
1882  *
1883  * @param plugin plugin that gave us the message
1884  * @param sender claimed sender of the PING
1885  * @param plugin_context context that might be used to send response
1886  * @param message the actual message
1887  */
1888 static void
1889 process_ping (struct TransportPlugin *plugin,
1890               const struct GNUNET_PeerIdentity *sender,
1891               void *plugin_context,
1892               const struct GNUNET_MessageHeader *message)
1893 {
1894   const struct ValidationChallengeMessage *vcm;
1895   struct ValidationChallengeResponse vcr;
1896   uint16_t msize;
1897   struct NeighbourList *n;
1898
1899 #if DEBUG_TRANSPORT
1900   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1901               "Processing PING\n");
1902 #endif
1903   msize = ntohs (message->size);
1904   if (msize < sizeof (struct ValidationChallengeMessage))
1905     {
1906       GNUNET_break_op (0);
1907       return;
1908     }
1909   vcm = (const struct ValidationChallengeMessage *) message;
1910   if (0 != memcmp (&vcm->target,
1911                    &my_identity, sizeof (struct GNUNET_PeerIdentity)))
1912     {
1913       GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1914                   _("Received `%s' message not destined for me!\n"), "PING");
1915       /* TODO: call statistics */
1916       return;
1917     }
1918   if ((ntohl (vcm->purpose.size) !=
1919        msize - sizeof (struct GNUNET_MessageHeader))
1920       || (ntohl (vcm->purpose.purpose) !=
1921           GNUNET_SIGNATURE_PURPOSE_TRANSPORT_HELLO))
1922     {
1923       GNUNET_break_op (0);
1924       return;
1925     }
1926   msize -= sizeof (struct ValidationChallengeMessage);
1927   if (GNUNET_OK !=
1928       plugin->api->address_suggested (plugin->api->cls, &vcm[1], msize))
1929     {
1930       GNUNET_break_op (0);
1931       return;
1932     }
1933   vcr.header.size = htons (sizeof (struct ValidationChallengeResponse));
1934   vcr.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
1935   vcr.challenge = vcm->challenge;
1936   vcr.sender = my_identity;
1937   GNUNET_assert (GNUNET_OK ==
1938                  GNUNET_CRYPTO_rsa_sign (my_private_key,
1939                                          &vcm->purpose, &vcr.signature));
1940 #if EXTRA_CHECKS
1941   GNUNET_assert (GNUNET_OK ==
1942                  GNUNET_CRYPTO_rsa_verify
1943                  (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_HELLO, &vcm->purpose,
1944                   &vcr.signature, &my_public_key));
1945 #endif
1946 #if DEBUG_TRANSPORT
1947   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1948               "Trying to transmit PONG using inbound connection\n");
1949 #endif
1950   n = find_neighbour (sender);
1951   if (n == NULL)
1952     {
1953       GNUNET_break (0);
1954       return;
1955     }
1956   transmit_to_peer (NULL, 0, &vcr.header, GNUNET_YES, n);
1957 }
1958
1959
1960 /**
1961  * Handle PONG-message.
1962  *
1963  * @param message the actual message
1964  */
1965 static void
1966 process_pong (struct TransportPlugin *plugin,
1967               const struct GNUNET_MessageHeader *message)
1968 {
1969   const struct ValidationChallengeResponse *vcr;
1970   struct ValidationList *pos;
1971   struct GNUNET_PeerIdentity peer;
1972   struct ValidationAddress *va;
1973   int all_done;
1974   int matched;
1975
1976 #if DEBUG_TRANSPORT
1977   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
1978               "Processing PONG\n");
1979 #endif
1980   vcr = (const struct ValidationChallengeResponse *) message;
1981   pos = pending_validations;
1982   while (pos != NULL)
1983     {
1984       GNUNET_CRYPTO_hash (&pos->publicKey,
1985                           sizeof (struct
1986                                   GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
1987                           &peer.hashPubKey);
1988       if (0 ==
1989           memcmp (&peer, &vcr->sender, sizeof (struct GNUNET_PeerIdentity)))
1990         break;
1991       pos = pos->next;
1992     }
1993   if (pos == NULL)
1994     {
1995       /* TODO: call statistics (unmatched PONG) */
1996       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1997                   _
1998                   ("Received `%s' message but have no record of a matching `%s' message. Ignoring.\n"),
1999                   "PONG", "PING");
2000       return;
2001     }
2002   all_done = GNUNET_YES;
2003   matched = GNUNET_NO;
2004   va = pos->addresses;
2005   while (va != NULL)
2006     {
2007       if (va->msg->challenge == vcr->challenge)
2008         {
2009           if (GNUNET_OK !=
2010               GNUNET_CRYPTO_rsa_verify
2011               (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_HELLO, &va->msg->purpose,
2012                &vcr->signature, &pos->publicKey))
2013             {
2014               /* this could rarely happen if we used the same
2015                  challenge number for the peer for two different
2016                  transports / addresses, but the likelihood is
2017                  very small... */
2018               GNUNET_break_op (0);
2019             }
2020           else
2021             {
2022 #if DEBUG_TRANSPORT
2023               GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2024                           "Confirmed validity of peer address.\n");
2025 #endif
2026               va->ok = GNUNET_YES;
2027               va->expiration =
2028                 GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
2029               matched = GNUNET_YES;
2030             }
2031         }
2032       if (va->ok != GNUNET_YES)
2033         all_done = GNUNET_NO;
2034       va = va->next;
2035     }
2036   if (GNUNET_NO == matched)
2037     {
2038       /* TODO: call statistics (unmatched PONG) */
2039       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2040                   _
2041                   ("Received `%s' message but have no record of a matching `%s' message. Ignoring.\n"),
2042                   "PONG", "PING");
2043     }
2044   if (GNUNET_YES == all_done)
2045     {
2046       pos->timeout.value = 0;
2047       GNUNET_SCHEDULER_add_delayed (sched,
2048                                     GNUNET_NO,
2049                                     GNUNET_SCHEDULER_PRIORITY_IDLE,
2050                                     GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
2051                                     GNUNET_TIME_UNIT_ZERO,
2052                                     &cleanup_validation, NULL);
2053     }
2054 }
2055
2056
2057 /**
2058  * The peer specified by the given neighbour has timed-out.  Update
2059  * our state and do the necessary notifications.  Also notifies
2060  * our clients that the neighbour is now officially gone.
2061  *
2062  * @param n the neighbour list entry for the peer
2063  */
2064 static void
2065 disconnect_neighbour (struct NeighbourList *n)
2066 {
2067   struct ReadyList *rpos;
2068   struct NeighbourList *npos;
2069   struct NeighbourList *nprev;
2070   struct MessageQueue *mq;
2071
2072 #if DEBUG_TRANSPORT
2073   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2074               "Disconnecting from neighbour\n");
2075 #endif
2076   /* remove n from neighbours list */
2077   nprev = NULL;
2078   npos = neighbours;
2079   while ((npos != NULL) && (npos != n))
2080     {
2081       nprev = npos;
2082       npos = npos->next;
2083     }
2084   GNUNET_assert (npos != NULL);
2085   if (nprev == NULL)
2086     neighbours = n->next;
2087   else
2088     nprev->next = n->next;
2089
2090   /* notify all clients about disconnect */
2091   notify_clients_disconnect (&n->id);
2092
2093   /* clean up all plugins, cancel connections & pending transmissions */
2094   while (NULL != (rpos = n->plugins))
2095     {
2096       n->plugins = rpos->next;
2097       GNUNET_assert (rpos->neighbour == n);
2098       rpos->plugin->api->cancel (rpos->plugin->api->cls,
2099                                  rpos->plugin_handle, rpos, &n->id);
2100       GNUNET_free (rpos);
2101     }
2102
2103   /* free all messages on the queue */
2104   while (NULL != (mq = n->messages))
2105     {
2106       n->messages = mq->next;
2107       GNUNET_assert (mq->neighbour == n);
2108       GNUNET_free (mq);
2109     }
2110
2111   /* finally, free n itself */
2112   GNUNET_free (n);
2113 }
2114
2115
2116 /**
2117  * Add an entry for each of our transport plugins
2118  * (that are able to send) to the list of plugins
2119  * for this neighbour.
2120  *
2121  * @param neighbour to initialize
2122  */
2123 static void
2124 add_plugins (struct NeighbourList *neighbour)
2125 {
2126   struct TransportPlugin *tp;
2127   struct ReadyList *rl;
2128
2129   neighbour->retry_plugins_time
2130     = GNUNET_TIME_relative_to_absolute (PLUGIN_RETRY_FREQUENCY);
2131   tp = plugins;
2132   while (tp != NULL)
2133     {
2134       if (tp->api->send != NULL)
2135         {
2136           rl = GNUNET_malloc (sizeof (struct ReadyList));
2137           rl->next = neighbour->plugins;
2138           neighbour->plugins = rl;
2139           rl->plugin = tp;
2140           rl->neighbour = neighbour;
2141           rl->transmit_ready = GNUNET_YES;
2142         }
2143       tp = tp->next;
2144     }
2145 }
2146
2147
2148 static void
2149 neighbour_timeout_task (void *cls,
2150                         const struct GNUNET_SCHEDULER_TaskContext *tc)
2151 {
2152   struct NeighbourList *n = cls;
2153
2154 #if DEBUG_TRANSPORT
2155   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2156               "Neighbour has timed out!\n");
2157 #endif
2158   n->timeout_task = GNUNET_SCHEDULER_NO_PREREQUISITE_TASK;
2159   disconnect_neighbour (n);
2160 }
2161
2162
2163
2164 /**
2165  * Create a fresh entry in our neighbour list for the given peer.
2166  * Will try to transmit our current HELLO to the new neighbour.  Also
2167  * notifies our clients about the new "connection".
2168  *
2169  * @param peer the peer for which we create the entry
2170  * @return the new neighbour list entry
2171  */
2172 static struct NeighbourList *
2173 setup_new_neighbour (const struct GNUNET_PeerIdentity *peer)
2174 {
2175   struct NeighbourList *n;
2176
2177 #if DEBUG_TRANSPORT
2178   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2179               "Setting up new neighbour `%4s', sending our HELLO to introduce ourselves\n",
2180               GNUNET_i2s (peer));
2181 #endif
2182   GNUNET_assert (our_hello != NULL);
2183   n = GNUNET_malloc (sizeof (struct NeighbourList));
2184   n->next = neighbours;
2185   neighbours = n;
2186   n->id = *peer;
2187   n->last_quota_update = GNUNET_TIME_absolute_get ();
2188   n->peer_timeout =
2189     GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2190   n->quota_in = (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000);
2191   add_plugins (n);
2192   n->timeout_task = GNUNET_SCHEDULER_add_delayed (sched,
2193                                                   GNUNET_NO,
2194                                                   GNUNET_SCHEDULER_PRIORITY_IDLE,
2195                                                   GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
2196                                                   GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2197                                                   &neighbour_timeout_task, n);
2198   transmit_to_peer (NULL, 0,
2199                     (const struct GNUNET_MessageHeader *) our_hello,
2200                     GNUNET_YES, n);
2201   notify_clients_connect (peer, GNUNET_TIME_UNIT_FOREVER_REL);
2202   return n;
2203 }
2204
2205
2206 /**
2207  * Function called by the plugin for each received message.
2208  * Update data volumes, possibly notify plugins about
2209  * reducing the rate at which they read from the socket
2210  * and generally forward to our receive callback.
2211  *
2212  * @param plugin_context value to pass to this plugin
2213  *        to respond to the given peer (use is optional,
2214  *        but may speed up processing)
2215  * @param service_context value passed to the transport-service
2216  *        to identify the neighbour; will be NULL on the first
2217  *        call for a given peer
2218  * @param latency estimated latency for communicating with the
2219  *             given peer
2220  * @param peer (claimed) identity of the other peer
2221  * @param message the message, NULL if peer was disconnected
2222  * @return the new service_context that the plugin should use
2223  *         for future receive calls for messages from this
2224  *         particular peer
2225  */
2226 static struct ReadyList *
2227 plugin_env_receive (void *cls,
2228                     void *plugin_context,
2229                     struct ReadyList *service_context,
2230                     struct GNUNET_TIME_Relative latency,
2231                     const struct GNUNET_PeerIdentity *peer,
2232                     const struct GNUNET_MessageHeader *message)
2233 {
2234   const struct GNUNET_MessageHeader ack = {
2235     htons (sizeof (struct GNUNET_MessageHeader)),
2236     htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ACK)
2237   };
2238   struct TransportPlugin *plugin = cls;
2239   struct TransportClient *cpos;
2240   struct InboundMessage *im;
2241   uint16_t msize;
2242   struct NeighbourList *n;
2243
2244   if (service_context != NULL)
2245     {
2246       n = service_context->neighbour;
2247       GNUNET_assert (n != NULL);
2248     }
2249   else
2250     {
2251       n = find_neighbour (peer);
2252       if (n == NULL)
2253         {
2254           if (message == NULL)
2255             return NULL;        /* disconnect of peer already marked down */
2256           n = setup_new_neighbour (peer);
2257         }
2258       service_context = n->plugins;
2259       while ((service_context != NULL) && (plugin != service_context->plugin))
2260         service_context = service_context->next;
2261       GNUNET_assert ((plugin->api->send == NULL) ||
2262                      (service_context != NULL));
2263     }
2264   if (message == NULL)
2265     {
2266       if ((service_context != NULL) &&
2267           (service_context->plugin_handle == plugin_context))
2268         {
2269           service_context->connected = GNUNET_NO;
2270           service_context->plugin_handle = NULL;
2271         }
2272       /* TODO: call stats */
2273       return NULL;
2274     }
2275 #if DEBUG_TRANSPORT
2276   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2277               "Processing message of type `%u' received by plugin...\n",
2278               ntohs (message->type));
2279 #endif
2280   if (service_context != NULL)
2281     {
2282       if (service_context->connected == GNUNET_NO)
2283         {
2284           service_context->connected = GNUNET_YES;
2285           service_context->transmit_ready = GNUNET_YES;
2286           service_context->connect_attempts++;
2287         }
2288       service_context->timeout
2289         = GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2290       service_context->plugin_handle = plugin_context;
2291       service_context->latency = latency;
2292     }
2293   /* update traffic received amount ... */
2294   msize = ntohs (message->size);
2295   n->last_received += msize;
2296   GNUNET_SCHEDULER_cancel (sched, n->timeout_task);
2297   n->peer_timeout =
2298     GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2299   n->timeout_task =
2300     GNUNET_SCHEDULER_add_delayed (sched, GNUNET_NO,
2301                                   GNUNET_SCHEDULER_PRIORITY_IDLE,
2302                                   GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
2303                                   GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2304                                   &neighbour_timeout_task, n);
2305   update_quota (n);
2306   if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
2307     {
2308       /* dropping message due to frequent inbound volume violations! */
2309       GNUNET_log (GNUNET_ERROR_TYPE_WARNING |
2310                   GNUNET_ERROR_TYPE_BULK,
2311                   _
2312                   ("Dropping incoming message due to repeated bandwidth quota violations.\n"));
2313       /* TODO: call stats */
2314       GNUNET_assert (NULL != service_context->neighbour);
2315       return service_context;
2316     }
2317   switch (ntohs (message->type))
2318     {
2319     case GNUNET_MESSAGE_TYPE_HELLO:
2320 #if DEBUG_TRANSPORT
2321       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2322                   "Receiving `%s' message from other peer.\n", "HELLO");
2323 #endif
2324       process_hello (plugin, message);
2325 #if DEBUG_TRANSPORT
2326       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2327                   "Sending `%s' message to connecting peer.\n", "ACK");
2328 #endif
2329       transmit_to_peer (NULL, 0, &ack, GNUNET_YES, n);
2330       break;
2331     case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
2332       process_ping (plugin, peer, plugin_context, message);
2333       break;
2334     case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
2335       process_pong (plugin, message);
2336       break;
2337     case GNUNET_MESSAGE_TYPE_TRANSPORT_ACK:
2338       n->saw_ack = GNUNET_YES;
2339       /* intentional fall-through! */
2340     default:
2341 #if DEBUG_TRANSPORT
2342       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2343                   "Received message of type %u from other peer, sending to all clients.\n",
2344                   ntohs (message->type));
2345 #endif
2346       /* transmit message to all clients */
2347       im = GNUNET_malloc (sizeof (struct InboundMessage) + msize);
2348       im->header.size = htons (sizeof (struct InboundMessage) + msize);
2349       im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
2350       im->latency = GNUNET_TIME_relative_hton (latency);
2351       im->peer = *peer;
2352       memcpy (&im[1], message, msize);
2353
2354       cpos = clients;
2355       while (cpos != NULL)
2356         {
2357           transmit_to_client (cpos, &im->header, GNUNET_YES);
2358           cpos = cpos->next;
2359         }
2360       GNUNET_free (im);
2361     }
2362   GNUNET_assert (NULL != service_context->neighbour);
2363   return service_context;
2364 }
2365
2366
2367 /**
2368  * Handle START-message.  This is the first message sent to us
2369  * by any client which causes us to add it to our list.
2370  *
2371  * @param cls closure (always NULL)
2372  * @param client identification of the client
2373  * @param message the actual message
2374  */
2375 static void
2376 handle_start (void *cls,
2377               struct GNUNET_SERVER_Client *client,
2378               const struct GNUNET_MessageHeader *message)
2379 {
2380   struct TransportClient *c;
2381   struct ConnectInfoMessage cim;
2382   struct NeighbourList *n;
2383   struct InboundMessage *im;
2384   struct GNUNET_MessageHeader *ack;
2385
2386 #if DEBUG_TRANSPORT
2387   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2388               "Received `%s' request from client\n", "START");
2389 #endif
2390   c = clients;
2391   while (c != NULL)
2392     {
2393       if (c->client == client)
2394         {
2395           /* client already on our list! */
2396           GNUNET_break (0);
2397           GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2398           return;
2399         }
2400       c = c->next;
2401     }
2402   c = GNUNET_malloc (sizeof (struct TransportClient));
2403   c->next = clients;
2404   clients = c;
2405   c->client = client;
2406   if (our_hello != NULL)
2407     {
2408 #if DEBUG_TRANSPORT
2409       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2410                   "Sending our own HELLO to new client\n");
2411 #endif
2412       transmit_to_client (c,
2413                           (const struct GNUNET_MessageHeader *) our_hello,
2414                           GNUNET_NO);
2415       /* tell new client about all existing connections */
2416       cim.header.size = htons (sizeof (struct ConnectInfoMessage));
2417       cim.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
2418       cim.quota_out = htonl (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT / (60 * 1000));
2419       cim.latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO);  /* FIXME? */
2420       im = GNUNET_malloc (sizeof (struct InboundMessage) +
2421                           sizeof (struct GNUNET_MessageHeader));
2422       im->header.size = htons (sizeof (struct InboundMessage) +
2423                                sizeof (struct GNUNET_MessageHeader));
2424       im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
2425       im->latency = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO);  /* FIXME? */
2426       ack = (struct GNUNET_MessageHeader *) &im[1];
2427       ack->size = htons (sizeof (struct GNUNET_MessageHeader));
2428       ack->type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ACK);
2429       for (n = neighbours; n != NULL; n = n->next)
2430         {
2431           cim.id = n->id;
2432           transmit_to_client (c, &cim.header, GNUNET_NO);
2433           if (n->saw_ack)
2434             {
2435               im->peer = n->id;
2436               transmit_to_client (c, &im->header, GNUNET_NO);
2437             }
2438         }
2439       GNUNET_free (im);
2440     }
2441   GNUNET_SERVER_receive_done (client, GNUNET_OK);
2442 }
2443
2444
2445 /**
2446  * Handle HELLO-message.
2447  *
2448  * @param cls closure (always NULL)
2449  * @param client identification of the client
2450  * @param message the actual message
2451  */
2452 static void
2453 handle_hello (void *cls,
2454               struct GNUNET_SERVER_Client *client,
2455               const struct GNUNET_MessageHeader *message)
2456 {
2457   int ret;
2458
2459 #if DEBUG_TRANSPORT
2460   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2461               "Received `%s' request from client\n", "HELLO");
2462 #endif
2463   ret = process_hello (NULL, message);
2464   GNUNET_SERVER_receive_done (client, ret);
2465 }
2466
2467
2468 /**
2469  * Handle SEND-message.
2470  *
2471  * @param cls closure (always NULL)
2472  * @param client identification of the client
2473  * @param message the actual message
2474  */
2475 static void
2476 handle_send (void *cls,
2477              struct GNUNET_SERVER_Client *client,
2478              const struct GNUNET_MessageHeader *message)
2479 {
2480   struct TransportClient *tc;
2481   struct NeighbourList *n;
2482   const struct OutboundMessage *obm;
2483   const struct GNUNET_MessageHeader *obmm;
2484   uint16_t size;
2485   uint16_t msize;
2486
2487   size = ntohs (message->size);
2488   if (size <
2489       sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
2490     {
2491       GNUNET_break (0);
2492       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2493       return;
2494     }
2495   obm = (const struct OutboundMessage *) message;
2496 #if DEBUG_TRANSPORT
2497   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2498               "Received `%s' request from client with target `%4s'\n",
2499               "SEND", GNUNET_i2s (&obm->peer));
2500 #endif
2501   obmm = (const struct GNUNET_MessageHeader *) &obm[1];
2502   msize = ntohs (obmm->size);
2503   if (size != msize + sizeof (struct OutboundMessage))
2504     {
2505       GNUNET_break (0);
2506       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2507       return;
2508     }
2509   n = find_neighbour (&obm->peer);
2510   if (n == NULL)
2511     n = setup_new_neighbour (&obm->peer);
2512   tc = clients;
2513   while ((tc != NULL) && (tc->client != client))
2514     tc = tc->next;
2515
2516 #if DEBUG_TRANSPORT
2517   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2518               "Client asked to transmit %u-byte message of type %u to `%4s'\n",
2519               ntohs (obmm->size),
2520               ntohs (obmm->type), GNUNET_i2s (&obm->peer));
2521 #endif
2522   transmit_to_peer (tc, ntohl(obm->priority), obmm, GNUNET_NO, n);
2523   GNUNET_SERVER_receive_done (client, GNUNET_OK);
2524 }
2525
2526
2527 /**
2528  * Handle SET_QUOTA-message.
2529  *
2530  * @param cls closure (always NULL)
2531  * @param client identification of the client
2532  * @param message the actual message
2533  */
2534 static void
2535 handle_set_quota (void *cls,
2536                   struct GNUNET_SERVER_Client *client,
2537                   const struct GNUNET_MessageHeader *message)
2538 {
2539   const struct QuotaSetMessage *qsm =
2540     (const struct QuotaSetMessage *) message;
2541   struct NeighbourList *n;
2542   struct TransportPlugin *p;
2543   struct ReadyList *rl;
2544
2545 #if DEBUG_TRANSPORT
2546   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2547               "Received `%s' request from client for peer `%4s'\n",
2548               "SET_QUOTA", GNUNET_i2s (&qsm->peer));
2549 #endif
2550   n = find_neighbour (&qsm->peer);
2551   if (n == NULL)
2552     {
2553       GNUNET_SERVER_receive_done (client, GNUNET_OK);
2554       return;
2555     }
2556   update_quota (n);
2557   if (n->quota_in < ntohl (qsm->quota_in))
2558     n->last_quota_update = GNUNET_TIME_absolute_get ();
2559   n->quota_in = ntohl (qsm->quota_in);
2560   rl = n->plugins;
2561   while (rl != NULL)
2562     {
2563       p = rl->plugin;
2564       p->api->set_receive_quota (p->api->cls,
2565                                  &qsm->peer, ntohl (qsm->quota_in));
2566       rl = rl->next;
2567     }
2568   GNUNET_SERVER_receive_done (client, GNUNET_OK);
2569 }
2570
2571
2572 /**
2573  * Handle TRY_CONNECT-message.
2574  *
2575  * @param cls closure (always NULL)
2576  * @param client identification of the client
2577  * @param message the actual message
2578  */
2579 static void
2580 handle_try_connect (void *cls,
2581                     struct GNUNET_SERVER_Client *client,
2582                     const struct GNUNET_MessageHeader *message)
2583 {
2584   const struct TryConnectMessage *tcm;
2585
2586   tcm = (const struct TryConnectMessage *) message;
2587 #if DEBUG_TRANSPORT
2588   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2589               "Received `%s' request from client asking to connect to `%4s'\n",
2590               "TRY_CONNECT", GNUNET_i2s (&tcm->peer));
2591 #endif
2592   if (NULL == find_neighbour (&tcm->peer))
2593     setup_new_neighbour (&tcm->peer);
2594   GNUNET_SERVER_receive_done (client, GNUNET_OK);
2595 }
2596
2597
2598 /**
2599  * List of handlers for the messages understood by this
2600  * service.
2601  */
2602 static struct GNUNET_SERVER_MessageHandler handlers[] = {
2603   {&handle_start, NULL,
2604    GNUNET_MESSAGE_TYPE_TRANSPORT_START, 0},
2605   {&handle_hello, NULL,
2606    GNUNET_MESSAGE_TYPE_HELLO, 0},
2607   {&handle_send, NULL,
2608    GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
2609   {&handle_set_quota, NULL,
2610    GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA, sizeof (struct QuotaSetMessage)},
2611   {&handle_try_connect, NULL,
2612    GNUNET_MESSAGE_TYPE_TRANSPORT_TRY_CONNECT,
2613    sizeof (struct TryConnectMessage)},
2614   {NULL, NULL, 0, 0}
2615 };
2616
2617
2618 /**
2619  * Setup the environment for this plugin.
2620  */
2621 static void
2622 create_environment (struct TransportPlugin *plug)
2623 {
2624   plug->env.cfg = cfg;
2625   plug->env.sched = sched;
2626   plug->env.my_public_key = &my_public_key;
2627   plug->env.cls = plug;
2628   plug->env.receive = &plugin_env_receive;
2629   plug->env.lookup = &plugin_env_lookup_address;
2630   plug->env.notify_address = &plugin_env_notify_address;
2631   plug->env.default_quota_in = (GNUNET_CONSTANTS_DEFAULT_BPM_IN_OUT + 59999) / (60 * 1000);
2632   plug->env.max_connections = max_connect_per_transport;
2633 }
2634
2635
2636 /**
2637  * Start the specified transport (load the plugin).
2638  */
2639 static void
2640 start_transport (struct GNUNET_SERVER_Handle *server, const char *name)
2641 {
2642   struct TransportPlugin *plug;
2643   char *libname;
2644
2645   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2646               _("Loading `%s' transport plugin\n"), name);
2647   GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", name);
2648   plug = GNUNET_malloc (sizeof (struct TransportPlugin));
2649   create_environment (plug);
2650   plug->short_name = GNUNET_strdup (name);
2651   plug->lib_name = libname;
2652   plug->next = plugins;
2653   plugins = plug;
2654   plug->api = GNUNET_PLUGIN_load (libname, &plug->env);
2655   if (plug->api == NULL)
2656     {
2657       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2658                   _("Failed to load transport plugin for `%s'\n"), name);
2659       GNUNET_free (plug->short_name);
2660       plugins = plug->next;
2661       GNUNET_free (libname);
2662       GNUNET_free (plug);
2663     }
2664 }
2665
2666
2667 /**
2668  * Called whenever a client is disconnected.  Frees our
2669  * resources associated with that client.
2670  *
2671  * @param cls closure
2672  * @param client identification of the client
2673  */
2674 static void
2675 client_disconnect_notification (void *cls,
2676                                 struct GNUNET_SERVER_Client *client)
2677 {
2678   struct TransportClient *pos;
2679   struct TransportClient *prev;
2680   struct ClientMessageQueueEntry *mqe;
2681
2682 #if DEBUG_TRANSPORT
2683   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
2684               "Client disconnected, cleaning up.\n");
2685 #endif
2686   prev = NULL;
2687   pos = clients;
2688   while ((pos != NULL) && (pos->client != client))
2689     {
2690       prev = pos;
2691       pos = pos->next;
2692     }
2693   if (pos == NULL)
2694     return;
2695   while (NULL != (mqe = pos->message_queue_head))
2696     {
2697       pos->message_queue_head = mqe->next;
2698       GNUNET_free (mqe);
2699     }
2700   pos->message_queue_head = NULL;
2701   if (prev == NULL)
2702     clients = pos->next;
2703   else
2704     prev->next = pos->next;
2705   if (GNUNET_YES == pos->tcs_pending)
2706     {
2707       pos->client = NULL;
2708       return;
2709     }
2710   GNUNET_free (pos);
2711 }
2712
2713
2714 /**
2715  * Initiate transport service.
2716  *
2717  * @param cls closure
2718  * @param s scheduler to use
2719  * @param serv the initialized server
2720  * @param c configuration to use
2721  */
2722 static void
2723 run (void *cls,
2724      struct GNUNET_SCHEDULER_Handle *s,
2725      struct GNUNET_SERVER_Handle *serv, struct GNUNET_CONFIGURATION_Handle *c)
2726 {
2727   char *plugs;
2728   char *pos;
2729   int no_transports;
2730   unsigned long long tneigh;
2731   char *keyfile;
2732
2733   sched = s;
2734   cfg = c;
2735   /* parse configuration */
2736   if ((GNUNET_OK !=
2737        GNUNET_CONFIGURATION_get_value_number (c,
2738                                               "TRANSPORT",
2739                                               "NEIGHBOUR_LIMIT",
2740                                               &tneigh)) ||
2741       (GNUNET_OK !=
2742        GNUNET_CONFIGURATION_get_value_filename (c,
2743                                                 "GNUNETD",
2744                                                 "HOSTKEY", &keyfile)))
2745     {
2746       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2747                   _
2748                   ("Transport service is lacking key configuration settings.  Exiting.\n"));
2749       GNUNET_SCHEDULER_shutdown (s);
2750       return;
2751     }
2752   max_connect_per_transport = (uint32_t) tneigh;
2753   my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
2754   GNUNET_free (keyfile);
2755   if (my_private_key == NULL)
2756     {
2757       GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2758                   _
2759                   ("Transport service could not access hostkey.  Exiting.\n"));
2760       GNUNET_SCHEDULER_shutdown (s);
2761       return;
2762     }
2763   GNUNET_CRYPTO_rsa_key_get_public (my_private_key, &my_public_key);
2764   GNUNET_CRYPTO_hash (&my_public_key,
2765                       sizeof (my_public_key), &my_identity.hashPubKey);
2766   /* setup notification */
2767   server = serv;
2768   GNUNET_SERVER_disconnect_notify (server,
2769                                    &client_disconnect_notification, NULL);
2770   /* load plugins... */
2771   no_transports = 1;
2772   if (GNUNET_OK ==
2773       GNUNET_CONFIGURATION_get_value_string (c,
2774                                              "TRANSPORT", "PLUGINS", &plugs))
2775     {
2776       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2777                   _("Starting transport plugins `%s'\n"), plugs);
2778       pos = strtok (plugs, " ");
2779       while (pos != NULL)
2780         {
2781           start_transport (server, pos);
2782           no_transports = 0;
2783           pos = strtok (NULL, " ");
2784         }
2785       GNUNET_free (plugs);
2786     }
2787   if (no_transports)
2788     refresh_hello ();
2789 #if DEBUG_TRANSPORT
2790   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2791               _("Transport service ready.\n"));
2792 #endif
2793   /* process client requests */
2794   GNUNET_SERVER_add_handlers (server, handlers);
2795 }
2796
2797
2798 /**
2799  * Function called when the service shuts
2800  * down.  Unloads our plugins.
2801  *
2802  * @param cls closure
2803  * @param cfg configuration to use
2804  */
2805 static void
2806 unload_plugins (void *cls, struct GNUNET_CONFIGURATION_Handle *cfg)
2807 {
2808   struct TransportPlugin *plug;
2809   struct AddressList *al;
2810
2811 #if DEBUG_TRANSPORT
2812   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2813               "Transport service is unloading plugins...\n");
2814 #endif
2815   while (NULL != (plug = plugins))
2816     {
2817       plugins = plug->next;
2818       GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
2819       GNUNET_free (plug->lib_name);
2820       GNUNET_free (plug->short_name);
2821       while (NULL != (al = plug->addresses))
2822         {
2823           plug->addresses = al->next;
2824           GNUNET_free (al);
2825         }
2826       GNUNET_free (plug);
2827     }
2828   if (my_private_key != NULL)
2829     GNUNET_CRYPTO_rsa_key_free (my_private_key);
2830 }
2831
2832
2833 /**
2834  * The main function for the transport service.
2835  *
2836  * @param argc number of arguments from the command line
2837  * @param argv command line arguments
2838  * @return 0 ok, 1 on error
2839  */
2840 int
2841 main (int argc, char *const *argv)
2842 {
2843   return (GNUNET_OK ==
2844           GNUNET_SERVICE_run (argc,
2845                               argv,
2846                               "transport",
2847                               &run, NULL, &unload_plugins, NULL)) ? 0 : 1;
2848 }
2849
2850 /* end of gnunet-service-transport.c */