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.c2448
1 files changed, 0 insertions, 2448 deletions
diff --git a/src/util/service.c b/src/util/service.c
deleted file mode 100644
index c48060437..000000000
--- a/src/util/service.c
+++ /dev/null
@@ -1,2448 +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,
674 const struct GNUNET_MessageHeader *message)
675{
676 struct GNUNET_SERVICE_Client *client = cls;
677
678 LOG (GNUNET_ERROR_TYPE_DEBUG,
679 "Received message of type %u and size %u from client\n",
680 ntohs (message->type),
681 ntohs (message->size));
682 GNUNET_assert (GNUNET_NO == client->needs_continue);
683 client->needs_continue = GNUNET_YES;
684 client->warn_type = ntohs (message->type);
685 client->warn_start = GNUNET_TIME_absolute_get ();
686 GNUNET_assert (NULL == client->warn_task);
687 client->warn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
688 &warn_no_client_continue,
689 client);
690 GNUNET_MQ_inject_message (client->mq, message);
691 if (NULL != client->drop_task)
692 return GNUNET_SYSERR;
693 return GNUNET_OK;
694}
695
696
697/**
698 * A client sent us data. Receive and process it. If we are done,
699 * reschedule this task.
700 *
701 * @param cls the `struct GNUNET_SERVICE_Client` that sent us data.
702 */
703static void
704service_client_recv (void *cls)
705{
706 struct GNUNET_SERVICE_Client *client = cls;
707 enum GNUNET_GenericReturnValue ret;
708
709 client->recv_task = NULL;
710 ret = GNUNET_MST_read (client->mst,
711 client->sock,
712 GNUNET_NO,
713 GNUNET_YES);
714 if (GNUNET_SYSERR == ret)
715 {
716 /* client closed connection (or IO error) */
717 if (NULL == client->drop_task)
718 {
719 GNUNET_assert (GNUNET_NO == client->needs_continue);
720 GNUNET_SERVICE_client_drop (client);
721 }
722 return;
723 }
724 if (GNUNET_NO == ret)
725 return; /* more messages in buffer, wait for application
726 to be done processing */
727 GNUNET_assert (GNUNET_OK == ret);
728 if (GNUNET_YES == client->needs_continue)
729 return;
730 if (NULL != client->recv_task)
731 return;
732 /* MST needs more data, re-schedule read job */
733 client->recv_task =
734 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
735 client->sock,
736 &service_client_recv,
737 client);
738}
739
740
741/**
742 * We have successfully accepted a connection from a client. Now
743 * setup the client (with the scheduler) and tell the application.
744 *
745 * @param sh service that accepted the client
746 * @param sock socket associated with the client
747 */
748static void
749start_client (struct GNUNET_SERVICE_Handle *sh,
750 struct GNUNET_NETWORK_Handle *csock)
751{
752 struct GNUNET_SERVICE_Client *client;
753
754 client = GNUNET_new (struct GNUNET_SERVICE_Client);
755 GNUNET_CONTAINER_DLL_insert (sh->clients_head, sh->clients_tail, client);
756 client->sh = sh;
757 client->sock = csock;
758 client->mq = GNUNET_MQ_queue_for_callbacks (&service_mq_send,
759 NULL,
760 &service_mq_cancel,
761 client,
762 sh->handlers,
763 &service_mq_error_handler,
764 client);
765 client->mst = GNUNET_MST_create (&service_client_mst_cb, client);
766 if (NULL != sh->connect_cb)
767 client->user_context = sh->connect_cb (sh->cb_cls, client, client->mq);
768 GNUNET_MQ_set_handlers_closure (client->mq, client->user_context);
769 client->recv_task =
770 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
771 client->sock,
772 &service_client_recv,
773 client);
774}
775
776
777/**
778 * We have a client. Accept the incoming socket(s) (and reschedule
779 * the listen task).
780 *
781 * @param cls the `struct ServiceListenContext` of the ready listen socket
782 */
783static void
784accept_client (void *cls)
785{
786 struct ServiceListenContext *slc = cls;
787 struct GNUNET_SERVICE_Handle *sh = slc->sh;
788
789 slc->listen_task = NULL;
790 while (1)
791 {
792 struct GNUNET_NETWORK_Handle *sock;
793 const struct sockaddr_in *v4;
794 const struct sockaddr_in6 *v6;
795 struct sockaddr_storage sa;
796 socklen_t addrlen;
797 int ok;
798
799 addrlen = sizeof(sa);
800 sock = GNUNET_NETWORK_socket_accept (slc->listen_socket,
801 (struct sockaddr *) &sa,
802 &addrlen);
803 if (NULL == sock)
804 {
805 if (EMFILE == errno)
806 do_suspend (sh, SUSPEND_STATE_EMFILE);
807 else if (EAGAIN != errno)
808 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "accept");
809 break;
810 }
811 switch (sa.ss_family)
812 {
813 case AF_INET:
814 GNUNET_assert (addrlen == sizeof(struct sockaddr_in));
815 v4 = (const struct sockaddr_in *) &sa;
816 ok = (((NULL == sh->v4_allowed) ||
817 (check_ipv4_listed (sh->v4_allowed, &v4->sin_addr))) &&
818 ((NULL == sh->v4_denied) ||
819 (! check_ipv4_listed (sh->v4_denied, &v4->sin_addr))));
820 break;
821
822 case AF_INET6:
823 GNUNET_assert (addrlen == sizeof(struct sockaddr_in6));
824 v6 = (const struct sockaddr_in6 *) &sa;
825 ok = (((NULL == sh->v6_allowed) ||
826 (check_ipv6_listed (sh->v6_allowed, &v6->sin6_addr))) &&
827 ((NULL == sh->v6_denied) ||
828 (! check_ipv6_listed (sh->v6_denied, &v6->sin6_addr))));
829 break;
830
831 case AF_UNIX:
832 ok = GNUNET_OK; /* controlled using file-system ACL now */
833 break;
834
835 default:
836 LOG (GNUNET_ERROR_TYPE_WARNING,
837 _ ("Unknown address family %d\n"),
838 sa.ss_family);
839 return;
840 }
841 if (! ok)
842 {
843 LOG (GNUNET_ERROR_TYPE_DEBUG,
844 "Service rejected incoming connection from %s due to policy.\n",
845 GNUNET_a2s ((const struct sockaddr *) &sa, addrlen));
846 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
847 continue;
848 }
849 LOG (GNUNET_ERROR_TYPE_DEBUG,
850 "Service accepted incoming connection from %s.\n",
851 GNUNET_a2s ((const struct sockaddr *) &sa, addrlen));
852 start_client (slc->sh, sock);
853 }
854 if (0 != sh->suspend_state)
855 return;
856 slc->listen_task =
857 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
858 slc->listen_socket,
859 &accept_client,
860 slc);
861}
862
863
864/**
865 * Resume accepting connections from the listen socket.
866 *
867 * @param sh service to resume accepting connections.
868 * @param sr reason that is no longer causing the suspension,
869 * or #SUSPEND_STATE_NONE on first startup
870 */
871static void
872do_resume (struct GNUNET_SERVICE_Handle *sh, enum SuspendReason sr)
873{
874 struct ServiceListenContext *slc;
875
876 GNUNET_assert ((SUSPEND_STATE_NONE == sr) || (0 != (sh->suspend_state & sr)));
877 sh->suspend_state -= sr;
878 if (SUSPEND_STATE_NONE != sh->suspend_state)
879 return;
880 for (slc = sh->slc_head; NULL != slc; slc = slc->next)
881 {
882 GNUNET_assert (NULL == slc->listen_task);
883 slc->listen_task =
884 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
885 slc->listen_socket,
886 &accept_client,
887 slc);
888 }
889}
890
891
892/**
893 * First task run by any service. Initializes our shutdown task,
894 * starts the listening operation on our listen sockets and launches
895 * the custom logic of the application service.
896 *
897 * @param cls our `struct GNUNET_SERVICE_Handle`
898 */
899static void
900service_main (void *cls)
901{
902 struct GNUNET_SERVICE_Handle *sh = cls;
903
904 if (GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN !=
905 (sh->options & GNUNET_SERVICE_OPTION_SHUTDOWN_BITMASK))
906 GNUNET_SCHEDULER_add_shutdown (&service_shutdown, sh);
907 do_resume (sh, SUSPEND_STATE_NONE);
908
909 if (-1 != sh->ready_confirm_fd)
910 {
911 GNUNET_break (1 == write (sh->ready_confirm_fd, ".", 1));
912 GNUNET_break (0 == close (sh->ready_confirm_fd));
913 sh->ready_confirm_fd = -1;
914 }
915
916 if (NULL != sh->service_init_cb)
917 sh->service_init_cb (sh->cb_cls, sh->cfg, sh);
918}
919
920
921/**
922 * Parse an IPv4 access control list.
923 *
924 * @param ret location where to write the ACL (set)
925 * @param sh service context to use to get the configuration
926 * @param option name of the ACL option to parse
927 * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including
928 * no ACL configured)
929 */
930static int
931process_acl4 (struct GNUNET_STRINGS_IPv4NetworkPolicy **ret,
932 struct GNUNET_SERVICE_Handle *sh,
933 const char *option)
934{
935 char *opt;
936
937 if (! GNUNET_CONFIGURATION_have_value (sh->cfg, sh->service_name, option))
938 {
939 *ret = NULL;
940 return GNUNET_OK;
941 }
942 GNUNET_break (GNUNET_OK ==
943 GNUNET_CONFIGURATION_get_value_string (sh->cfg,
944 sh->service_name,
945 option,
946 &opt));
947 if (NULL == (*ret = GNUNET_STRINGS_parse_ipv4_policy (opt)))
948 {
949 LOG (GNUNET_ERROR_TYPE_WARNING,
950 _ ("Could not parse IPv4 network specification `%s' for `%s:%s'\n"),
951 opt,
952 sh->service_name,
953 option);
954 GNUNET_free (opt);
955 return GNUNET_SYSERR;
956 }
957 GNUNET_free (opt);
958 return GNUNET_OK;
959}
960
961
962/**
963 * Parse an IPv6 access control list.
964 *
965 * @param ret location where to write the ACL (set)
966 * @param sh service context to use to get the configuration
967 * @param option name of the ACL option to parse
968 * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including
969 * no ACL configured)
970 */
971static int
972process_acl6 (struct GNUNET_STRINGS_IPv6NetworkPolicy **ret,
973 struct GNUNET_SERVICE_Handle *sh,
974 const char *option)
975{
976 char *opt;
977
978 if (! GNUNET_CONFIGURATION_have_value (sh->cfg, sh->service_name, option))
979 {
980 *ret = NULL;
981 return GNUNET_OK;
982 }
983 GNUNET_break (GNUNET_OK ==
984 GNUNET_CONFIGURATION_get_value_string (sh->cfg,
985 sh->service_name,
986 option,
987 &opt));
988 if (NULL == (*ret = GNUNET_STRINGS_parse_ipv6_policy (opt)))
989 {
990 LOG (GNUNET_ERROR_TYPE_WARNING,
991 _ ("Could not parse IPv6 network specification `%s' for `%s:%s'\n"),
992 opt,
993 sh->service_name,
994 option);
995 GNUNET_free (opt);
996 return GNUNET_SYSERR;
997 }
998 GNUNET_free (opt);
999 return GNUNET_OK;
1000}
1001
1002
1003/**
1004 * Add the given UNIX domain path as an address to the
1005 * list (as the first entry).
1006 *
1007 * @param saddrs array to update
1008 * @param saddrlens where to store the address length
1009 * @param unixpath path to add
1010 */
1011static void
1012add_unixpath (struct sockaddr **saddrs,
1013 socklen_t *saddrlens,
1014 const char *unixpath)
1015{
1016#ifdef AF_UNIX
1017 struct sockaddr_un *un;
1018
1019 un = GNUNET_new (struct sockaddr_un);
1020 un->sun_family = AF_UNIX;
1021 GNUNET_strlcpy (un->sun_path, unixpath, sizeof(un->sun_path));
1022#if HAVE_SOCKADDR_UN_SUN_LEN
1023 un->sun_len = (u_char) sizeof(struct sockaddr_un);
1024#endif
1025 *saddrs = (struct sockaddr *) un;
1026 *saddrlens = sizeof(struct sockaddr_un);
1027#else
1028 /* this function should never be called
1029 * unless AF_UNIX is defined! */
1030 GNUNET_assert (0);
1031#endif
1032}
1033
1034
1035/**
1036 * Get the list of addresses that a server for the given service
1037 * should bind to.
1038 *
1039 * @param service_name name of the service
1040 * @param cfg configuration (which specifies the addresses)
1041 * @param addrs set (call by reference) to an array of pointers to the
1042 * addresses the server should bind to and listen on; the
1043 * array will be NULL-terminated (on success)
1044 * @param addr_lens set (call by reference) to an array of the lengths
1045 * of the respective `struct sockaddr` struct in the @a addrs
1046 * array (on success)
1047 * @return number of addresses found on success,
1048 * #GNUNET_SYSERR if the configuration
1049 * did not specify reasonable finding information or
1050 * if it specified a hostname that could not be resolved;
1051 * #GNUNET_NO if the number of addresses configured is
1052 * zero (in this case, `*addrs` and `*addr_lens` will be
1053 * set to NULL).
1054 */
1055static int
1056get_server_addresses (const char *service_name,
1057 const struct GNUNET_CONFIGURATION_Handle *cfg,
1058 struct sockaddr ***addrs,
1059 socklen_t **addr_lens)
1060{
1061 int disablev6;
1062 struct GNUNET_NETWORK_Handle *desc;
1063 unsigned long long port;
1064 char *unixpath;
1065 struct addrinfo hints;
1066 struct addrinfo *res;
1067 struct addrinfo *pos;
1068 struct addrinfo *next;
1069 unsigned int i;
1070 int resi;
1071 int ret;
1072 struct sockaddr **saddrs;
1073 socklen_t *saddrlens;
1074 char *hostname;
1075
1076 *addrs = NULL;
1077 *addr_lens = NULL;
1078 desc = NULL;
1079 disablev6 = GNUNET_NO;
1080 if ((GNUNET_NO == GNUNET_NETWORK_test_pf (PF_INET6)) ||
1081 (GNUNET_YES ==
1082 GNUNET_CONFIGURATION_get_value_yesno (cfg, service_name, "DISABLEV6")))
1083 disablev6 = GNUNET_YES;
1084
1085 port = 0;
1086 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT"))
1087 {
1088 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg,
1089 service_name,
1090 "PORT",
1091 &port))
1092 {
1093 LOG (GNUNET_ERROR_TYPE_ERROR,
1094 _ ("Require valid port number for service `%s' in configuration!\n"),
1095 service_name);
1096 }
1097 if (port > 65535)
1098 {
1099 LOG (GNUNET_ERROR_TYPE_ERROR,
1100 _ ("Require valid port number for service `%s' in configuration!\n"),
1101 service_name);
1102 return GNUNET_SYSERR;
1103 }
1104 }
1105
1106 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO"))
1107 {
1108 GNUNET_break (GNUNET_OK ==
1109 GNUNET_CONFIGURATION_get_value_string (cfg,
1110 service_name,
1111 "BINDTO",
1112 &hostname));
1113 }
1114 else
1115 hostname = NULL;
1116
1117 unixpath = NULL;
1118#ifdef AF_UNIX
1119 if ((GNUNET_YES ==
1120 GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) &&
1121 (GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg,
1122 service_name,
1123 "UNIXPATH",
1124 &unixpath)) &&
1125 (0 < strlen (unixpath)))
1126 {
1127 /* probe UNIX support */
1128 struct sockaddr_un s_un;
1129
1130 if (strlen (unixpath) >= sizeof(s_un.sun_path))
1131 {
1132 LOG (GNUNET_ERROR_TYPE_WARNING,
1133 _ ("UNIXPATH `%s' too long, maximum length is %llu\n"),
1134 unixpath,
1135 (unsigned long long) sizeof(s_un.sun_path));
1136 unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
1137 LOG (GNUNET_ERROR_TYPE_INFO, _ ("Using `%s' instead\n"), unixpath);
1138 }
1139 if (GNUNET_OK != GNUNET_DISK_directory_create_for_file (unixpath))
1140 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "mkdir", unixpath);
1141 }
1142 if (NULL != unixpath)
1143 {
1144 desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
1145 if (NULL == desc)
1146 {
1147 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
1148 (EACCES == errno))
1149 {
1150 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
1151 GNUNET_free (hostname);
1152 GNUNET_free (unixpath);
1153 return GNUNET_SYSERR;
1154 }
1155 LOG (GNUNET_ERROR_TYPE_INFO,
1156 _ (
1157 "Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"),
1158 service_name,
1159 strerror (errno));
1160 GNUNET_free (unixpath);
1161 unixpath = NULL;
1162 }
1163 else
1164 {
1165 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
1166 desc = NULL;
1167 }
1168 }
1169#endif
1170
1171 if ((0 == port) && (NULL == unixpath))
1172 {
1173 LOG (GNUNET_ERROR_TYPE_ERROR,
1174 _ (
1175 "Have neither PORT nor UNIXPATH for service `%s', but one is required\n"),
1176 service_name);
1177 GNUNET_free (hostname);
1178 return GNUNET_SYSERR;
1179 }
1180 if (0 == port)
1181 {
1182 saddrs = GNUNET_new_array (2, struct sockaddr *);
1183 saddrlens = GNUNET_new_array (2, socklen_t);
1184 add_unixpath (saddrs, saddrlens, unixpath);
1185 GNUNET_free (unixpath);
1186 GNUNET_free (hostname);
1187 *addrs = saddrs;
1188 *addr_lens = saddrlens;
1189 return 1;
1190 }
1191
1192 if (NULL != hostname)
1193 {
1194 LOG (GNUNET_ERROR_TYPE_DEBUG,
1195 "Resolving `%s' since that is where `%s' will bind to.\n",
1196 hostname,
1197 service_name);
1198 memset (&hints, 0, sizeof(struct addrinfo));
1199 if (disablev6)
1200 hints.ai_family = AF_INET;
1201 hints.ai_protocol = IPPROTO_TCP;
1202 if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
1203 (NULL == res))
1204 {
1205 LOG (GNUNET_ERROR_TYPE_ERROR,
1206 _ ("Failed to resolve `%s': %s\n"),
1207 hostname,
1208 gai_strerror (ret));
1209 GNUNET_free (hostname);
1210 GNUNET_free (unixpath);
1211 return GNUNET_SYSERR;
1212 }
1213 next = res;
1214 i = 0;
1215 while (NULL != (pos = next))
1216 {
1217 next = pos->ai_next;
1218 if ((disablev6) && (pos->ai_family == AF_INET6))
1219 continue;
1220 i++;
1221 }
1222 if (0 == i)
1223 {
1224 LOG (GNUNET_ERROR_TYPE_ERROR,
1225 _ ("Failed to find %saddress for `%s'.\n"),
1226 disablev6 ? "IPv4 " : "",
1227 hostname);
1228 freeaddrinfo (res);
1229 GNUNET_free (hostname);
1230 GNUNET_free (unixpath);
1231 return GNUNET_SYSERR;
1232 }
1233 resi = i;
1234 if (NULL != unixpath)
1235 resi++;
1236 saddrs = GNUNET_new_array (resi + 1, struct sockaddr *);
1237 saddrlens = GNUNET_new_array (resi + 1, socklen_t);
1238 i = 0;
1239 if (NULL != unixpath)
1240 {
1241 add_unixpath (saddrs, saddrlens, unixpath);
1242 i++;
1243 }
1244 next = res;
1245 while (NULL != (pos = next))
1246 {
1247 next = pos->ai_next;
1248 if ((disablev6) && (AF_INET6 == pos->ai_family))
1249 continue;
1250 if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol))
1251 continue; /* not TCP */
1252 if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
1253 continue; /* huh? */
1254 LOG (GNUNET_ERROR_TYPE_DEBUG,
1255 "Service `%s' will bind to `%s'\n",
1256 service_name,
1257 GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
1258 if (AF_INET == pos->ai_family)
1259 {
1260 GNUNET_assert (sizeof(struct sockaddr_in) == pos->ai_addrlen);
1261 saddrlens[i] = pos->ai_addrlen;
1262 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1263 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
1264 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1265 }
1266 else
1267 {
1268 GNUNET_assert (AF_INET6 == pos->ai_family);
1269 GNUNET_assert (sizeof(struct sockaddr_in6) == pos->ai_addrlen);
1270 saddrlens[i] = pos->ai_addrlen;
1271 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1272 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
1273 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
1274 }
1275 i++;
1276 }
1277 GNUNET_free (hostname);
1278 freeaddrinfo (res);
1279 resi = i;
1280 }
1281 else
1282 {
1283 /* will bind against everything, just set port */
1284 if (disablev6)
1285 {
1286 /* V4-only */
1287 resi = 1;
1288 if (NULL != unixpath)
1289 resi++;
1290 i = 0;
1291 saddrs = GNUNET_new_array (resi + 1, struct sockaddr *);
1292 saddrlens = GNUNET_new_array (resi + 1, socklen_t);
1293 if (NULL != unixpath)
1294 {
1295 add_unixpath (saddrs, saddrlens, unixpath);
1296 i++;
1297 }
1298 saddrlens[i] = sizeof(struct sockaddr_in);
1299 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1300#if HAVE_SOCKADDR_IN_SIN_LEN
1301 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
1302#endif
1303 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
1304 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1305 }
1306 else
1307 {
1308 /* dual stack */
1309 resi = 2;
1310 if (NULL != unixpath)
1311 resi++;
1312 saddrs = GNUNET_new_array (resi + 1, struct sockaddr *);
1313 saddrlens = GNUNET_new_array (resi + 1, socklen_t);
1314 i = 0;
1315 if (NULL != unixpath)
1316 {
1317 add_unixpath (saddrs, saddrlens, unixpath);
1318 i++;
1319 }
1320 saddrlens[i] = sizeof(struct sockaddr_in6);
1321 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1322#if HAVE_SOCKADDR_IN_SIN_LEN
1323 ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
1324#endif
1325 ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
1326 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
1327 i++;
1328 saddrlens[i] = sizeof(struct sockaddr_in);
1329 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1330#if HAVE_SOCKADDR_IN_SIN_LEN
1331 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
1332#endif
1333 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
1334 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1335 }
1336 }
1337 GNUNET_free (unixpath);
1338 *addrs = saddrs;
1339 *addr_lens = saddrlens;
1340 return resi;
1341}
1342
1343
1344/**
1345 * Create and initialize a listen socket for the server.
1346 *
1347 * @param server_addr address to listen on
1348 * @param socklen length of @a server_addr
1349 * @return NULL on error, otherwise the listen socket
1350 */
1351static struct GNUNET_NETWORK_Handle *
1352open_listen_socket (const struct sockaddr *server_addr,
1353 socklen_t socklen)
1354{
1355 struct GNUNET_NETWORK_Handle *sock;
1356 uint16_t port;
1357 int eno;
1358
1359 switch (server_addr->sa_family)
1360 {
1361 case AF_INET:
1362 port = ntohs (((const struct sockaddr_in *) server_addr)->sin_port);
1363 break;
1364 case AF_INET6:
1365 port = ntohs (((const struct sockaddr_in6 *) server_addr)->sin6_port);
1366 break;
1367 case AF_UNIX:
1368 port = 0;
1369 break;
1370 default:
1371 GNUNET_break (0);
1372 port = 0;
1373 break;
1374 }
1375 sock = GNUNET_NETWORK_socket_create (server_addr->sa_family,
1376 SOCK_STREAM,
1377 0);
1378 if (NULL == sock)
1379 {
1380 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR,
1381 "socket");
1382 errno = 0;
1383 return NULL;
1384 }
1385 /* bind the socket */
1386 if (GNUNET_OK !=
1387 GNUNET_NETWORK_socket_bind (sock,
1388 server_addr,
1389 socklen))
1390 {
1391 eno = errno;
1392 if (EADDRINUSE != errno)
1393 {
1394 /* we don't log 'EADDRINUSE' here since an IPv4 bind may
1395 * fail if we already took the port on IPv6; if both IPv4 and
1396 * IPv6 binds fail, then our caller will log using the
1397 * errno preserved in 'eno' */
1398 if (0 != port)
1399 LOG (GNUNET_ERROR_TYPE_ERROR,
1400 _ ("`%s' failed for port %d (%s).\n"),
1401 "bind",
1402 port,
1403 (AF_INET == server_addr->sa_family) ? "IPv4" : "IPv6");
1404 else
1405 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "bind");
1406 eno = 0;
1407 }
1408 else
1409 {
1410 if (0 != port)
1411 LOG (GNUNET_ERROR_TYPE_WARNING,
1412 _ ("`%s' failed for port %d (%s): address already in use\n"),
1413 "bind",
1414 port,
1415 (AF_INET == server_addr->sa_family) ? "IPv4" : "IPv6");
1416 else if (AF_UNIX == server_addr->sa_family)
1417 {
1418 LOG (GNUNET_ERROR_TYPE_WARNING,
1419 _ ("`%s' failed for `%s': address already in use\n"),
1420 "bind",
1421 GNUNET_a2s (server_addr, socklen));
1422 }
1423 }
1424 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
1425 errno = eno;
1426 return NULL;
1427 }
1428 if (GNUNET_OK != GNUNET_NETWORK_socket_listen (sock, 5))
1429 {
1430 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "listen");
1431 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
1432 errno = 0;
1433 return NULL;
1434 }
1435 if (0 != port)
1436 LOG (GNUNET_ERROR_TYPE_DEBUG,
1437 "Server starts to listen on port %u.\n",
1438 port);
1439 return sock;
1440}
1441
1442
1443/**
1444 * Setup service handle
1445 *
1446 * Configuration may specify:
1447 * - PORT (where to bind to for TCP)
1448 * - UNIXPATH (where to bind to for UNIX domain sockets)
1449 * - DISABLEV6 (disable support for IPv6, otherwise we use dual-stack)
1450 * - BINDTO (hostname or IP address to bind to, otherwise we take everything)
1451 * - ACCEPT_FROM (only allow connections from specified IPv4 subnets)
1452 * - ACCEPT_FROM6 (only allow connections from specified IPv6 subnets)
1453 * - REJECT_FROM (disallow allow connections from specified IPv4 subnets)
1454 * - REJECT_FROM6 (disallow allow connections from specified IPv6 subnets)
1455 *
1456 * @param sh service context to initialize
1457 * @return #GNUNET_OK if configuration succeeded
1458 */
1459static int
1460setup_service (struct GNUNET_SERVICE_Handle *sh)
1461{
1462 int tolerant;
1463 struct GNUNET_NETWORK_Handle **csocks = NULL;
1464 struct GNUNET_NETWORK_Handle **lsocks;
1465 const char *nfds;
1466 unsigned int cnt;
1467 int flags;
1468 char dummy[2];
1469
1470 if (GNUNET_CONFIGURATION_have_value (sh->cfg,
1471 sh->service_name,
1472 "TOLERANT"))
1473 {
1474 if (GNUNET_SYSERR ==
1475 (tolerant = GNUNET_CONFIGURATION_get_value_yesno (sh->cfg,
1476 sh->service_name,
1477 "TOLERANT")))
1478 {
1479 LOG (GNUNET_ERROR_TYPE_ERROR,
1480 _ ("Specified value for `%s' of service `%s' is invalid\n"),
1481 "TOLERANT",
1482 sh->service_name);
1483 return GNUNET_SYSERR;
1484 }
1485 }
1486 else
1487 tolerant = GNUNET_NO;
1488
1489 lsocks = NULL;
1490 errno = 0;
1491 if ((NULL != (nfds = getenv ("LISTEN_FDS"))) &&
1492 (1 == sscanf (nfds, "%u%1s", &cnt, dummy)) && (cnt > 0) &&
1493 (cnt < FD_SETSIZE) && (cnt + 4 < FD_SETSIZE))
1494 {
1495 lsocks = GNUNET_new_array (cnt + 1, struct GNUNET_NETWORK_Handle *);
1496 while (0 < cnt--)
1497 {
1498 flags = fcntl (3 + cnt, F_GETFD);
1499 if ((flags < 0) || (0 != (flags & FD_CLOEXEC)) ||
1500 (NULL == (lsocks[cnt] = GNUNET_NETWORK_socket_box_native (3 + cnt))))
1501 {
1502 LOG (GNUNET_ERROR_TYPE_ERROR,
1503 _ (
1504 "Could not access pre-bound socket %u, will try to bind myself\n"),
1505 (unsigned int) 3 + cnt);
1506 cnt++;
1507 while (NULL != lsocks[cnt])
1508 GNUNET_break (GNUNET_OK ==
1509 GNUNET_NETWORK_socket_close (lsocks[cnt++]));
1510 GNUNET_free (lsocks);
1511 lsocks = NULL;
1512 break;
1513 }
1514 }
1515 unsetenv ("LISTEN_FDS");
1516 }
1517 if ( (0 != (GNUNET_SERVICE_OPTION_CLOSE_LSOCKS & sh->options)) &&
1518 (NULL != lsocks) )
1519 {
1520 csocks = lsocks;
1521 lsocks = NULL;
1522 }
1523
1524 if (NULL != lsocks)
1525 {
1526 /* listen only on inherited sockets if we have any */
1527 for (struct GNUNET_NETWORK_Handle **ls = lsocks; NULL != *ls; ls++)
1528 {
1529 struct ServiceListenContext *slc;
1530
1531 slc = GNUNET_new (struct ServiceListenContext);
1532 slc->sh = sh;
1533 slc->listen_socket = *ls;
1534 GNUNET_CONTAINER_DLL_insert (sh->slc_head, sh->slc_tail, slc);
1535 }
1536 GNUNET_free (lsocks);
1537 }
1538 else
1539 {
1540 struct sockaddr **addrs;
1541 socklen_t *addrlens;
1542 int num;
1543
1544 num = get_server_addresses (sh->service_name, sh->cfg, &addrs, &addrlens);
1545 if (GNUNET_SYSERR == num)
1546 return GNUNET_SYSERR;
1547
1548 for (int i = 0; i < num; i++)
1549 {
1550 struct ServiceListenContext *slc;
1551
1552 slc = GNUNET_new (struct ServiceListenContext);
1553 slc->sh = sh;
1554 slc->listen_socket = open_listen_socket (addrs[i], addrlens[i]);
1555 GNUNET_free (addrs[i]);
1556 if (NULL == slc->listen_socket)
1557 {
1558 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
1559 GNUNET_free (slc);
1560 continue;
1561 }
1562 GNUNET_CONTAINER_DLL_insert (sh->slc_head, sh->slc_tail, slc);
1563 }
1564 GNUNET_free (addrlens);
1565 GNUNET_free (addrs);
1566 if ((0 != num) && (NULL == sh->slc_head))
1567 {
1568 /* All attempts to bind failed, hard failure */
1569 GNUNET_log (
1570 GNUNET_ERROR_TYPE_ERROR,
1571 _ (
1572 "Could not bind to any of the ports I was supposed to, refusing to run!\n"));
1573 GNUNET_free (csocks);
1574 return GNUNET_SYSERR;
1575 }
1576 }
1577 if (NULL != csocks)
1578 {
1579 /* close inherited sockets to signal parent that we are ready */
1580 for (struct GNUNET_NETWORK_Handle **ls = csocks; NULL != *ls; ls++)
1581 GNUNET_NETWORK_socket_close (*ls);
1582 GNUNET_free (csocks);
1583 }
1584 sh->require_found = tolerant ? GNUNET_NO : GNUNET_YES;
1585 sh->match_uid = GNUNET_CONFIGURATION_get_value_yesno (sh->cfg,
1586 sh->service_name,
1587 "UNIX_MATCH_UID");
1588 sh->match_gid = GNUNET_CONFIGURATION_get_value_yesno (sh->cfg,
1589 sh->service_name,
1590 "UNIX_MATCH_GID");
1591 process_acl4 (&sh->v4_denied, sh, "REJECT_FROM");
1592 process_acl4 (&sh->v4_allowed, sh, "ACCEPT_FROM");
1593 process_acl6 (&sh->v6_denied, sh, "REJECT_FROM6");
1594 process_acl6 (&sh->v6_allowed, sh, "ACCEPT_FROM6");
1595 return GNUNET_OK;
1596}
1597
1598
1599/**
1600 * Get the name of the user that'll be used
1601 * to provide the service.
1602 *
1603 * @param sh service context
1604 * @return value of the 'USERNAME' option
1605 */
1606static char *
1607get_user_name (struct GNUNET_SERVICE_Handle *sh)
1608{
1609 char *un;
1610
1611 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (sh->cfg,
1612 sh->service_name,
1613 "USERNAME",
1614 &un))
1615 return NULL;
1616 return un;
1617}
1618
1619
1620/**
1621 * Set user ID.
1622 *
1623 * @param sh service context
1624 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1625 */
1626static int
1627set_user_id (struct GNUNET_SERVICE_Handle *sh)
1628{
1629 char *user;
1630
1631 if (NULL == (user = get_user_name (sh)))
1632 return GNUNET_OK; /* keep */
1633
1634 struct passwd *pws;
1635
1636 errno = 0;
1637 pws = getpwnam (user);
1638 if (NULL == pws)
1639 {
1640 LOG (GNUNET_ERROR_TYPE_ERROR,
1641 _ ("Cannot obtain information about user `%s': %s\n"),
1642 user,
1643 errno == 0 ? _ ("No such user") : strerror (errno));
1644 GNUNET_free (user);
1645 return GNUNET_SYSERR;
1646 }
1647 if ((0 != setgid (pws->pw_gid)) || (0 != setegid (pws->pw_gid)) ||
1648#if HAVE_INITGROUPS
1649 (0 != initgroups (user, pws->pw_gid)) ||
1650#endif
1651 (0 != setuid (pws->pw_uid)) || (0 != seteuid (pws->pw_uid)))
1652 {
1653 if ((0 != setregid (pws->pw_gid, pws->pw_gid)) ||
1654 (0 != setreuid (pws->pw_uid, pws->pw_uid)))
1655 {
1656 LOG (GNUNET_ERROR_TYPE_ERROR,
1657 _ ("Cannot change user/group to `%s': %s\n"),
1658 user,
1659 strerror (errno));
1660 GNUNET_free (user);
1661 return GNUNET_SYSERR;
1662 }
1663 }
1664
1665 GNUNET_free (user);
1666 return GNUNET_OK;
1667}
1668
1669
1670/**
1671 * Get the name of the file where we will
1672 * write the PID of the service.
1673 *
1674 * @param sh service context
1675 * @return name of the file for the process ID
1676 */
1677static char *
1678get_pid_file_name (struct GNUNET_SERVICE_Handle *sh)
1679{
1680 char *pif;
1681
1682 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (sh->cfg,
1683 sh->service_name,
1684 "PIDFILE",
1685 &pif))
1686 return NULL;
1687 return pif;
1688}
1689
1690
1691/**
1692 * Delete the PID file that was created by our parent.
1693 *
1694 * @param sh service context
1695 */
1696static void
1697pid_file_delete (struct GNUNET_SERVICE_Handle *sh)
1698{
1699 char *pif = get_pid_file_name (sh);
1700
1701 if (NULL == pif)
1702 return; /* no PID file */
1703 if (0 != unlink (pif))
1704 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", pif);
1705 GNUNET_free (pif);
1706}
1707
1708
1709/**
1710 * Detach from terminal.
1711 *
1712 * @param sh service context
1713 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1714 */
1715static int
1716detach_terminal (struct GNUNET_SERVICE_Handle *sh)
1717{
1718 pid_t pid;
1719 int nullfd;
1720 int filedes[2];
1721
1722 if (0 != pipe (filedes))
1723 {
1724 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "pipe");
1725 return GNUNET_SYSERR;
1726 }
1727 pid = fork ();
1728 if (pid < 0)
1729 {
1730 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork");
1731 return GNUNET_SYSERR;
1732 }
1733 if (0 != pid)
1734 {
1735 /* Parent */
1736 char c;
1737
1738 GNUNET_break (0 == close (filedes[1]));
1739 c = 'X';
1740 if (1 != read (filedes[0], &c, sizeof(char)))
1741 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "read");
1742 fflush (stdout);
1743 switch (c)
1744 {
1745 case '.':
1746 exit (0);
1747
1748 case 'I':
1749 LOG (GNUNET_ERROR_TYPE_INFO,
1750 _ ("Service process failed to initialize\n"));
1751 break;
1752
1753 case 'S':
1754 LOG (GNUNET_ERROR_TYPE_INFO,
1755 _ ("Service process could not initialize server function\n"));
1756 break;
1757
1758 case 'X':
1759 LOG (GNUNET_ERROR_TYPE_INFO,
1760 _ ("Service process failed to report status\n"));
1761 break;
1762 }
1763 exit (1); /* child reported error */
1764 }
1765 GNUNET_break (0 == close (0));
1766 GNUNET_break (0 == close (1));
1767 GNUNET_break (0 == close (filedes[0]));
1768 nullfd = open ("/dev/null", O_RDWR | O_APPEND);
1769 if (nullfd < 0)
1770 return GNUNET_SYSERR;
1771 /* set stdin/stdout to /dev/null */
1772 if ((dup2 (nullfd, 0) < 0) || (dup2 (nullfd, 1) < 0))
1773 {
1774 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2");
1775 (void) close (nullfd);
1776 return GNUNET_SYSERR;
1777 }
1778 (void) close (nullfd);
1779 /* Detach from controlling terminal */
1780 pid = setsid ();
1781 if (-1 == pid)
1782 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "setsid");
1783 sh->ready_confirm_fd = filedes[1];
1784
1785 return GNUNET_OK;
1786}
1787
1788
1789/**
1790 * Tear down the service, closing the listen sockets and
1791 * freeing the ACLs.
1792 *
1793 * @param sh handle to the service to tear down.
1794 */
1795static void
1796teardown_service (struct GNUNET_SERVICE_Handle *sh)
1797{
1798 struct ServiceListenContext *slc;
1799
1800 GNUNET_free (sh->v4_denied);
1801 GNUNET_free (sh->v6_denied);
1802 GNUNET_free (sh->v4_allowed);
1803 GNUNET_free (sh->v6_allowed);
1804 while (NULL != (slc = sh->slc_head))
1805 {
1806 GNUNET_CONTAINER_DLL_remove (sh->slc_head, sh->slc_tail, slc);
1807 if (NULL != slc->listen_task)
1808 GNUNET_SCHEDULER_cancel (slc->listen_task);
1809 GNUNET_break (GNUNET_OK ==
1810 GNUNET_NETWORK_socket_close (slc->listen_socket));
1811 GNUNET_free (slc);
1812 }
1813}
1814
1815
1816/**
1817 * Function to return link to AGPL source upon request.
1818 *
1819 * @param cls closure with the identification of the client
1820 * @param msg AGPL request
1821 */
1822static void
1823return_agpl (void *cls, const struct GNUNET_MessageHeader *msg)
1824{
1825 struct GNUNET_SERVICE_Client *client = cls;
1826 struct GNUNET_MQ_Handle *mq;
1827 struct GNUNET_MQ_Envelope *env;
1828 struct GNUNET_MessageHeader *res;
1829 size_t slen;
1830 const struct GNUNET_OS_ProjectData *pd = GNUNET_OS_project_data_get ();
1831
1832 (void) msg;
1833 slen = strlen (pd->agpl_url) + 1;
1834 env = GNUNET_MQ_msg_extra (res, GNUNET_MESSAGE_TYPE_RESPONSE_AGPL, slen);
1835 memcpy (&res[1], GNUNET_AGPL_URL, slen);
1836 mq = GNUNET_SERVICE_client_get_mq (client);
1837 GNUNET_MQ_send (mq, env);
1838 GNUNET_SERVICE_client_continue (client);
1839}
1840
1841
1842/**
1843 * Low-level function to start a service if the scheduler
1844 * is already running. Should only be used directly in
1845 * special cases.
1846 *
1847 * The function will launch the service with the name @a service_name
1848 * using the @a service_options to configure its shutdown
1849 * behavior. When clients connect or disconnect, the respective
1850 * @a connect_cb or @a disconnect_cb functions will be called. For
1851 * messages received from the clients, the respective @a handlers will
1852 * be invoked; for the closure of the handlers we use the return value
1853 * from the @a connect_cb invocation of the respective client.
1854 *
1855 * Each handler MUST call #GNUNET_SERVICE_client_continue() after each
1856 * message to receive further messages from this client. If
1857 * #GNUNET_SERVICE_client_continue() is not called within a short
1858 * time, a warning will be logged. If delays are expected, services
1859 * should call #GNUNET_SERVICE_client_disable_continue_warning() to
1860 * disable the warning.
1861 *
1862 * Clients sending invalid messages (based on @a handlers) will be
1863 * dropped. Additionally, clients can be dropped at any time using
1864 * #GNUNET_SERVICE_client_drop().
1865 *
1866 * The service must be stopped using #GNUNET_SERVICE_stop().
1867 *
1868 * @param service_name name of the service to run
1869 * @param cfg configuration to use
1870 * @param connect_cb function to call whenever a client connects
1871 * @param disconnect_cb function to call whenever a client disconnects
1872 * @param cls closure argument for @a connect_cb and @a disconnect_cb
1873 * @param handlers NULL-terminated array of message handlers for the service,
1874 * the closure will be set to the value returned by
1875 * the @a connect_cb for the respective connection
1876 * @return NULL on error
1877 */
1878struct GNUNET_SERVICE_Handle *
1879GNUNET_SERVICE_start (const char *service_name,
1880 const struct GNUNET_CONFIGURATION_Handle *cfg,
1881 GNUNET_SERVICE_ConnectHandler connect_cb,
1882 GNUNET_SERVICE_DisconnectHandler disconnect_cb,
1883 void *cls,
1884 const struct GNUNET_MQ_MessageHandler *handlers)
1885{
1886 struct GNUNET_SERVICE_Handle *sh;
1887
1888 sh = GNUNET_new (struct GNUNET_SERVICE_Handle);
1889 sh->service_name = service_name;
1890 sh->cfg = cfg;
1891 sh->connect_cb = connect_cb;
1892 sh->disconnect_cb = disconnect_cb;
1893 sh->cb_cls = cls;
1894 sh->handlers = GNUNET_MQ_copy_handlers2 (handlers, &return_agpl, NULL);
1895 if (GNUNET_OK != setup_service (sh))
1896 {
1897 GNUNET_free (sh->handlers);
1898 GNUNET_free (sh);
1899 return NULL;
1900 }
1901 do_resume (sh, SUSPEND_STATE_NONE);
1902 return sh;
1903}
1904
1905
1906/**
1907 * Stops a service that was started with #GNUNET_SERVICE_start().
1908 *
1909 * @param srv service to stop
1910 */
1911void
1912GNUNET_SERVICE_stop (struct GNUNET_SERVICE_Handle *srv)
1913{
1914 struct GNUNET_SERVICE_Client *client;
1915
1916 GNUNET_SERVICE_suspend (srv);
1917 while (NULL != (client = srv->clients_head))
1918 GNUNET_SERVICE_client_drop (client);
1919 teardown_service (srv);
1920 GNUNET_free (srv->handlers);
1921 GNUNET_free (srv);
1922}
1923
1924
1925/**
1926 * Creates the "main" function for a GNUnet service. You
1927 * should almost always use the #GNUNET_SERVICE_MAIN macro
1928 * instead of calling this function directly (except
1929 * for ARM, which should call this function directly).
1930 *
1931 * The function will launch the service with the name @a service_name
1932 * using the @a service_options to configure its shutdown
1933 * behavior. Once the service is ready, the @a init_cb will be called
1934 * for service-specific initialization. @a init_cb will be given the
1935 * service handler which can be used to control the service's
1936 * availability. When clients connect or disconnect, the respective
1937 * @a connect_cb or @a disconnect_cb functions will be called. For
1938 * messages received from the clients, the respective @a handlers will
1939 * be invoked; for the closure of the handlers we use the return value
1940 * from the @a connect_cb invocation of the respective client.
1941 *
1942 * Each handler MUST call #GNUNET_SERVICE_client_continue() after each
1943 * message to receive further messages from this client. If
1944 * #GNUNET_SERVICE_client_continue() is not called within a short
1945 * time, a warning will be logged. If delays are expected, services
1946 * should call #GNUNET_SERVICE_client_disable_continue_warning() to
1947 * disable the warning.
1948 *
1949 * Clients sending invalid messages (based on @a handlers) will be
1950 * dropped. Additionally, clients can be dropped at any time using
1951 * #GNUNET_SERVICE_client_drop().
1952 *
1953 * @param argc number of command-line arguments in @a argv
1954 * @param argv array of command-line arguments
1955 * @param service_name name of the service to run
1956 * @param options options controlling shutdown of the service
1957 * @param service_init_cb function to call once the service is ready
1958 * @param connect_cb function to call whenever a client connects
1959 * @param disconnect_cb function to call whenever a client disconnects
1960 * @param cls closure argument for @a service_init_cb, @a connect_cb and @a disconnect_cb
1961 * @param handlers NULL-terminated array of message handlers for the service,
1962 * the closure will be set to the value returned by
1963 * the @a connect_cb for the respective connection
1964 * @return 0 on success, non-zero on error
1965 */
1966int
1967GNUNET_SERVICE_run_ (int argc,
1968 char *const *argv,
1969 const char *service_name,
1970 enum GNUNET_SERVICE_Options options,
1971 GNUNET_SERVICE_InitCallback service_init_cb,
1972 GNUNET_SERVICE_ConnectHandler connect_cb,
1973 GNUNET_SERVICE_DisconnectHandler disconnect_cb,
1974 void *cls,
1975 const struct GNUNET_MQ_MessageHandler *handlers)
1976{
1977 struct GNUNET_SERVICE_Handle sh;
1978
1979#if ENABLE_NLS
1980 char *path;
1981#endif
1982 char *cfg_filename;
1983 char *opt_cfg_filename;
1984 char *loglev;
1985 const char *xdg;
1986 char *logfile;
1987 int do_daemonize;
1988 unsigned long long skew_offset;
1989 unsigned long long skew_variance;
1990 long long clock_offset;
1991 struct GNUNET_CONFIGURATION_Handle *cfg;
1992 int ret;
1993 int err;
1994 const struct GNUNET_OS_ProjectData *pd = GNUNET_OS_project_data_get ();
1995 struct GNUNET_GETOPT_CommandLineOption service_options[] = {
1996 GNUNET_GETOPT_option_cfgfile (&opt_cfg_filename),
1997 GNUNET_GETOPT_option_flag ('d',
1998 "daemonize",
1999 gettext_noop (
2000 "do daemonize (detach from terminal)"),
2001 &do_daemonize),
2002 GNUNET_GETOPT_option_help (NULL),
2003 GNUNET_GETOPT_option_loglevel (&loglev),
2004 GNUNET_GETOPT_option_logfile (&logfile),
2005 GNUNET_GETOPT_option_version (pd->version),
2006 GNUNET_GETOPT_OPTION_END
2007 };
2008
2009 err = 1;
2010 memset (&sh, 0, sizeof(sh));
2011 xdg = getenv ("XDG_CONFIG_HOME");
2012 if (NULL != xdg)
2013 GNUNET_asprintf (&cfg_filename,
2014 "%s%s%s",
2015 xdg,
2016 DIR_SEPARATOR_STR,
2017 pd->config_file);
2018 else
2019 cfg_filename = GNUNET_strdup (pd->user_config_file);
2020 sh.ready_confirm_fd = -1;
2021 sh.options = options;
2022 sh.cfg = cfg = GNUNET_CONFIGURATION_create ();
2023 sh.service_init_cb = service_init_cb;
2024 sh.connect_cb = connect_cb;
2025 sh.disconnect_cb = disconnect_cb;
2026 sh.cb_cls = cls;
2027 sh.handlers = (NULL == pd->agpl_url)
2028 ? GNUNET_MQ_copy_handlers (handlers)
2029 : GNUNET_MQ_copy_handlers2 (handlers, &return_agpl, NULL);
2030 sh.service_name = service_name;
2031 sh.ret = 0;
2032 /* setup subsystems */
2033 loglev = NULL;
2034 logfile = NULL;
2035 opt_cfg_filename = NULL;
2036 do_daemonize = 0;
2037#if ENABLE_NLS
2038 if (NULL != pd->gettext_domain)
2039 {
2040 setlocale (LC_ALL, "");
2041 path = (NULL == pd->gettext_path) ?
2042 GNUNET_OS_installation_get_path (GNUNET_OS_IPK_LOCALEDIR) :
2043 GNUNET_strdup (pd->gettext_path);
2044 if (NULL != path)
2045 {
2046 bindtextdomain (pd->gettext_domain, path);
2047 GNUNET_free (path);
2048 }
2049 textdomain (pd->gettext_domain);
2050 }
2051#endif
2052 ret = GNUNET_GETOPT_run (service_name,
2053 service_options,
2054 argc,
2055 argv);
2056 if (GNUNET_SYSERR == ret)
2057 goto shutdown;
2058 if (GNUNET_NO == ret)
2059 {
2060 err = 0;
2061 goto shutdown;
2062 }
2063 if (GNUNET_OK != GNUNET_log_setup (service_name,
2064 loglev,
2065 logfile))
2066 {
2067 GNUNET_break (0);
2068 goto shutdown;
2069 }
2070 if (NULL != opt_cfg_filename)
2071 {
2072 if ((GNUNET_YES != GNUNET_DISK_file_test (opt_cfg_filename)) ||
2073 (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, opt_cfg_filename)))
2074 {
2075 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2076 _ ("Malformed configuration file `%s', exit ...\n"),
2077 opt_cfg_filename);
2078 goto shutdown;
2079 }
2080 }
2081 else
2082 {
2083 if (GNUNET_YES == GNUNET_DISK_file_test (cfg_filename))
2084 {
2085 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, cfg_filename))
2086 {
2087 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2088 _ ("Malformed configuration file `%s', exit ...\n"),
2089 cfg_filename);
2090 goto shutdown;
2091 }
2092 }
2093 else
2094 {
2095 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, NULL))
2096 {
2097 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2098 _ ("Malformed configuration, exit ...\n"));
2099 goto shutdown;
2100 }
2101 }
2102 }
2103 if (GNUNET_OK != setup_service (&sh))
2104 goto shutdown;
2105 if ((1 == do_daemonize) && (GNUNET_OK != detach_terminal (&sh)))
2106 {
2107 GNUNET_break (0);
2108 goto shutdown;
2109 }
2110 if (GNUNET_OK != set_user_id (&sh))
2111 goto shutdown;
2112 LOG (GNUNET_ERROR_TYPE_DEBUG,
2113 "Service `%s' runs with configuration from `%s'\n",
2114 service_name,
2115 (NULL != opt_cfg_filename) ? opt_cfg_filename : cfg_filename);
2116 if ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (sh.cfg,
2117 "TESTING",
2118 "SKEW_OFFSET",
2119 &skew_offset)) &&
2120 (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (sh.cfg,
2121 "TESTING",
2122 "SKEW_VARIANCE",
2123 &skew_variance)))
2124 {
2125 clock_offset = skew_offset - skew_variance;
2126 GNUNET_TIME_set_offset (clock_offset);
2127 LOG (GNUNET_ERROR_TYPE_DEBUG,
2128 "Skewing clock by %lld ms\n",
2129 (long long) clock_offset);
2130 }
2131 GNUNET_RESOLVER_connect (sh.cfg);
2132
2133 /* actually run service */
2134 err = 0;
2135 GNUNET_SCHEDULER_run (&service_main, &sh);
2136 /* shutdown */
2137 if (1 == do_daemonize)
2138 pid_file_delete (&sh);
2139
2140shutdown:
2141 if (-1 != sh.ready_confirm_fd)
2142 {
2143 if (1 != write (sh.ready_confirm_fd, err ? "I" : "S", 1))
2144 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "write");
2145 GNUNET_break (0 == close (sh.ready_confirm_fd));
2146 }
2147#if HAVE_MALLINFO2
2148 {
2149 char *counter;
2150
2151 if ((GNUNET_YES == GNUNET_CONFIGURATION_have_value (sh.cfg,
2152 service_name,
2153 "GAUGER_HEAP")) &&
2154 (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (sh.cfg,
2155 service_name,
2156 "GAUGER_HEAP",
2157 &counter)))
2158 {
2159 struct mallinfo2 mi;
2160
2161 mi = mallinfo2 ();
2162 GAUGER (service_name, counter, mi.usmblks, "blocks");
2163 GNUNET_free (counter);
2164 }
2165 }
2166#endif
2167 teardown_service (&sh);
2168 GNUNET_free (sh.handlers);
2169 GNUNET_SPEEDUP_stop_ ();
2170 GNUNET_CONFIGURATION_destroy (cfg);
2171 GNUNET_free (logfile);
2172 GNUNET_free (loglev);
2173 GNUNET_free (cfg_filename);
2174 GNUNET_free (opt_cfg_filename);
2175
2176 return err ? GNUNET_SYSERR : sh.ret;
2177}
2178
2179
2180/**
2181 * Suspend accepting connections from the listen socket temporarily.
2182 * Resume activity using #GNUNET_SERVICE_resume.
2183 *
2184 * @param sh service to stop accepting connections.
2185 */
2186void
2187GNUNET_SERVICE_suspend (struct GNUNET_SERVICE_Handle *sh)
2188{
2189 do_suspend (sh, SUSPEND_STATE_APP);
2190}
2191
2192
2193/**
2194 * Resume accepting connections from the listen socket.
2195 *
2196 * @param sh service to resume accepting connections.
2197 */
2198void
2199GNUNET_SERVICE_resume (struct GNUNET_SERVICE_Handle *sh)
2200{
2201 do_resume (sh, SUSPEND_STATE_APP);
2202}
2203
2204
2205/**
2206 * Task run to resume receiving data from the client after
2207 * the client called #GNUNET_SERVICE_client_continue().
2208 *
2209 * @param cls our `struct GNUNET_SERVICE_Client`
2210 */
2211static void
2212resume_client_receive (void *cls)
2213{
2214 struct GNUNET_SERVICE_Client *c = cls;
2215 int ret;
2216
2217 c->recv_task = NULL;
2218 /* first, check if there is still something in the buffer */
2219 ret = GNUNET_MST_next (c->mst, GNUNET_YES);
2220 if (GNUNET_SYSERR == ret)
2221 {
2222 if (NULL == c->drop_task)
2223 GNUNET_SERVICE_client_drop (c);
2224 return;
2225 }
2226 if (GNUNET_NO == ret)
2227 return; /* done processing, wait for more later */
2228 GNUNET_assert (GNUNET_OK == ret);
2229 if (GNUNET_YES == c->needs_continue)
2230 return; /* #GNUNET_MST_next() did give a message to the client */
2231 /* need to receive more data from the network first */
2232 if (NULL != c->recv_task)
2233 return;
2234 c->recv_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
2235 c->sock,
2236 &service_client_recv,
2237 c);
2238}
2239
2240
2241/**
2242 * Continue receiving further messages from the given client.
2243 * Must be called after each message received.
2244 *
2245 * @param c the client to continue receiving from
2246 */
2247void
2248GNUNET_SERVICE_client_continue (struct GNUNET_SERVICE_Client *c)
2249{
2250 GNUNET_assert (NULL == c->drop_task);
2251 GNUNET_assert (GNUNET_YES == c->needs_continue);
2252 GNUNET_assert (NULL == c->recv_task);
2253 c->needs_continue = GNUNET_NO;
2254 if (NULL != c->warn_task)
2255 {
2256 GNUNET_SCHEDULER_cancel (c->warn_task);
2257 c->warn_task = NULL;
2258 }
2259 c->recv_task = GNUNET_SCHEDULER_add_now (&resume_client_receive, c);
2260}
2261
2262
2263/**
2264 * Disable the warning the server issues if a message is not
2265 * acknowledged in a timely fashion. Use this call if a client is
2266 * intentionally delayed for a while. Only applies to the current
2267 * message.
2268 *
2269 * @param c client for which to disable the warning
2270 */
2271void
2272GNUNET_SERVICE_client_disable_continue_warning (struct GNUNET_SERVICE_Client *c)
2273{
2274 GNUNET_break (NULL != c->warn_task);
2275 if (NULL != c->warn_task)
2276 {
2277 GNUNET_SCHEDULER_cancel (c->warn_task);
2278 c->warn_task = NULL;
2279 }
2280}
2281
2282
2283/**
2284 * Asynchronously finish dropping the client.
2285 *
2286 * @param cls the `struct GNUNET_SERVICE_Client`.
2287 */
2288static void
2289finish_client_drop (void *cls)
2290{
2291 struct GNUNET_SERVICE_Client *c = cls;
2292 struct GNUNET_SERVICE_Handle *sh = c->sh;
2293
2294 c->drop_task = NULL;
2295 GNUNET_assert (NULL == c->send_task);
2296 GNUNET_assert (NULL == c->recv_task);
2297 GNUNET_assert (NULL == c->warn_task);
2298 GNUNET_MST_destroy (c->mst);
2299 GNUNET_MQ_destroy (c->mq);
2300 if (GNUNET_NO == c->persist)
2301 {
2302 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (c->sock));
2303 if ((0 != (SUSPEND_STATE_EMFILE & sh->suspend_state)) &&
2304 (0 == (SUSPEND_STATE_SHUTDOWN & sh->suspend_state)))
2305 do_resume (sh, SUSPEND_STATE_EMFILE);
2306 }
2307 else
2308 {
2309 GNUNET_NETWORK_socket_free_memory_only_ (c->sock);
2310 }
2311 GNUNET_free (c);
2312 if ((0 != (SUSPEND_STATE_SHUTDOWN & sh->suspend_state)) &&
2313 (GNUNET_NO == have_non_monitor_clients (sh)))
2314 GNUNET_SERVICE_shutdown (sh);
2315}
2316
2317
2318/**
2319 * Ask the server to disconnect from the given client. This is the
2320 * same as returning #GNUNET_SYSERR within the check procedure when
2321 * handling a message, wexcept that it allows dropping of a client even
2322 * when not handling a message from that client. The `disconnect_cb`
2323 * will be called on @a c even if the application closes the connection
2324 * using this function.
2325 *
2326 * @param c client to disconnect now
2327 */
2328void
2329GNUNET_SERVICE_client_drop (struct GNUNET_SERVICE_Client *c)
2330{
2331 struct GNUNET_SERVICE_Handle *sh = c->sh;
2332
2333 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2334 "Client dropped: %p (MQ: %p)\n",
2335 c,
2336 c->mq);
2337#if EXECINFO
2338 {
2339 void *backtrace_array[MAX_TRACE_DEPTH];
2340 int num_backtrace_strings = backtrace (backtrace_array, MAX_TRACE_DEPTH);
2341 char **backtrace_strings =
2342 backtrace_symbols (backtrace_array, t->num_backtrace_strings);
2343 for (unsigned int i = 0; i < num_backtrace_strings; i++)
2344 LOG (GNUNET_ERROR_TYPE_DEBUG,
2345 "client drop trace %u: %s\n",
2346 i,
2347 backtrace_strings[i]);
2348 }
2349#endif
2350 if (NULL != c->drop_task)
2351 {
2352 /* asked to drop twice! */
2353 GNUNET_assert (0);
2354 return;
2355 }
2356 GNUNET_CONTAINER_DLL_remove (sh->clients_head,
2357 sh->clients_tail,
2358 c);
2359 if (NULL != sh->disconnect_cb)
2360 sh->disconnect_cb (sh->cb_cls,
2361 c,
2362 c->user_context);
2363 if (NULL != c->warn_task)
2364 {
2365 GNUNET_SCHEDULER_cancel (c->warn_task);
2366 c->warn_task = NULL;
2367 }
2368 if (NULL != c->recv_task)
2369 {
2370 GNUNET_SCHEDULER_cancel (c->recv_task);
2371 c->recv_task = NULL;
2372 }
2373 if (NULL != c->send_task)
2374 {
2375 GNUNET_SCHEDULER_cancel (c->send_task);
2376 c->send_task = NULL;
2377 }
2378 c->drop_task = GNUNET_SCHEDULER_add_now (&finish_client_drop, c);
2379}
2380
2381
2382/**
2383 * Explicitly stops the service.
2384 *
2385 * @param sh server to shutdown
2386 */
2387void
2388GNUNET_SERVICE_shutdown (struct GNUNET_SERVICE_Handle *sh)
2389{
2390 struct GNUNET_SERVICE_Client *client;
2391
2392 if (0 == (sh->suspend_state & SUSPEND_STATE_SHUTDOWN))
2393 do_suspend (sh, SUSPEND_STATE_SHUTDOWN);
2394 while (NULL != (client = sh->clients_head))
2395 GNUNET_SERVICE_client_drop (client);
2396}
2397
2398
2399/**
2400 * Set the 'monitor' flag on this client. Clients which have been
2401 * marked as 'monitors' won't prevent the server from shutting down
2402 * once #GNUNET_SERVICE_stop_listening() has been invoked. The idea is
2403 * that for "normal" clients we likely want to allow them to process
2404 * their requests; however, monitor-clients are likely to 'never'
2405 * disconnect during shutdown and thus will not be considered when
2406 * determining if the server should continue to exist after
2407 * shutdown has been triggered.
2408 *
2409 * @param c client to mark as a monitor
2410 */
2411void
2412GNUNET_SERVICE_client_mark_monitor (struct GNUNET_SERVICE_Client *c)
2413{
2414 c->is_monitor = GNUNET_YES;
2415 if (((0 != (SUSPEND_STATE_SHUTDOWN & c->sh->suspend_state)) &&
2416 (GNUNET_NO == have_non_monitor_clients (c->sh))))
2417 GNUNET_SERVICE_shutdown (c->sh);
2418}
2419
2420
2421/**
2422 * Set the persist option on this client. Indicates that the
2423 * underlying socket or fd should never really be closed. Used for
2424 * indicating process death.
2425 *
2426 * @param c client to persist the socket (never to be closed)
2427 */
2428void
2429GNUNET_SERVICE_client_persist (struct GNUNET_SERVICE_Client *c)
2430{
2431 c->persist = GNUNET_YES;
2432}
2433
2434
2435/**
2436 * Obtain the message queue of @a c. Convenience function.
2437 *
2438 * @param c the client to continue receiving from
2439 * @return the message queue of @a c
2440 */
2441struct GNUNET_MQ_Handle *
2442GNUNET_SERVICE_client_get_mq (struct GNUNET_SERVICE_Client *c)
2443{
2444 return c->mq;
2445}
2446
2447
2448/* end of service.c */