2 This file is part of GNUnet.
3 Copyright (C) 2016 GNUnet e.V.
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.
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.
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.
22 * @file nat/gnunet-service-nat.c
23 * @brief network address translation traversal service
24 * @author Christian Grothoff
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.
31 * - call GN_start_gnunet_nat_server_() if possible (i.e.
32 * when we find we have a non-global IPv4 address)
33 * - implement autoconfig
34 * - implmeent UPnPC/PMP-based NAT traversal
35 * - implement NEW logic for external IP detection
39 #include "gnunet_util_lib.h"
40 #include "gnunet_protocols.h"
41 #include "gnunet_signatures.h"
42 #include "gnunet_statistics_service.h"
43 #include "gnunet_nat_service.h"
44 #include "gnunet-service-nat_stun.h"
45 #include "gnunet-service-nat_helper.h"
51 * How often should we ask the OS about a list of active
54 #define SCAN_FREQ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
58 * Internal data structure we track for each of our clients.
66 struct ClientHandle *next;
71 struct ClientHandle *prev;
74 * Underlying handle for this client with the service.
76 struct GNUNET_SERVICE_Client *client;
79 * Message queue for communicating with the client.
81 struct GNUNET_MQ_Handle *mq;
84 * Array of addresses used by the service.
86 struct sockaddr **addrs;
89 * What does this client care about?
91 enum GNUNET_NAT_RegisterFlags flags;
94 * Port we would like as we are configured to use this one for
95 * advertising (in addition to the one we are binding to).
100 * Number of addresses that this service is bound to.
105 * Client's IPPROTO, e.g. IPPROTO_UDP or IPPROTO_TCP.
113 * List of local addresses this system has.
115 struct LocalAddressList
118 * This is a linked list.
120 struct LocalAddressList *next;
125 struct LocalAddressList *prev;
128 * The address itself (i.e. `struct sockaddr_in` or `struct
129 * sockaddr_in6`, in the respective byte order).
131 struct sockaddr_storage addr;
139 * What type of address is this?
141 enum GNUNET_NAT_AddressClass ac;
147 * External IP address as given to us via some STUN server.
149 struct StunExternalIP
154 struct StunExternalIP *next;
159 struct StunExternalIP *prev;
162 * Task we run to remove this entry when it is stale.
164 struct GNUNET_SCHEDULER_Task *timeout_task;
167 * Our external IP address as reported by the
170 struct sockaddr_in external_addr;
173 * Address of the reporting STUN server. Used to
174 * detect when a STUN server changes its opinion
175 * to more quickly remove stale results.
177 struct sockaddr_storage stun_server_addr;
180 * Number of bytes used in @e stun_server_addr.
182 size_t stun_server_addr_len;
187 * Timeout to use when STUN data is considered stale.
189 static struct GNUNET_TIME_Relative stun_stale_timeout;
192 * Handle to our current configuration.
194 static const struct GNUNET_CONFIGURATION_Handle *cfg;
197 * Handle to the statistics service.
199 static struct GNUNET_STATISTICS_Handle *stats;
202 * Task scheduled to periodically scan our network interfaces.
204 static struct GNUNET_SCHEDULER_Task *scan_task;
207 * Head of client DLL.
209 static struct ClientHandle *ch_head;
212 * Tail of client DLL.
214 static struct ClientHandle *ch_tail;
217 * Head of DLL of local addresses.
219 static struct LocalAddressList *lal_head;
222 * Tail of DLL of local addresses.
224 static struct LocalAddressList *lal_tail;
229 static struct StunExternalIP *se_head;
234 static struct StunExternalIP *se_tail;
238 * Free the DLL starting at #lal_head.
243 struct LocalAddressList *lal;
245 while (NULL != (lal = lal_head))
247 GNUNET_CONTAINER_DLL_remove (lal_head,
256 * Check validity of #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from
259 * @param cls client who sent the message
260 * @param message the message received
261 * @return #GNUNET_OK if message is well-formed
264 check_register (void *cls,
265 const struct GNUNET_NAT_RegisterMessage *message)
267 uint16_t num_addrs = ntohs (message->num_addrs);
268 const char *off = (const char *) &message[1];
269 size_t left = ntohs (message->header.size) - sizeof (*message);
271 for (unsigned int i=0;i<num_addrs;i++)
274 const struct sockaddr *sa = (const struct sockaddr *) off;
276 if (sizeof (sa_family_t) > left)
279 return GNUNET_SYSERR;
281 switch (sa->sa_family)
284 alen = sizeof (struct sockaddr_in);
287 alen = sizeof (struct sockaddr_in6);
291 alen = sizeof (struct sockaddr_un);
296 return GNUNET_SYSERR;
301 return GNUNET_SYSERR;
309 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REGISTER message from client.
310 * We remember the client for updates upon future NAT events.
312 * @param cls client who sent the message
313 * @param message the message received
316 handle_register (void *cls,
317 const struct GNUNET_NAT_RegisterMessage *message)
319 struct ClientHandle *ch = cls;
323 if ( (0 != ch->proto) ||
324 (NULL != ch->addrs) )
326 /* double registration not allowed */
328 GNUNET_SERVICE_client_drop (ch->client);
331 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
332 "Received REGISTER message from client\n");
333 ch->flags = message->flags;
334 ch->proto = message->proto;
335 ch->adv_port = ntohs (message->adv_port);
336 ch->num_addrs = ntohs (message->adv_port);
337 ch->addrs = GNUNET_new_array (ch->num_addrs,
339 left = ntohs (message->header.size) - sizeof (*message);
340 off = (const char *) &message[1];
341 for (unsigned int i=0;i<ch->num_addrs;i++)
344 const struct sockaddr *sa = (const struct sockaddr *) off;
346 if (sizeof (sa_family_t) > left)
349 GNUNET_SERVICE_client_drop (ch->client);
352 switch (sa->sa_family)
355 alen = sizeof (struct sockaddr_in);
358 alen = sizeof (struct sockaddr_in6);
362 alen = sizeof (struct sockaddr_un);
367 GNUNET_SERVICE_client_drop (ch->client);
370 GNUNET_assert (alen <= left);
371 ch->addrs[i] = GNUNET_malloc (alen);
372 GNUNET_memcpy (ch->addrs[i],
377 GNUNET_SERVICE_client_continue (ch->client);
382 * Check validity of #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from
385 * @param cls client who sent the message
386 * @param message the message received
387 * @return #GNUNET_OK if message is well-formed
390 check_stun (void *cls,
391 const struct GNUNET_NAT_HandleStunMessage *message)
393 size_t sa_len = ntohs (message->sender_addr_size);
394 size_t expect = sa_len + ntohs (message->payload_size);
396 if (ntohs (message->header.size) - sizeof (*message) != expect)
399 return GNUNET_SYSERR;
401 if (sa_len < sizeof (sa_family_t))
404 return GNUNET_SYSERR;
411 * Notify all clients about our external IP address
412 * as reported by the STUN server.
414 * @param ip the external IP
415 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
418 notify_clients_stun_change (const struct sockaddr_in *ip,
421 /* FIXME: notify clients about add/drop */
426 * Function to be called when we decide that an
427 * external IP address as told to us by a STUN
428 * server has gone stale.
430 * @param cls the `struct StunExternalIP` to drop
433 stun_ip_timeout (void *cls)
435 struct StunExternalIP *se = cls;
437 se->timeout_task = NULL;
438 notify_clients_stun_change (&se->external_addr,
440 GNUNET_CONTAINER_DLL_remove (se_head,
448 * Handler for #GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN message from
451 * @param cls client who sent the message
452 * @param message the message received
455 handle_stun (void *cls,
456 const struct GNUNET_NAT_HandleStunMessage *message)
458 struct ClientHandle *ch = cls;
459 const char *buf = (const char *) &message[1];
460 const struct sockaddr *sa;
464 struct sockaddr_in external_addr;
466 sa_len = ntohs (message->sender_addr_size);
467 payload_size = ntohs (message->payload_size);
468 sa = (const struct sockaddr *) &buf[0];
469 payload = (const struct sockaddr *) &buf[sa_len];
470 switch (sa->sa_family)
473 if (sa_len != sizeof (struct sockaddr_in))
476 GNUNET_SERVICE_client_drop (ch->client);
481 if (sa_len != sizeof (struct sockaddr_in6))
484 GNUNET_SERVICE_client_drop (ch->client);
489 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
490 "Received HANDLE_STUN message from client\n");
492 GNUNET_NAT_stun_handle_packet_ (payload,
496 /* We now know that a server at "sa" claims that
497 we are visible at IP "external_addr".
499 We should (for some fixed period of time) tell
500 all of our clients that listen to a NAT'ed address
501 that they might want to consider the given 'external_ip'
502 as their public IP address (this includes TCP and UDP
503 clients, even if only UDP sends STUN requests).
505 If we do not get a renewal, the "external_addr" should be
506 removed again. The timeout frequency should be configurable
507 (with a sane default), so that the UDP plugin can tell how
508 often to re-request STUN.
510 struct StunExternalIP *se;
512 /* Check if we had a prior response from this STUN server */
513 for (se = se_head; NULL != se; se = se->next)
515 if ( (se->stun_server_addr_len != sa_len) ||
517 &se->stun_server_addr,
519 continue; /* different STUN server */
520 if (0 != memcmp (&external_addr,
522 sizeof (struct sockaddr_in)))
524 /* external IP changed, update! */
525 notify_clients_stun_change (&se->external_addr,
527 se->external_addr = external_addr;
528 notify_clients_stun_change (&se->external_addr,
532 GNUNET_SCHEDULER_cancel (se->timeout_task);
534 = GNUNET_SCHEDULER_add_delayed (stun_stale_timeout,
539 /* STUN server is completely new, create fresh entry */
540 se = GNUNET_new (struct StunExternalIP);
541 se->external_addr = external_addr;
542 GNUNET_memcpy (&se->stun_server_addr,
545 se->stun_server_addr_len = sa_len;
546 se->timeout_task = GNUNET_SCHEDULER_add_delayed (stun_stale_timeout,
549 GNUNET_CONTAINER_DLL_insert (se_head,
552 notify_clients_stun_change (&se->external_addr,
555 GNUNET_SERVICE_client_continue (ch->client);
561 * #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL message from
564 * @param cls client who sent the message
565 * @param message the message received
566 * @return #GNUNET_OK if message is well-formed
569 check_request_connection_reversal (void *cls,
570 const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
574 expect = ntohs (message->local_addr_size)
575 + ntohs (message->remote_addr_size);
576 if (ntohs (message->header.size) - sizeof (*message) != expect)
579 return GNUNET_SYSERR;
586 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL
587 * message from client.
589 * @param cls client who sent the message
590 * @param message the message received
593 handle_request_connection_reversal (void *cls,
594 const struct GNUNET_NAT_RequestConnectionReversalMessage *message)
596 struct ClientHandle *ch = cls;
597 const char *buf = (const char *) &message[1];
598 size_t local_sa_len = ntohs (message->local_addr_size);
599 size_t remote_sa_len = ntohs (message->remote_addr_size);
600 const struct sockaddr *local_sa = (const struct sockaddr *) &buf[0];
601 const struct sockaddr *remote_sa = (const struct sockaddr *) &buf[local_sa_len];
603 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
604 "Received REQUEST CONNECTION REVERSAL message from client\n");
605 switch (local_sa->sa_family)
608 if (local_sa_len != sizeof (struct sockaddr_in))
611 GNUNET_SERVICE_client_drop (ch->client);
616 if (local_sa_len != sizeof (struct sockaddr_in6))
619 GNUNET_SERVICE_client_drop (ch->client);
625 GNUNET_SERVICE_client_drop (ch->client);
628 switch (remote_sa->sa_family)
631 if (remote_sa_len != sizeof (struct sockaddr_in))
634 GNUNET_SERVICE_client_drop (ch->client);
639 if (remote_sa_len != sizeof (struct sockaddr_in6))
642 GNUNET_SERVICE_client_drop (ch->client);
648 GNUNET_SERVICE_client_drop (ch->client);
651 /* FIXME: actually run the logic by
652 calling 'GN_request_connection_reversal()' */
654 GNUNET_SERVICE_client_continue (ch->client);
659 * Check validity of #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message
662 * @param cls client who sent the message
663 * @param message the message received
664 * @return #GNUNET_OK if message is well-formed
667 check_autoconfig_request (void *cls,
668 const struct GNUNET_NAT_AutoconfigRequestMessage *message)
670 return GNUNET_OK; /* checked later */
675 * Handler for #GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG message from
678 * @param cls client who sent the message
679 * @param message the message received
682 handle_autoconfig_request (void *cls,
683 const struct GNUNET_NAT_AutoconfigRequestMessage *message)
685 struct ClientHandle *ch = cls;
686 size_t left = ntohs (message->header.size);
687 struct GNUNET_CONFIGURATION_Handle *c;
689 c = GNUNET_CONFIGURATION_create ();
691 GNUNET_CONFIGURATION_deserialize (c,
692 (const char *) &message[1],
697 GNUNET_SERVICE_client_drop (ch->client);
700 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
701 "Received REQUEST_AUTO_CONFIG message from client\n");
702 // FIXME: actually handle request...
703 GNUNET_CONFIGURATION_destroy (c);
704 GNUNET_SERVICE_client_continue (ch->client);
709 * Task run during shutdown.
714 shutdown_task (void *cls)
716 struct StunExternalIP *se;
718 while (NULL != (se = se_head))
720 GNUNET_CONTAINER_DLL_remove (se_head,
723 GNUNET_SCHEDULER_cancel (se->timeout_task);
726 if (NULL != scan_task)
728 GNUNET_SCHEDULER_cancel (scan_task);
733 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
741 * Closure for #ifc_proc.
743 struct IfcProcContext
747 * Head of DLL of local addresses.
749 struct LocalAddressList *lal_head;
752 * Tail of DLL of local addresses.
754 struct LocalAddressList *lal_tail;
760 * Check if @a ip is in @a network with @a bits netmask.
762 * @param network to test
763 * @param ip IP address to test
764 * @param bits bitmask for the network
765 * @return #GNUNET_YES if @a ip is in @a network
768 match_ipv4 (const char *network,
769 const struct in_addr *ip,
776 GNUNET_assert (1 == inet_pton (AF_INET,
779 return ! ((ip->s_addr ^ net.s_addr) & htonl (0xFFFFFFFFu << (32 - bits)));
784 * Check if @a ip is in @a network with @a bits netmask.
786 * @param network to test
787 * @param ip IP address to test
788 * @param bits bitmask for the network
789 * @return #GNUNET_YES if @a ip is in @a network
792 match_ipv6 (const char *network,
793 const struct in6_addr *ip,
797 struct in6_addr mask;
802 GNUNET_assert (1 == inet_pton (AF_INET,
805 memset (&mask, 0, sizeof (mask));
809 mask.s6_addr[off++] = 0xFF;
814 mask.s6_addr[off] = (mask.s6_addr[off] >> 1) + 0x80;
817 for (unsigned j = 0; j < sizeof (struct in6_addr) / sizeof (uint32_t); j++)
818 if (((((uint32_t *) ip)[j] & ((uint32_t *) &mask)[j])) !=
819 (((uint32_t *) &net)[j] & ((int *) &mask)[j]))
826 * Test if the given IPv4 address is in a known range
827 * for private networks.
829 * @param ip address to test
830 * @return #GNUNET_YES if @a ip is in a NAT range
833 is_nat_v4 (const struct in_addr *ip)
836 match_ipv4 ("10.0.0.0", ip, 8) || /* RFC 1918 */
837 match_ipv4 ("100.64.0.0", ip, 10) || /* CG-NAT, RFC 6598 */
838 match_ipv4 ("192.168.0.0", ip, 12) || /* RFC 1918 */
839 match_ipv4 ("169.254.0.0", ip, 16) || /* AUTO, RFC 3927 */
840 match_ipv4 ("172.16.0.0", ip, 16); /* RFC 1918 */
845 * Test if the given IPv6 address is in a known range
846 * for private networks.
848 * @param ip address to test
849 * @return #GNUNET_YES if @a ip is in a NAT range
852 is_nat_v6 (const struct in6_addr *ip)
855 match_ipv6 ("fc00::", ip, 7) || /* RFC 4193 */
856 match_ipv6 ("fec0::", ip, 10) || /* RFC 3879 */
857 match_ipv6 ("fe80::", ip, 10); /* RFC 4291, link-local */
862 * Callback function invoked for each interface found. Adds them
863 * to our new address list.
865 * @param cls a `struct IfcProcContext *`
866 * @param name name of the interface (can be NULL for unknown)
867 * @param isDefault is this presumably the default interface
868 * @param addr address of this interface (can be NULL for unknown or unassigned)
869 * @param broadcast_addr the broadcast address (can be NULL for unknown or unassigned)
870 * @param netmask the network mask (can be NULL for unknown or unassigned)
871 * @param addrlen length of the address
872 * @return #GNUNET_OK to continue iteration, #GNUNET_SYSERR to abort
878 const struct sockaddr *addr,
879 const struct sockaddr *broadcast_addr,
880 const struct sockaddr *netmask,
883 struct IfcProcContext *ifc_ctx = cls;
884 struct LocalAddressList *lal;
886 const struct in_addr *ip4;
887 const struct in6_addr *ip6;
888 enum GNUNET_NAT_AddressClass ac;
890 switch (addr->sa_family)
893 alen = sizeof (struct sockaddr_in);
894 ip4 = &((const struct sockaddr_in *) addr)->sin_addr;
895 if (match_ipv4 ("127.0.0.0", ip4, 8))
896 ac = GNUNET_NAT_AC_LOOPBACK;
897 else if (is_nat_v4 (ip4))
898 ac = GNUNET_NAT_AC_LAN;
900 ac = GNUNET_NAT_AC_GLOBAL;
903 alen = sizeof (struct sockaddr_in6);
904 ip6 = &((const struct sockaddr_in6 *) addr)->sin6_addr;
905 if (match_ipv6 ("::1", ip6, 128))
906 ac = GNUNET_NAT_AC_LOOPBACK;
907 else if (is_nat_v6 (ip6))
908 ac = GNUNET_NAT_AC_LAN;
910 ac = GNUNET_NAT_AC_GLOBAL;
911 if ( (ip6->s6_addr[11] == 0xFF) &&
912 (ip6->s6_addr[12] == 0xFE) )
914 /* contains a MAC, be extra careful! */
915 ac |= GNUNET_NAT_AC_PRIVATE;
927 lal = GNUNET_malloc (sizeof (*lal));
928 lal->af = addr->sa_family;
930 GNUNET_memcpy (&lal->addr,
933 GNUNET_CONTAINER_DLL_insert (ifc_ctx->lal_head,
941 * Notify client about a change in the list
942 * of addresses this peer has.
944 * @param delta the entry in the list that changed
945 * @param ch client to contact
946 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
947 * @param addr the address that changed
948 * @param addr_len number of bytes in @a addr
951 notify_client (struct LocalAddressList *delta,
952 struct ClientHandle *ch,
957 struct GNUNET_MQ_Envelope *env;
958 struct GNUNET_NAT_AddressChangeNotificationMessage *msg;
960 env = GNUNET_MQ_msg_extra (msg,
962 GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE);
963 msg->add_remove = htonl (add);
964 msg->addr_class = htonl (delta->ac);
965 GNUNET_memcpy (&msg[1],
968 GNUNET_MQ_send (ch->mq,
974 * Notify all clients about a change in the list
975 * of addresses this peer has.
977 * @param delta the entry in the list that changed
978 * @param add #GNUNET_YES to add, #GNUNET_NO to remove
981 notify_clients (struct LocalAddressList *delta,
984 for (struct ClientHandle *ch = ch_head;
989 struct sockaddr_in v4;
990 struct sockaddr_in6 v6;
992 if (0 == (ch->flags & GNUNET_NAT_RF_ADDRESSES))
997 alen = sizeof (struct sockaddr_in);
1001 for (unsigned int i=0;i<ch->num_addrs;i++)
1003 const struct sockaddr_in *c4;
1005 if (AF_INET != ch->addrs[i]->sa_family)
1006 continue; /* IPv4 not relevant */
1007 c4 = (const struct sockaddr_in *) ch->addrs[i];
1008 v4.sin_port = c4->sin_port;
1009 notify_client (delta,
1017 alen = sizeof (struct sockaddr_in6);
1021 for (unsigned int i=0;i<ch->num_addrs;i++)
1023 const struct sockaddr_in6 *c6;
1025 if (AF_INET6 != ch->addrs[i]->sa_family)
1026 continue; /* IPv4 not relevant */
1027 c6 = (const struct sockaddr_in6 *) ch->addrs[i];
1028 v6.sin6_port = c6->sin6_port;
1029 notify_client (delta,
1045 * Task we run periodically to scan for network interfaces.
1050 run_scan (void *cls)
1052 struct IfcProcContext ifc_ctx;
1055 scan_task = GNUNET_SCHEDULER_add_delayed (SCAN_FREQ,
1061 GNUNET_OS_network_interfaces_list (&ifc_proc,
1063 for (struct LocalAddressList *lal = lal_head;
1068 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1072 if ( (pos->af == lal->af) &&
1073 (0 == memcmp (&lal->addr,
1075 (AF_INET == lal->af)
1076 ? sizeof (struct sockaddr_in)
1077 : sizeof (struct sockaddr_in6))) )
1080 if (GNUNET_NO == found)
1081 notify_clients (lal,
1085 for (struct LocalAddressList *pos = ifc_ctx.lal_head;
1090 for (struct LocalAddressList *lal = lal_head;
1094 if ( (pos->af == lal->af) &&
1095 (0 == memcmp (&lal->addr,
1097 (AF_INET == lal->af)
1098 ? sizeof (struct sockaddr_in)
1099 : sizeof (struct sockaddr_in6))) )
1102 if (GNUNET_NO == found)
1103 notify_clients (pos,
1108 lal_head = ifc_ctx.lal_head;
1109 lal_tail = ifc_ctx.lal_tail;
1114 * Handle network size estimate clients.
1116 * @param cls closure
1117 * @param c configuration to use
1118 * @param service the initialized service
1122 const struct GNUNET_CONFIGURATION_Handle *c,
1123 struct GNUNET_SERVICE_Handle *service)
1127 GNUNET_CONFIGURATION_get_value_time (cfg,
1130 &stun_stale_timeout))
1131 stun_stale_timeout = GNUNET_TIME_UNIT_HOURS;
1132 GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
1134 stats = GNUNET_STATISTICS_create ("nat",
1136 scan_task = GNUNET_SCHEDULER_add_now (&run_scan,
1142 * Callback called when a client connects to the service.
1144 * @param cls closure for the service
1145 * @param c the new client that connected to the service
1146 * @param mq the message queue used to send messages to the client
1147 * @return a `struct ClientHandle`
1150 client_connect_cb (void *cls,
1151 struct GNUNET_SERVICE_Client *c,
1152 struct GNUNET_MQ_Handle *mq)
1154 struct ClientHandle *ch;
1156 ch = GNUNET_new (struct ClientHandle);
1159 GNUNET_CONTAINER_DLL_insert (ch_head,
1167 * Callback called when a client disconnected from the service
1169 * @param cls closure for the service
1170 * @param c the client that disconnected
1171 * @param internal_cls a `struct ClientHandle *`
1174 client_disconnect_cb (void *cls,
1175 struct GNUNET_SERVICE_Client *c,
1178 struct ClientHandle *ch = internal_cls;
1180 GNUNET_CONTAINER_DLL_remove (ch_head,
1183 for (unsigned int i=0;i<ch->num_addrs;i++)
1184 GNUNET_free_non_null (ch->addrs[i]);
1185 GNUNET_free_non_null (ch->addrs);
1191 * Define "main" method using service macro.
1195 GNUNET_SERVICE_OPTION_NONE,
1198 &client_disconnect_cb,
1200 GNUNET_MQ_hd_var_size (register,
1201 GNUNET_MESSAGE_TYPE_NAT_REGISTER,
1202 struct GNUNET_NAT_RegisterMessage,
1204 GNUNET_MQ_hd_var_size (stun,
1205 GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN,
1206 struct GNUNET_NAT_HandleStunMessage,
1208 GNUNET_MQ_hd_var_size (request_connection_reversal,
1209 GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL,
1210 struct GNUNET_NAT_RequestConnectionReversalMessage,
1212 GNUNET_MQ_hd_var_size (autoconfig_request,
1213 GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG,
1214 struct GNUNET_NAT_AutoconfigRequestMessage,
1216 GNUNET_MQ_handler_end ());
1219 #if defined(LINUX) && defined(__GLIBC__)
1223 * MINIMIZE heap size (way below 128k) since this process doesn't need much.
1225 void __attribute__ ((constructor))
1226 GNUNET_ARM_memory_init ()
1228 mallopt (M_TRIM_THRESHOLD, 4 * 1024);
1229 mallopt (M_TOP_PAD, 1 * 1024);
1234 /* end of gnunet-service-nat.c */