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/>.
21 * @brief code for access to services
22 * @author Christian Grothoff
24 * Generic TCP code for reliable, record-oriented TCP
25 * connections between clients and service providers.
28 #include "gnunet_protocols.h"
29 #include "gnunet_util_lib.h"
30 #include "gnunet_resolver_service.h"
31 #include "gnunet_socks.h"
34 #define LOG(kind,...) GNUNET_log_from (kind, "util-client",__VA_ARGS__)
37 * Timeout we use on TCP connect before trying another
38 * result from the DNS resolver. Actual value used
39 * is this value divided by the number of address families.
42 #define CONNECT_RETRY_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
47 * Internal state for a client connected to a GNUnet service.
53 * During connect, we try multiple possible IP addresses
54 * to find out which one might work.
60 * This is a linked list.
62 struct AddressProbe *next;
65 * This is a doubly-linked list.
67 struct AddressProbe *prev;
70 * The address; do not free (allocated at the end of this struct).
72 const struct sockaddr *addr;
75 * Underlying OS's socket.
77 struct GNUNET_NETWORK_Handle *sock;
80 * Connection for which we are probing.
82 struct ClientState *cstate;
90 * Task waiting for the connection to finish connecting.
92 struct GNUNET_SCHEDULER_Task *task;
97 * Internal state for a client connected to a GNUnet service.
103 * The connection handle, NULL if not live
105 struct GNUNET_NETWORK_Handle *sock;
108 * Handle to a pending DNS lookup request, NULL if DNS is finished.
110 struct GNUNET_RESOLVER_RequestHandle *dns_active;
115 const struct GNUNET_CONFIGURATION_Handle *cfg;
118 * Linked list of sockets we are currently trying out
121 struct AddressProbe *ap_head;
124 * Linked list of sockets we are currently trying out
127 struct AddressProbe *ap_tail;
130 * Name of the service we interact with.
140 * Next message to transmit to the service. NULL for none.
142 const struct GNUNET_MessageHeader *msg;
145 * Task for trying to connect to the service.
147 struct GNUNET_SCHEDULER_Task *retry_task;
150 * Task for sending messages to the service.
152 struct GNUNET_SCHEDULER_Task *send_task;
155 * Task for sending messages to the service.
157 struct GNUNET_SCHEDULER_Task *recv_task;
160 * Tokenizer for inbound messages.
162 struct GNUNET_MessageStreamTokenizer *mst;
165 * Message queue under our control.
167 struct GNUNET_MQ_Handle *mq;
170 * Timeout for receiving a response (absolute time).
172 struct GNUNET_TIME_Absolute receive_timeout;
175 * Current value for our incremental back-off (for
178 struct GNUNET_TIME_Relative back_off;
181 * TCP port (0 for disabled).
183 unsigned long long port;
186 * Offset in the message where we are for transmission.
191 * How often have we tried to connect?
193 unsigned int attempts;
196 * Are we supposed to die? #GNUNET_SYSERR if destruction must be
197 * deferred, #GNUNET_NO by default, #GNUNET_YES if destruction was
206 * Try to connect to the service.
208 * @param cls the `struct ClientState` to try to connect to the service
211 start_connect (void *cls);
215 * We've failed for good to establish a connection (timeout or
216 * no more addresses to try).
218 * @param cstate the connection we tried to establish
221 connect_fail_continuation (struct ClientState *cstate)
223 GNUNET_break (NULL == cstate->ap_head);
224 GNUNET_break (NULL == cstate->ap_tail);
225 GNUNET_break (NULL == cstate->dns_active);
226 GNUNET_break (NULL == cstate->sock);
227 GNUNET_assert (NULL == cstate->send_task);
228 GNUNET_assert (NULL == cstate->recv_task);
229 // GNUNET_assert (NULL == cstate->proxy_handshake);
231 cstate->back_off = GNUNET_TIME_STD_BACKOFF (cstate->back_off);
232 LOG (GNUNET_ERROR_TYPE_DEBUG,
233 "Failed to establish connection to `%s', no further addresses to try, will try again in %s.\n",
234 cstate->service_name,
235 GNUNET_STRINGS_relative_time_to_string (cstate->back_off,
238 = GNUNET_SCHEDULER_add_delayed (cstate->back_off,
245 * We are ready to send a message to the service.
247 * @param cls the `struct ClientState` with the `msg` to transmit
250 transmit_ready (void *cls)
252 struct ClientState *cstate = cls;
256 int notify_in_flight;
258 cstate->send_task = NULL;
259 pos = (const char *) cstate->msg;
260 len = ntohs (cstate->msg->size);
261 GNUNET_assert (cstate->msg_off < len);
262 LOG (GNUNET_ERROR_TYPE_DEBUG,
263 "message of type %u trying to send with socket %p (MQ: %p\n",
264 ntohs(cstate->msg->type),
269 ret = GNUNET_NETWORK_socket_send (cstate->sock,
270 &pos[cstate->msg_off],
271 len - cstate->msg_off);
274 LOG (GNUNET_ERROR_TYPE_WARNING,
275 "Error during sending message of type %u\n",
276 ntohs(cstate->msg->type));
278 LOG (GNUNET_ERROR_TYPE_DEBUG,
279 "Retrying message of type %u\n",
280 ntohs(cstate->msg->type));
283 GNUNET_MQ_inject_error (cstate->mq,
284 GNUNET_MQ_ERROR_WRITE);
287 notify_in_flight = (0 == cstate->msg_off);
288 cstate->msg_off += ret;
289 if (cstate->msg_off < len)
291 LOG (GNUNET_ERROR_TYPE_DEBUG,
292 "rescheduling message of type %u\n",
293 ntohs(cstate->msg->type));
295 = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
299 if (notify_in_flight)
300 GNUNET_MQ_impl_send_in_flight (cstate->mq);
303 LOG (GNUNET_ERROR_TYPE_DEBUG,
304 "sending message of type %u successful\n",
305 ntohs(cstate->msg->type));
307 GNUNET_MQ_impl_send_continue (cstate->mq);
312 * We have received a full message, pass to the MQ dispatcher.
313 * Called by the tokenizer via #receive_ready().
315 * @param cls the `struct ClientState`
316 * @param msg message we received.
317 * @return #GNUNET_OK on success,
318 * #GNUNET_NO to stop further processing due to disconnect (no error)
319 * #GNUNET_SYSERR to stop further processing due to error
322 recv_message (void *cls,
323 const struct GNUNET_MessageHeader *msg)
325 struct ClientState *cstate = cls;
327 if (GNUNET_YES == cstate->in_destroy)
329 LOG (GNUNET_ERROR_TYPE_DEBUG,
330 "Received message of type %u and size %u from %s\n",
333 cstate->service_name);
334 GNUNET_MQ_inject_message (cstate->mq,
336 if (GNUNET_YES == cstate->in_destroy)
343 * Cancel all remaining connect attempts
345 * @param cstate handle of the client state to process
348 cancel_aps (struct ClientState *cstate)
350 struct AddressProbe *pos;
352 while (NULL != (pos = cstate->ap_head))
354 GNUNET_break (GNUNET_OK ==
355 GNUNET_NETWORK_socket_close (pos->sock));
356 GNUNET_SCHEDULER_cancel (pos->task);
357 GNUNET_CONTAINER_DLL_remove (cstate->ap_head,
366 * Implement the destruction of a message queue. Implementations must
367 * not free @a mq, but should take care of @a impl_state.
369 * @param mq the message queue to destroy
370 * @param impl_state our `struct ClientState`
373 connection_client_destroy_impl (struct GNUNET_MQ_Handle *mq,
376 struct ClientState *cstate = impl_state;
379 if (GNUNET_SYSERR == cstate->in_destroy)
381 /* defer destruction */
382 cstate->in_destroy = GNUNET_YES;
386 if (NULL != cstate->dns_active)
387 GNUNET_RESOLVER_request_cancel (cstate->dns_active);
388 if (NULL != cstate->send_task)
389 GNUNET_SCHEDULER_cancel (cstate->send_task);
390 if (NULL != cstate->recv_task)
391 GNUNET_SCHEDULER_cancel (cstate->recv_task);
392 if (NULL != cstate->retry_task)
393 GNUNET_SCHEDULER_cancel (cstate->retry_task);
394 if (NULL != cstate->sock){
395 LOG (GNUNET_ERROR_TYPE_DEBUG,
396 "destroying socket: %p\n",
398 GNUNET_NETWORK_socket_close (cstate->sock);
401 GNUNET_free (cstate->service_name);
402 GNUNET_free_non_null (cstate->hostname);
403 GNUNET_MST_destroy (cstate->mst);
404 GNUNET_free (cstate);
409 * This function is called once we have data ready to read.
411 * @param cls `struct ClientState` with connection to read from
414 receive_ready (void *cls)
416 struct ClientState *cstate = cls;
419 cstate->recv_task = NULL;
420 cstate->in_destroy = GNUNET_SYSERR;
421 ret = GNUNET_MST_read (cstate->mst,
425 if (GNUNET_SYSERR == ret)
427 if (NULL != cstate->mq)
428 GNUNET_MQ_inject_error (cstate->mq,
429 GNUNET_MQ_ERROR_READ);
430 if (GNUNET_YES == cstate->in_destroy)
431 connection_client_destroy_impl (cstate->mq,
435 if (GNUNET_YES == cstate->in_destroy)
437 connection_client_destroy_impl (cstate->mq,
441 cstate->in_destroy = GNUNET_NO;
443 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
451 * We've succeeded in establishing a connection.
453 * @param cstate the connection we tried to establish
456 connect_success_continuation (struct ClientState *cstate)
458 GNUNET_assert (NULL == cstate->recv_task);
460 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
464 if (NULL != cstate->msg)
466 GNUNET_assert (NULL == cstate->send_task);
468 = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
477 * Try connecting to the server using UNIX domain sockets.
479 * @param service_name name of service to connect to
480 * @param cfg configuration to use
481 * @return NULL on error, socket connected to UNIX otherwise
483 static struct GNUNET_NETWORK_Handle *
484 try_unixpath (const char *service_name,
485 const struct GNUNET_CONFIGURATION_Handle *cfg)
488 struct GNUNET_NETWORK_Handle *sock;
490 struct sockaddr_un s_un;
494 GNUNET_CONFIGURATION_get_value_filename (cfg,
498 (0 < strlen (unixpath)))
500 /* We have a non-NULL unixpath, need to validate it */
501 if (strlen (unixpath) >= sizeof (s_un.sun_path))
503 LOG (GNUNET_ERROR_TYPE_WARNING,
504 _("UNIXPATH `%s' too long, maximum length is %llu\n"),
506 (unsigned long long) sizeof (s_un.sun_path));
507 unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
508 LOG (GNUNET_ERROR_TYPE_INFO,
509 _("Using `%s' instead\n"),
511 if (NULL == unixpath)
517 s_un.sun_family = AF_UNIX;
518 strncpy (s_un.sun_path,
520 sizeof (s_un.sun_path) - 1);
525 abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
527 "USE_ABSTRACT_SOCKETS");
528 if (GNUNET_YES == abstract)
529 s_un.sun_path[0] = '\0';
532 #if HAVE_SOCKADDR_UN_SUN_LEN
533 s_un.sun_len = (u_char) sizeof (struct sockaddr_un);
535 sock = GNUNET_NETWORK_socket_create (AF_UNIX,
538 if ( (NULL != sock) &&
540 GNUNET_NETWORK_socket_connect (sock,
541 (struct sockaddr *) &s_un,
543 (EINPROGRESS == errno) ) )
545 LOG (GNUNET_ERROR_TYPE_DEBUG,
546 "Successfully connected to unixpath `%s'!\n",
548 GNUNET_free (unixpath);
552 GNUNET_NETWORK_socket_close (sock);
554 GNUNET_free_non_null (unixpath);
561 * Scheduler let us know that we're either ready to write on the
562 * socket OR connect timed out. Do the right thing.
564 * @param cls the `struct AddressProbe *` with the address that we are probing
567 connect_probe_continuation (void *cls)
569 struct AddressProbe *ap = cls;
570 struct ClientState *cstate = ap->cstate;
571 const struct GNUNET_SCHEDULER_TaskContext *tc;
576 GNUNET_assert (NULL != ap->sock);
577 GNUNET_CONTAINER_DLL_remove (cstate->ap_head,
580 len = sizeof (error);
582 tc = GNUNET_SCHEDULER_get_task_context ();
583 if ( (0 == (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) ||
585 GNUNET_NETWORK_socket_getsockopt (ap->sock,
592 GNUNET_break (GNUNET_OK ==
593 GNUNET_NETWORK_socket_close (ap->sock));
595 if ( (NULL == cstate->ap_head) &&
596 // (NULL == cstate->proxy_handshake) &&
597 (NULL == cstate->dns_active) )
598 connect_fail_continuation (cstate);
601 LOG (GNUNET_ERROR_TYPE_DEBUG,
602 "Connection to `%s' succeeded!\n",
603 cstate->service_name);
604 /* trigger jobs that waited for the connection */
605 GNUNET_assert (NULL == cstate->sock);
606 cstate->sock = ap->sock;
609 connect_success_continuation (cstate);
614 * Try to establish a connection given the specified address.
615 * This function is called by the resolver once we have a DNS reply.
617 * @param cls our `struct ClientState *`
618 * @param addr address to try, NULL for "last call"
619 * @param addrlen length of @a addr
622 try_connect_using_address (void *cls,
623 const struct sockaddr *addr,
626 struct ClientState *cstate = cls;
627 struct AddressProbe *ap;
631 cstate->dns_active = NULL;
632 if ( (NULL == cstate->ap_head) &&
633 // (NULL == cstate->proxy_handshake) &&
634 (NULL == cstate->sock) )
635 connect_fail_continuation (cstate);
638 if (NULL != cstate->sock)
639 return; /* already connected */
641 LOG (GNUNET_ERROR_TYPE_DEBUG,
642 "Trying to connect using address `%s:%u'\n",
646 ap = GNUNET_malloc (sizeof (struct AddressProbe) + addrlen);
647 ap->addr = (const struct sockaddr *) &ap[1];
648 GNUNET_memcpy (&ap[1],
651 ap->addrlen = addrlen;
654 switch (ap->addr->sa_family)
657 ((struct sockaddr_in *) ap->addr)->sin_port = htons (cstate->port);
660 ((struct sockaddr_in6 *) ap->addr)->sin6_port = htons (cstate->port);
665 return; /* not supported by us */
667 ap->sock = GNUNET_NETWORK_socket_create (ap->addr->sa_family,
670 if (NULL == ap->sock)
673 return; /* not supported by OS */
676 GNUNET_NETWORK_socket_connect (ap->sock,
679 (EINPROGRESS != errno) )
681 /* maybe refused / unsupported address, try next */
682 GNUNET_log_strerror (GNUNET_ERROR_TYPE_INFO,
684 GNUNET_break (GNUNET_OK ==
685 GNUNET_NETWORK_socket_close (ap->sock));
689 GNUNET_CONTAINER_DLL_insert (cstate->ap_head,
692 ap->task = GNUNET_SCHEDULER_add_write_net (CONNECT_RETRY_TIMEOUT,
694 &connect_probe_continuation,
700 * Test whether the configuration has proper values for connection
701 * (UNIXPATH || (PORT && HOSTNAME)).
703 * @param service_name name of service to connect to
704 * @param cfg configuration to use
705 * @return #GNUNET_OK if the configuration is valid, #GNUNET_SYSERR if not
708 test_service_configuration (const char *service_name,
709 const struct GNUNET_CONFIGURATION_Handle *cfg)
711 int ret = GNUNET_SYSERR;
712 char *hostname = NULL;
713 unsigned long long port;
715 char *unixpath = NULL;
718 GNUNET_CONFIGURATION_get_value_filename (cfg,
722 (0 < strlen (unixpath)))
724 else if ((GNUNET_OK ==
725 GNUNET_CONFIGURATION_have_value (cfg,
729 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
732 _("not a valid filename"));
733 return GNUNET_SYSERR; /* UNIXPATH specified but invalid! */
735 GNUNET_free_non_null (unixpath);
739 GNUNET_CONFIGURATION_have_value (cfg,
743 GNUNET_CONFIGURATION_get_value_number (cfg,
750 GNUNET_CONFIGURATION_get_value_string (cfg,
754 (0 != strlen (hostname)) )
756 GNUNET_free_non_null (hostname);
762 * Try to connect to the service.
764 * @param cls the `struct ClientState` to try to connect to the service
767 start_connect (void *cls)
769 struct ClientState *cstate = cls;
771 cstate->retry_task = NULL;
773 /* Never use a local source if a proxy is configured */
775 GNUNET_SOCKS_check_service (cstate->service_name,
778 socks_connect (cstate);
783 if ( (0 == (cstate->attempts++ % 2)) ||
784 (0 == cstate->port) ||
785 (NULL == cstate->hostname) )
787 /* on even rounds, try UNIX first, or always
788 if we do not have a DNS name and TCP port. */
789 cstate->sock = try_unixpath (cstate->service_name,
791 if (NULL != cstate->sock)
793 connect_success_continuation (cstate);
797 if ( (NULL == cstate->hostname) ||
798 (0 == cstate->port) )
800 /* All options failed. Boo! */
801 connect_fail_continuation (cstate);
805 = GNUNET_RESOLVER_ip_get (cstate->hostname,
807 CONNECT_RETRY_TIMEOUT,
808 &try_connect_using_address,
814 * Implements the transmission functionality of a message queue.
816 * @param mq the message queue
817 * @param msg the message to send
818 * @param impl_state our `struct ClientState`
821 connection_client_send_impl (struct GNUNET_MQ_Handle *mq,
822 const struct GNUNET_MessageHeader *msg,
825 struct ClientState *cstate = impl_state;
828 /* only one message at a time allowed */
829 GNUNET_assert (NULL == cstate->msg);
830 GNUNET_assert (NULL == cstate->send_task);
833 if (NULL == cstate->sock){
834 LOG (GNUNET_ERROR_TYPE_DEBUG,
835 "message of type %u waiting for socket\n",
837 return; /* still waiting for connection */
840 = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
848 * Cancel the currently sent message.
850 * @param mq message queue
851 * @param impl_state our `struct ClientState`
854 connection_client_cancel_impl (struct GNUNET_MQ_Handle *mq,
857 struct ClientState *cstate = impl_state;
860 GNUNET_assert (NULL != cstate->msg);
861 GNUNET_assert (0 == cstate->msg_off);
863 if (NULL != cstate->send_task)
865 GNUNET_SCHEDULER_cancel (cstate->send_task);
866 cstate->send_task = NULL;
872 * Create a message queue to connect to a GNUnet service.
873 * If handlers are specfied, receive messages from the connection.
875 * @param cfg our configuration
876 * @param service_name name of the service to connect to
877 * @param handlers handlers for receiving messages, can be NULL
878 * @param error_handler error handler
879 * @param error_handler_cls closure for the @a error_handler
880 * @return the message queue, NULL on error
882 struct GNUNET_MQ_Handle *
883 GNUNET_CLIENT_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
884 const char *service_name,
885 const struct GNUNET_MQ_MessageHandler *handlers,
886 GNUNET_MQ_ErrorHandler error_handler,
887 void *error_handler_cls)
889 struct ClientState *cstate;
892 test_service_configuration (service_name,
895 cstate = GNUNET_new (struct ClientState);
896 cstate->service_name = GNUNET_strdup (service_name);
898 cstate->retry_task = GNUNET_SCHEDULER_add_now (&start_connect,
900 cstate->mst = GNUNET_MST_create (&recv_message,
903 GNUNET_CONFIGURATION_have_value (cfg,
907 if (! ( (GNUNET_OK !=
908 GNUNET_CONFIGURATION_get_value_number (cfg,
912 (cstate->port > 65535) ||
914 GNUNET_CONFIGURATION_get_value_string (cfg,
917 &cstate->hostname)) ) &&
918 (0 == strlen (cstate->hostname)) )
920 GNUNET_free (cstate->hostname);
921 cstate->hostname = NULL;
922 LOG (GNUNET_ERROR_TYPE_WARNING,
923 _("Need a non-empty hostname for service `%s'.\n"),
927 cstate->mq = GNUNET_MQ_queue_for_callbacks (&connection_client_send_impl,
928 &connection_client_destroy_impl,
929 &connection_client_cancel_impl,
937 /* end of client.c */