added logging
[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, #GNUNET_SYSERR to stop further processing
310  */
311 static int
312 recv_message (void *cls,
313               const struct GNUNET_MessageHeader *msg)
314 {
315   struct ClientState *cstate = cls;
316
317   if (GNUNET_YES == cstate->in_destroy)
318     return GNUNET_SYSERR;
319   LOG (GNUNET_ERROR_TYPE_DEBUG,
320        "Received message of type %u and size %u from %s\n",
321        ntohs (msg->type),
322        ntohs (msg->size),
323        cstate->service_name);
324   GNUNET_MQ_inject_message (cstate->mq,
325                             msg);
326   if (GNUNET_YES == cstate->in_destroy)
327     return GNUNET_SYSERR;
328   return GNUNET_OK;
329 }
330
331
332 /**
333  * Cancel all remaining connect attempts
334  *
335  * @param cstate handle of the client state to process
336  */
337 static void
338 cancel_aps (struct ClientState *cstate)
339 {
340   struct AddressProbe *pos;
341
342   while (NULL != (pos = cstate->ap_head))
343   {
344     GNUNET_break (GNUNET_OK ==
345                   GNUNET_NETWORK_socket_close (pos->sock));
346     GNUNET_SCHEDULER_cancel (pos->task);
347     GNUNET_CONTAINER_DLL_remove (cstate->ap_head,
348                                  cstate->ap_tail,
349                                  pos);
350     GNUNET_free (pos);
351   }
352 }
353
354
355 /**
356  * Implement the destruction of a message queue.  Implementations must
357  * not free @a mq, but should take care of @a impl_state.
358  *
359  * @param mq the message queue to destroy
360  * @param impl_state our `struct ClientState`
361  */
362 static void
363 connection_client_destroy_impl (struct GNUNET_MQ_Handle *mq,
364                                 void *impl_state)
365 {
366   struct ClientState *cstate = impl_state;
367
368   if (GNUNET_SYSERR == cstate->in_destroy)
369   {
370     /* defer destruction */
371     cstate->in_destroy = GNUNET_YES;
372     cstate->mq = NULL;
373     return;
374   }
375   if (NULL != cstate->dns_active)
376     GNUNET_RESOLVER_request_cancel (cstate->dns_active);
377   if (NULL != cstate->send_task)
378     GNUNET_SCHEDULER_cancel (cstate->send_task);
379   if (NULL != cstate->recv_task)
380     GNUNET_SCHEDULER_cancel (cstate->recv_task);
381   if (NULL != cstate->retry_task)
382     GNUNET_SCHEDULER_cancel (cstate->retry_task);
383   if (NULL != cstate->sock)
384     GNUNET_NETWORK_socket_close (cstate->sock);
385   cancel_aps (cstate);
386   GNUNET_free (cstate->service_name);
387   GNUNET_free_non_null (cstate->hostname);
388   GNUNET_MST_destroy (cstate->mst);
389   GNUNET_free (cstate);
390 }
391
392
393 /**
394  * This function is called once we have data ready to read.
395  *
396  * @param cls `struct ClientState` with connection to read from
397  */
398 static void
399 receive_ready (void *cls)
400 {
401   struct ClientState *cstate = cls;
402   int ret;
403
404   cstate->recv_task = NULL;
405   cstate->in_destroy = GNUNET_SYSERR;
406   ret = GNUNET_MST_read (cstate->mst,
407                          cstate->sock,
408                          GNUNET_NO,
409                          GNUNET_NO);
410   if (GNUNET_SYSERR == ret)
411   {
412     if (NULL != cstate->mq)
413       GNUNET_MQ_inject_error (cstate->mq,
414                               GNUNET_MQ_ERROR_READ);
415     if (GNUNET_YES == cstate->in_destroy)
416       connection_client_destroy_impl (cstate->mq,
417                                       cstate);
418     return;
419   }
420   if (GNUNET_YES == cstate->in_destroy)
421   {
422     connection_client_destroy_impl (cstate->mq,
423                                     cstate);
424     return;
425   }
426   cstate->in_destroy = GNUNET_NO;
427   cstate->recv_task
428     = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
429                                      cstate->sock,
430                                      &receive_ready,
431                                      cstate);
432 }
433
434
435 /**
436  * We've succeeded in establishing a connection.
437  *
438  * @param cstate the connection we tried to establish
439  */
440 static void
441 connect_success_continuation (struct ClientState *cstate)
442 {
443   GNUNET_assert (NULL == cstate->recv_task);
444   cstate->recv_task
445     = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
446                                      cstate->sock,
447                                      &receive_ready,
448                                      cstate);
449   if (NULL != cstate->msg)
450   {
451     GNUNET_assert (NULL == cstate->send_task);
452     cstate->send_task
453       = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
454                                         cstate->sock,
455                                         &transmit_ready,
456                                         cstate);
457   }
458 }
459
460
461 /**
462  * Try connecting to the server using UNIX domain sockets.
463  *
464  * @param service_name name of service to connect to
465  * @param cfg configuration to use
466  * @return NULL on error, socket connected to UNIX otherwise
467  */
468 static struct GNUNET_NETWORK_Handle *
469 try_unixpath (const char *service_name,
470               const struct GNUNET_CONFIGURATION_Handle *cfg)
471 {
472 #if AF_UNIX
473   struct GNUNET_NETWORK_Handle *sock;
474   char *unixpath;
475   struct sockaddr_un s_un;
476
477   unixpath = NULL;
478   if ((GNUNET_OK ==
479        GNUNET_CONFIGURATION_get_value_filename (cfg,
480                                                 service_name,
481                                                 "UNIXPATH",
482                                                 &unixpath)) &&
483       (0 < strlen (unixpath)))
484   {
485     /* We have a non-NULL unixpath, need to validate it */
486     if (strlen (unixpath) >= sizeof (s_un.sun_path))
487     {
488       LOG (GNUNET_ERROR_TYPE_WARNING,
489            _("UNIXPATH `%s' too long, maximum length is %llu\n"),
490            unixpath,
491            (unsigned long long) sizeof (s_un.sun_path));
492       unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
493       LOG (GNUNET_ERROR_TYPE_INFO,
494            _("Using `%s' instead\n"),
495            unixpath);
496       if (NULL == unixpath)
497         return NULL;
498     }
499     memset (&s_un,
500             0,
501             sizeof (s_un));
502     s_un.sun_family = AF_UNIX;
503     strncpy (s_un.sun_path,
504              unixpath,
505              sizeof (s_un.sun_path) - 1);
506 #ifdef LINUX
507     {
508       int abstract;
509
510       abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
511                                                        "TESTING",
512                                                        "USE_ABSTRACT_SOCKETS");
513       if (GNUNET_YES == abstract)
514         s_un.sun_path[0] = '\0';
515     }
516 #endif
517 #if HAVE_SOCKADDR_UN_SUN_LEN
518     s_un.sun_len = (u_char) sizeof (struct sockaddr_un);
519 #endif
520     sock = GNUNET_NETWORK_socket_create (AF_UNIX,
521                                          SOCK_STREAM,
522                                          0);
523     if ( (NULL != sock) &&
524          ( (GNUNET_OK ==
525             GNUNET_NETWORK_socket_connect (sock,
526                                            (struct sockaddr *) &s_un,
527                                            sizeof (s_un))) ||
528            (EINPROGRESS == errno) ) )
529     {
530       LOG (GNUNET_ERROR_TYPE_DEBUG,
531            "Successfully connected to unixpath `%s'!\n",
532            unixpath);
533       GNUNET_free (unixpath);
534       return sock;
535     }
536     if (NULL != sock)
537       GNUNET_NETWORK_socket_close (sock);
538   }
539   GNUNET_free_non_null (unixpath);
540 #endif
541   return NULL;
542 }
543
544
545 /**
546  * Scheduler let us know that we're either ready to write on the
547  * socket OR connect timed out.  Do the right thing.
548  *
549  * @param cls the `struct AddressProbe *` with the address that we are probing
550  */
551 static void
552 connect_probe_continuation (void *cls)
553 {
554   struct AddressProbe *ap = cls;
555   struct ClientState *cstate = ap->cstate;
556   const struct GNUNET_SCHEDULER_TaskContext *tc;
557   int error;
558   socklen_t len;
559
560   ap->task = NULL;
561   GNUNET_assert (NULL != ap->sock);
562   GNUNET_CONTAINER_DLL_remove (cstate->ap_head,
563                                cstate->ap_tail,
564                                ap);
565   len = sizeof (error);
566   error = 0;
567   tc = GNUNET_SCHEDULER_get_task_context ();
568   if ( (0 == (tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY)) ||
569        (GNUNET_OK !=
570         GNUNET_NETWORK_socket_getsockopt (ap->sock,
571                                           SOL_SOCKET,
572                                           SO_ERROR,
573                                           &error,
574                                           &len)) ||
575        (0 != error) )
576   {
577     GNUNET_break (GNUNET_OK ==
578                   GNUNET_NETWORK_socket_close (ap->sock));
579     GNUNET_free (ap);
580     if ( (NULL == cstate->ap_head) &&
581          //      (NULL == cstate->proxy_handshake) &&
582          (NULL == cstate->dns_active) )
583       connect_fail_continuation (cstate);
584     return;
585   }
586   LOG (GNUNET_ERROR_TYPE_DEBUG,
587        "Connection to `%s' succeeded!\n",
588        cstate->service_name);
589   /* trigger jobs that waited for the connection */
590   GNUNET_assert (NULL == cstate->sock);
591   cstate->sock = ap->sock;
592   GNUNET_free (ap);
593   cancel_aps (cstate);
594   connect_success_continuation (cstate);
595 }
596
597
598 /**
599  * Try to establish a connection given the specified address.
600  * This function is called by the resolver once we have a DNS reply.
601  *
602  * @param cls our `struct ClientState *`
603  * @param addr address to try, NULL for "last call"
604  * @param addrlen length of @a addr
605  */
606 static void
607 try_connect_using_address (void *cls,
608                            const struct sockaddr *addr,
609                            socklen_t addrlen)
610 {
611   struct ClientState *cstate = cls;
612   struct AddressProbe *ap;
613
614   if (NULL == addr)
615   {
616     cstate->dns_active = NULL;
617     if ( (NULL == cstate->ap_head) &&
618          //  (NULL == cstate->proxy_handshake) &&
619          (NULL == cstate->sock) )
620       connect_fail_continuation (cstate);
621     return;
622   }
623   if (NULL != cstate->sock)
624     return;                     /* already connected */
625   /* try to connect */
626   LOG (GNUNET_ERROR_TYPE_DEBUG,
627        "Trying to connect using address `%s:%u'\n",
628        GNUNET_a2s (addr,
629                    addrlen),
630        cstate->port);
631   ap = GNUNET_malloc (sizeof (struct AddressProbe) + addrlen);
632   ap->addr = (const struct sockaddr *) &ap[1];
633   GNUNET_memcpy (&ap[1],
634                  addr,
635                  addrlen);
636   ap->addrlen = addrlen;
637   ap->cstate = cstate;
638
639   switch (ap->addr->sa_family)
640   {
641   case AF_INET:
642     ((struct sockaddr_in *) ap->addr)->sin_port = htons (cstate->port);
643     break;
644   case AF_INET6:
645     ((struct sockaddr_in6 *) ap->addr)->sin6_port = htons (cstate->port);
646     break;
647   default:
648     GNUNET_break (0);
649     GNUNET_free (ap);
650     return;                     /* not supported by us */
651   }
652   ap->sock = GNUNET_NETWORK_socket_create (ap->addr->sa_family,
653                                            SOCK_STREAM,
654                                            0);
655   if (NULL == ap->sock)
656   {
657     GNUNET_free (ap);
658     return;                     /* not supported by OS */
659   }
660   if ( (GNUNET_OK !=
661         GNUNET_NETWORK_socket_connect (ap->sock,
662                                        ap->addr,
663                                        ap->addrlen)) &&
664        (EINPROGRESS != errno) )
665   {
666     /* maybe refused / unsupported address, try next */
667     GNUNET_log_strerror (GNUNET_ERROR_TYPE_INFO,
668                          "connect");
669     GNUNET_break (GNUNET_OK ==
670                   GNUNET_NETWORK_socket_close (ap->sock));
671     GNUNET_free (ap);
672     return;
673   }
674   GNUNET_CONTAINER_DLL_insert (cstate->ap_head,
675                                cstate->ap_tail,
676                                ap);
677   ap->task = GNUNET_SCHEDULER_add_write_net (CONNECT_RETRY_TIMEOUT,
678                                              ap->sock,
679                                              &connect_probe_continuation,
680                                              ap);
681 }
682
683
684 /**
685  * Test whether the configuration has proper values for connection
686  * (UNIXPATH || (PORT && HOSTNAME)).
687  *
688  * @param service_name name of service to connect to
689  * @param cfg configuration to use
690  * @return #GNUNET_OK if the configuration is valid, #GNUNET_SYSERR if not
691  */
692 static int
693 test_service_configuration (const char *service_name,
694                             const struct GNUNET_CONFIGURATION_Handle *cfg)
695 {
696   int ret = GNUNET_SYSERR;
697   char *hostname = NULL;
698   unsigned long long port;
699 #if AF_UNIX
700   char *unixpath = NULL;
701
702   if ((GNUNET_OK ==
703        GNUNET_CONFIGURATION_get_value_filename (cfg,
704                                                 service_name,
705                                                 "UNIXPATH",
706                                                 &unixpath)) &&
707       (0 < strlen (unixpath)))
708     ret = GNUNET_OK;
709   GNUNET_free_non_null (unixpath);
710 #endif
711
712   if ( (GNUNET_YES ==
713         GNUNET_CONFIGURATION_have_value (cfg,
714                                          service_name,
715                                          "PORT")) &&
716        (GNUNET_OK ==
717         GNUNET_CONFIGURATION_get_value_number (cfg,
718                                                service_name,
719                                                "PORT",
720                                                &port)) &&
721        (port <= 65535) &&
722        (0 != port) &&
723        (GNUNET_OK ==
724         GNUNET_CONFIGURATION_get_value_string (cfg,
725                                                service_name,
726                                                "HOSTNAME",
727                                                &hostname)) &&
728        (0 != strlen (hostname)) )
729     ret = GNUNET_OK;
730   GNUNET_free_non_null (hostname);
731   return ret;
732 }
733
734
735 /**
736  * Try to connect to the service.
737  *
738  * @param cls the `struct ClientState` to try to connect to the service
739  */
740 static void
741 start_connect (void *cls)
742 {
743   struct ClientState *cstate = cls;
744
745   cstate->retry_task = NULL;
746 #if 0
747   /* Never use a local source if a proxy is configured */
748   if (GNUNET_YES ==
749       GNUNET_SOCKS_check_service (cstate->service_name,
750                                   cstate->cfg))
751   {
752     socks_connect (cstate);
753     return;
754   }
755 #endif
756
757   if ( (0 == (cstate->attempts++ % 2)) ||
758        (0 == cstate->port) ||
759        (NULL == cstate->hostname) )
760   {
761     /* on even rounds, try UNIX first, or always
762        if we do not have a DNS name and TCP port. */
763     cstate->sock = try_unixpath (cstate->service_name,
764                                  cstate->cfg);
765     if (NULL != cstate->sock)
766     {
767       connect_success_continuation (cstate);
768       return;
769     }
770   }
771   if ( (NULL == cstate->hostname) ||
772        (0 == cstate->port) )
773   {
774     /* All options failed. Boo! */
775     connect_fail_continuation (cstate);
776     return;
777   }
778   cstate->dns_active
779     = GNUNET_RESOLVER_ip_get (cstate->hostname,
780                               AF_UNSPEC,
781                               CONNECT_RETRY_TIMEOUT,
782                               &try_connect_using_address,
783                               cstate);
784 }
785
786
787 /**
788  * Implements the transmission functionality of a message queue.
789  *
790  * @param mq the message queue
791  * @param msg the message to send
792  * @param impl_state our `struct ClientState`
793  */
794 static void
795 connection_client_send_impl (struct GNUNET_MQ_Handle *mq,
796                              const struct GNUNET_MessageHeader *msg,
797                              void *impl_state)
798 {
799   struct ClientState *cstate = impl_state;
800
801   /* only one message at a time allowed */
802   GNUNET_assert (NULL == cstate->msg);
803   GNUNET_assert (NULL == cstate->send_task);
804   cstate->msg = msg;
805   cstate->msg_off = 0;
806   if (NULL == cstate->sock){
807     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
808                 "client: waiting for socket\n");
809     return; /* still waiting for connection */
810    }
811   cstate->send_task
812     = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
813                                       cstate->sock,
814                                       &transmit_ready,
815                                       cstate);
816 }
817
818
819 /**
820  * Cancel the currently sent message.
821  *
822  * @param mq message queue
823  * @param impl_state our `struct ClientState`
824  */
825 static void
826 connection_client_cancel_impl (struct GNUNET_MQ_Handle *mq,
827                                void *impl_state)
828 {
829   struct ClientState *cstate = impl_state;
830
831   GNUNET_assert (NULL != cstate->msg);
832   GNUNET_assert (0 == cstate->msg_off);
833   cstate->msg = NULL;
834   if (NULL != cstate->send_task)
835   {
836     GNUNET_SCHEDULER_cancel (cstate->send_task);
837     cstate->send_task = NULL;
838   }
839 }
840
841
842 /**
843  * Create a message queue to connect to a GNUnet service.
844  * If handlers are specfied, receive messages from the connection.
845  *
846  * @param cfg our configuration
847  * @param service_name name of the service to connect to
848  * @param handlers handlers for receiving messages, can be NULL
849  * @param error_handler error handler
850  * @param error_handler_cls closure for the @a error_handler
851  * @return the message queue, NULL on error
852  */
853 struct GNUNET_MQ_Handle *
854 GNUNET_CLIENT_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
855                        const char *service_name,
856                        const struct GNUNET_MQ_MessageHandler *handlers,
857                        GNUNET_MQ_ErrorHandler error_handler,
858                        void *error_handler_cls)
859 {
860   struct ClientState *cstate;
861
862   if (GNUNET_OK !=
863       test_service_configuration (service_name,
864                                   cfg))
865     return NULL;
866   cstate = GNUNET_new (struct ClientState);
867   cstate->service_name = GNUNET_strdup (service_name);
868   cstate->cfg = cfg;
869   cstate->retry_task = GNUNET_SCHEDULER_add_now (&start_connect,
870                                                  cstate);
871   cstate->mst = GNUNET_MST_create (&recv_message,
872                                    cstate);
873   if (GNUNET_YES ==
874       GNUNET_CONFIGURATION_have_value (cfg,
875                                        service_name,
876                                        "PORT"))
877   {
878     if (! ( (GNUNET_OK !=
879              GNUNET_CONFIGURATION_get_value_number (cfg,
880                                                     service_name,
881                                                     "PORT",
882                                                     &cstate->port)) ||
883             (cstate->port > 65535) ||
884             (GNUNET_OK !=
885              GNUNET_CONFIGURATION_get_value_string (cfg,
886                                                     service_name,
887                                                     "HOSTNAME",
888                                                     &cstate->hostname)) ) &&
889         (0 == strlen (cstate->hostname)) )
890     {
891       GNUNET_free (cstate->hostname);
892       cstate->hostname = NULL;
893       LOG (GNUNET_ERROR_TYPE_WARNING,
894            _("Need a non-empty hostname for service `%s'.\n"),
895            service_name);
896     }
897   }
898   cstate->mq = GNUNET_MQ_queue_for_callbacks (&connection_client_send_impl,
899                                               &connection_client_destroy_impl,
900                                               &connection_client_cancel_impl,
901                                               cstate,
902                                               handlers,
903                                               error_handler,
904                                               error_handler_cls);
905   return cstate->mq;
906 }
907
908 /* end of client.c */