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