fixed
[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, 2010 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_connection_lib.h"
30 #include "gnunet_os_lib.h"
31 #include "gnunet_protocols.h"
32 #include "gnunet_resolver_service.h"
33 #include "gnunet_server_lib.h"
34 #include "gnunet_service_lib.h"
35 #include "gnunet_signatures.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  * How long until we give up on transmitting the welcome message?
45  */
46 #define WELCOME_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
47
48 /**
49  * How long until we give up on transmitting the welcome message?
50  */
51 #define HOSTNAME_RESOLVE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
52
53
54 /**
55  * Initial handshake message for a session.
56  */
57 struct WelcomeMessage
58 {
59   /**
60    * Type is GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME.
61    */
62   struct GNUNET_MessageHeader header;
63
64   /**
65    * Identity of the node connecting (TCP client)
66    */
67   struct GNUNET_PeerIdentity clientIdentity;
68
69 };
70
71
72 /**
73  * Encapsulation of all of the state of the plugin.
74  */
75 struct Plugin;
76
77
78 /**
79  * Information kept for each message that is yet to
80  * be transmitted.
81  */
82 struct PendingMessage
83 {
84
85   /**
86    * This is a linked list.
87    */
88   struct PendingMessage *next;
89
90   /**
91    * The pending message
92    */
93   char *msg;
94
95   /*
96    * So that the gnunet_transport_service can group messages together,
97    * these pending messages need to accept a message buffer and size
98    * instead of just a GNUNET_MessageHeader.
99    */
100   size_t message_size;
101
102   /**
103    * Continuation function to call once the message
104    * has been sent.  Can be NULL if there is no
105    * continuation to call.
106    */
107   GNUNET_TRANSPORT_TransmitContinuation transmit_cont;
108
109   /**
110    * Closure for transmit_cont.
111    */
112   void *transmit_cont_cls;
113
114   /**
115    * Timeout value for the pending message.
116    */
117   struct GNUNET_TIME_Absolute timeout;
118
119 };
120
121
122 /**
123  * Session handle for TCP connections.
124  */
125 struct Session
126 {
127
128   /**
129    * Stored in a linked list.
130    */
131   struct Session *next;
132
133   /**
134    * Pointer to the global plugin struct.
135    */
136   struct Plugin *plugin;
137
138   /**
139    * The client (used to identify this connection)
140    */
141   struct GNUNET_SERVER_Client *client;
142
143   /**
144    * Messages currently pending for transmission
145    * to this peer, if any.
146    */
147   struct PendingMessage *pending_messages;
148
149   /**
150    * Handle for pending transmission request.
151    */
152   struct GNUNET_CONNECTION_TransmitHandle *transmit_handle;
153
154   /**
155    * To whom are we talking to (set to our identity
156    * if we are still waiting for the welcome message)
157    */
158   struct GNUNET_PeerIdentity target;
159
160   /**
161    * At what time did we reset last_received last?
162    */
163   struct GNUNET_TIME_Absolute last_quota_update;
164
165   /**
166    * Address of the other peer (either based on our 'connect'
167    * call or on our 'accept' call).
168    */
169   void *connect_addr;
170
171   /**
172    * How many bytes have we received since the "last_quota_update"
173    * timestamp?
174    */
175   uint64_t last_received;
176
177   /**
178    * Number of bytes per ms that this peer is allowed
179    * to send to us.
180    */
181   uint32_t quota_in;
182
183   /**
184    * Length of connect_addr.
185    */
186   size_t connect_alen;
187
188   /**
189    * Are we still expecting the welcome message? (GNUNET_YES/GNUNET_NO)
190    * GNUNET_SYSERR is used to mark non-welcoming connections (HELLO
191    * validation only).
192    */
193   int expecting_welcome;
194
195 };
196
197
198 /**
199  * Encapsulation of all of the state of the plugin.
200  */
201 struct Plugin
202 {
203   /**
204    * Our environment.
205    */
206   struct GNUNET_TRANSPORT_PluginEnvironment *env;
207
208   /**
209    * The listen socket.
210    */
211   struct GNUNET_CONNECTION_Handle *lsock;
212
213   /**
214    * List of open TCP sessions.
215    */
216   struct Session *sessions;
217
218   /**
219    * Handle for the statistics service.
220    */
221   struct GNUNET_STATISTICS_Handle *statistics;
222
223   /**
224    * Handle to the network service.
225    */
226   struct GNUNET_SERVICE_Context *service;
227
228   /**
229    * Handle to the server for this service.
230    */
231   struct GNUNET_SERVER_Handle *server;
232
233   /**
234    * Copy of the handler array where the closures are
235    * set to this struct's instance.
236    */
237   struct GNUNET_SERVER_MessageHandler *handlers;
238
239   /**
240    * Handle for request of hostname resolution, non-NULL if pending.
241    */
242   struct GNUNET_RESOLVER_RequestHandle *hostname_dns;
243
244   /**
245    * ID of task used to update our addresses when one expires.
246    */
247   GNUNET_SCHEDULER_TaskIdentifier address_update_task;
248
249   /**
250    * Port that we are actually listening on.
251    */
252   uint16_t open_port;
253
254   /**
255    * Port that the user said we would have visible to the
256    * rest of the world.
257    */
258   uint16_t adv_port;
259
260 };
261
262
263 /**
264  * Find the session handle for the given peer.
265  */
266 static struct Session *
267 find_session_by_target (struct Plugin *plugin,
268                         const struct GNUNET_PeerIdentity *target)
269 {
270   struct Session *ret;
271
272   ret = plugin->sessions;
273   while ( (ret != NULL) &&
274           ((GNUNET_SYSERR == ret->expecting_welcome) ||
275            (0 != memcmp (target,
276                          &ret->target, sizeof (struct GNUNET_PeerIdentity)))))
277     ret = ret->next;
278   return ret;
279 }
280
281
282 /**
283  * Find the session handle for the given peer.
284  */
285 static struct Session *
286 find_session_by_client (struct Plugin *plugin,
287                         const struct GNUNET_SERVER_Client *client)
288 {
289   struct Session *ret;
290
291   ret = plugin->sessions;
292   while ((ret != NULL) && (client != ret->client))
293     ret = ret->next;
294   return ret;
295 }
296
297
298 /**
299  * Create a welcome message.
300  */
301 static struct PendingMessage *
302 create_welcome (struct Plugin *plugin)
303 {
304   struct PendingMessage *pm;
305   struct WelcomeMessage *welcome;
306
307   pm = GNUNET_malloc (sizeof (struct PendingMessage));
308   pm->msg = GNUNET_malloc(sizeof(struct WelcomeMessage));
309   welcome = (struct WelcomeMessage *)pm->msg;
310   pm->message_size = sizeof (struct WelcomeMessage);
311   welcome->header.size = htons (sizeof (struct WelcomeMessage));
312   welcome->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME);
313   welcome->clientIdentity = *plugin->env->my_identity;
314   pm->timeout = GNUNET_TIME_relative_to_absolute (WELCOME_TIMEOUT);
315   return pm;
316 }
317
318
319 /**
320  * Create a new session.
321  *
322  * @param plugin us
323  * @param target peer to connect to
324  * @param client client to use
325  * @return new session object
326  */
327 static struct Session *
328 create_session (struct Plugin *plugin,
329                 const struct GNUNET_PeerIdentity *target,
330                 struct GNUNET_SERVER_Client *client)
331 {
332   struct Session *ret;
333
334   ret = GNUNET_malloc (sizeof (struct Session));
335   ret->plugin = plugin;
336   ret->next = plugin->sessions;
337   plugin->sessions = ret;
338   ret->client = client;
339   ret->target = *target;
340   ret->last_quota_update = GNUNET_TIME_absolute_get ();
341   ret->quota_in = plugin->env->default_quota_in;
342   ret->expecting_welcome = GNUNET_YES;
343   ret->pending_messages = create_welcome (plugin);
344   return ret;
345 }
346
347
348 /**
349  * If we have pending messages, ask the server to
350  * transmit them (schedule the respective tasks, etc.)
351  *
352  * @param session for which session should we do this
353  */
354 static void process_pending_messages (struct Session *session);
355
356
357 /**
358  * Function called to notify a client about the socket
359  * being ready to queue more data.  "buf" will be
360  * NULL and "size" zero if the socket was closed for
361  * writing in the meantime.
362  *
363  * @param cls closure
364  * @param size number of bytes available in buf
365  * @param buf where the callee should write the message
366  * @return number of bytes written to buf
367  */
368 static size_t
369 do_transmit (void *cls, size_t size, void *buf)
370 {
371   struct Session *session = cls;
372   struct PendingMessage *pm;
373   char *cbuf;
374
375   size_t ret;
376
377   session->transmit_handle = NULL;
378   if (buf == NULL)
379     {
380 #if DEBUG_TCP
381       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
382                        "tcp",
383                        "Timeout trying to transmit to peer `%4s', discarding message queue.\n",
384                        GNUNET_i2s (&session->target));
385 #endif
386       /* timeout */
387       while (NULL != (pm = session->pending_messages))
388         {
389           session->pending_messages = pm->next;
390 #if DEBUG_TCP
391           GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
392                            "tcp",
393                            "Failed to transmit message of to `%4s'.\n",
394                            GNUNET_i2s (&session->target));
395 #endif
396           if (pm->transmit_cont != NULL)
397             pm->transmit_cont (pm->transmit_cont_cls,
398                                &session->target, GNUNET_SYSERR);
399           GNUNET_free (pm);
400         }
401       return 0;
402     }
403   ret = 0;
404   cbuf = buf;
405   while (NULL != (pm = session->pending_messages))
406     {
407       if (size < pm->message_size)
408         break;
409       memcpy (cbuf, pm->msg, pm->message_size);
410       cbuf += pm->message_size;
411       ret += pm->message_size;
412       size -= pm->message_size;
413       session->pending_messages = pm->next;
414       if (pm->transmit_cont != NULL)
415         pm->transmit_cont (pm->transmit_cont_cls,
416                            &session->target, GNUNET_OK);
417       GNUNET_free (pm);
418     }
419   process_pending_messages (session);
420 #if DEBUG_TCP
421   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
422                    "tcp", "Transmitting %u bytes\n", ret);
423 #endif
424   return ret;
425 }
426
427
428 /**
429  * If we have pending messages, ask the server to
430  * transmit them (schedule the respective tasks, etc.)
431  *
432  * @param session for which session should we do this
433  */
434 static void
435 process_pending_messages (struct Session *session)
436 {
437   struct PendingMessage *pm;
438   GNUNET_assert (session->client != NULL);
439   if (session->transmit_handle != NULL)
440     return;
441   if (NULL == (pm = session->pending_messages))
442     return;
443   session->transmit_handle
444     = GNUNET_SERVER_notify_transmit_ready (session->client,
445                                            pm->message_size,
446                                            GNUNET_TIME_absolute_get_remaining
447                                            (pm->timeout),
448                                            &do_transmit, session);
449 }
450
451
452 /**
453  * Functions with this signature are called whenever we need
454  * to close a session due to a disconnect or failure to
455  * establish a connection.
456  *
457  * @param session session to close down
458  */
459 static void
460 disconnect_session (struct Session *session)
461 {
462   struct Session *prev;
463   struct Session *pos;
464   struct PendingMessage *pm;
465
466 #if DEBUG_TCP
467   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
468                    "tcp",
469                    "Disconnecting from `%4s' at %s (session %p).\n",
470                    GNUNET_i2s (&session->target),
471                    (session->connect_addr != NULL) ?
472                    GNUNET_a2s (session->connect_addr,
473                                session->connect_alen) : "*", session);
474 #endif
475   /* remove from session list */
476   prev = NULL;
477   pos = session->plugin->sessions;
478   while (pos != session)
479     {
480       prev = pos;
481       pos = pos->next;
482     }
483   if (prev == NULL)
484     session->plugin->sessions = session->next;
485   else
486     prev->next = session->next;
487   /* clean up state */
488   if (session->transmit_handle != NULL)
489     {
490       GNUNET_CONNECTION_notify_transmit_ready_cancel
491         (session->transmit_handle);
492       session->transmit_handle = NULL;
493     }
494   while (NULL != (pm = session->pending_messages))
495     {
496 #if DEBUG_TCP
497       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
498                        "tcp",
499                        pm->transmit_cont != NULL
500                        ? "Could not deliver message to `%4s'.\n"
501                        :
502                        "Could not deliver message to `%4s', notifying.\n",
503                        GNUNET_i2s (&session->target));
504 #endif
505       session->pending_messages = pm->next;
506       if (NULL != pm->transmit_cont)
507         pm->transmit_cont (pm->transmit_cont_cls,
508                            &session->target, GNUNET_SYSERR);
509       GNUNET_free(pm->msg);
510       GNUNET_free (pm);
511     }
512   if (GNUNET_NO == session->expecting_welcome)
513     {
514 #if DEBUG_TCP
515       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
516                        "tcp",
517                        "Notifying transport service about loss of data connection with `%4s'.\n",
518                        GNUNET_i2s (&session->target));
519 #endif
520       /* Data session that actually went past the
521          initial handshake; transport service may
522          know about this one, so we need to
523          notify transport service about disconnect */
524       session->plugin->env->receive (session->plugin->env->cls,
525                                      &session->target, NULL,
526                                      1,
527                                      session->connect_addr,
528                                      session->connect_alen);
529     }
530   if (session->client != NULL)
531     {
532       GNUNET_SERVER_client_drop (session->client);
533       session->client = NULL;
534     }
535   GNUNET_free_non_null (session->connect_addr);
536   GNUNET_free (session);
537 }
538
539
540 /**
541  * Function that can be used by the transport service to transmit
542  * a message using the plugin.   Note that in the case of a
543  * peer disconnecting, the continuation MUST be called
544  * prior to the disconnect notification itself.  This function
545  * will be called with this peer's HELLO message to initiate
546  * a fresh connection to another peer.
547  *
548  * @param cls closure
549  * @param target who should receive this message
550  * @param msg the message to transmit
551  * @param priority how important is the message (most plugins will
552  *                 ignore message priority and just FIFO)
553  * @param timeout how long to wait at most for the transmission (does not
554  *                require plugins to discard the message after the timeout,
555  *                just advisory for the desired delay; most plugins will ignore
556  *                this as well)
557  * @param addr the address to use (can be NULL if the plugin
558  *                is "on its own" (i.e. re-use existing TCP connection))
559  * @param addrlen length of the address in bytes
560  * @param force_address GNUNET_YES if the plugin MUST use the given address,
561  *                otherwise the plugin may use other addresses or
562  *                existing connections (if available)
563  * @param cont continuation to call once the message has
564  *        been transmitted (or if the transport is ready
565  *        for the next transmission call; or if the
566  *        peer disconnected...); can be NULL
567  * @param cont_cls closure for cont
568  * @return number of bytes used (on the physical network, with overheads);
569  *         -1 on hard errors (i.e. address invalid); 0 is a legal value
570  *         and does NOT mean that the message was not transmitted (DV)
571  */
572 static ssize_t
573 tcp_plugin_send (void *cls,
574                  const struct GNUNET_PeerIdentity *target,
575                  char *msg,
576                  size_t msgbuf_size,
577                  uint32_t priority,
578                  struct GNUNET_TIME_Relative timeout,
579                  const void *addr,
580                  size_t addrlen,
581                  int force_address,
582                  GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls)
583 {
584   struct Plugin *plugin = cls;
585   struct Session *session;
586   struct PendingMessage *pm;
587   struct PendingMessage *pme;
588   struct GNUNET_CONNECTION_Handle *sa;
589   int af;
590
591   session = find_session_by_target (plugin, target);
592   if ( (session != NULL) && ((GNUNET_YES == force_address) &&
593        ( (session->connect_alen != addrlen) ||
594          (0 != memcmp (session->connect_addr,
595                        addr,
596                        addrlen)) )) )
597     session = NULL; /* ignore existing session */
598
599   if ( (session == NULL) &&
600        (addr == NULL) )
601     {
602 #if DEBUG_TCP
603       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
604                        "tcp",
605                        "Asked to transmit to `%4s' without address and I have no existing connection (failing).\n",
606                        GNUNET_i2s (target));
607 #endif
608       return -1;
609     }
610   if (session == NULL)
611     {
612       if (sizeof (struct sockaddr_in) == addrlen)
613         af = AF_INET;
614       else if (sizeof (struct sockaddr_in6) == addrlen)
615         af = AF_INET6;
616       else
617         {
618           GNUNET_break_op (0);
619           return -1;
620         }
621       sa = GNUNET_CONNECTION_create_from_sockaddr (plugin->env->sched,
622                                                    af, addr, addrlen,
623                                                    GNUNET_SERVER_MAX_MESSAGE_SIZE);
624       if (sa == NULL)
625         {
626 #if DEBUG_TCP
627           GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
628                            "tcp",
629                            "Failed to create connection to `%4s' at `%s'\n",
630                            GNUNET_i2s (target),
631                            GNUNET_a2s (addr, addrlen));
632 #endif
633           return -1;
634         }
635
636 #if DEBUG_TCP
637       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
638                        "tcp",
639                        "Asked to transmit to `%4s', creating fresh session.\n",
640                        GNUNET_i2s (target));
641 #endif
642       session = create_session (plugin,
643                                 target,
644                                 GNUNET_SERVER_connect_socket (plugin->server,
645                                                               sa));
646       session->connect_addr = GNUNET_malloc (addrlen);
647       memcpy (session->connect_addr,
648               addr,
649               addrlen);
650       session->connect_alen = addrlen;
651     }
652   GNUNET_assert (session != NULL);
653   GNUNET_assert (session->client != NULL);
654
655 #if DEBUG_TCP
656       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
657                        "tcp",
658                        "Creating pending message of size %d\n",
659                        msgbuf_size);
660 #endif
661   /* create new message entry */
662   pm = GNUNET_malloc (sizeof (struct PendingMessage));
663   pm->msg = GNUNET_malloc(msgbuf_size);
664   memcpy (pm->msg, msg, msgbuf_size);
665   pm->message_size = msgbuf_size;
666   pm->timeout = GNUNET_TIME_relative_to_absolute (timeout);
667   pm->transmit_cont = cont;
668   pm->transmit_cont_cls = cont_cls;
669
670   /* append pm to pending_messages list */
671   pme = session->pending_messages;
672   if (pme == NULL)
673     {
674       session->pending_messages = pm;
675     }
676   else
677     {
678       /* FIXME: this could be done faster by keeping
679          track of the tail of the list... */
680       while (NULL != pme->next)
681         pme = pme->next;
682       pme->next = pm;
683     }
684 #if DEBUG_TCP
685   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
686                    "tcp",
687                    "Asked to transmit %u bytes to `%s', added message to list.\n",
688                    msgbuf_size,
689                    GNUNET_i2s (target));
690 #endif
691   process_pending_messages (session);
692   return msgbuf_size;
693 }
694
695
696 /**
697  * Function that can be called to force a disconnect from the
698  * specified neighbour.  This should also cancel all previously
699  * scheduled transmissions.  Obviously the transmission may have been
700  * partially completed already, which is OK.  The plugin is supposed
701  * to close the connection (if applicable) and no longer call the
702  * transmit continuation(s).
703  *
704  * Finally, plugin MUST NOT call the services's receive function to
705  * notify the service that the connection to the specified target was
706  * closed after a getting this call.
707  *
708  * @param cls closure
709  * @param target peer for which the last transmission is
710  *        to be cancelled
711  */
712 static void
713 tcp_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *target)
714 {
715   struct Plugin *plugin = cls;
716   struct Session *session;
717   struct PendingMessage *pm;
718
719 #if DEBUG_TCP
720   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
721                    "tcp",
722                    "Asked to cancel session with `%4s'\n",
723                    GNUNET_i2s (target));
724 #endif
725   while (NULL != (session = find_session_by_target (plugin, target)))
726     {
727       pm = session->pending_messages;
728       while (pm != NULL)
729         {
730           pm->transmit_cont = NULL;
731           pm->transmit_cont_cls = NULL;
732           pm = pm->next;
733         }
734       if (session->client != NULL)
735         {
736           GNUNET_SERVER_client_drop (session->client);
737           session->client = NULL;
738         }
739       /* rest of the clean-up of the session will be done as part of
740          disconnect_notify which should be triggered any time now
741          (or which may be triggering this call in the first place) */
742     }
743 }
744
745
746 struct PrettyPrinterContext
747 {
748   GNUNET_TRANSPORT_AddressStringCallback asc;
749   void *asc_cls;
750   uint16_t port;
751 };
752
753
754 /**
755  * Append our port and forward the result.
756  */
757 static void
758 append_port (void *cls, const char *hostname)
759 {
760   struct PrettyPrinterContext *ppc = cls;
761   char *ret;
762
763   if (hostname == NULL)
764     {
765       ppc->asc (ppc->asc_cls, NULL);
766       GNUNET_free (ppc);
767       return;
768     }
769   GNUNET_asprintf (&ret, "%s:%d", hostname, ppc->port);
770   ppc->asc (ppc->asc_cls, ret);
771   GNUNET_free (ret);
772 }
773
774
775 /**
776  * Convert the transports address to a nice, human-readable
777  * format.
778  *
779  * @param cls closure
780  * @param type name of the transport that generated the address
781  * @param addr one of the addresses of the host, NULL for the last address
782  *        the specific address format depends on the transport
783  * @param addrlen length of the address
784  * @param numeric should (IP) addresses be displayed in numeric form?
785  * @param timeout after how long should we give up?
786  * @param asc function to call on each string
787  * @param asc_cls closure for asc
788  */
789 static void
790 tcp_plugin_address_pretty_printer (void *cls,
791                                    const char *type,
792                                    const void *addr,
793                                    size_t addrlen,
794                                    int numeric,
795                                    struct GNUNET_TIME_Relative timeout,
796                                    GNUNET_TRANSPORT_AddressStringCallback asc,
797                                    void *asc_cls)
798 {
799   struct Plugin *plugin = cls;
800   const struct sockaddr_in *v4;
801   const struct sockaddr_in6 *v6;
802   struct PrettyPrinterContext *ppc;
803
804   if ((addrlen != sizeof (struct sockaddr_in)) &&
805       (addrlen != sizeof (struct sockaddr_in6)))
806     {
807       /* invalid address */
808       GNUNET_break_op (0);
809       asc (asc_cls, NULL);
810       return;
811     }
812   ppc = GNUNET_malloc (sizeof (struct PrettyPrinterContext));
813   ppc->asc = asc;
814   ppc->asc_cls = asc_cls;
815   if (addrlen == sizeof (struct sockaddr_in))
816     {
817       v4 = (const struct sockaddr_in *) addr;
818       ppc->port = ntohs (v4->sin_port);
819     }
820   else
821     {
822       v6 = (const struct sockaddr_in6 *) addr;
823       ppc->port = ntohs (v6->sin6_port);
824
825     }
826   GNUNET_RESOLVER_hostname_get (plugin->env->sched,
827                                 plugin->env->cfg,
828                                 addr,
829                                 addrlen,
830                                 !numeric, timeout, &append_port, ppc);
831 }
832
833
834 /**
835  * Update the last-received and bandwidth quota values
836  * for this session.
837  *
838  * @param session session to update
839  * @param force set to GNUNET_YES if we should update even
840  *        though the minimum refresh time has not yet expired
841  */
842 static void
843 update_quota (struct Session *session, int force)
844 {
845   struct GNUNET_TIME_Absolute now;
846   unsigned long long delta;
847   unsigned long long total_allowed;
848   unsigned long long total_remaining;
849
850   now = GNUNET_TIME_absolute_get ();
851   delta = now.value - session->last_quota_update.value;
852   if ((delta < MIN_QUOTA_REFRESH_TIME) && (!force))
853     return;                     /* too early, not enough data */
854
855   total_allowed = session->quota_in * delta;
856   if (total_allowed > session->last_received)
857     {
858       /* got less than acceptable */
859       total_remaining = total_allowed - session->last_received;
860       session->last_received = 0;
861       delta = total_remaining / session->quota_in;      /* bonus seconds */
862       if (delta > MAX_BANDWIDTH_CARRY)
863         delta = MAX_BANDWIDTH_CARRY;    /* limit amount of carry-over */
864     }
865   else
866     {
867       /* got more than acceptable */
868       session->last_received -= total_allowed;
869       delta = 0;
870     }
871   session->last_quota_update.value = now.value - delta;
872 }
873
874
875 /**
876  * Set a quota for receiving data from the given peer; this is a
877  * per-transport limit.  The transport should limit its read/select
878  * calls to stay below the quota (in terms of incoming data).
879  *
880  * @param cls closure
881  * @param target the peer for whom the quota is given
882  * @param quota_in quota for receiving/sending data in bytes per ms
883  */
884 static void
885 tcp_plugin_set_receive_quota (void *cls,
886                               const struct GNUNET_PeerIdentity *target,
887                               uint32_t quota_in)
888 {
889   struct Plugin *plugin = cls;
890   struct Session *session;
891
892   session = find_session_by_target (plugin, target);
893   if (session == NULL)
894     return;                     /* peer must have disconnected, ignore */
895   if (session->quota_in != quota_in)
896     {
897       update_quota (session, GNUNET_YES);
898       if (session->quota_in > quota_in)
899         session->last_quota_update = GNUNET_TIME_absolute_get ();
900       session->quota_in = quota_in;
901     }
902 }
903
904
905 /**
906  * Check if the given port is plausible (must be either
907  * our listen port or our advertised port).  If it is
908  * neither, we return one of these two ports at random.
909  *
910  * @return either in_port or a more plausible port
911  */
912 static uint16_t
913 check_port (struct Plugin *plugin, uint16_t in_port)
914 {
915   if ((in_port == plugin->adv_port) || (in_port == plugin->open_port))
916     return in_port;
917   return (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
918                                     2) == 0)
919     ? plugin->open_port : plugin->adv_port;
920 }
921
922
923 /**
924  * Another peer has suggested an address for this peer and transport
925  * plugin.  Check that this could be a valid address.
926  *
927  * @param cls closure
928  * @param addr pointer to the address
929  * @param addrlen length of addr
930  * @return GNUNET_OK if this is a plausible address for this peer
931  *         and transport
932  */
933 static int
934 tcp_plugin_check_address (void *cls, void *addr, size_t addrlen)
935 {
936   struct Plugin *plugin = cls;
937   char buf[sizeof (struct sockaddr_in6)];
938   struct sockaddr_in *v4;
939   struct sockaddr_in6 *v6;
940
941   if ((addrlen != sizeof (struct sockaddr_in)) &&
942       (addrlen != sizeof (struct sockaddr_in6)))
943     {
944       GNUNET_break_op (0);
945       return GNUNET_SYSERR;
946     }
947   memcpy (buf, addr, sizeof (struct sockaddr_in6));
948   if (addrlen == sizeof (struct sockaddr_in))
949     {
950       v4 = (struct sockaddr_in *) buf;
951       v4->sin_port = htons (check_port (plugin, ntohs (v4->sin_port)));
952     }
953   else
954     {
955       v6 = (struct sockaddr_in6 *) buf;
956       v6->sin6_port = htons (check_port (plugin, ntohs (v6->sin6_port)));
957     }
958 #if DEBUG_TCP
959   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
960                    "tcp",
961                    "Informing transport service about my address `%s'.\n",
962                    GNUNET_a2s (addr, addrlen));
963 #endif
964   return GNUNET_OK;
965 }
966
967
968 /**
969  * We've received a welcome from this peer via TCP.  Possibly create a
970  * fresh client record and send back our welcome.
971  *
972  * @param cls closure
973  * @param client identification of the client
974  * @param message the actual message
975  */
976 static void
977 handle_tcp_welcome (void *cls,
978                     struct GNUNET_SERVER_Client *client,
979                     const struct GNUNET_MessageHeader *message)
980 {
981   struct Plugin *plugin = cls;
982   const struct WelcomeMessage *wm = (const struct WelcomeMessage *) message;
983   struct Session *session;
984   size_t alen;
985   void *vaddr;
986
987 #if DEBUG_TCP
988   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
989                    "tcp",
990                    "Received `%s' message from a `%4s/%p'.\n", "WELCOME",
991                    GNUNET_i2s (&wm->clientIdentity), client);
992 #endif
993
994   session = find_session_by_client (plugin, client);
995   if (session == NULL)
996     {
997       GNUNET_SERVER_client_keep (client);
998       session = create_session (plugin,
999                                 &wm->clientIdentity, client);
1000       if (GNUNET_OK ==
1001           GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
1002         {
1003 #if DEBUG_TCP
1004       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1005                        "tcp",
1006                        "Found address for incoming `%s' message\n",
1007                        "WELCOME");
1008 #endif
1009           session->connect_addr = vaddr;
1010           session->connect_alen = alen;
1011         }
1012       else
1013         {
1014 #if DEBUG_TCP
1015       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1016                        "tcp",
1017                        "Didn't find address for incoming `%s' message\n",
1018                        "WELCOME");
1019 #endif
1020         }
1021 #if DEBUG_TCP
1022       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1023                        "tcp",
1024                        "Creating new session %p for incoming `%s' message.\n",
1025                        session, "WELCOME");
1026 #endif
1027       process_pending_messages (session);
1028     }
1029   if (session->expecting_welcome != GNUNET_YES)
1030     {
1031       GNUNET_break_op (0);
1032       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1033       return;
1034     }
1035   session->expecting_welcome = GNUNET_NO;
1036   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1037 }
1038
1039
1040 /**
1041  * Calculate how long we should delay reading from the TCP socket to
1042  * ensure that we stay within our bandwidth limits (push back).
1043  *
1044  * @param session for which client should this be calculated
1045  */
1046 static struct GNUNET_TIME_Relative
1047 calculate_throttle_delay (struct Session *session)
1048 {
1049   struct GNUNET_TIME_Relative ret;
1050   struct GNUNET_TIME_Absolute now;
1051   uint64_t del;
1052   uint64_t avail;
1053   uint64_t excess;
1054
1055   now = GNUNET_TIME_absolute_get ();
1056   del = now.value - session->last_quota_update.value;
1057   if (del > MAX_BANDWIDTH_CARRY)
1058     {
1059       update_quota (session, GNUNET_YES);
1060       del = now.value - session->last_quota_update.value;
1061       GNUNET_assert (del <= MAX_BANDWIDTH_CARRY);
1062     }
1063   if (session->quota_in == 0)
1064     session->quota_in = 1;      /* avoid divison by zero */
1065   avail = del * session->quota_in;
1066   if (avail > session->last_received)
1067     return GNUNET_TIME_UNIT_ZERO;       /* can receive right now */
1068   excess = session->last_received - avail;
1069   ret.value = excess / session->quota_in;
1070   return ret;
1071 }
1072
1073
1074 /**
1075  * Task to signal the server that we can continue
1076  * receiving from the TCP client now.
1077  */
1078 static void
1079 delayed_done (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1080 {
1081   struct Session *session = cls;
1082   GNUNET_SERVER_receive_done (session->client, GNUNET_OK);
1083 }
1084
1085
1086 /**
1087  * We've received data for this peer via TCP.  Unbox,
1088  * compute latency and forward.
1089  *
1090  * @param cls closure
1091  * @param client identification of the client
1092  * @param message the actual message
1093  */
1094 static void
1095 handle_tcp_data (void *cls,
1096                  struct GNUNET_SERVER_Client *client,
1097                  const struct GNUNET_MessageHeader *message)
1098 {
1099   struct Plugin *plugin = cls;
1100   struct Session *session;
1101   uint16_t msize;
1102   struct GNUNET_TIME_Relative delay;
1103
1104   msize = ntohs (message->size);
1105   session = find_session_by_client (plugin, client);
1106
1107   if (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME == ntohs(message->type))
1108   {
1109 #if DEBUG_TCP
1110   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1111                    "tcp", "Received a welcome, NOT sending to clients!\n");
1112 #endif
1113     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1114     return; /* We don't want to propagate WELCOME messages up! */
1115   }
1116   else
1117     {
1118 #if DEBUG_TCP
1119   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1120                    "tcp", "Received DATA message, checking session!\n");
1121 #endif
1122     }
1123
1124   if ( (NULL == session) || (GNUNET_NO != session->expecting_welcome))
1125     {
1126       GNUNET_break_op (0);
1127       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1128       return;
1129     }
1130 #if DEBUG_TCP
1131   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1132                    "tcp", "Receiving %u bytes from `%4s'.\n",
1133                    msize, GNUNET_i2s (&session->target));
1134 #endif
1135 #if DEBUG_TCP
1136   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1137                    "tcp",
1138                    "Forwarding %u bytes of data of type %u to transport service.\n",
1139                    (unsigned int) msize,
1140                    (unsigned int) ntohs (message->type));
1141 #endif
1142   plugin->env->receive (plugin->env->cls, &session->target, message, 1,
1143                         session->connect_addr,
1144                         session->connect_alen);
1145   /* update bandwidth used */
1146   session->last_received += msize;
1147   update_quota (session, GNUNET_NO);
1148   delay = calculate_throttle_delay (session);
1149   if (delay.value == 0)
1150     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1151   else
1152     GNUNET_SCHEDULER_add_delayed (session->plugin->env->sched,
1153                                   delay, &delayed_done, session);
1154 }
1155
1156
1157 /**
1158  * Handlers for the various TCP messages.
1159  */
1160 static struct GNUNET_SERVER_MessageHandler my_handlers[] = {
1161   {&handle_tcp_welcome, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME,
1162    sizeof (struct WelcomeMessage)},
1163   {&handle_tcp_data, NULL, GNUNET_MESSAGE_TYPE_ALL, 0},
1164   {NULL, NULL, 0, 0}
1165 };
1166
1167
1168 static void
1169 create_tcp_handlers (struct Plugin *plugin)
1170 {
1171   unsigned int i;
1172   plugin->handlers = GNUNET_malloc (sizeof (my_handlers));
1173   memcpy (plugin->handlers, my_handlers, sizeof (my_handlers));
1174   for (i = 0;
1175        i <
1176        sizeof (my_handlers) / sizeof (struct GNUNET_SERVER_MessageHandler);
1177        i++)
1178     plugin->handlers[i].callback_cls = plugin;
1179   GNUNET_SERVER_add_handlers (plugin->server, plugin->handlers);
1180 }
1181
1182
1183 /**
1184  * Functions with this signature are called whenever a peer
1185  * is disconnected on the network level.
1186  *
1187  * @param cls closure
1188  * @param client identification of the client
1189  */
1190 static void
1191 disconnect_notify (void *cls, struct GNUNET_SERVER_Client *client)
1192 {
1193   struct Plugin *plugin = cls;
1194   struct Session *session;
1195
1196   if (client == NULL)
1197     return;
1198   session = find_session_by_client (plugin, client);
1199   if (session == NULL)
1200     return;                     /* unknown, nothing to do */
1201 #if DEBUG_TCP
1202   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1203                    "tcp",
1204                    "Destroying session of `%4s' with %s (%p) due to network-level disconnect.\n",
1205                    GNUNET_i2s (&session->target),
1206                    (session->connect_addr != NULL) ?
1207                    GNUNET_a2s (session->connect_addr,
1208                                session->connect_alen) : "*", client);
1209 #endif
1210   disconnect_session (session);
1211 }
1212
1213
1214 /**
1215  * Add the IP of our network interface to the list of
1216  * our external IP addresses.
1217  */
1218 static int
1219 process_interfaces (void *cls,
1220                     const char *name,
1221                     int isDefault,
1222                     const struct sockaddr *addr, socklen_t addrlen)
1223 {
1224   struct Plugin *plugin = cls;
1225   int af;
1226   struct sockaddr_in *v4;
1227   struct sockaddr_in6 *v6;
1228
1229   af = addr->sa_family;
1230   if (af == AF_INET)
1231     {
1232       v4 = (struct sockaddr_in *) addr;
1233       v4->sin_port = htons (plugin->adv_port);
1234     }
1235   else
1236     {
1237       GNUNET_assert (af == AF_INET6);
1238       v6 = (struct sockaddr_in6 *) addr;
1239       v6->sin6_port = htons (plugin->adv_port);
1240     }
1241   GNUNET_log_from (GNUNET_ERROR_TYPE_INFO |
1242                    GNUNET_ERROR_TYPE_BULK,
1243                    "tcp", _("Found address `%s' (%s)\n"),
1244                    GNUNET_a2s (addr, addrlen), name);
1245   plugin->env->notify_address (plugin->env->cls,
1246                                "tcp",
1247                                addr, addrlen, GNUNET_TIME_UNIT_FOREVER_REL);
1248   return GNUNET_OK;
1249 }
1250
1251
1252 /**
1253  * Function called by the resolver for each address obtained from DNS
1254  * for our own hostname.  Add the addresses to the list of our
1255  * external IP addresses.
1256  *
1257  * @param cls closure
1258  * @param addr one of the addresses of the host, NULL for the last address
1259  * @param addrlen length of the address
1260  */
1261 static void
1262 process_hostname_ips (void *cls,
1263                       const struct sockaddr *addr, socklen_t addrlen)
1264 {
1265   struct Plugin *plugin = cls;
1266
1267   if (addr == NULL)
1268     {
1269       plugin->hostname_dns = NULL;
1270       return;
1271     }
1272   process_interfaces (plugin, "<hostname>", GNUNET_YES, addr, addrlen);
1273 }
1274
1275
1276 /**
1277  * Entry point for the plugin.
1278  */
1279 void *
1280 libgnunet_plugin_transport_tcp_init (void *cls)
1281 {
1282   struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
1283   struct GNUNET_TRANSPORT_PluginFunctions *api;
1284   struct Plugin *plugin;
1285   struct GNUNET_SERVICE_Context *service;
1286   unsigned long long aport;
1287   unsigned long long bport;
1288
1289   service = GNUNET_SERVICE_start ("transport-tcp", env->sched, env->cfg);
1290   if (service == NULL)
1291     {
1292       GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
1293                        "tcp",
1294                        _
1295                        ("Failed to start service for `%s' transport plugin.\n"),
1296                        "tcp");
1297       return NULL;
1298     }
1299   aport = 0;
1300   if ((GNUNET_OK !=
1301        GNUNET_CONFIGURATION_get_value_number (env->cfg,
1302                                               "transport-tcp",
1303                                               "PORT",
1304                                               &bport)) ||
1305       (bport > 65535) ||
1306       ((GNUNET_OK ==
1307         GNUNET_CONFIGURATION_get_value_number (env->cfg,
1308                                                "transport-tcp",
1309                                                "ADVERTISED-PORT",
1310                                                &aport)) && (aport > 65535)))
1311     {
1312       GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
1313                        "tcp",
1314                        _
1315                        ("Require valid port number for service `%s' in configuration!\n"),
1316                        "transport-tcp");
1317       GNUNET_SERVICE_stop (service);
1318       return NULL;
1319     }
1320   if (aport == 0)
1321     aport = bport;
1322   plugin = GNUNET_malloc (sizeof (struct Plugin));
1323   plugin->open_port = bport;
1324   plugin->adv_port = aport;
1325   plugin->env = env;
1326   plugin->lsock = NULL;
1327   plugin->statistics = NULL;
1328   api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
1329   api->cls = plugin;
1330   api->send = &tcp_plugin_send;
1331   api->disconnect = &tcp_plugin_disconnect;
1332   api->address_pretty_printer = &tcp_plugin_address_pretty_printer;
1333   api->set_receive_quota = &tcp_plugin_set_receive_quota;
1334   api->check_address = &tcp_plugin_check_address;
1335   plugin->service = service;
1336   plugin->server = GNUNET_SERVICE_get_server (service);
1337   create_tcp_handlers (plugin);
1338   GNUNET_log_from (GNUNET_ERROR_TYPE_INFO,
1339                    "tcp", _("TCP transport listening on port %llu\n"), bport);
1340   if (aport != bport)
1341     GNUNET_log_from (GNUNET_ERROR_TYPE_INFO,
1342                      "tcp",
1343                      _
1344                      ("TCP transport advertises itself as being on port %llu\n"),
1345                      aport);
1346   GNUNET_SERVER_disconnect_notify (plugin->server, &disconnect_notify,
1347                                    plugin);
1348   /* FIXME: do the two calls below periodically again and
1349      not just once (since the info we get might change...) */
1350   GNUNET_OS_network_interfaces_list (&process_interfaces, plugin);
1351   plugin->hostname_dns = GNUNET_RESOLVER_hostname_resolve (env->sched,
1352                                                            env->cfg,
1353                                                            AF_UNSPEC,
1354                                                            HOSTNAME_RESOLVE_TIMEOUT,
1355                                                            &process_hostname_ips,
1356                                                            plugin);
1357   return api;
1358 }
1359
1360
1361 /**
1362  * Exit point from the plugin.
1363  */
1364 void *
1365 libgnunet_plugin_transport_tcp_done (void *cls)
1366 {
1367   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
1368   struct Plugin *plugin = api->cls;
1369   struct Session *session;
1370
1371   while (NULL != (session = plugin->sessions))
1372     disconnect_session (session);
1373   if (NULL != plugin->hostname_dns)
1374     {
1375       GNUNET_RESOLVER_request_cancel (plugin->hostname_dns);
1376       plugin->hostname_dns = NULL;
1377     }
1378   GNUNET_SERVICE_stop (plugin->service);
1379   GNUNET_free (plugin->handlers);
1380   GNUNET_free (plugin);
1381   GNUNET_free (api);
1382   return NULL;
1383 }
1384
1385 /* end of plugin_transport_tcp.c */