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