plibc: win32 related, socket
[oweals/gnunet.git] / src / util / client.c
1 /*
2      This file is part of GNUnet.
3      Copyright (C) 2001-2016 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(GNUNET_TIME_UNIT_SECONDS, 5)
45
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    * This is a linked list.
61    */
62   struct AddressProbe *next;
63
64   /**
65    * This is a doubly-linked list.
66    */
67   struct AddressProbe *prev;
68
69   /**
70    * The address; do not free (allocated at the end of this struct).
71    */
72   const struct sockaddr *addr;
73
74   /**
75    * Underlying OS's socket.
76    */
77   struct GNUNET_NETWORK_Handle *sock;
78
79   /**
80    * Connection for which we are probing.
81    */
82   struct ClientState *cstate;
83
84   /**
85    * Lenth of addr.
86    */
87   socklen_t addrlen;
88
89   /**
90    * Task waiting for the connection to finish connecting.
91    */
92   struct GNUNET_SCHEDULER_Task *task;
93 };
94
95
96 /**
97  * Internal state for a client connected to a GNUnet service.
98  */
99 struct ClientState {
100   /**
101    * The connection handle, NULL if not live
102    */
103   struct GNUNET_NETWORK_Handle *sock;
104
105   /**
106    * Handle to a pending DNS lookup request, NULL if DNS is finished.
107    */
108   struct GNUNET_RESOLVER_RequestHandle *dns_active;
109
110   /**
111    * Our configuration.
112    */
113   const struct GNUNET_CONFIGURATION_Handle *cfg;
114
115   /**
116    * Linked list of sockets we are currently trying out
117    * (during connect).
118    */
119   struct AddressProbe *ap_head;
120
121   /**
122    * Linked list of sockets we are currently trying out
123    * (during connect).
124    */
125   struct AddressProbe *ap_tail;
126
127   /**
128    * Name of the service we interact with.
129    */
130   char *service_name;
131
132   /**
133    * Hostname, if any.
134    */
135   char *hostname;
136
137   /**
138    * Next message to transmit to the service. NULL for none.
139    */
140   const struct GNUNET_MessageHeader *msg;
141
142   /**
143    * Task for trying to connect to the service.
144    */
145   struct GNUNET_SCHEDULER_Task *retry_task;
146
147   /**
148    * Task for sending messages to the service.
149    */
150   struct GNUNET_SCHEDULER_Task *send_task;
151
152   /**
153    * Task for sending messages to the service.
154    */
155   struct GNUNET_SCHEDULER_Task *recv_task;
156
157   /**
158    * Tokenizer for inbound messages.
159    */
160   struct GNUNET_MessageStreamTokenizer *mst;
161
162   /**
163    * Message queue under our control.
164    */
165   struct GNUNET_MQ_Handle *mq;
166
167   /**
168    * Timeout for receiving a response (absolute time).
169    */
170   struct GNUNET_TIME_Absolute receive_timeout;
171
172   /**
173    * Current value for our incremental back-off (for
174    * connect re-tries).
175    */
176   struct GNUNET_TIME_Relative back_off;
177
178   /**
179    * TCP port (0 for disabled).
180    */
181   unsigned long long port;
182
183   /**
184    * Offset in the message where we are for transmission.
185    */
186   size_t msg_off;
187
188   /**
189    * How often have we tried to connect?
190    */
191   unsigned int attempts;
192
193   /**
194    * Are we supposed to die?  #GNUNET_SYSERR if destruction must be
195    * deferred, #GNUNET_NO by default, #GNUNET_YES if destruction was
196    * deferred.
197    */
198   int in_destroy;
199 };
200
201
202 /**
203  * Try to connect to the service.
204  *
205  * @param cls the `struct ClientState` to try to connect to the service
206  */
207 static void
208 start_connect(void *cls);
209
210
211 /**
212  * We've failed for good to establish a connection (timeout or
213  * no more addresses to try).
214  *
215  * @param cstate the connection we tried to establish
216  */
217 static void
218 connect_fail_continuation(struct ClientState *cstate)
219 {
220   GNUNET_break(NULL == cstate->ap_head);
221   GNUNET_break(NULL == cstate->ap_tail);
222   GNUNET_break(NULL == cstate->dns_active);
223   GNUNET_break(NULL == cstate->sock);
224   GNUNET_assert(NULL == cstate->send_task);
225   GNUNET_assert(NULL == cstate->recv_task);
226   // GNUNET_assert (NULL == cstate->proxy_handshake);
227
228   cstate->back_off = GNUNET_TIME_STD_BACKOFF(cstate->back_off);
229   LOG(GNUNET_ERROR_TYPE_DEBUG,
230       "Failed to establish connection to `%s', no further addresses to try, will try again in %s.\n",
231       cstate->service_name,
232       GNUNET_STRINGS_relative_time_to_string(cstate->back_off,
233                                              GNUNET_YES));
234   cstate->retry_task
235     = GNUNET_SCHEDULER_add_delayed(cstate->back_off,
236                                    &start_connect,
237                                    cstate);
238 }
239
240
241 /**
242  * We are ready to send a message to the service.
243  *
244  * @param cls the `struct ClientState` with the `msg` to transmit
245  */
246 static void
247 transmit_ready(void *cls)
248 {
249   struct ClientState *cstate = cls;
250   ssize_t ret;
251   size_t len;
252   const char *pos;
253   int notify_in_flight;
254
255   cstate->send_task = NULL;
256   if (GNUNET_YES == cstate->in_destroy)
257     return;
258   pos = (const char *)cstate->msg;
259   len = ntohs(cstate->msg->size);
260   GNUNET_assert(cstate->msg_off < len);
261   LOG(GNUNET_ERROR_TYPE_DEBUG,
262       "message of type %u trying to send with socket %p (MQ: %p\n",
263       ntohs(cstate->msg->type),
264       cstate->sock,
265       cstate->mq);
266
267 RETRY:
268   ret = GNUNET_NETWORK_socket_send(cstate->sock,
269                                    &pos[cstate->msg_off],
270                                    len - cstate->msg_off);
271   if (-1 == ret)
272     {
273       LOG(GNUNET_ERROR_TYPE_WARNING,
274           "Error during sending message of type %u\n",
275           ntohs(cstate->msg->type));
276       if (EINTR == errno)
277         {
278           LOG(GNUNET_ERROR_TYPE_DEBUG,
279               "Retrying message of type %u\n",
280               ntohs(cstate->msg->type));
281           goto RETRY;
282         }
283       GNUNET_MQ_inject_error(cstate->mq,
284                              GNUNET_MQ_ERROR_WRITE);
285       return;
286     }
287   notify_in_flight = (0 == cstate->msg_off);
288   cstate->msg_off += ret;
289   if (cstate->msg_off < len)
290     {
291       LOG(GNUNET_ERROR_TYPE_DEBUG,
292           "rescheduling message of type %u\n",
293           ntohs(cstate->msg->type));
294       cstate->send_task
295         = GNUNET_SCHEDULER_add_write_net(GNUNET_TIME_UNIT_FOREVER_REL,
296                                          cstate->sock,
297                                          &transmit_ready,
298                                          cstate);
299       if (notify_in_flight)
300         GNUNET_MQ_impl_send_in_flight(cstate->mq);
301       return;
302     }
303   LOG(GNUNET_ERROR_TYPE_DEBUG,
304       "sending message of type %u successful\n",
305       ntohs(cstate->msg->type));
306   cstate->msg = NULL;
307   GNUNET_MQ_impl_send_continue(cstate->mq);
308 }
309
310
311 /**
312  * We have received a full message, pass to the MQ dispatcher.
313  * Called by the tokenizer via #receive_ready().
314  *
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
320  */
321 static int
322 recv_message(void *cls,
323              const struct GNUNET_MessageHeader *msg)
324 {
325   struct ClientState *cstate = cls;
326
327   if (GNUNET_YES == cstate->in_destroy)
328     return GNUNET_NO;
329   LOG(GNUNET_ERROR_TYPE_DEBUG,
330       "Received message of type %u and size %u from %s\n",
331       ntohs(msg->type),
332       ntohs(msg->size),
333       cstate->service_name);
334   GNUNET_MQ_inject_message(cstate->mq,
335                            msg);
336   if (GNUNET_YES == cstate->in_destroy)
337     return GNUNET_NO;
338   return GNUNET_OK;
339 }
340
341
342 /**
343  * Cancel all remaining connect attempts
344  *
345  * @param cstate handle of the client state to process
346  */
347 static void
348 cancel_aps(struct ClientState *cstate)
349 {
350   struct AddressProbe *pos;
351
352   while (NULL != (pos = cstate->ap_head))
353     {
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,
358                                   cstate->ap_tail,
359                                   pos);
360       GNUNET_free(pos);
361     }
362 }
363
364
365 /**
366  * Implement the destruction of a message queue.  Implementations must
367  * not free @a mq, but should take care of @a impl_state.
368  *
369  * @param mq the message queue to destroy
370  * @param impl_state our `struct ClientState`
371  */
372 static void
373 connection_client_destroy_impl(struct GNUNET_MQ_Handle *mq,
374                                void *impl_state)
375 {
376   struct ClientState *cstate = impl_state;
377
378   (void)mq;
379   if (NULL != cstate->dns_active)
380     {
381       GNUNET_RESOLVER_request_cancel(cstate->dns_active);
382       cstate->dns_active = NULL;
383     }
384   if (NULL != cstate->send_task)
385     {
386       GNUNET_SCHEDULER_cancel(cstate->send_task);
387       cstate->send_task = NULL;
388     }
389   if (NULL != cstate->retry_task)
390     {
391       GNUNET_SCHEDULER_cancel(cstate->retry_task);
392       cstate->retry_task = NULL;
393     }
394   if (GNUNET_SYSERR == cstate->in_destroy)
395     {
396       /* defer destruction */
397       cstate->in_destroy = GNUNET_YES;
398       cstate->mq = NULL;
399       return;
400     }
401   if (NULL != cstate->recv_task)
402     {
403       GNUNET_SCHEDULER_cancel(cstate->recv_task);
404       cstate->recv_task = NULL;
405     }
406   if (NULL != cstate->sock)
407     {
408       LOG(GNUNET_ERROR_TYPE_DEBUG,
409           "destroying socket: %p\n",
410           cstate->sock);
411       GNUNET_NETWORK_socket_close(cstate->sock);
412     }
413   cancel_aps(cstate);
414   GNUNET_free(cstate->service_name);
415   GNUNET_free_non_null(cstate->hostname);
416   GNUNET_MST_destroy(cstate->mst);
417   GNUNET_free(cstate);
418 }
419
420
421 /**
422  * This function is called once we have data ready to read.
423  *
424  * @param cls `struct ClientState` with connection to read from
425  */
426 static void
427 receive_ready(void *cls)
428 {
429   struct ClientState *cstate = cls;
430   int ret;
431
432   cstate->recv_task = NULL;
433   cstate->in_destroy = GNUNET_SYSERR;
434   ret = GNUNET_MST_read(cstate->mst,
435                         cstate->sock,
436                         GNUNET_NO,
437                         GNUNET_NO);
438   if (GNUNET_SYSERR == ret)
439     {
440       if (NULL != cstate->mq)
441         GNUNET_MQ_inject_error(cstate->mq,
442                                GNUNET_MQ_ERROR_READ);
443       if (GNUNET_YES == cstate->in_destroy)
444         connection_client_destroy_impl(cstate->mq,
445                                        cstate);
446       return;
447     }
448   if (GNUNET_YES == cstate->in_destroy)
449     {
450       connection_client_destroy_impl(cstate->mq,
451                                      cstate);
452       return;
453     }
454   cstate->in_destroy = GNUNET_NO;
455   cstate->recv_task
456     = GNUNET_SCHEDULER_add_read_net(GNUNET_TIME_UNIT_FOREVER_REL,
457                                     cstate->sock,
458                                     &receive_ready,
459                                     cstate);
460 }
461
462
463 /**
464  * We've succeeded in establishing a connection.
465  *
466  * @param cstate the connection we tried to establish
467  */
468 static void
469 connect_success_continuation(struct ClientState *cstate)
470 {
471   GNUNET_assert(NULL == cstate->recv_task);
472   cstate->recv_task
473     = GNUNET_SCHEDULER_add_read_net(GNUNET_TIME_UNIT_FOREVER_REL,
474                                     cstate->sock,
475                                     &receive_ready,
476                                     cstate);
477   if (NULL != cstate->msg)
478     {
479       GNUNET_assert(NULL == cstate->send_task);
480       cstate->send_task
481         = GNUNET_SCHEDULER_add_write_net(GNUNET_TIME_UNIT_FOREVER_REL,
482                                          cstate->sock,
483                                          &transmit_ready,
484                                          cstate);
485     }
486 }
487
488
489 /**
490  * Try connecting to the server using UNIX domain sockets.
491  *
492  * @param service_name name of service to connect to
493  * @param cfg configuration to use
494  * @return NULL on error, socket connected to UNIX otherwise
495  */
496 static struct GNUNET_NETWORK_Handle *
497 try_unixpath(const char *service_name,
498              const struct GNUNET_CONFIGURATION_Handle *cfg)
499 {
500 #if AF_UNIX
501   struct GNUNET_NETWORK_Handle *sock;
502   char *unixpath;
503   struct sockaddr_un s_un;
504
505   unixpath = NULL;
506   if ((GNUNET_OK ==
507        GNUNET_CONFIGURATION_get_value_filename(cfg,
508                                                service_name,
509                                                "UNIXPATH",
510                                                &unixpath)) &&
511       (0 < strlen(unixpath)))
512     {
513       /* We have a non-NULL unixpath, need to validate it */
514       if (strlen(unixpath) >= sizeof(s_un.sun_path))
515         {
516           LOG(GNUNET_ERROR_TYPE_WARNING,
517               _("UNIXPATH `%s' too long, maximum length is %llu\n"),
518               unixpath,
519               (unsigned long long)sizeof(s_un.sun_path));
520           unixpath = GNUNET_NETWORK_shorten_unixpath(unixpath);
521           LOG(GNUNET_ERROR_TYPE_INFO,
522               _("Using `%s' instead\n"),
523               unixpath);
524           if (NULL == unixpath)
525             return NULL;
526         }
527       memset(&s_un,
528              0,
529              sizeof(s_un));
530       s_un.sun_family = AF_UNIX;
531       GNUNET_strlcpy(s_un.sun_path,
532                      unixpath,
533                      sizeof(s_un.sun_path));
534 #ifdef LINUX
535       {
536         int abstract;
537
538         abstract = GNUNET_CONFIGURATION_get_value_yesno(cfg,
539                                                         "TESTING",
540                                                         "USE_ABSTRACT_SOCKETS");
541         if (GNUNET_YES == abstract)
542           s_un.sun_path[0] = '\0';
543       }
544 #endif
545 #if HAVE_SOCKADDR_UN_SUN_LEN
546       s_un.sun_len = (u_char)sizeof(struct sockaddr_un);
547 #endif
548       sock = GNUNET_NETWORK_socket_create(AF_UNIX,
549                                           SOCK_STREAM,
550                                           0);
551       if ((NULL != sock) &&
552           ((GNUNET_OK ==
553             GNUNET_NETWORK_socket_connect(sock,
554                                           (struct sockaddr *)&s_un,
555                                           sizeof(s_un))) ||
556            (EINPROGRESS == errno)))
557         {
558           LOG(GNUNET_ERROR_TYPE_DEBUG,
559               "Successfully connected to unixpath `%s'!\n",
560               unixpath);
561           GNUNET_free(unixpath);
562           return sock;
563         }
564       if (NULL != sock)
565         GNUNET_NETWORK_socket_close(sock);
566     }
567   GNUNET_free_non_null(unixpath);
568 #endif
569   return NULL;
570 }
571
572
573 /**
574  * Scheduler let us know that we're either ready to write on the
575  * socket OR connect timed out.  Do the right thing.
576  *
577  * @param cls the `struct AddressProbe *` with the address that we are probing
578  */
579 static void
580 connect_probe_continuation(void *cls)
581 {
582   struct AddressProbe *ap = cls;
583   struct ClientState *cstate = ap->cstate;
584   const struct GNUNET_SCHEDULER_TaskContext *tc;
585   int error;
586   socklen_t len;
587
588   ap->task = NULL;
589   GNUNET_assert(NULL != ap->sock);
590   GNUNET_CONTAINER_DLL_remove(cstate->ap_head,
591                               cstate->ap_tail,
592                               ap);
593   len = sizeof(error);
594   error = 0;
595   tc = GNUNET_SCHEDULER_get_task_context();
596   if ((0 == (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) ||
597       (GNUNET_OK !=
598        GNUNET_NETWORK_socket_getsockopt(ap->sock,
599                                         SOL_SOCKET,
600                                         SO_ERROR,
601                                         &error,
602                                         &len)) ||
603       (0 != error))
604     {
605       GNUNET_break(GNUNET_OK ==
606                    GNUNET_NETWORK_socket_close(ap->sock));
607       GNUNET_free(ap);
608       if ((NULL == cstate->ap_head) &&
609           //     (NULL == cstate->proxy_handshake) &&
610           (NULL == cstate->dns_active))
611         connect_fail_continuation(cstate);
612       return;
613     }
614   LOG(GNUNET_ERROR_TYPE_DEBUG,
615       "Connection to `%s' succeeded!\n",
616       cstate->service_name);
617   /* trigger jobs that waited for the connection */
618   GNUNET_assert(NULL == cstate->sock);
619   cstate->sock = ap->sock;
620   GNUNET_free(ap);
621   cancel_aps(cstate);
622   connect_success_continuation(cstate);
623 }
624
625
626 /**
627  * Try to establish a connection given the specified address.
628  * This function is called by the resolver once we have a DNS reply.
629  *
630  * @param cls our `struct ClientState *`
631  * @param addr address to try, NULL for "last call"
632  * @param addrlen length of @a addr
633  */
634 static void
635 try_connect_using_address(void *cls,
636                           const struct sockaddr *addr,
637                           socklen_t addrlen)
638 {
639   struct ClientState *cstate = cls;
640   struct AddressProbe *ap;
641
642   if (NULL == addr)
643     {
644       cstate->dns_active = NULL;
645       if ((NULL == cstate->ap_head) &&
646           //  (NULL == cstate->proxy_handshake) &&
647           (NULL == cstate->sock))
648         connect_fail_continuation(cstate);
649       return;
650     }
651   if (NULL != cstate->sock)
652     return;                     /* already connected */
653   /* try to connect */
654   LOG(GNUNET_ERROR_TYPE_DEBUG,
655       "Trying to connect using address `%s:%u'\n",
656       GNUNET_a2s(addr,
657                  addrlen),
658       cstate->port);
659   ap = GNUNET_malloc(sizeof(struct AddressProbe) + addrlen);
660   ap->addr = (const struct sockaddr *)&ap[1];
661   GNUNET_memcpy(&ap[1],
662                 addr,
663                 addrlen);
664   ap->addrlen = addrlen;
665   ap->cstate = cstate;
666
667   switch (ap->addr->sa_family)
668     {
669     case AF_INET:
670       ((struct sockaddr_in *)ap->addr)->sin_port = htons(cstate->port);
671       break;
672
673     case AF_INET6:
674       ((struct sockaddr_in6 *)ap->addr)->sin6_port = htons(cstate->port);
675       break;
676
677     default:
678       GNUNET_break(0);
679       GNUNET_free(ap);
680       return;                   /* not supported by us */
681     }
682   ap->sock = GNUNET_NETWORK_socket_create(ap->addr->sa_family,
683                                           SOCK_STREAM,
684                                           0);
685   if (NULL == ap->sock)
686     {
687       GNUNET_free(ap);
688       return;                   /* not supported by OS */
689     }
690   if ((GNUNET_OK !=
691        GNUNET_NETWORK_socket_connect(ap->sock,
692                                      ap->addr,
693                                      ap->addrlen)) &&
694       (EINPROGRESS != errno))
695     {
696       /* maybe refused / unsupported address, try next */
697       GNUNET_log_strerror(GNUNET_ERROR_TYPE_INFO,
698                           "connect");
699       GNUNET_break(GNUNET_OK ==
700                    GNUNET_NETWORK_socket_close(ap->sock));
701       GNUNET_free(ap);
702       return;
703     }
704   GNUNET_CONTAINER_DLL_insert(cstate->ap_head,
705                               cstate->ap_tail,
706                               ap);
707   ap->task = GNUNET_SCHEDULER_add_write_net(CONNECT_RETRY_TIMEOUT,
708                                             ap->sock,
709                                             &connect_probe_continuation,
710                                             ap);
711 }
712
713
714 /**
715  * Test whether the configuration has proper values for connection
716  * (UNIXPATH || (PORT && HOSTNAME)).
717  *
718  * @param service_name name of service to connect to
719  * @param cfg configuration to use
720  * @return #GNUNET_OK if the configuration is valid, #GNUNET_SYSERR if not
721  */
722 static int
723 test_service_configuration(const char *service_name,
724                            const struct GNUNET_CONFIGURATION_Handle *cfg)
725 {
726   int ret = GNUNET_SYSERR;
727   char *hostname = NULL;
728   unsigned long long port;
729
730 #if AF_UNIX
731   char *unixpath = NULL;
732
733   if ((GNUNET_OK ==
734        GNUNET_CONFIGURATION_get_value_filename(cfg,
735                                                service_name,
736                                                "UNIXPATH",
737                                                &unixpath)) &&
738       (0 < strlen(unixpath)))
739     ret = GNUNET_OK;
740   else if ((GNUNET_OK ==
741             GNUNET_CONFIGURATION_have_value(cfg,
742                                             service_name,
743                                             "UNIXPATH")))
744     {
745       GNUNET_log_config_invalid(GNUNET_ERROR_TYPE_ERROR,
746                                 service_name,
747                                 "UNIXPATH",
748                                 _("not a valid filename"));
749       return GNUNET_SYSERR; /* UNIXPATH specified but invalid! */
750     }
751   GNUNET_free_non_null(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_non_null(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  */
782 static void
783 start_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  */
836 static void
837 connection_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_write_net(GNUNET_TIME_UNIT_FOREVER_REL,
858                                      cstate->sock,
859                                      &transmit_ready,
860                                      cstate);
861 }
862
863
864 /**
865  * Cancel the currently sent message.
866  *
867  * @param mq message queue
868  * @param impl_state our `struct ClientState`
869  */
870 static void
871 connection_client_cancel_impl(struct GNUNET_MQ_Handle *mq,
872                               void *impl_state)
873 {
874   struct ClientState *cstate = impl_state;
875
876   (void)mq;
877   GNUNET_assert(NULL != cstate->msg);
878   GNUNET_assert(0 == cstate->msg_off);
879   cstate->msg = NULL;
880   if (NULL != cstate->send_task)
881     {
882       GNUNET_SCHEDULER_cancel(cstate->send_task);
883       cstate->send_task = NULL;
884     }
885 }
886
887
888 /**
889  * Create a message queue to connect to a GNUnet service.
890  * If handlers are specfied, receive messages from the connection.
891  *
892  * @param cfg our configuration
893  * @param service_name name of the service to connect to
894  * @param handlers handlers for receiving messages, can be NULL
895  * @param error_handler error handler
896  * @param error_handler_cls closure for the @a error_handler
897  * @return the message queue, NULL on error
898  */
899 struct GNUNET_MQ_Handle *
900 GNUNET_CLIENT_connect(const struct GNUNET_CONFIGURATION_Handle *cfg,
901                       const char *service_name,
902                       const struct GNUNET_MQ_MessageHandler *handlers,
903                       GNUNET_MQ_ErrorHandler error_handler,
904                       void *error_handler_cls)
905 {
906   struct ClientState *cstate;
907
908   if (GNUNET_OK !=
909       test_service_configuration(service_name,
910                                  cfg))
911     return NULL;
912   cstate = GNUNET_new(struct ClientState);
913   cstate->service_name = GNUNET_strdup(service_name);
914   cstate->cfg = cfg;
915   cstate->retry_task = GNUNET_SCHEDULER_add_now(&start_connect,
916                                                 cstate);
917   cstate->mst = GNUNET_MST_create(&recv_message,
918                                   cstate);
919   if (GNUNET_YES ==
920       GNUNET_CONFIGURATION_have_value(cfg,
921                                       service_name,
922                                       "PORT"))
923     {
924       if (!((GNUNET_OK !=
925              GNUNET_CONFIGURATION_get_value_number(cfg,
926                                                    service_name,
927                                                    "PORT",
928                                                    &cstate->port)) ||
929             (cstate->port > 65535) ||
930             (GNUNET_OK !=
931              GNUNET_CONFIGURATION_get_value_string(cfg,
932                                                    service_name,
933                                                    "HOSTNAME",
934                                                    &cstate->hostname))) &&
935           (0 == strlen(cstate->hostname)))
936         {
937           GNUNET_free(cstate->hostname);
938           cstate->hostname = NULL;
939           LOG(GNUNET_ERROR_TYPE_WARNING,
940               _("Need a non-empty hostname for service `%s'.\n"),
941               service_name);
942         }
943     }
944   cstate->mq = GNUNET_MQ_queue_for_callbacks(&connection_client_send_impl,
945                                              &connection_client_destroy_impl,
946                                              &connection_client_cancel_impl,
947                                              cstate,
948                                              handlers,
949                                              error_handler,
950                                              error_handler_cls);
951   return cstate->mq;
952 }
953
954 /* end of client.c */