fixing non-terminating loop
[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                  const 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   session = plugin->sessions;
726   while (NULL != session)
727     {
728       if (0 == memcmp (target,
729                        &session->target,
730                        sizeof (struct GNUNET_PeerIdentity)))
731         {
732           pm = session->pending_messages;
733           while (pm != NULL)
734             {
735               pm->transmit_cont = NULL;
736               pm->transmit_cont_cls = NULL;
737               pm = pm->next;
738             }
739           if (session->client != NULL)
740             {
741               GNUNET_SERVER_client_drop (session->client);
742               session->client = NULL;
743             }
744           /* rest of the clean-up of the session will be done as part of
745              disconnect_notify which should be triggered any time now
746              (or which may be triggering this call in the first place) */
747         }
748       session = session->next;
749     }
750 }
751
752
753 struct PrettyPrinterContext
754 {
755   GNUNET_TRANSPORT_AddressStringCallback asc;
756   void *asc_cls;
757   uint16_t port;
758 };
759
760
761 /**
762  * Append our port and forward the result.
763  */
764 static void
765 append_port (void *cls, const char *hostname)
766 {
767   struct PrettyPrinterContext *ppc = cls;
768   char *ret;
769
770   if (hostname == NULL)
771     {
772       ppc->asc (ppc->asc_cls, NULL);
773       GNUNET_free (ppc);
774       return;
775     }
776   GNUNET_asprintf (&ret, "%s:%d", hostname, ppc->port);
777   ppc->asc (ppc->asc_cls, ret);
778   GNUNET_free (ret);
779 }
780
781
782 /**
783  * Convert the transports address to a nice, human-readable
784  * format.
785  *
786  * @param cls closure
787  * @param type name of the transport that generated the address
788  * @param addr one of the addresses of the host, NULL for the last address
789  *        the specific address format depends on the transport
790  * @param addrlen length of the address
791  * @param numeric should (IP) addresses be displayed in numeric form?
792  * @param timeout after how long should we give up?
793  * @param asc function to call on each string
794  * @param asc_cls closure for asc
795  */
796 static void
797 tcp_plugin_address_pretty_printer (void *cls,
798                                    const char *type,
799                                    const void *addr,
800                                    size_t addrlen,
801                                    int numeric,
802                                    struct GNUNET_TIME_Relative timeout,
803                                    GNUNET_TRANSPORT_AddressStringCallback asc,
804                                    void *asc_cls)
805 {
806   struct Plugin *plugin = cls;
807   const struct sockaddr_in *v4;
808   const struct sockaddr_in6 *v6;
809   struct PrettyPrinterContext *ppc;
810
811   if ((addrlen != sizeof (struct sockaddr_in)) &&
812       (addrlen != sizeof (struct sockaddr_in6)))
813     {
814       /* invalid address */
815       GNUNET_break_op (0);
816       asc (asc_cls, NULL);
817       return;
818     }
819   ppc = GNUNET_malloc (sizeof (struct PrettyPrinterContext));
820   ppc->asc = asc;
821   ppc->asc_cls = asc_cls;
822   if (addrlen == sizeof (struct sockaddr_in))
823     {
824       v4 = (const struct sockaddr_in *) addr;
825       ppc->port = ntohs (v4->sin_port);
826     }
827   else
828     {
829       v6 = (const struct sockaddr_in6 *) addr;
830       ppc->port = ntohs (v6->sin6_port);
831
832     }
833   GNUNET_RESOLVER_hostname_get (plugin->env->sched,
834                                 plugin->env->cfg,
835                                 addr,
836                                 addrlen,
837                                 !numeric, timeout, &append_port, ppc);
838 }
839
840
841 /**
842  * Update the last-received and bandwidth quota values
843  * for this session.
844  *
845  * @param session session to update
846  * @param force set to GNUNET_YES if we should update even
847  *        though the minimum refresh time has not yet expired
848  */
849 static void
850 update_quota (struct Session *session, int force)
851 {
852   struct GNUNET_TIME_Absolute now;
853   unsigned long long delta;
854   unsigned long long total_allowed;
855   unsigned long long total_remaining;
856
857   now = GNUNET_TIME_absolute_get ();
858   delta = now.value - session->last_quota_update.value;
859   if ((delta < MIN_QUOTA_REFRESH_TIME) && (!force))
860     return;                     /* too early, not enough data */
861
862   total_allowed = session->quota_in * delta;
863   if (total_allowed > session->last_received)
864     {
865       /* got less than acceptable */
866       total_remaining = total_allowed - session->last_received;
867       session->last_received = 0;
868       delta = total_remaining / session->quota_in;      /* bonus seconds */
869       if (delta > MAX_BANDWIDTH_CARRY)
870         delta = MAX_BANDWIDTH_CARRY;    /* limit amount of carry-over */
871     }
872   else
873     {
874       /* got more than acceptable */
875       session->last_received -= total_allowed;
876       delta = 0;
877     }
878   session->last_quota_update.value = now.value - delta;
879 }
880
881
882 /**
883  * Set a quota for receiving data from the given peer; this is a
884  * per-transport limit.  The transport should limit its read/select
885  * calls to stay below the quota (in terms of incoming data).
886  *
887  * @param cls closure
888  * @param target the peer for whom the quota is given
889  * @param quota_in quota for receiving/sending data in bytes per ms
890  */
891 static void
892 tcp_plugin_set_receive_quota (void *cls,
893                               const struct GNUNET_PeerIdentity *target,
894                               uint32_t quota_in)
895 {
896   struct Plugin *plugin = cls;
897   struct Session *session;
898
899   session = find_session_by_target (plugin, target);
900   if (session == NULL)
901     return;                     /* peer must have disconnected, ignore */
902   if (session->quota_in != quota_in)
903     {
904       update_quota (session, GNUNET_YES);
905       if (session->quota_in > quota_in)
906         session->last_quota_update = GNUNET_TIME_absolute_get ();
907       session->quota_in = quota_in;
908     }
909 }
910
911
912 /**
913  * Check if the given port is plausible (must be either
914  * our listen port or our advertised port).  If it is
915  * neither, we return one of these two ports at random.
916  *
917  * @return either in_port or a more plausible port
918  */
919 static uint16_t
920 check_port (struct Plugin *plugin, uint16_t in_port)
921 {
922   if ((in_port == plugin->adv_port) || (in_port == plugin->open_port))
923     return in_port;
924   return (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
925                                     2) == 0)
926     ? plugin->open_port : plugin->adv_port;
927 }
928
929
930 /**
931  * Another peer has suggested an address for this peer and transport
932  * plugin.  Check that this could be a valid address.
933  *
934  * @param cls closure
935  * @param addr pointer to the address
936  * @param addrlen length of addr
937  * @return GNUNET_OK if this is a plausible address for this peer
938  *         and transport
939  */
940 static int
941 tcp_plugin_check_address (void *cls, void *addr, size_t addrlen)
942 {
943   struct Plugin *plugin = cls;
944   char buf[sizeof (struct sockaddr_in6)];
945   struct sockaddr_in *v4;
946   struct sockaddr_in6 *v6;
947
948   if ((addrlen != sizeof (struct sockaddr_in)) &&
949       (addrlen != sizeof (struct sockaddr_in6)))
950     {
951       GNUNET_break_op (0);
952       return GNUNET_SYSERR;
953     }
954   memcpy (buf, addr, sizeof (struct sockaddr_in6));
955   if (addrlen == sizeof (struct sockaddr_in))
956     {
957       v4 = (struct sockaddr_in *) buf;
958       v4->sin_port = htons (check_port (plugin, ntohs (v4->sin_port)));
959     }
960   else
961     {
962       v6 = (struct sockaddr_in6 *) buf;
963       v6->sin6_port = htons (check_port (plugin, ntohs (v6->sin6_port)));
964     }
965 #if DEBUG_TCP
966   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
967                    "tcp",
968                    "Informing transport service about my address `%s'.\n",
969                    GNUNET_a2s (addr, addrlen));
970 #endif
971   return GNUNET_OK;
972 }
973
974
975 /**
976  * We've received a welcome from this peer via TCP.  Possibly create a
977  * fresh client record and send back our welcome.
978  *
979  * @param cls closure
980  * @param client identification of the client
981  * @param message the actual message
982  */
983 static void
984 handle_tcp_welcome (void *cls,
985                     struct GNUNET_SERVER_Client *client,
986                     const struct GNUNET_MessageHeader *message)
987 {
988   struct Plugin *plugin = cls;
989   const struct WelcomeMessage *wm = (const struct WelcomeMessage *) message;
990   struct Session *session;
991   size_t alen;
992   void *vaddr;
993
994 #if DEBUG_TCP
995   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
996                    "tcp",
997                    "Received `%s' message from a `%4s/%p'.\n", "WELCOME",
998                    GNUNET_i2s (&wm->clientIdentity), client);
999 #endif
1000
1001   session = find_session_by_client (plugin, client);
1002   if (session == NULL)
1003     {
1004       GNUNET_SERVER_client_keep (client);
1005       session = create_session (plugin,
1006                                 &wm->clientIdentity, client);
1007       if (GNUNET_OK ==
1008           GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
1009         {
1010 #if DEBUG_TCP
1011       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1012                        "tcp",
1013                        "Found address for incoming `%s' message\n",
1014                        "WELCOME");
1015 #endif
1016           session->connect_addr = vaddr;
1017           session->connect_alen = alen;
1018         }
1019       else
1020         {
1021 #if DEBUG_TCP
1022       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1023                        "tcp",
1024                        "Didn't find address for incoming `%s' message\n",
1025                        "WELCOME");
1026 #endif
1027         }
1028 #if DEBUG_TCP
1029       GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1030                        "tcp",
1031                        "Creating new session %p for incoming `%s' message.\n",
1032                        session, "WELCOME");
1033 #endif
1034       process_pending_messages (session);
1035     }
1036   if (session->expecting_welcome != GNUNET_YES)
1037     {
1038       GNUNET_break_op (0);
1039       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1040       return;
1041     }
1042   session->expecting_welcome = GNUNET_NO;
1043   GNUNET_SERVER_receive_done (client, GNUNET_OK);
1044 }
1045
1046
1047 /**
1048  * Calculate how long we should delay reading from the TCP socket to
1049  * ensure that we stay within our bandwidth limits (push back).
1050  *
1051  * @param session for which client should this be calculated
1052  */
1053 static struct GNUNET_TIME_Relative
1054 calculate_throttle_delay (struct Session *session)
1055 {
1056   struct GNUNET_TIME_Relative ret;
1057   struct GNUNET_TIME_Absolute now;
1058   uint64_t del;
1059   uint64_t avail;
1060   uint64_t excess;
1061
1062   now = GNUNET_TIME_absolute_get ();
1063   del = now.value - session->last_quota_update.value;
1064   if (del > MAX_BANDWIDTH_CARRY)
1065     {
1066       update_quota (session, GNUNET_YES);
1067       del = now.value - session->last_quota_update.value;
1068       GNUNET_assert (del <= MAX_BANDWIDTH_CARRY);
1069     }
1070   if (session->quota_in == 0)
1071     session->quota_in = 1;      /* avoid divison by zero */
1072   avail = del * session->quota_in;
1073   if (avail > session->last_received)
1074     return GNUNET_TIME_UNIT_ZERO;       /* can receive right now */
1075   excess = session->last_received - avail;
1076   ret.value = excess / session->quota_in;
1077   return ret;
1078 }
1079
1080
1081 /**
1082  * Task to signal the server that we can continue
1083  * receiving from the TCP client now.
1084  */
1085 static void
1086 delayed_done (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
1087 {
1088   struct Session *session = cls;
1089   GNUNET_SERVER_receive_done (session->client, GNUNET_OK);
1090 }
1091
1092
1093 /**
1094  * We've received data for this peer via TCP.  Unbox,
1095  * compute latency and forward.
1096  *
1097  * @param cls closure
1098  * @param client identification of the client
1099  * @param message the actual message
1100  */
1101 static void
1102 handle_tcp_data (void *cls,
1103                  struct GNUNET_SERVER_Client *client,
1104                  const struct GNUNET_MessageHeader *message)
1105 {
1106   struct Plugin *plugin = cls;
1107   struct Session *session;
1108   uint16_t msize;
1109   struct GNUNET_TIME_Relative delay;
1110
1111   msize = ntohs (message->size);
1112   session = find_session_by_client (plugin, client);
1113
1114   if (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME == ntohs(message->type))
1115   {
1116 #if DEBUG_TCP
1117   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1118                    "tcp", "Received a welcome, NOT sending to clients!\n");
1119 #endif
1120     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1121     return; /* We don't want to propagate WELCOME messages up! */
1122   }
1123   else
1124     {
1125 #if DEBUG_TCP
1126   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1127                    "tcp", "Received DATA message, checking session!\n");
1128 #endif
1129     }
1130
1131   if ( (NULL == session) || (GNUNET_NO != session->expecting_welcome))
1132     {
1133       GNUNET_break_op (0);
1134       GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
1135       return;
1136     }
1137 #if DEBUG_TCP
1138   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1139                    "tcp", "Receiving %u bytes from `%4s'.\n",
1140                    msize, GNUNET_i2s (&session->target));
1141 #endif
1142 #if DEBUG_TCP
1143   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1144                    "tcp",
1145                    "Forwarding %u bytes of data of type %u to transport service.\n",
1146                    (unsigned int) msize,
1147                    (unsigned int) ntohs (message->type));
1148 #endif
1149   plugin->env->receive (plugin->env->cls, &session->target, message, 1,
1150                         session->connect_addr,
1151                         session->connect_alen);
1152   /* update bandwidth used */
1153   session->last_received += msize;
1154   update_quota (session, GNUNET_NO);
1155   delay = calculate_throttle_delay (session);
1156   if (delay.value == 0)
1157     GNUNET_SERVER_receive_done (client, GNUNET_OK);
1158   else
1159     GNUNET_SCHEDULER_add_delayed (session->plugin->env->sched,
1160                                   delay, &delayed_done, session);
1161 }
1162
1163
1164 /**
1165  * Handlers for the various TCP messages.
1166  */
1167 static struct GNUNET_SERVER_MessageHandler my_handlers[] = {
1168   {&handle_tcp_welcome, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME,
1169    sizeof (struct WelcomeMessage)},
1170   {&handle_tcp_data, NULL, GNUNET_MESSAGE_TYPE_ALL, 0},
1171   {NULL, NULL, 0, 0}
1172 };
1173
1174
1175 static void
1176 create_tcp_handlers (struct Plugin *plugin)
1177 {
1178   unsigned int i;
1179   plugin->handlers = GNUNET_malloc (sizeof (my_handlers));
1180   memcpy (plugin->handlers, my_handlers, sizeof (my_handlers));
1181   for (i = 0;
1182        i <
1183        sizeof (my_handlers) / sizeof (struct GNUNET_SERVER_MessageHandler);
1184        i++)
1185     plugin->handlers[i].callback_cls = plugin;
1186   GNUNET_SERVER_add_handlers (plugin->server, plugin->handlers);
1187 }
1188
1189
1190 /**
1191  * Functions with this signature are called whenever a peer
1192  * is disconnected on the network level.
1193  *
1194  * @param cls closure
1195  * @param client identification of the client
1196  */
1197 static void
1198 disconnect_notify (void *cls, struct GNUNET_SERVER_Client *client)
1199 {
1200   struct Plugin *plugin = cls;
1201   struct Session *session;
1202
1203   if (client == NULL)
1204     return;
1205   session = find_session_by_client (plugin, client);
1206   if (session == NULL)
1207     return;                     /* unknown, nothing to do */
1208 #if DEBUG_TCP
1209   GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG,
1210                    "tcp",
1211                    "Destroying session of `%4s' with %s (%p) due to network-level disconnect.\n",
1212                    GNUNET_i2s (&session->target),
1213                    (session->connect_addr != NULL) ?
1214                    GNUNET_a2s (session->connect_addr,
1215                                session->connect_alen) : "*", client);
1216 #endif
1217   disconnect_session (session);
1218 }
1219
1220
1221 /**
1222  * Add the IP of our network interface to the list of
1223  * our external IP addresses.
1224  */
1225 static int
1226 process_interfaces (void *cls,
1227                     const char *name,
1228                     int isDefault,
1229                     const struct sockaddr *addr, socklen_t addrlen)
1230 {
1231   struct Plugin *plugin = cls;
1232   int af;
1233   struct sockaddr_in *v4;
1234   struct sockaddr_in6 *v6;
1235
1236   af = addr->sa_family;
1237   if (af == AF_INET)
1238     {
1239       v4 = (struct sockaddr_in *) addr;
1240       v4->sin_port = htons (plugin->adv_port);
1241     }
1242   else
1243     {
1244       GNUNET_assert (af == AF_INET6);
1245       v6 = (struct sockaddr_in6 *) addr;
1246       v6->sin6_port = htons (plugin->adv_port);
1247     }
1248   GNUNET_log_from (GNUNET_ERROR_TYPE_INFO |
1249                    GNUNET_ERROR_TYPE_BULK,
1250                    "tcp", _("Found address `%s' (%s)\n"),
1251                    GNUNET_a2s (addr, addrlen), name);
1252   plugin->env->notify_address (plugin->env->cls,
1253                                "tcp",
1254                                addr, addrlen, GNUNET_TIME_UNIT_FOREVER_REL);
1255   return GNUNET_OK;
1256 }
1257
1258
1259 /**
1260  * Function called by the resolver for each address obtained from DNS
1261  * for our own hostname.  Add the addresses to the list of our
1262  * external IP addresses.
1263  *
1264  * @param cls closure
1265  * @param addr one of the addresses of the host, NULL for the last address
1266  * @param addrlen length of the address
1267  */
1268 static void
1269 process_hostname_ips (void *cls,
1270                       const struct sockaddr *addr, socklen_t addrlen)
1271 {
1272   struct Plugin *plugin = cls;
1273
1274   if (addr == NULL)
1275     {
1276       plugin->hostname_dns = NULL;
1277       return;
1278     }
1279   process_interfaces (plugin, "<hostname>", GNUNET_YES, addr, addrlen);
1280 }
1281
1282
1283 /**
1284  * Entry point for the plugin.
1285  */
1286 void *
1287 libgnunet_plugin_transport_tcp_init (void *cls)
1288 {
1289   struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
1290   struct GNUNET_TRANSPORT_PluginFunctions *api;
1291   struct Plugin *plugin;
1292   struct GNUNET_SERVICE_Context *service;
1293   unsigned long long aport;
1294   unsigned long long bport;
1295
1296   service = GNUNET_SERVICE_start ("transport-tcp", env->sched, env->cfg);
1297   if (service == NULL)
1298     {
1299       GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING,
1300                        "tcp",
1301                        _
1302                        ("Failed to start service for `%s' transport plugin.\n"),
1303                        "tcp");
1304       return NULL;
1305     }
1306   aport = 0;
1307   if ((GNUNET_OK !=
1308        GNUNET_CONFIGURATION_get_value_number (env->cfg,
1309                                               "transport-tcp",
1310                                               "PORT",
1311                                               &bport)) ||
1312       (bport > 65535) ||
1313       ((GNUNET_OK ==
1314         GNUNET_CONFIGURATION_get_value_number (env->cfg,
1315                                                "transport-tcp",
1316                                                "ADVERTISED-PORT",
1317                                                &aport)) && (aport > 65535)))
1318     {
1319       GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR,
1320                        "tcp",
1321                        _
1322                        ("Require valid port number for service `%s' in configuration!\n"),
1323                        "transport-tcp");
1324       GNUNET_SERVICE_stop (service);
1325       return NULL;
1326     }
1327   if (aport == 0)
1328     aport = bport;
1329   plugin = GNUNET_malloc (sizeof (struct Plugin));
1330   plugin->open_port = bport;
1331   plugin->adv_port = aport;
1332   plugin->env = env;
1333   plugin->lsock = NULL;
1334   plugin->statistics = NULL;
1335   api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
1336   api->cls = plugin;
1337   api->send = &tcp_plugin_send;
1338   api->disconnect = &tcp_plugin_disconnect;
1339   api->address_pretty_printer = &tcp_plugin_address_pretty_printer;
1340   api->set_receive_quota = &tcp_plugin_set_receive_quota;
1341   api->check_address = &tcp_plugin_check_address;
1342   plugin->service = service;
1343   plugin->server = GNUNET_SERVICE_get_server (service);
1344   create_tcp_handlers (plugin);
1345   GNUNET_log_from (GNUNET_ERROR_TYPE_INFO,
1346                    "tcp", _("TCP transport listening on port %llu\n"), bport);
1347   if (aport != bport)
1348     GNUNET_log_from (GNUNET_ERROR_TYPE_INFO,
1349                      "tcp",
1350                      _
1351                      ("TCP transport advertises itself as being on port %llu\n"),
1352                      aport);
1353   GNUNET_SERVER_disconnect_notify (plugin->server, &disconnect_notify,
1354                                    plugin);
1355   /* FIXME: do the two calls below periodically again and
1356      not just once (since the info we get might change...) */
1357   GNUNET_OS_network_interfaces_list (&process_interfaces, plugin);
1358   plugin->hostname_dns = GNUNET_RESOLVER_hostname_resolve (env->sched,
1359                                                            env->cfg,
1360                                                            AF_UNSPEC,
1361                                                            HOSTNAME_RESOLVE_TIMEOUT,
1362                                                            &process_hostname_ips,
1363                                                            plugin);
1364   return api;
1365 }
1366
1367
1368 /**
1369  * Exit point from the plugin.
1370  */
1371 void *
1372 libgnunet_plugin_transport_tcp_done (void *cls)
1373 {
1374   struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
1375   struct Plugin *plugin = api->cls;
1376   struct Session *session;
1377
1378   while (NULL != (session = plugin->sessions))
1379     disconnect_session (session);
1380   if (NULL != plugin->hostname_dns)
1381     {
1382       GNUNET_RESOLVER_request_cancel (plugin->hostname_dns);
1383       plugin->hostname_dns = NULL;
1384     }
1385   GNUNET_SERVICE_stop (plugin->service);
1386   GNUNET_free (plugin->handlers);
1387   GNUNET_free (plugin);
1388   GNUNET_free (api);
1389   return NULL;
1390 }
1391
1392 /* end of plugin_transport_tcp.c */