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