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.
18 * @brief code for access to services
19 * @author Christian Grothoff
21 * Generic TCP code for reliable, record-oriented TCP
22 * connections between clients and service providers.
25 #include "gnunet_protocols.h"
26 #include "gnunet_util_lib.h"
27 #include "gnunet_resolver_service.h"
28 #include "gnunet_socks.h"
31 #define LOG(kind,...) GNUNET_log_from (kind, "util-client",__VA_ARGS__)
34 * Timeout we use on TCP connect before trying another
35 * result from the DNS resolver. Actual value used
36 * is this value divided by the number of address families.
39 #define CONNECT_RETRY_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
44 * Internal state for a client connected to a GNUnet service.
50 * During connect, we try multiple possible IP addresses
51 * to find out which one might work.
57 * This is a linked list.
59 struct AddressProbe *next;
62 * This is a doubly-linked list.
64 struct AddressProbe *prev;
67 * The address; do not free (allocated at the end of this struct).
69 const struct sockaddr *addr;
72 * Underlying OS's socket.
74 struct GNUNET_NETWORK_Handle *sock;
77 * Connection for which we are probing.
79 struct ClientState *cstate;
87 * Task waiting for the connection to finish connecting.
89 struct GNUNET_SCHEDULER_Task *task;
94 * Internal state for a client connected to a GNUnet service.
100 * The connection handle, NULL if not live
102 struct GNUNET_NETWORK_Handle *sock;
105 * Handle to a pending DNS lookup request, NULL if DNS is finished.
107 struct GNUNET_RESOLVER_RequestHandle *dns_active;
112 const struct GNUNET_CONFIGURATION_Handle *cfg;
115 * Linked list of sockets we are currently trying out
118 struct AddressProbe *ap_head;
121 * Linked list of sockets we are currently trying out
124 struct AddressProbe *ap_tail;
127 * Name of the service we interact with.
137 * Next message to transmit to the service. NULL for none.
139 const struct GNUNET_MessageHeader *msg;
142 * Task for trying to connect to the service.
144 struct GNUNET_SCHEDULER_Task *retry_task;
147 * Task for sending messages to the service.
149 struct GNUNET_SCHEDULER_Task *send_task;
152 * Task for sending messages to the service.
154 struct GNUNET_SCHEDULER_Task *recv_task;
157 * Tokenizer for inbound messages.
159 struct GNUNET_MessageStreamTokenizer *mst;
162 * Message queue under our control.
164 struct GNUNET_MQ_Handle *mq;
167 * Timeout for receiving a response (absolute time).
169 struct GNUNET_TIME_Absolute receive_timeout;
172 * Current value for our incremental back-off (for
175 struct GNUNET_TIME_Relative back_off;
178 * TCP port (0 for disabled).
180 unsigned long long port;
183 * Offset in the message where we are for transmission.
188 * How often have we tried to connect?
190 unsigned int attempts;
193 * Are we supposed to die? #GNUNET_SYSERR if destruction must be
194 * deferred, #GNUNET_NO by default, #GNUNET_YES if destruction was
203 * Try to connect to the service.
205 * @param cls the `struct ClientState` to try to connect to the service
208 start_connect (void *cls);
212 * We've failed for good to establish a connection (timeout or
213 * no more addresses to try).
215 * @param cstate the connection we tried to establish
218 connect_fail_continuation (struct ClientState *cstate)
220 GNUNET_break (NULL == cstate->ap_head);
221 GNUNET_break (NULL == cstate->ap_tail);
222 GNUNET_break (NULL == cstate->dns_active);
223 GNUNET_break (NULL == cstate->sock);
224 GNUNET_assert (NULL == cstate->send_task);
225 GNUNET_assert (NULL == cstate->recv_task);
226 // GNUNET_assert (NULL == cstate->proxy_handshake);
228 cstate->back_off = GNUNET_TIME_STD_BACKOFF (cstate->back_off);
229 LOG (GNUNET_ERROR_TYPE_DEBUG,
230 "Failed to establish connection to `%s', no further addresses to try, will try again in %s.\n",
231 cstate->service_name,
232 GNUNET_STRINGS_relative_time_to_string (cstate->back_off,
235 = GNUNET_SCHEDULER_add_delayed (cstate->back_off,
242 * We are ready to send a message to the service.
244 * @param cls the `struct ClientState` with the `msg` to transmit
247 transmit_ready (void *cls)
249 struct ClientState *cstate = cls;
253 int notify_in_flight;
255 cstate->send_task = NULL;
256 pos = (const char *) cstate->msg;
257 len = ntohs (cstate->msg->size);
258 GNUNET_assert (cstate->msg_off < len);
259 LOG (GNUNET_ERROR_TYPE_DEBUG,
260 "message of type %u trying to send with socket %p (MQ: %p\n",
261 ntohs(cstate->msg->type),
266 ret = GNUNET_NETWORK_socket_send (cstate->sock,
267 &pos[cstate->msg_off],
268 len - cstate->msg_off);
271 LOG (GNUNET_ERROR_TYPE_WARNING,
272 "Error during sending message of type %u\n",
273 ntohs(cstate->msg->type));
275 LOG (GNUNET_ERROR_TYPE_DEBUG,
276 "Retrying message of type %u\n",
277 ntohs(cstate->msg->type));
280 GNUNET_MQ_inject_error (cstate->mq,
281 GNUNET_MQ_ERROR_WRITE);
284 notify_in_flight = (0 == cstate->msg_off);
285 cstate->msg_off += ret;
286 if (cstate->msg_off < len)
288 LOG (GNUNET_ERROR_TYPE_DEBUG,
289 "rescheduling message of type %u\n",
290 ntohs(cstate->msg->type));
292 = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
296 if (notify_in_flight)
297 GNUNET_MQ_impl_send_in_flight (cstate->mq);
300 LOG (GNUNET_ERROR_TYPE_DEBUG,
301 "sending message of type %u successful\n",
302 ntohs(cstate->msg->type));
304 GNUNET_MQ_impl_send_continue (cstate->mq);
309 * We have received a full message, pass to the MQ dispatcher.
310 * Called by the tokenizer via #receive_ready().
312 * @param cls the `struct ClientState`
313 * @param msg message we received.
314 * @return #GNUNET_OK on success,
315 * #GNUNET_NO to stop further processing due to disconnect (no error)
316 * #GNUNET_SYSERR to stop further processing due to error
319 recv_message (void *cls,
320 const struct GNUNET_MessageHeader *msg)
322 struct ClientState *cstate = cls;
324 if (GNUNET_YES == cstate->in_destroy)
326 LOG (GNUNET_ERROR_TYPE_DEBUG,
327 "Received message of type %u and size %u from %s\n",
330 cstate->service_name);
331 GNUNET_MQ_inject_message (cstate->mq,
333 if (GNUNET_YES == cstate->in_destroy)
340 * Cancel all remaining connect attempts
342 * @param cstate handle of the client state to process
345 cancel_aps (struct ClientState *cstate)
347 struct AddressProbe *pos;
349 while (NULL != (pos = cstate->ap_head))
351 GNUNET_break (GNUNET_OK ==
352 GNUNET_NETWORK_socket_close (pos->sock));
353 GNUNET_SCHEDULER_cancel (pos->task);
354 GNUNET_CONTAINER_DLL_remove (cstate->ap_head,
363 * Implement the destruction of a message queue. Implementations must
364 * not free @a mq, but should take care of @a impl_state.
366 * @param mq the message queue to destroy
367 * @param impl_state our `struct ClientState`
370 connection_client_destroy_impl (struct GNUNET_MQ_Handle *mq,
373 struct ClientState *cstate = impl_state;
376 if (GNUNET_SYSERR == cstate->in_destroy)
378 /* defer destruction */
379 cstate->in_destroy = GNUNET_YES;
383 if (NULL != cstate->dns_active)
384 GNUNET_RESOLVER_request_cancel (cstate->dns_active);
385 if (NULL != cstate->send_task)
386 GNUNET_SCHEDULER_cancel (cstate->send_task);
387 if (NULL != cstate->recv_task)
388 GNUNET_SCHEDULER_cancel (cstate->recv_task);
389 if (NULL != cstate->retry_task)
390 GNUNET_SCHEDULER_cancel (cstate->retry_task);
391 if (NULL != cstate->sock){
392 LOG (GNUNET_ERROR_TYPE_DEBUG,
393 "destroying socket: %p\n",
395 GNUNET_NETWORK_socket_close (cstate->sock);
398 GNUNET_free (cstate->service_name);
399 GNUNET_free_non_null (cstate->hostname);
400 GNUNET_MST_destroy (cstate->mst);
401 GNUNET_free (cstate);
406 * This function is called once we have data ready to read.
408 * @param cls `struct ClientState` with connection to read from
411 receive_ready (void *cls)
413 struct ClientState *cstate = cls;
416 cstate->recv_task = NULL;
417 cstate->in_destroy = GNUNET_SYSERR;
418 ret = GNUNET_MST_read (cstate->mst,
422 if (GNUNET_SYSERR == ret)
424 if (NULL != cstate->mq)
425 GNUNET_MQ_inject_error (cstate->mq,
426 GNUNET_MQ_ERROR_READ);
427 if (GNUNET_YES == cstate->in_destroy)
428 connection_client_destroy_impl (cstate->mq,
432 if (GNUNET_YES == cstate->in_destroy)
434 connection_client_destroy_impl (cstate->mq,
438 cstate->in_destroy = GNUNET_NO;
440 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
448 * We've succeeded in establishing a connection.
450 * @param cstate the connection we tried to establish
453 connect_success_continuation (struct ClientState *cstate)
455 GNUNET_assert (NULL == cstate->recv_task);
457 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
461 if (NULL != cstate->msg)
463 GNUNET_assert (NULL == cstate->send_task);
465 = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
474 * Try connecting to the server using UNIX domain sockets.
476 * @param service_name name of service to connect to
477 * @param cfg configuration to use
478 * @return NULL on error, socket connected to UNIX otherwise
480 static struct GNUNET_NETWORK_Handle *
481 try_unixpath (const char *service_name,
482 const struct GNUNET_CONFIGURATION_Handle *cfg)
485 struct GNUNET_NETWORK_Handle *sock;
487 struct sockaddr_un s_un;
491 GNUNET_CONFIGURATION_get_value_filename (cfg,
495 (0 < strlen (unixpath)))
497 /* We have a non-NULL unixpath, need to validate it */
498 if (strlen (unixpath) >= sizeof (s_un.sun_path))
500 LOG (GNUNET_ERROR_TYPE_WARNING,
501 _("UNIXPATH `%s' too long, maximum length is %llu\n"),
503 (unsigned long long) sizeof (s_un.sun_path));
504 unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
505 LOG (GNUNET_ERROR_TYPE_INFO,
506 _("Using `%s' instead\n"),
508 if (NULL == unixpath)
514 s_un.sun_family = AF_UNIX;
515 strncpy (s_un.sun_path,
517 sizeof (s_un.sun_path) - 1);
522 abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
524 "USE_ABSTRACT_SOCKETS");
525 if (GNUNET_YES == abstract)
526 s_un.sun_path[0] = '\0';
529 #if HAVE_SOCKADDR_UN_SUN_LEN
530 s_un.sun_len = (u_char) sizeof (struct sockaddr_un);
532 sock = GNUNET_NETWORK_socket_create (AF_UNIX,
535 if ( (NULL != sock) &&
537 GNUNET_NETWORK_socket_connect (sock,
538 (struct sockaddr *) &s_un,
540 (EINPROGRESS == errno) ) )
542 LOG (GNUNET_ERROR_TYPE_DEBUG,
543 "Successfully connected to unixpath `%s'!\n",
545 GNUNET_free (unixpath);
549 GNUNET_NETWORK_socket_close (sock);
551 GNUNET_free_non_null (unixpath);
558 * Scheduler let us know that we're either ready to write on the
559 * socket OR connect timed out. Do the right thing.
561 * @param cls the `struct AddressProbe *` with the address that we are probing
564 connect_probe_continuation (void *cls)
566 struct AddressProbe *ap = cls;
567 struct ClientState *cstate = ap->cstate;
568 const struct GNUNET_SCHEDULER_TaskContext *tc;
573 GNUNET_assert (NULL != ap->sock);
574 GNUNET_CONTAINER_DLL_remove (cstate->ap_head,
577 len = sizeof (error);
579 tc = GNUNET_SCHEDULER_get_task_context ();
580 if ( (0 == (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) ||
582 GNUNET_NETWORK_socket_getsockopt (ap->sock,
589 GNUNET_break (GNUNET_OK ==
590 GNUNET_NETWORK_socket_close (ap->sock));
592 if ( (NULL == cstate->ap_head) &&
593 // (NULL == cstate->proxy_handshake) &&
594 (NULL == cstate->dns_active) )
595 connect_fail_continuation (cstate);
598 LOG (GNUNET_ERROR_TYPE_DEBUG,
599 "Connection to `%s' succeeded!\n",
600 cstate->service_name);
601 /* trigger jobs that waited for the connection */
602 GNUNET_assert (NULL == cstate->sock);
603 cstate->sock = ap->sock;
606 connect_success_continuation (cstate);
611 * Try to establish a connection given the specified address.
612 * This function is called by the resolver once we have a DNS reply.
614 * @param cls our `struct ClientState *`
615 * @param addr address to try, NULL for "last call"
616 * @param addrlen length of @a addr
619 try_connect_using_address (void *cls,
620 const struct sockaddr *addr,
623 struct ClientState *cstate = cls;
624 struct AddressProbe *ap;
628 cstate->dns_active = NULL;
629 if ( (NULL == cstate->ap_head) &&
630 // (NULL == cstate->proxy_handshake) &&
631 (NULL == cstate->sock) )
632 connect_fail_continuation (cstate);
635 if (NULL != cstate->sock)
636 return; /* already connected */
638 LOG (GNUNET_ERROR_TYPE_DEBUG,
639 "Trying to connect using address `%s:%u'\n",
643 ap = GNUNET_malloc (sizeof (struct AddressProbe) + addrlen);
644 ap->addr = (const struct sockaddr *) &ap[1];
645 GNUNET_memcpy (&ap[1],
648 ap->addrlen = addrlen;
651 switch (ap->addr->sa_family)
654 ((struct sockaddr_in *) ap->addr)->sin_port = htons (cstate->port);
657 ((struct sockaddr_in6 *) ap->addr)->sin6_port = htons (cstate->port);
662 return; /* not supported by us */
664 ap->sock = GNUNET_NETWORK_socket_create (ap->addr->sa_family,
667 if (NULL == ap->sock)
670 return; /* not supported by OS */
673 GNUNET_NETWORK_socket_connect (ap->sock,
676 (EINPROGRESS != errno) )
678 /* maybe refused / unsupported address, try next */
679 GNUNET_log_strerror (GNUNET_ERROR_TYPE_INFO,
681 GNUNET_break (GNUNET_OK ==
682 GNUNET_NETWORK_socket_close (ap->sock));
686 GNUNET_CONTAINER_DLL_insert (cstate->ap_head,
689 ap->task = GNUNET_SCHEDULER_add_write_net (CONNECT_RETRY_TIMEOUT,
691 &connect_probe_continuation,
697 * Test whether the configuration has proper values for connection
698 * (UNIXPATH || (PORT && HOSTNAME)).
700 * @param service_name name of service to connect to
701 * @param cfg configuration to use
702 * @return #GNUNET_OK if the configuration is valid, #GNUNET_SYSERR if not
705 test_service_configuration (const char *service_name,
706 const struct GNUNET_CONFIGURATION_Handle *cfg)
708 int ret = GNUNET_SYSERR;
709 char *hostname = NULL;
710 unsigned long long port;
712 char *unixpath = NULL;
715 GNUNET_CONFIGURATION_get_value_filename (cfg,
719 (0 < strlen (unixpath)))
721 GNUNET_free_non_null (unixpath);
725 GNUNET_CONFIGURATION_have_value (cfg,
729 GNUNET_CONFIGURATION_get_value_number (cfg,
736 GNUNET_CONFIGURATION_get_value_string (cfg,
740 (0 != strlen (hostname)) )
742 GNUNET_free_non_null (hostname);
748 * Try to connect to the service.
750 * @param cls the `struct ClientState` to try to connect to the service
753 start_connect (void *cls)
755 struct ClientState *cstate = cls;
757 cstate->retry_task = NULL;
759 /* Never use a local source if a proxy is configured */
761 GNUNET_SOCKS_check_service (cstate->service_name,
764 socks_connect (cstate);
769 if ( (0 == (cstate->attempts++ % 2)) ||
770 (0 == cstate->port) ||
771 (NULL == cstate->hostname) )
773 /* on even rounds, try UNIX first, or always
774 if we do not have a DNS name and TCP port. */
775 cstate->sock = try_unixpath (cstate->service_name,
777 if (NULL != cstate->sock)
779 connect_success_continuation (cstate);
783 if ( (NULL == cstate->hostname) ||
784 (0 == cstate->port) )
786 /* All options failed. Boo! */
787 connect_fail_continuation (cstate);
791 = GNUNET_RESOLVER_ip_get (cstate->hostname,
793 CONNECT_RETRY_TIMEOUT,
794 &try_connect_using_address,
800 * Implements the transmission functionality of a message queue.
802 * @param mq the message queue
803 * @param msg the message to send
804 * @param impl_state our `struct ClientState`
807 connection_client_send_impl (struct GNUNET_MQ_Handle *mq,
808 const struct GNUNET_MessageHeader *msg,
811 struct ClientState *cstate = impl_state;
814 /* only one message at a time allowed */
815 GNUNET_assert (NULL == cstate->msg);
816 GNUNET_assert (NULL == cstate->send_task);
819 if (NULL == cstate->sock){
820 LOG (GNUNET_ERROR_TYPE_DEBUG,
821 "message of type %u waiting for socket\n",
823 return; /* still waiting for connection */
826 = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
834 * Cancel the currently sent message.
836 * @param mq message queue
837 * @param impl_state our `struct ClientState`
840 connection_client_cancel_impl (struct GNUNET_MQ_Handle *mq,
843 struct ClientState *cstate = impl_state;
846 GNUNET_assert (NULL != cstate->msg);
847 GNUNET_assert (0 == cstate->msg_off);
849 if (NULL != cstate->send_task)
851 GNUNET_SCHEDULER_cancel (cstate->send_task);
852 cstate->send_task = NULL;
858 * Create a message queue to connect to a GNUnet service.
859 * If handlers are specfied, receive messages from the connection.
861 * @param cfg our configuration
862 * @param service_name name of the service to connect to
863 * @param handlers handlers for receiving messages, can be NULL
864 * @param error_handler error handler
865 * @param error_handler_cls closure for the @a error_handler
866 * @return the message queue, NULL on error
868 struct GNUNET_MQ_Handle *
869 GNUNET_CLIENT_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
870 const char *service_name,
871 const struct GNUNET_MQ_MessageHandler *handlers,
872 GNUNET_MQ_ErrorHandler error_handler,
873 void *error_handler_cls)
875 struct ClientState *cstate;
878 test_service_configuration (service_name,
881 cstate = GNUNET_new (struct ClientState);
882 cstate->service_name = GNUNET_strdup (service_name);
884 cstate->retry_task = GNUNET_SCHEDULER_add_now (&start_connect,
886 cstate->mst = GNUNET_MST_create (&recv_message,
889 GNUNET_CONFIGURATION_have_value (cfg,
893 if (! ( (GNUNET_OK !=
894 GNUNET_CONFIGURATION_get_value_number (cfg,
898 (cstate->port > 65535) ||
900 GNUNET_CONFIGURATION_get_value_string (cfg,
903 &cstate->hostname)) ) &&
904 (0 == strlen (cstate->hostname)) )
906 GNUNET_free (cstate->hostname);
907 cstate->hostname = NULL;
908 LOG (GNUNET_ERROR_TYPE_WARNING,
909 _("Need a non-empty hostname for service `%s'.\n"),
913 cstate->mq = GNUNET_MQ_queue_for_callbacks (&connection_client_send_impl,
914 &connection_client_destroy_impl,
915 &connection_client_cancel_impl,
923 /* end of client.c */