check for target repetition
[oweals/gnunet.git] / src / transport / plugin_transport_tcp.c
1 /*
2      This file is part of GNUnet
3      (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 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/plugin_transport_tcp.c
23  * @brief Implementation of the TCP transport service
24  * @author Christian Grothoff
25  */
26
27 #include "platform.h"
28 #include "gnunet_hello_lib.h"
29 #include "gnunet_network_lib.h"
30 #include "gnunet_os_lib.h"
31 #include "gnunet_peerinfo_service.h"
32 #include "gnunet_protocols.h"
33 #include "gnunet_resolver_service.h"
34 #include "gnunet_server_lib.h"
35 #include "gnunet_service_lib.h"
36 #include "gnunet_statistics_service.h"
37 #include "gnunet_transport_service.h"
38 #include "plugin_transport.h"
39 #include "transport.h"
40
41 #define DEBUG_TCP GNUNET_NO
42
43 /**
44  * After how long do we expire an address that we
45  * learned from another peer if it is not reconfirmed
46  * by anyone?
47  */
48 #define LEARNED_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 6)
49
50 /**
51  * How long until we give up on transmitting the welcome message?
52  */
53 #define WELCOME_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
54
55 /**
56  * How long until we give up on transmitting the welcome message?
57  */
58 #define HOSTNAME_RESOLVE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
59
60 /**
61  * For how many messages back to we keep transmission times?
62  */
63 #define ACK_LOG_SIZE 32
64
65 /**
66  * Initial handshake message for a session.  This header
67  * is followed by the address that the other peer used to
68  * connect to us (so that we may learn it) or the address
69  * that the other peer got from the accept call.
70  */
71 struct WelcomeMessage
72 {
73   struct GNUNET_MessageHeader header;
74
75   /**
76    * Identity of the node connecting (TCP client)
77    */
78   struct GNUNET_PeerIdentity clientIdentity;
79
80 };
81
82
83 /**
84  * Encapsulation for normal TCP traffic.
85  */
86 struct DataMessage
87 {
88   struct GNUNET_MessageHeader header;
89
90   /**
91    * For alignment.
92    */
93   uint32_t reserved GNUNET_PACKED;
94
95   /**
96    * Number of the last message that was received from the other peer.
97    */
98   uint64_t ack_in GNUNET_PACKED;
99
100   /**
101    * Number of this outgoing message.
102    */
103   uint64_t ack_out GNUNET_PACKED;
104
105   /**
106    * How long was sending this ack delayed by the other peer
107    * (estimate).  The receiver of this message can use the delay
108    * between sending his message number 'ack' and receiving this ack
109    * minus the delay as an estimate of the round-trip time.
110    */
111   struct GNUNET_TIME_RelativeNBO delay;
112
113 };
114
115
116 /**
117  * Encapsulation of all of the state of the plugin.
118  */
119 struct Plugin;
120
121
122 /**
123  * Information kept for each message that is yet to
124  * be transmitted.
125  */
126 struct PendingMessage
127 {
128
129   /**
130    * This is a linked list.
131    */
132   struct PendingMessage *next;
133
134   /**
135    * The pending message, pointer to the end
136    * of this struct, do not free!
137    */
138   struct GNUNET_MessageHeader *msg;
139
140
141   /**
142    * Continuation function to call once the message
143    * has been sent.  Can be  NULL if there is no
144    * continuation to call.
145    */
146   GNUNET_TRANSPORT_TransmitContinuation transmit_cont;
147
148   /**
149    * Closure for transmit_cont.
150    */
151   void *transmit_cont_cls;
152
153   /**
154    * Timeout value for the pending message.
155    */
156   struct GNUNET_TIME_Absolute timeout;
157
158   /**
159    * GNUNET_YES if this is a welcome message;
160    * otherwise this should be a DATA message.
161    */
162   int is_welcome;
163
164 };
165
166
167 /**
168  * Session handle for TCP connections.
169  */
170 struct Session
171 {
172
173   /**
174    * Stored in a linked list.
175    */
176   struct Session *next;
177
178   /**
179    * Pointer to the global plugin struct.
180    */
181   struct Plugin *plugin;
182
183   /**
184    * The client (used to identify this connection)
185    */
186   struct GNUNET_SERVER_Client *client;
187
188   /**
189    * gnunet-service-transport context for this connection.
190    */
191   struct ReadyList *service_context;
192
193   /**
194    * Messages currently pending for transmission
195    * to this peer, if any.
196    */
197   struct PendingMessage *pending_messages;
198
199   /**
200    * Handle for pending transmission request.
201    */
202   struct GNUNET_NETWORK_TransmitHandle *transmit_handle;
203
204   /**
205    * To whom are we talking to (set to our identity
206    * if we are still waiting for the welcome message)
207    */
208   struct GNUNET_PeerIdentity target;
209
210   /**
211    * At what time did we reset last_received last?
212    */
213   struct GNUNET_TIME_Absolute last_quota_update;
214
215   /**
216    * Address of the other peer if WE initiated the connection
217    * (and hence can be sure what it is), otherwise NULL.
218    */
219   void *connect_addr;
220
221   /**
222    * How many bytes have we received since the "last_quota_update"
223    * timestamp?
224    */
225   uint64_t last_received;
226
227   /**
228    * Our current latency estimate (in ms).
229    */
230   double latency_estimate;
231
232   /**
233    * Time when we generated the last ACK_LOG_SIZE acks.
234    * (the "last" refers to the "out_msg_counter" here)
235    */
236   struct GNUNET_TIME_Absolute gen_time[ACK_LOG_SIZE];
237
238   /**
239    * Our current sequence number.
240    */
241   uint64_t out_msg_counter;
242
243   /**
244    * Highest received incoming sequence number.
245    */
246   uint64_t max_in_msg_counter;
247
248   /**
249    * Number of bytes per ms that this peer is allowed
250    * to send to us.
251    */
252   uint32_t quota_in;
253
254   /**
255    * Length of connect_addr, can be 0.
256    */
257   size_t connect_alen;
258
259   /**
260    * Are we still expecting the welcome message? (GNUNET_YES/GNUNET_NO)
261    */
262   int expecting_welcome;
263
264   /**
265    * Are we still trying to connect?
266    */
267   int still_connecting;
268
269 };
270
271
272 /**
273  * Encapsulation of all of the state of the plugin.
274  */
275 struct Plugin
276 {
277   /**
278    * Our environment.
279    */
280   struct GNUNET_TRANSPORT_PluginEnvironment *env;
281
282   /**
283    * The listen socket.
284    */
285   struct GNUNET_NETWORK_SocketHandle *lsock;
286
287   /**
288    * List of open TCP sessions.
289    */
290   struct Session *sessions;
291
292   /**
293    * Handle for the statistics service.
294    */
295   struct GNUNET_STATISTICS_Handle *statistics;
296
297   /**
298    * Handle to the network service.
299    */
300   struct GNUNET_SERVICE_Context *service;
301
302   /**
303    * Handle to the server for this service.
304    */
305   struct GNUNET_SERVER_Handle *server;
306
307   /**
308    * Copy of the handler array where the closures are
309    * set to this struct's instance.
310    */
311   struct GNUNET_SERVER_MessageHandler *handlers;
312
313   /**
314    * ID of task used to update our addresses when one expires.
315    */
316   GNUNET_SCHEDULER_TaskIdentifier address_update_task;
317
318   /**
319    * Port that we are actually listening on.
320    */
321   uint16_t open_port;
322
323   /**
324    * Port that the user said we would have visible to the
325    * rest of the world.
326    */
327   uint16_t adv_port;
328
329 };
330
331
332 /**
333  * Find the session handle for the given peer.
334  */
335 static struct Session *
336 find_session_by_target (struct Plugin *plugin,
337                         const struct GNUNET_PeerIdentity *target)
338 {
339   struct Session *ret;
340
341   ret = plugin->sessions;
342   while ((ret != NULL) &&
343          (0 != memcmp (target,
344                        &ret->target, sizeof (struct GNUNET_PeerIdentity))))
345     ret = ret->next;
346   return ret;
347 }
348
349
350 /**
351  * Find the session handle for the given peer.
352  */
353 static struct Session *
354 find_session_by_client (struct Plugin *plugin,
355                         const struct GNUNET_SERVER_Client *client)
356 {
357   struct Session *ret;
358
359   ret = plugin->sessions;
360   while ((ret != NULL) && (client != ret->client))
361     ret = ret->next;
362   return ret;
363 }
364
365
366 /**
367  * Create a welcome message.
368  */
369 static struct PendingMessage *
370 create_welcome (size_t addrlen, const void *addr, struct Plugin *plugin)
371 {
372   struct PendingMessage *pm;
373   struct WelcomeMessage *welcome;
374
375   pm = GNUNET_malloc (sizeof (struct PendingMessage) +
376                       sizeof (struct WelcomeMessage) + addrlen);
377   pm->msg = (struct GNUNET_MessageHeader *) &pm[1];
378   welcome = (struct WelcomeMessage *) &pm[1];
379   welcome->header.size = htons (sizeof (struct WelcomeMessage) + addrlen);
380   welcome->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME);
381   GNUNET_CRYPTO_hash (plugin->env->my_public_key,
382                       sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
383                       &welcome->clientIdentity.hashPubKey);
384   memcpy (&welcome[1], addr, addrlen);
385   pm->timeout = GNUNET_TIME_relative_to_absolute (WELCOME_TIMEOUT);
386   pm->is_welcome = GNUNET_YES;
387   return pm;
388 }
389
390
391 /**
392  * Create a new session using the specified address
393  * for the welcome message.
394  *
395  * @param plugin us
396  * @param target peer to connect to
397  * @param client client to use
398  * @param addrlen IPv4 or IPv6
399  * @param addr either struct sockaddr_in or struct sockaddr_in6
400  * @return NULL connection failed / invalid address
401  */
402 static struct Session *
403 create_session (struct Plugin *plugin,
404                 const struct GNUNET_PeerIdentity *target,
405                 struct GNUNET_SERVER_Client *client,
406                 const void *addr, size_t addrlen)
407 {
408   struct Session *ret;
409
410   ret = GNUNET_malloc (sizeof (struct Session));
411   ret->plugin = plugin;
412   ret->next = plugin->sessions;
413   plugin->sessions = ret;
414   ret->client = client;
415   ret->target = *target;
416   ret->last_quota_update = GNUNET_TIME_absolute_get ();
417   ret->quota_in = plugin->env->default_quota_in;
418   ret->expecting_welcome = GNUNET_YES;
419   ret->pending_messages = create_welcome (addrlen, addr, plugin);
420   return ret;
421 }
422
423
424 /**
425  * Create a new session connecting to the specified
426  * target at the specified address.
427  *
428  * @param plugin us
429  * @param target peer to connect to
430  * @param addrlen IPv4 or IPv6
431  * @param addr either struct sockaddr_in or struct sockaddr_in6
432  * @return NULL connection failed / invalid address
433  */
434 static struct Session *
435 connect_and_create_session (struct Plugin *plugin,
436                             const struct GNUNET_PeerIdentity *target,
437                             const void *addr, size_t addrlen)
438 {
439   struct GNUNET_SERVER_Client *client;
440   struct GNUNET_NETWORK_SocketHandle *conn;
441   struct Session *session;
442   int af;
443
444   session = plugin->sessions;
445   while (session != NULL)
446     {
447       if ((0 == memcmp (target,
448                         &session->target,
449                         sizeof (struct GNUNET_PeerIdentity))) &&
450           (session->connect_alen == addrlen) &&
451           (0 == memcmp (session->connect_addr, addr, addrlen)))
452         return session;         /* already exists! */
453       session = session->next;
454     }
455
456   if (addrlen == sizeof (struct sockaddr_in))
457     af = AF_INET;
458   else if (addrlen == sizeof (struct sockaddr_in6))
459     af = AF_INET6;    
460   else
461     {
462       GNUNET_break_op (0);
463       return NULL;              /* invalid address */
464     }
465   conn = GNUNET_NETWORK_socket_create_from_sockaddr (plugin->env->sched,
466                                                      af,
467                                                      addr,
468                                                      addrlen,
469                                                      GNUNET_SERVER_MAX_MESSAGE_SIZE);
470   if (conn == NULL)
471     {
472 #if DEBUG_TCP
473       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
474                        "tcp",
475                        "Failed to create connection to peer at `%s'.\n",
476                        GNUNET_a2s(addr, addrlen));
477 #endif
478       return NULL;
479     }
480   client = GNUNET_SERVER_connect_socket (plugin->server, conn);
481   GNUNET_assert (client != NULL);
482   session = create_session (plugin, target, client, addr, addrlen);
483   session->connect_alen = addrlen;
484   session->connect_addr = GNUNET_malloc (addrlen);
485   memcpy (session->connect_addr, addr, addrlen);
486 #if DEBUG_TCP
487   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
488                    "tcp",
489                    "Creating new session %p with `%s' based on `%s' request.\n",
490                    session, 
491                    GNUNET_a2s(addr, addrlen),
492                    "send_to");
493 #endif
494   return session;
495 }
496
497
498 /**
499  * If we have pending messages, ask the server to
500  * transmit them (schedule the respective tasks, etc.)
501  *
502  * @param session for which session should we do this
503  */
504 static void process_pending_messages (struct Session *session);
505
506
507 /**
508  * Function called to notify a client about the socket
509  * begin ready to queue more data.  "buf" will be
510  * NULL and "size" zero if the socket was closed for
511  * writing in the meantime.
512  *
513  * @param cls closure
514  * @param size number of bytes available in buf
515  * @param buf where the callee should write the message
516  * @return number of bytes written to buf
517  */
518 static size_t
519 do_transmit (void *cls, size_t size, void *buf)
520 {
521   struct Session *session = cls;
522   struct PendingMessage *pm;
523   char *cbuf;
524   uint16_t msize;
525   size_t ret;
526   struct DataMessage *dm;
527
528   session->transmit_handle = NULL;
529   if (buf == NULL)
530     {
531 #if DEBUG_TCP
532       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
533                        "tcp", 
534                        "Timeout trying to transmit to peer `%4s', discarding message queue.\n",
535                        GNUNET_i2s(&session->target));
536 #endif
537       /* timeout */
538       while (NULL != (pm = session->pending_messages))
539         {
540           session->pending_messages = pm->next;
541           if (pm->transmit_cont != NULL)
542             pm->transmit_cont (pm->transmit_cont_cls,
543                                session->service_context,
544                                &session->target, GNUNET_SYSERR);
545           GNUNET_free (pm);
546         }
547       return 0;
548     }
549   ret = 0;
550   cbuf = buf;
551   while (NULL != (pm = session->pending_messages))
552     {
553       if (pm->is_welcome)
554         {
555           if (size < (msize = htons (pm->msg->size)))
556             break;
557           memcpy (cbuf, pm->msg, msize);
558           cbuf += msize;
559           ret += msize;
560           size -= msize;
561         }
562       else
563         {
564           if (size <
565               sizeof (struct DataMessage) + (msize = htons (pm->msg->size)))
566             break;
567           dm = (struct DataMessage *) cbuf;
568           dm->header.size = htons (sizeof (struct DataMessage) + msize);
569           dm->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_DATA);
570           dm->ack_out = GNUNET_htonll (++session->out_msg_counter);
571           dm->ack_in = GNUNET_htonll (session->max_in_msg_counter);
572           cbuf += sizeof (struct DataMessage);
573           ret += sizeof (struct DataMessage);
574           size -= sizeof (struct DataMessage);
575           memcpy (cbuf, pm->msg, msize);
576           cbuf += msize;
577           ret += msize;
578           size -= msize;
579         }
580       session->pending_messages = pm->next;
581       if (pm->transmit_cont != NULL)
582         pm->transmit_cont (pm->transmit_cont_cls,
583                            session->service_context,
584                            &session->target, GNUNET_OK);
585       GNUNET_free (pm);
586       session->gen_time[session->out_msg_counter % ACK_LOG_SIZE]
587         = GNUNET_TIME_absolute_get ();
588     }
589   process_pending_messages (session);
590 #if DEBUG_TCP
591   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
592                    "tcp", "Transmitting %u bytes\n", ret);
593 #endif
594   return ret;
595 }
596
597
598 /**
599  * If we have pending messages, ask the server to
600  * transmit them (schedule the respective tasks, etc.)
601  *
602  * @param session for which session should we do this
603  */
604 static void
605 process_pending_messages (struct Session *session)
606 {
607   GNUNET_assert (session->client != NULL);
608   if (session->pending_messages == NULL)
609     return;
610   if (session->transmit_handle != NULL)
611     return;
612   session->transmit_handle
613     = GNUNET_SERVER_notify_transmit_ready (session->client,
614                                            htons (session->
615                                                   pending_messages->msg->
616                                                   size) +
617                                            (session->
618                                             pending_messages->is_welcome ? 0 :
619                                             sizeof (struct DataMessage)),
620                                            GNUNET_TIME_absolute_get_remaining
621                                            (session->
622                                             pending_messages[0].timeout),
623                                            &do_transmit, session);
624 }
625
626
627 /**
628  * Function that can be used by the transport service to transmit
629  * a message using the plugin using a fresh connection (even if
630  * we already have a connection to this peer, this function is
631  * required to establish a new one).
632  *
633  * @param cls closure
634  * @param target who should receive this message
635  * @param msg1 first message to transmit
636  * @param msg2 second message to transmit (can be NULL)
637  * @param timeout how long should we try to transmit these?
638  * @param addrlen length of the address
639  * @param addr the address
640  * @return session if the transmission has been scheduled
641  *         NULL if the address format is invalid
642  */
643 static void *
644 tcp_plugin_send_to (void *cls,
645                     const struct GNUNET_PeerIdentity *target,
646                     const struct GNUNET_MessageHeader *msg1,
647                     const struct GNUNET_MessageHeader *msg2,
648                     struct GNUNET_TIME_Relative timeout,
649                     const void *addr, size_t addrlen)
650 {
651   struct Plugin *plugin = cls;
652   struct Session *session;
653   struct PendingMessage *pl;
654   struct PendingMessage *pm;
655
656   session = connect_and_create_session (plugin, target, addr, addrlen);
657   if (session == NULL)
658     {
659 #if DEBUG_TCP
660       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
661                        "tcp", "Failed to create fresh session.\n");
662 #endif
663       return NULL;
664     }
665   pl = NULL;
666   if (msg2 != NULL)
667     {
668       pm = GNUNET_malloc (sizeof (struct PendingMessage) +
669                           ntohs (msg2->size));
670       pm->msg = (struct GNUNET_MessageHeader *) &pm[1];
671       memcpy (pm->msg, msg2, ntohs (msg2->size));
672       pm->timeout = GNUNET_TIME_relative_to_absolute (timeout);
673       pm->is_welcome = GNUNET_NO;
674       pl = pm;
675     }
676   if (msg1 != NULL)
677     {
678       pm = GNUNET_malloc (sizeof (struct PendingMessage) +
679                           ntohs (msg1->size));
680       pm->msg = (struct GNUNET_MessageHeader *) &pm[1];
681       memcpy (pm->msg, msg1, ntohs (msg1->size));
682       pm->timeout = GNUNET_TIME_relative_to_absolute (timeout);
683       pm->is_welcome = GNUNET_NO;
684       pm->next = pl;
685       pl = pm;
686     }
687   /* append */
688   if (session->pending_messages != NULL)
689     {
690       pm = session->pending_messages;
691       while (pm->next != NULL)
692         pm = pm->next;
693       pm->next = pl;
694     }
695   else
696     {
697       session->pending_messages = pl;
698     }
699   process_pending_messages (session);
700   return session;
701 }
702
703
704 /**
705  * Functions with this signature are called whenever we need
706  * to close a session due to a disconnect or failure to
707  * establish a connection.
708  *
709  * @param session session to close down
710  */
711 static void
712 disconnect_session (struct Session *session)
713 {
714   struct Session *prev;
715   struct Session *pos;
716   struct PendingMessage *pm;
717
718 #if DEBUG_TCP
719   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
720                    "tcp",
721                    "Disconnecting from other peer (session %p).\n", session);
722 #endif
723   /* remove from session list */
724   prev = NULL;
725   pos = session->plugin->sessions;
726   while (pos != session)
727     {
728       prev = pos;
729       pos = pos->next;
730     }
731   if (prev == NULL)
732     session->plugin->sessions = session->next;
733   else
734     prev->next = session->next;
735   /* clean up state */
736   if (session->client != NULL)
737     {
738 #if DEBUG_TCP
739       GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
740                   "Disconnecting from client address %p\n", session->client);
741 #endif
742       GNUNET_SERVER_client_drop (session->client);
743       session->client = NULL;
744     }
745   if (session->transmit_handle != NULL)
746     {
747       GNUNET_NETWORK_notify_transmit_ready_cancel (session->transmit_handle);
748       session->transmit_handle = NULL;
749     }
750   while (NULL != (pm = session->pending_messages))
751     {
752       session->pending_messages = pm->next;
753       if (NULL != pm->transmit_cont)
754         pm->transmit_cont (pm->transmit_cont_cls,
755                            session->service_context,
756                            &session->target, GNUNET_SYSERR);
757       GNUNET_free (pm);
758     }
759   /* notify transport service about disconnect */
760   session->plugin->env->receive (session->plugin->env->cls,
761                                  session,
762                                  session->service_context,
763                                  GNUNET_TIME_UNIT_ZERO,
764                                  &session->target, NULL);
765   GNUNET_free_non_null (session->connect_addr);
766   GNUNET_free (session);
767 }
768
769
770 /**
771  * Iterator callback to go over all addresses.  If we get
772  * a TCP address, increment the counter
773  *
774  * @param cls closure, points to the counter
775  * @param tname name of the transport
776  * @param expiration expiration time
777  * @param addr the address
778  * @param addrlen length of the address
779  * @return GNUNET_OK to keep the address,
780  *         GNUNET_NO to delete it from the HELLO
781  *         GNUNET_SYSERR to stop iterating (but keep current address)
782  */
783 static int
784 count_tcp_addresses (void *cls,
785                      const char *tname,
786                      struct GNUNET_TIME_Absolute expiration,
787                      const void *addr, size_t addrlen)
788 {
789   unsigned int *counter = cls;
790
791   if (0 != strcmp (tname, "tcp"))
792     return GNUNET_OK;           /* not one of ours */
793   (*counter)++;
794   return GNUNET_OK;             /* failed to connect */
795 }
796
797
798 struct ConnectContext
799 {
800   struct Plugin *plugin;
801
802   struct GNUNET_NETWORK_SocketHandle *sa;
803
804   struct PendingMessage *welcome;
805
806   unsigned int pos;
807 };
808
809
810 /**
811  * Iterator callback to go over all addresses.  If we get
812  * the "pos" TCP address, try to connect to it.
813  *
814  * @param cls closure
815  * @param tname name of the transport
816  * @param expiration expiration time
817  * @param addrlen length of the address
818  * @param addr the address
819  * @return GNUNET_OK to keep the address,
820  *         GNUNET_NO to delete it from the HELLO
821  *         GNUNET_SYSERR to stop iterating (but keep current address)
822  */
823 static int
824 try_connect_to_address (void *cls,
825                         const char *tname,
826                         struct GNUNET_TIME_Absolute expiration,
827                         const void *addr, size_t addrlen)
828 {
829   struct ConnectContext *cc = cls;
830   int af;
831
832   if (0 != strcmp (tname, "tcp"))
833     return GNUNET_OK;           /* not one of ours */
834   if (sizeof (struct sockaddr_in) == addrlen)
835     af = AF_INET;
836   else if (sizeof (struct sockaddr_in6) == addrlen)
837     af = AF_INET6;
838   else
839     {
840       /* not a valid address */
841       GNUNET_break (0);
842       return GNUNET_NO;
843     }
844   if (0 == cc->pos--)
845     {
846       cc->welcome = create_welcome (addrlen, addr, cc->plugin);
847       cc->sa =
848         GNUNET_NETWORK_socket_create_from_sockaddr (cc->plugin->env->sched,
849                                                     af, addr, addrlen,
850                                                     GNUNET_SERVER_MAX_MESSAGE_SIZE);
851 #if DEBUG_TCP
852       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
853                        "tcp", "Connected to other peer.\n");
854 #endif
855       return GNUNET_SYSERR;
856     }
857   return GNUNET_OK;             /* failed to connect */
858 }
859
860
861 /**
862  * Type of an iterator over the hosts.  Note that each
863  * host will be called with each available protocol.
864  *
865  * @param cls closure
866  * @param peer id of the peer, NULL for last call
867  * @param hello hello message for the peer (can be NULL)
868  * @param trust amount of trust we have in the peer
869  */
870 static void
871 session_try_connect (void *cls,
872                      const struct GNUNET_PeerIdentity *peer,
873                      const struct GNUNET_HELLO_Message *hello, uint32_t trust)
874 {
875   struct Session *session = cls;
876   unsigned int count;
877   struct ConnectContext cctx;
878   struct PendingMessage *pm;
879
880   if (peer == NULL)
881     {
882       /* last call, destroy session if we are still not
883          connected */
884       if (session->still_connecting == GNUNET_NO)
885         {
886 #if DEBUG_TCP
887           GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
888                            "tcp",
889                            "Connected to other peer, now processing messages.\n");
890 #endif
891           process_pending_messages (session);
892         }
893       else
894         {
895 #if DEBUG_TCP
896           GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
897                            "tcp",
898                            "Failed to connect to other peer, now closing session.\n");
899 #endif
900           disconnect_session (session);
901         }
902       return;
903     }
904   if ((hello == NULL) || (session->client != NULL))
905     {
906       GNUNET_break (0);         /* should this ever happen!? */
907       return;
908     }
909   count = 0;
910   GNUNET_HELLO_iterate_addresses (hello,
911                                   GNUNET_NO, &count_tcp_addresses, &count);
912   if (count == 0)
913     {
914 #if DEBUG_TCP
915       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
916                        "tcp",
917                        "Asked to connect, but have no addresses to try.\n");
918 #endif
919       return;
920     }
921   cctx.plugin = session->plugin;
922   cctx.sa = NULL;
923   cctx.welcome = NULL;
924   cctx.pos = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, count);
925   GNUNET_HELLO_iterate_addresses (hello,
926                                   GNUNET_NO, &try_connect_to_address, &cctx);
927   if (cctx.sa == NULL)
928     {
929 #if DEBUG_TCP
930       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
931                        "tcp",
932                        "Asked to connect, but all addresses failed.\n");
933 #endif
934       GNUNET_free_non_null (cctx.welcome);
935       return;
936     }
937   session->client = GNUNET_SERVER_connect_socket (session->plugin->server,
938                                                   cctx.sa);
939 #if DEBUG_TCP
940   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
941               "Connected getting client address %p\n", session->client);
942 #endif
943   if (session->client == NULL)
944     {
945       GNUNET_break (0);         /* how could this happen? */
946       GNUNET_free_non_null (cctx.welcome);
947       return;
948     }
949   pm = cctx.welcome;
950   /* prepend (!) */
951   pm->next = session->pending_messages;
952   session->pending_messages = pm;
953   session->still_connecting = GNUNET_NO;
954 #if DEBUG_TCP
955   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
956                    "tcp",
957                    "Connected to other peer, now sending `%s' message.\n",
958                    "WELCOME");
959 #endif
960 }
961
962
963 /**
964  * Function that can be used by the transport service to transmit
965  * a message using the plugin.
966  *
967  * @param cls closure
968  * @param plugin_context value we were asked to pass to this plugin
969  *        to respond to the given peer (use is optional,
970  *        but may speed up processing), can be NULL
971  * @param service_context value passed to the transport-service
972  *        to identify the neighbour
973  * @param target who should receive this message
974  * @param msg the message to transmit
975  * @param cont continuation to call once the message has
976  *        been transmitted (or if the transport is ready
977  *        for the next transmission call; or if the
978  *        peer disconnected...)
979  * @param cont_cls closure for cont
980  * @return plugin_context that should be used next time for
981  *         sending messages to the specified peer
982  */
983 static void *
984 tcp_plugin_send (void *cls,
985                  void *plugin_context,
986                  struct ReadyList *service_context,
987                  const struct GNUNET_PeerIdentity *target,
988                  const struct GNUNET_MessageHeader *msg,
989                  struct GNUNET_TIME_Relative timeout,
990                  GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls)
991 {
992   struct Plugin *plugin = cls;
993   struct Session *session = plugin_context;
994   struct PendingMessage *pm;
995   struct PendingMessage *pme;
996
997   if (session == NULL)
998     session = find_session_by_target (plugin, target);  
999   pm = GNUNET_malloc (sizeof (struct PendingMessage) + ntohs (msg->size));
1000   pm->msg = (struct GNUNET_MessageHeader *) &pm[1];
1001   memcpy (pm->msg, msg, ntohs (msg->size));
1002   pm->timeout = GNUNET_TIME_relative_to_absolute (timeout);
1003   pm->transmit_cont = cont;
1004   pm->transmit_cont_cls = cont_cls;
1005   if (session == NULL)
1006     {
1007       session = GNUNET_malloc (sizeof (struct Session));
1008 #if DEBUG_TCP
1009       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1010                        "tcp",
1011                        "Asked to transmit, creating fresh session %p.\n",
1012                        session);
1013 #endif
1014       session->next = plugin->sessions;
1015       plugin->sessions = session;
1016       session->plugin = plugin;
1017       session->target = *target;
1018       session->last_quota_update = GNUNET_TIME_absolute_get ();
1019       session->quota_in = plugin->env->default_quota_in;
1020       session->expecting_welcome = GNUNET_YES;
1021       session->still_connecting = GNUNET_YES;
1022       session->pending_messages = pm;
1023       session->service_context = service_context;
1024       GNUNET_PEERINFO_for_all (plugin->env->cfg,
1025                                plugin->env->sched,
1026                                target,
1027                                0, timeout, &session_try_connect, session);
1028       return session;
1029     }
1030   GNUNET_assert (session != NULL);
1031   GNUNET_assert (session->still_connecting == GNUNET_NO);
1032   session->service_context = service_context;
1033   /* append pm to pending_messages list */
1034   pme = session->pending_messages;
1035   if (pme == NULL)
1036     {
1037       session->pending_messages = pm;
1038     }
1039   else
1040     {
1041       while (NULL != pme->next)
1042         pme = pme->next;
1043       pme->next = pm;
1044     }
1045 #if DEBUG_TCP
1046   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1047                    "tcp", "Asked to transmit, added message to list.\n");
1048 #endif
1049   process_pending_messages (session);
1050   return session;
1051 }
1052
1053
1054
1055 /**
1056  * Function that can be called to force a disconnect from the
1057  * specified neighbour.  This should also cancel all previously
1058  * scheduled transmissions.  Obviously the transmission may have been
1059  * partially completed already, which is OK.  The plugin is supposed
1060  * to close the connection (if applicable) and no longer call the
1061  * transmit continuation(s).
1062  *
1063  * Finally, plugin MUST NOT call the services's receive function to
1064  * notify the service that the connection to the specified target was
1065  * closed after a getting this call.
1066  *
1067  * @param cls closure
1068  * @param plugin_context value we were asked to pass to this plugin
1069  *        to respond to the given peer (use is optional,
1070  *        but may speed up processing), can be NULL (if
1071  *        NULL was returned from the transmit function)
1072  * @param service_context must correspond to the service context
1073  *        of the corresponding Transmit call; the plugin should
1074  *        not cancel a send call made with a different service
1075  *        context pointer!  Never NULL.
1076  * @param target peer for which the last transmission is
1077  *        to be cancelled
1078  */
1079 static void
1080 tcp_plugin_cancel (void *cls,
1081                    void *plugin_context,
1082                    struct ReadyList *service_context,
1083                    const struct GNUNET_PeerIdentity *target)
1084 {
1085   struct Plugin *plugin = cls;
1086   struct PendingMessage *pm;
1087   struct Session *session;
1088   struct Session *next;
1089   
1090   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1091                    "tcp",
1092                    "Asked to close session with `%4s'\n",
1093                    GNUNET_i2s(target));
1094   session = plugin->sessions;
1095   while (session != NULL)
1096     {
1097       next = session->next;
1098       if (0 == memcmp (target,
1099                        &session->target, sizeof (struct GNUNET_PeerIdentity)))
1100         {
1101           pm = session->pending_messages;
1102           while (pm != NULL)
1103             {
1104               pm->transmit_cont = NULL;
1105               pm->transmit_cont_cls = NULL;
1106               pm = pm->next;
1107             }
1108           session->service_context = NULL;
1109           GNUNET_SERVER_client_disconnect (session->client);
1110           /* rest of the clean-up of the session will be done as part of
1111              disconnect_notify which should be triggered any time now */
1112         }
1113       session = next;
1114     }
1115 }
1116
1117
1118 struct PrettyPrinterContext
1119 {
1120   GNUNET_TRANSPORT_AddressStringCallback asc;
1121   void *asc_cls;
1122   uint16_t port;
1123 };
1124
1125
1126 /**
1127  * Append our port and forward the result.
1128  */
1129 static void
1130 append_port (void *cls, const char *hostname)
1131 {
1132   struct PrettyPrinterContext *ppc = cls;
1133   char *ret;
1134
1135   if (hostname == NULL)
1136     {
1137       ppc->asc (ppc->asc_cls, NULL);
1138       GNUNET_free (ppc);
1139       return;
1140     }
1141   GNUNET_asprintf (&ret, "%s:%d", hostname, ppc->port);
1142   ppc->asc (ppc->asc_cls, ret);
1143   GNUNET_free (ret);
1144 }
1145
1146
1147 /**
1148  * Convert the transports address to a nice, human-readable
1149  * format.
1150  *
1151  * @param cls closure
1152  * @param name name of the transport that generated the address
1153  * @param addr one of the addresses of the host, NULL for the last address
1154  *        the specific address format depends on the transport
1155  * @param addrlen length of the address
1156  * @param numeric should (IP) addresses be displayed in numeric form?
1157  * @param timeout after how long should we give up?
1158  * @param asc function to call on each string
1159  * @param asc_cls closure for asc
1160  */
1161 static void
1162 tcp_plugin_address_pretty_printer (void *cls,
1163                                    const char *type,
1164                                    const void *addr,
1165                                    size_t addrlen,
1166                                    int numeric,
1167                                    struct GNUNET_TIME_Relative timeout,
1168                                    GNUNET_TRANSPORT_AddressStringCallback asc,
1169                                    void *asc_cls)
1170 {
1171   struct Plugin *plugin = cls;
1172   const struct sockaddr_in *v4;
1173   const struct sockaddr_in6 *v6;
1174   struct PrettyPrinterContext *ppc;
1175
1176   if ((addrlen != sizeof (struct sockaddr_in)) &&
1177       (addrlen != sizeof (struct sockaddr_in6)))
1178     {
1179       /* invalid address */
1180       GNUNET_break_op (0);
1181       asc (asc_cls, NULL);
1182       return;
1183     }
1184   ppc = GNUNET_malloc (sizeof (struct PrettyPrinterContext));
1185   ppc->asc = asc;
1186   ppc->asc_cls = asc_cls;
1187   if (addrlen == sizeof (struct sockaddr_in))
1188     {
1189       v4 = (const struct sockaddr_in *) addr;
1190       ppc->port = ntohs (v4->sin_port);
1191     }
1192   else
1193     {
1194       v6 = (const struct sockaddr_in6 *) addr;
1195       ppc->port = ntohs (v6->sin6_port);
1196
1197     }
1198   GNUNET_RESOLVER_hostname_get (plugin->env->sched,
1199                                 plugin->env->cfg,
1200                                 addr,
1201                                 addrlen,
1202                                 !numeric, timeout, &append_port, ppc);
1203 }
1204
1205
1206 /**
1207  * Update the last-received and bandwidth quota values
1208  * for this session.
1209  *
1210  * @param session session to update
1211  * @param force set to GNUNET_YES if we should update even
1212  *        though the minimum refresh time has not yet expired
1213  */
1214 static void
1215 update_quota (struct Session *session, int force)
1216 {
1217   struct GNUNET_TIME_Absolute now;
1218   unsigned long long delta;
1219   unsigned long long total_allowed;
1220   unsigned long long total_remaining;
1221
1222   now = GNUNET_TIME_absolute_get ();
1223   delta = now.value - session->last_quota_update.value;
1224   if ((delta < MIN_QUOTA_REFRESH_TIME) && (!force))
1225     return;                     /* too early, not enough data */
1226
1227   total_allowed = session->quota_in * delta;
1228   if (total_allowed > session->last_received)
1229     {
1230       /* got less than acceptable */
1231       total_remaining = total_allowed - session->last_received;
1232       session->last_received = 0;
1233       delta = total_remaining / session->quota_in;      /* bonus seconds */
1234       if (delta > MAX_BANDWIDTH_CARRY)
1235         delta = MAX_BANDWIDTH_CARRY;    /* limit amount of carry-over */
1236     }
1237   else
1238     {
1239       /* got more than acceptable */
1240       total_remaining = 0;
1241       session->last_received -= total_allowed;
1242       delta = 0;
1243     }
1244   session->last_quota_update.value = now.value - delta;
1245 }
1246
1247
1248 /**
1249  * Set a quota for receiving data from the given peer; this is a
1250  * per-transport limit.  The transport should limit its read/select
1251  * calls to stay below the quota (in terms of incoming data).
1252  *
1253  * @param cls closure
1254  * @param peer the peer for whom the quota is given
1255  * @param quota_in quota for receiving/sending data in bytes per ms
1256  */
1257 static void
1258 tcp_plugin_set_receive_quota (void *cls,
1259                               const struct GNUNET_PeerIdentity *target,
1260                               uint32_t quota_in)
1261 {
1262   struct Plugin *plugin = cls;
1263   struct Session *session;
1264
1265   session = find_session_by_target (plugin, target);
1266   if (session->quota_in != quota_in)
1267     {
1268       update_quota (session, GNUNET_YES);
1269       if (session->quota_in > quota_in)
1270         session->last_quota_update = GNUNET_TIME_absolute_get ();
1271       session->quota_in = quota_in;
1272     }
1273 }
1274
1275
1276 /**
1277  * Check if the given port is plausible (must be either
1278  * our listen port or our advertised port).  If it is
1279  * neither, we return one of these two ports at random.
1280  *
1281  * @return either in_port or a more plausible port
1282  */
1283 static uint16_t
1284 check_port (struct Plugin *plugin, uint16_t in_port)
1285 {
1286   if ((in_port == plugin->adv_port) || (in_port == plugin->open_port))
1287     return in_port;
1288   return (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
1289                                     2) == 0)
1290     ? plugin->open_port : plugin->adv_port;
1291 }
1292
1293
1294 /**
1295  * Another peer has suggested an address for this
1296  * peer and transport plugin.  Check that this could be a valid
1297  * address.  If so, consider adding it to the list
1298  * of addresses.
1299  *
1300  * @param cls closure
1301  * @param addr pointer to the address
1302  * @param addrlen length of addr
1303  * @return GNUNET_OK if this is a plausible address for this peer
1304  *         and transport
1305  */
1306 static int
1307 tcp_plugin_address_suggested (void *cls, const void *addr, size_t addrlen)
1308 {
1309   struct Plugin *plugin = cls;
1310   char buf[sizeof (struct sockaddr_in6)];
1311   struct sockaddr_in *v4;
1312   struct sockaddr_in6 *v6;
1313
1314   if ((addrlen != sizeof (struct sockaddr_in)) &&
1315       (addrlen != sizeof (struct sockaddr_in6)))
1316     {
1317       GNUNET_break_op (0);
1318       return GNUNET_SYSERR;
1319     }
1320   memcpy (buf, addr, sizeof (struct sockaddr_in6));
1321   if (addrlen == sizeof (struct sockaddr_in))
1322     {
1323       v4 = (struct sockaddr_in *) buf;
1324       v4->sin_port = htons (check_port (plugin, ntohs (v4->sin_port)));
1325     }
1326   else
1327     {
1328       v6 = (struct sockaddr_in6 *) buf;
1329       v6->sin6_port = htons (check_port (plugin, ntohs (v6->sin6_port)));
1330     }
1331 #if DEBUG_TCP
1332   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1333                    "tcp",
1334                    "Informing transport service about my address `%s'.\n",
1335                    GNUNET_a2s(addr, addrlen));
1336 #endif
1337   plugin->env->notify_address (plugin->env->cls,
1338                                "tcp",
1339                                buf, addrlen, LEARNED_ADDRESS_EXPIRATION);
1340   return GNUNET_OK;
1341 }
1342
1343
1344 /**
1345  * We've received a welcome from this peer via TCP.
1346  * Possibly create a fresh client record and send back
1347  * our welcome.
1348  *
1349  * @param cls closure
1350  * @param client identification of the client
1351  * @param message the actual message
1352  */
1353 static void
1354 handle_tcp_welcome (void *cls,
1355                     struct GNUNET_SERVER_Client *client,
1356                     const struct GNUNET_MessageHeader *message)
1357 {
1358   struct Plugin *plugin = cls;
1359   struct Session *session_c;
1360   const struct WelcomeMessage *wm;
1361   uint16_t msize;
1362   uint32_t addrlen;
1363   size_t alen;
1364   void *vaddr;
1365   const struct sockaddr *addr;
1366
1367 #if DEBUG_TCP
1368   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1369                    "tcp",
1370                    "Received `%s' message from %p.\n", "WELCOME", client);
1371 #endif
1372   msize = ntohs (message->size);
1373   if (msize < sizeof (struct WelcomeMessage))
1374     {
1375       GNUNET_break_op (0);
1376       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1377       return;
1378     }
1379   wm = (const struct WelcomeMessage *) message;
1380   session_c = find_session_by_client (plugin, client);
1381   if (session_c == NULL)
1382     {
1383       vaddr = NULL;
1384       GNUNET_SERVER_client_get_address (client, &vaddr, &alen);
1385       GNUNET_SERVER_client_keep (client);
1386       session_c = create_session (plugin,
1387                                   &wm->clientIdentity, client, vaddr, alen);
1388 #if DEBUG_TCP
1389       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1390                        "tcp",
1391                        "Creating new session %p for incoming `%s' message.\n",
1392                        session_c, "WELCOME");
1393 #endif
1394       GNUNET_free_non_null (vaddr);
1395       process_pending_messages (session_c);
1396     }
1397   session_c->expecting_welcome = GNUNET_NO;
1398   if (0 < (addrlen = msize - sizeof (struct WelcomeMessage)))
1399     {
1400       addr = (const struct sockaddr *) &wm[1];
1401       tcp_plugin_address_suggested (plugin, addr, addrlen);
1402     }
1403   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1404 }
1405
1406
1407 /**
1408  * Calculate how long we should delay reading from the TCP socket to
1409  * ensure that we stay within our bandwidth limits (push back).
1410  *
1411  * @param session for which client should this be calculated
1412  */
1413 static struct GNUNET_TIME_Relative
1414 calculate_throttle_delay (struct Session *session)
1415 {
1416   struct GNUNET_TIME_Relative ret;
1417   struct GNUNET_TIME_Absolute now;
1418   uint64_t del;
1419   uint64_t avail;
1420   uint64_t excess;
1421
1422   now = GNUNET_TIME_absolute_get ();
1423   del = now.value - session->last_quota_update.value;
1424   if (del > MAX_BANDWIDTH_CARRY)
1425     {
1426       update_quota (session, GNUNET_YES);
1427       del = now.value - session->last_quota_update.value;
1428       GNUNET_assert (del <= MAX_BANDWIDTH_CARRY);
1429     }
1430   if (session->quota_in == 0)
1431     session->quota_in = 1;      /* avoid divison by zero */
1432   avail = del * session->quota_in;
1433   if (avail > session->last_received)
1434     return GNUNET_TIME_UNIT_ZERO;       /* can receive right now */
1435   excess = session->last_received - avail;
1436   ret.value = excess / session->quota_in;
1437   return ret;
1438 }
1439
1440
1441 /**
1442  * Task to signal the server that we can continue
1443  * receiving from the TCP client now.
1444  */
1445 static void
1446 delayed_done (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1447 {
1448   struct Session *session = cls;
1449   GNUNET_SERVER_receive_done (session->client, GNUNET_OK);
1450 }
1451
1452
1453 /**
1454  * We've received data for this peer via TCP.  Unbox,
1455  * compute latency and forward.
1456  *
1457  * @param cls closure
1458  * @param client identification of the client
1459  * @param message the actual message
1460  */
1461 static void
1462 handle_tcp_data (void *cls,
1463                  struct GNUNET_SERVER_Client *client,
1464                  const struct GNUNET_MessageHeader *message)
1465 {
1466   struct Plugin *plugin = cls;
1467   struct Session *session;
1468   const struct DataMessage *dm;
1469   uint16_t msize;
1470   const struct GNUNET_MessageHeader *msg;
1471   struct GNUNET_TIME_Relative latency;
1472   struct GNUNET_TIME_Absolute ttime;
1473   struct GNUNET_TIME_Absolute now;
1474   struct GNUNET_TIME_Relative delay;
1475   uint64_t ack_in;
1476
1477 #if DEBUG_TCP
1478   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1479                    "tcp", "Receiving data from other peer.\n");
1480 #endif
1481   msize = ntohs (message->size);
1482   if ((msize <
1483        sizeof (struct DataMessage) + sizeof (struct GNUNET_MessageHeader)))
1484     {
1485       GNUNET_break_op (0);
1486       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1487       return;
1488     }
1489   session = find_session_by_client (plugin, client);
1490   if ((NULL == session) || (GNUNET_YES == session->expecting_welcome))
1491     {
1492       GNUNET_break_op (0);
1493       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1494       return;
1495     }
1496   dm = (const struct DataMessage *) message;
1497   session->max_in_msg_counter = GNUNET_MAX (session->max_in_msg_counter,
1498                                             GNUNET_ntohll (dm->ack_out));
1499   msg = (const struct GNUNET_MessageHeader *) &dm[1];
1500   if (msize != sizeof (struct DataMessage) + ntohs (msg->size))
1501     {
1502       GNUNET_break_op (0);
1503       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1504       return;
1505     }
1506   /* estimate latency */
1507   ack_in = GNUNET_ntohll (dm->ack_in);
1508   if ((ack_in <= session->out_msg_counter) &&
1509       (session->out_msg_counter - ack_in < ACK_LOG_SIZE))
1510     {
1511       delay = GNUNET_TIME_relative_ntoh (dm->delay);
1512       ttime = session->gen_time[ack_in % ACK_LOG_SIZE];
1513       now = GNUNET_TIME_absolute_get ();
1514       if (delay.value > now.value - ttime.value)
1515         delay.value = 0;        /* not plausible */
1516       /* update (round-trip) latency using ageing; we
1517          use 7:1 so that we can reasonably quickly react
1518          to changes, but not so fast that latency is largely
1519          jitter... */
1520       session->latency_estimate
1521         = ((7 * session->latency_estimate) +
1522            (now.value - ttime.value - delay.value)) / 8;
1523     }
1524   latency.value = (uint64_t) session->latency_estimate;
1525   /* deliver on */
1526 #if DEBUG_TCP
1527   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1528                    "tcp",
1529                    "Forwarding data of type %u to transport service.\n",
1530                    ntohs (msg->type));
1531 #endif
1532   session->service_context
1533     = plugin->env->receive (plugin->env->cls,
1534                             session,
1535                             session->service_context,
1536                             latency, &session->target, msg);
1537   /* update bandwidth used */
1538   session->last_received += msize;
1539   update_quota (session, GNUNET_NO);
1540
1541   delay = calculate_throttle_delay (session);
1542   if (delay.value == 0)
1543     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1544   else
1545     GNUNET_SCHEDULER_add_delayed (session->plugin->env->sched,
1546                                   GNUNET_NO,
1547                                   GNUNET_SCHEDULER_PRIORITY_HIGH,
1548                                   GNUNET_SCHEDULER_NO_PREREQUISITE_TASK,
1549                                   delay, &delayed_done, session);
1550 }
1551
1552
1553 /**
1554  * Handlers for the various TCP messages.
1555  */
1556 static struct GNUNET_SERVER_MessageHandler my_handlers[] = {
1557   {&handle_tcp_welcome, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME, 0},
1558   {&handle_tcp_data, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_DATA, 0},
1559   {NULL, NULL, 0, 0}
1560 };
1561
1562
1563 static void
1564 create_tcp_handlers (struct Plugin *plugin)
1565 {
1566   unsigned int i;
1567   plugin->handlers = GNUNET_malloc (sizeof (my_handlers));
1568   memcpy (plugin->handlers, my_handlers, sizeof (my_handlers));
1569   for (i = 0;
1570        i <
1571        sizeof (my_handlers) / sizeof (struct GNUNET_SERVER_MessageHandler);
1572        i++)
1573     plugin->handlers[i].callback_cls = plugin;
1574   GNUNET_SERVER_add_handlers (plugin->server, plugin->handlers);
1575 }
1576
1577
1578 /**
1579  * Functions with this signature are called whenever a peer
1580  * is disconnected on the network level.
1581  *
1582  * @param cls closure
1583  * @param client identification of the client
1584  */
1585 static void
1586 disconnect_notify (void *cls, struct GNUNET_SERVER_Client *client)
1587 {
1588   struct Plugin *plugin = cls;
1589   struct Session *session;
1590
1591 #if DEBUG_TCP
1592   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1593                    "tcp",
1594                    "Notified about network-level disconnect of client %p.\n",
1595                    client);
1596 #endif
1597   session = find_session_by_client (plugin, client);
1598   if (session == NULL)
1599     return;                     /* unknown, nothing to do */
1600 #if DEBUG_TCP
1601   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1602                    "tcp", "Will now destroy session %p.\n", session);
1603 #endif
1604   disconnect_session (session);
1605 }
1606
1607
1608 /**
1609  * Add the IP of our network interface to the list of
1610  * our external IP addresses.
1611  */
1612 static int
1613 process_interfaces (void *cls,
1614                     const char *name,
1615                     int isDefault,
1616                     const struct sockaddr *addr, socklen_t addrlen)
1617 {
1618   struct Plugin *plugin = cls;
1619   int af;
1620   struct sockaddr_in *v4;
1621   struct sockaddr_in6 *v6;
1622
1623   af = addr->sa_family;
1624   if (af == AF_INET)
1625     {
1626       v4 = (struct sockaddr_in *) addr;
1627       v4->sin_port = htons (plugin->adv_port);
1628     }
1629   else
1630     {
1631       GNUNET_assert (af == AF_INET6);
1632       v6 = (struct sockaddr_in6 *) addr;
1633       v6->sin6_port = htons (plugin->adv_port);
1634     }
1635   GNUNET_log_from (GNUNET_ERROR_TYPE_INFO |
1636                    GNUNET_ERROR_TYPE_BULK,
1637                    "tcp", _("Found address `%s' (%s)\n"), 
1638                    GNUNET_a2s(addr, addrlen), name);
1639   plugin->env->notify_address (plugin->env->cls,
1640                                "tcp",
1641                                addr, addrlen, GNUNET_TIME_UNIT_FOREVER_REL);
1642   return GNUNET_OK;
1643 }
1644
1645
1646 /**
1647  * Function called by the resolver for each address obtained from DNS
1648  * for our own hostname.  Add the addresses to the list of our
1649  * external IP addresses.
1650  *
1651  * @param cls closure
1652  * @param addr one of the addresses of the host, NULL for the last address
1653  * @param addrlen length of the address
1654  */
1655 static void
1656 process_hostname_ips (void *cls,
1657                       const struct sockaddr *addr, socklen_t addrlen)
1658 {
1659   struct Plugin *plugin = cls;
1660
1661   if (addr == NULL)
1662     return;
1663   plugin->env->notify_address (plugin->env->cls,
1664                                "tcp",
1665                                addr, addrlen, GNUNET_TIME_UNIT_FOREVER_REL);
1666 }
1667
1668
1669 /**
1670  * Entry point for the plugin.
1671  */
1672 void *
1673 libgnunet_plugin_transport_tcp_init (void *cls)
1674 {
1675   struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
1676   struct GNUNET_TRANSPORT_PluginFunctions *api;
1677   struct Plugin *plugin;
1678   struct GNUNET_SERVICE_Context *service;
1679   unsigned long long aport;
1680   unsigned long long bport;
1681
1682   service = GNUNET_SERVICE_start ("tcp", env->sched, env->cfg);
1683   if (service == NULL)
1684     {
1685       GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
1686                        "tcp",
1687                        _
1688                        ("Failed to start service for `%s' transport plugin.\n"),
1689                        "tcp");
1690       return NULL;
1691     }
1692   aport = 0;
1693   if ((GNUNET_OK !=
1694        GNUNET_CONFIGURATION_get_value_number (env->cfg,
1695                                               "tcp",
1696                                               "PORT",
1697                                               &bport)) ||
1698       (bport > 65535) ||
1699       ((GNUNET_OK ==
1700         GNUNET_CONFIGURATION_get_value_number (env->cfg,
1701                                                "tcp",
1702                                                "ADVERTISED-PORT",
1703                                                &aport)) && (aport > 65535)))
1704     {
1705       GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
1706                        "tcp",
1707                        _
1708                        ("Require valid port number for service `%s' in configuration!\n"),
1709                        "tcp");
1710       GNUNET_SERVICE_stop (service);
1711       return NULL;
1712     }
1713   if (aport == 0)
1714     aport = bport;
1715   plugin = GNUNET_malloc (sizeof (struct Plugin));
1716   plugin->open_port = bport;
1717   plugin->adv_port = aport;
1718   plugin->env = env;
1719   plugin->lsock = NULL;
1720   plugin->statistics = NULL;
1721   api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
1722   api->cls = plugin;
1723   api->send_to = &tcp_plugin_send_to;
1724   api->send = &tcp_plugin_send;
1725   api->cancel = &tcp_plugin_cancel;
1726   api->address_pretty_printer = &tcp_plugin_address_pretty_printer;
1727   api->set_receive_quota = &tcp_plugin_set_receive_quota;
1728   api->address_suggested = &tcp_plugin_address_suggested;
1729   api->cost_estimate = 42;      /* TODO: ATS */
1730   plugin->service = service;
1731   plugin->server = GNUNET_SERVICE_get_server (service);
1732   create_tcp_handlers (plugin);
1733   GNUNET_log_from (GNUNET_ERROR_TYPE_INFO,
1734                    "tcp", _("TCP transport listening on port %u\n"), bport);
1735   if (aport != bport)
1736     GNUNET_log_from (GNUNET_ERROR_TYPE_INFO,
1737                      "tcp",
1738                      _
1739                      ("TCP transport advertises itself as being on port %u\n"),
1740                      aport);
1741   GNUNET_SERVER_disconnect_notify (plugin->server, &disconnect_notify,
1742                                    plugin);
1743   GNUNET_OS_network_interfaces_list (&process_interfaces, plugin);
1744   GNUNET_RESOLVER_hostname_resolve (env->sched,
1745                                     env->cfg,
1746                                     AF_UNSPEC,
1747                                     HOSTNAME_RESOLVE_TIMEOUT,
1748                                     &process_hostname_ips, plugin);
1749   return api;
1750 }
1751
1752
1753 /**
1754  * Exit point from the plugin.
1755  */
1756 void *
1757 libgnunet_plugin_transport_tcp_done (void *cls)
1758 {
1759   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
1760   struct Plugin *plugin = api->cls;
1761
1762   GNUNET_SERVICE_stop (plugin->service);
1763   GNUNET_free (plugin->handlers);
1764   GNUNET_free (plugin);
1765   GNUNET_free (api);
1766   return NULL;
1767 }
1768
1769 /* end of plugin_transport_tcp.c */