2 This file is part of GNUnet.
3 Copyright (C) 2007-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 * @author Christian Grothoff
23 * @author Milan Bouchet-Valat
26 * Service for handling UPnP and NAT-PMP port forwarding
27 * and external IP address retrieval
30 #include "gnunet_nat_service.h"
36 * Entry in DLL of addresses of this peer.
44 struct AddrEntry *next;
49 struct AddrEntry *prev;
52 * Number of bytes that follow.
59 * Handle for active NAT registrations.
61 struct GNUNET_NAT_Handle
65 * Configuration we use.
67 const struct GNUNET_CONFIGURATION_Handle *cfg;
70 * Message queue for communicating with the NAT service.
72 struct GNUNET_MQ_Handle *mq;
75 * Our registration message.
77 struct GNUNET_MessageHeader *reg;
80 * Head of address DLL.
82 struct AddrEntry *ae_head;
85 * Tail of address DLL.
87 struct AddrEntry *ae_tail;
90 * Function to call when our addresses change.
92 GNUNET_NAT_AddressCallback address_callback;
95 * Function to call when another peer requests connection reversal.
97 GNUNET_NAT_ReversalCallback reversal_callback;
100 * Closure for the various callbacks.
105 * Task scheduled to reconnect to the service.
107 struct GNUNET_SCHEDULER_Task *reconnect_task;
110 * How long to wait until we reconnect.
112 struct GNUNET_TIME_Relative reconnect_delay;
117 * Task to connect to the NAT service.
119 * @param cls our `struct GNUNET_NAT_Handle *`
122 do_connect (void *cls);
126 * Task to connect to the NAT service.
128 * @param nh handle to reconnect
131 reconnect (struct GNUNET_NAT_Handle *nh)
135 GNUNET_MQ_destroy (nh->mq);
139 = GNUNET_TIME_STD_BACKOFF (nh->reconnect_delay);
141 = GNUNET_SCHEDULER_add_delayed (nh->reconnect_delay,
148 * Check connection reversal request.
150 * @param cls our `struct GNUNET_NAT_Handle`
151 * @param crm the message
152 * @return #GNUNET_OK if @a crm is well-formed
155 check_connection_reversal_request (void *cls,
156 const struct GNUNET_NAT_ConnectionReversalRequestedMessage *crm)
158 if (ntohs (crm->header.size) !=
160 ntohs (crm->local_addr_size) +
161 ntohs (crm->remote_addr_size) )
164 return GNUNET_SYSERR;
166 if ( (sizeof (struct sockaddr_in) != ntohs (crm->local_addr_size)) ||
167 (sizeof (struct sockaddr_in) != ntohs (crm->remote_addr_size)) )
170 return GNUNET_SYSERR;
177 * Handle connection reversal request.
179 * @param cls our `struct GNUNET_NAT_Handle`
180 * @param crm the message
183 handle_connection_reversal_request (void *cls,
184 const struct GNUNET_NAT_ConnectionReversalRequestedMessage *crm)
186 struct GNUNET_NAT_Handle *nh = cls;
187 const struct sockaddr_in *local_sa = (const struct sockaddr_in *) &crm[1];
188 const struct sockaddr_in *remote_sa = &local_sa[1];
190 nh->reversal_callback (nh->callback_cls,
191 (const struct sockaddr *) local_sa,
192 sizeof (struct sockaddr_in),
193 (const struct sockaddr *) remote_sa,
194 sizeof (struct sockaddr_in));
199 * Check address change notification.
201 * @param cls our `struct GNUNET_NAT_Handle`
202 * @param acn the message
203 * @return #GNUNET_OK if @a crm is well-formed
206 check_address_change_notification (void *cls,
207 const struct GNUNET_NAT_AddressChangeNotificationMessage *acn)
209 size_t alen = ntohs (acn->header.size) - sizeof (*acn);
213 case sizeof (struct sockaddr_in):
215 const struct sockaddr_in *s4
216 = (const struct sockaddr_in *) &acn[1];
217 if (AF_INET != s4->sin_family)
220 return GNUNET_SYSERR;
224 case sizeof (struct sockaddr_in6):
226 const struct sockaddr_in6 *s6
227 = (const struct sockaddr_in6 *) &acn[1];
228 if (AF_INET6 != s6->sin6_family)
231 return GNUNET_SYSERR;
237 return GNUNET_SYSERR;
244 * Handle connection reversal request.
246 * @param cls our `struct GNUNET_NAT_Handle`
247 * @param acn the message
250 handle_address_change_notification (void *cls,
251 const struct GNUNET_NAT_AddressChangeNotificationMessage *acn)
253 struct GNUNET_NAT_Handle *nh = cls;
254 size_t alen = ntohs (acn->header.size) - sizeof (*acn);
255 const struct sockaddr *sa = (const struct sockaddr *) &acn[1];
256 enum GNUNET_NAT_AddressClass ac;
257 struct AddrEntry *ae;
259 ac = (enum GNUNET_NAT_AddressClass) ntohl (acn->addr_class);
260 if (GNUNET_YES == ntohl (acn->add_remove))
262 ae = GNUNET_malloc (sizeof (*ae) + alen);
264 GNUNET_memcpy (&ae[1],
267 GNUNET_CONTAINER_DLL_insert (nh->ae_head,
273 for (ae = nh->ae_head; NULL != ae; ae = ae->next)
274 if ( (ae->addrlen == alen) &&
275 (0 == memcmp (&ae[1],
285 GNUNET_CONTAINER_DLL_remove (nh->ae_head,
290 nh->address_callback (nh->callback_cls,
291 ntohl (acn->add_remove),
299 * Handle queue errors by reconnecting to NAT.
301 * @param cls the `struct GNUNET_NAT_Handle *`
302 * @param error details about the error
305 mq_error_handler (void *cls,
306 enum GNUNET_MQ_Error error)
308 struct GNUNET_NAT_Handle *nh = cls;
315 * Task to connect to the NAT service.
317 * @param cls our `struct GNUNET_NAT_Handle *`
320 do_connect (void *cls)
322 struct GNUNET_NAT_Handle *nh = cls;
323 struct GNUNET_MQ_MessageHandler handlers[] = {
324 GNUNET_MQ_hd_var_size (connection_reversal_request,
325 GNUNET_MESSAGE_TYPE_NAT_CONNECTION_REVERSAL_REQUESTED,
326 struct GNUNET_NAT_ConnectionReversalRequestedMessage,
328 GNUNET_MQ_hd_var_size (address_change_notification,
329 GNUNET_MESSAGE_TYPE_NAT_ADDRESS_CHANGE,
330 struct GNUNET_NAT_AddressChangeNotificationMessage,
332 GNUNET_MQ_handler_end ()
335 nh->reconnect_task = NULL;
336 nh->mq = GNUNET_CLIENT_connecT (nh->cfg,
347 * Attempt to enable port redirection and detect public IP address
348 * contacting UPnP or NAT-PMP routers on the local network. Use @a
349 * addr to specify to which of the local host's addresses should the
350 * external port be mapped. The port is taken from the corresponding
351 * sockaddr_in[6] field. The NAT module should call the given @a
352 * address_callback for any 'plausible' external address.
354 * @param cfg configuration to use
355 * @param proto protocol this is about, IPPROTO_TCP or IPPROTO_UDP
356 * @param adv_port advertised port (port we are either bound to or that our OS
357 * locally performs redirection from to our bound port).
358 * @param num_addrs number of addresses in @a addrs
359 * @param addrs list of local addresses packets should be redirected to
360 * @param addrlens actual lengths of the addresses in @a addrs
361 * @param address_callback function to call everytime the public IP address changes
362 * @param reversal_callback function to call if someone wants connection reversal from us,
363 * NULL if connection reversal is not supported
364 * @param callback_cls closure for callbacks
365 * @return NULL on error, otherwise handle that can be used to unregister
367 struct GNUNET_NAT_Handle *
368 GNUNET_NAT_register (const struct GNUNET_CONFIGURATION_Handle *cfg,
371 unsigned int num_addrs,
372 const struct sockaddr **addrs,
373 const socklen_t *addrlens,
374 GNUNET_NAT_AddressCallback address_callback,
375 GNUNET_NAT_ReversalCallback reversal_callback,
378 struct GNUNET_NAT_Handle *nh;
379 struct GNUNET_NAT_RegisterMessage *rm;
384 for (unsigned int i=0;i<num_addrs;i++)
386 if ( (len > GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (*rm)) ||
387 (num_addrs > UINT16_MAX) )
392 rm = GNUNET_malloc (sizeof (*rm) + len);
393 rm->header.size = htons (sizeof (*rm) + len);
394 rm->header.type = htons (GNUNET_MESSAGE_TYPE_NAT_REGISTER);
395 rm->flags = GNUNET_NAT_RF_NONE;
396 if (NULL != address_callback)
397 rm->flags |= GNUNET_NAT_RF_ADDRESSES;
398 if (NULL != reversal_callback)
399 rm->flags |= GNUNET_NAT_RF_REVERSAL;
401 rm->adv_port = htons (adv_port);
402 rm->num_addrs = htons ((uint16_t) num_addrs);
403 off = (char *) &rm[1];
404 for (unsigned int i=0;i<num_addrs;i++)
412 nh = GNUNET_new (struct GNUNET_NAT_Handle);
413 nh->reg = &rm->header;
415 nh->address_callback = address_callback;
416 nh->reversal_callback = reversal_callback;
417 nh->callback_cls = callback_cls;
425 * Check if an incoming message is a STUN message.
427 * @param data the packet
428 * @param len the length of the packet in @a data
429 * @return #GNUNET_YES if @a data is a STUN packet,
430 * #GNUNET_NO if the packet is invalid (not a stun packet)
433 test_stun_packet (const void *data,
436 const struct stun_header *hdr;
437 const struct stun_attr *attr;
438 uint32_t advertised_message_size;
439 uint32_t message_magic_cookie;
441 /* On entry, 'len' is the length of the UDP payload. After the
442 * initial checks it becomes the size of unprocessed options,
443 * while 'data' is advanced accordingly.
445 if (len < sizeof(struct stun_header))
447 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
448 "STUN packet too short (only %d, wanting at least %d)\n",
450 (int) sizeof (struct stun_header));
453 hdr = (const struct stun_header *) data;
454 /* Skip header as it is already in hdr */
455 len -= sizeof (struct stun_header);
456 data += sizeof (struct stun_header);
458 /* len as advertised in the message */
459 advertised_message_size = ntohs (hdr->msglen);
461 message_magic_cookie = ntohl (hdr->magic);
462 /* Compare if the cookie match */
463 if (STUN_MAGIC_COOKIE != message_magic_cookie)
465 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
466 "Invalid magic cookie for STUN\n");
470 if (advertised_message_size > len)
472 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
473 "Scrambled STUN packet length (got %d, expecting %d)\n",
474 advertised_message_size,
478 len = advertised_message_size;
481 if (len < sizeof (struct stun_attr))
483 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
484 "Attribute too short in STUN packet (got %d, expecting %d)\n",
486 (int) sizeof(struct stun_attr));
489 attr = (const struct stun_attr *) data;
491 /* compute total attribute length */
492 advertised_message_size = ntohs (attr->len) + sizeof(struct stun_attr);
494 /* Check if we still have space in our buffer */
495 if (advertised_message_size > len)
497 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
498 "Inconsistent Attribute (length %d exceeds remaining msg len %d)\n",
499 advertised_message_size,
503 data += advertised_message_size;
504 len -= advertised_message_size;
506 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
507 "STUN Packet, msg %04x, length: %d\n",
508 ntohs (hdr->msgtype),
509 advertised_message_size);
515 * Handle an incoming STUN message. This function is useful as
516 * some GNUnet service may be listening on a UDP port and might
517 * thus receive STUN messages while trying to receive other data.
518 * In this case, this function can be used to act as a proper
519 * STUN server (if desired).
521 * The function does some basic sanity checks on packet size and
522 * content, try to extract a bit of information, and possibly replies
523 * if this is an actual STUN message.
525 * At the moment this only processes BIND requests, and returns the
526 * externally visible address of the request.
528 * @param nh handle to the NAT service
529 * @param sender_addr address from which we got @a data
530 * @param sender_addr_len number of bytes in @a sender_addr
531 * @param data the packet
532 * @param data_size number of bytes in @a data
533 * @return #GNUNET_OK on success
534 * #GNUNET_NO if the packet is not a STUN packet
535 * #GNUNET_SYSERR on internal error handling the packet
538 GNUNET_NAT_stun_handle_packet (struct GNUNET_NAT_Handle *nh,
539 const struct sockaddr *sender_addr,
540 size_t sender_addr_len,
544 struct GNUNET_MQ_Envelope *env;
545 struct GNUNET_NAT_HandleStunMessage *hsn;
549 test_stun_packet (data,
553 return GNUNET_SYSERR;
554 env = GNUNET_MQ_msg_extra (hsn,
555 data_size + sender_addr_len,
556 GNUNET_MESSAGE_TYPE_NAT_HANDLE_STUN);
557 hsn->sender_addr_size = htons ((uint16_t) sender_addr_len);
558 hsn->payload_size = htons ((uint16_t) data_size);
559 buf = (char *) &hsn[1];
563 buf += sender_addr_len;
567 GNUNET_MQ_send (nh->mq,
574 * Test if the given address is (currently) a plausible IP address for
575 * this peer. Mostly a convenience function so that clients do not
576 * have to explicitly track all IPs that the #GNUNET_NAT_AddressCallback
577 * has returned so far.
579 * @param nh the handle returned by register
580 * @param addr IP address to test (IPv4 or IPv6)
581 * @param addrlen number of bytes in @a addr
582 * @return #GNUNET_YES if the address is plausible,
583 * #GNUNET_NO if the address is not plausible,
584 * #GNUNET_SYSERR if the address is malformed
587 GNUNET_NAT_test_address (struct GNUNET_NAT_Handle *nh,
591 struct AddrEntry *ae;
593 if ( (addrlen != sizeof (struct sockaddr_in)) &&
594 (addrlen != sizeof (struct sockaddr_in6)) )
597 return GNUNET_SYSERR;
599 for (ae = nh->ae_head; NULL != ae; ae = ae->next)
600 if ( (addrlen == ae->addrlen) &&
610 * We learned about a peer (possibly behind NAT) so run the
611 * gnunet-nat-client to send dummy ICMP responses to cause
612 * that peer to connect to us (connection reversal).
614 * @param nh handle (used for configuration)
615 * @param local_sa our local address of the peer (IPv4-only)
616 * @param remote_sa the remote address of the peer (IPv4-only)
617 * @return #GNUNET_SYSERR on error,
618 * #GNUNET_NO if connection reversal is unavailable,
619 * #GNUNET_OK otherwise (presumably in progress)
622 GNUNET_NAT_request_reversal (struct GNUNET_NAT_Handle *nh,
623 const struct sockaddr_in *local_sa,
624 const struct sockaddr_in *remote_sa)
626 struct GNUNET_MQ_Envelope *env;
627 struct GNUNET_NAT_RequestConnectionReversalMessage *req;
631 return GNUNET_SYSERR;
632 env = GNUNET_MQ_msg_extra (req,
633 2 * sizeof (struct sockaddr_in),
634 GNUNET_MESSAGE_TYPE_NAT_REQUEST_CONNECTION_REVERSAL);
635 req->local_addr_size = htons (sizeof (struct sockaddr_in));
636 req->remote_addr_size = htons (sizeof (struct sockaddr_in));
637 buf = (char *) &req[1];
640 sizeof (struct sockaddr_in));
641 buf += sizeof (struct sockaddr_in);
644 sizeof (struct sockaddr_in));
645 GNUNET_MQ_send (nh->mq,
652 * Stop port redirection and public IP address detection for the given
653 * handle. This frees the handle, after having sent the needed
654 * commands to close open ports.
656 * @param nh the handle to stop
659 GNUNET_NAT_unregister (struct GNUNET_NAT_Handle *nh)
661 GNUNET_MQ_destroy (nh->mq);
662 GNUNET_free (nh->reg);
668 * Handle to a NAT test.
670 struct GNUNET_NAT_Test
674 * Configuration we use.
676 const struct GNUNET_CONFIGURATION_Handle *cfg;
679 * Message queue for communicating with the NAT service.
681 struct GNUNET_MQ_Handle *mq;
684 * Function called to report success or failure for
685 * NAT configuration test.
687 GNUNET_NAT_TestCallback cb;
698 * Handle result for a NAT test from the service.
700 * @param cls our `struct GNUNET_NAT_Test *`
701 * @param rm message with the result of the test
704 handle_test_result (void *cls,
705 const struct GNUNET_NAT_TestResultMessage *rm)
707 struct GNUNET_NAT_Test *tst = cls;
708 enum GNUNET_NAT_StatusCode sc;
710 sc = (enum GNUNET_NAT_StatusCode) ntohl (rm->status_code);
711 tst->cb (tst->cb_cls,
713 GNUNET_NAT_test_stop (tst);
718 * Handle queue errors by reporting test failure.
720 * @param cls the `struct GNUNET_NAT_Test *`
721 * @param error details about the error
724 tst_error_handler (void *cls,
725 enum GNUNET_MQ_Error error)
727 struct GNUNET_NAT_Test *tst = cls;
729 tst->cb (tst->cb_cls,
730 GNUNET_NAT_ERROR_IPC_FAILURE);
731 GNUNET_NAT_test_stop (tst);
736 * Start testing if NAT traversal works using the given configuration
737 * (IPv4-only). The transport adapters should be down while using
740 * @param cfg configuration for the NAT traversal
741 * @param proto protocol to test, i.e. IPPROTO_TCP or IPPROTO_UDP
742 * @param bind_ip IPv4 address to bind to
743 * @param bnd_port port to bind to, 0 to test connection reversal
744 * @param extern_ip IPv4 address to externally advertise
745 * @param extern_port externally advertised port to use
746 * @param report function to call with the result of the test
747 * @param report_cls closure for @a report
748 * @return handle to cancel NAT test
750 struct GNUNET_NAT_Test *
751 GNUNET_NAT_test_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
753 struct in_addr bind_ip,
755 struct in_addr extern_ip,
756 uint16_t extern_port,
757 GNUNET_NAT_TestCallback report,
760 struct GNUNET_NAT_Test *tst = GNUNET_new (struct GNUNET_NAT_Test);
761 struct GNUNET_MQ_MessageHandler handlers[] = {
762 GNUNET_MQ_hd_fixed_size (test_result,
763 GNUNET_MESSAGE_TYPE_NAT_TEST_RESULT,
764 struct GNUNET_NAT_TestResultMessage,
766 GNUNET_MQ_handler_end ()
768 struct GNUNET_MQ_Envelope *env;
769 struct GNUNET_NAT_RequestTestMessage *req;
772 tst->cb_cls = report_cls;
773 tst->mq = GNUNET_CLIENT_connecT (cfg,
784 env = GNUNET_MQ_msg (req,
785 GNUNET_MESSAGE_TYPE_NAT_REQUEST_TEST);
786 req->bind_port = htons (bnd_port);
787 req->extern_port = htons (extern_port);
788 req->bind_ip = bind_ip;
789 req->extern_ip = extern_ip;
791 GNUNET_MQ_send (tst->mq,
798 * Stop an active NAT test.
800 * @param tst test to stop.
803 GNUNET_NAT_test_stop (struct GNUNET_NAT_Test *tst)
805 GNUNET_MQ_destroy (tst->mq);
811 * Handle to auto-configuration in progress.
813 struct GNUNET_NAT_AutoHandle
817 * Configuration we use.
819 const struct GNUNET_CONFIGURATION_Handle *cfg;
822 * Message queue for communicating with the NAT service.
824 struct GNUNET_MQ_Handle *mq;
827 * Function called with the result from the autoconfiguration.
829 GNUNET_NAT_AutoResultCallback arc;
832 * Closure for @e arc.
840 * Converts `enum GNUNET_NAT_StatusCode` to string
842 * @param err error code to resolve to a string
843 * @return point to a static string containing the error code
846 GNUNET_NAT_status2string (enum GNUNET_NAT_StatusCode err)
850 case GNUNET_NAT_ERROR_SUCCESS:
851 return _ ("Operation Successful");
852 case GNUNET_NAT_ERROR_IPC_FAILURE:
853 return _ ("Internal Failure (IPC, ...)");
854 case GNUNET_NAT_ERROR_INTERNAL_NETWORK_ERROR:
855 return _ ("Failure in network subsystem, check permissions.");
856 case GNUNET_NAT_ERROR_TIMEOUT:
857 return _ ("Encountered timeout while performing operation");
858 case GNUNET_NAT_ERROR_NOT_ONLINE:
859 return _ ("detected that we are offline");
860 case GNUNET_NAT_ERROR_UPNPC_NOT_FOUND:
861 return _ ("`upnpc` command not found");
862 case GNUNET_NAT_ERROR_UPNPC_FAILED:
863 return _ ("Failed to run `upnpc` command");
864 case GNUNET_NAT_ERROR_UPNPC_TIMEOUT:
865 return _ ("`upnpc' command took too long, process killed");
866 case GNUNET_NAT_ERROR_UPNPC_PORTMAP_FAILED:
867 return _ ("`upnpc' command failed to establish port mapping");
868 case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_NOT_FOUND:
869 return _ ("`external-ip' command not found");
870 case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_FAILED:
871 return _ ("Failed to run `external-ip` command");
872 case GNUNET_NAT_ERROR_EXTERNAL_IP_UTILITY_OUTPUT_INVALID:
873 return _ ("`external-ip' command output invalid");
874 case GNUNET_NAT_ERROR_EXTERNAL_IP_ADDRESS_INVALID:
875 return _ ("no valid address was returned by `external-ip'");
876 case GNUNET_NAT_ERROR_NO_VALID_IF_IP_COMBO:
877 return _ ("Could not determine interface with internal/local network address");
878 case GNUNET_NAT_ERROR_HELPER_NAT_SERVER_NOT_FOUND:
879 return _ ("No functioning gnunet-helper-nat-server installation found");
880 case GNUNET_NAT_ERROR_NAT_TEST_START_FAILED:
881 return _ ("NAT test could not be initialized");
882 case GNUNET_NAT_ERROR_NAT_TEST_TIMEOUT:
883 return _ ("NAT test timeout reached");
884 case GNUNET_NAT_ERROR_NAT_REGISTER_FAILED:
885 return _ ("could not register NAT");
886 case GNUNET_NAT_ERROR_HELPER_NAT_CLIENT_NOT_FOUND:
887 return _ ("No working gnunet-helper-nat-client installation found");
889 return "unknown status code";
895 * Check result from autoconfiguration attempt.
897 * @param cls the `struct GNUNET_NAT_AutoHandle`
898 * @param res the result
899 * @return #GNUNET_OK if @a res is well-formed (always for now)
902 check_auto_result (void *cls,
903 const struct GNUNET_NAT_AutoconfigResultMessage *res)
910 * Handle result from autoconfiguration attempt.
912 * @param cls the `struct GNUNET_NAT_AutoHandle`
913 * @param res the result
916 handle_auto_result (void *cls,
917 const struct GNUNET_NAT_AutoconfigResultMessage *res)
919 struct GNUNET_NAT_AutoHandle *ah = cls;
921 struct GNUNET_CONFIGURATION_Handle *cfg;
922 enum GNUNET_NAT_Type type
923 = (enum GNUNET_NAT_Type) ntohl (res->type);
924 enum GNUNET_NAT_StatusCode status
925 = (enum GNUNET_NAT_StatusCode) ntohl (res->status_code);
927 left = ntohs (res->header.size) - sizeof (*res);
928 cfg = GNUNET_CONFIGURATION_create ();
930 GNUNET_CONFIGURATION_deserialize (cfg,
931 (const char *) &res[1],
936 ah->arc (ah->arc_cls,
938 GNUNET_NAT_ERROR_IPC_FAILURE,
943 ah->arc (ah->arc_cls,
948 GNUNET_CONFIGURATION_destroy (cfg);
949 GNUNET_NAT_autoconfig_cancel (ah);
954 * Handle queue errors by reporting autoconfiguration failure.
956 * @param cls the `struct GNUNET_NAT_AutoHandle *`
957 * @param error details about the error
960 ah_error_handler (void *cls,
961 enum GNUNET_MQ_Error error)
963 struct GNUNET_NAT_AutoHandle *ah = cls;
965 ah->arc (ah->arc_cls,
967 GNUNET_NAT_ERROR_IPC_FAILURE,
968 GNUNET_NAT_TYPE_UNKNOWN);
969 GNUNET_NAT_autoconfig_cancel (ah);
974 * Start auto-configuration routine. The transport adapters should
975 * be stopped while this function is called.
977 * @param cfg initial configuration
978 * @param cb function to call with autoconfiguration result
979 * @param cb_cls closure for @a cb
980 * @return handle to cancel operation
982 struct GNUNET_NAT_AutoHandle *
983 GNUNET_NAT_autoconfig_start (const struct GNUNET_CONFIGURATION_Handle *cfg,
984 GNUNET_NAT_AutoResultCallback cb,
987 struct GNUNET_NAT_AutoHandle *ah = GNUNET_new (struct GNUNET_NAT_AutoHandle);
988 struct GNUNET_MQ_MessageHandler handlers[] = {
989 GNUNET_MQ_hd_var_size (auto_result,
990 GNUNET_MESSAGE_TYPE_NAT_AUTO_CFG_RESULT,
991 struct GNUNET_NAT_AutoconfigResultMessage,
993 GNUNET_MQ_handler_end ()
995 struct GNUNET_MQ_Envelope *env;
996 struct GNUNET_NAT_AutoconfigRequestMessage *req;
1000 buf = GNUNET_CONFIGURATION_serialize (cfg,
1002 if (size > GNUNET_SERVER_MAX_MESSAGE_SIZE - sizeof (*req))
1010 ah->arc_cls = cb_cls;
1011 ah->mq = GNUNET_CLIENT_connecT (cfg,
1023 env = GNUNET_MQ_msg_extra (req,
1025 GNUNET_MESSAGE_TYPE_NAT_REQUEST_AUTO_CFG);
1026 GNUNET_memcpy (&req[1],
1030 GNUNET_MQ_send (ah->mq,
1037 * Abort autoconfiguration.
1039 * @param ah handle for operation to abort
1042 GNUNET_NAT_autoconfig_cancel (struct GNUNET_NAT_AutoHandle *ah)
1044 GNUNET_MQ_destroy (ah->mq);
1048 /* end of nat_api.c */