aboutsummaryrefslogtreecommitdiff
path: root/src/util/service.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util/service.c')
-rw-r--r--src/util/service.c2444
1 files changed, 0 insertions, 2444 deletions
diff --git a/src/util/service.c b/src/util/service.c
deleted file mode 100644
index df4feb0ec..000000000
--- a/src/util/service.c
+++ /dev/null
@@ -1,2444 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file util/service.c
23 * @brief functions related to starting services (redesign)
24 * @author Christian Grothoff
25 * @author Florian Dold
26 */
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_protocols.h"
30#include "gnunet_constants.h"
31#include "gnunet_resolver_service.h"
32#include "speedup.h"
33
34#if HAVE_MALLINFO2
35#include <malloc.h>
36#include "gauger.h"
37#endif
38
39
40#define LOG(kind, ...) GNUNET_log_from (kind, "util-service", __VA_ARGS__)
41
42#define LOG_STRERROR(kind, syscall) \
43 GNUNET_log_from_strerror (kind, "util-service", syscall)
44
45#define LOG_STRERROR_FILE(kind, syscall, filename) \
46 GNUNET_log_from_strerror_file (kind, "util-service", syscall, filename)
47
48
49/**
50 * Information the service tracks per listen operation.
51 */
52struct ServiceListenContext
53{
54 /**
55 * Kept in a DLL.
56 */
57 struct ServiceListenContext *next;
58
59 /**
60 * Kept in a DLL.
61 */
62 struct ServiceListenContext *prev;
63
64 /**
65 * Service this listen context belongs to.
66 */
67 struct GNUNET_SERVICE_Handle *sh;
68
69 /**
70 * Socket we are listening on.
71 */
72 struct GNUNET_NETWORK_Handle *listen_socket;
73
74 /**
75 * Task scheduled to do the listening.
76 */
77 struct GNUNET_SCHEDULER_Task *listen_task;
78};
79
80
81/**
82 * Reasons why we might be suspended.
83 */
84enum SuspendReason
85{
86 /**
87 * We are running normally.
88 */
89 SUSPEND_STATE_NONE = 0,
90
91 /**
92 * Application requested it.
93 */
94 SUSPEND_STATE_APP = 1,
95
96 /**
97 * OS ran out of file descriptors.
98 */
99 SUSPEND_STATE_EMFILE = 2,
100
101 /**
102 * Both reasons, APP and EMFILE apply.
103 */
104 SUSPEND_STATE_APP_AND_EMFILE = 3,
105
106 /**
107 * Suspension because service was permanently shutdown.
108 */
109 SUSPEND_STATE_SHUTDOWN = 4
110};
111
112
113/**
114 * Handle to a service.
115 */
116struct GNUNET_SERVICE_Handle
117{
118 /**
119 * Our configuration.
120 */
121 const struct GNUNET_CONFIGURATION_Handle *cfg;
122
123 /**
124 * Name of our service.
125 */
126 const char *service_name;
127
128 /**
129 * Main service-specific task to run.
130 */
131 GNUNET_SERVICE_InitCallback service_init_cb;
132
133 /**
134 * Function to call when clients connect.
135 */
136 GNUNET_SERVICE_ConnectHandler connect_cb;
137
138 /**
139 * Function to call when clients disconnect / are disconnected.
140 */
141 GNUNET_SERVICE_DisconnectHandler disconnect_cb;
142
143 /**
144 * Closure for @e service_init_cb, @e connect_cb, @e disconnect_cb.
145 */
146 void *cb_cls;
147
148 /**
149 * DLL of listen sockets used to accept new connections.
150 */
151 struct ServiceListenContext *slc_head;
152
153 /**
154 * DLL of listen sockets used to accept new connections.
155 */
156 struct ServiceListenContext *slc_tail;
157
158 /**
159 * Our clients, kept in a DLL.
160 */
161 struct GNUNET_SERVICE_Client *clients_head;
162
163 /**
164 * Our clients, kept in a DLL.
165 */
166 struct GNUNET_SERVICE_Client *clients_tail;
167
168 /**
169 * Message handlers to use for all clients.
170 */
171 struct GNUNET_MQ_MessageHandler *handlers;
172
173 /**
174 * Closure for @e task.
175 */
176 void *task_cls;
177
178
179 /**
180 * IPv4 addresses that are not allowed to connect.
181 */
182 struct GNUNET_STRINGS_IPv4NetworkPolicy *v4_denied;
183
184 /**
185 * IPv6 addresses that are not allowed to connect.
186 */
187 struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_denied;
188
189 /**
190 * IPv4 addresses that are allowed to connect (if not
191 * set, all are allowed).
192 */
193 struct GNUNET_STRINGS_IPv4NetworkPolicy *v4_allowed;
194
195 /**
196 * IPv6 addresses that are allowed to connect (if not
197 * set, all are allowed).
198 */
199 struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_allowed;
200
201 /**
202 * Do we require a matching UID for UNIX domain socket connections?
203 * #GNUNET_NO means that the UID does not have to match (however,
204 * @e match_gid may still impose other access control checks).
205 */
206 int match_uid;
207
208 /**
209 * Do we require a matching GID for UNIX domain socket connections?
210 * Ignored if @e match_uid is #GNUNET_YES. Note that this is about
211 * checking that the client's UID is in our group OR that the
212 * client's GID is our GID. If both "match_gid" and @e match_uid are
213 * #GNUNET_NO, all users on the local system have access.
214 */
215 int match_gid;
216
217 /**
218 * Are we suspended, and if so, why?
219 */
220 enum SuspendReason suspend_state;
221
222 /**
223 * Our options.
224 */
225 enum GNUNET_SERVICE_Options options;
226
227 /**
228 * If we are daemonizing, this FD is set to the
229 * pipe to the parent. Send '.' if we started
230 * ok, '!' if not. -1 if we are not daemonizing.
231 */
232 int ready_confirm_fd;
233
234 /**
235 * Overall success/failure of the service start.
236 */
237 int ret;
238
239 /**
240 * If #GNUNET_YES, consider unknown message types an error where the
241 * client is disconnected.
242 */
243 int require_found;
244};
245
246
247/**
248 * Handle to a client that is connected to a service.
249 */
250struct GNUNET_SERVICE_Client
251{
252 /**
253 * Kept in a DLL.
254 */
255 struct GNUNET_SERVICE_Client *next;
256
257 /**
258 * Kept in a DLL.
259 */
260 struct GNUNET_SERVICE_Client *prev;
261
262 /**
263 * Service that this client belongs to.
264 */
265 struct GNUNET_SERVICE_Handle *sh;
266
267 /**
268 * Socket of this client.
269 */
270 struct GNUNET_NETWORK_Handle *sock;
271
272 /**
273 * Message queue for the client.
274 */
275 struct GNUNET_MQ_Handle *mq;
276
277 /**
278 * Tokenizer we use for processing incoming data.
279 */
280 struct GNUNET_MessageStreamTokenizer *mst;
281
282 /**
283 * Task that warns about missing calls to
284 * #GNUNET_SERVICE_client_continue().
285 */
286 struct GNUNET_SCHEDULER_Task *warn_task;
287
288 /**
289 * Task run to finish dropping the client after the stack has
290 * properly unwound.
291 */
292 struct GNUNET_SCHEDULER_Task *drop_task;
293
294 /**
295 * Task that receives data from the client to
296 * pass it to the handlers.
297 */
298 struct GNUNET_SCHEDULER_Task *recv_task;
299
300 /**
301 * Task that transmit data to the client.
302 */
303 struct GNUNET_SCHEDULER_Task *send_task;
304
305 /**
306 * Pointer to the message to be transmitted by @e send_task.
307 */
308 const struct GNUNET_MessageHeader *msg;
309
310 /**
311 * User context value, value returned from
312 * the connect callback.
313 */
314 void *user_context;
315
316 /**
317 * Time when we last gave a message from this client
318 * to the application.
319 */
320 struct GNUNET_TIME_Absolute warn_start;
321
322 /**
323 * Current position in @e msg at which we are transmitting.
324 */
325 size_t msg_pos;
326
327 /**
328 * Persist the file handle for this client no matter what happens,
329 * force the OS to close once the process actually dies. Should only
330 * be used in special cases!
331 */
332 int persist;
333
334 /**
335 * Is this client a 'monitor' client that should not be counted
336 * when deciding on destroying the server during soft shutdown?
337 * (see also #GNUNET_SERVICE_start)
338 */
339 int is_monitor;
340
341 /**
342 * Are we waiting for the application to call #GNUNET_SERVICE_client_continue()?
343 */
344 int needs_continue;
345
346 /**
347 * Type of last message processed (for warn_no_receive_done).
348 */
349 uint16_t warn_type;
350};
351
352
353/**
354 * Check if any of the clients we have left are unrelated to
355 * monitoring.
356 *
357 * @param sh service to check clients for
358 * @return #GNUNET_YES if we have non-monitoring clients left
359 */
360static int
361have_non_monitor_clients (struct GNUNET_SERVICE_Handle *sh)
362{
363 for (struct GNUNET_SERVICE_Client *client = sh->clients_head; NULL != client;
364 client = client->next)
365 {
366 if (client->is_monitor)
367 continue;
368 return GNUNET_YES;
369 }
370 return GNUNET_NO;
371}
372
373
374/**
375 * Suspend accepting connections from the listen socket temporarily.
376 * Resume activity using #do_resume.
377 *
378 * @param sh service to stop accepting connections.
379 * @param sr reason for suspending accepting connections
380 */
381static void
382do_suspend (struct GNUNET_SERVICE_Handle *sh, enum SuspendReason sr)
383{
384 struct ServiceListenContext *slc;
385
386 GNUNET_assert (0 == (sh->suspend_state & sr));
387 sh->suspend_state |= sr;
388 for (slc = sh->slc_head; NULL != slc; slc = slc->next)
389 {
390 if (NULL != slc->listen_task)
391 {
392 GNUNET_SCHEDULER_cancel (slc->listen_task);
393 slc->listen_task = NULL;
394 }
395 }
396}
397
398
399/**
400 * Shutdown task triggered when a service should be terminated.
401 * This considers active clients and the service options to see
402 * how this specific service is to be terminated, and depending
403 * on this proceeds with the shutdown logic.
404 *
405 * @param cls our `struct GNUNET_SERVICE_Handle`
406 */
407static void
408service_shutdown (void *cls)
409{
410 struct GNUNET_SERVICE_Handle *sh = cls;
411
412 switch (sh->options & GNUNET_SERVICE_OPTION_SHUTDOWN_BITMASK)
413 {
414 case GNUNET_SERVICE_OPTION_NONE:
415 GNUNET_SERVICE_shutdown (sh);
416 break;
417 case GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN:
418 /* This task should never be run if we are using
419 the manual shutdown. */
420 GNUNET_assert (0);
421 break;
422 case GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN:
423 if (0 == (sh->suspend_state & SUSPEND_STATE_SHUTDOWN))
424 do_suspend (sh, SUSPEND_STATE_SHUTDOWN);
425 if (GNUNET_NO == have_non_monitor_clients (sh))
426 GNUNET_SERVICE_shutdown (sh);
427 break;
428 }
429}
430
431
432/**
433 * Check if the given IP address is in the list of IP addresses.
434 *
435 * @param list a list of networks
436 * @param add the IP to check (in network byte order)
437 * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is
438 */
439static int
440check_ipv4_listed (const struct GNUNET_STRINGS_IPv4NetworkPolicy *list,
441 const struct in_addr *add)
442{
443 unsigned int i;
444
445 if (NULL == list)
446 return GNUNET_NO;
447 i = 0;
448 while ((0 != list[i].network.s_addr) || (0 != list[i].netmask.s_addr))
449 {
450 if ((add->s_addr & list[i].netmask.s_addr) ==
451 (list[i].network.s_addr & list[i].netmask.s_addr))
452 return GNUNET_YES;
453 i++;
454 }
455 return GNUNET_NO;
456}
457
458
459/**
460 * Check if the given IP address is in the list of IP addresses.
461 *
462 * @param list a list of networks
463 * @param ip the IP to check (in network byte order)
464 * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is
465 */
466static int
467check_ipv6_listed (const struct GNUNET_STRINGS_IPv6NetworkPolicy *list,
468 const struct in6_addr *ip)
469{
470 unsigned int i;
471
472 if (NULL == list)
473 return GNUNET_NO;
474 i = 0;
475NEXT:
476 while (GNUNET_NO == GNUNET_is_zero (&list[i].network))
477 {
478 for (unsigned int j = 0; j < sizeof(struct in6_addr) / sizeof(int); j++)
479 if (((((int *) ip)[j] & ((int *) &list[i].netmask)[j])) !=
480 (((int *) &list[i].network)[j] & ((int *) &list[i].netmask)[j]))
481 {
482 i++;
483 goto NEXT;
484 }
485 return GNUNET_YES;
486 }
487 return GNUNET_NO;
488}
489
490
491/**
492 * Task run when we are ready to transmit data to the
493 * client.
494 *
495 * @param cls the `struct GNUNET_SERVICE_Client *` to send to
496 */
497static void
498do_send (void *cls)
499{
500 struct GNUNET_SERVICE_Client *client = cls;
501 ssize_t ret;
502 size_t left;
503 const char *buf;
504
505 LOG (GNUNET_ERROR_TYPE_DEBUG,
506 "service: sending message with type %u\n",
507 ntohs (client->msg->type));
508 client->send_task = NULL;
509 buf = (const char *) client->msg;
510 left = ntohs (client->msg->size) - client->msg_pos;
511 ret = GNUNET_NETWORK_socket_send (client->sock,
512 &buf[client->msg_pos],
513 left);
514 GNUNET_assert (ret <= (ssize_t) left);
515 if (0 == ret)
516 {
517 LOG (GNUNET_ERROR_TYPE_DEBUG, "no data send");
518 GNUNET_MQ_inject_error (client->mq, GNUNET_MQ_ERROR_WRITE);
519 return;
520 }
521 if (-1 == ret)
522 {
523 if ((EAGAIN == errno) || (EINTR == errno))
524 {
525 /* ignore */
526 ret = 0;
527 }
528 else
529 {
530 if (EPIPE != errno)
531 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "send");
532 LOG (GNUNET_ERROR_TYPE_DEBUG,
533 "socket send returned with error code %i",
534 errno);
535 GNUNET_MQ_inject_error (client->mq, GNUNET_MQ_ERROR_WRITE);
536 return;
537 }
538 }
539 if (0 == client->msg_pos)
540 {
541 GNUNET_MQ_impl_send_in_flight (client->mq);
542 }
543 client->msg_pos += ret;
544 if (left > (size_t) ret)
545 {
546 GNUNET_assert (NULL == client->drop_task);
547 client->send_task =
548 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
549 client->sock,
550 &do_send,
551 client);
552 return;
553 }
554 GNUNET_MQ_impl_send_continue (client->mq);
555}
556
557
558/**
559 * Signature of functions implementing the sending functionality of a
560 * message queue.
561 *
562 * @param mq the message queue
563 * @param msg the message to send
564 * @param impl_state our `struct GNUNET_SERVICE_Client *`
565 */
566static void
567service_mq_send (struct GNUNET_MQ_Handle *mq,
568 const struct GNUNET_MessageHeader *msg,
569 void *impl_state)
570{
571 struct GNUNET_SERVICE_Client *client = impl_state;
572
573 (void) mq;
574 if (NULL != client->drop_task)
575 return; /* we're going down right now, do not try to send */
576 GNUNET_assert (NULL == client->send_task);
577 LOG (GNUNET_ERROR_TYPE_DEBUG,
578 "Sending message of type %u and size %u to client\n",
579 ntohs (msg->type),
580 ntohs (msg->size));
581 client->msg = msg;
582 client->msg_pos = 0;
583 client->send_task = GNUNET_SCHEDULER_add_now (&do_send,
584 client);
585}
586
587
588/**
589 * Implementation function that cancels the currently sent message.
590 *
591 * @param mq message queue
592 * @param impl_state state specific to the implementation
593 */
594static void
595service_mq_cancel (struct GNUNET_MQ_Handle *mq, void *impl_state)
596{
597 struct GNUNET_SERVICE_Client *client = impl_state;
598
599 (void) mq;
600 GNUNET_assert (0 == client->msg_pos);
601 client->msg = NULL;
602 GNUNET_SCHEDULER_cancel (client->send_task);
603 client->send_task = NULL;
604}
605
606
607/**
608 * Generic error handler, called with the appropriate
609 * error code and the same closure specified at the creation of
610 * the message queue.
611 * Not every message queue implementation supports an error handler.
612 *
613 * @param cls closure with our `struct GNUNET_SERVICE_Client`
614 * @param error error code
615 */
616static void
617service_mq_error_handler (void *cls, enum GNUNET_MQ_Error error)
618{
619 struct GNUNET_SERVICE_Client *client = cls;
620 struct GNUNET_SERVICE_Handle *sh = client->sh;
621
622 if ((GNUNET_MQ_ERROR_NO_MATCH == error) && (GNUNET_NO == sh->require_found))
623 {
624 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
625 "No handler for message of type %u found\n",
626 (unsigned int) client->warn_type);
627 GNUNET_SERVICE_client_continue (client);
628 return; /* ignore error */
629 }
630 GNUNET_SERVICE_client_drop (client);
631}
632
633
634/**
635 * Task run to warn about missing calls to #GNUNET_SERVICE_client_continue().
636 *
637 * @param cls our `struct GNUNET_SERVICE_Client *` to process more requests from
638 */
639static void
640warn_no_client_continue (void *cls)
641{
642 struct GNUNET_SERVICE_Client *client = cls;
643
644 GNUNET_break (
645 0 !=
646 client->warn_type); /* type should never be 0 here, as we don't use 0 */
647 client->warn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
648 &warn_no_client_continue,
649 client);
650 LOG (
651 GNUNET_ERROR_TYPE_WARNING,
652 _ (
653 "Processing code for message of type %u did not call `GNUNET_SERVICE_client_continue' after %s\n"),
654 (unsigned int) client->warn_type,
655 GNUNET_STRINGS_relative_time_to_string (GNUNET_TIME_absolute_get_duration (
656 client->warn_start),
657 GNUNET_YES));
658}
659
660
661/**
662 * Functions with this signature are called whenever a
663 * complete message is received by the tokenizer for a client.
664 *
665 * Do not call #GNUNET_MST_destroy() from within
666 * the scope of this callback.
667 *
668 * @param cls closure with the `struct GNUNET_SERVICE_Client *`
669 * @param message the actual message
670 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the client was dropped
671 */
672static int
673service_client_mst_cb (void *cls, const struct GNUNET_MessageHeader *message)
674{
675 struct GNUNET_SERVICE_Client *client = cls;
676
677 LOG (GNUNET_ERROR_TYPE_DEBUG,
678 "Received message of type %u and size %u from client\n",
679 ntohs (message->type),
680 ntohs (message->size));
681 GNUNET_assert (GNUNET_NO == client->needs_continue);
682 client->needs_continue = GNUNET_YES;
683 client->warn_type = ntohs (message->type);
684 client->warn_start = GNUNET_TIME_absolute_get ();
685 GNUNET_assert (NULL == client->warn_task);
686 client->warn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
687 &warn_no_client_continue,
688 client);
689 GNUNET_MQ_inject_message (client->mq, message);
690 if (NULL != client->drop_task)
691 return GNUNET_SYSERR;
692 return GNUNET_OK;
693}
694
695
696/**
697 * A client sent us data. Receive and process it. If we are done,
698 * reschedule this task.
699 *
700 * @param cls the `struct GNUNET_SERVICE_Client` that sent us data.
701 */
702static void
703service_client_recv (void *cls)
704{
705 struct GNUNET_SERVICE_Client *client = cls;
706 int ret;
707
708 client->recv_task = NULL;
709 ret = GNUNET_MST_read (client->mst, client->sock, GNUNET_NO, GNUNET_YES);
710 if (GNUNET_SYSERR == ret)
711 {
712 /* client closed connection (or IO error) */
713 if (NULL == client->drop_task)
714 {
715 GNUNET_assert (GNUNET_NO == client->needs_continue);
716 GNUNET_SERVICE_client_drop (client);
717 }
718 return;
719 }
720 if (GNUNET_NO == ret)
721 return; /* more messages in buffer, wait for application
722 to be done processing */
723 GNUNET_assert (GNUNET_OK == ret);
724 if (GNUNET_YES == client->needs_continue)
725 return;
726 if (NULL != client->recv_task)
727 return;
728 /* MST needs more data, re-schedule read job */
729 client->recv_task =
730 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
731 client->sock,
732 &service_client_recv,
733 client);
734}
735
736
737/**
738 * We have successfully accepted a connection from a client. Now
739 * setup the client (with the scheduler) and tell the application.
740 *
741 * @param sh service that accepted the client
742 * @param sock socket associated with the client
743 */
744static void
745start_client (struct GNUNET_SERVICE_Handle *sh,
746 struct GNUNET_NETWORK_Handle *csock)
747{
748 struct GNUNET_SERVICE_Client *client;
749
750 client = GNUNET_new (struct GNUNET_SERVICE_Client);
751 GNUNET_CONTAINER_DLL_insert (sh->clients_head, sh->clients_tail, client);
752 client->sh = sh;
753 client->sock = csock;
754 client->mq = GNUNET_MQ_queue_for_callbacks (&service_mq_send,
755 NULL,
756 &service_mq_cancel,
757 client,
758 sh->handlers,
759 &service_mq_error_handler,
760 client);
761 client->mst = GNUNET_MST_create (&service_client_mst_cb, client);
762 if (NULL != sh->connect_cb)
763 client->user_context = sh->connect_cb (sh->cb_cls, client, client->mq);
764 GNUNET_MQ_set_handlers_closure (client->mq, client->user_context);
765 client->recv_task =
766 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
767 client->sock,
768 &service_client_recv,
769 client);
770}
771
772
773/**
774 * We have a client. Accept the incoming socket(s) (and reschedule
775 * the listen task).
776 *
777 * @param cls the `struct ServiceListenContext` of the ready listen socket
778 */
779static void
780accept_client (void *cls)
781{
782 struct ServiceListenContext *slc = cls;
783 struct GNUNET_SERVICE_Handle *sh = slc->sh;
784
785 slc->listen_task = NULL;
786 while (1)
787 {
788 struct GNUNET_NETWORK_Handle *sock;
789 const struct sockaddr_in *v4;
790 const struct sockaddr_in6 *v6;
791 struct sockaddr_storage sa;
792 socklen_t addrlen;
793 int ok;
794
795 addrlen = sizeof(sa);
796 sock = GNUNET_NETWORK_socket_accept (slc->listen_socket,
797 (struct sockaddr *) &sa,
798 &addrlen);
799 if (NULL == sock)
800 {
801 if (EMFILE == errno)
802 do_suspend (sh, SUSPEND_STATE_EMFILE);
803 else if (EAGAIN != errno)
804 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "accept");
805 break;
806 }
807 switch (sa.ss_family)
808 {
809 case AF_INET:
810 GNUNET_assert (addrlen == sizeof(struct sockaddr_in));
811 v4 = (const struct sockaddr_in *) &sa;
812 ok = (((NULL == sh->v4_allowed) ||
813 (check_ipv4_listed (sh->v4_allowed, &v4->sin_addr))) &&
814 ((NULL == sh->v4_denied) ||
815 (! check_ipv4_listed (sh->v4_denied, &v4->sin_addr))));
816 break;
817
818 case AF_INET6:
819 GNUNET_assert (addrlen == sizeof(struct sockaddr_in6));
820 v6 = (const struct sockaddr_in6 *) &sa;
821 ok = (((NULL == sh->v6_allowed) ||
822 (check_ipv6_listed (sh->v6_allowed, &v6->sin6_addr))) &&
823 ((NULL == sh->v6_denied) ||
824 (! check_ipv6_listed (sh->v6_denied, &v6->sin6_addr))));
825 break;
826
827 case AF_UNIX:
828 ok = GNUNET_OK; /* controlled using file-system ACL now */
829 break;
830
831 default:
832 LOG (GNUNET_ERROR_TYPE_WARNING,
833 _ ("Unknown address family %d\n"),
834 sa.ss_family);
835 return;
836 }
837 if (! ok)
838 {
839 LOG (GNUNET_ERROR_TYPE_DEBUG,
840 "Service rejected incoming connection from %s due to policy.\n",
841 GNUNET_a2s ((const struct sockaddr *) &sa, addrlen));
842 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
843 continue;
844 }
845 LOG (GNUNET_ERROR_TYPE_DEBUG,
846 "Service accepted incoming connection from %s.\n",
847 GNUNET_a2s ((const struct sockaddr *) &sa, addrlen));
848 start_client (slc->sh, sock);
849 }
850 if (0 != sh->suspend_state)
851 return;
852 slc->listen_task =
853 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
854 slc->listen_socket,
855 &accept_client,
856 slc);
857}
858
859
860/**
861 * Resume accepting connections from the listen socket.
862 *
863 * @param sh service to resume accepting connections.
864 * @param sr reason that is no longer causing the suspension,
865 * or #SUSPEND_STATE_NONE on first startup
866 */
867static void
868do_resume (struct GNUNET_SERVICE_Handle *sh, enum SuspendReason sr)
869{
870 struct ServiceListenContext *slc;
871
872 GNUNET_assert ((SUSPEND_STATE_NONE == sr) || (0 != (sh->suspend_state & sr)));
873 sh->suspend_state -= sr;
874 if (SUSPEND_STATE_NONE != sh->suspend_state)
875 return;
876 for (slc = sh->slc_head; NULL != slc; slc = slc->next)
877 {
878 GNUNET_assert (NULL == slc->listen_task);
879 slc->listen_task =
880 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
881 slc->listen_socket,
882 &accept_client,
883 slc);
884 }
885}
886
887
888/**
889 * First task run by any service. Initializes our shutdown task,
890 * starts the listening operation on our listen sockets and launches
891 * the custom logic of the application service.
892 *
893 * @param cls our `struct GNUNET_SERVICE_Handle`
894 */
895static void
896service_main (void *cls)
897{
898 struct GNUNET_SERVICE_Handle *sh = cls;
899
900 if (GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN !=
901 (sh->options & GNUNET_SERVICE_OPTION_SHUTDOWN_BITMASK))
902 GNUNET_SCHEDULER_add_shutdown (&service_shutdown, sh);
903 do_resume (sh, SUSPEND_STATE_NONE);
904
905 if (-1 != sh->ready_confirm_fd)
906 {
907 GNUNET_break (1 == write (sh->ready_confirm_fd, ".", 1));
908 GNUNET_break (0 == close (sh->ready_confirm_fd));
909 sh->ready_confirm_fd = -1;
910 }
911
912 if (NULL != sh->service_init_cb)
913 sh->service_init_cb (sh->cb_cls, sh->cfg, sh);
914}
915
916
917/**
918 * Parse an IPv4 access control list.
919 *
920 * @param ret location where to write the ACL (set)
921 * @param sh service context to use to get the configuration
922 * @param option name of the ACL option to parse
923 * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including
924 * no ACL configured)
925 */
926static int
927process_acl4 (struct GNUNET_STRINGS_IPv4NetworkPolicy **ret,
928 struct GNUNET_SERVICE_Handle *sh,
929 const char *option)
930{
931 char *opt;
932
933 if (! GNUNET_CONFIGURATION_have_value (sh->cfg, sh->service_name, option))
934 {
935 *ret = NULL;
936 return GNUNET_OK;
937 }
938 GNUNET_break (GNUNET_OK ==
939 GNUNET_CONFIGURATION_get_value_string (sh->cfg,
940 sh->service_name,
941 option,
942 &opt));
943 if (NULL == (*ret = GNUNET_STRINGS_parse_ipv4_policy (opt)))
944 {
945 LOG (GNUNET_ERROR_TYPE_WARNING,
946 _ ("Could not parse IPv4 network specification `%s' for `%s:%s'\n"),
947 opt,
948 sh->service_name,
949 option);
950 GNUNET_free (opt);
951 return GNUNET_SYSERR;
952 }
953 GNUNET_free (opt);
954 return GNUNET_OK;
955}
956
957
958/**
959 * Parse an IPv6 access control list.
960 *
961 * @param ret location where to write the ACL (set)
962 * @param sh service context to use to get the configuration
963 * @param option name of the ACL option to parse
964 * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including
965 * no ACL configured)
966 */
967static int
968process_acl6 (struct GNUNET_STRINGS_IPv6NetworkPolicy **ret,
969 struct GNUNET_SERVICE_Handle *sh,
970 const char *option)
971{
972 char *opt;
973
974 if (! GNUNET_CONFIGURATION_have_value (sh->cfg, sh->service_name, option))
975 {
976 *ret = NULL;
977 return GNUNET_OK;
978 }
979 GNUNET_break (GNUNET_OK ==
980 GNUNET_CONFIGURATION_get_value_string (sh->cfg,
981 sh->service_name,
982 option,
983 &opt));
984 if (NULL == (*ret = GNUNET_STRINGS_parse_ipv6_policy (opt)))
985 {
986 LOG (GNUNET_ERROR_TYPE_WARNING,
987 _ ("Could not parse IPv6 network specification `%s' for `%s:%s'\n"),
988 opt,
989 sh->service_name,
990 option);
991 GNUNET_free (opt);
992 return GNUNET_SYSERR;
993 }
994 GNUNET_free (opt);
995 return GNUNET_OK;
996}
997
998
999/**
1000 * Add the given UNIX domain path as an address to the
1001 * list (as the first entry).
1002 *
1003 * @param saddrs array to update
1004 * @param saddrlens where to store the address length
1005 * @param unixpath path to add
1006 */
1007static void
1008add_unixpath (struct sockaddr **saddrs,
1009 socklen_t *saddrlens,
1010 const char *unixpath)
1011{
1012#ifdef AF_UNIX
1013 struct sockaddr_un *un;
1014
1015 un = GNUNET_new (struct sockaddr_un);
1016 un->sun_family = AF_UNIX;
1017 GNUNET_strlcpy (un->sun_path, unixpath, sizeof(un->sun_path));
1018#if HAVE_SOCKADDR_UN_SUN_LEN
1019 un->sun_len = (u_char) sizeof(struct sockaddr_un);
1020#endif
1021 *saddrs = (struct sockaddr *) un;
1022 *saddrlens = sizeof(struct sockaddr_un);
1023#else
1024 /* this function should never be called
1025 * unless AF_UNIX is defined! */
1026 GNUNET_assert (0);
1027#endif
1028}
1029
1030
1031/**
1032 * Get the list of addresses that a server for the given service
1033 * should bind to.
1034 *
1035 * @param service_name name of the service
1036 * @param cfg configuration (which specifies the addresses)
1037 * @param addrs set (call by reference) to an array of pointers to the
1038 * addresses the server should bind to and listen on; the
1039 * array will be NULL-terminated (on success)
1040 * @param addr_lens set (call by reference) to an array of the lengths
1041 * of the respective `struct sockaddr` struct in the @a addrs
1042 * array (on success)
1043 * @return number of addresses found on success,
1044 * #GNUNET_SYSERR if the configuration
1045 * did not specify reasonable finding information or
1046 * if it specified a hostname that could not be resolved;
1047 * #GNUNET_NO if the number of addresses configured is
1048 * zero (in this case, `*addrs` and `*addr_lens` will be
1049 * set to NULL).
1050 */
1051static int
1052get_server_addresses (const char *service_name,
1053 const struct GNUNET_CONFIGURATION_Handle *cfg,
1054 struct sockaddr ***addrs,
1055 socklen_t **addr_lens)
1056{
1057 int disablev6;
1058 struct GNUNET_NETWORK_Handle *desc;
1059 unsigned long long port;
1060 char *unixpath;
1061 struct addrinfo hints;
1062 struct addrinfo *res;
1063 struct addrinfo *pos;
1064 struct addrinfo *next;
1065 unsigned int i;
1066 int resi;
1067 int ret;
1068 struct sockaddr **saddrs;
1069 socklen_t *saddrlens;
1070 char *hostname;
1071
1072 *addrs = NULL;
1073 *addr_lens = NULL;
1074 desc = NULL;
1075 disablev6 = GNUNET_NO;
1076 if ((GNUNET_NO == GNUNET_NETWORK_test_pf (PF_INET6)) ||
1077 (GNUNET_YES ==
1078 GNUNET_CONFIGURATION_get_value_yesno (cfg, service_name, "DISABLEV6")))
1079 disablev6 = GNUNET_YES;
1080
1081 port = 0;
1082 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT"))
1083 {
1084 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg,
1085 service_name,
1086 "PORT",
1087 &port))
1088 {
1089 LOG (GNUNET_ERROR_TYPE_ERROR,
1090 _ ("Require valid port number for service `%s' in configuration!\n"),
1091 service_name);
1092 }
1093 if (port > 65535)
1094 {
1095 LOG (GNUNET_ERROR_TYPE_ERROR,
1096 _ ("Require valid port number for service `%s' in configuration!\n"),
1097 service_name);
1098 return GNUNET_SYSERR;
1099 }
1100 }
1101
1102 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO"))
1103 {
1104 GNUNET_break (GNUNET_OK ==
1105 GNUNET_CONFIGURATION_get_value_string (cfg,
1106 service_name,
1107 "BINDTO",
1108 &hostname));
1109 }
1110 else
1111 hostname = NULL;
1112
1113 unixpath = NULL;
1114#ifdef AF_UNIX
1115 if ((GNUNET_YES ==
1116 GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) &&
1117 (GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg,
1118 service_name,
1119 "UNIXPATH",
1120 &unixpath)) &&
1121 (0 < strlen (unixpath)))
1122 {
1123 /* probe UNIX support */
1124 struct sockaddr_un s_un;
1125
1126 if (strlen (unixpath) >= sizeof(s_un.sun_path))
1127 {
1128 LOG (GNUNET_ERROR_TYPE_WARNING,
1129 _ ("UNIXPATH `%s' too long, maximum length is %llu\n"),
1130 unixpath,
1131 (unsigned long long) sizeof(s_un.sun_path));
1132 unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
1133 LOG (GNUNET_ERROR_TYPE_INFO, _ ("Using `%s' instead\n"), unixpath);
1134 }
1135 if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (unixpath))
1136 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "mkdir", unixpath);
1137 }
1138 if (NULL != unixpath)
1139 {
1140 desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
1141 if (NULL == desc)
1142 {
1143 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
1144 (EACCES == errno))
1145 {
1146 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
1147 GNUNET_free (hostname);
1148 GNUNET_free (unixpath);
1149 return GNUNET_SYSERR;
1150 }
1151 LOG (GNUNET_ERROR_TYPE_INFO,
1152 _ (
1153 "Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"),
1154 service_name,
1155 strerror (errno));
1156 GNUNET_free (unixpath);
1157 unixpath = NULL;
1158 }
1159 else
1160 {
1161 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
1162 desc = NULL;
1163 }
1164 }
1165#endif
1166
1167 if ((0 == port) && (NULL == unixpath))
1168 {
1169 LOG (GNUNET_ERROR_TYPE_ERROR,
1170 _ (
1171 "Have neither PORT nor UNIXPATH for service `%s', but one is required\n"),
1172 service_name);
1173 GNUNET_free (hostname);
1174 return GNUNET_SYSERR;
1175 }
1176 if (0 == port)
1177 {
1178 saddrs = GNUNET_new_array (2, struct sockaddr *);
1179 saddrlens = GNUNET_new_array (2, socklen_t);
1180 add_unixpath (saddrs, saddrlens, unixpath);
1181 GNUNET_free (unixpath);
1182 GNUNET_free (hostname);
1183 *addrs = saddrs;
1184 *addr_lens = saddrlens;
1185 return 1;
1186 }
1187
1188 if (NULL != hostname)
1189 {
1190 LOG (GNUNET_ERROR_TYPE_DEBUG,
1191 "Resolving `%s' since that is where `%s' will bind to.\n",
1192 hostname,
1193 service_name);
1194 memset (&hints, 0, sizeof(struct addrinfo));
1195 if (disablev6)
1196 hints.ai_family = AF_INET;
1197 hints.ai_protocol = IPPROTO_TCP;
1198 if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
1199 (NULL == res))
1200 {
1201 LOG (GNUNET_ERROR_TYPE_ERROR,
1202 _ ("Failed to resolve `%s': %s\n"),
1203 hostname,
1204 gai_strerror (ret));
1205 GNUNET_free (hostname);
1206 GNUNET_free (unixpath);
1207 return GNUNET_SYSERR;
1208 }
1209 next = res;
1210 i = 0;
1211 while (NULL != (pos = next))
1212 {
1213 next = pos->ai_next;
1214 if ((disablev6) && (pos->ai_family == AF_INET6))
1215 continue;
1216 i++;
1217 }
1218 if (0 == i)
1219 {
1220 LOG (GNUNET_ERROR_TYPE_ERROR,
1221 _ ("Failed to find %saddress for `%s'.\n"),
1222 disablev6 ? "IPv4 " : "",
1223 hostname);
1224 freeaddrinfo (res);
1225 GNUNET_free (hostname);
1226 GNUNET_free (unixpath);
1227 return GNUNET_SYSERR;
1228 }
1229 resi = i;
1230 if (NULL != unixpath)
1231 resi++;
1232 saddrs = GNUNET_new_array (resi + 1, struct sockaddr *);
1233 saddrlens = GNUNET_new_array (resi + 1, socklen_t);
1234 i = 0;
1235 if (NULL != unixpath)
1236 {
1237 add_unixpath (saddrs, saddrlens, unixpath);
1238 i++;
1239 }
1240 next = res;
1241 while (NULL != (pos = next))
1242 {
1243 next = pos->ai_next;
1244 if ((disablev6) && (AF_INET6 == pos->ai_family))
1245 continue;
1246 if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol))
1247 continue; /* not TCP */
1248 if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
1249 continue; /* huh? */
1250 LOG (GNUNET_ERROR_TYPE_DEBUG,
1251 "Service `%s' will bind to `%s'\n",
1252 service_name,
1253 GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
1254 if (AF_INET == pos->ai_family)
1255 {
1256 GNUNET_assert (sizeof(struct sockaddr_in) == pos->ai_addrlen);
1257 saddrlens[i] = pos->ai_addrlen;
1258 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1259 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
1260 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1261 }
1262 else
1263 {
1264 GNUNET_assert (AF_INET6 == pos->ai_family);
1265 GNUNET_assert (sizeof(struct sockaddr_in6) == pos->ai_addrlen);
1266 saddrlens[i] = pos->ai_addrlen;
1267 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1268 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
1269 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
1270 }
1271 i++;
1272 }
1273 GNUNET_free (hostname);
1274 freeaddrinfo (res);
1275 resi = i;
1276 }
1277 else
1278 {
1279 /* will bind against everything, just set port */
1280 if (disablev6)
1281 {
1282 /* V4-only */
1283 resi = 1;
1284 if (NULL != unixpath)
1285 resi++;
1286 i = 0;
1287 saddrs = GNUNET_new_array (resi + 1, struct sockaddr *);
1288 saddrlens = GNUNET_new_array (resi + 1, socklen_t);
1289 if (NULL != unixpath)
1290 {
1291 add_unixpath (saddrs, saddrlens, unixpath);
1292 i++;
1293 }
1294 saddrlens[i] = sizeof(struct sockaddr_in);
1295 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1296#if HAVE_SOCKADDR_IN_SIN_LEN
1297 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
1298#endif
1299 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
1300 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1301 }
1302 else
1303 {
1304 /* dual stack */
1305 resi = 2;
1306 if (NULL != unixpath)
1307 resi++;
1308 saddrs = GNUNET_new_array (resi + 1, struct sockaddr *);
1309 saddrlens = GNUNET_new_array (resi + 1, socklen_t);
1310 i = 0;
1311 if (NULL != unixpath)
1312 {
1313 add_unixpath (saddrs, saddrlens, unixpath);
1314 i++;
1315 }
1316 saddrlens[i] = sizeof(struct sockaddr_in6);
1317 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1318#if HAVE_SOCKADDR_IN_SIN_LEN
1319 ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
1320#endif
1321 ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
1322 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
1323 i++;
1324 saddrlens[i] = sizeof(struct sockaddr_in);
1325 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1326#if HAVE_SOCKADDR_IN_SIN_LEN
1327 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
1328#endif
1329 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
1330 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1331 }
1332 }
1333 GNUNET_free (unixpath);
1334 *addrs = saddrs;
1335 *addr_lens = saddrlens;
1336 return resi;
1337}
1338
1339
1340/**
1341 * Create and initialize a listen socket for the server.
1342 *
1343 * @param server_addr address to listen on
1344 * @param socklen length of @a server_addr
1345 * @return NULL on error, otherwise the listen socket
1346 */
1347static struct GNUNET_NETWORK_Handle *
1348open_listen_socket (const struct sockaddr *server_addr,
1349 socklen_t socklen)
1350{
1351 struct GNUNET_NETWORK_Handle *sock;
1352 uint16_t port;
1353 int eno;
1354
1355 switch (server_addr->sa_family)
1356 {
1357 case AF_INET:
1358 port = ntohs (((const struct sockaddr_in *) server_addr)->sin_port);
1359 break;
1360 case AF_INET6:
1361 port = ntohs (((const struct sockaddr_in6 *) server_addr)->sin6_port);
1362 break;
1363 case AF_UNIX:
1364 port = 0;
1365 break;
1366 default:
1367 GNUNET_break (0);
1368 port = 0;
1369 break;
1370 }
1371 sock = GNUNET_NETWORK_socket_create (server_addr->sa_family,
1372 SOCK_STREAM,
1373 0);
1374 if (NULL == sock)
1375 {
1376 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
1377 "socket");
1378 errno = 0;
1379 return NULL;
1380 }
1381 /* bind the socket */
1382 if (GNUNET_OK !=
1383 GNUNET_NETWORK_socket_bind (sock,
1384 server_addr,
1385 socklen))
1386 {
1387 eno = errno;
1388 if (EADDRINUSE != errno)
1389 {
1390 /* we don't log 'EADDRINUSE' here since an IPv4 bind may
1391 * fail if we already took the port on IPv6; if both IPv4 and
1392 * IPv6 binds fail, then our caller will log using the
1393 * errno preserved in 'eno' */
1394 if (0 != port)
1395 LOG (GNUNET_ERROR_TYPE_ERROR,
1396 _ ("`%s' failed for port %d (%s).\n"),
1397 "bind",
1398 port,
1399 (AF_INET == server_addr->sa_family) ? "IPv4" : "IPv6");
1400 else
1401 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "bind");
1402 eno = 0;
1403 }
1404 else
1405 {
1406 if (0 != port)
1407 LOG (GNUNET_ERROR_TYPE_WARNING,
1408 _ ("`%s' failed for port %d (%s): address already in use\n"),
1409 "bind",
1410 port,
1411 (AF_INET == server_addr->sa_family) ? "IPv4" : "IPv6");
1412 else if (AF_UNIX == server_addr->sa_family)
1413 {
1414 LOG (GNUNET_ERROR_TYPE_WARNING,
1415 _ ("`%s' failed for `%s': address already in use\n"),
1416 "bind",
1417 GNUNET_a2s (server_addr, socklen));
1418 }
1419 }
1420 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
1421 errno = eno;
1422 return NULL;
1423 }
1424 if (GNUNET_OK != GNUNET_NETWORK_socket_listen (sock, 5))
1425 {
1426 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "listen");
1427 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
1428 errno = 0;
1429 return NULL;
1430 }
1431 if (0 != port)
1432 LOG (GNUNET_ERROR_TYPE_DEBUG,
1433 "Server starts to listen on port %u.\n",
1434 port);
1435 return sock;
1436}
1437
1438
1439/**
1440 * Setup service handle
1441 *
1442 * Configuration may specify:
1443 * - PORT (where to bind to for TCP)
1444 * - UNIXPATH (where to bind to for UNIX domain sockets)
1445 * - DISABLEV6 (disable support for IPv6, otherwise we use dual-stack)
1446 * - BINDTO (hostname or IP address to bind to, otherwise we take everything)
1447 * - ACCEPT_FROM (only allow connections from specified IPv4 subnets)
1448 * - ACCEPT_FROM6 (only allow connections from specified IPv6 subnets)
1449 * - REJECT_FROM (disallow allow connections from specified IPv4 subnets)
1450 * - REJECT_FROM6 (disallow allow connections from specified IPv6 subnets)
1451 *
1452 * @param sh service context to initialize
1453 * @return #GNUNET_OK if configuration succeeded
1454 */
1455static int
1456setup_service (struct GNUNET_SERVICE_Handle *sh)
1457{
1458 int tolerant;
1459 struct GNUNET_NETWORK_Handle **csocks = NULL;
1460 struct GNUNET_NETWORK_Handle **lsocks;
1461 const char *nfds;
1462 unsigned int cnt;
1463 int flags;
1464 char dummy[2];
1465
1466 if (GNUNET_CONFIGURATION_have_value (sh->cfg,
1467 sh->service_name,
1468 "TOLERANT"))
1469 {
1470 if (GNUNET_SYSERR ==
1471 (tolerant = GNUNET_CONFIGURATION_get_value_yesno (sh->cfg,
1472 sh->service_name,
1473 "TOLERANT")))
1474 {
1475 LOG (GNUNET_ERROR_TYPE_ERROR,
1476 _ ("Specified value for `%s' of service `%s' is invalid\n"),
1477 "TOLERANT",
1478 sh->service_name);
1479 return GNUNET_SYSERR;
1480 }
1481 }
1482 else
1483 tolerant = GNUNET_NO;
1484
1485 lsocks = NULL;
1486 errno = 0;
1487 if ((NULL != (nfds = getenv ("LISTEN_FDS"))) &&
1488 (1 == sscanf (nfds, "%u%1s", &cnt, dummy)) && (cnt > 0) &&
1489 (cnt < FD_SETSIZE) && (cnt + 4 < FD_SETSIZE))
1490 {
1491 lsocks = GNUNET_new_array (cnt + 1, struct GNUNET_NETWORK_Handle *);
1492 while (0 < cnt--)
1493 {
1494 flags = fcntl (3 + cnt, F_GETFD);
1495 if ((flags < 0) || (0 != (flags & FD_CLOEXEC)) ||
1496 (NULL == (lsocks[cnt] = GNUNET_NETWORK_socket_box_native (3 + cnt))))
1497 {
1498 LOG (GNUNET_ERROR_TYPE_ERROR,
1499 _ (
1500 "Could not access pre-bound socket %u, will try to bind myself\n"),
1501 (unsigned int) 3 + cnt);
1502 cnt++;
1503 while (NULL != lsocks[cnt])
1504 GNUNET_break (GNUNET_OK ==
1505 GNUNET_NETWORK_socket_close (lsocks[cnt++]));
1506 GNUNET_free (lsocks);
1507 lsocks = NULL;
1508 break;
1509 }
1510 }
1511 unsetenv ("LISTEN_FDS");
1512 }
1513 if ( (0 != (GNUNET_SERVICE_OPTION_CLOSE_LSOCKS & sh->options)) &&
1514 (NULL != lsocks) )
1515 {
1516 csocks = lsocks;
1517 lsocks = NULL;
1518 }
1519
1520 if (NULL != lsocks)
1521 {
1522 /* listen only on inherited sockets if we have any */
1523 for (struct GNUNET_NETWORK_Handle **ls = lsocks; NULL != *ls; ls++)
1524 {
1525 struct ServiceListenContext *slc;
1526
1527 slc = GNUNET_new (struct ServiceListenContext);
1528 slc->sh = sh;
1529 slc->listen_socket = *ls;
1530 GNUNET_CONTAINER_DLL_insert (sh->slc_head, sh->slc_tail, slc);
1531 }
1532 GNUNET_free (lsocks);
1533 }
1534 else
1535 {
1536 struct sockaddr **addrs;
1537 socklen_t *addrlens;
1538 int num;
1539
1540 num = get_server_addresses (sh->service_name, sh->cfg, &addrs, &addrlens);
1541 if (GNUNET_SYSERR == num)
1542 return GNUNET_SYSERR;
1543
1544 for (int i = 0; i < num; i++)
1545 {
1546 struct ServiceListenContext *slc;
1547
1548 slc = GNUNET_new (struct ServiceListenContext);
1549 slc->sh = sh;
1550 slc->listen_socket = open_listen_socket (addrs[i], addrlens[i]);
1551 GNUNET_free (addrs[i]);
1552 if (NULL == slc->listen_socket)
1553 {
1554 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
1555 GNUNET_free (slc);
1556 continue;
1557 }
1558 GNUNET_CONTAINER_DLL_insert (sh->slc_head, sh->slc_tail, slc);
1559 }
1560 GNUNET_free (addrlens);
1561 GNUNET_free (addrs);
1562 if ((0 != num) && (NULL == sh->slc_head))
1563 {
1564 /* All attempts to bind failed, hard failure */
1565 GNUNET_log (
1566 GNUNET_ERROR_TYPE_ERROR,
1567 _ (
1568 "Could not bind to any of the ports I was supposed to, refusing to run!\n"));
1569 GNUNET_free (csocks);
1570 return GNUNET_SYSERR;
1571 }
1572 }
1573 if (NULL != csocks)
1574 {
1575 /* close inherited sockets to signal parent that we are ready */
1576 for (struct GNUNET_NETWORK_Handle **ls = csocks; NULL != *ls; ls++)
1577 GNUNET_NETWORK_socket_close (*ls);
1578 GNUNET_free (csocks);
1579 }
1580 sh->require_found = tolerant ? GNUNET_NO : GNUNET_YES;
1581 sh->match_uid = GNUNET_CONFIGURATION_get_value_yesno (sh->cfg,
1582 sh->service_name,
1583 "UNIX_MATCH_UID");
1584 sh->match_gid = GNUNET_CONFIGURATION_get_value_yesno (sh->cfg,
1585 sh->service_name,
1586 "UNIX_MATCH_GID");
1587 process_acl4 (&sh->v4_denied, sh, "REJECT_FROM");
1588 process_acl4 (&sh->v4_allowed, sh, "ACCEPT_FROM");
1589 process_acl6 (&sh->v6_denied, sh, "REJECT_FROM6");
1590 process_acl6 (&sh->v6_allowed, sh, "ACCEPT_FROM6");
1591 return GNUNET_OK;
1592}
1593
1594
1595/**
1596 * Get the name of the user that'll be used
1597 * to provide the service.
1598 *
1599 * @param sh service context
1600 * @return value of the 'USERNAME' option
1601 */
1602static char *
1603get_user_name (struct GNUNET_SERVICE_Handle *sh)
1604{
1605 char *un;
1606
1607 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (sh->cfg,
1608 sh->service_name,
1609 "USERNAME",
1610 &un))
1611 return NULL;
1612 return un;
1613}
1614
1615
1616/**
1617 * Set user ID.
1618 *
1619 * @param sh service context
1620 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1621 */
1622static int
1623set_user_id (struct GNUNET_SERVICE_Handle *sh)
1624{
1625 char *user;
1626
1627 if (NULL == (user = get_user_name (sh)))
1628 return GNUNET_OK; /* keep */
1629
1630 struct passwd *pws;
1631
1632 errno = 0;
1633 pws = getpwnam (user);
1634 if (NULL == pws)
1635 {
1636 LOG (GNUNET_ERROR_TYPE_ERROR,
1637 _ ("Cannot obtain information about user `%s': %s\n"),
1638 user,
1639 errno == 0 ? _ ("No such user") : strerror (errno));
1640 GNUNET_free (user);
1641 return GNUNET_SYSERR;
1642 }
1643 if ((0 != setgid (pws->pw_gid)) || (0 != setegid (pws->pw_gid)) ||
1644#if HAVE_INITGROUPS
1645 (0 != initgroups (user, pws->pw_gid)) ||
1646#endif
1647 (0 != setuid (pws->pw_uid)) || (0 != seteuid (pws->pw_uid)))
1648 {
1649 if ((0 != setregid (pws->pw_gid, pws->pw_gid)) ||
1650 (0 != setreuid (pws->pw_uid, pws->pw_uid)))
1651 {
1652 LOG (GNUNET_ERROR_TYPE_ERROR,
1653 _ ("Cannot change user/group to `%s': %s\n"),
1654 user,
1655 strerror (errno));
1656 GNUNET_free (user);
1657 return GNUNET_SYSERR;
1658 }
1659 }
1660
1661 GNUNET_free (user);
1662 return GNUNET_OK;
1663}
1664
1665
1666/**
1667 * Get the name of the file where we will
1668 * write the PID of the service.
1669 *
1670 * @param sh service context
1671 * @return name of the file for the process ID
1672 */
1673static char *
1674get_pid_file_name (struct GNUNET_SERVICE_Handle *sh)
1675{
1676 char *pif;
1677
1678 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (sh->cfg,
1679 sh->service_name,
1680 "PIDFILE",
1681 &pif))
1682 return NULL;
1683 return pif;
1684}
1685
1686
1687/**
1688 * Delete the PID file that was created by our parent.
1689 *
1690 * @param sh service context
1691 */
1692static void
1693pid_file_delete (struct GNUNET_SERVICE_Handle *sh)
1694{
1695 char *pif = get_pid_file_name (sh);
1696
1697 if (NULL == pif)
1698 return; /* no PID file */
1699 if (0 != unlink (pif))
1700 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", pif);
1701 GNUNET_free (pif);
1702}
1703
1704
1705/**
1706 * Detach from terminal.
1707 *
1708 * @param sh service context
1709 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1710 */
1711static int
1712detach_terminal (struct GNUNET_SERVICE_Handle *sh)
1713{
1714 pid_t pid;
1715 int nullfd;
1716 int filedes[2];
1717
1718 if (0 != pipe (filedes))
1719 {
1720 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "pipe");
1721 return GNUNET_SYSERR;
1722 }
1723 pid = fork ();
1724 if (pid < 0)
1725 {
1726 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork");
1727 return GNUNET_SYSERR;
1728 }
1729 if (0 != pid)
1730 {
1731 /* Parent */
1732 char c;
1733
1734 GNUNET_break (0 == close (filedes[1]));
1735 c = 'X';
1736 if (1 != read (filedes[0], &c, sizeof(char)))
1737 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "read");
1738 fflush (stdout);
1739 switch (c)
1740 {
1741 case '.':
1742 exit (0);
1743
1744 case 'I':
1745 LOG (GNUNET_ERROR_TYPE_INFO,
1746 _ ("Service process failed to initialize\n"));
1747 break;
1748
1749 case 'S':
1750 LOG (GNUNET_ERROR_TYPE_INFO,
1751 _ ("Service process could not initialize server function\n"));
1752 break;
1753
1754 case 'X':
1755 LOG (GNUNET_ERROR_TYPE_INFO,
1756 _ ("Service process failed to report status\n"));
1757 break;
1758 }
1759 exit (1); /* child reported error */
1760 }
1761 GNUNET_break (0 == close (0));
1762 GNUNET_break (0 == close (1));
1763 GNUNET_break (0 == close (filedes[0]));
1764 nullfd = open ("/dev/null", O_RDWR | O_APPEND);
1765 if (nullfd < 0)
1766 return GNUNET_SYSERR;
1767 /* set stdin/stdout to /dev/null */
1768 if ((dup2 (nullfd, 0) < 0) || (dup2 (nullfd, 1) < 0))
1769 {
1770 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2");
1771 (void) close (nullfd);
1772 return GNUNET_SYSERR;
1773 }
1774 (void) close (nullfd);
1775 /* Detach from controlling terminal */
1776 pid = setsid ();
1777 if (-1 == pid)
1778 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "setsid");
1779 sh->ready_confirm_fd = filedes[1];
1780
1781 return GNUNET_OK;
1782}
1783
1784
1785/**
1786 * Tear down the service, closing the listen sockets and
1787 * freeing the ACLs.
1788 *
1789 * @param sh handle to the service to tear down.
1790 */
1791static void
1792teardown_service (struct GNUNET_SERVICE_Handle *sh)
1793{
1794 struct ServiceListenContext *slc;
1795
1796 GNUNET_free (sh->v4_denied);
1797 GNUNET_free (sh->v6_denied);
1798 GNUNET_free (sh->v4_allowed);
1799 GNUNET_free (sh->v6_allowed);
1800 while (NULL != (slc = sh->slc_head))
1801 {
1802 GNUNET_CONTAINER_DLL_remove (sh->slc_head, sh->slc_tail, slc);
1803 if (NULL != slc->listen_task)
1804 GNUNET_SCHEDULER_cancel (slc->listen_task);
1805 GNUNET_break (GNUNET_OK ==
1806 GNUNET_NETWORK_socket_close (slc->listen_socket));
1807 GNUNET_free (slc);
1808 }
1809}
1810
1811
1812/**
1813 * Function to return link to AGPL source upon request.
1814 *
1815 * @param cls closure with the identification of the client
1816 * @param msg AGPL request
1817 */
1818static void
1819return_agpl (void *cls, const struct GNUNET_MessageHeader *msg)
1820{
1821 struct GNUNET_SERVICE_Client *client = cls;
1822 struct GNUNET_MQ_Handle *mq;
1823 struct GNUNET_MQ_Envelope *env;
1824 struct GNUNET_MessageHeader *res;
1825 size_t slen;
1826 const struct GNUNET_OS_ProjectData *pd = GNUNET_OS_project_data_get ();
1827
1828 (void) msg;
1829 slen = strlen (pd->agpl_url) + 1;
1830 env = GNUNET_MQ_msg_extra (res, GNUNET_MESSAGE_TYPE_RESPONSE_AGPL, slen);
1831 memcpy (&res[1], GNUNET_AGPL_URL, slen);
1832 mq = GNUNET_SERVICE_client_get_mq (client);
1833 GNUNET_MQ_send (mq, env);
1834 GNUNET_SERVICE_client_continue (client);
1835}
1836
1837
1838/**
1839 * Low-level function to start a service if the scheduler
1840 * is already running. Should only be used directly in
1841 * special cases.
1842 *
1843 * The function will launch the service with the name @a service_name
1844 * using the @a service_options to configure its shutdown
1845 * behavior. When clients connect or disconnect, the respective
1846 * @a connect_cb or @a disconnect_cb functions will be called. For
1847 * messages received from the clients, the respective @a handlers will
1848 * be invoked; for the closure of the handlers we use the return value
1849 * from the @a connect_cb invocation of the respective client.
1850 *
1851 * Each handler MUST call #GNUNET_SERVICE_client_continue() after each
1852 * message to receive further messages from this client. If
1853 * #GNUNET_SERVICE_client_continue() is not called within a short
1854 * time, a warning will be logged. If delays are expected, services
1855 * should call #GNUNET_SERVICE_client_disable_continue_warning() to
1856 * disable the warning.
1857 *
1858 * Clients sending invalid messages (based on @a handlers) will be
1859 * dropped. Additionally, clients can be dropped at any time using
1860 * #GNUNET_SERVICE_client_drop().
1861 *
1862 * The service must be stopped using #GNUNET_SERVICE_stop().
1863 *
1864 * @param service_name name of the service to run
1865 * @param cfg configuration to use
1866 * @param connect_cb function to call whenever a client connects
1867 * @param disconnect_cb function to call whenever a client disconnects
1868 * @param cls closure argument for @a connect_cb and @a disconnect_cb
1869 * @param handlers NULL-terminated array of message handlers for the service,
1870 * the closure will be set to the value returned by
1871 * the @a connect_cb for the respective connection
1872 * @return NULL on error
1873 */
1874struct GNUNET_SERVICE_Handle *
1875GNUNET_SERVICE_start (const char *service_name,
1876 const struct GNUNET_CONFIGURATION_Handle *cfg,
1877 GNUNET_SERVICE_ConnectHandler connect_cb,
1878 GNUNET_SERVICE_DisconnectHandler disconnect_cb,
1879 void *cls,
1880 const struct GNUNET_MQ_MessageHandler *handlers)
1881{
1882 struct GNUNET_SERVICE_Handle *sh;
1883
1884 sh = GNUNET_new (struct GNUNET_SERVICE_Handle);
1885 sh->service_name = service_name;
1886 sh->cfg = cfg;
1887 sh->connect_cb = connect_cb;
1888 sh->disconnect_cb = disconnect_cb;
1889 sh->cb_cls = cls;
1890 sh->handlers = GNUNET_MQ_copy_handlers2 (handlers, &return_agpl, NULL);
1891 if (GNUNET_OK != setup_service (sh))
1892 {
1893 GNUNET_free (sh->handlers);
1894 GNUNET_free (sh);
1895 return NULL;
1896 }
1897 do_resume (sh, SUSPEND_STATE_NONE);
1898 return sh;
1899}
1900
1901
1902/**
1903 * Stops a service that was started with #GNUNET_SERVICE_start().
1904 *
1905 * @param srv service to stop
1906 */
1907void
1908GNUNET_SERVICE_stop (struct GNUNET_SERVICE_Handle *srv)
1909{
1910 struct GNUNET_SERVICE_Client *client;
1911
1912 GNUNET_SERVICE_suspend (srv);
1913 while (NULL != (client = srv->clients_head))
1914 GNUNET_SERVICE_client_drop (client);
1915 teardown_service (srv);
1916 GNUNET_free (srv->handlers);
1917 GNUNET_free (srv);
1918}
1919
1920
1921/**
1922 * Creates the "main" function for a GNUnet service. You
1923 * should almost always use the #GNUNET_SERVICE_MAIN macro
1924 * instead of calling this function directly (except
1925 * for ARM, which should call this function directly).
1926 *
1927 * The function will launch the service with the name @a service_name
1928 * using the @a service_options to configure its shutdown
1929 * behavior. Once the service is ready, the @a init_cb will be called
1930 * for service-specific initialization. @a init_cb will be given the
1931 * service handler which can be used to control the service's
1932 * availability. When clients connect or disconnect, the respective
1933 * @a connect_cb or @a disconnect_cb functions will be called. For
1934 * messages received from the clients, the respective @a handlers will
1935 * be invoked; for the closure of the handlers we use the return value
1936 * from the @a connect_cb invocation of the respective client.
1937 *
1938 * Each handler MUST call #GNUNET_SERVICE_client_continue() after each
1939 * message to receive further messages from this client. If
1940 * #GNUNET_SERVICE_client_continue() is not called within a short
1941 * time, a warning will be logged. If delays are expected, services
1942 * should call #GNUNET_SERVICE_client_disable_continue_warning() to
1943 * disable the warning.
1944 *
1945 * Clients sending invalid messages (based on @a handlers) will be
1946 * dropped. Additionally, clients can be dropped at any time using
1947 * #GNUNET_SERVICE_client_drop().
1948 *
1949 * @param argc number of command-line arguments in @a argv
1950 * @param argv array of command-line arguments
1951 * @param service_name name of the service to run
1952 * @param options options controlling shutdown of the service
1953 * @param service_init_cb function to call once the service is ready
1954 * @param connect_cb function to call whenever a client connects
1955 * @param disconnect_cb function to call whenever a client disconnects
1956 * @param cls closure argument for @a service_init_cb, @a connect_cb and @a disconnect_cb
1957 * @param handlers NULL-terminated array of message handlers for the service,
1958 * the closure will be set to the value returned by
1959 * the @a connect_cb for the respective connection
1960 * @return 0 on success, non-zero on error
1961 */
1962int
1963GNUNET_SERVICE_run_ (int argc,
1964 char *const *argv,
1965 const char *service_name,
1966 enum GNUNET_SERVICE_Options options,
1967 GNUNET_SERVICE_InitCallback service_init_cb,
1968 GNUNET_SERVICE_ConnectHandler connect_cb,
1969 GNUNET_SERVICE_DisconnectHandler disconnect_cb,
1970 void *cls,
1971 const struct GNUNET_MQ_MessageHandler *handlers)
1972{
1973 struct GNUNET_SERVICE_Handle sh;
1974
1975#if ENABLE_NLS
1976 char *path;
1977#endif
1978 char *cfg_filename;
1979 char *opt_cfg_filename;
1980 char *loglev;
1981 const char *xdg;
1982 char *logfile;
1983 int do_daemonize;
1984 unsigned long long skew_offset;
1985 unsigned long long skew_variance;
1986 long long clock_offset;
1987 struct GNUNET_CONFIGURATION_Handle *cfg;
1988 int ret;
1989 int err;
1990 const struct GNUNET_OS_ProjectData *pd = GNUNET_OS_project_data_get ();
1991 struct GNUNET_GETOPT_CommandLineOption service_options[] = {
1992 GNUNET_GETOPT_option_cfgfile (&opt_cfg_filename),
1993 GNUNET_GETOPT_option_flag ('d',
1994 "daemonize",
1995 gettext_noop (
1996 "do daemonize (detach from terminal)"),
1997 &do_daemonize),
1998 GNUNET_GETOPT_option_help (NULL),
1999 GNUNET_GETOPT_option_loglevel (&loglev),
2000 GNUNET_GETOPT_option_logfile (&logfile),
2001 GNUNET_GETOPT_option_version (pd->version),
2002 GNUNET_GETOPT_OPTION_END
2003 };
2004
2005 err = 1;
2006 memset (&sh, 0, sizeof(sh));
2007 xdg = getenv ("XDG_CONFIG_HOME");
2008 if (NULL != xdg)
2009 GNUNET_asprintf (&cfg_filename,
2010 "%s%s%s",
2011 xdg,
2012 DIR_SEPARATOR_STR,
2013 pd->config_file);
2014 else
2015 cfg_filename = GNUNET_strdup (pd->user_config_file);
2016 sh.ready_confirm_fd = -1;
2017 sh.options = options;
2018 sh.cfg = cfg = GNUNET_CONFIGURATION_create ();
2019 sh.service_init_cb = service_init_cb;
2020 sh.connect_cb = connect_cb;
2021 sh.disconnect_cb = disconnect_cb;
2022 sh.cb_cls = cls;
2023 sh.handlers = (NULL == pd->agpl_url)
2024 ? GNUNET_MQ_copy_handlers (handlers)
2025 : GNUNET_MQ_copy_handlers2 (handlers, &return_agpl, NULL);
2026 sh.service_name = service_name;
2027 sh.ret = 0;
2028 /* setup subsystems */
2029 loglev = NULL;
2030 logfile = NULL;
2031 opt_cfg_filename = NULL;
2032 do_daemonize = 0;
2033#if ENABLE_NLS
2034 if (NULL != pd->gettext_domain)
2035 {
2036 setlocale (LC_ALL, "");
2037 path = (NULL == pd->gettext_path) ?
2038 GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LOCALEDIR) :
2039 GNUNET_strdup (pd->gettext_path);
2040 if (NULL != path)
2041 {
2042 bindtextdomain (pd->gettext_domain, path);
2043 GNUNET_free (path);
2044 }
2045 textdomain (pd->gettext_domain);
2046 }
2047#endif
2048 ret = GNUNET_GETOPT_run (service_name,
2049 service_options,
2050 argc,
2051 argv);
2052 if (GNUNET_SYSERR == ret)
2053 goto shutdown;
2054 if (GNUNET_NO == ret)
2055 {
2056 err = 0;
2057 goto shutdown;
2058 }
2059 if (GNUNET_OK != GNUNET_log_setup (service_name,
2060 loglev,
2061 logfile))
2062 {
2063 GNUNET_break (0);
2064 goto shutdown;
2065 }
2066 if (NULL != opt_cfg_filename)
2067 {
2068 if ((GNUNET_YES != GNUNET_DISK_file_test (opt_cfg_filename)) ||
2069 (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, opt_cfg_filename)))
2070 {
2071 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2072 _ ("Malformed configuration file `%s', exit ...\n"),
2073 opt_cfg_filename);
2074 goto shutdown;
2075 }
2076 }
2077 else
2078 {
2079 if (GNUNET_YES == GNUNET_DISK_file_test (cfg_filename))
2080 {
2081 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, cfg_filename))
2082 {
2083 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2084 _ ("Malformed configuration file `%s', exit ...\n"),
2085 cfg_filename);
2086 goto shutdown;
2087 }
2088 }
2089 else
2090 {
2091 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, NULL))
2092 {
2093 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2094 _ ("Malformed configuration, exit ...\n"));
2095 goto shutdown;
2096 }
2097 }
2098 }
2099 if (GNUNET_OK != setup_service (&sh))
2100 goto shutdown;
2101 if ((1 == do_daemonize) && (GNUNET_OK != detach_terminal (&sh)))
2102 {
2103 GNUNET_break (0);
2104 goto shutdown;
2105 }
2106 if (GNUNET_OK != set_user_id (&sh))
2107 goto shutdown;
2108 LOG (GNUNET_ERROR_TYPE_DEBUG,
2109 "Service `%s' runs with configuration from `%s'\n",
2110 service_name,
2111 (NULL != opt_cfg_filename) ? opt_cfg_filename : cfg_filename);
2112 if ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (sh.cfg,
2113 "TESTING",
2114 "SKEW_OFFSET",
2115 &skew_offset)) &&
2116 (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (sh.cfg,
2117 "TESTING",
2118 "SKEW_VARIANCE",
2119 &skew_variance)))
2120 {
2121 clock_offset = skew_offset - skew_variance;
2122 GNUNET_TIME_set_offset (clock_offset);
2123 LOG (GNUNET_ERROR_TYPE_DEBUG,
2124 "Skewing clock by %lld ms\n",
2125 (long long) clock_offset);
2126 }
2127 GNUNET_RESOLVER_connect (sh.cfg);
2128
2129 /* actually run service */
2130 err = 0;
2131 GNUNET_SCHEDULER_run (&service_main, &sh);
2132 /* shutdown */
2133 if (1 == do_daemonize)
2134 pid_file_delete (&sh);
2135
2136shutdown:
2137 if (-1 != sh.ready_confirm_fd)
2138 {
2139 if (1 != write (sh.ready_confirm_fd, err ? "I" : "S", 1))
2140 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "write");
2141 GNUNET_break (0 == close (sh.ready_confirm_fd));
2142 }
2143#if HAVE_MALLINFO2
2144 {
2145 char *counter;
2146
2147 if ((GNUNET_YES == GNUNET_CONFIGURATION_have_value (sh.cfg,
2148 service_name,
2149 "GAUGER_HEAP")) &&
2150 (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (sh.cfg,
2151 service_name,
2152 "GAUGER_HEAP",
2153 &counter)))
2154 {
2155 struct mallinfo2 mi;
2156
2157 mi = mallinfo2 ();
2158 GAUGER (service_name, counter, mi.usmblks, "blocks");
2159 GNUNET_free (counter);
2160 }
2161 }
2162#endif
2163 teardown_service (&sh);
2164 GNUNET_free (sh.handlers);
2165 GNUNET_SPEEDUP_stop_ ();
2166 GNUNET_CONFIGURATION_destroy (cfg);
2167 GNUNET_free (logfile);
2168 GNUNET_free (loglev);
2169 GNUNET_free (cfg_filename);
2170 GNUNET_free (opt_cfg_filename);
2171
2172 return err ? GNUNET_SYSERR : sh.ret;
2173}
2174
2175
2176/**
2177 * Suspend accepting connections from the listen socket temporarily.
2178 * Resume activity using #GNUNET_SERVICE_resume.
2179 *
2180 * @param sh service to stop accepting connections.
2181 */
2182void
2183GNUNET_SERVICE_suspend (struct GNUNET_SERVICE_Handle *sh)
2184{
2185 do_suspend (sh, SUSPEND_STATE_APP);
2186}
2187
2188
2189/**
2190 * Resume accepting connections from the listen socket.
2191 *
2192 * @param sh service to resume accepting connections.
2193 */
2194void
2195GNUNET_SERVICE_resume (struct GNUNET_SERVICE_Handle *sh)
2196{
2197 do_resume (sh, SUSPEND_STATE_APP);
2198}
2199
2200
2201/**
2202 * Task run to resume receiving data from the client after
2203 * the client called #GNUNET_SERVICE_client_continue().
2204 *
2205 * @param cls our `struct GNUNET_SERVICE_Client`
2206 */
2207static void
2208resume_client_receive (void *cls)
2209{
2210 struct GNUNET_SERVICE_Client *c = cls;
2211 int ret;
2212
2213 c->recv_task = NULL;
2214 /* first, check if there is still something in the buffer */
2215 ret = GNUNET_MST_next (c->mst, GNUNET_YES);
2216 if (GNUNET_SYSERR == ret)
2217 {
2218 if (NULL == c->drop_task)
2219 GNUNET_SERVICE_client_drop (c);
2220 return;
2221 }
2222 if (GNUNET_NO == ret)
2223 return; /* done processing, wait for more later */
2224 GNUNET_assert (GNUNET_OK == ret);
2225 if (GNUNET_YES == c->needs_continue)
2226 return; /* #GNUNET_MST_next() did give a message to the client */
2227 /* need to receive more data from the network first */
2228 if (NULL != c->recv_task)
2229 return;
2230 c->recv_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
2231 c->sock,
2232 &service_client_recv,
2233 c);
2234}
2235
2236
2237/**
2238 * Continue receiving further messages from the given client.
2239 * Must be called after each message received.
2240 *
2241 * @param c the client to continue receiving from
2242 */
2243void
2244GNUNET_SERVICE_client_continue (struct GNUNET_SERVICE_Client *c)
2245{
2246 GNUNET_assert (NULL == c->drop_task);
2247 GNUNET_assert (GNUNET_YES == c->needs_continue);
2248 GNUNET_assert (NULL == c->recv_task);
2249 c->needs_continue = GNUNET_NO;
2250 if (NULL != c->warn_task)
2251 {
2252 GNUNET_SCHEDULER_cancel (c->warn_task);
2253 c->warn_task = NULL;
2254 }
2255 c->recv_task = GNUNET_SCHEDULER_add_now (&resume_client_receive, c);
2256}
2257
2258
2259/**
2260 * Disable the warning the server issues if a message is not
2261 * acknowledged in a timely fashion. Use this call if a client is
2262 * intentionally delayed for a while. Only applies to the current
2263 * message.
2264 *
2265 * @param c client for which to disable the warning
2266 */
2267void
2268GNUNET_SERVICE_client_disable_continue_warning (struct GNUNET_SERVICE_Client *c)
2269{
2270 GNUNET_break (NULL != c->warn_task);
2271 if (NULL != c->warn_task)
2272 {
2273 GNUNET_SCHEDULER_cancel (c->warn_task);
2274 c->warn_task = NULL;
2275 }
2276}
2277
2278
2279/**
2280 * Asynchronously finish dropping the client.
2281 *
2282 * @param cls the `struct GNUNET_SERVICE_Client`.
2283 */
2284static void
2285finish_client_drop (void *cls)
2286{
2287 struct GNUNET_SERVICE_Client *c = cls;
2288 struct GNUNET_SERVICE_Handle *sh = c->sh;
2289
2290 c->drop_task = NULL;
2291 GNUNET_assert (NULL == c->send_task);
2292 GNUNET_assert (NULL == c->recv_task);
2293 GNUNET_assert (NULL == c->warn_task);
2294 GNUNET_MST_destroy (c->mst);
2295 GNUNET_MQ_destroy (c->mq);
2296 if (GNUNET_NO == c->persist)
2297 {
2298 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (c->sock));
2299 if ((0 != (SUSPEND_STATE_EMFILE & sh->suspend_state)) &&
2300 (0 == (SUSPEND_STATE_SHUTDOWN & sh->suspend_state)))
2301 do_resume (sh, SUSPEND_STATE_EMFILE);
2302 }
2303 else
2304 {
2305 GNUNET_NETWORK_socket_free_memory_only_ (c->sock);
2306 }
2307 GNUNET_free (c);
2308 if ((0 != (SUSPEND_STATE_SHUTDOWN & sh->suspend_state)) &&
2309 (GNUNET_NO == have_non_monitor_clients (sh)))
2310 GNUNET_SERVICE_shutdown (sh);
2311}
2312
2313
2314/**
2315 * Ask the server to disconnect from the given client. This is the
2316 * same as returning #GNUNET_SYSERR within the check procedure when
2317 * handling a message, wexcept that it allows dropping of a client even
2318 * when not handling a message from that client. The `disconnect_cb`
2319 * will be called on @a c even if the application closes the connection
2320 * using this function.
2321 *
2322 * @param c client to disconnect now
2323 */
2324void
2325GNUNET_SERVICE_client_drop (struct GNUNET_SERVICE_Client *c)
2326{
2327 struct GNUNET_SERVICE_Handle *sh = c->sh;
2328
2329 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2330 "Client dropped: %p (MQ: %p)\n",
2331 c,
2332 c->mq);
2333#if EXECINFO
2334 {
2335 void *backtrace_array[MAX_TRACE_DEPTH];
2336 int num_backtrace_strings = backtrace (backtrace_array, MAX_TRACE_DEPTH);
2337 char **backtrace_strings =
2338 backtrace_symbols (backtrace_array, t->num_backtrace_strings);
2339 for (unsigned int i = 0; i < num_backtrace_strings; i++)
2340 LOG (GNUNET_ERROR_TYPE_DEBUG,
2341 "client drop trace %u: %s\n",
2342 i,
2343 backtrace_strings[i]);
2344 }
2345#endif
2346 if (NULL != c->drop_task)
2347 {
2348 /* asked to drop twice! */
2349 GNUNET_assert (0);
2350 return;
2351 }
2352 GNUNET_CONTAINER_DLL_remove (sh->clients_head,
2353 sh->clients_tail,
2354 c);
2355 if (NULL != sh->disconnect_cb)
2356 sh->disconnect_cb (sh->cb_cls,
2357 c,
2358 c->user_context);
2359 if (NULL != c->warn_task)
2360 {
2361 GNUNET_SCHEDULER_cancel (c->warn_task);
2362 c->warn_task = NULL;
2363 }
2364 if (NULL != c->recv_task)
2365 {
2366 GNUNET_SCHEDULER_cancel (c->recv_task);
2367 c->recv_task = NULL;
2368 }
2369 if (NULL != c->send_task)
2370 {
2371 GNUNET_SCHEDULER_cancel (c->send_task);
2372 c->send_task = NULL;
2373 }
2374 c->drop_task = GNUNET_SCHEDULER_add_now (&finish_client_drop, c);
2375}
2376
2377
2378/**
2379 * Explicitly stops the service.
2380 *
2381 * @param sh server to shutdown
2382 */
2383void
2384GNUNET_SERVICE_shutdown (struct GNUNET_SERVICE_Handle *sh)
2385{
2386 struct GNUNET_SERVICE_Client *client;
2387
2388 if (0 == (sh->suspend_state & SUSPEND_STATE_SHUTDOWN))
2389 do_suspend (sh, SUSPEND_STATE_SHUTDOWN);
2390 while (NULL != (client = sh->clients_head))
2391 GNUNET_SERVICE_client_drop (client);
2392}
2393
2394
2395/**
2396 * Set the 'monitor' flag on this client. Clients which have been
2397 * marked as 'monitors' won't prevent the server from shutting down
2398 * once #GNUNET_SERVICE_stop_listening() has been invoked. The idea is
2399 * that for "normal" clients we likely want to allow them to process
2400 * their requests; however, monitor-clients are likely to 'never'
2401 * disconnect during shutdown and thus will not be considered when
2402 * determining if the server should continue to exist after
2403 * shutdown has been triggered.
2404 *
2405 * @param c client to mark as a monitor
2406 */
2407void
2408GNUNET_SERVICE_client_mark_monitor (struct GNUNET_SERVICE_Client *c)
2409{
2410 c->is_monitor = GNUNET_YES;
2411 if (((0 != (SUSPEND_STATE_SHUTDOWN & c->sh->suspend_state)) &&
2412 (GNUNET_NO == have_non_monitor_clients (c->sh))))
2413 GNUNET_SERVICE_shutdown (c->sh);
2414}
2415
2416
2417/**
2418 * Set the persist option on this client. Indicates that the
2419 * underlying socket or fd should never really be closed. Used for
2420 * indicating process death.
2421 *
2422 * @param c client to persist the socket (never to be closed)
2423 */
2424void
2425GNUNET_SERVICE_client_persist (struct GNUNET_SERVICE_Client *c)
2426{
2427 c->persist = GNUNET_YES;
2428}
2429
2430
2431/**
2432 * Obtain the message queue of @a c. Convenience function.
2433 *
2434 * @param c the client to continue receiving from
2435 * @return the message queue of @a c
2436 */
2437struct GNUNET_MQ_Handle *
2438GNUNET_SERVICE_client_get_mq (struct GNUNET_SERVICE_Client *c)
2439{
2440 return c->mq;
2441}
2442
2443
2444/* end of service.c */