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