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
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.
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__)
40 * Internal state for a client connected to a GNUnet service.
46 * During connect, we try multiple possible IP addresses
47 * to find out which one might work.
53 * This is a linked list.
55 struct AddressProbe *next;
58 * This is a doubly-linked list.
60 struct AddressProbe *prev;
63 * The address; do not free (allocated at the end of this struct).
65 const struct sockaddr *addr;
68 * Underlying OS's socket.
70 struct GNUNET_NETWORK_Handle *sock;
73 * Connection for which we are probing.
75 struct ClientState *cstate;
83 * Task waiting for the connection to finish connecting.
85 struct GNUNET_SCHEDULER_Task *task;
90 * Internal state for a client connected to a GNUnet service.
96 * The connection handle, NULL if not live
98 struct GNUNET_NETWORK_Handle *sock;
101 * Handle to a pending DNS lookup request, NULL if DNS is finished.
103 struct GNUNET_RESOLVER_RequestHandle *dns_active;
108 const struct GNUNET_CONFIGURATION_Handle *cfg;
111 * Linked list of sockets we are currently trying out
114 struct AddressProbe *ap_head;
117 * Linked list of sockets we are currently trying out
120 struct AddressProbe *ap_tail;
123 * Name of the service we interact with.
133 * Next message to transmit to the service. NULL for none.
135 const struct GNUNET_MessageHeader *msg;
138 * Task for trying to connect to the service.
140 struct GNUNET_SCHEDULER_Task *retry_task;
143 * Task for sending messages to the service.
145 struct GNUNET_SCHEDULER_Task *send_task;
148 * Task for sending messages to the service.
150 struct GNUNET_SCHEDULER_Task *recv_task;
153 * Tokenizer for inbound messages.
155 struct GNUNET_MessageStreamTokenizer *mst;
158 * Message queue under our control.
160 struct GNUNET_MQ_Handle *mq;
163 * Timeout for receiving a response (absolute time).
165 struct GNUNET_TIME_Absolute receive_timeout;
168 * Current value for our incremental back-off (for
171 struct GNUNET_TIME_Relative back_off;
174 * TCP port (0 for disabled).
176 unsigned long long port;
179 * Offset in the message where we are for transmission.
184 * How often have we tried to connect?
186 unsigned int attempts;
189 * Are we supposed to die? #GNUNET_SYSERR if destruction must be
190 * deferred, #GNUNET_NO by default, #GNUNET_YES if destruction was
199 * Try to connect to the service.
201 * @param cls the `struct ClientState` to try to connect to the service
204 start_connect (void *cls);
208 * We've failed for good to establish a connection (timeout or
209 * no more addresses to try).
211 * @param cstate the connection we tried to establish
214 connect_fail_continuation (struct ClientState *cstate)
216 GNUNET_break (NULL == cstate->ap_head);
217 GNUNET_break (NULL == cstate->ap_tail);
218 GNUNET_break (NULL == cstate->dns_active);
219 GNUNET_break (NULL == cstate->sock);
220 GNUNET_assert (NULL == cstate->send_task);
221 GNUNET_assert (NULL == cstate->recv_task);
222 // GNUNET_assert (NULL == cstate->proxy_handshake);
224 cstate->back_off = GNUNET_TIME_STD_BACKOFF (cstate->back_off);
225 LOG (GNUNET_ERROR_TYPE_DEBUG,
226 "Failed to establish connection to `%s', no further addresses to try, will try again in %s.\n",
227 cstate->service_name,
228 GNUNET_STRINGS_relative_time_to_string (cstate->back_off,
231 = GNUNET_SCHEDULER_add_delayed (cstate->back_off,
238 * We are ready to send a message to the service.
240 * @param cls the `struct ClientState` with the `msg` to transmit
243 transmit_ready (void *cls)
245 struct ClientState *cstate = cls;
249 int notify_in_flight;
251 cstate->send_task = NULL;
252 pos = (const char *) cstate->msg;
253 len = ntohs (cstate->msg->size);
254 GNUNET_assert (cstate->msg_off < len);
256 ret = GNUNET_NETWORK_socket_send (cstate->sock,
257 &pos[cstate->msg_off],
258 len - cstate->msg_off);
263 GNUNET_MQ_inject_error (cstate->mq,
264 GNUNET_MQ_ERROR_WRITE);
267 notify_in_flight = (0 == cstate->msg_off);
268 cstate->msg_off += ret;
269 if (cstate->msg_off < len)
272 = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
276 if (notify_in_flight)
277 GNUNET_MQ_impl_send_in_flight (cstate->mq);
281 GNUNET_MQ_impl_send_continue (cstate->mq);
286 * We have received a full message, pass to the MQ dispatcher.
287 * Called by the tokenizer via #receive_ready().
289 * @param cls the `struct ClientState`
290 * @param msg message we received.
291 * @return #GNUNET_OK on success, #GNUNET_SYSERR to stop further processing
294 recv_message (void *cls,
295 const struct GNUNET_MessageHeader *msg)
297 struct ClientState *cstate = cls;
299 if (GNUNET_YES == cstate->in_destroy)
300 return GNUNET_SYSERR;
301 LOG (GNUNET_ERROR_TYPE_DEBUG,
302 "Received message of type %u and size %u from %s\n",
305 cstate->service_name);
306 GNUNET_MQ_inject_message (cstate->mq,
308 if (GNUNET_YES == cstate->in_destroy)
309 return GNUNET_SYSERR;
315 * Cancel all remaining connect attempts
317 * @param cstate handle of the client state to process
320 cancel_aps (struct ClientState *cstate)
322 struct AddressProbe *pos;
324 while (NULL != (pos = cstate->ap_head))
326 GNUNET_break (GNUNET_OK ==
327 GNUNET_NETWORK_socket_close (pos->sock));
328 GNUNET_SCHEDULER_cancel (pos->task);
329 GNUNET_CONTAINER_DLL_remove (cstate->ap_head,
338 * Implement the destruction of a message queue. Implementations must
339 * not free @a mq, but should take care of @a impl_state.
341 * @param mq the message queue to destroy
342 * @param impl_state our `struct ClientState`
345 connection_client_destroy_impl (struct GNUNET_MQ_Handle *mq,
348 struct ClientState *cstate = impl_state;
350 if (GNUNET_SYSERR == cstate->in_destroy)
352 /* defer destruction */
353 cstate->in_destroy = GNUNET_YES;
357 if (NULL != cstate->dns_active)
358 GNUNET_RESOLVER_request_cancel (cstate->dns_active);
359 if (NULL != cstate->send_task)
360 GNUNET_SCHEDULER_cancel (cstate->send_task);
361 if (NULL != cstate->recv_task)
362 GNUNET_SCHEDULER_cancel (cstate->recv_task);
363 if (NULL != cstate->retry_task)
364 GNUNET_SCHEDULER_cancel (cstate->retry_task);
365 if (NULL != cstate->sock)
366 GNUNET_NETWORK_socket_close (cstate->sock);
368 GNUNET_free (cstate->service_name);
369 GNUNET_free_non_null (cstate->hostname);
370 GNUNET_MST_destroy (cstate->mst);
371 GNUNET_free (cstate);
376 * This function is called once we have data ready to read.
378 * @param cls `struct ClientState` with connection to read from
381 receive_ready (void *cls)
383 struct ClientState *cstate = cls;
386 cstate->recv_task = NULL;
387 cstate->in_destroy = GNUNET_SYSERR;
388 ret = GNUNET_MST_read (cstate->mst,
392 if (GNUNET_SYSERR == ret)
394 if (NULL != cstate->mq)
395 GNUNET_MQ_inject_error (cstate->mq,
396 GNUNET_MQ_ERROR_READ);
397 if (GNUNET_YES == cstate->in_destroy)
398 connection_client_destroy_impl (cstate->mq,
402 if (GNUNET_YES == cstate->in_destroy)
404 connection_client_destroy_impl (cstate->mq,
408 cstate->in_destroy = GNUNET_NO;
410 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
418 * We've succeeded in establishing a connection.
420 * @param cstate the connection we tried to establish
423 connect_success_continuation (struct ClientState *cstate)
425 GNUNET_assert (NULL == cstate->recv_task);
427 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
431 if (NULL != cstate->msg)
433 GNUNET_assert (NULL == cstate->send_task);
435 = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
444 * Try connecting to the server using UNIX domain sockets.
446 * @param service_name name of service to connect to
447 * @param cfg configuration to use
448 * @return NULL on error, socket connected to UNIX otherwise
450 static struct GNUNET_NETWORK_Handle *
451 try_unixpath (const char *service_name,
452 const struct GNUNET_CONFIGURATION_Handle *cfg)
455 struct GNUNET_NETWORK_Handle *sock;
457 struct sockaddr_un s_un;
461 GNUNET_CONFIGURATION_get_value_filename (cfg,
465 (0 < strlen (unixpath)))
467 /* We have a non-NULL unixpath, need to validate it */
468 if (strlen (unixpath) >= sizeof (s_un.sun_path))
470 LOG (GNUNET_ERROR_TYPE_WARNING,
471 _("UNIXPATH `%s' too long, maximum length is %llu\n"),
473 (unsigned long long) sizeof (s_un.sun_path));
474 unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
475 LOG (GNUNET_ERROR_TYPE_INFO,
476 _("Using `%s' instead\n"),
478 if (NULL == unixpath)
484 s_un.sun_family = AF_UNIX;
485 strncpy (s_un.sun_path,
487 sizeof (s_un.sun_path) - 1);
492 abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
494 "USE_ABSTRACT_SOCKETS");
495 if (GNUNET_YES == abstract)
496 s_un.sun_path[0] = '\0';
499 #if HAVE_SOCKADDR_UN_SUN_LEN
500 s_un.sun_len = (u_char) sizeof (struct sockaddr_un);
502 sock = GNUNET_NETWORK_socket_create (AF_UNIX,
505 if ( (NULL != sock) &&
507 GNUNET_NETWORK_socket_connect (sock,
508 (struct sockaddr *) &s_un,
510 (EINPROGRESS == errno) ) )
512 LOG (GNUNET_ERROR_TYPE_DEBUG,
513 "Successfully connected to unixpath `%s'!\n",
515 GNUNET_free (unixpath);
519 GNUNET_NETWORK_socket_close (sock);
521 GNUNET_free_non_null (unixpath);
528 * Scheduler let us know that we're either ready to write on the
529 * socket OR connect timed out. Do the right thing.
531 * @param cls the `struct AddressProbe *` with the address that we are probing
534 connect_probe_continuation (void *cls)
536 struct AddressProbe *ap = cls;
537 struct ClientState *cstate = ap->cstate;
538 const struct GNUNET_SCHEDULER_TaskContext *tc;
543 GNUNET_assert (NULL != ap->sock);
544 GNUNET_CONTAINER_DLL_remove (cstate->ap_head,
547 len = sizeof (error);
549 tc = GNUNET_SCHEDULER_get_task_context ();
550 if ( (0 == (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) ||
552 GNUNET_NETWORK_socket_getsockopt (ap->sock,
559 GNUNET_break (GNUNET_OK ==
560 GNUNET_NETWORK_socket_close (ap->sock));
562 if ( (NULL == cstate->ap_head) &&
563 // (NULL == cstate->proxy_handshake) &&
564 (NULL == cstate->dns_active) )
565 connect_fail_continuation (cstate);
568 LOG (GNUNET_ERROR_TYPE_DEBUG,
569 "Connection to `%s' succeeded!\n",
570 cstate->service_name);
571 /* trigger jobs that waited for the connection */
572 GNUNET_assert (NULL == cstate->sock);
573 cstate->sock = ap->sock;
576 connect_success_continuation (cstate);
581 * Try to establish a connection given the specified address.
582 * This function is called by the resolver once we have a DNS reply.
584 * @param cls our `struct ClientState *`
585 * @param addr address to try, NULL for "last call"
586 * @param addrlen length of @a addr
589 try_connect_using_address (void *cls,
590 const struct sockaddr *addr,
593 struct ClientState *cstate = cls;
594 struct AddressProbe *ap;
598 cstate->dns_active = NULL;
599 if ( (NULL == cstate->ap_head) &&
600 // (NULL == cstate->proxy_handshake) &&
601 (NULL == cstate->sock) )
602 connect_fail_continuation (cstate);
605 if (NULL != cstate->sock)
606 return; /* already connected */
608 LOG (GNUNET_ERROR_TYPE_DEBUG,
609 "Trying to connect using address `%s:%u'\n",
613 ap = GNUNET_malloc (sizeof (struct AddressProbe) + addrlen);
614 ap->addr = (const struct sockaddr *) &ap[1];
615 GNUNET_memcpy (&ap[1],
618 ap->addrlen = addrlen;
621 switch (ap->addr->sa_family)
624 ((struct sockaddr_in *) ap->addr)->sin_port = htons (cstate->port);
627 ((struct sockaddr_in6 *) ap->addr)->sin6_port = htons (cstate->port);
632 return; /* not supported by us */
634 ap->sock = GNUNET_NETWORK_socket_create (ap->addr->sa_family,
637 if (NULL == ap->sock)
640 return; /* not supported by OS */
643 GNUNET_NETWORK_socket_connect (ap->sock,
646 (EINPROGRESS != errno) )
648 /* maybe refused / unsupported address, try next */
649 GNUNET_log_strerror (GNUNET_ERROR_TYPE_INFO,
651 GNUNET_break (GNUNET_OK ==
652 GNUNET_NETWORK_socket_close (ap->sock));
656 GNUNET_CONTAINER_DLL_insert (cstate->ap_head,
659 ap->task = GNUNET_SCHEDULER_add_write_net (GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT,
661 &connect_probe_continuation,
667 * Test whether the configuration has proper values for connection
668 * (UNIXPATH || (PORT && HOSTNAME)).
670 * @param service_name name of service to connect to
671 * @param cfg configuration to use
672 * @return #GNUNET_OK if the configuration is valid, #GNUNET_SYSERR if not
675 test_service_configuration (const char *service_name,
676 const struct GNUNET_CONFIGURATION_Handle *cfg)
678 int ret = GNUNET_SYSERR;
679 char *hostname = NULL;
680 unsigned long long port;
682 char *unixpath = NULL;
685 GNUNET_CONFIGURATION_get_value_filename (cfg,
689 (0 < strlen (unixpath)))
691 GNUNET_free_non_null (unixpath);
695 GNUNET_CONFIGURATION_have_value (cfg,
699 GNUNET_CONFIGURATION_get_value_number (cfg,
706 GNUNET_CONFIGURATION_get_value_string (cfg,
710 (0 != strlen (hostname)) )
712 GNUNET_free_non_null (hostname);
718 * Try to connect to the service.
720 * @param cls the `struct ClientState` to try to connect to the service
723 start_connect (void *cls)
725 struct ClientState *cstate = cls;
727 cstate->retry_task = NULL;
729 /* Never use a local source if a proxy is configured */
731 GNUNET_SOCKS_check_service (cstate->service_name,
734 socks_connect (cstate);
739 if ( (0 == (cstate->attempts++ % 2)) ||
740 (0 == cstate->port) ||
741 (NULL == cstate->hostname) )
743 /* on even rounds, try UNIX first, or always
744 if we do not have a DNS name and TCP port. */
745 cstate->sock = try_unixpath (cstate->service_name,
747 if (NULL != cstate->sock)
749 connect_success_continuation (cstate);
753 if ( (NULL == cstate->hostname) ||
754 (0 == cstate->port) )
756 /* All options failed. Boo! */
757 connect_fail_continuation (cstate);
761 = GNUNET_RESOLVER_ip_get (cstate->hostname,
763 GNUNET_CONNECTION_CONNECT_RETRY_TIMEOUT,
764 &try_connect_using_address,
770 * Implements the transmission functionality of a message queue.
772 * @param mq the message queue
773 * @param msg the message to send
774 * @param impl_state our `struct ClientState`
777 connection_client_send_impl (struct GNUNET_MQ_Handle *mq,
778 const struct GNUNET_MessageHeader *msg,
781 struct ClientState *cstate = impl_state;
783 /* only one message at a time allowed */
784 GNUNET_assert (NULL == cstate->msg);
785 GNUNET_assert (NULL == cstate->send_task);
788 if (NULL == cstate->sock)
789 return; /* still waiting for connection */
791 = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
799 * Cancel the currently sent message.
801 * @param mq message queue
802 * @param impl_state our `struct ClientState`
805 connection_client_cancel_impl (struct GNUNET_MQ_Handle *mq,
808 struct ClientState *cstate = impl_state;
810 GNUNET_assert (NULL != cstate->msg);
811 GNUNET_assert (0 == cstate->msg_off);
813 if (NULL != cstate->send_task)
815 GNUNET_SCHEDULER_cancel (cstate->send_task);
816 cstate->send_task = NULL;
822 * Create a message queue to connect to a GNUnet service.
823 * If handlers are specfied, receive messages from the connection.
825 * @param cfg our configuration
826 * @param service_name name of the service to connect to
827 * @param handlers handlers for receiving messages, can be NULL
828 * @param error_handler error handler
829 * @param error_handler_cls closure for the @a error_handler
830 * @return the message queue, NULL on error
832 struct GNUNET_MQ_Handle *
833 GNUNET_CLIENT_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
834 const char *service_name,
835 const struct GNUNET_MQ_MessageHandler *handlers,
836 GNUNET_MQ_ErrorHandler error_handler,
837 void *error_handler_cls)
839 struct ClientState *cstate;
842 test_service_configuration (service_name,
845 cstate = GNUNET_new (struct ClientState);
846 cstate->service_name = GNUNET_strdup (service_name);
848 cstate->retry_task = GNUNET_SCHEDULER_add_now (&start_connect,
850 cstate->mst = GNUNET_MST_create (&recv_message,
853 GNUNET_CONFIGURATION_have_value (cfg,
857 if (! ( (GNUNET_OK !=
858 GNUNET_CONFIGURATION_get_value_number (cfg,
862 (cstate->port > 65535) ||
864 GNUNET_CONFIGURATION_get_value_string (cfg,
867 &cstate->hostname)) ) &&
868 (0 == strlen (cstate->hostname)) )
870 GNUNET_free (cstate->hostname);
871 cstate->hostname = NULL;
872 LOG (GNUNET_ERROR_TYPE_WARNING,
873 _("Need a non-empty hostname for service `%s'.\n"),
877 cstate->mq = GNUNET_MQ_queue_for_callbacks (&connection_client_send_impl,
878 &connection_client_destroy_impl,
879 &connection_client_cancel_impl,
887 /* end of client.c */