error handling
[oweals/gnunet.git] / src / util / client.c
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  */
51 struct ClientState;
52
53
54 /**
55  * During connect, we try multiple possible IP addresses
56  * to find out which one might work.
57  */
58 struct 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    * Lenth 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  */
100 struct 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  */
209 static void
210 start_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  */
219 static void
220 connect_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  */
248 static void
249 transmit_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
269 RETRY:
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  */
331 static int
332 recv_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  */
357 static void
358 cancel_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  */
382 static void
383 connection_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_non_null (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  */
436 static void
437 receive_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  */
478 static void
479 connect_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  */
506 static struct GNUNET_NETWORK_Handle *
507 try_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_non_null (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  */
578 static void
579 connect_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  */
633 static void
634 try_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        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  */
721 static int
722 test_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     return GNUNET_SYSERR;   /* UNIXPATH specified but invalid! */
749   }
750   GNUNET_free_non_null (unixpath);
751 #endif
752
753   if ((GNUNET_YES ==
754        GNUNET_CONFIGURATION_have_value (cfg,
755                                         service_name,
756                                         "PORT")) &&
757       (GNUNET_OK ==
758        GNUNET_CONFIGURATION_get_value_number (cfg,
759                                               service_name,
760                                               "PORT",
761                                               &port)) &&
762       (port <= 65535) &&
763       (0 != port) &&
764       (GNUNET_OK ==
765        GNUNET_CONFIGURATION_get_value_string (cfg,
766                                               service_name,
767                                               "HOSTNAME",
768                                               &hostname)) &&
769       (0 != strlen (hostname)))
770     ret = GNUNET_OK;
771   GNUNET_free_non_null (hostname);
772   return ret;
773 }
774
775
776 /**
777  * Try to connect to the service.
778  *
779  * @param cls the `struct ClientState` to try to connect to the service
780  */
781 static void
782 start_connect (void *cls)
783 {
784   struct ClientState *cstate = cls;
785
786   cstate->retry_task = NULL;
787 #if 0
788   /* Never use a local source if a proxy is configured */
789   if (GNUNET_YES ==
790       GNUNET_SOCKS_check_service (cstate->service_name,
791                                   cstate->cfg))
792   {
793     socks_connect (cstate);
794     return;
795   }
796 #endif
797
798   if ((0 == (cstate->attempts++ % 2)) ||
799       (0 == cstate->port) ||
800       (NULL == cstate->hostname))
801   {
802     /* on even rounds, try UNIX first, or always
803        if we do not have a DNS name and TCP port. */
804     cstate->sock = try_unixpath (cstate->service_name,
805                                  cstate->cfg);
806     if (NULL != cstate->sock)
807     {
808       connect_success_continuation (cstate);
809       return;
810     }
811   }
812   if ((NULL == cstate->hostname) ||
813       (0 == cstate->port))
814   {
815     /* All options failed. Boo! */
816     connect_fail_continuation (cstate);
817     return;
818   }
819   cstate->dns_active
820     = GNUNET_RESOLVER_ip_get (cstate->hostname,
821                               AF_UNSPEC,
822                               CONNECT_RETRY_TIMEOUT,
823                               &try_connect_using_address,
824                               cstate);
825 }
826
827
828 /**
829  * Implements the transmission functionality of a message queue.
830  *
831  * @param mq the message queue
832  * @param msg the message to send
833  * @param impl_state our `struct ClientState`
834  */
835 static void
836 connection_client_send_impl (struct GNUNET_MQ_Handle *mq,
837                              const struct GNUNET_MessageHeader *msg,
838                              void *impl_state)
839 {
840   struct ClientState *cstate = impl_state;
841
842   (void) mq;
843   /* only one message at a time allowed */
844   GNUNET_assert (NULL == cstate->msg);
845   GNUNET_assert (NULL == cstate->send_task);
846   cstate->msg = msg;
847   cstate->msg_off = 0;
848   if (NULL == cstate->sock)
849   {
850     LOG (GNUNET_ERROR_TYPE_DEBUG,
851          "message of type %u waiting for socket\n",
852          ntohs (msg->type));
853     return;   /* still waiting for connection */
854   }
855   cstate->send_task
856     = GNUNET_SCHEDULER_add_now (&transmit_ready,
857                                 cstate);
858 }
859
860
861 /**
862  * Cancel the currently sent message.
863  *
864  * @param mq message queue
865  * @param impl_state our `struct ClientState`
866  */
867 static void
868 connection_client_cancel_impl (struct GNUNET_MQ_Handle *mq,
869                                void *impl_state)
870 {
871   struct ClientState *cstate = impl_state;
872
873   (void) mq;
874   GNUNET_assert (NULL != cstate->msg);
875   GNUNET_assert (0 == cstate->msg_off);
876   cstate->msg = NULL;
877   if (NULL != cstate->send_task)
878   {
879     GNUNET_SCHEDULER_cancel (cstate->send_task);
880     cstate->send_task = NULL;
881   }
882 }
883
884
885 /**
886  * Test if the port or UNIXPATH of the given @a service_name
887  * is in use and thus (most likely) the respective service is up.
888  *
889  * @param cfg our configuration
890  * @param service_name name of the service to connect to
891  * @return #GNUNET_YES if the service is (likely) up,
892  *         #GNUNET_NO if the service is (definitively) down,
893  *         #GNUNET_SYSERR if the configuration does not give us
894  *          the necessary information about the service, or if
895  *          we could not check (i.e. socket() failed)
896  */
897 int
898 GNUNET_CLIENT_test (const struct GNUNET_CONFIGURATION_Handle *cfg,
899                     const char *service_name)
900 {
901   char *hostname = NULL;
902   unsigned long long port;
903   int ret;
904
905 #if AF_UNIX
906   {
907     char *unixpath = NULL;
908
909     if (GNUNET_OK ==
910         GNUNET_CONFIGURATION_get_value_filename (cfg,
911                                                  service_name,
912                                                  "UNIXPATH",
913                                                  &unixpath))
914     {
915       if (0 == strlen (unixpath))
916       {
917         GNUNET_free (unixpath);
918         return GNUNET_SYSERR; /* empty string not OK */
919       }
920       if (0 == access (unixpath,
921                        F_OK))
922       {
923         GNUNET_free (unixpath);
924         return GNUNET_OK; /* file exists, we assume service is running */
925       }
926       GNUNET_free (unixpath);
927     }
928     else if (GNUNET_OK ==
929              GNUNET_CONFIGURATION_have_value (cfg,
930                                               service_name,
931                                               "UNIXPATH"))
932     {
933       /* UNIXPATH specified but not a valid path! */
934       GNUNET_log_config_invalid (GNUNET_ERROR_TYPE_ERROR,
935                                  service_name,
936                                  "UNIXPATH",
937                                  _ ("not a valid filename"));
938       return GNUNET_SYSERR;
939     }
940   }
941 #endif
942
943   if ( (GNUNET_OK !=
944         GNUNET_CONFIGURATION_get_value_number (cfg,
945                                                service_name,
946                                                "PORT",
947                                                &port)) ||
948        (port > 65535) ||
949        (0 == port) )
950   {
951     return GNUNET_SYSERR;
952   }
953   if (GNUNET_OK ==
954       GNUNET_CONFIGURATION_get_value_string (cfg,
955                                              service_name,
956                                              "HOSTNAME",
957                                              &hostname))
958   {
959     /* We always assume remotes are up */
960     ret = GNUNET_YES;
961   }
962   else
963   {
964     /* We look for evidence the service is up */
965     ret = GNUNET_NO;
966   }
967   if ( (NULL == hostname) ||
968        (0 == strcasecmp (hostname,
969                          "localhost")) ||
970        (0 == strcasecmp (hostname,
971                          "ip6-localnet")) )
972   {
973     /* service runs on loopback */
974     struct sockaddr_in v4;
975     struct sockaddr_in6 v6;
976     int sock;
977
978     memset (&v4, 0, sizeof (v4));
979     memset (&v6, 0, sizeof (v6));
980     v4.sin_family = AF_INET;
981     v4.sin_port = htons ((uint16_t) port);
982 #if HAVE_SOCKADDR_IN_SUN_LEN
983     v4.sin_len = (u_char) sizeof(struct sockaddr_in);
984 #endif
985     inet_pton (AF_INET,
986                "127.0.0.1",
987                &v4.sin_addr);
988     ret = GNUNET_NO;
989     sock = socket (AF_INET,
990                    SOCK_STREAM,
991                    0);
992     if (-1 != sock)
993     {
994       if (0 != bind (sock,
995                      (struct sockaddr *) &v4,
996                      sizeof (v4)))
997       {
998         /* bind failed, so someone is listening! */
999         ret = GNUNET_YES;
1000       }
1001       (void) close (sock);
1002     }
1003     else
1004     {
1005       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
1006                            "socket");
1007       if (GNUNET_NO == ret)
1008         ret = GNUNET_SYSERR;
1009     }
1010     v6.sin6_family = AF_INET6;
1011     v6.sin6_port = htons ((uint16_t) port);
1012 #if HAVE_SOCKADDR_IN_SUN_LEN
1013     v6.sin6_len = (u_char) sizeof(struct sockaddr_in6);
1014 #endif
1015     inet_pton (AF_INET6,
1016                "::1",
1017                &v6.sin6_addr);
1018     sock = socket (AF_INET6,
1019                    SOCK_STREAM,
1020                    0);
1021     if (-1 != sock)
1022     {
1023       if (0 != bind (sock,
1024                      (struct sockaddr *) &v6,
1025                      sizeof (v6)))
1026       {
1027         /* bind failed, so someone is listening! */
1028         ret = GNUNET_YES;
1029       }
1030       (void) close (sock);
1031     }
1032     else
1033     {
1034       GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
1035                            "socket");
1036       /* not changing 'ret' intentionally here, as
1037          v4 succeeding and v6 failing just means we
1038          should use v4 */
1039     }
1040   }
1041   else
1042   {
1043     /* service running remotely */
1044     ret = GNUNET_OK;
1045   }
1046   GNUNET_free_non_null (hostname);
1047   return ret;
1048 }
1049
1050
1051 /**
1052  * Create a message queue to connect to a GNUnet service.
1053  * If handlers are specfied, receive messages from the connection.
1054  *
1055  * @param cfg our configuration
1056  * @param service_name name of the service to connect to
1057  * @param handlers handlers for receiving messages, can be NULL
1058  * @param error_handler error handler
1059  * @param error_handler_cls closure for the @a error_handler
1060  * @return the message queue, NULL on error
1061  */
1062 struct GNUNET_MQ_Handle *
1063 GNUNET_CLIENT_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
1064                        const char *service_name,
1065                        const struct GNUNET_MQ_MessageHandler *handlers,
1066                        GNUNET_MQ_ErrorHandler error_handler,
1067                        void *error_handler_cls)
1068 {
1069   struct ClientState *cstate;
1070
1071   if (GNUNET_OK !=
1072       test_service_configuration (service_name,
1073                                   cfg))
1074     return NULL;
1075   cstate = GNUNET_new (struct ClientState);
1076   cstate->service_name = GNUNET_strdup (service_name);
1077   cstate->cfg = cfg;
1078   cstate->retry_task = GNUNET_SCHEDULER_add_now (&start_connect,
1079                                                  cstate);
1080   cstate->mst = GNUNET_MST_create (&recv_message,
1081                                    cstate);
1082   if (GNUNET_YES ==
1083       GNUNET_CONFIGURATION_have_value (cfg,
1084                                        service_name,
1085                                        "PORT"))
1086   {
1087     if (! ((GNUNET_OK !=
1088             GNUNET_CONFIGURATION_get_value_number (cfg,
1089                                                    service_name,
1090                                                    "PORT",
1091                                                    &cstate->port)) ||
1092            (cstate->port > 65535) ||
1093            (GNUNET_OK !=
1094             GNUNET_CONFIGURATION_get_value_string (cfg,
1095                                                    service_name,
1096                                                    "HOSTNAME",
1097                                                    &cstate->hostname))) &&
1098         (0 == strlen (cstate->hostname)))
1099     {
1100       GNUNET_free (cstate->hostname);
1101       cstate->hostname = NULL;
1102       LOG (GNUNET_ERROR_TYPE_WARNING,
1103            _ ("Need a non-empty hostname for service `%s'.\n"),
1104            service_name);
1105     }
1106   }
1107   cstate->mq = GNUNET_MQ_queue_for_callbacks (&connection_client_send_impl,
1108                                               &connection_client_destroy_impl,
1109                                               &connection_client_cancel_impl,
1110                                               cstate,
1111                                               handlers,
1112                                               error_handler,
1113                                               error_handler_cls);
1114   return cstate->mq;
1115 }
1116
1117
1118 /* end of client.c */