aboutsummaryrefslogtreecommitdiff
path: root/src/transport/tcp_service_legacy.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/transport/tcp_service_legacy.c')
-rw-r--r--src/transport/tcp_service_legacy.c1646
1 files changed, 0 insertions, 1646 deletions
diff --git a/src/transport/tcp_service_legacy.c b/src/transport/tcp_service_legacy.c
deleted file mode 100644
index 8606b353b..000000000
--- a/src/transport/tcp_service_legacy.c
+++ /dev/null
@@ -1,1646 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2012 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/service.c
23 * @brief functions related to starting services
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_protocols.h"
29#include "gnunet_constants.h"
30#include "gnunet_resolver_service.h"
31
32#if HAVE_MALLINFO
33#include <malloc.h>
34#include "gauger.h"
35#endif
36
37
38/* ******************* access control ******************** */
39
40/**
41 * Check if the given IP address is in the list of IP addresses.
42 *
43 * @param list a list of networks
44 * @param add the IP to check (in network byte order)
45 * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is
46 */
47static int
48check_ipv4_listed (const struct GNUNET_STRINGS_IPv4NetworkPolicy *list,
49 const struct in_addr *add)
50{
51 unsigned int i;
52
53 if (NULL == list)
54 return GNUNET_NO;
55 i = 0;
56 while ((list[i].network.s_addr != 0) || (list[i].netmask.s_addr != 0))
57 {
58 if ((add->s_addr & list[i].netmask.s_addr) ==
59 (list[i].network.s_addr & list[i].netmask.s_addr))
60 return GNUNET_YES;
61 i++;
62 }
63 return GNUNET_NO;
64}
65
66
67/**
68 * Check if the given IP address is in the list of IP addresses.
69 *
70 * @param list a list of networks
71 * @param ip the IP to check (in network byte order)
72 * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is
73 */
74static int
75check_ipv6_listed (const struct GNUNET_STRINGS_IPv6NetworkPolicy *list,
76 const struct in6_addr *ip)
77{
78 unsigned int i;
79 unsigned int j;
80 struct in6_addr zero;
81
82 if (NULL == list)
83 return GNUNET_NO;
84 memset (&zero, 0, sizeof(struct in6_addr));
85 i = 0;
86NEXT:
87 while (0 != memcmp (&zero, &list[i].network, sizeof(struct in6_addr)))
88 {
89 for (j = 0; j < sizeof(struct in6_addr) / sizeof(int); j++)
90 if (((((int *) ip)[j] & ((int *) &list[i].netmask)[j])) !=
91 (((int *) &list[i].network)[j] & ((int *) &list[i].netmask)[j]))
92 {
93 i++;
94 goto NEXT;
95 }
96 return GNUNET_YES;
97 }
98 return GNUNET_NO;
99}
100
101
102/* ****************** service struct ****************** */
103
104
105/**
106 * Context for "service_task".
107 */
108struct LEGACY_SERVICE_Context
109{
110 /**
111 * Our configuration.
112 */
113 const struct GNUNET_CONFIGURATION_Handle *cfg;
114
115 /**
116 * Handle for the server.
117 */
118 struct GNUNET_SERVER_Handle *server;
119
120 /**
121 * NULL-terminated array of addresses to bind to, NULL if we got pre-bound
122 * listen sockets.
123 */
124 struct sockaddr **addrs;
125
126 /**
127 * Name of our service.
128 */
129 const char *service_name;
130
131 /**
132 * Main service-specific task to run.
133 */
134 LEGACY_SERVICE_Main task;
135
136 /**
137 * Closure for @e task.
138 */
139 void *task_cls;
140
141 /**
142 * IPv4 addresses that are not allowed to connect.
143 */
144 struct GNUNET_STRINGS_IPv4NetworkPolicy *v4_denied;
145
146 /**
147 * IPv6 addresses that are not allowed to connect.
148 */
149 struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_denied;
150
151 /**
152 * IPv4 addresses that are allowed to connect (if not
153 * set, all are allowed).
154 */
155 struct GNUNET_STRINGS_IPv4NetworkPolicy *v4_allowed;
156
157 /**
158 * IPv6 addresses that are allowed to connect (if not
159 * set, all are allowed).
160 */
161 struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_allowed;
162
163 /**
164 * My (default) message handlers. Adjusted copy
165 * of "defhandlers".
166 */
167 struct GNUNET_SERVER_MessageHandler *my_handlers;
168
169 /**
170 * Array of the lengths of the entries in addrs.
171 */
172 socklen_t *addrlens;
173
174 /**
175 * NULL-terminated array of listen sockets we should take over.
176 */
177 struct GNUNET_NETWORK_Handle **lsocks;
178
179 /**
180 * Task ID of the shutdown task.
181 */
182 struct GNUNET_SCHEDULER_Task *shutdown_task;
183
184 /**
185 * Idle timeout for server.
186 */
187 struct GNUNET_TIME_Relative timeout;
188
189 /**
190 * Overall success/failure of the service start.
191 */
192 int ret;
193
194 /**
195 * If we are daemonizing, this FD is set to the
196 * pipe to the parent. Send '.' if we started
197 * ok, '!' if not. -1 if we are not daemonizing.
198 */
199 int ready_confirm_fd;
200
201 /**
202 * Do we close connections if we receive messages
203 * for which we have no handler?
204 */
205 int require_found;
206
207 /**
208 * Do we require a matching UID for UNIX domain socket connections?
209 * #GNUNET_NO means that the UID does not have to match (however,
210 * @e match_gid may still impose other access control checks).
211 */
212 int match_uid;
213
214 /**
215 * Do we require a matching GID for UNIX domain socket connections?
216 * Ignored if @e match_uid is #GNUNET_YES. Note that this is about
217 * checking that the client's UID is in our group OR that the
218 * client's GID is our GID. If both "match_gid" and @e match_uid are
219 * #GNUNET_NO, all users on the local system have access.
220 */
221 int match_gid;
222
223 /**
224 * Our options.
225 */
226 enum LEGACY_SERVICE_Options options;
227};
228
229
230/* ****************** message handlers ****************** */
231
232/**
233 * Send a 'TEST' message back to the client.
234 *
235 * @param cls the 'struct GNUNET_SERVER_Client' to send TEST to
236 * @param size number of bytes available in 'buf'
237 * @param buf where to copy the message
238 * @return number of bytes written to 'buf'
239 */
240static size_t
241write_test (void *cls, size_t size, void *buf)
242{
243 struct GNUNET_SERVER_Client *client = cls;
244 struct GNUNET_MessageHeader *msg;
245
246 if (size < sizeof(struct GNUNET_MessageHeader))
247 {
248 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
249 return 0; /* client disconnected */
250 }
251 msg = (struct GNUNET_MessageHeader *) buf;
252 msg->type = htons (GNUNET_MESSAGE_TYPE_TEST);
253 msg->size = htons (sizeof(struct GNUNET_MessageHeader));
254 GNUNET_SERVER_receive_done (client, GNUNET_OK);
255 return sizeof(struct GNUNET_MessageHeader);
256}
257
258
259/**
260 * Handler for TEST message.
261 *
262 * @param cls closure (refers to service)
263 * @param client identification of the client
264 * @param message the actual message
265 */
266static void
267handle_test (void *cls,
268 struct GNUNET_SERVER_Client *client,
269 const struct GNUNET_MessageHeader *message)
270{
271 /* simply bounce message back to acknowledge */
272 if (NULL ==
273 GNUNET_SERVER_notify_transmit_ready (client,
274 sizeof(struct GNUNET_MessageHeader),
275 GNUNET_TIME_UNIT_FOREVER_REL,
276 &write_test,
277 client))
278 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
279}
280
281
282/**
283 * Default handlers for all services. Will be copied and the
284 * "callback_cls" fields will be replaced with the specific service
285 * struct.
286 */
287static const struct GNUNET_SERVER_MessageHandler defhandlers[] =
288{ { &handle_test,
289 NULL,
290 GNUNET_MESSAGE_TYPE_TEST,
291 sizeof(struct GNUNET_MessageHeader) },
292 { NULL, NULL, 0, 0 } };
293
294
295/* ****************** service core routines ************** */
296
297
298/**
299 * Check if access to the service is allowed from the given address.
300 *
301 * @param cls closure
302 * @param uc credentials, if available, otherwise NULL
303 * @param addr address
304 * @param addrlen length of address
305 * @return #GNUNET_YES to allow, #GNUNET_NO to deny, #GNUNET_SYSERR
306 * for unknown address family (will be denied).
307 */
308static int
309check_access (void *cls,
310 const struct GNUNET_CONNECTION_Credentials *uc,
311 const struct sockaddr *addr,
312 socklen_t addrlen)
313{
314 struct LEGACY_SERVICE_Context *sctx = cls;
315 const struct sockaddr_in *i4;
316 const struct sockaddr_in6 *i6;
317 int ret;
318
319 switch (addr->sa_family)
320 {
321 case AF_INET:
322 GNUNET_assert (addrlen == sizeof(struct sockaddr_in));
323 i4 = (const struct sockaddr_in *) addr;
324 ret = ((NULL == sctx->v4_allowed) ||
325 (check_ipv4_listed (sctx->v4_allowed, &i4->sin_addr))) &&
326 ((NULL == sctx->v4_denied) ||
327 (! check_ipv4_listed (sctx->v4_denied, &i4->sin_addr)));
328 break;
329
330 case AF_INET6:
331 GNUNET_assert (addrlen == sizeof(struct sockaddr_in6));
332 i6 = (const struct sockaddr_in6 *) addr;
333 ret = ((NULL == sctx->v6_allowed) ||
334 (check_ipv6_listed (sctx->v6_allowed, &i6->sin6_addr))) &&
335 ((NULL == sctx->v6_denied) ||
336 (! check_ipv6_listed (sctx->v6_denied, &i6->sin6_addr)));
337 break;
338
339 case AF_UNIX:
340 ret = GNUNET_OK; /* controlled using file-system ACL now */
341 break;
342
343 default:
344 LOG (GNUNET_ERROR_TYPE_WARNING,
345 _ ("Unknown address family %d\n"),
346 addr->sa_family);
347 return GNUNET_SYSERR;
348 }
349 if (GNUNET_OK != ret)
350 {
351 LOG (GNUNET_ERROR_TYPE_WARNING,
352 _ ("Access from `%s' denied to service `%s'\n"),
353 GNUNET_a2s (addr, addrlen),
354 sctx->service_name);
355 }
356 return ret;
357}
358
359
360/**
361 * Get the name of the file where we will
362 * write the PID of the service.
363 *
364 * @param sctx service context
365 * @return name of the file for the process ID
366 */
367static char *
368get_pid_file_name (struct LEGACY_SERVICE_Context *sctx)
369{
370 char *pif;
371
372 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (sctx->cfg,
373 sctx->service_name,
374 "PIDFILE",
375 &pif))
376 return NULL;
377 return pif;
378}
379
380
381/**
382 * Parse an IPv4 access control list.
383 *
384 * @param ret location where to write the ACL (set)
385 * @param sctx service context to use to get the configuration
386 * @param option name of the ACL option to parse
387 * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including
388 * no ACL configured)
389 */
390static int
391process_acl4 (struct GNUNET_STRINGS_IPv4NetworkPolicy **ret,
392 struct LEGACY_SERVICE_Context *sctx,
393 const char *option)
394{
395 char *opt;
396
397 if (! GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, option))
398 {
399 *ret = NULL;
400 return GNUNET_OK;
401 }
402 GNUNET_break (GNUNET_OK ==
403 GNUNET_CONFIGURATION_get_value_string (sctx->cfg,
404 sctx->service_name,
405 option,
406 &opt));
407 if (NULL == (*ret = GNUNET_STRINGS_parse_ipv4_policy (opt)))
408 {
409 LOG (GNUNET_ERROR_TYPE_WARNING,
410 _ ("Could not parse IPv4 network specification `%s' for `%s:%s'\n"),
411 opt,
412 sctx->service_name,
413 option);
414 GNUNET_free (opt);
415 return GNUNET_SYSERR;
416 }
417 GNUNET_free (opt);
418 return GNUNET_OK;
419}
420
421
422/**
423 * Parse an IPv6 access control list.
424 *
425 * @param ret location where to write the ACL (set)
426 * @param sctx service context to use to get the configuration
427 * @param option name of the ACL option to parse
428 * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including
429 * no ACL configured)
430 */
431static int
432process_acl6 (struct GNUNET_STRINGS_IPv6NetworkPolicy **ret,
433 struct LEGACY_SERVICE_Context *sctx,
434 const char *option)
435{
436 char *opt;
437
438 if (! GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, option))
439 {
440 *ret = NULL;
441 return GNUNET_OK;
442 }
443 GNUNET_break (GNUNET_OK ==
444 GNUNET_CONFIGURATION_get_value_string (sctx->cfg,
445 sctx->service_name,
446 option,
447 &opt));
448 if (NULL == (*ret = GNUNET_STRINGS_parse_ipv6_policy (opt)))
449 {
450 LOG (GNUNET_ERROR_TYPE_WARNING,
451 _ ("Could not parse IPv6 network specification `%s' for `%s:%s'\n"),
452 opt,
453 sctx->service_name,
454 option);
455 GNUNET_free (opt);
456 return GNUNET_SYSERR;
457 }
458 GNUNET_free (opt);
459 return GNUNET_OK;
460}
461
462
463/**
464 * Add the given UNIX domain path as an address to the
465 * list (as the first entry).
466 *
467 * @param saddrs array to update
468 * @param saddrlens where to store the address length
469 * @param unixpath path to add
470 * @param abstract #GNUNET_YES to add an abstract UNIX domain socket. This
471 * parameter is ignore on systems other than LINUX
472 */
473static void
474add_unixpath (struct sockaddr **saddrs,
475 socklen_t *saddrlens,
476 const char *unixpath,
477 int abstract)
478{
479#ifdef AF_UNIX
480 struct sockaddr_un *un;
481
482 un = GNUNET_new (struct sockaddr_un);
483 un->sun_family = AF_UNIX;
484 GNUNET_strlcpy (un->sun_path, unixpath, sizeof(un->sun_path));
485#ifdef __linux__
486 if (GNUNET_YES == abstract)
487 un->sun_path[0] = '\0';
488#endif
489#if HAVE_SOCKADDR_UN_SUN_LEN
490 un->sun_len = (u_char) sizeof(struct sockaddr_un);
491#endif
492 *saddrs = (struct sockaddr *) un;
493 *saddrlens = sizeof(struct sockaddr_un);
494#else
495 /* this function should never be called
496 * unless AF_UNIX is defined! */
497 GNUNET_assert (0);
498#endif
499}
500
501
502/**
503 * Get the list of addresses that a server for the given service
504 * should bind to.
505 *
506 * @param service_name name of the service
507 * @param cfg configuration (which specifies the addresses)
508 * @param addrs set (call by reference) to an array of pointers to the
509 * addresses the server should bind to and listen on; the
510 * array will be NULL-terminated (on success)
511 * @param addr_lens set (call by reference) to an array of the lengths
512 * of the respective `struct sockaddr` struct in the @a addrs
513 * array (on success)
514 * @return number of addresses found on success,
515 * #GNUNET_SYSERR if the configuration
516 * did not specify reasonable finding information or
517 * if it specified a hostname that could not be resolved;
518 * #GNUNET_NO if the number of addresses configured is
519 * zero (in this case, `*addrs` and `*addr_lens` will be
520 * set to NULL).
521 */
522int
523LEGACY_SERVICE_get_server_addresses (
524 const char *service_name,
525 const struct GNUNET_CONFIGURATION_Handle *cfg,
526 struct sockaddr ***addrs,
527 socklen_t **addr_lens)
528{
529 int disablev6;
530 struct GNUNET_NETWORK_Handle *desc;
531 unsigned long long port;
532 char *unixpath;
533 struct addrinfo hints;
534 struct addrinfo *res;
535 struct addrinfo *pos;
536 struct addrinfo *next;
537 unsigned int i;
538 int resi;
539 int ret;
540 int abstract;
541 struct sockaddr **saddrs;
542 socklen_t *saddrlens;
543 char *hostname;
544
545 *addrs = NULL;
546 *addr_lens = NULL;
547 desc = NULL;
548 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "DISABLEV6"))
549 {
550 if (GNUNET_SYSERR ==
551 (disablev6 = GNUNET_CONFIGURATION_get_value_yesno (cfg,
552 service_name,
553 "DISABLEV6")))
554 return GNUNET_SYSERR;
555 }
556 else
557 disablev6 = GNUNET_NO;
558
559 if (! disablev6)
560 {
561 /* probe IPv6 support */
562 desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
563 if (NULL == desc)
564 {
565 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
566 (EACCES == errno))
567 {
568 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
569 return GNUNET_SYSERR;
570 }
571 LOG (GNUNET_ERROR_TYPE_INFO,
572 _ (
573 "Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"),
574 service_name,
575 strerror (errno));
576 disablev6 = GNUNET_YES;
577 }
578 else
579 {
580 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
581 desc = NULL;
582 }
583 }
584
585 port = 0;
586 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT"))
587 {
588 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg,
589 service_name,
590 "PORT",
591 &port))
592 {
593 LOG (GNUNET_ERROR_TYPE_ERROR,
594 _ ("Require valid port number for service `%s' in configuration!\n"),
595 service_name);
596 }
597 if (port > 65535)
598 {
599 LOG (GNUNET_ERROR_TYPE_ERROR,
600 _ ("Require valid port number for service `%s' in configuration!\n"),
601 service_name);
602 return GNUNET_SYSERR;
603 }
604 }
605
606 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO"))
607 {
608 GNUNET_break (GNUNET_OK ==
609 GNUNET_CONFIGURATION_get_value_string (cfg,
610 service_name,
611 "BINDTO",
612 &hostname));
613 }
614 else
615 hostname = NULL;
616
617 unixpath = NULL;
618 abstract = GNUNET_NO;
619#ifdef AF_UNIX
620 if ((GNUNET_YES ==
621 GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) &&
622 (GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg,
623 service_name,
624 "UNIXPATH",
625 &unixpath)) &&
626 (0 < strlen (unixpath)))
627 {
628 /* probe UNIX support */
629 struct sockaddr_un s_un;
630
631 if (strlen (unixpath) >= sizeof(s_un.sun_path))
632 {
633 LOG (GNUNET_ERROR_TYPE_WARNING,
634 _ ("UNIXPATH `%s' too long, maximum length is %llu\n"),
635 unixpath,
636 (unsigned long long) sizeof(s_un.sun_path));
637 unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
638 LOG (GNUNET_ERROR_TYPE_INFO, _ ("Using `%s' instead\n"), unixpath);
639 }
640#ifdef __linux__
641 abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
642 "TESTING",
643 "USE_ABSTRACT_SOCKETS");
644 if (GNUNET_SYSERR == abstract)
645 abstract = GNUNET_NO;
646#endif
647 if ((GNUNET_YES != abstract) &&
648 (GNUNET_OK != GNUNET_DISK_directory_create_for_file (unixpath)))
649 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "mkdir", unixpath);
650 }
651 if (NULL != unixpath)
652 {
653 desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
654 if (NULL == desc)
655 {
656 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
657 (EACCES == errno))
658 {
659 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
660 GNUNET_free (hostname);
661 GNUNET_free (unixpath);
662 return GNUNET_SYSERR;
663 }
664 LOG (GNUNET_ERROR_TYPE_INFO,
665 _ (
666 "Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"),
667 service_name,
668 strerror (errno));
669 GNUNET_free (unixpath);
670 unixpath = NULL;
671 }
672 else
673 {
674 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
675 desc = NULL;
676 }
677 }
678#endif
679
680 if ((0 == port) && (NULL == unixpath))
681 {
682 LOG (GNUNET_ERROR_TYPE_ERROR,
683 _ (
684 "Have neither PORT nor UNIXPATH for service `%s', but one is required\n"),
685 service_name);
686 GNUNET_free (hostname);
687 return GNUNET_SYSERR;
688 }
689 if (0 == port)
690 {
691 saddrs = GNUNET_malloc (2 * sizeof(struct sockaddr *));
692 saddrlens = GNUNET_malloc (2 * sizeof(socklen_t));
693 add_unixpath (saddrs, saddrlens, unixpath, abstract);
694 GNUNET_free (unixpath);
695 GNUNET_free (hostname);
696 *addrs = saddrs;
697 *addr_lens = saddrlens;
698 return 1;
699 }
700
701 if (NULL != hostname)
702 {
703 LOG (GNUNET_ERROR_TYPE_DEBUG,
704 "Resolving `%s' since that is where `%s' will bind to.\n",
705 hostname,
706 service_name);
707 memset (&hints, 0, sizeof(struct addrinfo));
708 if (disablev6)
709 hints.ai_family = AF_INET;
710 hints.ai_protocol = IPPROTO_TCP;
711 if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
712 (NULL == res))
713 {
714 LOG (GNUNET_ERROR_TYPE_ERROR,
715 _ ("Failed to resolve `%s': %s\n"),
716 hostname,
717 gai_strerror (ret));
718 GNUNET_free (hostname);
719 GNUNET_free (unixpath);
720 return GNUNET_SYSERR;
721 }
722 next = res;
723 i = 0;
724 while (NULL != (pos = next))
725 {
726 next = pos->ai_next;
727 if ((disablev6) && (pos->ai_family == AF_INET6))
728 continue;
729 i++;
730 }
731 if (0 == i)
732 {
733 LOG (GNUNET_ERROR_TYPE_ERROR,
734 _ ("Failed to find %saddress for `%s'.\n"),
735 disablev6 ? "IPv4 " : "",
736 hostname);
737 freeaddrinfo (res);
738 GNUNET_free (hostname);
739 GNUNET_free (unixpath);
740 return GNUNET_SYSERR;
741 }
742 resi = i;
743 if (NULL != unixpath)
744 resi++;
745 saddrs = GNUNET_malloc ((resi + 1) * sizeof(struct sockaddr *));
746 saddrlens = GNUNET_malloc ((resi + 1) * sizeof(socklen_t));
747 i = 0;
748 if (NULL != unixpath)
749 {
750 add_unixpath (saddrs, saddrlens, unixpath, abstract);
751 i++;
752 }
753 next = res;
754 while (NULL != (pos = next))
755 {
756 next = pos->ai_next;
757 if ((disablev6) && (AF_INET6 == pos->ai_family))
758 continue;
759 if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol))
760 continue; /* not TCP */
761 if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
762 continue; /* huh? */
763 LOG (GNUNET_ERROR_TYPE_DEBUG,
764 "Service `%s' will bind to `%s'\n",
765 service_name,
766 GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
767 if (AF_INET == pos->ai_family)
768 {
769 GNUNET_assert (sizeof(struct sockaddr_in) == pos->ai_addrlen);
770 saddrlens[i] = pos->ai_addrlen;
771 saddrs[i] = GNUNET_malloc (saddrlens[i]);
772 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
773 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
774 }
775 else
776 {
777 GNUNET_assert (AF_INET6 == pos->ai_family);
778 GNUNET_assert (sizeof(struct sockaddr_in6) == pos->ai_addrlen);
779 saddrlens[i] = pos->ai_addrlen;
780 saddrs[i] = GNUNET_malloc (saddrlens[i]);
781 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
782 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
783 }
784 i++;
785 }
786 GNUNET_free (hostname);
787 freeaddrinfo (res);
788 resi = i;
789 }
790 else
791 {
792 /* will bind against everything, just set port */
793 if (disablev6)
794 {
795 /* V4-only */
796 resi = 1;
797 if (NULL != unixpath)
798 resi++;
799 i = 0;
800 saddrs = GNUNET_malloc ((resi + 1) * sizeof(struct sockaddr *));
801 saddrlens = GNUNET_malloc ((resi + 1) * sizeof(socklen_t));
802 if (NULL != unixpath)
803 {
804 add_unixpath (saddrs, saddrlens, unixpath, abstract);
805 i++;
806 }
807 saddrlens[i] = sizeof(struct sockaddr_in);
808 saddrs[i] = GNUNET_malloc (saddrlens[i]);
809#if HAVE_SOCKADDR_IN_SIN_LEN
810 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
811#endif
812 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
813 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
814 }
815 else
816 {
817 /* dual stack */
818 resi = 2;
819 if (NULL != unixpath)
820 resi++;
821 saddrs = GNUNET_malloc ((resi + 1) * sizeof(struct sockaddr *));
822 saddrlens = GNUNET_malloc ((resi + 1) * sizeof(socklen_t));
823 i = 0;
824 if (NULL != unixpath)
825 {
826 add_unixpath (saddrs, saddrlens, unixpath, abstract);
827 i++;
828 }
829 saddrlens[i] = sizeof(struct sockaddr_in6);
830 saddrs[i] = GNUNET_malloc (saddrlens[i]);
831#if HAVE_SOCKADDR_IN_SIN_LEN
832 ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
833#endif
834 ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
835 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
836 i++;
837 saddrlens[i] = sizeof(struct sockaddr_in);
838 saddrs[i] = GNUNET_malloc (saddrlens[i]);
839#if HAVE_SOCKADDR_IN_SIN_LEN
840 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
841#endif
842 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
843 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
844 }
845 }
846 GNUNET_free (unixpath);
847 *addrs = saddrs;
848 *addr_lens = saddrlens;
849 return resi;
850}
851
852
853/**
854 * Setup addr, addrlen, idle_timeout
855 * based on configuration!
856 *
857 * Configuration may specify:
858 * - PORT (where to bind to for TCP)
859 * - UNIXPATH (where to bind to for UNIX domain sockets)
860 * - TIMEOUT (after how many ms does an inactive service timeout);
861 * - DISABLEV6 (disable support for IPv6, otherwise we use dual-stack)
862 * - BINDTO (hostname or IP address to bind to, otherwise we take everything)
863 * - ACCEPT_FROM (only allow connections from specified IPv4 subnets)
864 * - ACCEPT_FROM6 (only allow connections from specified IPv6 subnets)
865 * - REJECT_FROM (disallow allow connections from specified IPv4 subnets)
866 * - REJECT_FROM6 (disallow allow connections from specified IPv6 subnets)
867 *
868 * @param sctx service context to initialize
869 * @return #GNUNET_OK if configuration succeeded
870 */
871static int
872setup_service (struct LEGACY_SERVICE_Context *sctx)
873{
874 struct GNUNET_TIME_Relative idleout;
875 int tolerant;
876 const char *nfds;
877 unsigned int cnt;
878 int flags;
879
880 if (GNUNET_CONFIGURATION_have_value (sctx->cfg,
881 sctx->service_name,
882 "TIMEOUT"))
883 {
884 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (sctx->cfg,
885 sctx->service_name,
886 "TIMEOUT",
887 &idleout))
888 {
889 LOG (GNUNET_ERROR_TYPE_ERROR,
890 _ ("Specified value for `%s' of service `%s' is invalid\n"),
891 "TIMEOUT",
892 sctx->service_name);
893 return GNUNET_SYSERR;
894 }
895 sctx->timeout = idleout;
896 }
897 else
898 sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
899
900 if (GNUNET_CONFIGURATION_have_value (sctx->cfg,
901 sctx->service_name,
902 "TOLERANT"))
903 {
904 if (GNUNET_SYSERR ==
905 (tolerant = GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg,
906 sctx->service_name,
907 "TOLERANT")))
908 {
909 LOG (GNUNET_ERROR_TYPE_ERROR,
910 _ ("Specified value for `%s' of service `%s' is invalid\n"),
911 "TOLERANT",
912 sctx->service_name);
913 return GNUNET_SYSERR;
914 }
915 }
916 else
917 tolerant = GNUNET_NO;
918
919 errno = 0;
920 if ((NULL != (nfds = getenv ("LISTEN_FDS"))) &&
921 (1 == sscanf (nfds, "%u", &cnt)) && (cnt > 0) && (cnt < FD_SETSIZE) &&
922 (cnt + 4 < FD_SETSIZE))
923 {
924 sctx->lsocks =
925 GNUNET_malloc (sizeof(struct GNUNET_NETWORK_Handle *) * (cnt + 1));
926 while (0 < cnt--)
927 {
928 flags = fcntl (3 + cnt, F_GETFD);
929 if ((flags < 0) || (0 != (flags & FD_CLOEXEC)) ||
930 (NULL ==
931 (sctx->lsocks[cnt] = GNUNET_NETWORK_socket_box_native (3 + cnt))))
932 {
933 LOG (GNUNET_ERROR_TYPE_ERROR,
934 _ (
935 "Could not access pre-bound socket %u, will try to bind myself\n"),
936 (unsigned int) 3 + cnt);
937 cnt++;
938 while (sctx->lsocks[cnt] != NULL)
939 GNUNET_break (0 == GNUNET_NETWORK_socket_close (sctx->lsocks[cnt++]));
940 GNUNET_free (sctx->lsocks);
941 sctx->lsocks = NULL;
942 break;
943 }
944 }
945 unsetenv ("LISTEN_FDS");
946 }
947
948 if ((NULL == sctx->lsocks) &&
949 (GNUNET_SYSERR == LEGACY_SERVICE_get_server_addresses (sctx->service_name,
950 sctx->cfg,
951 &sctx->addrs,
952 &sctx->addrlens)))
953 return GNUNET_SYSERR;
954 sctx->require_found = tolerant ? GNUNET_NO : GNUNET_YES;
955 sctx->match_uid = GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg,
956 sctx->service_name,
957 "UNIX_MATCH_UID");
958 sctx->match_gid = GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg,
959 sctx->service_name,
960 "UNIX_MATCH_GID");
961 process_acl4 (&sctx->v4_denied, sctx, "REJECT_FROM");
962 process_acl4 (&sctx->v4_allowed, sctx, "ACCEPT_FROM");
963 process_acl6 (&sctx->v6_denied, sctx, "REJECT_FROM6");
964 process_acl6 (&sctx->v6_allowed, sctx, "ACCEPT_FROM6");
965
966 return GNUNET_OK;
967}
968
969
970/**
971 * Get the name of the user that'll be used
972 * to provide the service.
973 *
974 * @param sctx service context
975 * @return value of the 'USERNAME' option
976 */
977static char *
978get_user_name (struct LEGACY_SERVICE_Context *sctx)
979{
980 char *un;
981
982 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (sctx->cfg,
983 sctx->service_name,
984 "USERNAME",
985 &un))
986 return NULL;
987 return un;
988}
989
990
991/**
992 * Write PID file.
993 *
994 * @param sctx service context
995 * @param pid PID to write (should be equal to 'getpid()'
996 * @return #GNUNET_OK on success (including no work to be done)
997 */
998static int
999write_pid_file (struct LEGACY_SERVICE_Context *sctx, pid_t pid)
1000{
1001 FILE *pidfd;
1002 char *pif;
1003 char *user;
1004 char *rdir;
1005 int len;
1006
1007 if (NULL == (pif = get_pid_file_name (sctx)))
1008 return GNUNET_OK; /* no file desired */
1009 user = get_user_name (sctx);
1010 rdir = GNUNET_strdup (pif);
1011 len = strlen (rdir);
1012 while ((len > 0) && (rdir[len] != DIR_SEPARATOR))
1013 len--;
1014 rdir[len] = '\0';
1015 if (0 != access (rdir, F_OK))
1016 {
1017 /* we get to create a directory -- and claim it
1018 * as ours! */
1019 (void) GNUNET_DISK_directory_create (rdir);
1020 if ((NULL != user) && (0 < strlen (user)))
1021 GNUNET_DISK_file_change_owner (rdir, user);
1022 }
1023 if (0 != access (rdir, W_OK | X_OK))
1024 {
1025 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "access", rdir);
1026 GNUNET_free (rdir);
1027 GNUNET_free (user);
1028 GNUNET_free (pif);
1029 return GNUNET_SYSERR;
1030 }
1031 GNUNET_free (rdir);
1032 pidfd = fopen (pif, "w");
1033 if (NULL == pidfd)
1034 {
1035 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "fopen", pif);
1036 GNUNET_free (pif);
1037 GNUNET_free (user);
1038 return GNUNET_SYSERR;
1039 }
1040 if (0 > fprintf (pidfd, "%u", pid))
1041 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fprintf", pif);
1042 GNUNET_break (0 == fclose (pidfd));
1043 if ((NULL != user) && (0 < strlen (user)))
1044 GNUNET_DISK_file_change_owner (pif, user);
1045 GNUNET_free (user);
1046 GNUNET_free (pif);
1047 return GNUNET_OK;
1048}
1049
1050
1051/**
1052 * Task run during shutdown. Stops the server/service.
1053 *
1054 * @param cls the `struct LEGACY_SERVICE_Context`
1055 */
1056static void
1057shutdown_task (void *cls)
1058{
1059 struct LEGACY_SERVICE_Context *service = cls;
1060 struct GNUNET_SERVER_Handle *server = service->server;
1061
1062 service->shutdown_task = NULL;
1063 if (0 != (service->options & LEGACY_SERVICE_OPTION_SOFT_SHUTDOWN))
1064 GNUNET_SERVER_stop_listening (server);
1065 else
1066 GNUNET_SERVER_destroy (server);
1067}
1068
1069
1070/**
1071 * Initial task for the service.
1072 *
1073 * @param cls service context
1074 */
1075static void
1076service_task (void *cls)
1077{
1078 struct LEGACY_SERVICE_Context *sctx = cls;
1079 unsigned int i;
1080
1081 GNUNET_RESOLVER_connect (sctx->cfg);
1082 if (NULL != sctx->lsocks)
1083 sctx->server = GNUNET_SERVER_create_with_sockets (&check_access,
1084 sctx,
1085 sctx->lsocks,
1086 sctx->timeout,
1087 sctx->require_found);
1088 else
1089 sctx->server = GNUNET_SERVER_create (&check_access,
1090 sctx,
1091 sctx->addrs,
1092 sctx->addrlens,
1093 sctx->timeout,
1094 sctx->require_found);
1095 if (NULL == sctx->server)
1096 {
1097 if (NULL != sctx->addrs)
1098 for (i = 0; NULL != sctx->addrs[i]; i++)
1099 LOG (GNUNET_ERROR_TYPE_INFO,
1100 _ ("Failed to start `%s' at `%s'\n"),
1101 sctx->service_name,
1102 GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i]));
1103 sctx->ret = GNUNET_SYSERR;
1104 return;
1105 }
1106
1107 if (NULL != sctx->addrs)
1108 for (i = 0; NULL != sctx->addrs[i]; i++)
1109 if ((AF_UNIX == sctx->addrs[i]->sa_family) &&
1110 ('\0' != ((const struct sockaddr_un *) sctx->addrs[i])->sun_path[0]))
1111 GNUNET_DISK_fix_permissions (((const struct sockaddr_un *)
1112 sctx->addrs[i])
1113 ->sun_path,
1114 sctx->match_uid,
1115 sctx->match_gid);
1116
1117 if (0 == (sctx->options & LEGACY_SERVICE_OPTION_MANUAL_SHUTDOWN))
1118 {
1119 /* install a task that will kill the server
1120 * process if the scheduler ever gets a shutdown signal */
1121 sctx->shutdown_task = GNUNET_SCHEDULER_add_shutdown (&shutdown_task, sctx);
1122 }
1123 sctx->my_handlers = GNUNET_malloc (sizeof(defhandlers));
1124 GNUNET_memcpy (sctx->my_handlers, defhandlers, sizeof(defhandlers));
1125 i = 0;
1126 while (NULL != sctx->my_handlers[i].callback)
1127 sctx->my_handlers[i++].callback_cls = sctx;
1128 GNUNET_SERVER_add_handlers (sctx->server, sctx->my_handlers);
1129 if (-1 != sctx->ready_confirm_fd)
1130 {
1131 GNUNET_break (1 == write (sctx->ready_confirm_fd, ".", 1));
1132 GNUNET_break (0 == close (sctx->ready_confirm_fd));
1133 sctx->ready_confirm_fd = -1;
1134 write_pid_file (sctx, getpid ());
1135 }
1136 if (NULL != sctx->addrs)
1137 {
1138 i = 0;
1139 while (NULL != sctx->addrs[i])
1140 {
1141 LOG (GNUNET_ERROR_TYPE_INFO,
1142 _ ("Service `%s' runs at %s\n"),
1143 sctx->service_name,
1144 GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i]));
1145 i++;
1146 }
1147 }
1148 sctx->task (sctx->task_cls, sctx->server, sctx->cfg);
1149}
1150
1151
1152/**
1153 * Detach from terminal.
1154 *
1155 * @param sctx service context
1156 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1157 */
1158static int
1159detach_terminal (struct LEGACY_SERVICE_Context *sctx)
1160{
1161 pid_t pid;
1162 int nullfd;
1163 int filedes[2];
1164
1165 if (0 != pipe (filedes))
1166 {
1167 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "pipe");
1168 return GNUNET_SYSERR;
1169 }
1170 pid = fork ();
1171 if (pid < 0)
1172 {
1173 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork");
1174 return GNUNET_SYSERR;
1175 }
1176 if (0 != pid)
1177 {
1178 /* Parent */
1179 char c;
1180
1181 GNUNET_break (0 == close (filedes[1]));
1182 c = 'X';
1183 if (1 != read (filedes[0], &c, sizeof(char)))
1184 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "read");
1185 fflush (stdout);
1186 switch (c)
1187 {
1188 case '.':
1189 exit (0);
1190
1191 case 'I':
1192 LOG (GNUNET_ERROR_TYPE_INFO,
1193 _ ("Service process failed to initialize\n"));
1194 break;
1195
1196 case 'S':
1197 LOG (GNUNET_ERROR_TYPE_INFO,
1198 _ ("Service process could not initialize server function\n"));
1199 break;
1200
1201 case 'X':
1202 LOG (GNUNET_ERROR_TYPE_INFO,
1203 _ ("Service process failed to report status\n"));
1204 break;
1205 }
1206 exit (1); /* child reported error */
1207 }
1208 GNUNET_break (0 == close (0));
1209 GNUNET_break (0 == close (1));
1210 GNUNET_break (0 == close (filedes[0]));
1211 nullfd = open ("/dev/null", O_RDWR | O_APPEND);
1212 if (nullfd < 0)
1213 return GNUNET_SYSERR;
1214 /* set stdin/stdout to /dev/null */
1215 if ((dup2 (nullfd, 0) < 0) || (dup2 (nullfd, 1) < 0))
1216 {
1217 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2");
1218 (void) close (nullfd);
1219 return GNUNET_SYSERR;
1220 }
1221 (void) close (nullfd);
1222 /* Detach from controlling terminal */
1223 pid = setsid ();
1224 if (-1 == pid)
1225 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "setsid");
1226 sctx->ready_confirm_fd = filedes[1];
1227
1228 return GNUNET_OK;
1229}
1230
1231
1232/**
1233 * Set user ID.
1234 *
1235 * @param sctx service context
1236 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1237 */
1238static int
1239set_user_id (struct LEGACY_SERVICE_Context *sctx)
1240{
1241 char *user;
1242
1243 if (NULL == (user = get_user_name (sctx)))
1244 return GNUNET_OK; /* keep */
1245
1246 struct passwd *pws;
1247
1248 errno = 0;
1249 pws = getpwnam (user);
1250 if (NULL == pws)
1251 {
1252 LOG (GNUNET_ERROR_TYPE_ERROR,
1253 _ ("Cannot obtain information about user `%s': %s\n"),
1254 user,
1255 errno == 0 ? _ ("No such user") : strerror (errno));
1256 GNUNET_free (user);
1257 return GNUNET_SYSERR;
1258 }
1259 if ((0 != setgid (pws->pw_gid)) || (0 != setegid (pws->pw_gid)) ||
1260#if HAVE_INITGROUPS
1261 (0 != initgroups (user, pws->pw_gid)) ||
1262#endif
1263 (0 != setuid (pws->pw_uid)) || (0 != seteuid (pws->pw_uid)))
1264 {
1265 if ((0 != setregid (pws->pw_gid, pws->pw_gid)) ||
1266 (0 != setreuid (pws->pw_uid, pws->pw_uid)))
1267 {
1268 LOG (GNUNET_ERROR_TYPE_ERROR,
1269 _ ("Cannot change user/group to `%s': %s\n"),
1270 user,
1271 strerror (errno));
1272 GNUNET_free (user);
1273 return GNUNET_SYSERR;
1274 }
1275 }
1276
1277 GNUNET_free (user);
1278 return GNUNET_OK;
1279}
1280
1281
1282/**
1283 * Delete the PID file that was created by our parent.
1284 *
1285 * @param sctx service context
1286 */
1287static void
1288pid_file_delete (struct LEGACY_SERVICE_Context *sctx)
1289{
1290 char *pif = get_pid_file_name (sctx);
1291
1292 if (NULL == pif)
1293 return; /* no PID file */
1294 if (0 != unlink (pif))
1295 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", pif);
1296 GNUNET_free (pif);
1297}
1298
1299
1300/**
1301 * Run a standard GNUnet service startup sequence (initialize loggers
1302 * and configuration, parse options).
1303 *
1304 * @param argc number of command line arguments
1305 * @param argv command line arguments
1306 * @param service_name our service name
1307 * @param options service options
1308 * @param task main task of the service
1309 * @param task_cls closure for @a task
1310 * @return #GNUNET_SYSERR on error, #GNUNET_OK
1311 * if we shutdown nicely
1312 */
1313int
1314LEGACY_SERVICE_run (int argc,
1315 char *const *argv,
1316 const char *service_name,
1317 enum LEGACY_SERVICE_Options options,
1318 LEGACY_SERVICE_Main task,
1319 void *task_cls)
1320{
1321#define HANDLE_ERROR \
1322 do \
1323 { \
1324 GNUNET_break (0); \
1325 goto shutdown; \
1326 } while (0)
1327
1328 int err;
1329 int ret;
1330 char *cfg_fn;
1331 char *opt_cfg_fn;
1332 char *loglev;
1333 char *logfile;
1334 int do_daemonize;
1335 unsigned int i;
1336 unsigned long long skew_offset;
1337 unsigned long long skew_variance;
1338 long long clock_offset;
1339 struct LEGACY_SERVICE_Context sctx;
1340 struct GNUNET_CONFIGURATION_Handle *cfg;
1341 const char *xdg;
1342
1343 struct GNUNET_GETOPT_CommandLineOption service_options[] =
1344 { GNUNET_GETOPT_option_cfgfile (&opt_cfg_fn),
1345 GNUNET_GETOPT_option_flag ('d',
1346 "daemonize",
1347 gettext_noop (
1348 "do daemonize (detach from terminal)"),
1349 &do_daemonize),
1350 GNUNET_GETOPT_option_help (NULL),
1351 GNUNET_GETOPT_option_loglevel (&loglev),
1352 GNUNET_GETOPT_option_logfile (&logfile),
1353 GNUNET_GETOPT_option_version (PACKAGE_VERSION " " VCS_VERSION),
1354 GNUNET_GETOPT_OPTION_END };
1355 err = 1;
1356 do_daemonize = 0;
1357 logfile = NULL;
1358 loglev = NULL;
1359 opt_cfg_fn = NULL;
1360 xdg = getenv ("XDG_CONFIG_HOME");
1361 if (NULL != xdg)
1362 GNUNET_asprintf (&cfg_fn,
1363 "%s%s%s",
1364 xdg,
1365 DIR_SEPARATOR_STR,
1366 GNUNET_OS_project_data_get ()->config_file);
1367 else
1368 cfg_fn = GNUNET_strdup (GNUNET_OS_project_data_get ()->user_config_file);
1369 memset (&sctx, 0, sizeof(sctx));
1370 sctx.options = options;
1371 sctx.ready_confirm_fd = -1;
1372 sctx.ret = GNUNET_OK;
1373 sctx.timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1374 sctx.task = task;
1375 sctx.task_cls = task_cls;
1376 sctx.service_name = service_name;
1377 sctx.cfg = cfg = GNUNET_CONFIGURATION_create ();
1378
1379 /* setup subsystems */
1380 ret = GNUNET_GETOPT_run (service_name, service_options, argc, argv);
1381 if (GNUNET_SYSERR == ret)
1382 goto shutdown;
1383 if (GNUNET_NO == ret)
1384 {
1385 err = 0;
1386 goto shutdown;
1387 }
1388 if (GNUNET_OK != GNUNET_log_setup (service_name, loglev, logfile))
1389 HANDLE_ERROR;
1390 if (NULL == opt_cfg_fn)
1391 opt_cfg_fn = GNUNET_strdup (cfg_fn);
1392 if (GNUNET_YES == GNUNET_DISK_file_test (opt_cfg_fn))
1393 {
1394 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, opt_cfg_fn))
1395 {
1396 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1397 _ ("Malformed configuration file `%s', exit ...\n"),
1398 opt_cfg_fn);
1399 goto shutdown;
1400 }
1401 }
1402 else
1403 {
1404 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, NULL))
1405 {
1406 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1407 _ ("Malformed configuration, exit ...\n"));
1408 goto shutdown;
1409 }
1410 if (0 != strcmp (opt_cfg_fn, cfg_fn))
1411 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1412 _ ("Could not access configuration file `%s'\n"),
1413 opt_cfg_fn);
1414 }
1415 if (GNUNET_OK != setup_service (&sctx))
1416 goto shutdown;
1417 if ((1 == do_daemonize) && (GNUNET_OK != detach_terminal (&sctx)))
1418 HANDLE_ERROR;
1419 if (GNUNET_OK != set_user_id (&sctx))
1420 goto shutdown;
1421 LOG (GNUNET_ERROR_TYPE_DEBUG,
1422 "Service `%s' runs with configuration from `%s'\n",
1423 service_name,
1424 opt_cfg_fn);
1425 if ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (sctx.cfg,
1426 "TESTING",
1427 "SKEW_OFFSET",
1428 &skew_offset)) &&
1429 (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (sctx.cfg,
1430 "TESTING",
1431 "SKEW_VARIANCE",
1432 &skew_variance)))
1433 {
1434 clock_offset = skew_offset - skew_variance;
1435 GNUNET_TIME_set_offset (clock_offset);
1436 LOG (GNUNET_ERROR_TYPE_DEBUG, "Skewing clock by %lld ms\n", clock_offset);
1437 }
1438 /* actually run service */
1439 err = 0;
1440 GNUNET_SCHEDULER_run (&service_task, &sctx);
1441 /* shutdown */
1442 if ((1 == do_daemonize) && (NULL != sctx.server))
1443 pid_file_delete (&sctx);
1444 GNUNET_free (sctx.my_handlers);
1445
1446shutdown:
1447 if (-1 != sctx.ready_confirm_fd)
1448 {
1449 if (1 != write (sctx.ready_confirm_fd, err ? "I" : "S", 1))
1450 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "write");
1451 GNUNET_break (0 == close (sctx.ready_confirm_fd));
1452 }
1453#if HAVE_MALLINFO
1454 {
1455 char *counter;
1456
1457 if ((GNUNET_YES == GNUNET_CONFIGURATION_have_value (sctx.cfg,
1458 service_name,
1459 "GAUGER_HEAP")) &&
1460 (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (sctx.cfg,
1461 service_name,
1462 "GAUGER_HEAP",
1463 &counter)))
1464 {
1465 struct mallinfo mi;
1466
1467 mi = mallinfo ();
1468 GAUGER (service_name, counter, mi.usmblks, "blocks");
1469 GNUNET_free (counter);
1470 }
1471 }
1472#endif
1473 GNUNET_CONFIGURATION_destroy (cfg);
1474 i = 0;
1475 if (NULL != sctx.addrs)
1476 while (NULL != sctx.addrs[i])
1477 GNUNET_free_nz (sctx.addrs[i++]);
1478 GNUNET_free (sctx.addrs);
1479 GNUNET_free (sctx.addrlens);
1480 GNUNET_free (logfile);
1481 GNUNET_free (loglev);
1482 GNUNET_free (cfg_fn);
1483 GNUNET_free (opt_cfg_fn);
1484 GNUNET_free (sctx.v4_denied);
1485 GNUNET_free (sctx.v6_denied);
1486 GNUNET_free (sctx.v4_allowed);
1487 GNUNET_free (sctx.v6_allowed);
1488
1489 return err ? GNUNET_SYSERR : sctx.ret;
1490}
1491
1492
1493/**
1494 * Run a service startup sequence within an existing
1495 * initialized system.
1496 *
1497 * @param service_name our service name
1498 * @param cfg configuration to use
1499 * @param options service options
1500 * @return NULL on error, service handle
1501 */
1502struct LEGACY_SERVICE_Context *
1503LEGACY_SERVICE_start (const char *service_name,
1504 const struct GNUNET_CONFIGURATION_Handle *cfg,
1505 enum LEGACY_SERVICE_Options options)
1506{
1507 int i;
1508 struct LEGACY_SERVICE_Context *sctx;
1509
1510 sctx = GNUNET_new (struct LEGACY_SERVICE_Context);
1511 sctx->ready_confirm_fd = -1; /* no daemonizing */
1512 sctx->ret = GNUNET_OK;
1513 sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1514 sctx->service_name = service_name;
1515 sctx->cfg = cfg;
1516 sctx->options = options;
1517
1518 /* setup subsystems */
1519 if (GNUNET_OK != setup_service (sctx))
1520 {
1521 LEGACY_SERVICE_stop (sctx);
1522 return NULL;
1523 }
1524 if (NULL != sctx->lsocks)
1525 sctx->server = GNUNET_SERVER_create_with_sockets (&check_access,
1526 sctx,
1527 sctx->lsocks,
1528 sctx->timeout,
1529 sctx->require_found);
1530 else
1531 sctx->server = GNUNET_SERVER_create (&check_access,
1532 sctx,
1533 sctx->addrs,
1534 sctx->addrlens,
1535 sctx->timeout,
1536 sctx->require_found);
1537
1538 if (NULL == sctx->server)
1539 {
1540 LEGACY_SERVICE_stop (sctx);
1541 return NULL;
1542 }
1543
1544 if (NULL != sctx->addrs)
1545 for (i = 0; NULL != sctx->addrs[i]; i++)
1546 if ((AF_UNIX == sctx->addrs[i]->sa_family) &&
1547 ('\0' != ((const struct sockaddr_un *) sctx->addrs[i])->sun_path[0]))
1548 GNUNET_DISK_fix_permissions (((const struct sockaddr_un *)
1549 sctx->addrs[i])
1550 ->sun_path,
1551 sctx->match_uid,
1552 sctx->match_gid);
1553
1554 sctx->my_handlers = GNUNET_malloc (sizeof(defhandlers));
1555 GNUNET_memcpy (sctx->my_handlers, defhandlers, sizeof(defhandlers));
1556 i = 0;
1557 while ((sctx->my_handlers[i].callback != NULL))
1558 sctx->my_handlers[i++].callback_cls = sctx;
1559 GNUNET_SERVER_add_handlers (sctx->server, sctx->my_handlers);
1560 return sctx;
1561}
1562
1563
1564/**
1565 * Obtain the server used by a service. Note that the server must NOT
1566 * be destroyed by the caller.
1567 *
1568 * @param ctx the service context returned from the start function
1569 * @return handle to the server for this service, NULL if there is none
1570 */
1571struct GNUNET_SERVER_Handle *
1572LEGACY_SERVICE_get_server (struct LEGACY_SERVICE_Context *ctx)
1573{
1574 return ctx->server;
1575}
1576
1577
1578/**
1579 * Get the NULL-terminated array of listen sockets for this service.
1580 *
1581 * @param ctx service context to query
1582 * @return NULL if there are no listen sockets, otherwise NULL-terminated
1583 * array of listen sockets.
1584 */
1585struct GNUNET_NETWORK_Handle *const *
1586LEGACY_SERVICE_get_listen_sockets (struct LEGACY_SERVICE_Context *ctx)
1587{
1588 return ctx->lsocks;
1589}
1590
1591
1592/**
1593 * Stop a service that was started with "LEGACY_SERVICE_start".
1594 *
1595 * @param sctx the service context returned from the start function
1596 */
1597void
1598LEGACY_SERVICE_stop (struct LEGACY_SERVICE_Context *sctx)
1599{
1600 unsigned int i;
1601
1602#if HAVE_MALLINFO
1603 {
1604 char *counter;
1605
1606 if ((GNUNET_YES == GNUNET_CONFIGURATION_have_value (sctx->cfg,
1607 sctx->service_name,
1608 "GAUGER_HEAP")) &&
1609 (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (sctx->cfg,
1610 sctx->service_name,
1611 "GAUGER_HEAP",
1612 &counter)))
1613 {
1614 struct mallinfo mi;
1615
1616 mi = mallinfo ();
1617 GAUGER (sctx->service_name, counter, mi.usmblks, "blocks");
1618 GNUNET_free (counter);
1619 }
1620 }
1621#endif
1622 if (NULL != sctx->shutdown_task)
1623 {
1624 GNUNET_SCHEDULER_cancel (sctx->shutdown_task);
1625 sctx->shutdown_task = NULL;
1626 }
1627 if (NULL != sctx->server)
1628 GNUNET_SERVER_destroy (sctx->server);
1629 GNUNET_free (sctx->my_handlers);
1630 if (NULL != sctx->addrs)
1631 {
1632 i = 0;
1633 while (NULL != sctx->addrs[i])
1634 GNUNET_free_nz (sctx->addrs[i++]);
1635 GNUNET_free (sctx->addrs);
1636 }
1637 GNUNET_free (sctx->addrlens);
1638 GNUNET_free (sctx->v4_denied);
1639 GNUNET_free (sctx->v6_denied);
1640 GNUNET_free (sctx->v4_allowed);
1641 GNUNET_free (sctx->v6_allowed);
1642 GNUNET_free (sctx);
1643}
1644
1645
1646/* end of service.c */