aboutsummaryrefslogtreecommitdiff
path: root/src/util/client.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/client.c')
-rw-r--r--src/util/client.c1119
1 files changed, 0 insertions, 1119 deletions
diff --git a/src/util/client.c b/src/util/client.c
deleted file mode 100644
index 4e5eca32a..000000000
--- a/src/util/client.c
+++ /dev/null
@@ -1,1119 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2001-2016, 2019 GNUnet e.V.
4
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.
9
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.
14
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/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file util/client.c
23 * @brief code for access to services
24 * @author Christian Grothoff
25 *
26 * Generic TCP code for reliable, record-oriented TCP
27 * connections between clients and service providers.
28 */
29#include "platform.h"
30#include "gnunet_protocols.h"
31#include "gnunet_util_lib.h"
32#include "gnunet_resolver_service.h"
33#include "gnunet_socks.h"
34
35
36#define LOG(kind, ...) GNUNET_log_from (kind, "util-client", __VA_ARGS__)
37
38/**
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.
42 * Default is 5s.
43 */
44#define CONNECT_RETRY_TIMEOUT GNUNET_TIME_relative_multiply ( \
45 GNUNET_TIME_UNIT_SECONDS, 5)
46
47
48/**
49 * Internal state for a client connected to a GNUnet service.
50 */
51struct ClientState;
52
53
54/**
55 * During connect, we try multiple possible IP addresses
56 * to find out which one might work.
57 */
58struct AddressProbe
59{
60 /**
61 * This is a linked list.
62 */
63 struct AddressProbe *next;
64
65 /**
66 * This is a doubly-linked list.
67 */
68 struct AddressProbe *prev;
69
70 /**
71 * The address; do not free (allocated at the end of this struct).
72 */
73 const struct sockaddr *addr;
74
75 /**
76 * Underlying OS's socket.
77 */
78 struct GNUNET_NETWORK_Handle *sock;
79
80 /**
81 * Connection for which we are probing.
82 */
83 struct ClientState *cstate;
84
85 /**
86 * Length of addr.
87 */
88 socklen_t addrlen;
89
90 /**
91 * Task waiting for the connection to finish connecting.
92 */
93 struct GNUNET_SCHEDULER_Task *task;
94};
95
96
97/**
98 * Internal state for a client connected to a GNUnet service.
99 */
100struct ClientState
101{
102 /**
103 * The connection handle, NULL if not live
104 */
105 struct GNUNET_NETWORK_Handle *sock;
106
107 /**
108 * Handle to a pending DNS lookup request, NULL if DNS is finished.
109 */
110 struct GNUNET_RESOLVER_RequestHandle *dns_active;
111
112 /**
113 * Our configuration.
114 */
115 const struct GNUNET_CONFIGURATION_Handle *cfg;
116
117 /**
118 * Linked list of sockets we are currently trying out
119 * (during connect).
120 */
121 struct AddressProbe *ap_head;
122
123 /**
124 * Linked list of sockets we are currently trying out
125 * (during connect).
126 */
127 struct AddressProbe *ap_tail;
128
129 /**
130 * Name of the service we interact with.
131 */
132 char *service_name;
133
134 /**
135 * Hostname, if any.
136 */
137 char *hostname;
138
139 /**
140 * Next message to transmit to the service. NULL for none.
141 */
142 const struct GNUNET_MessageHeader *msg;
143
144 /**
145 * Task for trying to connect to the service.
146 */
147 struct GNUNET_SCHEDULER_Task *retry_task;
148
149 /**
150 * Task for sending messages to the service.
151 */
152 struct GNUNET_SCHEDULER_Task *send_task;
153
154 /**
155 * Task for sending messages to the service.
156 */
157 struct GNUNET_SCHEDULER_Task *recv_task;
158
159 /**
160 * Tokenizer for inbound messages.
161 */
162 struct GNUNET_MessageStreamTokenizer *mst;
163
164 /**
165 * Message queue under our control.
166 */
167 struct GNUNET_MQ_Handle *mq;
168
169 /**
170 * Timeout for receiving a response (absolute time).
171 */
172 struct GNUNET_TIME_Absolute receive_timeout;
173
174 /**
175 * Current value for our incremental back-off (for
176 * connect re-tries).
177 */
178 struct GNUNET_TIME_Relative back_off;
179
180 /**
181 * TCP port (0 for disabled).
182 */
183 unsigned long long port;
184
185 /**
186 * Offset in the message where we are for transmission.
187 */
188 size_t msg_off;
189
190 /**
191 * How often have we tried to connect?
192 */
193 unsigned int attempts;
194
195 /**
196 * Are we supposed to die? #GNUNET_SYSERR if destruction must be
197 * deferred, #GNUNET_NO by default, #GNUNET_YES if destruction was
198 * deferred.
199 */
200 int in_destroy;
201};
202
203
204/**
205 * Try to connect to the service.
206 *
207 * @param cls the `struct ClientState` to try to connect to the service
208 */
209static void
210start_connect (void *cls);
211
212
213/**
214 * We've failed for good to establish a connection (timeout or
215 * no more addresses to try).
216 *
217 * @param cstate the connection we tried to establish
218 */
219static void
220connect_fail_continuation (struct ClientState *cstate)
221{
222 GNUNET_break (NULL == cstate->ap_head);
223 GNUNET_break (NULL == cstate->ap_tail);
224 GNUNET_break (NULL == cstate->dns_active);
225 GNUNET_break (NULL == cstate->sock);
226 GNUNET_assert (NULL == cstate->send_task);
227 GNUNET_assert (NULL == cstate->recv_task);
228 // GNUNET_assert (NULL == cstate->proxy_handshake);
229
230 cstate->back_off = GNUNET_TIME_STD_BACKOFF (cstate->back_off);
231 LOG (GNUNET_ERROR_TYPE_DEBUG,
232 "Failed to establish connection to `%s', no further addresses to try, will try again in %s.\n",
233 cstate->service_name,
234 GNUNET_STRINGS_relative_time_to_string (cstate->back_off,
235 GNUNET_YES));
236 cstate->retry_task
237 = GNUNET_SCHEDULER_add_delayed (cstate->back_off,
238 &start_connect,
239 cstate);
240}
241
242
243/**
244 * We are ready to send a message to the service.
245 *
246 * @param cls the `struct ClientState` with the `msg` to transmit
247 */
248static void
249transmit_ready (void *cls)
250{
251 struct ClientState *cstate = cls;
252 ssize_t ret;
253 size_t len;
254 const char *pos;
255 int notify_in_flight;
256
257 cstate->send_task = NULL;
258 if (GNUNET_YES == cstate->in_destroy)
259 return;
260 pos = (const char *) cstate->msg;
261 len = ntohs (cstate->msg->size);
262 GNUNET_assert (cstate->msg_off < len);
263 LOG (GNUNET_ERROR_TYPE_DEBUG,
264 "message of type %u trying to send with socket %p (MQ: %p\n",
265 ntohs (cstate->msg->type),
266 cstate->sock,
267 cstate->mq);
268
269RETRY:
270 ret = GNUNET_NETWORK_socket_send (cstate->sock,
271 &pos[cstate->msg_off],
272 len - cstate->msg_off);
273 if ( (-1 == ret) &&
274 ( (EAGAIN == errno) ||
275 (EINTR == errno) ) )
276 {
277 /* ignore */
278 ret = 0;
279 }
280 if (-1 == ret)
281 {
282 LOG (GNUNET_ERROR_TYPE_WARNING,
283 "Error during sending message of type %u: %s\n",
284 ntohs (cstate->msg->type),
285 strerror (errno));
286 if (EINTR == errno)
287 {
288 LOG (GNUNET_ERROR_TYPE_DEBUG,
289 "Retrying message of type %u\n",
290 ntohs (cstate->msg->type));
291 goto RETRY;
292 }
293 GNUNET_MQ_inject_error (cstate->mq,
294 GNUNET_MQ_ERROR_WRITE);
295 return;
296 }
297 notify_in_flight = (0 == cstate->msg_off);
298 cstate->msg_off += ret;
299 if (cstate->msg_off < len)
300 {
301 LOG (GNUNET_ERROR_TYPE_DEBUG,
302 "rescheduling message of type %u\n",
303 ntohs (cstate->msg->type));
304 cstate->send_task
305 = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
306 cstate->sock,
307 &transmit_ready,
308 cstate);
309 if (notify_in_flight)
310 GNUNET_MQ_impl_send_in_flight (cstate->mq);
311 return;
312 }
313 LOG (GNUNET_ERROR_TYPE_DEBUG,
314 "sending message of type %u successful\n",
315 ntohs (cstate->msg->type));
316 cstate->msg = NULL;
317 GNUNET_MQ_impl_send_continue (cstate->mq);
318}
319
320
321/**
322 * We have received a full message, pass to the MQ dispatcher.
323 * Called by the tokenizer via #receive_ready().
324 *
325 * @param cls the `struct ClientState`
326 * @param msg message we received.
327 * @return #GNUNET_OK on success,
328 * #GNUNET_NO to stop further processing due to disconnect (no error)
329 * #GNUNET_SYSERR to stop further processing due to error
330 */
331static int
332recv_message (void *cls,
333 const struct GNUNET_MessageHeader *msg)
334{
335 struct ClientState *cstate = cls;
336
337 if (GNUNET_YES == cstate->in_destroy)
338 return GNUNET_NO;
339 LOG (GNUNET_ERROR_TYPE_DEBUG,
340 "Received message of type %u and size %u from %s\n",
341 ntohs (msg->type),
342 ntohs (msg->size),
343 cstate->service_name);
344 GNUNET_MQ_inject_message (cstate->mq,
345 msg);
346 if (GNUNET_YES == cstate->in_destroy)
347 return GNUNET_NO;
348 return GNUNET_OK;
349}
350
351
352/**
353 * Cancel all remaining connect attempts
354 *
355 * @param cstate handle of the client state to process
356 */
357static void
358cancel_aps (struct ClientState *cstate)
359{
360 struct AddressProbe *pos;
361
362 while (NULL != (pos = cstate->ap_head))
363 {
364 GNUNET_break (GNUNET_OK ==
365 GNUNET_NETWORK_socket_close (pos->sock));
366 GNUNET_SCHEDULER_cancel (pos->task);
367 GNUNET_CONTAINER_DLL_remove (cstate->ap_head,
368 cstate->ap_tail,
369 pos);
370 GNUNET_free (pos);
371 }
372}
373
374
375/**
376 * Implement the destruction of a message queue. Implementations must
377 * not free @a mq, but should take care of @a impl_state.
378 *
379 * @param mq the message queue to destroy
380 * @param impl_state our `struct ClientState`
381 */
382static void
383connection_client_destroy_impl (struct GNUNET_MQ_Handle *mq,
384 void *impl_state)
385{
386 struct ClientState *cstate = impl_state;
387
388 (void) mq;
389 if (NULL != cstate->dns_active)
390 {
391 GNUNET_RESOLVER_request_cancel (cstate->dns_active);
392 cstate->dns_active = NULL;
393 }
394 if (NULL != cstate->send_task)
395 {
396 GNUNET_SCHEDULER_cancel (cstate->send_task);
397 cstate->send_task = NULL;
398 }
399 if (NULL != cstate->retry_task)
400 {
401 GNUNET_SCHEDULER_cancel (cstate->retry_task);
402 cstate->retry_task = NULL;
403 }
404 if (GNUNET_SYSERR == cstate->in_destroy)
405 {
406 /* defer destruction */
407 cstate->in_destroy = GNUNET_YES;
408 cstate->mq = NULL;
409 return;
410 }
411 if (NULL != cstate->recv_task)
412 {
413 GNUNET_SCHEDULER_cancel (cstate->recv_task);
414 cstate->recv_task = NULL;
415 }
416 if (NULL != cstate->sock)
417 {
418 LOG (GNUNET_ERROR_TYPE_DEBUG,
419 "destroying socket: %p\n",
420 cstate->sock);
421 GNUNET_NETWORK_socket_close (cstate->sock);
422 }
423 cancel_aps (cstate);
424 GNUNET_free (cstate->service_name);
425 GNUNET_free (cstate->hostname);
426 GNUNET_MST_destroy (cstate->mst);
427 GNUNET_free (cstate);
428}
429
430
431/**
432 * This function is called once we have data ready to read.
433 *
434 * @param cls `struct ClientState` with connection to read from
435 */
436static void
437receive_ready (void *cls)
438{
439 struct ClientState *cstate = cls;
440 int ret;
441
442 cstate->recv_task = NULL;
443 cstate->in_destroy = GNUNET_SYSERR;
444 ret = GNUNET_MST_read (cstate->mst,
445 cstate->sock,
446 GNUNET_NO,
447 GNUNET_NO);
448 if (GNUNET_SYSERR == ret)
449 {
450 if (NULL != cstate->mq)
451 GNUNET_MQ_inject_error (cstate->mq,
452 GNUNET_MQ_ERROR_READ);
453 if (GNUNET_YES == cstate->in_destroy)
454 connection_client_destroy_impl (cstate->mq,
455 cstate);
456 return;
457 }
458 if (GNUNET_YES == cstate->in_destroy)
459 {
460 connection_client_destroy_impl (cstate->mq,
461 cstate);
462 return;
463 }
464 cstate->in_destroy = GNUNET_NO;
465 cstate->recv_task
466 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
467 cstate->sock,
468 &receive_ready,
469 cstate);
470}
471
472
473/**
474 * We've succeeded in establishing a connection.
475 *
476 * @param cstate the connection we tried to establish
477 */
478static void
479connect_success_continuation (struct ClientState *cstate)
480{
481 GNUNET_assert (NULL == cstate->recv_task);
482 cstate->recv_task
483 = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
484 cstate->sock,
485 &receive_ready,
486 cstate);
487 if (NULL != cstate->msg)
488 {
489 GNUNET_assert (NULL == cstate->send_task);
490 cstate->send_task
491 = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
492 cstate->sock,
493 &transmit_ready,
494 cstate);
495 }
496}
497
498
499/**
500 * Try connecting to the server using UNIX domain sockets.
501 *
502 * @param service_name name of service to connect to
503 * @param cfg configuration to use
504 * @return NULL on error, socket connected to UNIX otherwise
505 */
506static struct GNUNET_NETWORK_Handle *
507try_unixpath (const char *service_name,
508 const struct GNUNET_CONFIGURATION_Handle *cfg)
509{
510#if AF_UNIX
511 struct GNUNET_NETWORK_Handle *sock;
512 char *unixpath;
513 struct sockaddr_un s_un;
514
515 unixpath = NULL;
516 if ((GNUNET_OK ==
517 GNUNET_CONFIGURATION_get_value_filename (cfg,
518 service_name,
519 "UNIXPATH",
520 &unixpath)) &&
521 (0 < strlen (unixpath)))
522 {
523 /* We have a non-NULL unixpath, need to validate it */
524 if (strlen (unixpath) >= sizeof(s_un.sun_path))
525 {
526 LOG (GNUNET_ERROR_TYPE_WARNING,
527 _ ("UNIXPATH `%s' too long, maximum length is %llu\n"),
528 unixpath,
529 (unsigned long long) sizeof(s_un.sun_path));
530 unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
531 LOG (GNUNET_ERROR_TYPE_INFO,
532 _ ("Using `%s' instead\n"),
533 unixpath);
534 if (NULL == unixpath)
535 return NULL;
536 }
537 memset (&s_un,
538 0,
539 sizeof(s_un));
540 s_un.sun_family = AF_UNIX;
541 GNUNET_strlcpy (s_un.sun_path,
542 unixpath,
543 sizeof(s_un.sun_path));
544#if HAVE_SOCKADDR_UN_SUN_LEN
545 s_un.sun_len = (u_char) sizeof(struct sockaddr_un);
546#endif
547 sock = GNUNET_NETWORK_socket_create (AF_UNIX,
548 SOCK_STREAM,
549 0);
550 if ((NULL != sock) &&
551 ((GNUNET_OK ==
552 GNUNET_NETWORK_socket_connect (sock,
553 (struct sockaddr *) &s_un,
554 sizeof(s_un))) ||
555 (EINPROGRESS == errno)))
556 {
557 LOG (GNUNET_ERROR_TYPE_DEBUG,
558 "Successfully connected to unixpath `%s'!\n",
559 unixpath);
560 GNUNET_free (unixpath);
561 return sock;
562 }
563 if (NULL != sock)
564 GNUNET_NETWORK_socket_close (sock);
565 }
566 GNUNET_free (unixpath);
567#endif
568 return NULL;
569}
570
571
572/**
573 * Scheduler let us know that we're either ready to write on the
574 * socket OR connect timed out. Do the right thing.
575 *
576 * @param cls the `struct AddressProbe *` with the address that we are probing
577 */
578static void
579connect_probe_continuation (void *cls)
580{
581 struct AddressProbe *ap = cls;
582 struct ClientState *cstate = ap->cstate;
583 const struct GNUNET_SCHEDULER_TaskContext *tc;
584 int error;
585 socklen_t len;
586
587 ap->task = NULL;
588 GNUNET_assert (NULL != ap->sock);
589 GNUNET_CONTAINER_DLL_remove (cstate->ap_head,
590 cstate->ap_tail,
591 ap);
592 len = sizeof(error);
593 error = 0;
594 tc = GNUNET_SCHEDULER_get_task_context ();
595 if ((0 == (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) ||
596 (GNUNET_OK !=
597 GNUNET_NETWORK_socket_getsockopt (ap->sock,
598 SOL_SOCKET,
599 SO_ERROR,
600 &error,
601 &len)) ||
602 (0 != error))
603 {
604 GNUNET_break (GNUNET_OK ==
605 GNUNET_NETWORK_socket_close (ap->sock));
606 GNUNET_free (ap);
607 if ((NULL == cstate->ap_head) &&
608 // (NULL == cstate->proxy_handshake) &&
609 (NULL == cstate->dns_active))
610 connect_fail_continuation (cstate);
611 return;
612 }
613 LOG (GNUNET_ERROR_TYPE_DEBUG,
614 "Connection to `%s' succeeded!\n",
615 cstate->service_name);
616 /* trigger jobs that waited for the connection */
617 GNUNET_assert (NULL == cstate->sock);
618 cstate->sock = ap->sock;
619 GNUNET_free (ap);
620 cancel_aps (cstate);
621 connect_success_continuation (cstate);
622}
623
624
625/**
626 * Try to establish a connection given the specified address.
627 * This function is called by the resolver once we have a DNS reply.
628 *
629 * @param cls our `struct ClientState *`
630 * @param addr address to try, NULL for "last call"
631 * @param addrlen length of @a addr
632 */
633static void
634try_connect_using_address (void *cls,
635 const struct sockaddr *addr,
636 socklen_t addrlen)
637{
638 struct ClientState *cstate = cls;
639 struct AddressProbe *ap;
640
641 if (NULL == addr)
642 {
643 cstate->dns_active = NULL;
644 if ((NULL == cstate->ap_head) &&
645 // (NULL == cstate->proxy_handshake) &&
646 (NULL == cstate->sock))
647 connect_fail_continuation (cstate);
648 return;
649 }
650 if (NULL != cstate->sock)
651 return; /* already connected */
652 /* try to connect */
653 LOG (GNUNET_ERROR_TYPE_DEBUG,
654 "Trying to connect using address `%s:%u'\n",
655 GNUNET_a2s (addr,
656 addrlen),
657 (unsigned int) cstate->port);
658 ap = GNUNET_malloc (sizeof(struct AddressProbe) + addrlen);
659 ap->addr = (const struct sockaddr *) &ap[1];
660 GNUNET_memcpy (&ap[1],
661 addr,
662 addrlen);
663 ap->addrlen = addrlen;
664 ap->cstate = cstate;
665
666 switch (ap->addr->sa_family)
667 {
668 case AF_INET:
669 ((struct sockaddr_in *) ap->addr)->sin_port = htons (cstate->port);
670 break;
671
672 case AF_INET6:
673 ((struct sockaddr_in6 *) ap->addr)->sin6_port = htons (cstate->port);
674 break;
675
676 default:
677 GNUNET_break (0);
678 GNUNET_free (ap);
679 return; /* not supported by us */
680 }
681 ap->sock = GNUNET_NETWORK_socket_create (ap->addr->sa_family,
682 SOCK_STREAM,
683 0);
684 if (NULL == ap->sock)
685 {
686 GNUNET_free (ap);
687 return; /* not supported by OS */
688 }
689 if ((GNUNET_OK !=
690 GNUNET_NETWORK_socket_connect (ap->sock,
691 ap->addr,
692 ap->addrlen)) &&
693 (EINPROGRESS != errno))
694 {
695 /* maybe refused / unsupported address, try next */
696 GNUNET_log_strerror (GNUNET_ERROR_TYPE_INFO,
697 "connect");
698 GNUNET_break (GNUNET_OK ==
699 GNUNET_NETWORK_socket_close (ap->sock));
700 GNUNET_free (ap);
701 return;
702 }
703 GNUNET_CONTAINER_DLL_insert (cstate->ap_head,
704 cstate->ap_tail,
705 ap);
706 ap->task = GNUNET_SCHEDULER_add_write_net (CONNECT_RETRY_TIMEOUT,
707 ap->sock,
708 &connect_probe_continuation,
709 ap);
710}
711
712
713/**
714 * Test whether the configuration has proper values for connection
715 * (UNIXPATH || (PORT && HOSTNAME)).
716 *
717 * @param service_name name of service to connect to
718 * @param cfg configuration to use
719 * @return #GNUNET_OK if the configuration is valid, #GNUNET_SYSERR if not
720 */
721static int
722test_service_configuration (const char *service_name,
723 const struct GNUNET_CONFIGURATION_Handle *cfg)
724{
725 int ret = GNUNET_SYSERR;
726 char *hostname = NULL;
727 unsigned long long port;
728
729#if AF_UNIX
730 char *unixpath = NULL;
731
732 if ((GNUNET_OK ==
733 GNUNET_CONFIGURATION_get_value_filename (cfg,
734 service_name,
735 "UNIXPATH",
736 &unixpath)) &&
737 (0 < strlen (unixpath)))
738 ret = GNUNET_OK;
739 else if ((GNUNET_OK ==
740 GNUNET_CONFIGURATION_have_value (cfg,
741 service_name,
742 "UNIXPATH")))
743 {
744 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
745 service_name,
746 "UNIXPATH",
747 _ ("not a valid filename"));
748 GNUNET_free (unixpath);
749 return GNUNET_SYSERR; /* UNIXPATH specified but invalid! */
750 }
751 GNUNET_free (unixpath);
752#endif
753
754 if ((GNUNET_YES ==
755 GNUNET_CONFIGURATION_have_value (cfg,
756 service_name,
757 "PORT")) &&
758 (GNUNET_OK ==
759 GNUNET_CONFIGURATION_get_value_number (cfg,
760 service_name,
761 "PORT",
762 &port)) &&
763 (port <= 65535) &&
764 (0 != port) &&
765 (GNUNET_OK ==
766 GNUNET_CONFIGURATION_get_value_string (cfg,
767 service_name,
768 "HOSTNAME",
769 &hostname)) &&
770 (0 != strlen (hostname)))
771 ret = GNUNET_OK;
772 GNUNET_free (hostname);
773 return ret;
774}
775
776
777/**
778 * Try to connect to the service.
779 *
780 * @param cls the `struct ClientState` to try to connect to the service
781 */
782static void
783start_connect (void *cls)
784{
785 struct ClientState *cstate = cls;
786
787 cstate->retry_task = NULL;
788#if 0
789 /* Never use a local source if a proxy is configured */
790 if (GNUNET_YES ==
791 GNUNET_SOCKS_check_service (cstate->service_name,
792 cstate->cfg))
793 {
794 socks_connect (cstate);
795 return;
796 }
797#endif
798
799 if ((0 == (cstate->attempts++ % 2)) ||
800 (0 == cstate->port) ||
801 (NULL == cstate->hostname))
802 {
803 /* on even rounds, try UNIX first, or always
804 if we do not have a DNS name and TCP port. */
805 cstate->sock = try_unixpath (cstate->service_name,
806 cstate->cfg);
807 if (NULL != cstate->sock)
808 {
809 connect_success_continuation (cstate);
810 return;
811 }
812 }
813 if ((NULL == cstate->hostname) ||
814 (0 == cstate->port))
815 {
816 /* All options failed. Boo! */
817 connect_fail_continuation (cstate);
818 return;
819 }
820 cstate->dns_active
821 = GNUNET_RESOLVER_ip_get (cstate->hostname,
822 AF_UNSPEC,
823 CONNECT_RETRY_TIMEOUT,
824 &try_connect_using_address,
825 cstate);
826}
827
828
829/**
830 * Implements the transmission functionality of a message queue.
831 *
832 * @param mq the message queue
833 * @param msg the message to send
834 * @param impl_state our `struct ClientState`
835 */
836static void
837connection_client_send_impl (struct GNUNET_MQ_Handle *mq,
838 const struct GNUNET_MessageHeader *msg,
839 void *impl_state)
840{
841 struct ClientState *cstate = impl_state;
842
843 (void) mq;
844 /* only one message at a time allowed */
845 GNUNET_assert (NULL == cstate->msg);
846 GNUNET_assert (NULL == cstate->send_task);
847 cstate->msg = msg;
848 cstate->msg_off = 0;
849 if (NULL == cstate->sock)
850 {
851 LOG (GNUNET_ERROR_TYPE_DEBUG,
852 "message of type %u waiting for socket\n",
853 ntohs (msg->type));
854 return; /* still waiting for connection */
855 }
856 cstate->send_task
857 = GNUNET_SCHEDULER_add_now (&transmit_ready,
858 cstate);
859}
860
861
862/**
863 * Cancel the currently sent message.
864 *
865 * @param mq message queue
866 * @param impl_state our `struct ClientState`
867 */
868static void
869connection_client_cancel_impl (struct GNUNET_MQ_Handle *mq,
870 void *impl_state)
871{
872 struct ClientState *cstate = impl_state;
873
874 (void) mq;
875 GNUNET_assert (NULL != cstate->msg);
876 GNUNET_assert (0 == cstate->msg_off);
877 cstate->msg = NULL;
878 if (NULL != cstate->send_task)
879 {
880 GNUNET_SCHEDULER_cancel (cstate->send_task);
881 cstate->send_task = NULL;
882 }
883}
884
885
886/**
887 * Test if the port or UNIXPATH of the given @a service_name
888 * is in use and thus (most likely) the respective service is up.
889 *
890 * @param cfg our configuration
891 * @param service_name name of the service to connect to
892 * @return #GNUNET_YES if the service is (likely) up,
893 * #GNUNET_NO if the service is (definitively) down,
894 * #GNUNET_SYSERR if the configuration does not give us
895 * the necessary information about the service, or if
896 * we could not check (e.g. socket() failed)
897 */
898int
899GNUNET_CLIENT_test (const struct GNUNET_CONFIGURATION_Handle *cfg,
900 const char *service_name)
901{
902 char *hostname = NULL;
903 unsigned long long port;
904 int ret;
905
906#if AF_UNIX
907 {
908 char *unixpath = NULL;
909
910 if (GNUNET_OK ==
911 GNUNET_CONFIGURATION_get_value_filename (cfg,
912 service_name,
913 "UNIXPATH",
914 &unixpath))
915 {
916 if (0 == strlen (unixpath))
917 {
918 GNUNET_free (unixpath);
919 return GNUNET_SYSERR; /* empty string not OK */
920 }
921 if (0 == access (unixpath,
922 F_OK))
923 {
924 GNUNET_free (unixpath);
925 return GNUNET_OK; /* file exists, we assume service is running */
926 }
927 GNUNET_free (unixpath);
928 }
929 else if (GNUNET_OK ==
930 GNUNET_CONFIGURATION_have_value (cfg,
931 service_name,
932 "UNIXPATH"))
933 {
934 /* UNIXPATH specified but not a valid path! */
935 GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
936 service_name,
937 "UNIXPATH",
938 _ ("not a valid filename"));
939 return GNUNET_SYSERR;
940 }
941 }
942#endif
943
944 if ( (GNUNET_OK !=
945 GNUNET_CONFIGURATION_get_value_number (cfg,
946 service_name,
947 "PORT",
948 &port)) ||
949 (port > 65535) ||
950 (0 == port) )
951 {
952 return GNUNET_SYSERR;
953 }
954 if (GNUNET_OK ==
955 GNUNET_CONFIGURATION_get_value_string (cfg,
956 service_name,
957 "HOSTNAME",
958 &hostname))
959 {
960 /* We always assume remotes are up */
961 ret = GNUNET_YES;
962 }
963 else
964 {
965 /* We look for evidence the service is up */
966 ret = GNUNET_NO;
967 }
968 if ( (NULL == hostname) ||
969 (0 == strcasecmp (hostname,
970 "localhost")) ||
971 (0 == strcasecmp (hostname,
972 "ip6-localnet")) )
973 {
974 /* service runs on loopback */
975 struct sockaddr_in v4;
976 struct sockaddr_in6 v6;
977 int sock;
978
979 memset (&v4, 0, sizeof (v4));
980 memset (&v6, 0, sizeof (v6));
981 v4.sin_family = AF_INET;
982 v4.sin_port = htons ((uint16_t) port);
983#if HAVE_SOCKADDR_IN_SUN_LEN
984 v4.sin_len = (u_char) sizeof(struct sockaddr_in);
985#endif
986 inet_pton (AF_INET,
987 "127.0.0.1",
988 &v4.sin_addr);
989 ret = GNUNET_NO;
990 sock = socket (AF_INET,
991 SOCK_STREAM,
992 0);
993 if (-1 != sock)
994 {
995 if (0 != bind (sock,
996 (struct sockaddr *) &v4,
997 sizeof (v4)))
998 {
999 /* bind failed, so someone is listening! */
1000 ret = GNUNET_YES;
1001 }
1002 (void) close (sock);
1003 }
1004 else
1005 {
1006 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
1007 "socket");
1008 if (GNUNET_NO == ret)
1009 ret = GNUNET_SYSERR;
1010 }
1011 v6.sin6_family = AF_INET6;
1012 v6.sin6_port = htons ((uint16_t) port);
1013#if HAVE_SOCKADDR_IN_SUN_LEN
1014 v6.sin6_len = (u_char) sizeof(struct sockaddr_in6);
1015#endif
1016 inet_pton (AF_INET6,
1017 "::1",
1018 &v6.sin6_addr);
1019 sock = socket (AF_INET6,
1020 SOCK_STREAM,
1021 0);
1022 if (-1 != sock)
1023 {
1024 if (0 != bind (sock,
1025 (struct sockaddr *) &v6,
1026 sizeof (v6)))
1027 {
1028 /* bind failed, so someone is listening! */
1029 ret = GNUNET_YES;
1030 }
1031 (void) close (sock);
1032 }
1033 else
1034 {
1035 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
1036 "socket");
1037 /* not changing 'ret' intentionally here, as
1038 v4 succeeding and v6 failing just means we
1039 should use v4 */
1040 }
1041 }
1042 else
1043 {
1044 /* service running remotely */
1045 ret = GNUNET_OK;
1046 }
1047 GNUNET_free (hostname);
1048 return ret;
1049}
1050
1051
1052/**
1053 * Create a message queue to connect to a GNUnet service.
1054 * If handlers are specified, receive messages from the connection.
1055 *
1056 * @param cfg our configuration
1057 * @param service_name name of the service to connect to
1058 * @param handlers handlers for receiving messages, can be NULL
1059 * @param error_handler error handler
1060 * @param error_handler_cls closure for the @a error_handler
1061 * @return the message queue, NULL on error
1062 */
1063struct GNUNET_MQ_Handle *
1064GNUNET_CLIENT_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
1065 const char *service_name,
1066 const struct GNUNET_MQ_MessageHandler *handlers,
1067 GNUNET_MQ_ErrorHandler error_handler,
1068 void *error_handler_cls)
1069{
1070 struct ClientState *cstate;
1071
1072 if (GNUNET_OK !=
1073 test_service_configuration (service_name,
1074 cfg))
1075 return NULL;
1076 cstate = GNUNET_new (struct ClientState);
1077 cstate->service_name = GNUNET_strdup (service_name);
1078 cstate->cfg = cfg;
1079 cstate->retry_task = GNUNET_SCHEDULER_add_now (&start_connect,
1080 cstate);
1081 cstate->mst = GNUNET_MST_create (&recv_message,
1082 cstate);
1083 if (GNUNET_YES ==
1084 GNUNET_CONFIGURATION_have_value (cfg,
1085 service_name,
1086 "PORT"))
1087 {
1088 if (! ((GNUNET_OK !=
1089 GNUNET_CONFIGURATION_get_value_number (cfg,
1090 service_name,
1091 "PORT",
1092 &cstate->port)) ||
1093 (cstate->port > 65535) ||
1094 (GNUNET_OK !=
1095 GNUNET_CONFIGURATION_get_value_string (cfg,
1096 service_name,
1097 "HOSTNAME",
1098 &cstate->hostname))) &&
1099 (0 == strlen (cstate->hostname)))
1100 {
1101 GNUNET_free (cstate->hostname);
1102 cstate->hostname = NULL;
1103 LOG (GNUNET_ERROR_TYPE_WARNING,
1104 _ ("Need a non-empty hostname for service `%s'.\n"),
1105 service_name);
1106 }
1107 }
1108 cstate->mq = GNUNET_MQ_queue_for_callbacks (&connection_client_send_impl,
1109 &connection_client_destroy_impl,
1110 &connection_client_cancel_impl,
1111 cstate,
1112 handlers,
1113 error_handler,
1114 error_handler_cls);
1115 return cstate->mq;
1116}
1117
1118
1119/* end of client.c */