GNUnet debian-0.24.3-28-g4f2a77692
 
Loading...
Searching...
No Matches
service.c File Reference

functions related to starting services (redesign) More...

#include "platform.h"
#include "gnunet_util_lib.h"
#include "gnunet_protocols.h"
#include "gnunet_constants.h"
#include "gnunet_resolver_service.h"
#include "speedup.h"
Include dependency graph for service.c:

Go to the source code of this file.

Data Structures

struct  ServiceListenContext
 Information the service tracks per listen operation. More...
 
struct  GNUNET_SERVICE_Handle
 Handle to a service. More...
 
struct  GNUNET_SERVICE_Client
 Handle to a client that is connected to a service. More...
 
struct  ServiceHandleList
 A list of service to be launched when GNUNET_SERVICE_main() is called. More...
 
struct  LaunchContext
 

Macros

#define LOG(kind, ...)   GNUNET_log_from (kind, "util-service", __VA_ARGS__)
 
#define LOG_STRERROR(kind, syscall)    GNUNET_log_from_strerror (kind, "util-service", syscall)
 
#define LOG_STRERROR_FILE(kind, syscall, filename)    GNUNET_log_from_strerror_file (kind, "util-service", syscall, filename)
 

Enumerations

enum  SuspendReason {
  SUSPEND_STATE_NONE = 0 , SUSPEND_STATE_APP = 1 , SUSPEND_STATE_EMFILE = 2 , SUSPEND_STATE_APP_AND_EMFILE = 3 ,
  SUSPEND_STATE_SHUTDOWN = 4
}
 Reasons why we might be suspended. More...
 

Functions

static enum GNUNET_GenericReturnValue have_non_monitor_clients (struct GNUNET_SERVICE_Handle *sh)
 Check if any of the clients we have left are unrelated to monitoring.
 
static void do_suspend (struct GNUNET_SERVICE_Handle *sh, enum SuspendReason sr)
 Suspend accepting connections from the listen socket temporarily.
 
static void service_shutdown (void *cls)
 Shutdown task triggered when a service should be terminated.
 
static bool check_ipv4_listed (const struct GNUNET_STRINGS_IPv4NetworkPolicy *list, const struct in_addr *add)
 Check if the given IP address is in the list of IP addresses.
 
static bool check_ipv6_listed (const struct GNUNET_STRINGS_IPv6NetworkPolicy *list, const struct in6_addr *ip)
 Check if the given IP address is in the list of IP addresses.
 
static void do_send (void *cls)
 Task run when we are ready to transmit data to the client.
 
static void service_mq_send (struct GNUNET_MQ_Handle *mq, const struct GNUNET_MessageHeader *msg, void *impl_state)
 Signature of functions implementing the sending functionality of a message queue.
 
static void service_mq_cancel (struct GNUNET_MQ_Handle *mq, void *impl_state)
 Implementation function that cancels the currently sent message.
 
static void service_mq_error_handler (void *cls, enum GNUNET_MQ_Error error)
 Generic error handler, called with the appropriate error code and the same closure specified at the creation of the message queue.
 
static void warn_no_client_continue (void *cls)
 Task run to warn about missing calls to GNUNET_SERVICE_client_continue().
 
static int service_client_mst_cb (void *cls, const struct GNUNET_MessageHeader *message)
 Functions with this signature are called whenever a complete message is received by the tokenizer for a client.
 
static void service_client_recv (void *cls)
 A client sent us data.
 
static void start_client (struct GNUNET_SERVICE_Handle *sh, struct GNUNET_NETWORK_Handle *csock)
 We have successfully accepted a connection from a client.
 
static void accept_client (void *cls)
 We have a client.
 
static void do_resume (struct GNUNET_SERVICE_Handle *sh, enum SuspendReason sr)
 Resume accepting connections from the listen socket.
 
static void service_main (void *cls)
 First task run by any service.
 
static enum GNUNET_GenericReturnValue process_acl4 (struct GNUNET_STRINGS_IPv4NetworkPolicy **ret, struct GNUNET_SERVICE_Handle *sh, const char *option)
 Parse an IPv4 access control list.
 
static enum GNUNET_GenericReturnValue process_acl6 (struct GNUNET_STRINGS_IPv6NetworkPolicy **ret, struct GNUNET_SERVICE_Handle *sh, const char *option)
 Parse an IPv6 access control list.
 
static void add_unixpath (struct sockaddr **saddrs, socklen_t *saddrlens, const char *unixpath)
 Add the given UNIX domain path as an address to the list (as the first entry).
 
static int get_server_addresses (const char *service_name, const struct GNUNET_CONFIGURATION_Handle *cfg, struct sockaddr ***addrs, socklen_t **addr_lens)
 Get the list of addresses that a server for the given service should bind to.
 
static struct GNUNET_NETWORK_Handleopen_listen_socket (const struct sockaddr *server_addr, socklen_t socklen)
 Create and initialize a listen socket for the server.
 
static enum GNUNET_GenericReturnValue setup_service (const struct GNUNET_OS_ProjectData *pd, struct GNUNET_SERVICE_Handle *sh)
 Setup service handle.
 
static char * get_user_name (struct GNUNET_SERVICE_Handle *sh)
 Get the name of the user that'll be used to provide the service.
 
static enum GNUNET_GenericReturnValue set_user_id (struct GNUNET_SERVICE_Handle *sh)
 Set user ID.
 
static char * get_pid_file_name (struct GNUNET_SERVICE_Handle *sh)
 Get the name of the file where we will write the PID of the service.
 
static void pid_file_delete (struct GNUNET_SERVICE_Handle *sh)
 Delete the PID file that was created by our parent.
 
static enum GNUNET_GenericReturnValue detach_terminal (struct GNUNET_SERVICE_Handle *sh)
 Detach from terminal.
 
static void teardown_service (struct GNUNET_SERVICE_Handle *sh)
 Tear down the service, closing the listen sockets and freeing the ACLs.
 
static void return_agpl (void *cls, const struct GNUNET_MessageHeader *msg)
 Function to return link to AGPL source upon request.
 
struct GNUNET_SERVICE_HandleGNUNET_SERVICE_start (const struct GNUNET_OS_ProjectData *pd, const char *service_name, const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_SERVICE_ConnectHandler connect_cb, GNUNET_SERVICE_DisconnectHandler disconnect_cb, void *cls, const struct GNUNET_MQ_MessageHandler *handlers)
 Low-level function to start a service if the scheduler is already running.
 
static void finish_client_drop (void *cls)
 Asynchronously finish dropping the client.
 
void GNUNET_SERVICE_stop (struct GNUNET_SERVICE_Handle *srv)
 Stops a service that was started with GNUNET_SERVICE_start().
 
int GNUNET_SERVICE_run_ (const struct GNUNET_OS_ProjectData *pd, int argc, char *const *argv, const char *service_name, enum GNUNET_SERVICE_Options options, GNUNET_SERVICE_InitCallback service_init_cb, GNUNET_SERVICE_ConnectHandler connect_cb, GNUNET_SERVICE_DisconnectHandler disconnect_cb, void *cls, const struct GNUNET_MQ_MessageHandler *handlers)
 Creates the "main" function for a GNUnet service.
 
int GNUNET_SERVICE_register_ (const struct GNUNET_OS_ProjectData *pd, const char *service_name, enum GNUNET_SERVICE_Options options, GNUNET_SERVICE_InitCallback service_init_cb, GNUNET_SERVICE_ConnectHandler connect_cb, GNUNET_SERVICE_DisconnectHandler disconnect_cb, void *cls, const struct GNUNET_MQ_MessageHandler *handlers)
 Registers the GNUnet service to be scheduled as part of a monilithic libgnunet.
 
static void do_registered_services_shutdown (void *cls)
 
static void launch_registered_services (void *cls)
 
void GNUNET_SERVICE_main (const struct GNUNET_OS_ProjectData *pd, int argc, char *const *argv, struct GNUNET_CONFIGURATION_Handle *cfg, enum GNUNET_GenericReturnValue with_scheduler)
 Run the mainloop in a monolithic libgnunet.
 
void GNUNET_SERVICE_suspend (struct GNUNET_SERVICE_Handle *sh)
 Suspend accepting connections from the listen socket temporarily.
 
void GNUNET_SERVICE_resume (struct GNUNET_SERVICE_Handle *sh)
 Resume accepting connections from the listen socket.
 
static void resume_client_receive (void *cls)
 Task run to resume receiving data from the client after the client called GNUNET_SERVICE_client_continue().
 
void GNUNET_SERVICE_client_continue (struct GNUNET_SERVICE_Client *c)
 Continue receiving further messages from the given client.
 
void GNUNET_SERVICE_client_disable_continue_warning (struct GNUNET_SERVICE_Client *c)
 Disable the warning the server issues if a message is not acknowledged in a timely fashion.
 
void GNUNET_SERVICE_client_drop (struct GNUNET_SERVICE_Client *c)
 Ask the server to disconnect from the given client.
 
void GNUNET_SERVICE_shutdown (struct GNUNET_SERVICE_Handle *sh)
 Explicitly stops the service.
 
void GNUNET_SERVICE_client_mark_monitor (struct GNUNET_SERVICE_Client *c)
 Set the 'monitor' flag on this client.
 
void GNUNET_SERVICE_client_persist (struct GNUNET_SERVICE_Client *c)
 Set the persist option on this client.
 
struct GNUNET_MQ_HandleGNUNET_SERVICE_client_get_mq (struct GNUNET_SERVICE_Client *c)
 Obtain the message queue of c.
 

Variables

static struct ServiceHandleListhll_head
 
static struct ServiceHandleListhll_tail
 

Detailed Description

functions related to starting services (redesign)

Author
Christian Grothoff
Florian Dold

Definition in file service.c.

Macro Definition Documentation

◆ LOG

#define LOG (   kind,
  ... 
)    GNUNET_log_from (kind, "util-service", __VA_ARGS__)

Definition at line 39 of file service.c.

◆ LOG_STRERROR

#define LOG_STRERROR (   kind,
  syscall 
)     GNUNET_log_from_strerror (kind, "util-service", syscall)

Definition at line 41 of file service.c.

51{
56
61
66
70 struct GNUNET_NETWORK_Handle *listen_socket;
71
75 struct GNUNET_SCHEDULER_Task *listen_task;
76};
77
78
83{
88
93
98
103
108};
109
110
115{
119 const struct GNUNET_CONFIGURATION_Handle *cfg;
120
124 const struct GNUNET_OS_ProjectData *pd;
125
129 const char *service_name;
130
135
140
145
149 void *cb_cls;
150
155
160
165
170
175
179 void *task_cls;
180
185
190
196
202
208 int match_uid;
209
217 int match_gid;
218
223
228
235
240 bool require_found;
241};
242
243
248{
253
258
263
268
272 struct GNUNET_MQ_Handle *mq;
273
278
284
290
296
301
305 const struct GNUNET_MessageHeader *msg;
306
311 void *user_context;
312
318
322 size_t msg_pos;
323
329 bool persist;
330
336 bool is_monitor;
337
341 bool needs_continue;
342
346 uint16_t warn_type;
347};
348
349
359{
360 for (struct GNUNET_SERVICE_Client *client = sh->clients_head;
361 NULL != client;
362 client = client->next)
363 {
364 if (NULL != client->drop_task)
365 continue;
366 if (client->is_monitor)
367 continue;
368 return true;
369 }
370 return false;
371}
372
373
381static void
383 enum SuspendReason sr)
384{
385 GNUNET_assert (0 == (sh->suspend_state & sr));
386 sh->suspend_state |= sr;
387 for (struct ServiceListenContext *slc = sh->slc_head;
388 NULL != slc;
389 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
408static void
409service_shutdown (void *cls)
410{
411 struct GNUNET_SERVICE_Handle *sh = cls;
412
414 {
417 break;
419 /* This task should never be run if we are using
420 the manual shutdown. */
421 GNUNET_assert (0);
422 break;
424 if (0 == (sh->suspend_state & SUSPEND_STATE_SHUTDOWN))
428 break;
429 }
430}
431
432
440static bool
442 const struct in_addr *add)
443{
444 for (unsigned int i = 0;
445 0 != list[i].network.s_addr;
446 i++)
447 {
448 if ( (add->s_addr & list[i].netmask.s_addr) ==
449 (list[i].network.s_addr & list[i].netmask.s_addr) )
450 return true;
451 }
452 return false;
453}
454
455
463static bool
465 const struct in6_addr *ip)
466{
467 for (unsigned int i = 0;
468 ! GNUNET_is_zero (&list[i].network);
469 i++)
470 {
471 bool match = true;
472
473 for (unsigned int j = 0; j < sizeof(struct in6_addr) / sizeof(int); j++)
474 if (((((int *) ip)[j] & ((int *) &list[i].netmask)[j])) !=
475 (((int *) &list[i].network)[j] & ((int *) &list[i].netmask)[j]))
476 {
477 match = false;
478 break;
479 }
480 if (match)
481 return true;
482 }
483 return false;
484}
485
486
493static void
494do_send (void *cls)
495{
496 struct GNUNET_SERVICE_Client *client = cls;
497 ssize_t ret;
498 size_t left;
499 const char *buf;
500
502 "service: sending message with type %u\n",
503 ntohs (client->msg->type));
504 client->send_task = NULL;
505 buf = (const char *) client->msg;
506 left = ntohs (client->msg->size) - client->msg_pos;
508 &buf[client->msg_pos],
509 left);
510 GNUNET_assert (ret <= (ssize_t) left);
511 if (0 == ret)
512 {
513 LOG (GNUNET_ERROR_TYPE_DEBUG, "no data send");
515 return;
516 }
517 if (-1 == ret)
518 {
519 if ((EAGAIN == errno) || (EINTR == errno))
520 {
521 /* ignore */
522 ret = 0;
523 }
524 else
525 {
526 if (EPIPE != errno)
529 "socket send returned with error code %i",
530 errno);
532 return;
533 }
534 }
535 if (0 == client->msg_pos)
536 {
538 }
539 client->msg_pos += ret;
540 if (left > (size_t) ret)
541 {
542 GNUNET_assert (NULL == client->drop_task);
543 client->send_task =
545 client->sock,
546 &do_send,
547 client);
548 return;
549 }
551}
552
553
562static void
564 const struct GNUNET_MessageHeader *msg,
565 void *impl_state)
566{
567 struct GNUNET_SERVICE_Client *client = impl_state;
568
569 (void) mq;
570 if (NULL != client->drop_task)
571 return; /* we're going down right now, do not try to send */
572 GNUNET_assert (NULL == client->send_task);
574 "Sending message of type %u and size %u to client\n",
575 ntohs (msg->type),
576 ntohs (msg->size));
577 client->msg = msg;
578 client->msg_pos = 0;
580 client);
581}
582
583
590static void
592 void *impl_state)
593{
594 struct GNUNET_SERVICE_Client *client = impl_state;
595
596 (void) mq;
597 GNUNET_assert (0 == client->msg_pos);
598 client->msg = NULL;
600 client->send_task = NULL;
601}
602
603
613static void
614service_mq_error_handler (void *cls,
615 enum GNUNET_MQ_Error error)
616{
617 struct GNUNET_SERVICE_Client *client = cls;
618 struct GNUNET_SERVICE_Handle *sh = client->sh;
619
620 if ( (GNUNET_MQ_ERROR_NO_MATCH == error) &&
621 (! sh->require_found) )
622 {
624 "No handler for message of type %u found\n",
625 (unsigned int) client->warn_type);
627 return; /* ignore error */
628 }
630}
631
632
638static void
639warn_no_client_continue (void *cls)
640{
641 struct GNUNET_SERVICE_Client *client = cls;
642
644 0 !=
645 client->warn_type); /* type should never be 0 here, as we don't use 0 */
648 client);
649 LOG (
651 _ (
652 "Processing code for message of type %u did not call `GNUNET_SERVICE_client_continue' after %s\n"),
653 (unsigned int) client->warn_type,
655 client->warn_start),
656 GNUNET_YES));
657}
658
659
671static int
672service_client_mst_cb (void *cls,
673 const struct GNUNET_MessageHeader *message)
674{
675 struct GNUNET_SERVICE_Client *client = cls;
676
678 "Received message of type %u and size %u from client\n",
679 ntohs (message->type),
680 ntohs (message->size));
681 GNUNET_assert (! client->needs_continue);
682 client->needs_continue = true;
683 client->warn_type = ntohs (message->type);
685 GNUNET_assert (NULL == client->warn_task);
688 client);
689 GNUNET_MQ_inject_message (client->mq, message);
690 if (NULL != client->drop_task)
691 return GNUNET_SYSERR;
692 return GNUNET_OK;
693}
694
695
702static void
703service_client_recv (void *cls)
704{
705 struct GNUNET_SERVICE_Client *client = cls;
707
708 client->recv_task = NULL;
709 ret = GNUNET_MST_read (client->mst,
710 client->sock,
711 GNUNET_NO,
712 GNUNET_YES);
713 if (GNUNET_SYSERR == ret)
714 {
715 /* client closed connection (or IO error) */
716 if (NULL == client->drop_task)
717 {
718 GNUNET_assert (! client->needs_continue);
720 }
721 return;
722 }
723 if (GNUNET_NO == ret)
724 return; /* more messages in buffer, wait for application
725 to be done processing */
727 if (client->needs_continue)
728 return;
729 if (NULL != client->recv_task)
730 return;
731 /* MST needs more data, re-schedule read job */
732 client->recv_task =
734 client->sock,
736 client);
737}
738
739
747static void
749 struct GNUNET_NETWORK_Handle *csock)
750{
751 struct GNUNET_SERVICE_Client *client;
752
753 client = GNUNET_new (struct GNUNET_SERVICE_Client);
754 GNUNET_CONTAINER_DLL_insert (sh->clients_head,
755 sh->clients_tail,
756 client);
757 client->sh = sh;
758 client->sock = csock;
760 NULL,
762 client,
763 sh->handlers,
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);
770 client->recv_task =
772 client->sock,
774 client);
775}
776
777
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);
802 (struct sockaddr *) &sa,
803 &addrlen);
804 if (NULL == sock)
805 {
806 if (EMFILE == errno)
808 else if (EAGAIN != errno)
810 "accept");
811 break;
812 }
813 switch (sa.ss_family)
814 {
815 case AF_INET:
816 GNUNET_assert (addrlen == sizeof(struct sockaddr_in));
817 v4 = (const struct sockaddr_in *) &sa;
818 ok = (((NULL == sh->v4_allowed) ||
819 (check_ipv4_listed (sh->v4_allowed,
820 &v4->sin_addr))) &&
821 ((NULL == sh->v4_denied) ||
822 (! check_ipv4_listed (sh->v4_denied,
823 &v4->sin_addr))));
824 break;
825
826 case AF_INET6:
827 GNUNET_assert (addrlen == sizeof(struct sockaddr_in6));
828 v6 = (const struct sockaddr_in6 *) &sa;
829 ok = (((NULL == sh->v6_allowed) ||
830 (check_ipv6_listed (sh->v6_allowed,
831 &v6->sin6_addr))) &&
832 ((NULL == sh->v6_denied) ||
833 (! check_ipv6_listed (sh->v6_denied,
834 &v6->sin6_addr))));
835 break;
836
837 case AF_UNIX:
838 ok = GNUNET_OK; /* controlled using file-system ACL now */
839 break;
840
841 default:
843 _ ("Unknown address family %d\n"),
844 sa.ss_family);
845 return;
846 }
847 if (! ok)
848 {
850 "Service rejected incoming connection from %s due to policy.\n",
851 GNUNET_a2s ((const struct sockaddr *) &sa, addrlen));
853 continue;
854 }
856 "Service accepted incoming connection from %s.\n",
857 GNUNET_a2s ((const struct sockaddr *) &sa, addrlen));
858 start_client (slc->sh,
859 sock);
860 }
861 if (0 != sh->suspend_state)
862 return;
863 slc->listen_task =
865 slc->listen_socket,
867 slc);
868}
869
870
878static void
880 enum SuspendReason sr)
881{
882 GNUNET_assert ((SUSPEND_STATE_NONE == sr) || (0 != (sh->suspend_state & sr)));
883 sh->suspend_state -= sr;
884 if (SUSPEND_STATE_NONE != sh->suspend_state)
885 return;
886 for (struct ServiceListenContext *slc = sh->slc_head;
887 NULL != slc;
888 slc = slc->next)
889 {
890 GNUNET_assert (NULL == slc->listen_task);
891 slc->listen_task =
893 slc->listen_socket,
895 slc);
896 }
897}
898
899
907static void
908service_main (void *cls)
909{
910 struct GNUNET_SERVICE_Handle *sh = cls;
911
916
917 if (-1 != sh->ready_confirm_fd)
918 {
919 GNUNET_break (1 == write (sh->ready_confirm_fd, ".", 1));
920 GNUNET_break (0 == close (sh->ready_confirm_fd));
921 sh->ready_confirm_fd = -1;
922 }
923
924 if (NULL != sh->service_init_cb)
925 sh->service_init_cb (sh->cb_cls, sh->cfg, sh);
926}
927
928
941 const char *option)
942{
943 char *opt;
944
945 if (! GNUNET_CONFIGURATION_have_value (sh->cfg, sh->service_name, option))
946 {
947 *ret = NULL;
948 return GNUNET_OK;
949 }
952 sh->service_name,
953 option,
954 &opt));
955 if (NULL == (*ret = GNUNET_STRINGS_parse_ipv4_policy (opt)))
956 {
958 _ ("Could not parse IPv4 network specification `%s' for `%s:%s'\n"),
959 opt,
960 sh->service_name,
961 option);
962 GNUNET_free (opt);
963 return GNUNET_SYSERR;
964 }
965 GNUNET_free (opt);
966 return GNUNET_OK;
967}
968
969
982 const char *option)
983{
984 char *opt;
985
986 if (! GNUNET_CONFIGURATION_have_value (sh->cfg, sh->service_name, option))
987 {
988 *ret = NULL;
989 return GNUNET_OK;
990 }
993 sh->service_name,
994 option,
995 &opt));
996 if (NULL == (*ret = GNUNET_STRINGS_parse_ipv6_policy (opt)))
997 {
999 _ ("Could not parse IPv6 network specification `%s' for `%s:%s'\n"),
1000 opt,
1001 sh->service_name,
1002 option);
1003 GNUNET_free (opt);
1004 return GNUNET_SYSERR;
1005 }
1006 GNUNET_free (opt);
1007 return GNUNET_OK;
1008}
1009
1010
1019static void
1020add_unixpath (struct sockaddr **saddrs,
1021 socklen_t *saddrlens,
1022 const char *unixpath)
1023{
1024#ifdef AF_UNIX
1025 struct sockaddr_un *un;
1026
1027 un = GNUNET_new (struct sockaddr_un);
1028 un->sun_family = AF_UNIX;
1029 GNUNET_strlcpy (un->sun_path, unixpath, sizeof(un->sun_path));
1030#if HAVE_SOCKADDR_UN_SUN_LEN
1031 un->sun_len = (u_char) sizeof(struct sockaddr_un);
1032#endif
1033 *saddrs = (struct sockaddr *) un;
1034 *saddrlens = sizeof(struct sockaddr_un);
1035#else
1036 /* this function should never be called
1037 * unless AF_UNIX is defined! */
1038 GNUNET_assert (0);
1039#endif
1040}
1041
1042
1063static int
1065 const struct GNUNET_CONFIGURATION_Handle *cfg,
1066 struct sockaddr ***addrs,
1067 socklen_t **addr_lens)
1068{
1069 bool disablev6;
1070 struct GNUNET_NETWORK_Handle *desc;
1071 unsigned long long port;
1072 char *unixpath;
1073 struct addrinfo hints;
1074 struct addrinfo *res;
1075 struct addrinfo *pos;
1076 struct addrinfo *next;
1077 unsigned int i;
1078 int resi;
1079 int ret;
1080 struct sockaddr **saddrs;
1081 socklen_t *saddrlens;
1082 char *hostname;
1083
1084 *addrs = NULL;
1085 *addr_lens = NULL;
1086 desc = NULL;
1087 disablev6 = false;
1088 if ((GNUNET_NO ==
1089 GNUNET_NETWORK_test_pf (PF_INET6)) ||
1090 (GNUNET_YES ==
1093 "DISABLEV6")))
1094 disablev6 = true;
1095
1096 port = 0;
1097 if (GNUNET_SYSERR ==
1100 "PORT",
1101 &port))
1102 {
1104 _ ("Require valid port number for service `%s' in configuration!\n"),
1105 service_name);
1106 }
1107 if (port > 65535)
1108 {
1110 _ ("Require valid port number for service `%s' in configuration!\n"),
1111 service_name);
1112 return GNUNET_SYSERR;
1113 }
1114
1115 hostname = NULL;
1119 "BINDTO",
1120 &hostname));
1121
1122 unixpath = NULL;
1123#ifdef AF_UNIX
1124 if ( (GNUNET_OK ==
1127 "UNIXPATH",
1128 &unixpath)) &&
1129 (0 < strlen (unixpath)) )
1130 {
1131 /* probe UNIX support */
1132 struct sockaddr_un s_un;
1133
1134 if (strlen (unixpath) >= sizeof(s_un.sun_path))
1135 {
1137 "UNIXPATH `%s' too long, maximum length is %llu\n",
1138 unixpath,
1139 (unsigned long long) sizeof(s_un.sun_path));
1140 unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
1142 _ ("Using `%s' instead\n"),
1143 unixpath);
1144 }
1145 if (GNUNET_OK !=
1148 "mkdir",
1149 unixpath);
1150 }
1151 if (NULL != unixpath)
1152 {
1153 desc = GNUNET_NETWORK_socket_create (AF_UNIX,
1154 SOCK_STREAM,
1155 0);
1156 if (NULL == desc)
1157 {
1158 if ((ENOBUFS == errno) ||
1159 (ENOMEM == errno) ||
1160 (ENFILE == errno) ||
1161 (EACCES == errno))
1162 {
1164 "socket");
1165 GNUNET_free (hostname);
1166 GNUNET_free (unixpath);
1167 return GNUNET_SYSERR;
1168 }
1170 "Failed to create UNIX domain socket for service %s: %s\n",
1172 strerror (errno));
1173 GNUNET_free (unixpath);
1174 unixpath = NULL;
1175 }
1176 else
1177 {
1180 desc = NULL;
1181 }
1182 }
1183#endif
1184
1185 if ( (0 == port) &&
1186 (NULL == unixpath) )
1187 {
1189 "Have neither PORT nor UNIXPATH for service `%s', but one is required\n",
1190 service_name);
1191 GNUNET_free (hostname);
1192 return GNUNET_SYSERR;
1193 }
1194 if (0 == port)
1195 {
1196 saddrs = GNUNET_new_array (2, struct sockaddr *);
1197 saddrlens = GNUNET_new_array (2, socklen_t);
1198 add_unixpath (saddrs, saddrlens, unixpath);
1199 GNUNET_free (unixpath);
1200 GNUNET_free (hostname);
1201 *addrs = saddrs;
1202 *addr_lens = saddrlens;
1203 return 1;
1204 }
1205
1206 if (NULL != hostname)
1207 {
1209 "Resolving `%s' since that is where `%s' will bind to.\n",
1210 hostname,
1211 service_name);
1212 memset (&hints, 0, sizeof(struct addrinfo));
1213 if (disablev6)
1214 hints.ai_family = AF_INET;
1215 hints.ai_protocol = IPPROTO_TCP;
1216 if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
1217 (NULL == res))
1218 {
1220 _ ("Failed to resolve `%s': %s\n"),
1221 hostname,
1222 gai_strerror (ret));
1223 GNUNET_free (hostname);
1224 GNUNET_free (unixpath);
1225 return GNUNET_SYSERR;
1226 }
1227 next = res;
1228 i = 0;
1229 while (NULL != (pos = next))
1230 {
1231 next = pos->ai_next;
1232 if ((disablev6) && (pos->ai_family == AF_INET6))
1233 continue;
1234 i++;
1235 }
1236 if (0 == i)
1237 {
1239 _ ("Failed to find %saddress for `%s'.\n"),
1240 disablev6 ? "IPv4 " : "",
1241 hostname);
1242 freeaddrinfo (res);
1243 GNUNET_free (hostname);
1244 GNUNET_free (unixpath);
1245 return GNUNET_SYSERR;
1246 }
1247 resi = i;
1248 if (NULL != unixpath)
1249 resi++;
1250 saddrs = GNUNET_new_array (resi + 1, struct sockaddr *);
1251 saddrlens = GNUNET_new_array (resi + 1, socklen_t);
1252 i = 0;
1253 if (NULL != unixpath)
1254 {
1255 add_unixpath (saddrs, saddrlens, unixpath);
1256 i++;
1257 }
1258 next = res;
1259 while (NULL != (pos = next))
1260 {
1261 next = pos->ai_next;
1262 if ((disablev6) && (AF_INET6 == pos->ai_family))
1263 continue;
1264 if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol))
1265 continue; /* not TCP */
1266 if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
1267 continue; /* huh? */
1269 "Service `%s' will bind to `%s'\n",
1271 GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
1272 if (AF_INET == pos->ai_family)
1273 {
1274 GNUNET_assert (sizeof(struct sockaddr_in) == pos->ai_addrlen);
1275 saddrlens[i] = pos->ai_addrlen;
1276 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1277 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
1278 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1279 }
1280 else
1281 {
1282 GNUNET_assert (AF_INET6 == pos->ai_family);
1283 GNUNET_assert (sizeof(struct sockaddr_in6) == pos->ai_addrlen);
1284 saddrlens[i] = pos->ai_addrlen;
1285 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1286 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
1287 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
1288 }
1289 i++;
1290 }
1291 GNUNET_free (hostname);
1292 freeaddrinfo (res);
1293 resi = i;
1294 }
1295 else
1296 {
1297 /* will bind against everything, just set port */
1298 if (disablev6)
1299 {
1300 /* V4-only */
1301 resi = 1;
1302 if (NULL != unixpath)
1303 resi++;
1304 i = 0;
1305 saddrs = GNUNET_new_array (resi + 1, struct sockaddr *);
1306 saddrlens = GNUNET_new_array (resi + 1, socklen_t);
1307 if (NULL != unixpath)
1308 {
1309 add_unixpath (saddrs, saddrlens, unixpath);
1310 i++;
1311 }
1312 saddrlens[i] = sizeof(struct sockaddr_in);
1313 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1314#if HAVE_SOCKADDR_IN_SIN_LEN
1315 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
1316#endif
1317 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
1318 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1319 }
1320 else
1321 {
1322 /* dual stack */
1323 resi = 2;
1324 if (NULL != unixpath)
1325 resi++;
1326 saddrs = GNUNET_new_array (resi + 1, struct sockaddr *);
1327 saddrlens = GNUNET_new_array (resi + 1, socklen_t);
1328 i = 0;
1329 if (NULL != unixpath)
1330 {
1331 add_unixpath (saddrs, saddrlens, unixpath);
1332 i++;
1333 }
1334 saddrlens[i] = sizeof(struct sockaddr_in6);
1335 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1336#if HAVE_SOCKADDR_IN_SIN_LEN
1337 ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
1338#endif
1339 ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
1340 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
1341 i++;
1342 saddrlens[i] = sizeof(struct sockaddr_in);
1343 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1344#if HAVE_SOCKADDR_IN_SIN_LEN
1345 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
1346#endif
1347 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
1348 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1349 }
1350 }
1351 GNUNET_free (unixpath);
1352 *addrs = saddrs;
1353 *addr_lens = saddrlens;
1354 return resi;
1355}
1356
1357
1365static struct GNUNET_NETWORK_Handle *
1366open_listen_socket (const struct sockaddr *server_addr,
1367 socklen_t socklen)
1368{
1369 struct GNUNET_NETWORK_Handle *sock;
1370 uint16_t port;
1371 int eno;
1372
1373 switch (server_addr->sa_family)
1374 {
1375 case AF_INET:
1376 port = ntohs (((const struct sockaddr_in *) server_addr)->sin_port);
1377 break;
1378 case AF_INET6:
1379 port = ntohs (((const struct sockaddr_in6 *) server_addr)->sin6_port);
1380 break;
1381 case AF_UNIX:
1382 port = 0;
1383 break;
1384 default:
1385 GNUNET_break (0);
1386 port = 0;
1387 break;
1388 }
1389 sock = GNUNET_NETWORK_socket_create (server_addr->sa_family,
1390 SOCK_STREAM,
1391 0);
1392 if (NULL == sock)
1393 {
1395 "socket");
1396 errno = 0;
1397 return NULL;
1398 }
1399 /* bind the socket */
1400 if (GNUNET_OK !=
1402 server_addr,
1403 socklen))
1404 {
1405 eno = errno;
1406 if (EADDRINUSE != errno)
1407 {
1408 /* we don't log 'EADDRINUSE' here since an IPv4 bind may
1409 * fail if we already took the port on IPv6; if both IPv4 and
1410 * IPv6 binds fail, then our caller will log using the
1411 * errno preserved in 'eno' */
1412 if (0 != port)
1414 _ ("`%s' failed for port %d (%s).\n"),
1415 "bind",
1416 port,
1417 (AF_INET == server_addr->sa_family) ? "IPv4" : "IPv6");
1418 else
1420 eno = 0;
1421 }
1422 else
1423 {
1424 if (0 != port)
1426 _ ("`%s' failed for port %d (%s): address already in use\n"),
1427 "bind",
1428 port,
1429 (AF_INET == server_addr->sa_family) ? "IPv4" : "IPv6");
1430 else if (AF_UNIX == server_addr->sa_family)
1431 {
1433 _ ("`%s' failed for `%s': address already in use\n"),
1434 "bind",
1435 GNUNET_a2s (server_addr, socklen));
1436 }
1437 }
1439 errno = eno;
1440 return NULL;
1441 }
1442 if (GNUNET_OK != GNUNET_NETWORK_socket_listen (sock, 5))
1443 {
1446 errno = 0;
1447 return NULL;
1448 }
1449 if (0 != port)
1451 "Server starts to listen on port %u.\n",
1452 port);
1453 return sock;
1454}
1455
1456
1474static enum GNUNET_GenericReturnValue
1475setup_service (const struct GNUNET_OS_ProjectData *pd,
1476 struct GNUNET_SERVICE_Handle *sh)
1477{
1478 int tolerant;
1479 struct GNUNET_NETWORK_Handle **csocks = NULL;
1480 struct GNUNET_NETWORK_Handle **lsocks;
1481 const char *nfds;
1482 const char *fdns;
1483 unsigned int cnt;
1484 int flags;
1485 char dummy;
1486
1488 sh->service_name,
1489 "TOLERANT"))
1490 {
1491 if (GNUNET_SYSERR ==
1493 sh->service_name,
1494 "TOLERANT")))
1495 {
1497 _ ("Specified value for `%s' of service `%s' is invalid\n"),
1498 "TOLERANT",
1499 sh->service_name);
1500 return GNUNET_SYSERR;
1501 }
1502 }
1503 else
1504 tolerant = GNUNET_NO;
1505
1506 lsocks = NULL;
1507 errno = 0;
1508 if ( (NULL != (nfds = getenv ("LISTEN_FDS"))) &&
1509 (NULL != (fdns = getenv ("LISTEN_FDNAMES"))) &&
1510 (1 == sscanf (nfds,
1511 "%u%c",
1512 &cnt,
1513 &dummy)) &&
1514 (cnt > 0) &&
1515 (cnt < FD_SETSIZE) )
1516 {
1517 char *fdnames;
1518 unsigned int pos;
1519
1520 lsocks = GNUNET_new_array (cnt + 1,
1521 struct GNUNET_NETWORK_Handle *);
1522 fdnames = GNUNET_strdup (fdns);
1523 pos = 0;
1524 for (const char *tok = strtok (fdnames,
1525 ":");
1526 NULL != tok;
1527 tok = strtok (NULL, ":"))
1528 {
1529 unsigned int fd;
1530
1531 if (pos == cnt)
1532 {
1534 "More than LISTEN_FDS sockets given in LISTEN_FDNAMES\n");
1535 break;
1536 }
1537 if (1 != sscanf (tok,
1538 "%u%c",
1539 &fd,
1540 &dummy))
1541 {
1543 "Malformed socket given in LISTEN_FDNAMES than in LISTEN_FDS\n");
1544 break;
1545 }
1546 if (fd >= FD_SETSIZE)
1547 {
1549 "Socket given in LISTEN_FDNAMES outside of select()able range\n");
1550 break;
1551 }
1552 flags = fcntl ((int) fd,
1553 F_GETFD);
1554 if ((flags < 0) ||
1555 (0 != (flags & FD_CLOEXEC)) ||
1556 (NULL == (lsocks[pos] = GNUNET_NETWORK_socket_box_native ((int) fd))))
1557 {
1559 "Could not access pre-bound socket %u\n",
1560 fd);
1561 break;
1562 }
1563 pos++;
1564 }
1565 if (0 == pos)
1566 {
1567 for (unsigned int i=0; i<cnt; i++)
1569 GNUNET_NETWORK_socket_close (lsocks[i]));
1570 GNUNET_free (lsocks);
1571 }
1572 unsetenv ("LISTEN_FDS");
1573 cnt = pos;
1574 }
1575 if ( (0 != (GNUNET_SERVICE_OPTION_CLOSE_LSOCKS & sh->options)) &&
1576 (NULL != lsocks) )
1577 {
1578 csocks = lsocks;
1579 lsocks = NULL;
1580 }
1581
1582 if (NULL != lsocks)
1583 {
1584 /* listen only on inherited sockets if we have any */
1585 for (struct GNUNET_NETWORK_Handle **ls = lsocks; NULL != *ls; ls++)
1586 {
1587 struct ServiceListenContext *slc;
1588
1589 slc = GNUNET_new (struct ServiceListenContext);
1590 slc->sh = sh;
1591 slc->listen_socket = *ls;
1593 sh->slc_tail,
1594 slc);
1595 }
1596 GNUNET_free (lsocks);
1597 }
1598 else
1599 {
1600 struct sockaddr **addrs;
1601 socklen_t *addrlens;
1602 int num;
1603
1604 num = get_server_addresses (sh->service_name,
1605 sh->cfg,
1606 &addrs,
1607 &addrlens);
1608 if (GNUNET_SYSERR == num)
1609 {
1610 GNUNET_free (csocks);
1611 return GNUNET_SYSERR;
1612 }
1613
1614 for (int i = 0; i < num; i++)
1615 {
1616 struct ServiceListenContext *slc;
1617
1618 slc = GNUNET_new (struct ServiceListenContext);
1619 slc->sh = sh;
1620 slc->listen_socket = open_listen_socket (addrs[i],
1621 addrlens[i]);
1622 GNUNET_free (addrs[i]);
1623 if (NULL == slc->listen_socket)
1624 {
1626 GNUNET_free (slc);
1627 continue;
1628 }
1630 sh->slc_tail,
1631 slc);
1632 }
1633 GNUNET_free (addrlens);
1634 GNUNET_free (addrs);
1635 if ((0 != num) && (NULL == sh->slc_head))
1636 {
1637 /* All attempts to bind failed, hard failure */
1638 GNUNET_log (
1640 "Could not bind to any of the ports I was supposed to, refusing to run!\n");
1641 GNUNET_free (csocks);
1642 return GNUNET_SYSERR;
1643 }
1644 }
1645 if (NULL != csocks)
1646 {
1647 /* close inherited sockets to signal parent that we are ready */
1648 for (struct GNUNET_NETWORK_Handle **ls = csocks; NULL != *ls; ls++)
1650 GNUNET_free (csocks);
1651 }
1652 sh->require_found = (GNUNET_NO == tolerant);
1654 sh->service_name,
1655 "UNIX_MATCH_UID");
1657 sh->service_name,
1658 "UNIX_MATCH_GID");
1659 process_acl4 (&sh->v4_denied, sh, "REJECT_FROM");
1660 process_acl4 (&sh->v4_allowed, sh, "ACCEPT_FROM");
1661 process_acl6 (&sh->v6_denied, sh, "REJECT_FROM6");
1662 process_acl6 (&sh->v6_allowed, sh, "ACCEPT_FROM6");
1663 return GNUNET_OK;
1664}
1665
1666
1674static char *
1676{
1677 char *un;
1678
1679 if (GNUNET_OK !=
1681 sh->service_name,
1682 "USERNAME",
1683 &un))
1684 return NULL;
1685 return un;
1686}
1687
1688
1695static enum GNUNET_GenericReturnValue
1697{
1698 char *user;
1699 struct passwd *pws;
1700
1701 if (NULL == (user = get_user_name (sh)))
1702 return GNUNET_OK; /* keep */
1703 errno = 0;
1704 pws = getpwnam (user);
1705 if (NULL == pws)
1706 {
1708 _ ("Cannot obtain information about user `%s': %s\n"),
1709 user,
1710 errno == 0 ? _ ("No such user") : strerror (errno));
1711 GNUNET_free (user);
1712 return GNUNET_SYSERR;
1713 }
1714 if ((0 != setgid (pws->pw_gid)) || (0 != setegid (pws->pw_gid)) ||
1715#if HAVE_INITGROUPS
1716 (0 != initgroups (user, pws->pw_gid)) ||
1717#endif
1718 (0 != setuid (pws->pw_uid)) ||
1719 (0 != seteuid (pws->pw_uid)))
1720 {
1721 if ((0 != setregid (pws->pw_gid, pws->pw_gid)) ||
1722 (0 != setreuid (pws->pw_uid, pws->pw_uid)))
1723 {
1725 _ ("Cannot change user/group to `%s': %s\n"),
1726 user,
1727 strerror (errno));
1728 GNUNET_free (user);
1729 return GNUNET_SYSERR;
1730 }
1731 }
1732
1733 GNUNET_free (user);
1734 return GNUNET_OK;
1735}
1736
1737
1745static char *
1747{
1748 char *pif;
1749
1750 if (GNUNET_OK !=
1752 sh->service_name,
1753 "PIDFILE",
1754 &pif))
1755 return NULL;
1756 return pif;
1757}
1758
1759
1765static void
1767{
1768 char *pif = get_pid_file_name (sh);
1769
1770 if (NULL == pif)
1771 return; /* no PID file */
1772 if (0 != unlink (pif))
1774 "unlink",
1775 pif);
1776 GNUNET_free (pif);
1777}
1778
1779
1786static enum GNUNET_GenericReturnValue
1788{
1789 pid_t pid;
1790 int nullfd;
1791 int filedes[2];
1792
1793 if (0 != pipe (filedes))
1794 {
1796 "pipe");
1797 return GNUNET_SYSERR;
1798 }
1799 pid = fork ();
1800 if (pid < 0)
1801 {
1803 "fork");
1804 return GNUNET_SYSERR;
1805 }
1806 if (0 != pid)
1807 {
1808 /* Parent */
1809 char c;
1810
1811 GNUNET_break (0 == close (filedes[1]));
1812 c = 'X';
1813 if (1 != read (filedes[0], &c, sizeof(char)))
1815 "read");
1816 fflush (stdout);
1817 switch (c)
1818 {
1819 case '.':
1820 exit (0);
1821
1822 case 'I':
1824 _ ("Service process failed to initialize\n"));
1825 break;
1826
1827 case 'S':
1829 _ ("Service process could not initialize server function\n"));
1830 break;
1831
1832 case 'X':
1834 _ ("Service process failed to report status\n"));
1835 break;
1836 }
1837 exit (1); /* child reported error */
1838 }
1839 GNUNET_break (0 == close (0));
1840 GNUNET_break (0 == close (1));
1841 GNUNET_break (0 == close (filedes[0]));
1842 nullfd = open ("/dev/null", O_RDWR | O_APPEND);
1843 if (nullfd < 0)
1844 return GNUNET_SYSERR;
1845 /* set stdin/stdout to /dev/null */
1846 if ((dup2 (nullfd, 0) < 0) || (dup2 (nullfd, 1) < 0))
1847 {
1849 (void) close (nullfd);
1850 return GNUNET_SYSERR;
1851 }
1852 (void) close (nullfd);
1853 /* Detach from controlling terminal */
1854 pid = setsid ();
1855 if (-1 == pid)
1857 "setsid");
1858 sh->ready_confirm_fd = filedes[1];
1859
1860 return GNUNET_OK;
1861}
1862
1863
1870static void
1872{
1873 struct ServiceListenContext *slc;
1874
1875 GNUNET_free (sh->v4_denied);
1876 GNUNET_free (sh->v6_denied);
1877 GNUNET_free (sh->v4_allowed);
1878 GNUNET_free (sh->v6_allowed);
1879 while (NULL != (slc = sh->slc_head))
1880 {
1882 sh->slc_tail,
1883 slc);
1884 if (NULL != slc->listen_task)
1888 GNUNET_free (slc);
1889 }
1890}
1891
1892
1899static void
1900return_agpl (void *cls,
1901 const struct GNUNET_MessageHeader *msg)
1902{
1903 struct GNUNET_SERVICE_Client *client = cls;
1904 const struct GNUNET_OS_ProjectData *pd = client->sh->pd;
1905 struct GNUNET_MQ_Handle *mq;
1906 struct GNUNET_MQ_Envelope *env;
1907 struct GNUNET_MessageHeader *res;
1908 size_t slen;
1909
1910 (void) msg;
1911 slen = strlen (pd->agpl_url) + 1;
1914 slen);
1915 memcpy (&res[1],
1917 slen);
1920 env);
1922}
1923
1924
1925struct GNUNET_SERVICE_Handle *
1927 const char *service_name,
1928 const struct GNUNET_CONFIGURATION_Handle *cfg,
1931 void *cls,
1932 const struct GNUNET_MQ_MessageHandler *handlers)
1933{
1934 struct GNUNET_SERVICE_Handle *sh;
1935
1937 sh->pd = pd;
1938 sh->service_name = service_name;
1939 sh->cfg = cfg;
1940 sh->connect_cb = connect_cb;
1941 sh->disconnect_cb = disconnect_cb;
1942 sh->cb_cls = cls;
1944 &return_agpl,
1945 NULL);
1946 if (GNUNET_OK !=
1948 sh))
1949 {
1950 GNUNET_free (sh->handlers);
1951 GNUNET_free (sh);
1952 return NULL;
1953 }
1954 do_resume (sh,
1956 return sh;
1957}
1958
1959
1965static void
1966finish_client_drop (void *cls)
1967{
1968 struct GNUNET_SERVICE_Client *c = cls;
1969 struct GNUNET_SERVICE_Handle *sh = c->sh;
1970
1971 c->drop_task = NULL;
1972 GNUNET_CONTAINER_DLL_remove (sh->clients_head,
1973 sh->clients_tail,
1974 c);
1975 GNUNET_assert (NULL == c->send_task);
1976 GNUNET_assert (NULL == c->recv_task);
1977 GNUNET_assert (NULL == c->warn_task);
1979 GNUNET_MQ_destroy (c->mq);
1980 if (! c->persist)
1981 {
1984 if ((0 != (SUSPEND_STATE_EMFILE & sh->suspend_state)) &&
1985 (0 == (SUSPEND_STATE_SHUTDOWN & sh->suspend_state)))
1986 do_resume (sh,
1988 }
1989 else
1990 {
1992 }
1993 GNUNET_free (c);
1994 if ((0 != (SUSPEND_STATE_SHUTDOWN & sh->suspend_state)) &&
1997}
1998
1999
2000void
2002{
2003 struct GNUNET_SERVICE_Client *client;
2004
2006 while (NULL != (client = srv->clients_head))
2007 {
2008 if (NULL == client->drop_task)
2011 finish_client_drop (client);
2012 }
2013 teardown_service (srv);
2014 GNUNET_free (srv->handlers);
2015 GNUNET_free (srv);
2016}
2017
2018
2019int
2021 int argc,
2022 char *const *argv,
2023 const char *service_name,
2025 GNUNET_SERVICE_InitCallback service_init_cb,
2028 void *cls,
2029 const struct GNUNET_MQ_MessageHandler *handlers)
2030{
2032
2033#if ENABLE_NLS
2034 char *path;
2035#endif
2036 char *cfg_filename;
2037 char *opt_cfg_filename;
2038 char *loglev;
2039 const char *xdg;
2040 char *logfile;
2041 int do_daemonize;
2042 unsigned long long skew_offset;
2043 unsigned long long skew_variance;
2044 long long clock_offset;
2046 int ret;
2047 int err;
2048 struct GNUNET_GETOPT_CommandLineOption service_options[] = {
2049 GNUNET_GETOPT_option_cfgfile (&opt_cfg_filename),
2051 "daemonize",
2052 gettext_noop (
2053 "do daemonize (detach from terminal)"),
2054 &do_daemonize),
2056 NULL),
2061 };
2062
2063 err = 1;
2064 memset (&sh, 0, sizeof(sh));
2065 xdg = getenv ("XDG_CONFIG_HOME");
2066 if (NULL != xdg)
2068 "%s%s%s",
2069 xdg,
2071 pd->config_file);
2072 else
2074 sh.pd = pd;
2075 sh.ready_confirm_fd = -1;
2076 sh.options = options;
2078 sh.service_init_cb = service_init_cb;
2079 sh.connect_cb = connect_cb;
2080 sh.disconnect_cb = disconnect_cb;
2081 sh.cb_cls = cls;
2082 sh.handlers = (NULL == pd->agpl_url)
2085 &return_agpl,
2086 NULL);
2087 sh.service_name = service_name;
2088 /* setup subsystems */
2089 loglev = NULL;
2090 logfile = NULL;
2091 opt_cfg_filename = NULL;
2092 do_daemonize = 0;
2093#if ENABLE_NLS
2094 if (NULL != pd->gettext_domain)
2095 {
2096 setlocale (LC_ALL, "");
2097 path = (NULL == pd->gettext_path)
2101 if (NULL != path)
2102 {
2103 bindtextdomain (pd->gettext_domain, path);
2104 GNUNET_free (path);
2105 }
2107 }
2108#endif
2110 service_options,
2111 argc,
2112 argv);
2113 if (GNUNET_SYSERR == ret)
2114 goto shutdown;
2115 if (GNUNET_NO == ret)
2116 {
2117 err = 0;
2118 goto shutdown;
2119 }
2121 loglev,
2122 logfile))
2123 {
2124 GNUNET_break (0);
2125 goto shutdown;
2126 }
2127 if (NULL != opt_cfg_filename)
2128 {
2129 if ((GNUNET_YES != GNUNET_DISK_file_test (opt_cfg_filename)) ||
2130 (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, opt_cfg_filename)))
2131 {
2133 _ ("Malformed configuration file `%s', exit ...\n"),
2134 opt_cfg_filename);
2135 goto shutdown;
2136 }
2137 }
2138 else
2139 {
2140 if (GNUNET_YES ==
2142 {
2143 if (GNUNET_SYSERR ==
2145 cfg_filename))
2146 {
2148 _ ("Malformed configuration file `%s', exit ...\n"),
2149 cfg_filename);
2150 goto shutdown;
2151 }
2152 }
2153 else
2154 {
2155 if (GNUNET_SYSERR ==
2157 NULL))
2158 {
2160 _ ("Malformed configuration, exit ...\n"));
2161 goto shutdown;
2162 }
2163 }
2164 }
2165 if (GNUNET_OK !=
2166 setup_service (pd,
2167 &sh))
2168 goto shutdown;
2169 if ( (1 == do_daemonize) &&
2170 (GNUNET_OK !=
2171 detach_terminal (&sh)) )
2172 {
2173 GNUNET_break (0);
2174 goto shutdown;
2175 }
2176 if (GNUNET_OK != set_user_id (&sh))
2177 goto shutdown;
2179 "Service `%s' runs with configuration from `%s'\n",
2181 (NULL != opt_cfg_filename) ? opt_cfg_filename : cfg_filename);
2182 if ( (GNUNET_OK ==
2184 "TESTING",
2185 "SKEW_OFFSET",
2186 &skew_offset)) &&
2187 (GNUNET_OK ==
2189 "TESTING",
2190 "SKEW_VARIANCE",
2191 &skew_variance)) )
2192 {
2193 clock_offset = skew_offset - skew_variance;
2194 GNUNET_TIME_set_offset (clock_offset);
2196 "Skewing clock by %lld ms\n",
2197 (long long) clock_offset);
2198 }
2200
2201 /* actually run service */
2202 err = 0;
2204 /* shutdown */
2205 if (1 == do_daemonize)
2207
2208shutdown:
2209 if (-1 != sh.ready_confirm_fd)
2210 {
2211 if (1 != write (sh.ready_confirm_fd, err ? "I" : "S", 1))
2213 GNUNET_break (0 == close (sh.ready_confirm_fd));
2214 }
2216 GNUNET_free (sh.handlers);
2219 GNUNET_free (logfile);
2220 GNUNET_free (loglev);
2222 GNUNET_free (opt_cfg_filename);
2223
2224 return err ? GNUNET_SYSERR : 0;
2225}
2226
2227
2232struct ServiceHandleList
2233{
2234 /* DLL */
2235 struct ServiceHandleList *prev;
2236
2237 /* DLL */
2238 struct ServiceHandleList *next;
2239
2240 /* Handle to the service to launch */
2241 struct GNUNET_SERVICE_Handle *sh;
2242};
2243
2244/* The service list */
2245static struct ServiceHandleList *hll_head;
2246
2247/* The service list */
2248static struct ServiceHandleList *hll_tail;
2249
2250
2251int
2253 const char *service_name,
2255 GNUNET_SERVICE_InitCallback service_init_cb,
2258 void *cls,
2259 const struct GNUNET_MQ_MessageHandler *handlers)
2260{
2261 struct ServiceHandleList *hle;
2263
2264 sh->pd = pd;
2265 sh->ready_confirm_fd = -1;
2266 sh->options = options;
2267 sh->service_init_cb = service_init_cb;
2268 sh->connect_cb = connect_cb;
2269 sh->disconnect_cb = disconnect_cb;
2270 sh->cb_cls = cls;
2271 sh->handlers = (NULL == pd->agpl_url)
2274 sh->service_name = service_name;
2275 hle = GNUNET_new (struct ServiceHandleList);
2276 hle->sh = sh;
2278 hll_tail,
2279 hle);
2280 return 0;
2281}
2282
2283
2284static void
2286{
2287 while (NULL != hll_head)
2288 {
2289 struct ServiceHandleList *shl = hll_head;
2290 struct GNUNET_SERVICE_Handle *sh = shl->sh;
2291
2293 hll_tail,
2294 shl);
2295 GNUNET_free (shl);
2296 if (-1 != sh->ready_confirm_fd)
2297 {
2298 if (1 != write (sh->ready_confirm_fd, "S", 1))
2300 "write");
2301 GNUNET_break (0 ==
2302 close (sh->ready_confirm_fd));
2303 }
2305 GNUNET_free (sh->handlers);
2306 GNUNET_free (sh);
2307 }
2308}
2309
2310
2311struct LaunchContext
2312{
2314 const struct GNUNET_OS_ProjectData *pd;
2315};
2316
2317
2318static void
2320{
2321 struct LaunchContext *lc = cls;
2322 struct GNUNET_CONFIGURATION_Handle *cfg = lc->cfg;
2323 const struct GNUNET_OS_ProjectData *pd = lc->pd;
2324
2325 for (struct ServiceHandleList *shl = hll_head;
2326 NULL != shl;
2327 shl = shl->next)
2328 {
2329 shl->sh->cfg = cfg;
2330 if (GNUNET_OK !=
2331 setup_service (pd,
2332 shl->sh))
2333 continue;
2334 if (GNUNET_OK !=
2335 set_user_id (shl->sh))
2336 continue;
2338 shl->sh);
2339 }
2341 NULL);
2342}
2343
2344
2345void
2347 int argc,
2348 char *const *argv,
2350 enum GNUNET_GenericReturnValue with_scheduler)
2351{
2352 struct LaunchContext lc = {
2353 .pd = pd,
2354 .cfg = cfg
2355 };
2356
2358 "Entering GNUNET_SERVICE_main\n");
2359 if (GNUNET_YES == with_scheduler)
2360 {
2361 if (GNUNET_YES !=
2363 argc,
2364 argv,
2365 cfg))
2366 return;
2368 &lc);
2369 }
2370 else
2371 {
2374 }
2375}
2376
2377
2378void
2380{
2381 do_suspend (sh,
2383}
2384
2385
2386void
2388{
2389 do_resume (sh,
2391}
2392
2393
2400static void
2401resume_client_receive (void *cls)
2402{
2403 struct GNUNET_SERVICE_Client *c = cls;
2404 int ret;
2405
2406 c->recv_task = NULL;
2407 /* first, check if there is still something in the buffer */
2408 ret = GNUNET_MST_next (c->mst,
2409 GNUNET_YES);
2410 if (GNUNET_SYSERR == ret)
2411 {
2412 if (NULL == c->drop_task)
2414 return;
2415 }
2416 if (GNUNET_NO == ret)
2417 return; /* done processing, wait for more later */
2419 if (c->needs_continue)
2420 return; /* #GNUNET_MST_next() did give a message to the client */
2421 /* need to receive more data from the network first */
2422 if (NULL != c->recv_task)
2423 return;
2425 c->sock,
2427 c);
2428}
2429
2430
2431void
2433{
2434 GNUNET_assert (NULL == c->drop_task);
2436 GNUNET_assert (NULL == c->recv_task);
2437 c->needs_continue = false;
2438 if (NULL != c->warn_task)
2439 {
2441 c->warn_task = NULL;
2442 }
2444 c);
2445}
2446
2447
2448void
2450{
2451 GNUNET_break (NULL != c->warn_task);
2452 if (NULL != c->warn_task)
2453 {
2455 c->warn_task = NULL;
2456 }
2457}
2458
2459
2460void
2462{
2463 struct GNUNET_SERVICE_Handle *sh = c->sh;
2464
2466 "Client dropped: %p (MQ: %p)\n",
2467 c,
2468 c->mq);
2469#if EXECINFO
2470 {
2471 void *backtrace_array[MAX_TRACE_DEPTH];
2472 int num_backtrace_strings = backtrace (backtrace_array,
2473 MAX_TRACE_DEPTH);
2474 char **backtrace_strings =
2475 backtrace_symbols (backtrace_array,
2476 t->num_backtrace_strings);
2477 for (unsigned int i = 0; i < num_backtrace_strings; i++)
2479 "client drop trace %u: %s\n",
2480 i,
2481 backtrace_strings[i]);
2482 }
2483#endif
2484 GNUNET_assert (NULL == c->drop_task);
2485 if (NULL != sh->disconnect_cb)
2486 sh->disconnect_cb (sh->cb_cls,
2487 c,
2488 c->user_context);
2489 if (NULL != c->warn_task)
2490 {
2492 c->warn_task = NULL;
2493 }
2494 if (NULL != c->recv_task)
2495 {
2497 c->recv_task = NULL;
2498 }
2499 if (NULL != c->send_task)
2500 {
2502 c->send_task = NULL;
2503 }
2505 c);
2506}
2507
2508
2509void
2511{
2512 if (0 == (sh->suspend_state & SUSPEND_STATE_SHUTDOWN))
2513 do_suspend (sh,
2515 for (struct GNUNET_SERVICE_Client *client = sh->clients_head;
2516 NULL != client;
2517 client = client->next)
2518 {
2519 if (NULL == client->drop_task)
2521 }
2522}
2523
2524
2525void
2527{
2528 c->is_monitor = true;
2529 if (((0 != (SUSPEND_STATE_SHUTDOWN & c->sh->suspend_state)) &&
2530 (! have_non_monitor_clients (c->sh))))
2532}
2533
2534
2535void
2537{
2538 c->persist = true;
2539}
2540
2541
2542struct GNUNET_MQ_Handle *
2544{
2545 return c->mq;
2546}
2547
2548
2549/* end of service.c */
struct GNUNET_GETOPT_CommandLineOption options[]
Definition 002.c:5
struct GNUNET_MQ_MessageHandlers handlers[]
Definition 003.c:1
struct GNUNET_MessageHeader * msg
Definition 005.c:2
struct GNUNET_MQ_Envelope * env
Definition 005.c:1
char * getenv()
#define gettext_noop(String)
Definition gettext.h:74
#define textdomain(Domainname)
Definition gettext.h:61
#define bindtextdomain(Domainname, Dirname)
Definition gettext.h:62
static int list
Set if we should print a list of currently running services.
Definition gnunet-arm.c:68
static int ret
Final status code.
Definition gnunet-arm.c:93
static struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
Definition gnunet-arm.c:108
static char * cfg_filename
Name of the configuration file.
static uint16_t port
Port number.
Definition gnunet-bcd.c:146
static struct in_addr dummy
Target "dummy" address of the packet we pretend to respond to.
static struct GNUNET_IDENTITY_Handle * sh
Handle to IDENTITY service.
static char * res
Currently read line or NULL on EOF.
static int add
Desired action is to add a record.
static struct GNUNET_NETWORK_Handle * ls
Listen socket for STUN processing.
Definition gnunet-nat.c:85
static struct GNUNET_PeerIdentity pid
Identity of the peer we transmit to / connect to.
static char * service_name
Option -s: service name (hash to get service descriptor)
Definition gnunet-vpn.c:50
static struct GNUNET_SCHEDULER_Task * t
Main task.
#define GNUNET_AGPL_URL
NOTE: You MUST adjust this URL to point to the location of a publicly accessible repository (or TGZ) ...
struct GNUNET_CONFIGURATION_Handle * GNUNET_CONFIGURATION_create(const struct GNUNET_OS_ProjectData *pd)
Create a new configuration object.
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_filename(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, char **value)
Get a configuration value that should be the name of a file or directory.
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_number(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, unsigned long long *number)
Get a configuration value that should be a number.
void GNUNET_CONFIGURATION_destroy(struct GNUNET_CONFIGURATION_Handle *cfg)
Destroy configuration object.
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_yesno(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option)
Get a configuration value that should be in a set of "YES" or "NO".
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_get_value_string(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option, char **value)
Get a configuration value that should be a string.
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_load(struct GNUNET_CONFIGURATION_Handle *cfg, const char *filename)
Load configuration.
enum GNUNET_GenericReturnValue GNUNET_CONFIGURATION_have_value(const struct GNUNET_CONFIGURATION_Handle *cfg, const char *section, const char *option)
Test if we have a value for a particular option.
enum GNUNET_GenericReturnValue GNUNET_DISK_file_test(const char *fil)
Check that fil corresponds to a filename (of a file that exists and that is not a directory).
Definition disk.c:533
enum GNUNET_GenericReturnValue GNUNET_DISK_directory_create_for_file(const char *filename)
Create the directory structure for storing a file.
Definition disk.c:633
#define GNUNET_CONTAINER_DLL_remove(head, tail, element)
Remove an element from a DLL.
#define GNUNET_CONTAINER_DLL_insert(head, tail, element)
Insert an element at the head of a DLL.
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_cfgfile(char **fn)
Allow user to specify configuration file name (-c option)
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_logfile(char **logfn)
Allow user to specify log file name (-l option)
int GNUNET_GETOPT_run(const char *binaryOptions, const struct GNUNET_GETOPT_CommandLineOption *allOptions, unsigned int argc, char *const *argv)
Parse the command line.
Definition getopt.c:884
#define GNUNET_GETOPT_OPTION_END
Marker for the end of the list of options.
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_help(const struct GNUNET_OS_ProjectData *pd, const char *about)
Defining the option to print the command line help text (-h option).
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_loglevel(char **level)
Define the '-L' log level option.
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_flag(char shortName, const char *name, const char *description, int *val)
Allow user to specify a flag (which internally means setting an integer to 1/GNUNET_YES/GNUNET_OK.
struct GNUNET_GETOPT_CommandLineOption GNUNET_GETOPT_option_version(const char *version)
Define the option to print the version of the application (-v option)
#define GNUNET_is_zero(a)
Check that memory in a is all zeros.
uint16_t type
The type of the message (GNUNET_MESSAGE_TYPE_XXXX), in big-endian format.
#define GNUNET_log(kind,...)
#define GNUNET_memcpy(dst, src, n)
Call memcpy() but check for n being 0 first.
GNUNET_GenericReturnValue
Named constants for return values.
uint16_t size
The length of the struct (in bytes, including the length field itself), in big-endian format.
@ GNUNET_OK
@ GNUNET_YES
@ GNUNET_NO
@ GNUNET_SYSERR
#define GNUNET_assert(cond)
Use this for fatal errors that cannot be handled.
#define GNUNET_break(cond)
Use this for internal assertion violations that are not fatal (can be handled) but should not occur.
enum GNUNET_GenericReturnValue GNUNET_log_setup(const char *comp, const char *loglevel, const char *logfile)
Setup logging.
const char * GNUNET_a2s(const struct sockaddr *addr, socklen_t addrlen)
Convert a "struct sockaddr*" (IPv4 or IPv6 address) to a string (for printing debug messages).
#define GNUNET_log_strerror(level, cmd)
Log an error message at log-level 'level' that indicates a failure of the command 'cmd' with the mess...
#define GNUNET_log_strerror_file(level, cmd, filename)
Log an error message at log-level 'level' that indicates a failure of the command 'cmd' with the mess...
@ GNUNET_ERROR_TYPE_WARNING
@ GNUNET_ERROR_TYPE_ERROR
@ GNUNET_ERROR_TYPE_DEBUG
@ GNUNET_ERROR_TYPE_INFO
int int GNUNET_asprintf(char **buf, const char *format,...) __attribute__((format(printf
Like asprintf, just portable.
#define GNUNET_strdup(a)
Wrapper around GNUNET_xstrdup_.
#define GNUNET_new(type)
Allocate a struct or union of the given type.
#define GNUNET_malloc(size)
Wrapper around malloc.
#define GNUNET_new_array(n, type)
Allocate a size n array with structs or unions of the given type.
#define GNUNET_free(ptr)
Wrapper around free.
GNUNET_MQ_Error
Error codes for the queue.
void GNUNET_MQ_inject_error(struct GNUNET_MQ_Handle *mq, enum GNUNET_MQ_Error error)
Call the error handler of a message queue with the given error code.
Definition mq.c:269
struct GNUNET_MQ_Handle * GNUNET_MQ_queue_for_callbacks(GNUNET_MQ_SendImpl send, GNUNET_MQ_DestroyImpl destroy, GNUNET_MQ_CancelImpl cancel, void *impl_state, const struct GNUNET_MQ_MessageHandler *handlers, GNUNET_MQ_ErrorHandler error_handler, void *cls)
Create a message queue for the specified handlers.
Definition mq.c:482
void GNUNET_MQ_send(struct GNUNET_MQ_Handle *mq, struct GNUNET_MQ_Envelope *ev)
Send a message with the given message queue.
Definition mq.c:305
#define GNUNET_MQ_msg_extra(mvar, esize, type)
Allocate an envelope, with extra space allocated after the space needed by the message struct.
struct GNUNET_MQ_MessageHandler * GNUNET_MQ_copy_handlers2(const struct GNUNET_MQ_MessageHandler *handlers, GNUNET_MQ_MessageCallback agpl_handler, void *agpl_cls)
Copy an array of handlers, appending AGPL handler.
Definition mq.c:992
struct GNUNET_MQ_MessageHandler * GNUNET_MQ_copy_handlers(const struct GNUNET_MQ_MessageHandler *handlers)
Copy an array of handlers.
Definition mq.c:974
void GNUNET_MQ_impl_send_continue(struct GNUNET_MQ_Handle *mq)
Call the send implementation for the next queued message, if any.
Definition mq.c:437
void GNUNET_MQ_inject_message(struct GNUNET_MQ_Handle *mq, const struct GNUNET_MessageHeader *mh)
Call the message message handler that was registered for the type of the given message in the given m...
Definition mq.c:187
void GNUNET_MQ_impl_send_in_flight(struct GNUNET_MQ_Handle *mq)
Call the send notification for the current message, but do not try to send the next message until #gn...
Definition mq.c:461
void GNUNET_MQ_set_handlers_closure(struct GNUNET_MQ_Handle *mq, void *handlers_cls)
Change the closure argument in all of the handlers of the mq.
Definition mq.c:506
void GNUNET_MQ_destroy(struct GNUNET_MQ_Handle *mq)
Destroy the message queue.
Definition mq.c:700
@ GNUNET_MQ_ERROR_NO_MATCH
We received a message for which we have no matching handler.
@ GNUNET_MQ_ERROR_WRITE
FIXME: document!
struct GNUNET_NETWORK_Handle * GNUNET_NETWORK_socket_accept(const struct GNUNET_NETWORK_Handle *desc, struct sockaddr *address, socklen_t *address_len)
Accept a new connection on a socket.
Definition network.c:392
enum GNUNET_GenericReturnValue GNUNET_NETWORK_socket_close(struct GNUNET_NETWORK_Handle *desc)
Close a socket.
Definition network.c:508
char * GNUNET_NETWORK_shorten_unixpath(char *unixpath)
Given a unixpath that is too long (larger than UNIX_PATH_MAX), shorten it to an acceptable length whi...
Definition network.c:143
struct GNUNET_NETWORK_Handle * GNUNET_NETWORK_socket_box_native(int fd)
Box a native socket (and check that it is a socket).
Definition network.c:580
struct GNUNET_NETWORK_Handle * GNUNET_NETWORK_socket_create(int domain, int type, int protocol)
Create a new socket.
Definition network.c:833
void GNUNET_NETWORK_socket_free_memory_only_(struct GNUNET_NETWORK_Handle *desc)
Only free memory of a socket, keep the file descriptor untouched.
Definition network.c:566
ssize_t GNUNET_NETWORK_socket_send(const struct GNUNET_NETWORK_Handle *desc, const void *buffer, size_t length)
Send data (always non-blocking).
Definition network.c:738
enum GNUNET_GenericReturnValue GNUNET_NETWORK_test_pf(int pf)
Test if the given protocol family is supported by this system.
Definition network.c:79
enum GNUNET_GenericReturnValue GNUNET_NETWORK_socket_bind(struct GNUNET_NETWORK_Handle *desc, const struct sockaddr *address, socklen_t address_len)
Bind a socket to a particular address.
Definition network.c:439
enum GNUNET_GenericReturnValue GNUNET_NETWORK_socket_listen(const struct GNUNET_NETWORK_Handle *desc, int backlog)
Listen on a socket.
Definition network.c:652
char * GNUNET_OS_installation_get_path(const struct GNUNET_OS_ProjectData *pd, enum GNUNET_OS_InstallationPathKind dirkind)
Get the path to a specific GNUnet installation directory or, with GNUNET_OS_IPK_SELF_PREFIX,...
@ GNUNET_OS_IPK_LOCALEDIR
Return the directory where translations are installed (share/locale/)
enum GNUNET_GenericReturnValue GNUNET_PROGRAM_conf_and_options(const struct GNUNET_OS_ProjectData *pd, int argc, char *const *argv, struct GNUNET_CONFIGURATION_Handle *cfg)
Create configuration handle from options and configuration file.
Definition program.c:429
#define GNUNET_MESSAGE_TYPE_RESPONSE_AGPL
Source code link.
void GNUNET_RESOLVER_connect(const struct GNUNET_CONFIGURATION_Handle *cfg)
Create the connection to the resolver service.
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_read_net(struct GNUNET_TIME_Relative delay, struct GNUNET_NETWORK_Handle *rfd, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay or when the specified file descriptor is ready f...
Definition scheduler.c:1511
void GNUNET_SCHEDULER_run(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Initialize and run scheduler.
Definition scheduler.c:725
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_write_net(struct GNUNET_TIME_Relative delay, struct GNUNET_NETWORK_Handle *wfd, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay or when the specified file descriptor is ready f...
Definition scheduler.c:1582
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_shutdown(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run on shutdown, that is when a CTRL-C signal is received,...
Definition scheduler.c:1339
void * GNUNET_SCHEDULER_cancel(struct GNUNET_SCHEDULER_Task *task)
Cancel the task with the specified identifier.
Definition scheduler.c:980
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_now(GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run as soon as possible.
Definition scheduler.c:1304
struct GNUNET_SCHEDULER_Task * GNUNET_SCHEDULER_add_delayed(struct GNUNET_TIME_Relative delay, GNUNET_SCHEDULER_TaskCallback task, void *task_cls)
Schedule a new task to be run with a specified delay.
Definition scheduler.c:1277
enum GNUNET_GenericReturnValue GNUNET_MST_next(struct GNUNET_MessageStreamTokenizer *mst, int one_shot)
Obtain the next message from the mst, assuming that there are more unprocessed messages in the intern...
Definition mst.c:387
struct GNUNET_MessageStreamTokenizer * GNUNET_MST_create(GNUNET_MessageTokenizerCallback cb, void *cb_cls)
Create a message stream tokenizer.
Definition mst.c:86
void GNUNET_MST_destroy(struct GNUNET_MessageStreamTokenizer *mst)
Destroys a tokenizer.
Definition mst.c:404
enum GNUNET_GenericReturnValue GNUNET_MST_read(struct GNUNET_MessageStreamTokenizer *mst, struct GNUNET_NETWORK_Handle *sock, int purge, int one_shot)
Add incoming data to the receive buffer and call the callback for all complete messages.
Definition mst.c:338
void GNUNET_SERVICE_suspend(struct GNUNET_SERVICE_Handle *sh)
Suspend accepting connections from the listen socket temporarily.
Definition service.c:2380
void GNUNET_SERVICE_stop(struct GNUNET_SERVICE_Handle *srv)
Stops a service that was started with GNUNET_SERVICE_start().
Definition service.c:2002
void GNUNET_SERVICE_shutdown(struct GNUNET_SERVICE_Handle *sh)
Explicitly stops the service.
Definition service.c:2511
int GNUNET_SERVICE_run_(const struct GNUNET_OS_ProjectData *pd, int argc, char *const *argv, const char *service_name, enum GNUNET_SERVICE_Options options, GNUNET_SERVICE_InitCallback service_init_cb, GNUNET_SERVICE_ConnectHandler connect_cb, GNUNET_SERVICE_DisconnectHandler disconnect_cb, void *cls, const struct GNUNET_MQ_MessageHandler *handlers)
Creates the "main" function for a GNUnet service.
Definition service.c:2021
GNUNET_SERVICE_Options
Options for the service (bitmask).
void GNUNET_SERVICE_client_mark_monitor(struct GNUNET_SERVICE_Client *c)
Set the 'monitor' flag on this client.
Definition service.c:2527
int GNUNET_SERVICE_register_(const struct GNUNET_OS_ProjectData *pd, const char *service_name, enum GNUNET_SERVICE_Options options, GNUNET_SERVICE_InitCallback service_init_cb, GNUNET_SERVICE_ConnectHandler connect_cb, GNUNET_SERVICE_DisconnectHandler disconnect_cb, void *cls, const struct GNUNET_MQ_MessageHandler *handlers)
Registers the GNUnet service to be scheduled as part of a monilithic libgnunet.
Definition service.c:2253
void(* GNUNET_SERVICE_DisconnectHandler)(void *cls, struct GNUNET_SERVICE_Client *c, void *internal_cls)
Callback to be called when a client disconnected from the service.
void GNUNET_SERVICE_client_drop(struct GNUNET_SERVICE_Client *c)
Ask the server to disconnect from the given client.
Definition service.c:2462
struct GNUNET_SERVICE_Handle * GNUNET_SERVICE_start(const struct GNUNET_OS_ProjectData *pd, const char *service_name, const struct GNUNET_CONFIGURATION_Handle *cfg, GNUNET_SERVICE_ConnectHandler connect_cb, GNUNET_SERVICE_DisconnectHandler disconnect_cb, void *cls, const struct GNUNET_MQ_MessageHandler *handlers)
Low-level function to start a service if the scheduler is already running.
Definition service.c:1927
void GNUNET_SERVICE_client_persist(struct GNUNET_SERVICE_Client *c)
Set the persist option on this client.
Definition service.c:2537
void GNUNET_SERVICE_client_disable_continue_warning(struct GNUNET_SERVICE_Client *c)
Disable the warning the server issues if a message is not acknowledged in a timely fashion.
Definition service.c:2450
void GNUNET_SERVICE_main(const struct GNUNET_OS_ProjectData *pd, int argc, char *const *argv, struct GNUNET_CONFIGURATION_Handle *cfg, enum GNUNET_GenericReturnValue with_scheduler)
Run the mainloop in a monolithic libgnunet.
Definition service.c:2347
void(* GNUNET_SERVICE_InitCallback)(void *cls, const struct GNUNET_CONFIGURATION_Handle *cfg, struct GNUNET_SERVICE_Handle *sh)
Callback to initialize a service, called exactly once when the service is run.
void *(* GNUNET_SERVICE_ConnectHandler)(void *cls, struct GNUNET_SERVICE_Client *c, struct GNUNET_MQ_Handle *mq)
Callback to be called when a client connects to the service.
struct GNUNET_MQ_Handle * GNUNET_SERVICE_client_get_mq(struct GNUNET_SERVICE_Client *c)
Obtain the message queue of c.
Definition service.c:2544
void GNUNET_SERVICE_client_continue(struct GNUNET_SERVICE_Client *c)
Continue receiving further messages from the given client.
Definition service.c:2433
void GNUNET_SERVICE_resume(struct GNUNET_SERVICE_Handle *sh)
Resume accepting connections from the listen socket.
Definition service.c:2388
@ GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN
Do not trigger server shutdown on signal at all; instead, allow for the user to terminate the server ...
@ GNUNET_SERVICE_OPTION_SHUTDOWN_BITMASK
Bitmask over the shutdown options.
@ GNUNET_SERVICE_OPTION_CLOSE_LSOCKS
Instead of listening on lsocks passed by the parent, close them after opening our own listen socket(s...
@ GNUNET_SERVICE_OPTION_NONE
Use defaults.
@ GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN
Trigger a SOFT server shutdown on signals, allowing active non-monitor clients to complete their tran...
struct GNUNET_STRINGS_IPv6NetworkPolicy * GNUNET_STRINGS_parse_ipv6_policy(const char *routeListX)
Parse an IPv6 network policy.
Definition strings.c:1469
struct GNUNET_STRINGS_IPv4NetworkPolicy * GNUNET_STRINGS_parse_ipv4_policy(const char *routeListX)
Parse an IPv4 network policy.
Definition strings.c:1294
size_t GNUNET_strlcpy(char *dst, const char *src, size_t n)
Like strlcpy but portable.
Definition strings.c:137
#define GNUNET_TIME_UNIT_FOREVER_REL
Constant used to specify "forever".
struct GNUNET_TIME_Relative GNUNET_TIME_absolute_get_duration(struct GNUNET_TIME_Absolute whence)
Get the duration of an operation as the difference of the current time and the given start time "henc...
Definition time.c:438
const char * GNUNET_STRINGS_relative_time_to_string(struct GNUNET_TIME_Relative delta, int do_round)
Give relative time in human-readable fancy format.
Definition strings.c:599
struct GNUNET_TIME_Absolute GNUNET_TIME_absolute_get(void)
Get the current time.
Definition time.c:111
#define GNUNET_TIME_UNIT_MINUTES
One minute.
void GNUNET_TIME_set_offset(long long offset)
Set the timestamp offset for this instance.
Definition time.c:49
#define DIR_SEPARATOR_STR
Definition platform.h:167
#define _(String)
GNU gettext support macro.
Definition platform.h:179
static struct GNUNET_MQ_Handle * mq
Our connection to the resolver service, created on-demand, but then persists until error or shutdown.
static void do_registered_services_shutdown(void *cls)
Definition service.c:2286
static char * get_pid_file_name(struct GNUNET_SERVICE_Handle *sh)
Get the name of the file where we will write the PID of the service.
Definition service.c:1747
static void do_resume(struct GNUNET_SERVICE_Handle *sh, enum SuspendReason sr)
Resume accepting connections from the listen socket.
Definition service.c:880
static bool check_ipv6_listed(const struct GNUNET_STRINGS_IPv6NetworkPolicy *list, const struct in6_addr *ip)
Check if the given IP address is in the list of IP addresses.
Definition service.c:465
static void return_agpl(void *cls, const struct GNUNET_MessageHeader *msg)
Function to return link to AGPL source upon request.
Definition service.c:1901
static void teardown_service(struct GNUNET_SERVICE_Handle *sh)
Tear down the service, closing the listen sockets and freeing the ACLs.
Definition service.c:1872
static void service_client_recv(void *cls)
A client sent us data.
Definition service.c:704
static void service_mq_cancel(struct GNUNET_MQ_Handle *mq, void *impl_state)
Implementation function that cancels the currently sent message.
Definition service.c:592
static void service_shutdown(void *cls)
Shutdown task triggered when a service should be terminated.
Definition service.c:410
static void resume_client_receive(void *cls)
Task run to resume receiving data from the client after the client called GNUNET_SERVICE_client_conti...
Definition service.c:2402
static enum GNUNET_GenericReturnValue detach_terminal(struct GNUNET_SERVICE_Handle *sh)
Detach from terminal.
Definition service.c:1788
static void launch_registered_services(void *cls)
Definition service.c:2320
static struct ServiceHandleList * hll_head
Definition service.c:2246
static void service_mq_send(struct GNUNET_MQ_Handle *mq, const struct GNUNET_MessageHeader *msg, void *impl_state)
Signature of functions implementing the sending functionality of a message queue.
Definition service.c:564
static char * get_user_name(struct GNUNET_SERVICE_Handle *sh)
Get the name of the user that'll be used to provide the service.
Definition service.c:1676
#define LOG_STRERROR_FILE(kind, syscall, filename)
Definition service.c:44
static void start_client(struct GNUNET_SERVICE_Handle *sh, struct GNUNET_NETWORK_Handle *csock)
We have successfully accepted a connection from a client.
Definition service.c:749
static void do_send(void *cls)
Task run when we are ready to transmit data to the client.
Definition service.c:495
static enum GNUNET_GenericReturnValue process_acl4(struct GNUNET_STRINGS_IPv4NetworkPolicy **ret, struct GNUNET_SERVICE_Handle *sh, const char *option)
Parse an IPv4 access control list.
Definition service.c:940
static enum GNUNET_GenericReturnValue setup_service(const struct GNUNET_OS_ProjectData *pd, struct GNUNET_SERVICE_Handle *sh)
Setup service handle.
Definition service.c:1476
static void finish_client_drop(void *cls)
Asynchronously finish dropping the client.
Definition service.c:1967
static int service_client_mst_cb(void *cls, const struct GNUNET_MessageHeader *message)
Functions with this signature are called whenever a complete message is received by the tokenizer for...
Definition service.c:673
static bool check_ipv4_listed(const struct GNUNET_STRINGS_IPv4NetworkPolicy *list, const struct in_addr *add)
Check if the given IP address is in the list of IP addresses.
Definition service.c:442
static void pid_file_delete(struct GNUNET_SERVICE_Handle *sh)
Delete the PID file that was created by our parent.
Definition service.c:1767
static int get_server_addresses(const char *service_name, const struct GNUNET_CONFIGURATION_Handle *cfg, struct sockaddr ***addrs, socklen_t **addr_lens)
Get the list of addresses that a server for the given service should bind to.
Definition service.c:1065
static void do_suspend(struct GNUNET_SERVICE_Handle *sh, enum SuspendReason sr)
Suspend accepting connections from the listen socket temporarily.
Definition service.c:383
static void warn_no_client_continue(void *cls)
Task run to warn about missing calls to GNUNET_SERVICE_client_continue().
Definition service.c:640
static enum GNUNET_GenericReturnValue set_user_id(struct GNUNET_SERVICE_Handle *sh)
Set user ID.
Definition service.c:1697
static void service_mq_error_handler(void *cls, enum GNUNET_MQ_Error error)
Generic error handler, called with the appropriate error code and the same closure specified at the c...
Definition service.c:615
static void add_unixpath(struct sockaddr **saddrs, socklen_t *saddrlens, const char *unixpath)
Add the given UNIX domain path as an address to the list (as the first entry).
Definition service.c:1021
static void service_main(void *cls)
First task run by any service.
Definition service.c:909
static enum GNUNET_GenericReturnValue process_acl6(struct GNUNET_STRINGS_IPv6NetworkPolicy **ret, struct GNUNET_SERVICE_Handle *sh, const char *option)
Parse an IPv6 access control list.
Definition service.c:981
static enum GNUNET_GenericReturnValue have_non_monitor_clients(struct GNUNET_SERVICE_Handle *sh)
Check if any of the clients we have left are unrelated to monitoring.
Definition service.c:359
#define LOG(kind,...)
Definition service.c:39
#define LOG_STRERROR(kind, syscall)
Definition service.c:41
static void accept_client(void *cls)
We have a client.
Definition service.c:786
SuspendReason
Reasons why we might be suspended.
Definition service.c:84
@ SUSPEND_STATE_SHUTDOWN
Suspension because service was permanently shutdown.
Definition service.c:108
@ SUSPEND_STATE_APP
Application requested it.
Definition service.c:93
@ SUSPEND_STATE_NONE
We are running normally.
Definition service.c:88
@ SUSPEND_STATE_APP_AND_EMFILE
Both reasons, APP and EMFILE apply.
Definition service.c:103
@ SUSPEND_STATE_EMFILE
OS ran out of file descriptors.
Definition service.c:98
static struct ServiceHandleList * hll_tail
Definition service.c:2249
static struct GNUNET_NETWORK_Handle * open_listen_socket(const struct sockaddr *server_addr, socklen_t socklen)
Create and initialize a listen socket for the server.
Definition service.c:1367
void GNUNET_SPEEDUP_stop_()
Stop tasks that modify clock behavior.
Definition speedup.c:100
Definition of a command line option.
const struct GNUNET_CONFIGURATION_Handle * cfg
Configuration to use.
void * cb_cls
Closure for cb.
Handle to a message queue.
Definition mq.c:87
Message handler for a specific message type.
Header for all communications.
Handle to a message stream tokenizer.
Definition mst.c:45
handle to a socket
Definition network.c:53
Project-specific data used to help the OS subsystem find installation paths.
const char * gettext_path
Gettext directory, e.g.
const char * gettext_domain
Gettext domain for localisation, e.g.
const char * agpl_url
URL pointing to the source code of the application.
const char * user_config_file
Configuration file name to use (if $XDG_CONFIG_HOME is not set).
const char * config_file
Configuration file name (in $XDG_CONFIG_HOME) to use.
const char * version
String identifying the current project version.
Entry in list of pending tasks.
Definition scheduler.c:136
Handle to a client that is connected to a service.
Definition service.c:249
bool persist
Persist the file handle for this client no matter what happens, force the OS to close once the proces...
Definition service.c:330
size_t msg_pos
Current position in msg at which we are transmitting.
Definition service.c:323
struct GNUNET_SCHEDULER_Task * send_task
Task that transmit data to the client.
Definition service.c:301
struct GNUNET_SCHEDULER_Task * drop_task
Task run to finish dropping the client after the stack has properly unwound.
Definition service.c:290
struct GNUNET_TIME_Absolute warn_start
Time when we last gave a message from this client to the application.
Definition service.c:318
struct GNUNET_NETWORK_Handle * sock
Socket of this client.
Definition service.c:268
uint16_t warn_type
Type of last message processed (for warn_no_receive_done).
Definition service.c:347
const struct GNUNET_MessageHeader * msg
Pointer to the message to be transmitted by send_task.
Definition service.c:306
struct GNUNET_SCHEDULER_Task * warn_task
Task that warns about missing calls to GNUNET_SERVICE_client_continue().
Definition service.c:284
struct GNUNET_SCHEDULER_Task * recv_task
Task that receives data from the client to pass it to the handlers.
Definition service.c:296
struct GNUNET_SERVICE_Handle * sh
Service that this client belongs to.
Definition service.c:263
struct GNUNET_SERVICE_Client * next
Kept in a DLL.
Definition service.c:253
void * user_context
User context value, value returned from the connect callback.
Definition service.c:312
bool needs_continue
Are we waiting for the application to call GNUNET_SERVICE_client_continue()?
Definition service.c:342
bool is_monitor
Is this client a 'monitor' client that should not be counted when deciding on destroying the server d...
Definition service.c:337
struct GNUNET_SERVICE_Client * prev
Kept in a DLL.
Definition service.c:258
struct GNUNET_MQ_Handle * mq
Message queue for the client.
Definition service.c:273
struct GNUNET_MessageStreamTokenizer * mst
Tokenizer we use for processing incoming data.
Definition service.c:278
Handle to a service.
Definition service.c:116
void * task_cls
Closure for task.
Definition service.c:180
struct GNUNET_STRINGS_IPv6NetworkPolicy * v6_denied
IPv6 addresses that are not allowed to connect.
Definition service.c:190
GNUNET_SERVICE_ConnectHandler connect_cb
Function to call when clients connect.
Definition service.c:140
GNUNET_SERVICE_InitCallback service_init_cb
Main service-specific task to run.
Definition service.c:135
int ready_confirm_fd
If we are daemonizing, this FD is set to the pipe to the parent.
Definition service.c:235
struct GNUNET_SERVICE_Client * clients_tail
Our clients, kept in a DLL.
Definition service.c:170
struct GNUNET_MQ_MessageHandler * handlers
Message handlers to use for all clients.
Definition service.c:175
void * cb_cls
Closure for service_init_cb, connect_cb, disconnect_cb.
Definition service.c:150
struct GNUNET_STRINGS_IPv4NetworkPolicy * v4_denied
IPv4 addresses that are not allowed to connect.
Definition service.c:185
struct GNUNET_STRINGS_IPv6NetworkPolicy * v6_allowed
IPv6 addresses that are allowed to connect (if not set, all are allowed).
Definition service.c:202
const char * service_name
Name of our service.
Definition service.c:130
struct GNUNET_SERVICE_Client * clients_head
Our clients, kept in a DLL.
Definition service.c:165
bool require_found
If true, consider unknown message types an error where the client is disconnected.
Definition service.c:241
GNUNET_SERVICE_DisconnectHandler disconnect_cb
Function to call when clients disconnect / are disconnected.
Definition service.c:145
enum GNUNET_SERVICE_Options options
Our options.
Definition service.c:228
int match_uid
Do we require a matching UID for UNIX domain socket connections? GNUNET_NO means that the UID does no...
Definition service.c:209
int match_gid
Do we require a matching GID for UNIX domain socket connections? Ignored if match_uid is GNUNET_YES.
Definition service.c:218
struct ServiceListenContext * slc_head
DLL of listen sockets used to accept new connections.
Definition service.c:155
const struct GNUNET_CONFIGURATION_Handle * cfg
Our configuration.
Definition service.c:120
enum SuspendReason suspend_state
Are we suspended, and if so, why?
Definition service.c:223
const struct GNUNET_OS_ProjectData * pd
Project data of this service.
Definition service.c:125
struct ServiceListenContext * slc_tail
DLL of listen sockets used to accept new connections.
Definition service.c:160
struct GNUNET_STRINGS_IPv4NetworkPolicy * v4_allowed
IPv4 addresses that are allowed to connect (if not set, all are allowed).
Definition service.c:196
IPV4 network in CIDR notation.
network in CIDR notation for IPV6.
Time for absolute times used by GNUnet, in microseconds.
struct GNUNET_CONFIGURATION_Handle * cfg
Definition service.c:2314
const struct GNUNET_OS_ProjectData * pd
Definition service.c:2315
A list of service to be launched when GNUNET_SERVICE_main() is called.
Definition service.c:2234
struct GNUNET_SERVICE_Handle * sh
Definition service.c:2242
struct ServiceHandleList * next
Definition service.c:2239
struct ServiceHandleList * prev
Definition service.c:2236
Information the service tracks per listen operation.
Definition service.c:52
struct ServiceListenContext * next
Kept in a DLL.
Definition service.c:56
struct ServiceListenContext * prev
Kept in a DLL.
Definition service.c:61
struct GNUNET_SCHEDULER_Task * listen_task
Task scheduled to do the listening.
Definition service.c:76
struct GNUNET_NETWORK_Handle * listen_socket
Socket we are listening on.
Definition service.c:71
struct GNUNET_SERVICE_Handle * sh
Service this listen context belongs to.
Definition service.c:66
static void * connect_cb(void *cls, const struct GNUNET_PeerIdentity *peer_id, struct GNUNET_MQ_Handle *mq, enum GNUNET_CORE_PeerClass class)
static void disconnect_cb(void *cls, const struct GNUNET_PeerIdentity *peer, void *peer_cls)

◆ LOG_STRERROR_FILE

#define LOG_STRERROR_FILE (   kind,
  syscall,
  filename 
)     GNUNET_log_from_strerror_file (kind, "util-service", syscall, filename)

Definition at line 44 of file service.c.

Enumeration Type Documentation

◆ SuspendReason

Reasons why we might be suspended.

Enumerator
SUSPEND_STATE_NONE 

We are running normally.

SUSPEND_STATE_APP 

Application requested it.

SUSPEND_STATE_EMFILE 

OS ran out of file descriptors.

SUSPEND_STATE_APP_AND_EMFILE 

Both reasons, APP and EMFILE apply.

SUSPEND_STATE_SHUTDOWN 

Suspension because service was permanently shutdown.

Definition at line 83 of file service.c.

84{
89
94
99
104
109};

Function Documentation

◆ have_non_monitor_clients()

static enum GNUNET_GenericReturnValue have_non_monitor_clients ( struct GNUNET_SERVICE_Handle sh)
static

Check if any of the clients we have left are unrelated to monitoring.

Parameters
shservice to check clients for
Returns
true if we have non-monitoring clients left

Definition at line 359 of file service.c.

360{
361 for (struct GNUNET_SERVICE_Client *client = sh->clients_head;
362 NULL != client;
363 client = client->next)
364 {
365 if (NULL != client->drop_task)
366 continue;
367 if (client->is_monitor)
368 continue;
369 return true;
370 }
371 return false;
372}

References sh.

Referenced by finish_client_drop(), GNUNET_SERVICE_client_mark_monitor(), and service_shutdown().

Here is the caller graph for this function:

◆ do_suspend()

static void do_suspend ( struct GNUNET_SERVICE_Handle sh,
enum SuspendReason  sr 
)
static

Suspend accepting connections from the listen socket temporarily.

Resume activity using do_resume.

Parameters
shservice to stop accepting connections.
srreason for suspending accepting connections

Definition at line 383 of file service.c.

385{
386 GNUNET_assert (0 == (sh->suspend_state & sr));
387 sh->suspend_state |= sr;
388 for (struct ServiceListenContext *slc = sh->slc_head;
389 NULL != slc;
390 slc = slc->next)
391 {
392 if (NULL != slc->listen_task)
393 {
394 GNUNET_SCHEDULER_cancel (slc->listen_task);
395 slc->listen_task = NULL;
396 }
397 }
398}

References GNUNET_assert, GNUNET_SCHEDULER_cancel(), and sh.

Referenced by accept_client(), GNUNET_SERVICE_shutdown(), GNUNET_SERVICE_suspend(), and service_shutdown().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ service_shutdown()

static void service_shutdown ( void *  cls)
static

Shutdown task triggered when a service should be terminated.

This considers active clients and the service options to see how this specific service is to be terminated, and depending on this proceeds with the shutdown logic.

Parameters
clsour struct GNUNET_SERVICE_Handle

Definition at line 410 of file service.c.

411{
412 struct GNUNET_SERVICE_Handle *sh = cls;
413
415 {
418 break;
420 /* This task should never be run if we are using
421 the manual shutdown. */
422 GNUNET_assert (0);
423 break;
425 if (0 == (sh->suspend_state & SUSPEND_STATE_SHUTDOWN))
429 break;
430 }
431}

References do_suspend(), GNUNET_assert, GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN, GNUNET_SERVICE_OPTION_NONE, GNUNET_SERVICE_OPTION_SHUTDOWN_BITMASK, GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN, GNUNET_SERVICE_shutdown(), have_non_monitor_clients(), sh, and SUSPEND_STATE_SHUTDOWN.

Referenced by service_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ check_ipv4_listed()

static bool check_ipv4_listed ( const struct GNUNET_STRINGS_IPv4NetworkPolicy list,
const struct in_addr *  add 
)
static

Check if the given IP address is in the list of IP addresses.

Parameters
lista list of networks
addthe IP to check (in network byte order)
Returns
false if the IP is not in the list, true if it it is

Definition at line 442 of file service.c.

444{
445 for (unsigned int i = 0;
446 0 != list[i].network.s_addr;
447 i++)
448 {
449 if ( (add->s_addr & list[i].netmask.s_addr) ==
450 (list[i].network.s_addr & list[i].netmask.s_addr) )
451 return true;
452 }
453 return false;
454}

References add, and list.

Referenced by accept_client().

Here is the caller graph for this function:

◆ check_ipv6_listed()

static bool check_ipv6_listed ( const struct GNUNET_STRINGS_IPv6NetworkPolicy list,
const struct in6_addr *  ip 
)
static

Check if the given IP address is in the list of IP addresses.

Parameters
lista list of networks
ipthe IP to check (in network byte order)
Returns
false if the IP is not in the list, true if it it is

Definition at line 465 of file service.c.

467{
468 for (unsigned int i = 0;
469 ! GNUNET_is_zero (&list[i].network);
470 i++)
471 {
472 bool match = true;
473
474 for (unsigned int j = 0; j < sizeof(struct in6_addr) / sizeof(int); j++)
475 if (((((int *) ip)[j] & ((int *) &list[i].netmask)[j])) !=
476 (((int *) &list[i].network)[j] & ((int *) &list[i].netmask)[j]))
477 {
478 match = false;
479 break;
480 }
481 if (match)
482 return true;
483 }
484 return false;
485}

References GNUNET_is_zero, and list.

Referenced by accept_client().

Here is the caller graph for this function:

◆ do_send()

static void do_send ( void *  cls)
static

Task run when we are ready to transmit data to the client.

Parameters
clsthe struct GNUNET_SERVICE_Client * to send to

Definition at line 495 of file service.c.

496{
497 struct GNUNET_SERVICE_Client *client = cls;
498 ssize_t ret;
499 size_t left;
500 const char *buf;
501
503 "service: sending message with type %u\n",
504 ntohs (client->msg->type));
505 client->send_task = NULL;
506 buf = (const char *) client->msg;
507 left = ntohs (client->msg->size) - client->msg_pos;
509 &buf[client->msg_pos],
510 left);
511 GNUNET_assert (ret <= (ssize_t) left);
512 if (0 == ret)
513 {
514 LOG (GNUNET_ERROR_TYPE_DEBUG, "no data send");
516 return;
517 }
518 if (-1 == ret)
519 {
520 if ((EAGAIN == errno) || (EINTR == errno))
521 {
522 /* ignore */
523 ret = 0;
524 }
525 else
526 {
527 if (EPIPE != errno)
530 "socket send returned with error code %i",
531 errno);
533 return;
534 }
535 }
536 if (0 == client->msg_pos)
537 {
539 }
540 client->msg_pos += ret;
541 if (left > (size_t) ret)
542 {
543 GNUNET_assert (NULL == client->drop_task);
544 client->send_task =
546 client->sock,
547 &do_send,
548 client);
549 return;
550 }
552}

References do_send(), GNUNET_SERVICE_Client::drop_task, GNUNET_assert, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_WARNING, GNUNET_log_strerror, GNUNET_MQ_ERROR_WRITE, GNUNET_MQ_impl_send_continue(), GNUNET_MQ_impl_send_in_flight(), GNUNET_MQ_inject_error(), GNUNET_NETWORK_socket_send(), GNUNET_SCHEDULER_add_write_net(), GNUNET_TIME_UNIT_FOREVER_REL, LOG, GNUNET_SERVICE_Client::mq, GNUNET_SERVICE_Client::msg, GNUNET_SERVICE_Client::msg_pos, ret, GNUNET_SERVICE_Client::send_task, GNUNET_MessageHeader::size, GNUNET_SERVICE_Client::sock, and GNUNET_MessageHeader::type.

Referenced by do_send(), and service_mq_send().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ service_mq_send()

static void service_mq_send ( struct GNUNET_MQ_Handle mq,
const struct GNUNET_MessageHeader msg,
void *  impl_state 
)
static

Signature of functions implementing the sending functionality of a message queue.

Parameters
mqthe message queue
msgthe message to send
impl_stateour struct GNUNET_SERVICE_Client *

Definition at line 564 of file service.c.

567{
568 struct GNUNET_SERVICE_Client *client = impl_state;
569
570 (void) mq;
571 if (NULL != client->drop_task)
572 return; /* we're going down right now, do not try to send */
573 GNUNET_assert (NULL == client->send_task);
575 "Sending message of type %u and size %u to client\n",
576 ntohs (msg->type),
577 ntohs (msg->size));
578 client->msg = msg;
579 client->msg_pos = 0;
581 client);
582}

References do_send(), GNUNET_SERVICE_Client::drop_task, GNUNET_assert, GNUNET_ERROR_TYPE_DEBUG, GNUNET_SCHEDULER_add_now(), LOG, mq, msg, GNUNET_SERVICE_Client::msg, GNUNET_SERVICE_Client::msg_pos, GNUNET_SERVICE_Client::send_task, GNUNET_MessageHeader::size, and GNUNET_MessageHeader::type.

Referenced by start_client().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ service_mq_cancel()

static void service_mq_cancel ( struct GNUNET_MQ_Handle mq,
void *  impl_state 
)
static

Implementation function that cancels the currently sent message.

Parameters
mqmessage queue
impl_statestate specific to the implementation

Definition at line 592 of file service.c.

594{
595 struct GNUNET_SERVICE_Client *client = impl_state;
596
597 (void) mq;
598 GNUNET_assert (0 == client->msg_pos);
599 client->msg = NULL;
601 client->send_task = NULL;
602}

References GNUNET_assert, GNUNET_SCHEDULER_cancel(), mq, GNUNET_SERVICE_Client::msg, GNUNET_SERVICE_Client::msg_pos, and GNUNET_SERVICE_Client::send_task.

Referenced by start_client().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ service_mq_error_handler()

static void service_mq_error_handler ( void *  cls,
enum GNUNET_MQ_Error  error 
)
static

Generic error handler, called with the appropriate error code and the same closure specified at the creation of the message queue.

Not every message queue implementation supports an error handler.

Parameters
clsclosure with our struct GNUNET_SERVICE_Client
errorerror code

Definition at line 615 of file service.c.

617{
618 struct GNUNET_SERVICE_Client *client = cls;
619 struct GNUNET_SERVICE_Handle *sh = client->sh;
620
621 if ( (GNUNET_MQ_ERROR_NO_MATCH == error) &&
622 (! sh->require_found) )
623 {
625 "No handler for message of type %u found\n",
626 (unsigned int) client->warn_type);
628 return; /* ignore error */
629 }
631}

References GNUNET_ERROR_TYPE_DEBUG, GNUNET_log, GNUNET_MQ_ERROR_NO_MATCH, GNUNET_SERVICE_client_continue(), GNUNET_SERVICE_client_drop(), sh, GNUNET_SERVICE_Client::sh, and GNUNET_SERVICE_Client::warn_type.

Referenced by start_client().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ warn_no_client_continue()

static void warn_no_client_continue ( void *  cls)
static

Task run to warn about missing calls to GNUNET_SERVICE_client_continue().

Parameters
clsour struct GNUNET_SERVICE_Client * to process more requests from

Definition at line 640 of file service.c.

641{
642 struct GNUNET_SERVICE_Client *client = cls;
643
645 0 !=
646 client->warn_type); /* type should never be 0 here, as we don't use 0 */
649 client);
650 LOG (
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,
656 client->warn_start),
657 GNUNET_YES));
658}

References _, GNUNET_break, GNUNET_ERROR_TYPE_WARNING, GNUNET_SCHEDULER_add_delayed(), GNUNET_STRINGS_relative_time_to_string(), GNUNET_TIME_absolute_get_duration(), GNUNET_TIME_UNIT_MINUTES, GNUNET_YES, LOG, warn_no_client_continue(), GNUNET_SERVICE_Client::warn_start, GNUNET_SERVICE_Client::warn_task, and GNUNET_SERVICE_Client::warn_type.

Referenced by service_client_mst_cb(), and warn_no_client_continue().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ service_client_mst_cb()

static int service_client_mst_cb ( void *  cls,
const struct GNUNET_MessageHeader message 
)
static

Functions with this signature are called whenever a complete message is received by the tokenizer for a client.

Do not call GNUNET_MST_destroy() from within the scope of this callback.

Parameters
clsclosure with the struct GNUNET_SERVICE_Client *
messagethe actual message
Returns
GNUNET_OK on success, GNUNET_SYSERR if the client was dropped

Definition at line 673 of file service.c.

675{
676 struct GNUNET_SERVICE_Client *client = cls;
677
679 "Received message of type %u and size %u from client\n",
680 ntohs (message->type),
681 ntohs (message->size));
682 GNUNET_assert (! client->needs_continue);
683 client->needs_continue = true;
684 client->warn_type = ntohs (message->type);
686 GNUNET_assert (NULL == client->warn_task);
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}

References GNUNET_SERVICE_Client::drop_task, GNUNET_assert, GNUNET_ERROR_TYPE_DEBUG, GNUNET_MQ_inject_message(), GNUNET_OK, GNUNET_SCHEDULER_add_delayed(), GNUNET_SYSERR, GNUNET_TIME_absolute_get(), GNUNET_TIME_UNIT_MINUTES, LOG, GNUNET_SERVICE_Client::mq, GNUNET_SERVICE_Client::needs_continue, GNUNET_MessageHeader::size, GNUNET_MessageHeader::type, warn_no_client_continue(), GNUNET_SERVICE_Client::warn_start, GNUNET_SERVICE_Client::warn_task, and GNUNET_SERVICE_Client::warn_type.

Referenced by start_client().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ service_client_recv()

static void service_client_recv ( void *  cls)
static

A client sent us data.

Receive and process it. If we are done, reschedule this task.

Parameters
clsthe struct GNUNET_SERVICE_Client that sent us data.

Definition at line 704 of file service.c.

705{
706 struct GNUNET_SERVICE_Client *client = cls;
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 (! client->needs_continue);
721 }
722 return;
723 }
724 if (GNUNET_NO == ret)
725 return; /* more messages in buffer, wait for application
726 to be done processing */
728 if (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 =
735 client->sock,
737 client);
738}

References GNUNET_SERVICE_Client::drop_task, GNUNET_assert, GNUNET_MST_read(), GNUNET_NO, GNUNET_OK, GNUNET_SCHEDULER_add_read_net(), GNUNET_SERVICE_client_drop(), GNUNET_SYSERR, GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_YES, GNUNET_SERVICE_Client::mst, GNUNET_SERVICE_Client::needs_continue, GNUNET_SERVICE_Client::recv_task, ret, service_client_recv(), and GNUNET_SERVICE_Client::sock.

Referenced by resume_client_receive(), service_client_recv(), and start_client().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ start_client()

static void start_client ( struct GNUNET_SERVICE_Handle sh,
struct GNUNET_NETWORK_Handle csock 
)
static

We have successfully accepted a connection from a client.

Now setup the client (with the scheduler) and tell the application.

Parameters
shservice that accepted the client
csocksocket associated with the client

Definition at line 749 of file service.c.

751{
752 struct GNUNET_SERVICE_Client *client;
753
754 client = GNUNET_new (struct GNUNET_SERVICE_Client);
755 GNUNET_CONTAINER_DLL_insert (sh->clients_head,
756 sh->clients_tail,
757 client);
758 client->sh = sh;
759 client->sock = csock;
761 NULL,
763 client,
764 sh->handlers,
766 client);
767 client->mst = GNUNET_MST_create (&service_client_mst_cb, client);
768 if (NULL != sh->connect_cb)
769 client->user_context = sh->connect_cb (sh->cb_cls, client, client->mq);
771 client->recv_task =
773 client->sock,
775 client);
776}

References GNUNET_IDENTITY_Handle::cb_cls, GNUNET_CONTAINER_DLL_insert, GNUNET_MQ_queue_for_callbacks(), GNUNET_MQ_set_handlers_closure(), GNUNET_MST_create(), GNUNET_new, GNUNET_SCHEDULER_add_read_net(), GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_SERVICE_Client::mq, GNUNET_SERVICE_Client::mst, GNUNET_SERVICE_Client::recv_task, service_client_mst_cb(), service_client_recv(), service_mq_cancel(), service_mq_error_handler(), service_mq_send(), sh, GNUNET_SERVICE_Client::sh, GNUNET_SERVICE_Client::sock, and GNUNET_SERVICE_Client::user_context.

Referenced by accept_client().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ accept_client()

static void accept_client ( void *  cls)
static

We have a client.

Accept the incoming socket(s) (and reschedule the listen task).

Parameters
clsthe struct ServiceListenContext of the ready listen socket

Definition at line 786 of file service.c.

787{
788 struct ServiceListenContext *slc = cls;
789 struct GNUNET_SERVICE_Handle *sh = slc->sh;
790
791 slc->listen_task = NULL;
792 while (1)
793 {
794 struct GNUNET_NETWORK_Handle *sock;
795 const struct sockaddr_in *v4;
796 const struct sockaddr_in6 *v6;
797 struct sockaddr_storage sa;
798 socklen_t addrlen;
799 int ok;
800
801 addrlen = sizeof(sa);
803 (struct sockaddr *) &sa,
804 &addrlen);
805 if (NULL == sock)
806 {
807 if (EMFILE == errno)
809 else if (EAGAIN != errno)
811 "accept");
812 break;
813 }
814 switch (sa.ss_family)
815 {
816 case AF_INET:
817 GNUNET_assert (addrlen == sizeof(struct sockaddr_in));
818 v4 = (const struct sockaddr_in *) &sa;
819 ok = (((NULL == sh->v4_allowed) ||
820 (check_ipv4_listed (sh->v4_allowed,
821 &v4->sin_addr))) &&
822 ((NULL == sh->v4_denied) ||
823 (! check_ipv4_listed (sh->v4_denied,
824 &v4->sin_addr))));
825 break;
826
827 case AF_INET6:
828 GNUNET_assert (addrlen == sizeof(struct sockaddr_in6));
829 v6 = (const struct sockaddr_in6 *) &sa;
830 ok = (((NULL == sh->v6_allowed) ||
831 (check_ipv6_listed (sh->v6_allowed,
832 &v6->sin6_addr))) &&
833 ((NULL == sh->v6_denied) ||
834 (! check_ipv6_listed (sh->v6_denied,
835 &v6->sin6_addr))));
836 break;
837
838 case AF_UNIX:
839 ok = GNUNET_OK; /* controlled using file-system ACL now */
840 break;
841
842 default:
844 _ ("Unknown address family %d\n"),
845 sa.ss_family);
846 return;
847 }
848 if (! ok)
849 {
851 "Service rejected incoming connection from %s due to policy.\n",
852 GNUNET_a2s ((const struct sockaddr *) &sa, addrlen));
854 continue;
855 }
857 "Service accepted incoming connection from %s.\n",
858 GNUNET_a2s ((const struct sockaddr *) &sa, addrlen));
859 start_client (slc->sh,
860 sock);
861 }
862 if (0 != sh->suspend_state)
863 return;
864 slc->listen_task =
866 slc->listen_socket,
868 slc);
869}

References _, accept_client(), check_ipv4_listed(), check_ipv6_listed(), do_suspend(), GNUNET_a2s(), GNUNET_assert, GNUNET_break, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_WARNING, GNUNET_log_strerror, GNUNET_NETWORK_socket_accept(), GNUNET_NETWORK_socket_close(), GNUNET_OK, GNUNET_SCHEDULER_add_read_net(), GNUNET_TIME_UNIT_FOREVER_REL, ServiceListenContext::listen_socket, ServiceListenContext::listen_task, LOG, sh, ServiceListenContext::sh, start_client(), and SUSPEND_STATE_EMFILE.

Referenced by accept_client(), and do_resume().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ do_resume()

static void do_resume ( struct GNUNET_SERVICE_Handle sh,
enum SuspendReason  sr 
)
static

Resume accepting connections from the listen socket.

Parameters
shservice to resume accepting connections.
srreason that is no longer causing the suspension, or SUSPEND_STATE_NONE on first startup

Definition at line 880 of file service.c.

882{
883 GNUNET_assert ((SUSPEND_STATE_NONE == sr) || (0 != (sh->suspend_state & sr)));
884 sh->suspend_state -= sr;
885 if (SUSPEND_STATE_NONE != sh->suspend_state)
886 return;
887 for (struct ServiceListenContext *slc = sh->slc_head;
888 NULL != slc;
889 slc = slc->next)
890 {
891 GNUNET_assert (NULL == slc->listen_task);
892 slc->listen_task =
894 slc->listen_socket,
896 slc);
897 }
898}

References accept_client(), GNUNET_assert, GNUNET_SCHEDULER_add_read_net(), GNUNET_TIME_UNIT_FOREVER_REL, sh, and SUSPEND_STATE_NONE.

Referenced by finish_client_drop(), GNUNET_SERVICE_resume(), GNUNET_SERVICE_start(), and service_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ service_main()

static void service_main ( void *  cls)
static

First task run by any service.

Initializes our shutdown task, starts the listening operation on our listen sockets and launches the custom logic of the application service.

Parameters
clsour struct GNUNET_SERVICE_Handle

Definition at line 909 of file service.c.

910{
911 struct GNUNET_SERVICE_Handle *sh = cls;
912
917
918 if (-1 != sh->ready_confirm_fd)
919 {
920 GNUNET_break (1 == write (sh->ready_confirm_fd, ".", 1));
921 GNUNET_break (0 == close (sh->ready_confirm_fd));
922 sh->ready_confirm_fd = -1;
923 }
924
925 if (NULL != sh->service_init_cb)
926 sh->service_init_cb (sh->cb_cls, sh->cfg, sh);
927}

References GNUNET_IDENTITY_Handle::cb_cls, GNUNET_IDENTITY_Handle::cfg, do_resume(), GNUNET_break, GNUNET_SCHEDULER_add_shutdown(), GNUNET_SERVICE_OPTION_MANUAL_SHUTDOWN, GNUNET_SERVICE_OPTION_SHUTDOWN_BITMASK, service_shutdown(), sh, and SUSPEND_STATE_NONE.

Referenced by GNUNET_SERVICE_run_(), and launch_registered_services().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_acl4()

static enum GNUNET_GenericReturnValue process_acl4 ( struct GNUNET_STRINGS_IPv4NetworkPolicy **  ret,
struct GNUNET_SERVICE_Handle sh,
const char *  option 
)
static

Parse an IPv4 access control list.

Parameters
retlocation where to write the ACL (set)
shservice context to use to get the configuration
optionname of the ACL option to parse
Returns
GNUNET_SYSERR on parse error, GNUNET_OK on success (including no ACL configured)

Definition at line 940 of file service.c.

943{
944 char *opt;
945
946 if (! GNUNET_CONFIGURATION_have_value (sh->cfg, sh->service_name, option))
947 {
948 *ret = NULL;
949 return GNUNET_OK;
950 }
953 sh->service_name,
954 option,
955 &opt));
956 if (NULL == (*ret = GNUNET_STRINGS_parse_ipv4_policy (opt)))
957 {
959 _ ("Could not parse IPv4 network specification `%s' for `%s:%s'\n"),
960 opt,
961 sh->service_name,
962 option);
963 GNUNET_free (opt);
964 return GNUNET_SYSERR;
965 }
966 GNUNET_free (opt);
967 return GNUNET_OK;
968}

References _, GNUNET_IDENTITY_Handle::cfg, GNUNET_break, GNUNET_CONFIGURATION_get_value_string(), GNUNET_CONFIGURATION_have_value(), GNUNET_ERROR_TYPE_WARNING, GNUNET_free, GNUNET_OK, GNUNET_STRINGS_parse_ipv4_policy(), GNUNET_SYSERR, LOG, ret, and sh.

Referenced by setup_service().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ process_acl6()

static enum GNUNET_GenericReturnValue process_acl6 ( struct GNUNET_STRINGS_IPv6NetworkPolicy **  ret,
struct GNUNET_SERVICE_Handle sh,
const char *  option 
)
static

Parse an IPv6 access control list.

Parameters
retlocation where to write the ACL (set)
shservice context to use to get the configuration
optionname of the ACL option to parse
Returns
GNUNET_SYSERR on parse error, GNUNET_OK on success (including no ACL configured)

Definition at line 981 of file service.c.

984{
985 char *opt;
986
987 if (! GNUNET_CONFIGURATION_have_value (sh->cfg, sh->service_name, option))
988 {
989 *ret = NULL;
990 return GNUNET_OK;
991 }
994 sh->service_name,
995 option,
996 &opt));
997 if (NULL == (*ret = GNUNET_STRINGS_parse_ipv6_policy (opt)))
998 {
1000 _ ("Could not parse IPv6 network specification `%s' for `%s:%s'\n"),
1001 opt,
1002 sh->service_name,
1003 option);
1004 GNUNET_free (opt);
1005 return GNUNET_SYSERR;
1006 }
1007 GNUNET_free (opt);
1008 return GNUNET_OK;
1009}

References _, GNUNET_IDENTITY_Handle::cfg, GNUNET_break, GNUNET_CONFIGURATION_get_value_string(), GNUNET_CONFIGURATION_have_value(), GNUNET_ERROR_TYPE_WARNING, GNUNET_free, GNUNET_OK, GNUNET_STRINGS_parse_ipv6_policy(), GNUNET_SYSERR, LOG, ret, and sh.

Referenced by setup_service().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ add_unixpath()

static void add_unixpath ( struct sockaddr **  saddrs,
socklen_t *  saddrlens,
const char *  unixpath 
)
static

Add the given UNIX domain path as an address to the list (as the first entry).

Parameters
saddrsarray to update
saddrlenswhere to store the address length
unixpathpath to add

Definition at line 1021 of file service.c.

1024{
1025#ifdef AF_UNIX
1026 struct sockaddr_un *un;
1027
1028 un = GNUNET_new (struct sockaddr_un);
1029 un->sun_family = AF_UNIX;
1030 GNUNET_strlcpy (un->sun_path, unixpath, sizeof(un->sun_path));
1031#if HAVE_SOCKADDR_UN_SUN_LEN
1032 un->sun_len = (u_char) sizeof(struct sockaddr_un);
1033#endif
1034 *saddrs = (struct sockaddr *) un;
1035 *saddrlens = sizeof(struct sockaddr_un);
1036#else
1037 /* this function should never be called
1038 * unless AF_UNIX is defined! */
1039 GNUNET_assert (0);
1040#endif
1041}

References GNUNET_assert, GNUNET_new, and GNUNET_strlcpy().

Referenced by get_server_addresses().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_server_addresses()

static int get_server_addresses ( const char *  service_name,
const struct GNUNET_CONFIGURATION_Handle cfg,
struct sockaddr ***  addrs,
socklen_t **  addr_lens 
)
static

Get the list of addresses that a server for the given service should bind to.

Parameters
service_namename of the service
cfgconfiguration (which specifies the addresses)
addrsset (call by reference) to an array of pointers to the addresses the server should bind to and listen on; the array will be NULL-terminated (on success)
addr_lensset (call by reference) to an array of the lengths of the respective struct sockaddr struct in the addrs array (on success)
Returns
number of addresses found on success, GNUNET_SYSERR if the configuration did not specify reasonable finding information or if it specified a hostname that could not be resolved; GNUNET_NO if the number of addresses configured is zero (in this case, *addrs and *addr_lens will be set to NULL).

Definition at line 1065 of file service.c.

1069{
1070 bool disablev6;
1071 struct GNUNET_NETWORK_Handle *desc;
1072 unsigned long long port;
1073 char *unixpath;
1074 struct addrinfo hints;
1075 struct addrinfo *res;
1076 struct addrinfo *pos;
1077 struct addrinfo *next;
1078 unsigned int i;
1079 int resi;
1080 int ret;
1081 struct sockaddr **saddrs;
1082 socklen_t *saddrlens;
1083 char *hostname;
1084
1085 *addrs = NULL;
1086 *addr_lens = NULL;
1087 desc = NULL;
1088 disablev6 = false;
1089 if ((GNUNET_NO ==
1090 GNUNET_NETWORK_test_pf (PF_INET6)) ||
1091 (GNUNET_YES ==
1094 "DISABLEV6")))
1095 disablev6 = true;
1096
1097 port = 0;
1098 if (GNUNET_SYSERR ==
1101 "PORT",
1102 &port))
1103 {
1105 _ ("Require valid port number for service `%s' in configuration!\n"),
1106 service_name);
1107 }
1108 if (port > 65535)
1109 {
1111 _ ("Require valid port number for service `%s' in configuration!\n"),
1112 service_name);
1113 return GNUNET_SYSERR;
1114 }
1115
1116 hostname = NULL;
1120 "BINDTO",
1121 &hostname));
1122
1123 unixpath = NULL;
1124#ifdef AF_UNIX
1125 if ( (GNUNET_OK ==
1128 "UNIXPATH",
1129 &unixpath)) &&
1130 (0 < strlen (unixpath)) )
1131 {
1132 /* probe UNIX support */
1133 struct sockaddr_un s_un;
1134
1135 if (strlen (unixpath) >= sizeof(s_un.sun_path))
1136 {
1138 "UNIXPATH `%s' too long, maximum length is %llu\n",
1139 unixpath,
1140 (unsigned long long) sizeof(s_un.sun_path));
1141 unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
1143 _ ("Using `%s' instead\n"),
1144 unixpath);
1145 }
1146 if (GNUNET_OK !=
1149 "mkdir",
1150 unixpath);
1151 }
1152 if (NULL != unixpath)
1153 {
1154 desc = GNUNET_NETWORK_socket_create (AF_UNIX,
1155 SOCK_STREAM,
1156 0);
1157 if (NULL == desc)
1158 {
1159 if ((ENOBUFS == errno) ||
1160 (ENOMEM == errno) ||
1161 (ENFILE == errno) ||
1162 (EACCES == errno))
1163 {
1165 "socket");
1166 GNUNET_free (hostname);
1167 GNUNET_free (unixpath);
1168 return GNUNET_SYSERR;
1169 }
1171 "Failed to create UNIX domain socket for service %s: %s\n",
1173 strerror (errno));
1174 GNUNET_free (unixpath);
1175 unixpath = NULL;
1176 }
1177 else
1178 {
1181 desc = NULL;
1182 }
1183 }
1184#endif
1185
1186 if ( (0 == port) &&
1187 (NULL == unixpath) )
1188 {
1190 "Have neither PORT nor UNIXPATH for service `%s', but one is required\n",
1191 service_name);
1192 GNUNET_free (hostname);
1193 return GNUNET_SYSERR;
1194 }
1195 if (0 == port)
1196 {
1197 saddrs = GNUNET_new_array (2, struct sockaddr *);
1198 saddrlens = GNUNET_new_array (2, socklen_t);
1199 add_unixpath (saddrs, saddrlens, unixpath);
1200 GNUNET_free (unixpath);
1201 GNUNET_free (hostname);
1202 *addrs = saddrs;
1203 *addr_lens = saddrlens;
1204 return 1;
1205 }
1206
1207 if (NULL != hostname)
1208 {
1210 "Resolving `%s' since that is where `%s' will bind to.\n",
1211 hostname,
1212 service_name);
1213 memset (&hints, 0, sizeof(struct addrinfo));
1214 if (disablev6)
1215 hints.ai_family = AF_INET;
1216 hints.ai_protocol = IPPROTO_TCP;
1217 if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
1218 (NULL == res))
1219 {
1221 _ ("Failed to resolve `%s': %s\n"),
1222 hostname,
1223 gai_strerror (ret));
1224 GNUNET_free (hostname);
1225 GNUNET_free (unixpath);
1226 return GNUNET_SYSERR;
1227 }
1228 next = res;
1229 i = 0;
1230 while (NULL != (pos = next))
1231 {
1232 next = pos->ai_next;
1233 if ((disablev6) && (pos->ai_family == AF_INET6))
1234 continue;
1235 i++;
1236 }
1237 if (0 == i)
1238 {
1240 _ ("Failed to find %saddress for `%s'.\n"),
1241 disablev6 ? "IPv4 " : "",
1242 hostname);
1243 freeaddrinfo (res);
1244 GNUNET_free (hostname);
1245 GNUNET_free (unixpath);
1246 return GNUNET_SYSERR;
1247 }
1248 resi = i;
1249 if (NULL != unixpath)
1250 resi++;
1251 saddrs = GNUNET_new_array (resi + 1, struct sockaddr *);
1252 saddrlens = GNUNET_new_array (resi + 1, socklen_t);
1253 i = 0;
1254 if (NULL != unixpath)
1255 {
1256 add_unixpath (saddrs, saddrlens, unixpath);
1257 i++;
1258 }
1259 next = res;
1260 while (NULL != (pos = next))
1261 {
1262 next = pos->ai_next;
1263 if ((disablev6) && (AF_INET6 == pos->ai_family))
1264 continue;
1265 if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol))
1266 continue; /* not TCP */
1267 if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
1268 continue; /* huh? */
1270 "Service `%s' will bind to `%s'\n",
1272 GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
1273 if (AF_INET == pos->ai_family)
1274 {
1275 GNUNET_assert (sizeof(struct sockaddr_in) == pos->ai_addrlen);
1276 saddrlens[i] = pos->ai_addrlen;
1277 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1278 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
1279 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1280 }
1281 else
1282 {
1283 GNUNET_assert (AF_INET6 == pos->ai_family);
1284 GNUNET_assert (sizeof(struct sockaddr_in6) == pos->ai_addrlen);
1285 saddrlens[i] = pos->ai_addrlen;
1286 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1287 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
1288 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
1289 }
1290 i++;
1291 }
1292 GNUNET_free (hostname);
1293 freeaddrinfo (res);
1294 resi = i;
1295 }
1296 else
1297 {
1298 /* will bind against everything, just set port */
1299 if (disablev6)
1300 {
1301 /* V4-only */
1302 resi = 1;
1303 if (NULL != unixpath)
1304 resi++;
1305 i = 0;
1306 saddrs = GNUNET_new_array (resi + 1, struct sockaddr *);
1307 saddrlens = GNUNET_new_array (resi + 1, socklen_t);
1308 if (NULL != unixpath)
1309 {
1310 add_unixpath (saddrs, saddrlens, unixpath);
1311 i++;
1312 }
1313 saddrlens[i] = sizeof(struct sockaddr_in);
1314 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1315#if HAVE_SOCKADDR_IN_SIN_LEN
1316 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
1317#endif
1318 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
1319 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1320 }
1321 else
1322 {
1323 /* dual stack */
1324 resi = 2;
1325 if (NULL != unixpath)
1326 resi++;
1327 saddrs = GNUNET_new_array (resi + 1, struct sockaddr *);
1328 saddrlens = GNUNET_new_array (resi + 1, socklen_t);
1329 i = 0;
1330 if (NULL != unixpath)
1331 {
1332 add_unixpath (saddrs, saddrlens, unixpath);
1333 i++;
1334 }
1335 saddrlens[i] = sizeof(struct sockaddr_in6);
1336 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1337#if HAVE_SOCKADDR_IN_SIN_LEN
1338 ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
1339#endif
1340 ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
1341 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
1342 i++;
1343 saddrlens[i] = sizeof(struct sockaddr_in);
1344 saddrs[i] = GNUNET_malloc (saddrlens[i]);
1345#if HAVE_SOCKADDR_IN_SIN_LEN
1346 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
1347#endif
1348 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
1349 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
1350 }
1351 }
1352 GNUNET_free (unixpath);
1353 *addrs = saddrs;
1354 *addr_lens = saddrlens;
1355 return resi;
1356}

References _, add_unixpath(), cfg, GNUNET_a2s(), GNUNET_assert, GNUNET_break, GNUNET_CONFIGURATION_get_value_filename(), GNUNET_CONFIGURATION_get_value_number(), GNUNET_CONFIGURATION_get_value_string(), GNUNET_CONFIGURATION_get_value_yesno(), GNUNET_DISK_directory_create_for_file(), GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_ERROR_TYPE_INFO, GNUNET_ERROR_TYPE_WARNING, GNUNET_free, GNUNET_log_strerror_file, GNUNET_malloc, GNUNET_memcpy, GNUNET_NETWORK_shorten_unixpath(), GNUNET_NETWORK_socket_close(), GNUNET_NETWORK_socket_create(), GNUNET_NETWORK_test_pf(), GNUNET_new_array, GNUNET_NO, GNUNET_OK, GNUNET_SYSERR, GNUNET_YES, LOG, LOG_STRERROR, port, res, ret, and service_name.

Referenced by setup_service().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ open_listen_socket()

static struct GNUNET_NETWORK_Handle * open_listen_socket ( const struct sockaddr *  server_addr,
socklen_t  socklen 
)
static

Create and initialize a listen socket for the server.

Parameters
server_addraddress to listen on
socklenlength of server_addr
Returns
NULL on error, otherwise the listen socket

Definition at line 1367 of file service.c.

1369{
1370 struct GNUNET_NETWORK_Handle *sock;
1371 uint16_t port;
1372 int eno;
1373
1374 switch (server_addr->sa_family)
1375 {
1376 case AF_INET:
1377 port = ntohs (((const struct sockaddr_in *) server_addr)->sin_port);
1378 break;
1379 case AF_INET6:
1380 port = ntohs (((const struct sockaddr_in6 *) server_addr)->sin6_port);
1381 break;
1382 case AF_UNIX:
1383 port = 0;
1384 break;
1385 default:
1386 GNUNET_break (0);
1387 port = 0;
1388 break;
1389 }
1390 sock = GNUNET_NETWORK_socket_create (server_addr->sa_family,
1391 SOCK_STREAM,
1392 0);
1393 if (NULL == sock)
1394 {
1396 "socket");
1397 errno = 0;
1398 return NULL;
1399 }
1400 /* bind the socket */
1401 if (GNUNET_OK !=
1403 server_addr,
1404 socklen))
1405 {
1406 eno = errno;
1407 if (EADDRINUSE != errno)
1408 {
1409 /* we don't log 'EADDRINUSE' here since an IPv4 bind may
1410 * fail if we already took the port on IPv6; if both IPv4 and
1411 * IPv6 binds fail, then our caller will log using the
1412 * errno preserved in 'eno' */
1413 if (0 != port)
1415 _ ("`%s' failed for port %d (%s).\n"),
1416 "bind",
1417 port,
1418 (AF_INET == server_addr->sa_family) ? "IPv4" : "IPv6");
1419 else
1421 eno = 0;
1422 }
1423 else
1424 {
1425 if (0 != port)
1427 _ ("`%s' failed for port %d (%s): address already in use\n"),
1428 "bind",
1429 port,
1430 (AF_INET == server_addr->sa_family) ? "IPv4" : "IPv6");
1431 else if (AF_UNIX == server_addr->sa_family)
1432 {
1434 _ ("`%s' failed for `%s': address already in use\n"),
1435 "bind",
1436 GNUNET_a2s (server_addr, socklen));
1437 }
1438 }
1440 errno = eno;
1441 return NULL;
1442 }
1443 if (GNUNET_OK != GNUNET_NETWORK_socket_listen (sock, 5))
1444 {
1447 errno = 0;
1448 return NULL;
1449 }
1450 if (0 != port)
1452 "Server starts to listen on port %u.\n",
1453 port);
1454 return sock;
1455}

References _, GNUNET_a2s(), GNUNET_break, GNUNET_ERROR_TYPE_DEBUG, GNUNET_ERROR_TYPE_ERROR, GNUNET_ERROR_TYPE_WARNING, GNUNET_NETWORK_socket_bind(), GNUNET_NETWORK_socket_close(), GNUNET_NETWORK_socket_create(), GNUNET_NETWORK_socket_listen(), GNUNET_OK, LOG, LOG_STRERROR, and port.

Referenced by setup_service().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ setup_service()

static enum GNUNET_GenericReturnValue setup_service ( const struct GNUNET_OS_ProjectData pd,
struct GNUNET_SERVICE_Handle sh 
)
static

Setup service handle.

Configuration may specify:

  • PORT (where to bind to for TCP)
  • UNIXPATH (where to bind to for UNIX domain sockets)
  • DISABLEV6 (disable support for IPv6, otherwise we use dual-stack)
  • BINDTO (hostname or IP address to bind to, otherwise we take everything)
  • ACCEPT_FROM (only allow connections from specified IPv4 subnets)
  • ACCEPT_FROM6 (only allow connections from specified IPv6 subnets)
  • REJECT_FROM (disallow allow connections from specified IPv4 subnets)
  • REJECT_FROM6 (disallow allow connections from specified IPv6 subnets)
Parameters
pdproject data to use for the service
shservice context to initialize
Returns
GNUNET_OK if configuration succeeded

Definition at line 1476 of file service.c.

1478{
1479 int tolerant;
1480 struct GNUNET_NETWORK_Handle **csocks = NULL;
1481 struct GNUNET_NETWORK_Handle **lsocks;
1482 const char *nfds;
1483 const char *fdns;
1484 unsigned int cnt;
1485 int flags;
1486 char dummy;
1487
1489 sh->service_name,
1490 "TOLERANT"))
1491 {
1492 if (GNUNET_SYSERR ==
1494 sh->service_name,
1495 "TOLERANT")))
1496 {
1498 _ ("Specified value for `%s' of service `%s' is invalid\n"),
1499 "TOLERANT",
1500 sh->service_name);
1501 return GNUNET_SYSERR;
1502 }
1503 }
1504 else
1505 tolerant = GNUNET_NO;
1506
1507 lsocks = NULL;
1508 errno = 0;
1509 if ( (NULL != (nfds = getenv ("LISTEN_FDS"))) &&
1510 (NULL != (fdns = getenv ("LISTEN_FDNAMES"))) &&
1511 (1 == sscanf (nfds,
1512 "%u%c",
1513 &cnt,
1514 &dummy)) &&
1515 (cnt > 0) &&
1516 (cnt < FD_SETSIZE) )
1517 {
1518 char *fdnames;
1519 unsigned int pos;
1520
1521 lsocks = GNUNET_new_array (cnt + 1,
1522 struct GNUNET_NETWORK_Handle *);
1523 fdnames = GNUNET_strdup (fdns);
1524 pos = 0;
1525 for (const char *tok = strtok (fdnames,
1526 ":");
1527 NULL != tok;
1528 tok = strtok (NULL, ":"))
1529 {
1530 unsigned int fd;
1531
1532 if (pos == cnt)
1533 {
1535 "More than LISTEN_FDS sockets given in LISTEN_FDNAMES\n");
1536 break;
1537 }
1538 if (1 != sscanf (tok,
1539 "%u%c",
1540 &fd,
1541 &dummy))
1542 {
1544 "Malformed socket given in LISTEN_FDNAMES than in LISTEN_FDS\n");
1545 break;
1546 }
1547 if (fd >= FD_SETSIZE)
1548 {
1550 "Socket given in LISTEN_FDNAMES outside of select()able range\n");
1551 break;
1552 }
1553 flags = fcntl ((int) fd,
1554 F_GETFD);
1555 if ((flags < 0) ||
1556 (0 != (flags & FD_CLOEXEC)) ||
1557 (NULL == (lsocks[pos] = GNUNET_NETWORK_socket_box_native ((int) fd))))
1558 {
1560 "Could not access pre-bound socket %u\n",
1561 fd);
1562 break;
1563 }
1564 pos++;
1565 }
1566 if (0 == pos)
1567 {
1568 for (unsigned int i=0; i<cnt; i++)
1570 GNUNET_NETWORK_socket_close (lsocks[i]));
1571 GNUNET_free (lsocks);
1572 }
1573 unsetenv ("LISTEN_FDS");
1574 cnt = pos;
1575 }
1576 if ( (0 != (GNUNET_SERVICE_OPTION_CLOSE_LSOCKS & sh->options)) &&
1577 (NULL != lsocks) )
1578 {
1579 csocks = lsocks;
1580 lsocks = NULL;
1581 }
1582
1583 if (NULL != lsocks)
1584 {
1585 /* listen only on inherited sockets if we have any */
1586 for (struct GNUNET_NETWORK_Handle **ls = lsocks; NULL != *ls; ls++)
1587 {
1588 struct ServiceListenContext *slc;
1589
1590 slc = GNUNET_new (struct ServiceListenContext);
1591 slc->sh = sh;
1592 slc->listen_socket = *ls;
1594 sh->slc_tail,
1595 slc);
1596 }
1597 GNUNET_free (lsocks);
1598 }
1599 else
1600 {
1601 struct sockaddr **addrs;
1602 socklen_t *addrlens;
1603 int num;
1604
1605 num = get_server_addresses (sh->service_name,
1606 sh->cfg,
1607 &addrs,
1608 &addrlens);
1609 if (GNUNET_SYSERR == num)
1610 {
1611 GNUNET_free (csocks);
1612 return GNUNET_SYSERR;
1613 }
1614
1615 for (int i = 0; i < num; i++)
1616 {
1617 struct ServiceListenContext *slc;
1618
1619 slc = GNUNET_new (struct ServiceListenContext);
1620 slc->sh = sh;
1621 slc->listen_socket = open_listen_socket (addrs[i],
1622 addrlens[i]);
1623 GNUNET_free (addrs[i]);
1624 if (NULL == slc->listen_socket)
1625 {
1627 GNUNET_free (slc);
1628 continue;
1629 }
1631 sh->slc_tail,
1632 slc);
1633 }
1634 GNUNET_free (addrlens);
1635 GNUNET_free (addrs);
1636 if ((0 != num) && (NULL == sh->slc_head))
1637 {
1638 /* All attempts to bind failed, hard failure */
1639 GNUNET_log (
1641 "Could not bind to any of the ports I was supposed to, refusing to run!\n");
1642 GNUNET_free (csocks);
1643 return GNUNET_SYSERR;
1644 }
1645 }
1646 if (NULL != csocks)
1647 {
1648 /* close inherited sockets to signal parent that we are ready */
1649 for (struct GNUNET_NETWORK_Handle **ls = csocks; NULL != *ls; ls++)
1651 GNUNET_free (csocks);
1652 }
1653 sh->require_found = (GNUNET_NO == tolerant);
1655 sh->service_name,
1656 "UNIX_MATCH_UID");
1658 sh->service_name,
1659 "UNIX_MATCH_GID");
1660 process_acl4 (&sh->v4_denied, sh, "REJECT_FROM");
1661 process_acl4 (&sh->v4_allowed, sh, "ACCEPT_FROM");
1662 process_acl6 (&sh->v6_denied, sh, "REJECT_FROM6");
1663 process_acl6 (&sh->v6_allowed, sh, "ACCEPT_FROM6");
1664 return GNUNET_OK;
1665}

References _, GNUNET_IDENTITY_Handle::cfg, dummy, GNUNET_NETWORK_Handle::fd, get_server_addresses(), getenv(), GNUNET_break, GNUNET_CONFIGURATION_get_value_yesno(), GNUNET_CONFIGURATION_have_value(), GNUNET_CONTAINER_DLL_insert, GNUNET_ERROR_TYPE_ERROR, GNUNET_ERROR_TYPE_WARNING, GNUNET_free, GNUNET_log, GNUNET_log_strerror, GNUNET_NETWORK_socket_box_native(), GNUNET_NETWORK_socket_close(), GNUNET_new, GNUNET_new_array, GNUNET_NO, GNUNET_OK, GNUNET_SERVICE_OPTION_CLOSE_LSOCKS, GNUNET_strdup, GNUNET_SYSERR, ServiceListenContext::listen_socket, LOG, ls, open_listen_socket(), process_acl4(), process_acl6(), sh, and ServiceListenContext::sh.

Referenced by GNUNET_SERVICE_run_(), GNUNET_SERVICE_start(), and launch_registered_services().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_user_name()

static char * get_user_name ( struct GNUNET_SERVICE_Handle sh)
static

Get the name of the user that'll be used to provide the service.

Parameters
shservice context
Returns
value of the 'USERNAME' option

Definition at line 1676 of file service.c.

1677{
1678 char *un;
1679
1680 if (GNUNET_OK !=
1682 sh->service_name,
1683 "USERNAME",
1684 &un))
1685 return NULL;
1686 return un;
1687}

References GNUNET_IDENTITY_Handle::cfg, GNUNET_CONFIGURATION_get_value_filename(), GNUNET_OK, and sh.

Referenced by set_user_id().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ set_user_id()

static enum GNUNET_GenericReturnValue set_user_id ( struct GNUNET_SERVICE_Handle sh)
static

Set user ID.

Parameters
shservice context
Returns
GNUNET_OK on success, GNUNET_SYSERR on error

Definition at line 1697 of file service.c.

1698{
1699 char *user;
1700 struct passwd *pws;
1701
1702 if (NULL == (user = get_user_name (sh)))
1703 return GNUNET_OK; /* keep */
1704 errno = 0;
1705 pws = getpwnam (user);
1706 if (NULL == pws)
1707 {
1709 _ ("Cannot obtain information about user `%s': %s\n"),
1710 user,
1711 errno == 0 ? _ ("No such user") : strerror (errno));
1712 GNUNET_free (user);
1713 return GNUNET_SYSERR;
1714 }
1715 if ((0 != setgid (pws->pw_gid)) || (0 != setegid (pws->pw_gid)) ||
1716#if HAVE_INITGROUPS
1717 (0 != initgroups (user, pws->pw_gid)) ||
1718#endif
1719 (0 != setuid (pws->pw_uid)) ||
1720 (0 != seteuid (pws->pw_uid)))
1721 {
1722 if ((0 != setregid (pws->pw_gid, pws->pw_gid)) ||
1723 (0 != setreuid (pws->pw_uid, pws->pw_uid)))
1724 {
1726 _ ("Cannot change user/group to `%s': %s\n"),
1727 user,
1728 strerror (errno));
1729 GNUNET_free (user);
1730 return GNUNET_SYSERR;
1731 }
1732 }
1733
1734 GNUNET_free (user);
1735 return GNUNET_OK;
1736}

References _, get_user_name(), GNUNET_ERROR_TYPE_ERROR, GNUNET_free, GNUNET_OK, GNUNET_SYSERR, LOG, and sh.

Referenced by GNUNET_SERVICE_run_(), and launch_registered_services().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ get_pid_file_name()

static char * get_pid_file_name ( struct GNUNET_SERVICE_Handle sh)
static

Get the name of the file where we will write the PID of the service.

Parameters
shservice context
Returns
name of the file for the process ID

Definition at line 1747 of file service.c.

1748{
1749 char *pif;
1750
1751 if (GNUNET_OK !=
1753 sh->service_name,
1754 "PIDFILE",
1755 &pif))
1756 return NULL;
1757 return pif;
1758}

References GNUNET_IDENTITY_Handle::cfg, GNUNET_CONFIGURATION_get_value_filename(), GNUNET_OK, and sh.

Referenced by pid_file_delete().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ pid_file_delete()

static void pid_file_delete ( struct GNUNET_SERVICE_Handle sh)
static

Delete the PID file that was created by our parent.

Parameters
shservice context

Definition at line 1767 of file service.c.

1768{
1769 char *pif = get_pid_file_name (sh);
1770
1771 if (NULL == pif)
1772 return; /* no PID file */
1773 if (0 != unlink (pif))
1775 "unlink",
1776 pif);
1777 GNUNET_free (pif);
1778}

References get_pid_file_name(), GNUNET_ERROR_TYPE_WARNING, GNUNET_free, LOG_STRERROR_FILE, and sh.

Referenced by GNUNET_SERVICE_run_().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ detach_terminal()

static enum GNUNET_GenericReturnValue detach_terminal ( struct GNUNET_SERVICE_Handle sh)
static

Detach from terminal.

Parameters
shservice context
Returns
GNUNET_OK on success, GNUNET_SYSERR on error

Definition at line 1788 of file service.c.

1789{
1790 pid_t pid;
1791 int nullfd;
1792 int filedes[2];
1793
1794 if (0 != pipe (filedes))
1795 {
1797 "pipe");
1798 return GNUNET_SYSERR;
1799 }
1800 pid = fork ();
1801 if (pid < 0)
1802 {
1804 "fork");
1805 return GNUNET_SYSERR;
1806 }
1807 if (0 != pid)
1808 {
1809 /* Parent */
1810 char c;
1811
1812 GNUNET_break (0 == close (filedes[1]));
1813 c = 'X';
1814 if (1 != read (filedes[0], &c, sizeof(char)))
1816 "read");
1817 fflush (stdout);
1818 switch (c)
1819 {
1820 case '.':
1821 exit (0);
1822
1823 case 'I':
1825 _ ("Service process failed to initialize\n"));
1826 break;
1827
1828 case 'S':
1830 _ ("Service process could not initialize server function\n"));
1831 break;
1832
1833 case 'X':
1835 _ ("Service process failed to report status\n"));
1836 break;
1837 }
1838 exit (1); /* child reported error */
1839 }
1840 GNUNET_break (0 == close (0));
1841 GNUNET_break (0 == close (1));
1842 GNUNET_break (0 == close (filedes[0]));
1843 nullfd = open ("/dev/null", O_RDWR | O_APPEND);
1844 if (nullfd < 0)
1845 return GNUNET_SYSERR;
1846 /* set stdin/stdout to /dev/null */
1847 if ((dup2 (nullfd, 0) < 0) || (dup2 (nullfd, 1) < 0))
1848 {
1850 (void) close (nullfd);
1851 return GNUNET_SYSERR;
1852 }
1853 (void) close (nullfd);
1854 /* Detach from controlling terminal */
1855 pid = setsid ();
1856 if (-1 == pid)
1858 "setsid");
1859 sh->ready_confirm_fd = filedes[1];
1860
1861 return GNUNET_OK;
1862}

References _, GNUNET_break, GNUNET_ERROR_TYPE_ERROR, GNUNET_ERROR_TYPE_INFO, GNUNET_ERROR_TYPE_WARNING, GNUNET_OK, GNUNET_SYSERR, LOG, LOG_STRERROR, pid, and sh.

Referenced by GNUNET_SERVICE_run_().

Here is the caller graph for this function:

◆ teardown_service()

static void teardown_service ( struct GNUNET_SERVICE_Handle sh)
static

Tear down the service, closing the listen sockets and freeing the ACLs.

Parameters
shhandle to the service to tear down.

Definition at line 1872 of file service.c.

1873{
1874 struct ServiceListenContext *slc;
1875
1876 GNUNET_free (sh->v4_denied);
1877 GNUNET_free (sh->v6_denied);
1878 GNUNET_free (sh->v4_allowed);
1879 GNUNET_free (sh->v6_allowed);
1880 while (NULL != (slc = sh->slc_head))
1881 {
1883 sh->slc_tail,
1884 slc);
1885 if (NULL != slc->listen_task)
1889 GNUNET_free (slc);
1890 }
1891}

References GNUNET_break, GNUNET_CONTAINER_DLL_remove, GNUNET_free, GNUNET_NETWORK_socket_close(), GNUNET_OK, GNUNET_SCHEDULER_cancel(), ServiceListenContext::listen_socket, ServiceListenContext::listen_task, and sh.

Referenced by do_registered_services_shutdown(), GNUNET_SERVICE_run_(), and GNUNET_SERVICE_stop().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ return_agpl()

static void return_agpl ( void *  cls,
const struct GNUNET_MessageHeader msg 
)
static

Function to return link to AGPL source upon request.

Parameters
clsclosure with the identification of the client
msgAGPL request

Definition at line 1901 of file service.c.

1903{
1904 struct GNUNET_SERVICE_Client *client = cls;
1905 const struct GNUNET_OS_ProjectData *pd = client->sh->pd;
1906 struct GNUNET_MQ_Handle *mq;
1907 struct GNUNET_MQ_Envelope *env;
1908 struct GNUNET_MessageHeader *res;
1909 size_t slen;
1910
1911 (void) msg;
1912 slen = strlen (pd->agpl_url) + 1;
1915 slen);
1916 memcpy (&res[1],
1918 slen);
1921 env);
1923}

References GNUNET_OS_ProjectData::agpl_url, env, GNUNET_AGPL_URL, GNUNET_MESSAGE_TYPE_RESPONSE_AGPL, GNUNET_MQ_msg_extra, GNUNET_MQ_send(), GNUNET_SERVICE_client_continue(), GNUNET_SERVICE_client_get_mq(), mq, msg, GNUNET_SERVICE_Handle::pd, res, and GNUNET_SERVICE_Client::sh.

Referenced by GNUNET_SERVICE_register_(), GNUNET_SERVICE_run_(), and GNUNET_SERVICE_start().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ finish_client_drop()

static void finish_client_drop ( void *  cls)
static

Asynchronously finish dropping the client.

Parameters
clsthe struct GNUNET_SERVICE_Client.

Definition at line 1967 of file service.c.

1968{
1969 struct GNUNET_SERVICE_Client *c = cls;
1970 struct GNUNET_SERVICE_Handle *sh = c->sh;
1971
1972 c->drop_task = NULL;
1973 GNUNET_CONTAINER_DLL_remove (sh->clients_head,
1974 sh->clients_tail,
1975 c);
1976 GNUNET_assert (NULL == c->send_task);
1977 GNUNET_assert (NULL == c->recv_task);
1978 GNUNET_assert (NULL == c->warn_task);
1980 GNUNET_MQ_destroy (c->mq);
1981 if (! c->persist)
1982 {
1985 if ((0 != (SUSPEND_STATE_EMFILE & sh->suspend_state)) &&
1986 (0 == (SUSPEND_STATE_SHUTDOWN & sh->suspend_state)))
1987 do_resume (sh,
1989 }
1990 else
1991 {
1993 }
1994 GNUNET_free (c);
1995 if ((0 != (SUSPEND_STATE_SHUTDOWN & sh->suspend_state)) &&
1998}

References do_resume(), GNUNET_SERVICE_Client::drop_task, GNUNET_assert, GNUNET_break, GNUNET_CONTAINER_DLL_remove, GNUNET_free, GNUNET_MQ_destroy(), GNUNET_MST_destroy(), GNUNET_NETWORK_socket_close(), GNUNET_NETWORK_socket_free_memory_only_(), GNUNET_OK, GNUNET_SERVICE_shutdown(), have_non_monitor_clients(), GNUNET_SERVICE_Client::mq, GNUNET_SERVICE_Client::mst, GNUNET_SERVICE_Client::persist, GNUNET_SERVICE_Client::recv_task, GNUNET_SERVICE_Client::send_task, sh, GNUNET_SERVICE_Client::sh, GNUNET_SERVICE_Client::sock, SUSPEND_STATE_EMFILE, SUSPEND_STATE_SHUTDOWN, and GNUNET_SERVICE_Client::warn_task.

Referenced by GNUNET_SERVICE_client_drop(), and GNUNET_SERVICE_stop().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ do_registered_services_shutdown()

static void do_registered_services_shutdown ( void *  cls)
static

Definition at line 2286 of file service.c.

2287{
2288 while (NULL != hll_head)
2289 {
2290 struct ServiceHandleList *shl = hll_head;
2291 struct GNUNET_SERVICE_Handle *sh = shl->sh;
2292
2294 hll_tail,
2295 shl);
2296 GNUNET_free (shl);
2297 if (-1 != sh->ready_confirm_fd)
2298 {
2299 if (1 != write (sh->ready_confirm_fd, "S", 1))
2301 "write");
2302 GNUNET_break (0 ==
2303 close (sh->ready_confirm_fd));
2304 }
2306 GNUNET_free (sh->handlers);
2307 GNUNET_free (sh);
2308 }
2309}

References GNUNET_break, GNUNET_CONTAINER_DLL_remove, GNUNET_ERROR_TYPE_WARNING, GNUNET_free, hll_head, hll_tail, LOG_STRERROR, sh, ServiceHandleList::sh, and teardown_service().

Referenced by launch_registered_services().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ launch_registered_services()

static void launch_registered_services ( void *  cls)
static

Definition at line 2320 of file service.c.

2321{
2322 struct LaunchContext *lc = cls;
2323 struct GNUNET_CONFIGURATION_Handle *cfg = lc->cfg;
2324 const struct GNUNET_OS_ProjectData *pd = lc->pd;
2325
2326 for (struct ServiceHandleList *shl = hll_head;
2327 NULL != shl;
2328 shl = shl->next)
2329 {
2330 shl->sh->cfg = cfg;
2331 if (GNUNET_OK !=
2332 setup_service (pd,
2333 shl->sh))
2334 continue;
2335 if (GNUNET_OK !=
2336 set_user_id (shl->sh))
2337 continue;
2339 shl->sh);
2340 }
2342 NULL);
2343}

References cfg, LaunchContext::cfg, do_registered_services_shutdown(), GNUNET_OK, GNUNET_SCHEDULER_add_now(), GNUNET_SCHEDULER_add_shutdown(), hll_head, ServiceHandleList::next, LaunchContext::pd, service_main(), set_user_id(), and setup_service().

Referenced by GNUNET_SERVICE_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ resume_client_receive()

static void resume_client_receive ( void *  cls)
static

Task run to resume receiving data from the client after the client called GNUNET_SERVICE_client_continue().

Parameters
clsour struct GNUNET_SERVICE_Client

Definition at line 2402 of file service.c.

2403{
2404 struct GNUNET_SERVICE_Client *c = cls;
2405 int ret;
2406
2407 c->recv_task = NULL;
2408 /* first, check if there is still something in the buffer */
2409 ret = GNUNET_MST_next (c->mst,
2410 GNUNET_YES);
2411 if (GNUNET_SYSERR == ret)
2412 {
2413 if (NULL == c->drop_task)
2415 return;
2416 }
2417 if (GNUNET_NO == ret)
2418 return; /* done processing, wait for more later */
2420 if (c->needs_continue)
2421 return; /* #GNUNET_MST_next() did give a message to the client */
2422 /* need to receive more data from the network first */
2423 if (NULL != c->recv_task)
2424 return;
2426 c->sock,
2428 c);
2429}

References GNUNET_SERVICE_Client::drop_task, GNUNET_assert, GNUNET_MST_next(), GNUNET_NO, GNUNET_OK, GNUNET_SCHEDULER_add_read_net(), GNUNET_SERVICE_client_drop(), GNUNET_SYSERR, GNUNET_TIME_UNIT_FOREVER_REL, GNUNET_YES, GNUNET_SERVICE_Client::mst, GNUNET_SERVICE_Client::needs_continue, GNUNET_SERVICE_Client::recv_task, ret, service_client_recv(), and GNUNET_SERVICE_Client::sock.

Referenced by GNUNET_SERVICE_client_continue().

Here is the call graph for this function:
Here is the caller graph for this function:

Variable Documentation

◆ hll_head

struct ServiceHandleList* hll_head
static

◆ hll_tail

struct ServiceHandleList* hll_tail
static

Definition at line 2249 of file service.c.

Referenced by do_registered_services_shutdown(), and GNUNET_SERVICE_register_().