2 This file is part of GNUnet.
3 Copyright (C) 2001-2016 GNUnet e.V.
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your 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 Affero General Public License for more details.
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
18 SPDX-License-Identifier: AGPL3.0-or-later
23 * @brief code for access to services
24 * @author Christian Grothoff
26 * Generic TCP code for reliable, record-oriented TCP
27 * connections between clients and service providers.
30 #include "gnunet_protocols.h"
31 #include "gnunet_util_lib.h"
32 #include "gnunet_resolver_service.h"
33 #include "gnunet_socks.h"
36 #define LOG(kind,...) GNUNET_log_from (kind, "util-client",__VA_ARGS__)
39 * Timeout we use on TCP connect before trying another
40 * result from the DNS resolver. Actual value used
41 * is this value divided by the number of address families.
44 #define CONNECT_RETRY_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
49 * Internal state for a client connected to a GNUnet service.
55 * During connect, we try multiple possible IP addresses
56 * to find out which one might work.
62 * This is a linked list.
64 struct AddressProbe *next;
67 * This is a doubly-linked list.
69 struct AddressProbe *prev;
72 * The address; do not free (allocated at the end of this struct).
74 const struct sockaddr *addr;
77 * Underlying OS's socket.
79 struct GNUNET_NETWORK_Handle *sock;
82 * Connection for which we are probing.
84 struct ClientState *cstate;
92 * Task waiting for the connection to finish connecting.
94 struct GNUNET_SCHEDULER_Task *task;
99 * Internal state for a client connected to a GNUnet service.
105 * The connection handle, NULL if not live
107 struct GNUNET_NETWORK_Handle *sock;
110 * Handle to a pending DNS lookup request, NULL if DNS is finished.
112 struct GNUNET_RESOLVER_RequestHandle *dns_active;
117 const struct GNUNET_CONFIGURATION_Handle *cfg;
120 * Linked list of sockets we are currently trying out
123 struct AddressProbe *ap_head;
126 * Linked list of sockets we are currently trying out
129 struct AddressProbe *ap_tail;
132 * Name of the service we interact with.
142 * Next message to transmit to the service. NULL for none.
144 const struct GNUNET_MessageHeader *msg;
147 * Task for trying to connect to the service.
149 struct GNUNET_SCHEDULER_Task *retry_task;
152 * Task for sending messages to the service.
154 struct GNUNET_SCHEDULER_Task *send_task;
157 * Task for sending messages to the service.
159 struct GNUNET_SCHEDULER_Task *recv_task;
162 * Tokenizer for inbound messages.
164 struct GNUNET_MessageStreamTokenizer *mst;
167 * Message queue under our control.
169 struct GNUNET_MQ_Handle *mq;
172 * Timeout for receiving a response (absolute time).
174 struct GNUNET_TIME_Absolute receive_timeout;
177 * Current value for our incremental back-off (for
180 struct GNUNET_TIME_Relative back_off;
183 * TCP port (0 for disabled).
185 unsigned long long port;
188 * Offset in the message where we are for transmission.
193 * How often have we tried to connect?
195 unsigned int attempts;
198 * Are we supposed to die? #GNUNET_SYSERR if destruction must be
199 * deferred, #GNUNET_NO by default, #GNUNET_YES if destruction was
208 * Try to connect to the service.
210 * @param cls the `struct ClientState` to try to connect to the service
213 start_connect (void *cls);
217 * We've failed for good to establish a connection (timeout or
218 * no more addresses to try).
220 * @param cstate the connection we tried to establish
223 connect_fail_continuation (struct ClientState *cstate)
225 GNUNET_break (NULL == cstate->ap_head);
226 GNUNET_break (NULL == cstate->ap_tail);
227 GNUNET_break (NULL == cstate->dns_active);
228 GNUNET_break (NULL == cstate->sock);
229 GNUNET_assert (NULL == cstate->send_task);
230 GNUNET_assert (NULL == cstate->recv_task);
231 // GNUNET_assert (NULL == cstate->proxy_handshake);
233 cstate->back_off = GNUNET_TIME_STD_BACKOFF (cstate->back_off);
234 LOG (GNUNET_ERROR_TYPE_DEBUG,
235 "Failed to establish connection to `%s', no further addresses to try, will try again in %s.\n",
236 cstate->service_name,
237 GNUNET_STRINGS_relative_time_to_string (cstate->back_off,
240 = GNUNET_SCHEDULER_add_delayed (cstate->back_off,
247 * We are ready to send a message to the service.
249 * @param cls the `struct ClientState` with the `msg` to transmit
252 transmit_ready (void *cls)
254 struct ClientState *cstate = cls;
258 int notify_in_flight;
260 cstate->send_task = NULL;
261 if (GNUNET_YES == cstate->in_destroy)
263 pos = (const char *) cstate->msg;
264 len = ntohs (cstate->msg->size);
265 GNUNET_assert (cstate->msg_off < len);
266 LOG (GNUNET_ERROR_TYPE_DEBUG,
267 "message of type %u trying to send with socket %p (MQ: %p\n",
268 ntohs(cstate->msg->type),
273 ret = GNUNET_NETWORK_socket_send (cstate->sock,
274 &pos[cstate->msg_off],
275 len - cstate->msg_off);
278 LOG (GNUNET_ERROR_TYPE_WARNING,
279 "Error during sending message of type %u\n",
280 ntohs(cstate->msg->type));
282 LOG (GNUNET_ERROR_TYPE_DEBUG,
283 "Retrying message of type %u\n",
284 ntohs(cstate->msg->type));
287 GNUNET_MQ_inject_error (cstate->mq,
288 GNUNET_MQ_ERROR_WRITE);
291 notify_in_flight = (0 == cstate->msg_off);
292 cstate->msg_off += ret;
293 if (cstate->msg_off < len)
295 LOG (GNUNET_ERROR_TYPE_DEBUG,
296 "rescheduling message of type %u\n",
297 ntohs(cstate->msg->type));
299 = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
303 if (notify_in_flight)
304 GNUNET_MQ_impl_send_in_flight (cstate->mq);
307 LOG (GNUNET_ERROR_TYPE_DEBUG,
308 "sending message of type %u successful\n",
309 ntohs(cstate->msg->type));
311 GNUNET_MQ_impl_send_continue (cstate->mq);
316 * We have received a full message, pass to the MQ dispatcher.
317 * Called by the tokenizer via #receive_ready().
319 * @param cls the `struct ClientState`
320 * @param msg message we received.
321 * @return #GNUNET_OK on success,
322 * #GNUNET_NO to stop further processing due to disconnect (no error)
323 * #GNUNET_SYSERR to stop further processing due to error
326 recv_message (void *cls,
327 const struct GNUNET_MessageHeader *msg)
329 struct ClientState *cstate = cls;
331 if (GNUNET_YES == cstate->in_destroy)
333 LOG (GNUNET_ERROR_TYPE_DEBUG,
334 "Received message of type %u and size %u from %s\n",
337 cstate->service_name);
338 GNUNET_MQ_inject_message (cstate->mq,
340 if (GNUNET_YES == cstate->in_destroy)
347 * Cancel all remaining connect attempts
349 * @param cstate handle of the client state to process
352 cancel_aps (struct ClientState *cstate)
354 struct AddressProbe *pos;
356 while (NULL != (pos = cstate->ap_head))
358 GNUNET_break (GNUNET_OK ==
359 GNUNET_NETWORK_socket_close (pos->sock));
360 GNUNET_SCHEDULER_cancel (pos->task);
361 GNUNET_CONTAINER_DLL_remove (cstate->ap_head,
370 * Implement the destruction of a message queue. Implementations must
371 * not free @a mq, but should take care of @a impl_state.
373 * @param mq the message queue to destroy
374 * @param impl_state our `struct ClientState`
377 connection_client_destroy_impl (struct GNUNET_MQ_Handle *mq,
380 struct ClientState *cstate = impl_state;
383 if (NULL != cstate->dns_active)
385 GNUNET_RESOLVER_request_cancel (cstate->dns_active);
386 cstate->dns_active = NULL;
388 if (NULL != cstate->send_task)
390 GNUNET_SCHEDULER_cancel (cstate->send_task);
391 cstate->send_task = NULL;
393 if (NULL != cstate->retry_task)
395 GNUNET_SCHEDULER_cancel (cstate->retry_task);
396 cstate->retry_task = NULL;
398 if (GNUNET_SYSERR == cstate->in_destroy)
400 /* defer destruction */
401 cstate->in_destroy = GNUNET_YES;
405 if (NULL != cstate->recv_task)
407 GNUNET_SCHEDULER_cancel (cstate->recv_task);
408 cstate->recv_task = NULL;
410 if (NULL != cstate->sock)
412 LOG (GNUNET_ERROR_TYPE_DEBUG,
413 "destroying socket: %p\n",
415 GNUNET_NETWORK_socket_close (cstate->sock);
418 GNUNET_free (cstate->service_name);
419 GNUNET_free_non_null (cstate->hostname);
420 GNUNET_MST_destroy (cstate->mst);
421 GNUNET_free (cstate);
426 * This function is called once we have data ready to read.
428 * @param cls `struct ClientState` with connection to read from
431 receive_ready (void *cls)
433 struct ClientState *cstate = cls;
436 cstate->recv_task = NULL;
437 cstate->in_destroy = GNUNET_SYSERR;
438 ret = GNUNET_MST_read (cstate->mst,
442 if (GNUNET_SYSERR == ret)
444 if (NULL != cstate->mq)
445 GNUNET_MQ_inject_error (cstate->mq,
446 GNUNET_MQ_ERROR_READ);
447 if (GNUNET_YES == cstate->in_destroy)
448 connection_client_destroy_impl (cstate->mq,
452 if (GNUNET_YES == cstate->in_destroy)
454 connection_client_destroy_impl (cstate->mq,
458 cstate->in_destroy = GNUNET_NO;
460 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
468 * We've succeeded in establishing a connection.
470 * @param cstate the connection we tried to establish
473 connect_success_continuation (struct ClientState *cstate)
475 GNUNET_assert (NULL == cstate->recv_task);
477 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
481 if (NULL != cstate->msg)
483 GNUNET_assert (NULL == cstate->send_task);
485 = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
494 * Try connecting to the server using UNIX domain sockets.
496 * @param service_name name of service to connect to
497 * @param cfg configuration to use
498 * @return NULL on error, socket connected to UNIX otherwise
500 static struct GNUNET_NETWORK_Handle *
501 try_unixpath (const char *service_name,
502 const struct GNUNET_CONFIGURATION_Handle *cfg)
505 struct GNUNET_NETWORK_Handle *sock;
507 struct sockaddr_un s_un;
511 GNUNET_CONFIGURATION_get_value_filename (cfg,
515 (0 < strlen (unixpath)))
517 /* We have a non-NULL unixpath, need to validate it */
518 if (strlen (unixpath) >= sizeof (s_un.sun_path))
520 LOG (GNUNET_ERROR_TYPE_WARNING,
521 _("UNIXPATH `%s' too long, maximum length is %llu\n"),
523 (unsigned long long) sizeof (s_un.sun_path));
524 unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
525 LOG (GNUNET_ERROR_TYPE_INFO,
526 _("Using `%s' instead\n"),
528 if (NULL == unixpath)
534 s_un.sun_family = AF_UNIX;
535 strncpy (s_un.sun_path,
537 sizeof (s_un.sun_path) - 1);
542 abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
544 "USE_ABSTRACT_SOCKETS");
545 if (GNUNET_YES == abstract)
546 s_un.sun_path[0] = '\0';
549 #if HAVE_SOCKADDR_UN_SUN_LEN
550 s_un.sun_len = (u_char) sizeof (struct sockaddr_un);
552 sock = GNUNET_NETWORK_socket_create (AF_UNIX,
555 if ( (NULL != sock) &&
557 GNUNET_NETWORK_socket_connect (sock,
558 (struct sockaddr *) &s_un,
560 (EINPROGRESS == errno) ) )
562 LOG (GNUNET_ERROR_TYPE_DEBUG,
563 "Successfully connected to unixpath `%s'!\n",
565 GNUNET_free (unixpath);
569 GNUNET_NETWORK_socket_close (sock);
571 GNUNET_free_non_null (unixpath);
578 * Scheduler let us know that we're either ready to write on the
579 * socket OR connect timed out. Do the right thing.
581 * @param cls the `struct AddressProbe *` with the address that we are probing
584 connect_probe_continuation (void *cls)
586 struct AddressProbe *ap = cls;
587 struct ClientState *cstate = ap->cstate;
588 const struct GNUNET_SCHEDULER_TaskContext *tc;
593 GNUNET_assert (NULL != ap->sock);
594 GNUNET_CONTAINER_DLL_remove (cstate->ap_head,
597 len = sizeof (error);
599 tc = GNUNET_SCHEDULER_get_task_context ();
600 if ( (0 == (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) ||
602 GNUNET_NETWORK_socket_getsockopt (ap->sock,
609 GNUNET_break (GNUNET_OK ==
610 GNUNET_NETWORK_socket_close (ap->sock));
612 if ( (NULL == cstate->ap_head) &&
613 // (NULL == cstate->proxy_handshake) &&
614 (NULL == cstate->dns_active) )
615 connect_fail_continuation (cstate);
618 LOG (GNUNET_ERROR_TYPE_DEBUG,
619 "Connection to `%s' succeeded!\n",
620 cstate->service_name);
621 /* trigger jobs that waited for the connection */
622 GNUNET_assert (NULL == cstate->sock);
623 cstate->sock = ap->sock;
626 connect_success_continuation (cstate);
631 * Try to establish a connection given the specified address.
632 * This function is called by the resolver once we have a DNS reply.
634 * @param cls our `struct ClientState *`
635 * @param addr address to try, NULL for "last call"
636 * @param addrlen length of @a addr
639 try_connect_using_address (void *cls,
640 const struct sockaddr *addr,
643 struct ClientState *cstate = cls;
644 struct AddressProbe *ap;
648 cstate->dns_active = NULL;
649 if ( (NULL == cstate->ap_head) &&
650 // (NULL == cstate->proxy_handshake) &&
651 (NULL == cstate->sock) )
652 connect_fail_continuation (cstate);
655 if (NULL != cstate->sock)
656 return; /* already connected */
658 LOG (GNUNET_ERROR_TYPE_DEBUG,
659 "Trying to connect using address `%s:%u'\n",
663 ap = GNUNET_malloc (sizeof (struct AddressProbe) + addrlen);
664 ap->addr = (const struct sockaddr *) &ap[1];
665 GNUNET_memcpy (&ap[1],
668 ap->addrlen = addrlen;
671 switch (ap->addr->sa_family)
674 ((struct sockaddr_in *) ap->addr)->sin_port = htons (cstate->port);
677 ((struct sockaddr_in6 *) ap->addr)->sin6_port = htons (cstate->port);
682 return; /* not supported by us */
684 ap->sock = GNUNET_NETWORK_socket_create (ap->addr->sa_family,
687 if (NULL == ap->sock)
690 return; /* not supported by OS */
693 GNUNET_NETWORK_socket_connect (ap->sock,
696 (EINPROGRESS != errno) )
698 /* maybe refused / unsupported address, try next */
699 GNUNET_log_strerror (GNUNET_ERROR_TYPE_INFO,
701 GNUNET_break (GNUNET_OK ==
702 GNUNET_NETWORK_socket_close (ap->sock));
706 GNUNET_CONTAINER_DLL_insert (cstate->ap_head,
709 ap->task = GNUNET_SCHEDULER_add_write_net (CONNECT_RETRY_TIMEOUT,
711 &connect_probe_continuation,
717 * Test whether the configuration has proper values for connection
718 * (UNIXPATH || (PORT && HOSTNAME)).
720 * @param service_name name of service to connect to
721 * @param cfg configuration to use
722 * @return #GNUNET_OK if the configuration is valid, #GNUNET_SYSERR if not
725 test_service_configuration (const char *service_name,
726 const struct GNUNET_CONFIGURATION_Handle *cfg)
728 int ret = GNUNET_SYSERR;
729 char *hostname = NULL;
730 unsigned long long port;
732 char *unixpath = NULL;
735 GNUNET_CONFIGURATION_get_value_filename (cfg,
739 (0 < strlen (unixpath)))
741 else if ((GNUNET_OK ==
742 GNUNET_CONFIGURATION_have_value (cfg,
746 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
749 _("not a valid filename"));
750 return GNUNET_SYSERR; /* UNIXPATH specified but invalid! */
752 GNUNET_free_non_null (unixpath);
756 GNUNET_CONFIGURATION_have_value (cfg,
760 GNUNET_CONFIGURATION_get_value_number (cfg,
767 GNUNET_CONFIGURATION_get_value_string (cfg,
771 (0 != strlen (hostname)) )
773 GNUNET_free_non_null (hostname);
779 * Try to connect to the service.
781 * @param cls the `struct ClientState` to try to connect to the service
784 start_connect (void *cls)
786 struct ClientState *cstate = cls;
788 cstate->retry_task = NULL;
790 /* Never use a local source if a proxy is configured */
792 GNUNET_SOCKS_check_service (cstate->service_name,
795 socks_connect (cstate);
800 if ( (0 == (cstate->attempts++ % 2)) ||
801 (0 == cstate->port) ||
802 (NULL == cstate->hostname) )
804 /* on even rounds, try UNIX first, or always
805 if we do not have a DNS name and TCP port. */
806 cstate->sock = try_unixpath (cstate->service_name,
808 if (NULL != cstate->sock)
810 connect_success_continuation (cstate);
814 if ( (NULL == cstate->hostname) ||
815 (0 == cstate->port) )
817 /* All options failed. Boo! */
818 connect_fail_continuation (cstate);
822 = GNUNET_RESOLVER_ip_get (cstate->hostname,
824 CONNECT_RETRY_TIMEOUT,
825 &try_connect_using_address,
831 * Implements the transmission functionality of a message queue.
833 * @param mq the message queue
834 * @param msg the message to send
835 * @param impl_state our `struct ClientState`
838 connection_client_send_impl (struct GNUNET_MQ_Handle *mq,
839 const struct GNUNET_MessageHeader *msg,
842 struct ClientState *cstate = impl_state;
845 /* only one message at a time allowed */
846 GNUNET_assert (NULL == cstate->msg);
847 GNUNET_assert (NULL == cstate->send_task);
850 if (NULL == cstate->sock)
852 LOG (GNUNET_ERROR_TYPE_DEBUG,
853 "message of type %u waiting for socket\n",
855 return; /* still waiting for connection */
858 = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
866 * Cancel the currently sent message.
868 * @param mq message queue
869 * @param impl_state our `struct ClientState`
872 connection_client_cancel_impl (struct GNUNET_MQ_Handle *mq,
875 struct ClientState *cstate = impl_state;
878 GNUNET_assert (NULL != cstate->msg);
879 GNUNET_assert (0 == cstate->msg_off);
881 if (NULL != cstate->send_task)
883 GNUNET_SCHEDULER_cancel (cstate->send_task);
884 cstate->send_task = NULL;
890 * Create a message queue to connect to a GNUnet service.
891 * If handlers are specfied, receive messages from the connection.
893 * @param cfg our configuration
894 * @param service_name name of the service to connect to
895 * @param handlers handlers for receiving messages, can be NULL
896 * @param error_handler error handler
897 * @param error_handler_cls closure for the @a error_handler
898 * @return the message queue, NULL on error
900 struct GNUNET_MQ_Handle *
901 GNUNET_CLIENT_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
902 const char *service_name,
903 const struct GNUNET_MQ_MessageHandler *handlers,
904 GNUNET_MQ_ErrorHandler error_handler,
905 void *error_handler_cls)
907 struct ClientState *cstate;
910 test_service_configuration (service_name,
913 cstate = GNUNET_new (struct ClientState);
914 cstate->service_name = GNUNET_strdup (service_name);
916 cstate->retry_task = GNUNET_SCHEDULER_add_now (&start_connect,
918 cstate->mst = GNUNET_MST_create (&recv_message,
921 GNUNET_CONFIGURATION_have_value (cfg,
925 if (! ( (GNUNET_OK !=
926 GNUNET_CONFIGURATION_get_value_number (cfg,
930 (cstate->port > 65535) ||
932 GNUNET_CONFIGURATION_get_value_string (cfg,
935 &cstate->hostname)) ) &&
936 (0 == strlen (cstate->hostname)) )
938 GNUNET_free (cstate->hostname);
939 cstate->hostname = NULL;
940 LOG (GNUNET_ERROR_TYPE_WARNING,
941 _("Need a non-empty hostname for service `%s'.\n"),
945 cstate->mq = GNUNET_MQ_queue_for_callbacks (&connection_client_send_impl,
946 &connection_client_destroy_impl,
947 &connection_client_cancel_impl,
955 /* end of client.c */