towards implementing notification for peer addresses
[oweals/gnunet.git] / src / nat / gnunet-service-nat.c
1 /*
2   This file is part of GNUnet.
3   Copyright (C) 2016 GNUnet e.V.
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 3, 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., 51 Franklin Street, Fifth Floor,
18   Boston, MA 02110-1301, USA.
19  */
20
21 /**
22  * @file nat/gnunet-service-nat.c
23  * @brief network address translation traversal service
24  * @author Christian Grothoff
25  *
26  * The purpose of this service is to enable transports to 
27  * traverse NAT routers, by providing traversal options and
28  * knowledge about the local network topology.
29  */
30 #include "platform.h"
31 #include <math.h>
32 #include "gnunet_util_lib.h"
33 #include "gnunet_protocols.h"
34 #include "gnunet_signatures.h"
35 #include "gnunet_statistics_service.h"
36 #include "gnunet_nat_service.h"
37 #include "nat.h"
38 #include <gcrypt.h>
39
40
41 /**
42  * How often should we ask the OS about a list of active
43  * network interfaces?
44  */
45 #define SCAN_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
46
47
48 /**
49  * Internal data structure we track for each of our clients.
50  */
51 struct ClientHandle
52 {
53
54   /**
55    * Kept in a DLL.
56    */
57   struct ClientHandle *next;
58   
59   /**
60    * Kept in a DLL.
61    */
62   struct ClientHandle *prev;
63
64   /**
65    * Underlying handle for this client with the service.
66    */ 
67   struct GNUNET_SERVICE_Client *client;
68
69   /**
70    * Message queue for communicating with the client.
71    */
72   struct GNUNET_MQ_Handle *mq;
73
74   /**
75    * Array of addresses used by the service.
76    */
77   struct sockaddr **addrs;
78   
79   /**
80    * What does this client care about?
81    */
82   enum GNUNET_NAT_RegisterFlags flags;
83
84   /**
85    * Port we would like as we are configured to use this one for
86    * advertising (in addition to the one we are binding to).
87    */
88   uint16_t adv_port;
89
90   /**
91    * Number of addresses that this service is bound to.
92    */
93   uint16_t num_addrs;
94   
95   /**
96    * Client's IPPROTO, e.g. IPPROTO_UDP or IPPROTO_TCP.
97    */
98   uint8_t proto;
99
100 };
101
102
103 /**
104  * List of local addresses this system has.
105  */
106 struct LocalAddressList
107 {
108   /**
109    * This is a linked list.
110    */
111   struct LocalAddressList *next;
112
113   /**
114    * Previous entry.
115    */
116   struct LocalAddressList *prev;
117
118   /**
119    * The address itself (i.e. `struct in_addr` or `struct in6_addr`,
120    * in the respective byte order).  Allocated at the end of this
121    * struct.
122    */
123   const void *addr;
124
125   /**
126    * Address family.
127    */
128   int af;
129
130   /**
131    * What type of address is this?
132    */
133   enum GNUNET_NAT_AddressClass ac;
134   
135 };
136
137
138
139
140 /**
141  * Handle to our current configuration.
142  */
143 static const struct GNUNET_CONFIGURATION_Handle *cfg;
144
145 /**
146  * Handle to the statistics service.
147  */
148 static struct GNUNET_STATISTICS_Handle *stats;
149
150 /**
151  * Task scheduled to periodically scan our network interfaces.
152  */
153 static struct GNUNET_SCHEDULER_Task *scan_task;
154
155 /**
156  * Head of client DLL.
157  */
158 static struct ClientHandle *ch_head;
159   
160 /**
161  * Tail of client DLL.
162  */
163 static struct ClientHandle *ch_tail;
164
165 /**
166  * Head of DLL of local addresses.
167  */
168 static struct LocalAddressList *lal_head;
169
170 /**
171  * Tail of DLL of local addresses.
172  */
173 static struct LocalAddressList *lal_tail;
174
175
176 /**
177  * Free the DLL starting at #lal_head.
178  */ 
179 static void
180 destroy_lal ()
181 {
182   struct LocalAddressList *lal;
183
184   while (NULL != (lal = lal_head))
185   {
186     GNUNET_CONTAINER_DLL_remove (lal_head,
187                                  lal_tail,
188                                  lal);
189     GNUNET_free (lal);
190   }
191 }
192
193
194 /**
195  * Check validity of #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from
196  * client.
197  *
198  * @param cls client who sent the message
199  * @param message the message received
200  * @return #GNUNET_OK if message is well-formed
201  */
202 static int
203 check_register (void *cls,
204                 const struct GNUNET_NAT_RegisterMessage *message)
205 {
206   uint16_t num_addrs = ntohs (message->num_addrs);
207   const char *off = (const char *) &message[1];
208   size_t left = ntohs (message->header.size) - sizeof (*message);
209
210   for (unsigned int i=0;i<num_addrs;i++)
211   {
212     size_t alen;
213     const struct sockaddr *sa = (const struct sockaddr *) off;
214
215     if (sizeof (sa_family_t) > left)
216     {
217       GNUNET_break (0);
218       return GNUNET_SYSERR;
219     }
220     switch (sa->sa_family)
221     {
222     case AF_INET:
223       alen = sizeof (struct sockaddr_in);
224       break;
225     case AF_INET6:
226       alen = sizeof (struct sockaddr_in6);
227       break;
228 #if AF_UNIX
229     case AF_UNIX:
230       alen = sizeof (struct sockaddr_un);
231       break;
232 #endif
233     default:
234       GNUNET_break (0);
235       return GNUNET_SYSERR;      
236     }
237     if (alen > left)
238     {
239       GNUNET_break (0);
240       return GNUNET_SYSERR;      
241     }
242   }  
243   return GNUNET_OK; 
244 }
245
246
247 /**
248  * Handler for #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client.
249  * We remember the client for updates upon future NAT events.
250  *
251  * @param cls client who sent the message
252  * @param message the message received
253  */
254 static void
255 handle_register (void *cls,
256                  const struct GNUNET_NAT_RegisterMessage *message)
257 {
258   struct ClientHandle *ch = cls;
259   const char *off;
260   size_t left;
261
262   if ( (0 != ch->proto) ||
263        (NULL != ch->addrs) )
264   {
265     /* double registration not allowed */
266     GNUNET_break (0);
267     GNUNET_SERVICE_client_drop (ch->client);
268     return;
269   }
270   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
271               "Received REGISTER message from client\n");
272   ch->flags = message->flags;
273   ch->proto = message->proto;
274   ch->adv_port = ntohs (message->adv_port);
275   ch->num_addrs = ntohs (message->adv_port);
276   ch->addrs = GNUNET_new_array (ch->num_addrs,
277                                 struct sockaddr *);
278   left = ntohs (message->header.size) - sizeof (*message);
279   off = (const char *) &message[1];
280   for (unsigned int i=0;i<ch->num_addrs;i++)
281   {
282     size_t alen;
283     const struct sockaddr *sa = (const struct sockaddr *) off;
284
285     if (sizeof (sa_family_t) > left)
286     {
287       GNUNET_break (0);
288       GNUNET_SERVICE_client_drop (ch->client);
289       return;
290     }
291     switch (sa->sa_family)
292     {
293     case AF_INET:
294       alen = sizeof (struct sockaddr_in);
295       break;
296     case AF_INET6:
297       alen = sizeof (struct sockaddr_in6);
298       break;
299 #if AF_UNIX
300     case AF_UNIX:
301       alen = sizeof (struct sockaddr_un);
302       break;
303 #endif
304     default:
305       GNUNET_break (0);
306       GNUNET_SERVICE_client_drop (ch->client);
307       return;      
308     }
309     GNUNET_assert (alen <= left);
310     ch->addrs[i] = GNUNET_malloc (alen);
311     GNUNET_memcpy (ch->addrs[i],
312                    sa,
313                    alen);    
314     off += alen;
315   }  
316   GNUNET_SERVICE_client_continue (ch->client);
317 }
318
319
320 /**
321  * Check validity of #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from
322  * client.
323  *
324  * @param cls client who sent the message
325  * @param message the message received
326  * @return #GNUNET_OK if message is well-formed
327  */
328 static int
329 check_stun (void *cls,
330             const struct GNUNET_NAT_HandleStunMessage *message)
331 {
332   size_t sa_len = ntohs (message->sender_addr_size);
333   size_t expect = sa_len + ntohs (message->payload_size);
334   
335   if (ntohs (message->header.size) - sizeof (*message) != expect)
336   {
337     GNUNET_break (0);
338     return GNUNET_SYSERR;
339   }
340   if (sa_len < sizeof (sa_family_t))
341   {
342     GNUNET_break (0);
343     return GNUNET_SYSERR;
344   }
345   return GNUNET_OK;
346 }
347
348
349 /**
350  * Handler for #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from
351  * client.
352  *
353  * @param cls client who sent the message
354  * @param message the message received
355  */
356 static void
357 handle_stun (void *cls,
358              const struct GNUNET_NAT_HandleStunMessage *message)
359 {
360   struct ClientHandle *ch = cls;
361   const char *buf = (const char *) &message[1];
362   const struct sockaddr *sa;
363   const void *payload;
364   size_t sa_len;
365   size_t payload_size;
366
367   sa_len = ntohs (message->sender_addr_size);
368   payload_size = ntohs (message->payload_size);
369   sa = (const struct sockaddr *) &buf[0];
370   payload = (const struct sockaddr *) &buf[sa_len];
371   switch (sa->sa_family)
372   {
373   case AF_INET:
374     if (sa_len != sizeof (struct sockaddr_in))
375     {
376       GNUNET_break (0);
377       GNUNET_SERVICE_client_drop (ch->client);
378       return;
379     }
380     break;
381   case AF_INET6:
382     if (sa_len != sizeof (struct sockaddr_in6))
383     {
384       GNUNET_break (0);
385       GNUNET_SERVICE_client_drop (ch->client);
386       return;
387     }
388     break;
389   }
390   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
391               "Received HANDLE_STUN message from client\n");
392   // FIXME: actually handle STUN request!
393   GNUNET_SERVICE_client_continue (ch->client);
394 }
395
396
397 /**
398  * Check validity of
399  * #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL message from
400  * client.
401  *
402  * @param cls client who sent the message
403  * @param message the message received
404  * @return #GNUNET_OK if message is well-formed
405  */
406 static int
407 check_request_connection_reversal (void *cls,
408                                    const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
409 {
410   size_t expect;
411
412   expect = ntohs (message->local_addr_size)
413     + ntohs (message->remote_addr_size);
414   if (ntohs (message->header.size) - sizeof (*message) != expect)
415   {
416     GNUNET_break (0);
417     return GNUNET_SYSERR;
418   }
419   return GNUNET_OK;
420 }
421
422
423 /**
424  * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL
425  * message from client.
426  *
427  * @param cls client who sent the message
428  * @param message the message received
429  */
430 static void
431 handle_request_connection_reversal (void *cls,
432                                     const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
433 {
434   struct ClientHandle *ch = cls;
435   const char *buf = (const char *) &message[1];
436   size_t local_sa_len = ntohs (message->local_addr_size);
437   size_t remote_sa_len = ntohs (message->remote_addr_size);
438   const struct sockaddr *local_sa = (const struct sockaddr *) &buf[0];
439   const struct sockaddr *remote_sa = (const struct sockaddr *) &buf[local_sa_len];
440   
441   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
442               "Received REQUEST CONNECTION REVERSAL message from client\n");
443   switch (local_sa->sa_family)
444   {
445   case AF_INET:
446     if (local_sa_len != sizeof (struct sockaddr_in))
447     {
448       GNUNET_break (0);
449       GNUNET_SERVICE_client_drop (ch->client);
450       return;
451     }
452     break;
453   case AF_INET6:
454     if (local_sa_len != sizeof (struct sockaddr_in6))
455     {
456       GNUNET_break (0);
457       GNUNET_SERVICE_client_drop (ch->client);
458       return;
459     }
460     break;
461   default:
462     GNUNET_break (0);
463     GNUNET_SERVICE_client_drop (ch->client);
464     return;
465   }
466   switch (remote_sa->sa_family)
467   {
468   case AF_INET:
469     if (remote_sa_len != sizeof (struct sockaddr_in))
470     {
471       GNUNET_break (0);
472       GNUNET_SERVICE_client_drop (ch->client);
473       return;
474     }
475     break;
476   case AF_INET6:
477     if (remote_sa_len != sizeof (struct sockaddr_in6))
478     {
479       GNUNET_break (0);
480       GNUNET_SERVICE_client_drop (ch->client);
481       return;
482     }
483     break;
484   default:
485     GNUNET_break (0);
486     GNUNET_SERVICE_client_drop (ch->client);
487     return;
488   }
489   /* FIXME: actually run the logic! */
490   
491   GNUNET_SERVICE_client_continue (ch->client);
492 }
493
494
495 /**
496  * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_TEST message from
497  * client.
498  *
499  * @param cls client who sent the message
500  * @param message the message received
501  */
502 static void
503 handle_test (void *cls,
504              const struct GNUNET_NAT_RequestTestMessage *message)
505 {
506   struct ClientHandle *ch = cls;
507
508   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
509               "Received REQUEST_TEST message from client\n");
510   /* FIXME: actually process test request */
511   GNUNET_SERVICE_client_continue (ch->client);
512 }
513
514
515 /**
516  * Check validity of #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message
517  * from client.
518  *
519  * @param cls client who sent the message
520  * @param message the message received
521  * @return #GNUNET_OK if message is well-formed
522  */
523 static int
524 check_autoconfig_request (void *cls,
525                           const struct GNUNET_NAT_AutoconfigRequestMessage *message)
526 {
527   return GNUNET_OK;  /* checked later */
528 }
529
530
531 /**
532  * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message from
533  * client.
534  *
535  * @param cls client who sent the message
536  * @param message the message received
537  */
538 static void
539 handle_autoconfig_request (void *cls,
540                            const struct GNUNET_NAT_AutoconfigRequestMessage *message)
541 {
542   struct ClientHandle *ch = cls;
543   size_t left = ntohs (message->header.size);
544   struct GNUNET_CONFIGURATION_Handle *c;
545
546   c = GNUNET_CONFIGURATION_create ();
547   if (GNUNET_OK !=
548       GNUNET_CONFIGURATION_deserialize (c,
549                                         (const char *) &message[1],
550                                         left,
551                                         GNUNET_NO))
552   {
553     GNUNET_break (0);
554     GNUNET_SERVICE_client_drop (ch->client);
555     return;
556   }
557   GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
558               "Received REQUEST_AUTO_CONFIG message from client\n");
559   // FIXME: actually handle request...
560   GNUNET_CONFIGURATION_destroy (c);
561   GNUNET_SERVICE_client_continue (ch->client);
562 }
563
564
565 /**
566  * Task run during shutdown.
567  *
568  * @param cls unused
569  */
570 static void
571 shutdown_task (void *cls)
572 {
573   if (NULL != scan_task)
574   {
575     GNUNET_SCHEDULER_cancel (scan_task);
576     scan_task = NULL;
577   }
578   if (NULL != stats)
579   {
580     GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
581     stats = NULL;
582   }
583   destroy_lal ();
584 }
585
586
587 /**
588  * Closure for #ifc_proc.
589  */
590 struct IfcProcContext
591 {
592
593   /** 
594    * Head of DLL of local addresses.
595    */
596   struct LocalAddressList *lal_head;
597
598   /**
599    * Tail of DLL of local addresses.
600    */
601   struct LocalAddressList *lal_tail;
602
603 };
604
605
606 /**
607  * Callback function invoked for each interface found.  Adds them
608  * to our new address list.
609  *
610  * @param cls a `struct IfcProcContext *`
611  * @param name name of the interface (can be NULL for unknown)
612  * @param isDefault is this presumably the default interface
613  * @param addr address of this interface (can be NULL for unknown or unassigned)
614  * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
615  * @param netmask the network mask (can be NULL for unknown or unassigned)
616  * @param addrlen length of the address
617  * @return #GNUNET_OK to continue iteration, #GNUNET_SYSERR to abort
618  */
619 static int
620 ifc_proc (void *cls,
621           const char *name,
622           int isDefault,
623           const struct sockaddr *addr,
624           const struct sockaddr *broadcast_addr,
625           const struct sockaddr *netmask,
626           socklen_t addrlen)
627 {
628   struct IfcProcContext *ifc_ctx = cls;
629   struct LocalAddressList *lal;
630   size_t alen;
631   const void *ip;
632
633   switch (addr->sa_family)
634   {
635   case AF_INET:
636     alen = sizeof (struct in_addr);
637     ip = &((const struct sockaddr_in *) addr)->sin_addr;
638     break;
639   case AF_INET6:
640     alen = sizeof (struct in6_addr);
641     ip = &((const struct sockaddr_in6 *) addr)->sin6_addr;
642     break;
643 #if AF_UNIX
644   case AF_UNIX:
645     GNUNET_break (0);
646     return GNUNET_OK;
647 #endif
648   default:
649     GNUNET_break (0);
650     return GNUNET_OK;
651   }
652   lal = GNUNET_malloc (sizeof (*lal) + alen);
653   lal->af = addr->sa_family;
654   lal->addr = &lal[1];
655   GNUNET_memcpy (&lal[1],
656                  ip,
657                  alen);
658   GNUNET_CONTAINER_DLL_insert (ifc_ctx->lal_head,
659                                ifc_ctx->lal_tail,
660                                lal);
661   return GNUNET_OK;
662 }
663
664
665 /**
666  * Notify all clients about a change in the list
667  * of addresses this peer has.
668  *
669  * @param delta the entry in the list that changed
670  * @param add #GNUNET_YES to add, #GNUNET_NO to remove
671  */
672 static void
673 notify_clients (struct LocalAddressList *delta,
674                 int add)
675 {
676   for (struct ClientHandle *ch = ch_head;
677        NULL != ch;
678        ch = ch->next)
679   {
680     struct GNUNET_MQ_Envelope *env;
681     struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
682     void *addr;
683     struct sockaddr_in v4;
684     struct sockaddr_in6 v6;
685     size_t alen;
686     
687     if (0 == (ch->flags & GNUNET_NAT_RF_ADDRESSES))
688       continue;
689     switch (delta->af)
690     {
691     case AF_INET:
692       alen = sizeof (struct sockaddr_in);
693       addr = &v4;
694       memset (&v4, 0, sizeof (v4));
695       v4.sin_family = AF_INET;
696       GNUNET_memcpy (&v4.sin_addr,
697                      delta->addr,
698                      sizeof (struct in_addr));
699       /* FIXME: set port */
700       break;
701     case AF_INET6:
702       alen = sizeof (struct sockaddr_in6);
703       addr = &v6;
704       memset (&v6, 0, sizeof (v6));
705       v6.sin6_family = AF_INET6;
706       GNUNET_memcpy (&v6.sin6_addr,
707                      delta->addr,
708                      sizeof (struct in6_addr));
709       /* FIXME: set port, and link/interface! */
710       break;
711     default:
712       GNUNET_break (0);
713       continue;
714     }
715     env = GNUNET_MQ_msg_extra (msg,
716                                alen,
717                                GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
718     msg->add_remove = htonl (add);
719     msg->addr_class = htonl (delta->ac);
720     GNUNET_memcpy (&msg[1],
721                    addr,
722                    alen);
723     GNUNET_MQ_send (ch->mq,
724                     env);
725   }
726 }
727
728
729 /**
730  * Task we run periodically to scan for network interfaces.
731  *
732  * @param cls NULL
733  */ 
734 static void
735 run_scan (void *cls)
736 {
737   struct IfcProcContext ifc_ctx;
738   int found;
739   
740   scan_task = GNUNET_SCHEDULER_add_delayed (SCAN_FREQ,
741                                             &run_scan,
742                                             NULL);
743   memset (&ifc_ctx,
744           0,
745           sizeof (ifc_ctx));
746   GNUNET_OS_network_interfaces_list (&ifc_proc,
747                                      &ifc_ctx);
748   for (struct LocalAddressList *lal = lal_head;
749        NULL != lal;
750        lal = lal->next)
751   {
752     found = GNUNET_NO;
753     for (struct LocalAddressList *pos = ifc_ctx.lal_head;
754          NULL != pos;
755          pos = pos->next)
756     {
757       if ( (pos->af == lal->af) &&
758            (0 == memcmp (lal->addr,
759                          pos->addr,
760                          (AF_INET == lal->af)
761                          ? sizeof (struct in_addr)
762                          : sizeof (struct in6_addr))) )
763         found = GNUNET_YES;
764     }
765     if (GNUNET_NO == found)
766       notify_clients (lal,
767                       GNUNET_NO);
768   }
769
770   for (struct LocalAddressList *pos = ifc_ctx.lal_head;
771        NULL != pos;
772        pos = pos->next)
773   {
774     found = GNUNET_NO;
775     for (struct LocalAddressList *lal = lal_head;
776          NULL != lal;
777          lal = lal->next)
778     {
779       if ( (pos->af == lal->af) &&
780            (0 == memcmp (lal->addr,
781                          pos->addr,
782                          (AF_INET == lal->af)
783                          ? sizeof (struct in_addr)
784                          : sizeof (struct in6_addr))) )
785         found = GNUNET_YES;
786     }
787     if (GNUNET_NO == found)
788       notify_clients (pos,
789                       GNUNET_YES);
790   }
791
792   destroy_lal ();
793   lal_head = ifc_ctx.lal_head;
794   lal_tail = ifc_ctx.lal_tail;
795 }
796
797
798 /**
799  * Handle network size estimate clients.
800  *
801  * @param cls closure
802  * @param c configuration to use
803  * @param service the initialized service
804  */
805 static void
806 run (void *cls,
807      const struct GNUNET_CONFIGURATION_Handle *c,
808      struct GNUNET_SERVICE_Handle *service)
809 {
810   cfg = c;
811   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
812                                  NULL);
813   stats = GNUNET_STATISTICS_create ("nat",
814                                     cfg);
815   scan_task = GNUNET_SCHEDULER_add_now (&run_scan,
816                                         NULL);
817 }
818
819
820 /**
821  * Callback called when a client connects to the service.
822  *
823  * @param cls closure for the service
824  * @param c the new client that connected to the service
825  * @param mq the message queue used to send messages to the client
826  * @return a `struct ClientHandle`
827  */
828 static void *
829 client_connect_cb (void *cls,
830                    struct GNUNET_SERVICE_Client *c,
831                    struct GNUNET_MQ_Handle *mq)
832 {
833   struct ClientHandle *ch;
834
835   ch = GNUNET_new (struct ClientHandle);
836   ch->mq = mq;
837   ch->client = c;
838   GNUNET_CONTAINER_DLL_insert (ch_head,
839                                ch_tail,
840                                ch);
841   return ch;
842 }
843
844
845 /**
846  * Callback called when a client disconnected from the service
847  *
848  * @param cls closure for the service
849  * @param c the client that disconnected
850  * @param internal_cls a `struct ClientHandle *`
851  */
852 static void
853 client_disconnect_cb (void *cls,
854                       struct GNUNET_SERVICE_Client *c,
855                       void *internal_cls)
856 {
857   struct ClientHandle *ch = internal_cls;
858
859   GNUNET_CONTAINER_DLL_remove (ch_head,
860                                ch_tail,
861                                ch);
862   for (unsigned int i=0;i<ch->num_addrs;i++)
863     GNUNET_free_non_null (ch->addrs[i]);
864   GNUNET_free_non_null (ch->addrs);
865   GNUNET_free (ch);
866 }
867
868
869 /**
870  * Define "main" method using service macro.
871  */
872 GNUNET_SERVICE_MAIN
873 ("nat",
874  GNUNET_SERVICE_OPTION_NONE,
875  &run,
876  &client_connect_cb,
877  &client_disconnect_cb,
878  NULL,
879  GNUNET_MQ_hd_var_size (register,
880                         GNUNET_MESSAGE_TYPE_NAT_REGISTER,
881                         struct GNUNET_NAT_RegisterMessage,
882                         NULL),
883  GNUNET_MQ_hd_var_size (stun,
884                         GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN,
885                         struct GNUNET_NAT_HandleStunMessage,
886                         NULL),
887  GNUNET_MQ_hd_var_size (request_connection_reversal,
888                         GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL,
889                         struct GNUNET_NAT_RequestConnectionReversalMessage,
890                         NULL),
891  GNUNET_MQ_hd_fixed_size (test,
892                           GNUNET_MESSAGE_TYPE_NAT_REQUEST_TEST,
893                           struct GNUNET_NAT_RequestTestMessage,
894                           NULL),
895  GNUNET_MQ_hd_var_size (autoconfig_request,
896                         GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG,
897                         struct GNUNET_NAT_AutoconfigRequestMessage,
898                         NULL),
899  GNUNET_MQ_handler_end ());
900
901
902 #if defined(LINUX) && defined(__GLIBC__)
903 #include <malloc.h>
904
905 /**
906  * MINIMIZE heap size (way below 128k) since this process doesn't need much.
907  */
908 void __attribute__ ((constructor))
909 GNUNET_ARM_memory_init ()
910 {
911   mallopt (M_TRIM_THRESHOLD, 4 * 1024);
912   mallopt (M_TOP_PAD, 1 * 1024);
913   malloc_trim (0);
914 }
915 #endif
916
917 /* end of gnunet-service-nat.c */