static gboolean systemd_syslog_sd_acquire_socket(AFSocketSourceDriver *s, gint *acquired_fd) { gint fd, number_of_fds; *acquired_fd = -1; fd = -1; number_of_fds = sd_listen_fds(0); if (number_of_fds > 1) { msg_error("Systemd socket activation failed: got more than one fd", evt_tag_int("number", number_of_fds), NULL); return TRUE; } else if (number_of_fds < 1) { msg_error("Failed to acquire /run/systemd/journal/syslog socket, disabling systemd-syslog source", NULL); return TRUE; } else { fd = SD_LISTEN_FDS_START; msg_debug("Systemd socket activation", evt_tag_int("file-descriptor", fd), NULL); if (sd_is_socket_unix(fd, SOCK_DGRAM, -1, NULL, 0)) { *acquired_fd = fd; } else { msg_error("The systemd supplied UNIX domain socket is of a" " different type, check the configured driver and" " the matching systemd unit file", evt_tag_int("systemd-sock-fd", fd), evt_tag_str("expecting", "unix-dgram()"), NULL); *acquired_fd = -1; return TRUE; } } if (*acquired_fd != -1) { g_fd_set_nonblock(*acquired_fd, TRUE); msg_verbose("Acquired systemd syslog socket", evt_tag_int("systemd-syslog-sock-fd", *acquired_fd), NULL); return TRUE; } return TRUE; }
int main(int argc, char *argv[]) { Context context = {}; int r, n, fd; log_parse_environment(); log_open(); r = parse_argv(argc, argv); if (r <= 0) goto finish; r = sd_event_default(&context.event); if (r < 0) { log_error_errno(r, "Failed to allocate event loop: %m"); goto finish; } r = sd_resolve_default(&context.resolve); if (r < 0) { log_error_errno(r, "Failed to allocate resolver: %m"); goto finish; } r = sd_resolve_attach_event(context.resolve, context.event, 0); if (r < 0) { log_error_errno(r, "Failed to attach resolver: %m"); goto finish; } sd_event_set_watchdog(context.event, true); n = sd_listen_fds(1); if (n < 0) { log_error("Failed to receive sockets from parent."); r = n; goto finish; } else if (n == 0) { log_error("Didn't get any sockets passed in."); r = -EINVAL; goto finish; } for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) { r = add_listen_socket(&context, fd); if (r < 0) goto finish; } r = sd_event_loop(context.event); if (r < 0) { log_error_errno(r, "Failed to run event loop: %m"); goto finish; } finish: context_free(&context); return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; }
static void _j4status_io_add_systemd(J4statusIOContext *self) { #ifdef ENABLE_SYSTEMD gint fds = sd_listen_fds(TRUE); if ( fds < 0 ) { g_warning("Failed to acquire systemd sockets: %s", g_strerror(-fds)); return; } if ( fds == 0 ) return; gboolean socket_added = FALSE; _j4status_io_add_server(self); GError *error = NULL; gint fd; for ( fd = SD_LISTEN_FDS_START ; fd < SD_LISTEN_FDS_START + fds ; ++fd ) { gint r; r = sd_is_socket(fd, AF_UNSPEC, SOCK_STREAM, 1); if ( r < 0 ) { g_warning("Failed to verify systemd socket type: %s", g_strerror(-r)); continue; } if ( r == 0 ) continue; GSocket *socket; socket = g_socket_new_from_fd(fd, &error); if ( socket == NULL ) { g_warning("Failed to take a socket from systemd: %s", error->message); g_clear_error(&error); continue; } if ( ! g_socket_listener_add_socket(G_SOCKET_LISTENER(self->server), socket, NULL, &error) ) { g_warning("Failed to add systemd socket to server: %s", error->message); g_clear_error(&error); continue; } socket_added = TRUE; } if ( ! socket_added ) { g_object_unref(self->server); self->server = NULL; } #endif /* ENABLE_SYSTEMD */ }
int main(int argc, char *argv[]) { int r, accept_fd; uid_t uid, bus_uid; gid_t gid; log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); log_parse_environment(); log_open(); bus_uid = getuid(); if (geteuid() == 0) { const char *user = "******"; r = get_user_creds(&user, &uid, &gid, NULL, NULL); if (r < 0) { log_error_errno(r, "Cannot resolve user name %s: %m", user); goto finish; } r = drop_privileges(uid, gid, 1ULL << CAP_IPC_OWNER); if (r < 0) { log_error_errno(r, "Cannot drop privileges: %m"); goto finish; } } r = parse_argv(argc, argv); if (r <= 0) goto finish; r = sd_listen_fds(0); if (r != 1) { log_error("Illegal number of file descriptors passed"); goto finish; } accept_fd = SD_LISTEN_FDS_START; r = fd_nonblock(accept_fd, false); if (r < 0) { log_error_errno(r, "Cannot mark accept-fd non-blocking: %m"); goto finish; } r = loop_clients(accept_fd, bus_uid); finish: sd_notify(false, "STOPPING=1\n" "STATUS=Shutting down."); strv_free(arg_configuration); free(arg_address); return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; }
int get_socket() { int fd, n; size_t name_length; socklen_t new_length; name_length = strlen(ABSTRACT_SOCKET_NAME) + 1; if (HAVE_LIBSYSTEMD == 1) { /* Check for file descriptors passed by the system manager */ n = sd_listen_fds(0); } else { n = 0; } if (n < 0) { /* Below 0 is an error code */ fprintf(stderr, "sd_listen_fds(): %s\n", strerror(-n)); exit(EXIT_FAILURE); } else if (n > 1) { /* Only need one socket */ fprintf(stderr, "Too many file descriptors received.\n"); exit(EXIT_FAILURE); } else if (n == 1) { /* Got one socket */ fd = SD_LISTEN_FDS_START + 0; /* Check it is correct type */ if (sd_is_socket_unix(fd, SOCK_STREAM, -1, "\0", name_length) <= 0) { fprintf(stderr, "Invalid socket passed.\n"); exit(EXIT_FAILURE); } } else { /* No socket from system manager. Lets make our own then */ struct sockaddr_un addr; memset(&addr, 0, sizeof(struct sockaddr_un)); /* Clear address structure */ addr.sun_family = AF_UNIX; /* UNIX domain address */ /* addr.sun_path[0] has already been set to 0 by memset() */ strncpy(&addr.sun_path[1], ABSTRACT_SOCKET_NAME, strlen(ABSTRACT_SOCKET_NAME)); fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0); if (fd == -1) { printf("socket error"); exit(EXIT_FAILURE); } new_length = (socklen_t) sizeof(sa_family_t) + (socklen_t) name_length; if (bind(fd, (struct sockaddr *) &addr, new_length) == -1) { printf("socket binding error"); exit(EXIT_FAILURE); } } return fd; }
CAMLprim value ocaml_launched_by_systemd(value ignore) { CAMLparam1(ignore); CAMLlocal1(ret); ret = Val_false; if (sd_listen_fds(0) > 0) ret = Val_true; CAMLreturn(ret); }
static int open_sockets(int *epoll_fd, bool accept) { char **address; int n, fd, r; int count = 0; n = sd_listen_fds(true); if (n < 0) { log_error("Failed to read listening file descriptors from environment: %s", strerror(-n)); return n; } if (n > 0) { log_info("Received %i descriptors via the environment.", n); for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) { r = fd_cloexec(fd, arg_accept); if (r < 0) return r; count ++; } } /* Close logging and all other descriptors */ if (arg_listen) { int except[3 + n]; for (fd = 0; fd < SD_LISTEN_FDS_START + n; fd++) except[fd] = fd; log_close(); close_all_fds(except, 3 + n); } /** Note: we leak some fd's on error here. I doesn't matter * much, since the program will exit immediately anyway, but * would be a pain to fix. */ STRV_FOREACH(address, arg_listen) { fd = make_socket_fd(*address, SOCK_STREAM | (arg_accept*SOCK_CLOEXEC)); if (fd < 0) { log_open(); log_error("Failed to open '%s': %s", *address, strerror(-fd)); return fd; } assert(fd == SD_LISTEN_FDS_START + count); count ++; }
QList<int> getListenFds() { QList<int> fds; int n = sd_listen_fds(0); for(int i=0;i<n;++i) { int fd = SD_LISTEN_FDS_START + i; if(sd_is_socket_inet(fd, AF_UNSPEC, SOCK_STREAM, 1, 0) < 0) { logger::error() << "Socket" << i << " is not listening inet socket!"; } else { fds.append(fd); } } return fds; }
static int controlfd_init_systemd(void) { #ifdef HAVE_SYSTEMD_DAEMON int nfd, controlfd; nfd = sd_listen_fds(0); if (nfd > 1) { errx(1, "Too many file descriptors received."); } if (nfd == 1) { return (SD_LISTEN_FDS_START + 0); } #else errx(1, "systemd is not supported or not detected on your system, " "please consider filing report or submitting a patch"); #endif return (-1); }
void Setup_Systemd( void ) { int fds = sd_listen_fds(0) ; int fd_count = 0 ; int i ; for ( i = 0 ; i < fds ; ++i ) { struct connection_out *out = NewOut(); if (out == NULL) { break ; } out->file_descriptor = i + SD_LISTEN_FDS_START ; ++ fd_count ; out->name = owstrdup("systemd"); out->inet_type = inet_systemd ; } if ( fd_count > 0 ) { Globals.daemon_status = e_daemon_sd ; Globals.inet_type = inet_systemd ; } }
static int add_systemd_sockets(struct weston_compositor *compositor) { int fd; int cnt_systemd_sockets; int current_fd = 0; cnt_systemd_sockets = sd_listen_fds(1); if (cnt_systemd_sockets < 0) { weston_log("sd_listen_fds failed with: %d\n", cnt_systemd_sockets); return -1; } /* socket-based activation not used, return silently */ if (cnt_systemd_sockets == 0) return 0; while (current_fd < cnt_systemd_sockets) { fd = SD_LISTEN_FDS_START + current_fd; if (sd_is_socket(fd, AF_UNIX, SOCK_STREAM,1) <= 0) { weston_log("invalid socket provided from systemd\n"); return -1; } if (wl_display_add_socket_fd(compositor->wl_display, fd)) { weston_log("wl_display_add_socket_fd failed" "for systemd provided socket\n"); return -1; } current_fd++; } weston_log("info: add %d socket(s) provided by systemd\n", current_fd); return current_fd; }
int main(int argc, char **argv) { base = event_base_new(); struct evconnlistener *listener = NULL; if (sd_listen_fds(0) == 1) { listener = init_socket_activated(); } else if (argc == 2) { int port = atoi(argv[1]); listener = init_socket_standalone(port); } else { exit(EXIT_FAILURE); } event_base_dispatch(base); evconnlistener_free(listener); event_base_free(base); printf("DONE\n"); return 0; }
static char * system_linux_find_dev_log(void) { int r, fd; r = sd_listen_fds(0); if (r == 0) return "/dev/log"; if (r < 0) { msg_error ("system(): sd_listen_fds() failed", evt_tag_int("errno", r), NULL); return NULL; } /* We only support socket activation for /dev/log, meaning * one socket only. Bail out if we get more. */ if (r != 1) { msg_error("system(): Too many sockets passed in for socket activation, syslog-ng only supports one.", NULL); return NULL; } fd = SD_LISTEN_FDS_START; if (sd_is_socket_unix(fd, SOCK_DGRAM, -1, "/run/systemd/journal/syslog", 0) != 1) { msg_error("system(): Socket activation is only supported on /run/systemd/journal/syslog", NULL); return NULL; } return "/run/systemd/journal/syslog"; }
void main_init() { /* one-time initialization */ #ifdef USE_SYSTEMD int i; systemd_fds=sd_listen_fds(1); if(systemd_fds<0) fatal("systemd initialization failed"); listen_fds_start=SD_LISTEN_FDS_START; /* set non-blocking mode on systemd file descriptors */ for(i=0; i<systemd_fds; ++i) set_nonblock(listen_fds_start+i, 1); #else systemd_fds=0; /* no descriptors received */ listen_fds_start=3; /* the value is not really important */ #endif /* basic initialization contains essential functions required for logging * subsystem to function properly, thus all errors here are fatal */ if(ssl_init()) /* initialize TLS library */ fatal("TLS initialization failed"); if(sthreads_init()) /* initialize critical sections & TLS callbacks */ fatal("Threads initialization failed"); if(cron_init()) /* initialize periodic events */ fatal("Cron initialization failed"); options_defaults(); options_apply(); #ifndef USE_FORK get_limits(); /* required by setup_fd() */ #endif fds=s_poll_alloc(); if(signal_pipe_init()) fatal("Signal pipe initialization failed: " "check your personal firewall"); stunnel_info(LOG_NOTICE); if(systemd_fds>0) s_log(LOG_INFO, "Systemd socket activation: %d descriptors received", systemd_fds); }
int bind_cmdsocket( char *name ) { int cmd_fd; #ifdef HAVE_SYSTEMD if (sd_listen_fds(0) == 1) { fprintf(stderr, SD_DEBUG "Found socket passed from systemd\n"); return SD_LISTEN_FDS_START + 0; } #endif struct sockaddr_un addr; /* remove any stale files */ struct stat sb; int serr = stat(name, &sb); if ( !serr && S_ISSOCK(sb.st_mode)) { unlink(name); } cmd_fd = socket(AF_UNIX, SOCK_DGRAM, 0); strcpy(addr.sun_path, name); addr.sun_family = AF_UNIX; bind (cmd_fd, (struct sockaddr *) &addr, strlen(addr.sun_path) + sizeof (addr.sun_family)); return cmd_fd; }
/* Functions called directly from spop */ void interface_init() { /* Try to use systemd socket activation */ int n, sock; n = sd_listen_fds(1); if (n < 0) g_error("Can't check file descriptors passed by the system manager: %s", g_strerror(errno)); else if (n > 0) { /* Use these sockets */ for (sock = SD_LISTEN_FDS_START; sock < SD_LISTEN_FDS_START + n; sock++) { interface_init_chan(sock); } g_info("Listening to %d systemd sockets", n); } else { /* Traditional socket creation... */ const char* ip_addr; const char* port; struct addrinfo hints; struct addrinfo* res; struct addrinfo* rp; int _true = 1; int ret; /* Get what we need from the config */ ip_addr = config_get_string_opt("listen_address", NULL); port = config_get_string_opt("listen_port", "6602"); /* Get corresponding addrinfo's */ bzero(&hints, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG | AI_NUMERICHOST | AI_NUMERICSERV; ret = getaddrinfo(ip_addr, port, &hints, &res); if (ret != 0) g_error("Can't get address info: %s", gai_strerror(ret)); /* Handle each address */ for (rp = res; rp != NULL; rp = rp->ai_next) { char hostname[NI_MAXHOST]; ret = getnameinfo(rp->ai_addr, rp->ai_addrlen, hostname, NI_MAXHOST, NULL, 0, NI_NUMERICHOST); if (ret != 0) g_error("Can't convert address to text: %s", gai_strerror(ret)); g_debug("Will listen on %s:%s...", hostname, port); /* Create the socket */ sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (sock < 0) g_error("Can't create socket: %s", g_strerror(errno)); if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &_true, sizeof(int)) == -1) g_error("Can't set socket options: %s", g_strerror(errno)); /* Bind the socket */ if (bind(sock, rp->ai_addr, rp->ai_addrlen) != 0) g_error("Can't bind socket: %s", g_strerror(errno)); /* Start listening */ if (listen(sock, SOMAXCONN) != 0) g_error("Can't listen on socket: %s", g_strerror(errno)); interface_init_chan(sock); g_info("Listening on %s: %s", hostname, port); } freeaddrinfo(res); } }
int cr_service(bool daemon_mode) { int server_fd = -1, n; int child_pid; struct sockaddr_un client_addr; socklen_t client_addr_len; n = sd_listen_fds(0); if (n > 1) { pr_err("Too many file descriptors (%d) recieved", n); goto err; } else if (n == 1) server_fd = SD_LISTEN_FDS_START + 0; else { struct sockaddr_un server_addr; socklen_t server_addr_len; server_fd = socket(AF_LOCAL, SOCK_SEQPACKET, 0); if (server_fd == -1) { pr_perror("Can't initialize service socket"); goto err; } memset(&server_addr, 0, sizeof(server_addr)); memset(&client_addr, 0, sizeof(client_addr)); server_addr.sun_family = AF_LOCAL; if (opts.addr == NULL) opts.addr = CR_DEFAULT_SERVICE_ADDRESS; strcpy(server_addr.sun_path, opts.addr); server_addr_len = strlen(server_addr.sun_path) + sizeof(server_addr.sun_family); client_addr_len = sizeof(client_addr); unlink(server_addr.sun_path); if (bind(server_fd, (struct sockaddr *) &server_addr, server_addr_len) == -1) { pr_perror("Can't bind"); goto err; } pr_info("The service socket is bound to %s\n", server_addr.sun_path); /* change service socket permissions, so anyone can connect to it */ if (chmod(server_addr.sun_path, 0666)) { pr_perror("Can't change permissions of the service socket"); goto err; } if (listen(server_fd, 16) == -1) { pr_perror("Can't listen for socket connections"); goto err; } } if (daemon_mode) { if (daemon(1, 0) == -1) { pr_perror("Can't run service server in the background"); goto err; } } if (opts.pidfile) { if (write_pidfile(getpid()) == -1) { pr_perror("Can't write pidfile"); goto err; } } if (setup_sigchld_handler()) goto err; while (1) { int sk; pr_info("Waiting for connection...\n"); sk = accept(server_fd, &client_addr, &client_addr_len); if (sk == -1) { pr_perror("Can't accept connection"); goto err; } pr_info("Connected.\n"); child_pid = fork(); if (child_pid == 0) { int ret; if (restore_sigchld_handler()) exit(1); close(server_fd); init_opts(); ret = cr_service_work(sk); close(sk); exit(ret != 0); } if (child_pid < 0) pr_perror("Can't fork a child"); close(sk); } err: close_safe(&server_fd); return 1; }
static gboolean cockpit_web_server_initable_init (GInitable *initable, GCancellable *cancellable, GError **error) { CockpitWebServer *server = COCKPIT_WEB_SERVER (initable); gboolean ret = FALSE; gboolean failed = FALSE; int n, fd; server->socket_service = g_socket_service_new (); n = sd_listen_fds (0); if (n > 0) { /* We got file descriptors passed in, use those. */ for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) { GSocket *s = NULL; gboolean b; int type; socklen_t l = sizeof (type); /* * HACK: Workaround g_error() happy code in GSocket * https://bugzilla.gnome.org/show_bug.cgi?id=746339 */ if (getsockopt (fd, SOL_SOCKET, SO_TYPE, &type, &l) < 0) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "invalid socket passed via systemd activation: %d: %s", fd, g_strerror (errno)); goto out; } s = g_socket_new_from_fd (fd, error); if (s == NULL) { g_prefix_error (error, "Failed to acquire passed socket %i: ", fd); goto out; } b = cockpit_web_server_add_socket (server, s, error); g_object_unref (s); if (!b) { g_prefix_error (error, "Failed to add listener for socket %i: ", fd); goto out; } } server->socket_activated = TRUE; } else { /* No fds passed in, let's listen on our own. */ if (server->port == 0) { server->port = g_socket_listener_add_any_inet_port (G_SOCKET_LISTENER (server->socket_service), NULL, error); failed = (server->port == 0); } else if (server->port > 0) { failed = !g_socket_listener_add_inet_port (G_SOCKET_LISTENER (server->socket_service), server->port, NULL, error); } if (failed) { g_prefix_error (error, "Failed to bind to port %d: ", server->port); goto out; } } g_signal_connect (server->socket_service, "incoming", G_CALLBACK (on_incoming), server); ret = TRUE; out: return ret; }
int main(int argc, char *argv[]) { int r = 255; int wrote_pid_file = 0; avahi_set_log_function(log_function); init_rand_seed(); avahi_server_config_init(&config.server_config); config.command = DAEMON_RUN; config.daemonize = 0; config.config_file = NULL; #ifdef HAVE_DBUS config.enable_dbus = 1; config.fail_on_missing_dbus = 1; config.n_clients_max = 0; config.n_objects_per_client_max = 0; config.n_entries_per_entry_group_max = 0; #endif config.drop_root = 1; config.set_rlimits = 1; #ifdef ENABLE_CHROOT config.use_chroot = 1; #endif config.modify_proc_title = 1; config.disable_user_service_publishing = 0; config.publish_dns_servers = NULL; config.publish_resolv_conf = 0; config.use_syslog = 0; config.debug = 0; config.rlimit_as_set = 0; config.rlimit_core_set = 0; config.rlimit_data_set = 0; config.rlimit_fsize_set = 0; config.rlimit_nofile_set = 0; config.rlimit_stack_set = 0; #ifdef RLIMIT_NPROC config.rlimit_nproc_set = 0; #endif if ((argv0 = strrchr(argv[0], '/'))) argv0 = avahi_strdup(argv0 + 1); else argv0 = avahi_strdup(argv[0]); daemon_pid_file_ident = (const char *) argv0; daemon_log_ident = (char*) argv0; daemon_pid_file_proc = pid_file_proc; if (parse_command_line(&config, argc, argv) < 0) goto finish; if (config.modify_proc_title) avahi_init_proc_title(argc, argv); #ifdef ENABLE_CHROOT config.use_chroot = config.use_chroot && config.drop_root; #endif if (config.command == DAEMON_HELP) { help(stdout); r = 0; } else if (config.command == DAEMON_VERSION) { printf("%s "PACKAGE_VERSION"\n", argv0); r = 0; } else if (config.command == DAEMON_KILL) { if (daemon_pid_file_kill_wait(SIGTERM, 5) < 0) { avahi_log_warn("Failed to kill daemon: %s", strerror(errno)); goto finish; } r = 0; } else if (config.command == DAEMON_RELOAD) { if (daemon_pid_file_kill(SIGHUP) < 0) { avahi_log_warn("Failed to kill daemon: %s", strerror(errno)); goto finish; } r = 0; } else if (config.command == DAEMON_CHECK) r = (daemon_pid_file_is_running() >= 0) ? 0 : 1; else if (config.command == DAEMON_RUN) { pid_t pid; if (getuid() != 0 && config.drop_root) { avahi_log_error("This program is intended to be run as root."); goto finish; } if ((pid = daemon_pid_file_is_running()) >= 0) { avahi_log_error("Daemon already running on PID %u", pid); goto finish; } if (load_config_file(&config) < 0) goto finish; if (config.daemonize) { daemon_retval_init(); if ((pid = daemon_fork()) < 0) goto finish; else if (pid != 0) { int ret; /** Parent **/ if ((ret = daemon_retval_wait(20)) < 0) { avahi_log_error("Could not receive return value from daemon process."); goto finish; } r = ret; goto finish; } /* Child */ } if (config.use_syslog || config.daemonize) daemon_log_use = DAEMON_LOG_SYSLOG; if (sd_listen_fds(0) <= 0) if (daemon_close_all(-1) < 0) avahi_log_warn("Failed to close all remaining file descriptors: %s", strerror(errno)); daemon_reset_sigs(-1); daemon_unblock_sigs(-1); if (make_runtime_dir() < 0) goto finish; if (config.drop_root) { #ifdef ENABLE_CHROOT if (config.use_chroot) if (avahi_caps_reduce() < 0) goto finish; #endif if (drop_root() < 0) goto finish; #ifdef ENABLE_CHROOT if (config.use_chroot) if (avahi_caps_reduce2() < 0) goto finish; #endif } if (daemon_pid_file_create() < 0) { avahi_log_error("Failed to create PID file: %s", strerror(errno)); if (config.daemonize) daemon_retval_send(1); goto finish; } else wrote_pid_file = 1; if (config.set_rlimits) enforce_rlimits(); chdir("/"); #ifdef ENABLE_CHROOT if (config.drop_root && config.use_chroot) if (avahi_chroot_helper_start(argv0) < 0) { avahi_log_error("failed to start chroot() helper daemon."); goto finish; } #endif avahi_log_info("%s "PACKAGE_VERSION" starting up.", argv0); sd_notifyf(0, "STATUS=%s "PACKAGE_VERSION" starting up.", argv0); avahi_set_proc_title(argv0, "%s: starting up", argv0); if (run_server(&config) == 0) r = 0; avahi_log_info("%s "PACKAGE_VERSION" exiting.", argv0); sd_notifyf(0, "STATUS=%s "PACKAGE_VERSION" exiting.", argv0); } finish: if (config.daemonize) daemon_retval_done(); avahi_server_config_free(&config.server_config); avahi_free(config.config_file); avahi_strfreev(config.publish_dns_servers); avahi_strfreev(resolv_conf_name_servers); avahi_strfreev(resolv_conf_search_domains); if (wrote_pid_file) { #ifdef ENABLE_CHROOT avahi_chroot_helper_unlink(pid_file_proc()); #else daemon_pid_file_remove(); #endif } #ifdef ENABLE_CHROOT avahi_chroot_helper_shutdown(); #endif avahi_free(argv0); return r; }
/** * @short Starts the listening phase for this listen point for sockets. * @memberof onion_listen_point_t * * Default listen implementation that listens on sockets. Opens sockets and setup everything properly. * * @param op The listen point * @returns 0 if ok, !=0 some error; it will be the errno value. */ int onion_listen_point_listen(onion_listen_point *op){ if (op->listen){ op->listen(op); return 0; } #ifdef HAVE_SYSTEMD if (op->server->flags&O_SYSTEMD){ int n=sd_listen_fds(0); ONION_DEBUG("Checking if have systemd sockets: %d",n); if (n>0){ // If 0, normal startup. Else use the first LISTEN_FDS. ONION_DEBUG("Using systemd sockets"); if (n>1){ ONION_WARNING("Get more than one systemd socket descriptor. Using only the first."); } op->listenfd=SD_LISTEN_FDS_START+0; return 0; } } #endif struct addrinfo hints; struct addrinfo *result, *rp; int sockfd; memset(&hints,0, sizeof(struct addrinfo)); hints.ai_canonname=NULL; hints.ai_addr=NULL; hints.ai_next=NULL; hints.ai_socktype=SOCK_STREAM; hints.ai_family=AF_UNSPEC; hints.ai_flags=AI_PASSIVE|AI_NUMERICSERV; ONION_DEBUG("Trying to listen at %s:%s", op->hostname, op->port ? op->port : "8080"); if (getaddrinfo(op->hostname, op->port ? op->port : "8080", &hints, &result) !=0 ){ ONION_ERROR("Error getting local address and port: %s", strerror(errno)); return errno; } int optval=1; for(rp=result;rp!=NULL;rp=rp->ai_next){ sockfd=socket(rp->ai_family, rp->ai_socktype | SOCK_CLOEXEC, rp->ai_protocol); if (sockfd<0) // not valid continue; if(SOCK_CLOEXEC == 0) { // Good compiler know how to cut this out int flags=fcntl(sockfd, F_GETFD); if (flags==-1){ ONION_ERROR("Retrieving flags from listen socket"); } flags|=FD_CLOEXEC; if (fcntl(sockfd, F_SETFD, flags)==-1){ ONION_ERROR("Setting O_CLOEXEC to listen socket"); } } if (setsockopt(sockfd,SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval) ) < 0){ ONION_ERROR("Could not set socket options: %s",strerror(errno)); } if (bind(sockfd, rp->ai_addr, rp->ai_addrlen) == 0) break; // Success else { ONION_ERROR("Could not bind to socket: %s",strerror(errno)); } close(sockfd); } if (rp==NULL){ ONION_ERROR("Could not find any suitable address to bind to."); return errno; } #ifdef __DEBUG__ char address[64]; getnameinfo(rp->ai_addr, rp->ai_addrlen, address, 32, &address[32], 32, NI_NUMERICHOST | NI_NUMERICSERV); ONION_DEBUG("Listening to %s:%s, fd %d",address,&address[32],sockfd); #endif freeaddrinfo(result); listen(sockfd,5); // queue of only 5. op->listenfd=sockfd; return 0; }
int main(int argc, char **argv) { int rv; char setToForeground; char HotPlug; char *newReaderConfig; struct stat fStatBuf; int customMaxThreadCounter = 0; int customMaxReaderHandles = 0; int customMaxThreadCardHandles = 0; int opt; int limited_rights = FALSE; int r; #ifdef HAVE_GETOPT_LONG int option_index = 0; static struct option long_options[] = { {"config", 1, NULL, 'c'}, {"foreground", 0, NULL, 'f'}, {"color", 0, NULL, 'T'}, {"help", 0, NULL, 'h'}, {"version", 0, NULL, 'v'}, {"apdu", 0, NULL, 'a'}, {"debug", 0, NULL, 'd'}, {"info", 0, NULL, 0}, {"error", 0, NULL, 'e'}, {"critical", 0, NULL, 'C'}, {"hotplug", 0, NULL, 'H'}, {"force-reader-polling", optional_argument, NULL, 0}, {"max-thread", 1, NULL, 't'}, {"max-card-handle-per-thread", 1, NULL, 's'}, {"max-card-handle-per-reader", 1, NULL, 'r'}, {"auto-exit", 0, NULL, 'x'}, {"reader-name-no-serial", 0, NULL, 'S'}, {"reader-name-no-interface", 0, NULL, 'I'}, {NULL, 0, NULL, 0} }; #endif #define OPT_STRING "c:fTdhvaeCHt:r:s:xSI" newReaderConfig = NULL; setToForeground = FALSE; HotPlug = FALSE; /* * test the version */ if (strcmp(PCSCLITE_VERSION_NUMBER, VERSION) != 0) { printf("BUILD ERROR: The release version number PCSCLITE_VERSION_NUMBER\n"); printf(" in pcsclite.h (%s) does not match the release version number\n", PCSCLITE_VERSION_NUMBER); printf(" generated in config.h (%s) (see configure.in).\n", VERSION); return EXIT_FAILURE; } /* * By default we create a daemon (not connected to any output) * so log to syslog to have error messages. */ DebugLogSetLogType(DEBUGLOG_SYSLOG_DEBUG); /* if the process is setuid or setgid it may have some restrictions */ limited_rights = (getgid() != getegid()) && (getuid() != 0); /* * Handle any command line arguments */ #ifdef HAVE_GETOPT_LONG while ((opt = getopt_long (argc, argv, OPT_STRING, long_options, &option_index)) != -1) { #else while ((opt = getopt (argc, argv, OPT_STRING)) != -1) { #endif switch (opt) { #ifdef HAVE_GETOPT_LONG case 0: if (strcmp(long_options[option_index].name, "force-reader-polling") == 0) HPForceReaderPolling = optarg ? abs(atoi(optarg)) : 1; break; #endif case 'c': if (limited_rights) { Log1(PCSC_LOG_CRITICAL, "Can't use a user specified config file"); return EXIT_FAILURE; } Log2(PCSC_LOG_INFO, "using new config file: %s", optarg); newReaderConfig = optarg; break; case 'f': setToForeground = TRUE; /* debug to stdout instead of default syslog */ DebugLogSetLogType(DEBUGLOG_STDOUT_DEBUG); Log1(PCSC_LOG_INFO, "pcscd set to foreground with debug send to stdout"); break; case 'T': DebugLogSetLogType(DEBUGLOG_STDOUT_COLOR_DEBUG); Log1(PCSC_LOG_INFO, "Force colored logs"); break; case 'd': DebugLogSetLevel(PCSC_LOG_DEBUG); break; case 'e': DebugLogSetLevel(PCSC_LOG_ERROR); break; case 'C': DebugLogSetLevel(PCSC_LOG_CRITICAL); break; case 'h': print_usage (argv[0]); return EXIT_SUCCESS; case 'v': print_version (); return EXIT_SUCCESS; case 'a': if (limited_rights) { Log1(PCSC_LOG_CRITICAL, "Can't log APDU (restricted)"); return EXIT_FAILURE; } (void)DebugLogSetCategory(DEBUG_CATEGORY_APDU); break; case 'H': /* debug to stdout instead of default syslog */ DebugLogSetLogType(DEBUGLOG_STDOUT_DEBUG); HotPlug = TRUE; break; case 't': customMaxThreadCounter = optarg ? atoi(optarg) : 0; if (limited_rights && (customMaxThreadCounter < PCSC_MAX_CONTEXT_THREADS)) customMaxThreadCounter = PCSC_MAX_CONTEXT_THREADS; Log2(PCSC_LOG_INFO, "setting customMaxThreadCounter to: %d", customMaxThreadCounter); break; case 'r': customMaxReaderHandles = optarg ? atoi(optarg) : 0; if (limited_rights && (customMaxReaderHandles < PCSC_MAX_READER_HANDLES)) customMaxReaderHandles = PCSC_MAX_READER_HANDLES; Log2(PCSC_LOG_INFO, "setting customMaxReaderHandles to: %d", customMaxReaderHandles); break; case 's': customMaxThreadCardHandles = optarg ? atoi(optarg) : 0; if (limited_rights && (customMaxThreadCardHandles < PCSC_MAX_CONTEXT_CARD_HANDLES)) customMaxThreadCardHandles = PCSC_MAX_CONTEXT_CARD_HANDLES; Log2(PCSC_LOG_INFO, "setting customMaxThreadCardHandles to: %d", customMaxThreadCardHandles); break; case 'x': AutoExit = TRUE; Log2(PCSC_LOG_INFO, "Auto exit after %d seconds of inactivity", TIME_BEFORE_SUICIDE); break; case 'S': Add_Serial_In_Name = FALSE; break; case 'I': Add_Interface_In_Name = FALSE; break; default: print_usage (argv[0]); return EXIT_FAILURE; } } if (argv[optind]) { printf("Unknown option: %s\n", argv[optind]); print_usage(argv[0]); return EXIT_FAILURE; } /* * Check if systemd passed us any file descriptors */ rv = sd_listen_fds(0); if (rv > 1) { Log1(PCSC_LOG_CRITICAL, "Too many file descriptors received"); return EXIT_FAILURE; } else { if (rv == 1) { SocketActivated = TRUE; Log1(PCSC_LOG_INFO, "Started by systemd"); } else SocketActivated = FALSE; } /* * test the presence of /var/run/pcscd/pcscd.comm */ rv = stat(PCSCLITE_CSOCK_NAME, &fStatBuf); if (rv == 0) { pid_t pid; /* read the pid file to get the old pid and test if the old pcscd is * still running */ pid = GetDaemonPid(); if (pid != -1) { if (HotPlug) return SendHotplugSignal(); rv = kill(pid, 0); if (0 == rv) { Log1(PCSC_LOG_CRITICAL, "file " PCSCLITE_CSOCK_NAME " already exists."); Log2(PCSC_LOG_CRITICAL, "Another pcscd (pid: %d) seems to be running.", pid); return EXIT_FAILURE; } else if (ESRCH == errno) { /* the old pcscd is dead. make some cleanup */ clean_temp_files(); } else { /* permission denied or other error */ Log2(PCSC_LOG_CRITICAL, "kill failed: %s", strerror(errno)); return EXIT_FAILURE; } } else { if (HotPlug) { Log1(PCSC_LOG_CRITICAL, "file " PCSCLITE_RUN_PID " do not exist"); Log1(PCSC_LOG_CRITICAL, "Hotplug failed"); return EXIT_FAILURE; } } } else if (HotPlug) { Log1(PCSC_LOG_CRITICAL, "Hotplug failed: pcscd is not running"); return EXIT_FAILURE; } /* like in daemon(3): changes the current working directory to the * root ("/") */ r = chdir("/"); if (r < 0) { Log2(PCSC_LOG_CRITICAL, "chdir() failed: %s", strerror(errno)); return EXIT_FAILURE; } /* * If this is set to one the user has asked it not to fork */ if (!setToForeground) { int pid; int fd; if (pipe(pipefd) == -1) { Log2(PCSC_LOG_CRITICAL, "pipe() failed: %s", strerror(errno)); return EXIT_FAILURE; } pid = fork(); if (-1 == pid) { Log2(PCSC_LOG_CRITICAL, "fork() failed: %s", strerror(errno)); return EXIT_FAILURE; } /* like in daemon(3): redirect standard input, standard output * and standard error to /dev/null */ fd = open("/dev/null", O_RDWR); if (fd != -1) { dup2(fd, STDIN_FILENO); dup2(fd, STDOUT_FILENO); dup2(fd, STDERR_FILENO); /* do not close stdin, stdout or stderr */ if (fd > 2) close(fd); } if (pid) /* in the father */ { char buf; int ret; /* close write side */ close(pipefd[1]); /* wait for the son to write the return code */ ret = read(pipefd[0], &buf, 1); if (ret <= 0) return 2; close(pipefd[0]); /* exit code */ return buf; } else /* in the son */ { /* close read side */ close(pipefd[0]); } } /* * cleanly remove /var/run/pcscd/files when exiting * signal_trap() does just set a global variable used by the main loop */ (void)signal(SIGQUIT, signal_trap); (void)signal(SIGTERM, signal_trap); /* default kill signal & init round 1 */ (void)signal(SIGINT, signal_trap); /* sent by Ctrl-C */ /* exits on SIGALARM to allow pcscd to suicide if not used */ (void)signal(SIGALRM, signal_trap); /* * If PCSCLITE_IPC_DIR does not exist then create it */ { int mode = S_IROTH | S_IXOTH | S_IRGRP | S_IXGRP | S_IRWXU; rv = mkdir(PCSCLITE_IPC_DIR, mode); if ((rv != 0) && (errno != EEXIST)) { Log2(PCSC_LOG_CRITICAL, "cannot create " PCSCLITE_IPC_DIR ": %s", strerror(errno)); return EXIT_FAILURE; } /* set mode so that the directory is world readable and * executable even is umask is restrictive * The directory containes files used by libpcsclite */ (void)chmod(PCSCLITE_IPC_DIR, mode); } /* * Allocate memory for reader structures */ rv = RFAllocateReaderSpace(customMaxReaderHandles); if (SCARD_S_SUCCESS != rv) at_exit(); #ifdef USE_SERIAL /* * Grab the information from the reader.conf */ if (newReaderConfig) { rv = RFStartSerialReaders(newReaderConfig); if (rv != 0) { Log3(PCSC_LOG_CRITICAL, "invalid file %s: %s", newReaderConfig, strerror(errno)); at_exit(); } } else { rv = RFStartSerialReaders(PCSCLITE_CONFIG_DIR); if (rv == -1) at_exit(); } #endif Log1(PCSC_LOG_INFO, "pcsc-lite " VERSION " daemon ready."); /* * Record our pid to make it easier * to kill the correct pcscd * * Do not fork after this point or the stored pid will be wrong */ { int f; int mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; f = open(PCSCLITE_RUN_PID, O_RDWR | O_CREAT, mode); if (f != -1) { char pid[PID_ASCII_SIZE]; ssize_t rr; (void)snprintf(pid, sizeof(pid), "%u\n", (unsigned) getpid()); rr = write(f, pid, strlen(pid) + 1); if (rr < 0) { Log2(PCSC_LOG_CRITICAL, "writing " PCSCLITE_RUN_PID " failed: %s", strerror(errno)); } (void)close(f); /* set mode so that the file is world readable even is umask is * restrictive * The file is used by libpcsclite */ (void)chmod(PCSCLITE_RUN_PID, mode); } else Log2(PCSC_LOG_CRITICAL, "cannot create " PCSCLITE_RUN_PID ": %s", strerror(errno)); } /* * post initialistion */ Init = FALSE; /* * Hotplug rescan */ (void)signal(SIGUSR1, signal_reload); /* * Initialize the comm structure */ if (SocketActivated) rv = ListenExistingSocket(SD_LISTEN_FDS_START + 0); else rv = InitializeSocket(); if (rv) { Log1(PCSC_LOG_CRITICAL, "Error initializing pcscd."); at_exit(); } /* * Initialize the contexts structure */ rv = ContextsInitialize(customMaxThreadCounter, customMaxThreadCardHandles); if (rv == -1) { Log1(PCSC_LOG_CRITICAL, "Error initializing pcscd."); at_exit(); } (void)signal(SIGPIPE, SIG_IGN); (void)signal(SIGHUP, SIG_IGN); /* needed for Solaris. The signal is sent * when the shell is existed */ #if !defined(PCSCLITE_STATIC_DRIVER) && defined(USE_USB) /* * Set up the search for USB/PCMCIA devices */ rv = HPSearchHotPluggables(); #ifndef USE_SERIAL if (rv) at_exit(); #endif rv = HPRegisterForHotplugEvents(); if (rv) { Log1(PCSC_LOG_ERROR, "HPRegisterForHotplugEvents failed"); at_exit(); } RFWaitForReaderInit(); #endif /* * Set up the power management callback routine */ (void)PMRegisterForPowerEvents(); /* initialisation succeeded */ if (pipefd[1] >= 0) { char buf = 0; ssize_t rr; /* write a 0 (success) to father process */ rr = write(pipefd[1], &buf, 1); if (rr < 0) { Log2(PCSC_LOG_ERROR, "write() failed: %s", strerror(errno)); } close(pipefd[1]); } SVCServiceRunLoop(); Log1(PCSC_LOG_ERROR, "SVCServiceRunLoop returned"); return EXIT_FAILURE; } static void at_exit(void) { Log1(PCSC_LOG_INFO, "cleaning " PCSCLITE_IPC_DIR); clean_temp_files(); if (pipefd[1] >= 0) { char buf; ssize_t r; /* write the error code to father process */ buf = ExitValue; r = write(pipefd[1], &buf, 1); if (r < 0) { Log2(PCSC_LOG_ERROR, "write() failed: %s", strerror(errno)); } close(pipefd[1]); } exit(ExitValue); }
static error_t parse_opt (int key, char *arg, struct argp_state *state) { struct arguments *arguments = state->input; unsigned short port; #ifdef HAS_SYSTEMD int num_sockets; #endif // HAS_SYSTEMD struct alias_list_element* alias_element; switch (key) { case 'p': x_sockaddr_set_port(&arguments->listen.value.sa, atoi(arg)); break; case 'a': alias_element = (struct alias_list_element*)init_list(malloc(sizeof(struct alias_list_element))); if (alias_element == NULL) { return ARGP_ERR_UNKNOWN; } alias_element->pair.vpath = arg; alias_element->pair.ppath = parse_alias_opt(arg); if (alias_element->pair.ppath == NULL) { free(alias_element); return ARGP_ERR_UNKNOWN; } arguments->alias_list = list_push_back(arguments->alias_list, alias_element); break; case 'r': alias_element = (struct alias_list_element*)init_list(malloc(sizeof(struct alias_list_element))); if (alias_element == NULL) { return ARGP_ERR_UNKNOWN; } alias_element->pair.vpath = "/"; alias_element->pair.ppath = arg; arguments->alias_list = list_push_back(arguments->alias_list, alias_element); break; case 'v': arguments->verbose = 1; break; case 'l': arguments->log = 1; break; case 256: port = x_sockaddr_get_port(&arguments->listen.value.sa); if(inet_pton(AF_INET, arg, &(((struct sockaddr_in*)(&arguments->listen.value.sa))->sin_addr))) { arguments->listen.value.sa.sa_family = AF_INET; x_sockaddr_set_port(&arguments->listen.value.sa, port); arguments->listen.type = LOGFANOUTD_LISTEN_SOCKADDR; } else if(inet_pton(AF_INET6, arg, &(((struct sockaddr_in6*)(&arguments->listen.value.sa))->sin6_addr))) { arguments->listen.value.sa.sa_family = AF_INET6; x_sockaddr_set_port(&arguments->listen.value.sa, port); arguments->listen.type = LOGFANOUTD_LISTEN_SOCKADDR; } else { return ARGP_ERR_UNKNOWN; } break; #ifdef HAS_SYSTEMD case 257: num_sockets = sd_listen_fds(0); if (num_sockets == 1) { arguments->listen.type = LOGFANOUTD_LISTEN_FD; arguments->listen.value.fd = SD_LISTEN_FDS_START; } else { if (num_sockets == 0) { fprintf(stderr, "No sockets are provided by systemd\n"); } else if (num_sockets < 0) { fprintf(stderr, "An error occured during sd_listen_fds\n"); } else if (num_sockets > 1) { fprintf(stderr, "Too many sockets are provided by systemd\n"); } return ARGP_ERR_UNKNOWN; } break; #endif // HAS_SYSTEMD default: return ARGP_ERR_UNKNOWN; } return 0; }
/* * Class: org_linjian_sd_daemon_java_NativeUtil * Method: sd_listen_fds * Signature: (I)I */ JNIEXPORT jint JNICALL Java_org_linjian_sd_1daemon_1java_NativeUtil_sd_1listen_1fds (JNIEnv *env, jclass cls, jint unset) { return (jint)sd_listen_fds((int)unset); }
/*! starts listening on a TCP/IP (v4 or v6) address. * * \param address the IP address to bind to * \param port the TCP/IP port number to listen to * \param flags some flags, such as O_CLOEXEC and O_NONBLOCK (the most prominent) to set on server socket and each created client socket * * \retval true successfully initialized * \retval false some failure occured during setting up the server socket. */ bool ServerSocket::open(const std::string& address, int port, int flags) { #ifndef NDEBUG setLoggingPrefix("ServerSocket(%s:%d)", address.c_str(), port); #endif TRACE("opening"); int sd_fd_count = sd_listen_fds(false); addrinfo* res = nullptr; addrinfo hints; addrinfo* ri = nullptr; int rc; int fd = -1; in6_addr saddr; memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_NUMERICSERV; hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; if ((rc = inet_pton(AF_INET, address.c_str(), &saddr)) == 1) { hints.ai_family = AF_INET; hints.ai_flags |= AI_NUMERICHOST; } else if ((rc = inet_pton(AF_INET6, address.c_str(), &saddr)) == 1) { hints.ai_family = AF_INET6; hints.ai_flags |= AI_NUMERICHOST; } else { switch (rc) { case -1: // errno is set properly errorText_ = strerror(errno); break; case 0: // invalid network addr format errorText_ = strerror(EINVAL); break; default: // unknown error errorText_ = strerror(EINVAL); break; } return false; } char sport[16]; snprintf(sport, sizeof(sport), "%d", port); if ((rc = getaddrinfo(address.c_str(), sport, &hints, &res)) != 0) { errorText_ = gai_strerror(rc); goto err; } typeMask_ = 0; flags_ = flags; if (flags & O_CLOEXEC) { flags_ &= ~O_CLOEXEC; typeMask_ |= SOCK_CLOEXEC; } if (flags & O_NONBLOCK) { flags_ &= ~O_NONBLOCK; typeMask_ |= SOCK_NONBLOCK; } // check if passed by parent x0d first for (ri = res; ri != nullptr; ri = ri->ai_next) { if ((fd = x0::getSocketInet(address.c_str(), port)) >= 0) { // socket found, but ensure our expected `flags` are set. if ((flags & O_NONBLOCK) && fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK) < 0) goto syserr; if ((flags & O_CLOEXEC) && fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC) < 0) goto syserr; goto done; } } // check if systemd created the socket for us if (sd_fd_count > 0) { fd = SD_LISTEN_FDS_START; int last = fd + sd_fd_count; for (addrinfo* ri = res; ri != nullptr; ri = ri->ai_next) { for (; fd < last; ++fd) { if (sd_is_socket_inet(fd, ri->ai_family, ri->ai_socktype, true, port) > 0) { // socket found, but ensure our expected `flags` are set. if ((flags & O_NONBLOCK) && fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK) < 0) goto syserr; if ((flags & O_CLOEXEC) && fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC) < 0) goto syserr; #if defined(TCP_QUICKACK) if (::setsockopt(fd, SOL_TCP, TCP_QUICKACK, &rc, sizeof(rc)) < 0) goto syserr; #endif #if defined(TCP_DEFER_ACCEPT) && defined(WITH_TCP_DEFER_ACCEPT) if (::setsockopt(fd, SOL_TCP, TCP_DEFER_ACCEPT, &rc, sizeof(rc)) < 0) goto syserr; #endif goto done; } } } char buf[256]; snprintf(buf, sizeof(buf), "Running under systemd socket unit, but we received no socket for %s:%d.", address.c_str(), port); errorText_ = buf; goto err; } // create socket manually for (ri = res; ri != nullptr; ri = ri->ai_next) { fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (fd < 0) goto syserr; if ((flags & O_NONBLOCK) && fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK) < 0) goto syserr; if ((flags & O_CLOEXEC) && fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC) < 0) goto syserr; rc = 1; #if defined(SO_REUSEADDR) if (::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &rc, sizeof(rc)) < 0) goto syserr; #endif #if defined(TCP_QUICKACK) if (::setsockopt(fd, SOL_TCP, TCP_QUICKACK, &rc, sizeof(rc)) < 0) goto syserr; #endif #if defined(TCP_DEFER_ACCEPT) && defined(WITH_TCP_DEFER_ACCEPT) if (::setsockopt(fd, SOL_TCP, TCP_DEFER_ACCEPT, &rc, sizeof(rc)) < 0) goto syserr; #endif // TODO so_linger(false, 0) // TODO so_keepalive(true) if (::bind(fd, res->ai_addr, res->ai_addrlen) < 0) goto syserr; if (::listen(fd, backlog_) < 0) goto syserr; goto done; } done: fd_ = fd; addressFamily_ = res->ai_family; freeaddrinfo(res); address_ = address; port_ = port; io_.set<ServerSocket, &ServerSocket::accept>(this); start(); return true; syserr: errorText_ = strerror(errno); err: if (res) freeaddrinfo(res); if (fd >= 0) ::close(fd); return false; }
/** * @short Performs the listening with the given mode * @memberof onion_t * * This is the main loop for the onion server. * * @returns !=0 if there is any error. It returns actualy errno from the network operations. See socket for more information. */ int onion_listen(onion *o){ #ifdef HAVE_PTHREADS if (o->flags&O_DETACH_LISTEN && !(o->flags&O_DETACHED)){ // On first call it sets the variable, and then call again, this time detached. o->flags|=O_DETACHED; pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED); // It do not need to pthread_join. No leak here. pthread_t listen_thread; pthread_create(&listen_thread, &attr,(void*(*)(void*)) onion_listen, o); pthread_attr_destroy(&attr); return 0; } #endif int sockfd=0; #ifdef HAVE_SYSTEMD if (o->flags&O_SYSTEMD){ int n=sd_listen_fds(0); ONION_DEBUG("Checking if have systemd sockets: %d",n); if (n>0){ // If 0, normal startup. Else use the first LISTEN_FDS. ONION_DEBUG("Using systemd sockets"); if (n>1){ ONION_WARNING("Get more than one systemd socket descriptor. Using only the first."); } sockfd=SD_LISTEN_FDS_START+0; } } #endif if (sockfd==0){ struct addrinfo hints; struct addrinfo *result, *rp; memset(&hints,0, sizeof(struct addrinfo)); hints.ai_canonname=NULL; hints.ai_addr=NULL; hints.ai_next=NULL; hints.ai_socktype=SOCK_STREAM; hints.ai_family=AF_UNSPEC; hints.ai_flags=AI_PASSIVE|AI_NUMERICSERV; if (getaddrinfo(o->hostname, o->port, &hints, &result) !=0 ){ ONION_ERROR("Error getting local address and port: %s", strerror(errno)); return errno; } int optval=1; for(rp=result;rp!=NULL;rp=rp->ai_next){ sockfd=socket(rp->ai_family, rp->ai_socktype | SOCK_CLOEXEC, rp->ai_protocol); if(SOCK_CLOEXEC == 0) { // Good compiler know how to cut this out int flags=fcntl(sockfd, F_GETFD); if (flags==-1){ ONION_ERROR("Retrieving flags from listen socket"); } flags|=FD_CLOEXEC; if (fcntl(sockfd, F_SETFD, flags)==-1){ ONION_ERROR("Setting O_CLOEXEC to listen socket"); } } if (sockfd<0) // not valid continue; if (setsockopt(sockfd,SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval) ) < 0){ ONION_ERROR("Could not set socket options: %s",strerror(errno)); } if (bind(sockfd, rp->ai_addr, rp->ai_addrlen) == 0) break; // Success close(sockfd); } if (rp==NULL){ ONION_ERROR("Could not find any suitable address to bind to."); return errno; } #ifdef __DEBUG__ char address[64]; getnameinfo(rp->ai_addr, rp->ai_addrlen, address, 32, &address[32], 32, NI_NUMERICHOST | NI_NUMERICSERV); ONION_DEBUG("Listening to %s:%s",address,&address[32]); #endif freeaddrinfo(result); listen(sockfd,5); // queue of only 5. } o->listenfd=sockfd; // Drops priviledges as it has binded. if (o->username){ struct passwd *pw; pw=getpwnam(o->username); int error; if (!pw){ ONION_ERROR("Cant find user to drop priviledges: %s", o->username); return errno; } else{ error=initgroups(o->username, pw->pw_gid); error|=setgid(pw->pw_gid); error|=setuid(pw->pw_uid); } if (error){ ONION_ERROR("Cant set the uid/gid for user %s", o->username); return errno; } } if (o->flags&O_POLL){ #ifdef HAVE_PTHREADS o->poller=onion_poller_new(o->max_threads+1); #else o->poller=onion_poller_new(8); #endif onion_poller_add(o->poller, onion_poller_slot_new(o->listenfd, (void*)onion_accept_request, o)); // O_POLL && O_THREADED == O_POOL. Create several threads to poll. #ifdef HAVE_PTHREADS if (o->flags&O_THREADED){ ONION_WARNING("Pool mode is experimental. %d threads.", o->max_threads); pthread_t *thread=(pthread_t*)malloc(sizeof(pthread_t)*(o->max_threads-1)); int i; for(i=0;i<o->max_threads-1;i++){ pthread_create(&thread[i], NULL, onion_poller_adaptor, o); } onion_poller_poll(o->poller); ONION_DEBUG("Stopped poll"); for(i=0;i<o->max_threads-1;i++){ //pthread_cancel(thread[i]); // Cancel is WRONG! It left sometimes mutex without unlock, wich made deadlocks. For example. pthread_join(thread[i], NULL); } free(thread); } else #endif { ONION_WARNING("Poller mode is experimental."); onion_poller_poll(o->poller); } } else if (o->flags&O_ONE){ if ((o->flags&O_ONE_LOOP) == O_ONE_LOOP){ while(o->listenfd>0){ // Loop while listening onion_accept_request(o); } } else{ ONION_DEBUG("Listening just one connection"); onion_accept_request(o); } } #ifdef HAVE_PTHREADS else if (o->flags&O_THREADS_ENABLED){ pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED); // It do not need to pthread_join. No leak here. while(1){ struct sockaddr_storage cli_addr; socklen_t cli_len; int clientfd=onion_accept(o, &cli_addr, &cli_len); if (clientfd<0) return errno; // If more than allowed processes, it waits here blocking socket, as it should be. // __DEBUG__ #if 0 int nt; sem_getvalue(&o->thread_count, &nt); ONION_DEBUG("%d threads working, %d max threads", o->max_threads-nt, o->max_threads); #endif sem_wait(&o->thread_count); // Has to be malloc'd. If not it wil be overwritten on next petition. The threads frees it onion_request_thread_data *data=malloc(sizeof(onion_request_thread_data)); data->o=o; data->clientfd=clientfd; data->client_addr=cli_addr; data->client_len=cli_len; pthread_create(&data->thread_handle, &attr, onion_request_thread, data); } pthread_attr_destroy(&attr); } #endif close(o->listenfd); return 0; }
int simple_protocol_setup(const AvahiPoll *poll_api) { struct sockaddr_un sa; mode_t u; int n; assert(!server); server = avahi_new(Server, 1); server->poll_api = poll_api; server->remove_socket = 0; server->fd = -1; server->n_clients = 0; AVAHI_LLIST_HEAD_INIT(Client, server->clients); server->watch = NULL; u = umask(0000); if ((n = sd_listen_fds(1)) < 0) { avahi_log_warn("Failed to acquire systemd file descriptors: %s", strerror(-n)); goto fail; } if (n > 1) { avahi_log_warn("Too many systemd file descriptors passed."); goto fail; } if (n == 1) { int r; if ((r = sd_is_socket(SD_LISTEN_FDS_START, AF_LOCAL, SOCK_STREAM, 1)) < 0) { avahi_log_warn("Passed systemd file descriptor is of wrong type: %s", strerror(-r)); goto fail; } server->fd = SD_LISTEN_FDS_START; } else { if ((server->fd = socket(AF_LOCAL, SOCK_STREAM, 0)) < 0) { avahi_log_warn("socket(AF_LOCAL, SOCK_STREAM, 0): %s", strerror(errno)); goto fail; } memset(&sa, 0, sizeof(sa)); sa.sun_family = AF_LOCAL; strncpy(sa.sun_path, AVAHI_SOCKET, sizeof(sa.sun_path)-1); /* We simply remove existing UNIX sockets under this name. The Avahi daemon makes sure that it runs only once on a host, therefore sockets that already exist are stale and may be removed without any ill effects */ unlink(AVAHI_SOCKET); if (bind(server->fd, (struct sockaddr*) &sa, sizeof(sa)) < 0) { avahi_log_warn("bind(): %s", strerror(errno)); goto fail; } server->remove_socket = 1; if (listen(server->fd, SOMAXCONN) < 0) { avahi_log_warn("listen(): %s", strerror(errno)); goto fail; } } umask(u); server->watch = poll_api->watch_new(poll_api, server->fd, AVAHI_WATCH_IN, server_work, server); return 0; fail: umask(u); simple_protocol_shutdown(); return -1; }
/*! starts listening on a UNIX domain server socket. * * \param path the path on the local file system, that this socket is to listen to. * \param flags some flags, such as O_CLOEXEC and O_NONBLOCK (the most prominent) to set on server socket and each created client socket * * \retval true successfully initialized * \retval false some failure occured during setting up the server socket. */ bool ServerSocket::open(const std::string& path, int flags) { #ifndef NDEBUG setLoggingPrefix("ServerSocket(%s)", path.c_str()); #endif TRACE("opening"); int fd = -1; size_t addrlen; int sd_fd_count = sd_listen_fds(false); typeMask_ = 0; flags_ = flags; if (flags & O_CLOEXEC) { flags_ &= ~O_CLOEXEC; typeMask_ |= SOCK_CLOEXEC; } if (flags & O_NONBLOCK) { flags_ &= ~O_NONBLOCK; typeMask_ |= SOCK_NONBLOCK; } // check if passed by parent x0d first if ((fd = x0::getSocketUnix(path.c_str())) >= 0) { // socket found, but ensure our expected `flags` are set. if (flags && fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | flags) < 0) { goto syserr; } else { goto done; } } // check if systemd created the socket for us if (sd_fd_count > 0) { fd = SD_LISTEN_FDS_START; int last = fd + sd_fd_count; for (; fd < last; ++fd) { if (sd_is_socket_unix(fd, AF_UNIX, SOCK_STREAM, path.c_str(), path.size()) > 0) { // socket found, but ensure our expected `flags` are set. if (flags && fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | flags) < 0) { goto syserr; } else { goto done; } } } errorText_ = "Running under systemd socket unit, but we received no UNIX-socket for \"" + path + "\"."; goto err; } // create socket manually fd = ::socket(PF_UNIX, SOCK_STREAM, 0); if (fd < 0) goto syserr; if (flags && fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | flags) < 0) goto syserr; struct sockaddr_un addr; addr.sun_family = AF_UNIX; if (path.size() >= sizeof(addr.sun_path)) { errno = ENAMETOOLONG; goto syserr; } addrlen = sizeof(addr.sun_family) + strlen(strncpy(addr.sun_path, path.c_str(), sizeof(addr.sun_path))); if (::bind(fd, reinterpret_cast<struct sockaddr*>(&addr), addrlen) < 0) goto syserr; if (::listen(fd, backlog_)) goto syserr; if (chmod(path.c_str(), 0666) < 0) { perror("chmod"); } done: fd_ = fd; addressFamily_ = AF_UNIX; address_ = path; port_ = 0; io_.set<ServerSocket, &ServerSocket::accept>(this); start(); return true; syserr: errorText_ = strerror(errno); err: if (fd >= 0) ::close(fd); return false; }
void SocketManager::MainLoop() { // remove evironment values passed by systemd sd_listen_fds(1); // Daemon is ready to work. sd_notify(0, "READY=1"); m_working = true; while (m_working) { fd_set readSet = m_readSet; fd_set writeSet = m_writeSet; timeval localTempTimeout; timeval *ptrTimeout = &localTempTimeout; // I need to extract timeout from priority_queue. // Timeout in priority_queue may be deprecated. // I need to find some actual one. while (!m_timeoutQueue.empty()) { auto &top = m_timeoutQueue.top(); auto &desc = m_socketDescriptionVector[top.sock]; if (top.time == desc.timeout) { // This timeout matches timeout from socket. // It can be used. break; } else { // This socket was used after timeout in priority queue was set up. // We need to update timeout and find some useable one. Timeout tm = { desc.timeout , top.sock}; m_timeoutQueue.pop(); m_timeoutQueue.push(tm); } } if (m_timeoutQueue.empty()) { LogDebug("No usaable timeout found."); ptrTimeout = NULL; // select will wait without timeout } else { time_t currentTime = time(NULL); auto &pqTimeout = m_timeoutQueue.top(); // 0 means that select won't block and socket will be closed ;-) ptrTimeout->tv_sec = currentTime < pqTimeout.time ? pqTimeout.time - currentTime : 0; ptrTimeout->tv_usec = 0; } int ret = select(m_maxDesc+1, &readSet, &writeSet, NULL, ptrTimeout); if (0 == ret) { // timeout Assert(!m_timeoutQueue.empty()); Timeout pqTimeout = m_timeoutQueue.top(); m_timeoutQueue.pop(); auto &desc = m_socketDescriptionVector[pqTimeout.sock]; if (!desc.isTimeout() || !desc.isOpen()) { // Connection was closed. Timeout is useless... desc.setTimeout(false); continue; } if (pqTimeout.time < desc.timeout) { // Is it possible? // This socket was used after timeout. We need to update timeout. pqTimeout.time = desc.timeout; m_timeoutQueue.push(pqTimeout); continue; } // timeout from m_timeoutQueue matches with socket.timeout // and connection is open. Time to close it! // Putting new timeout in queue here is pointless. desc.setTimeout(false); CloseSocket(pqTimeout.sock); // All done. Now we should process next select ;-) continue; } if (-1 == ret) { switch (errno) { case EINTR: LogDebug("EINTR in select"); break; default: int err = errno; LogError("Error in select: " << GetErrnoString(err)); return; } continue; } for (int i = 0; i < m_maxDesc+1 && ret; ++i) { if (FD_ISSET(i, &readSet)) { ReadyForRead(i); --ret; } if (FD_ISSET(i, &writeSet)) { ReadyForWrite(i); --ret; } } ProcessQueue(); } }
int main(int argc, char *argv[]) { _cleanup_(sd_bus_unrefp) sd_bus *a = NULL, *b = NULL; sd_id128_t server_id; bool is_unix; int r, in_fd, out_fd; log_set_target(LOG_TARGET_JOURNAL_OR_KMSG); log_parse_environment(); log_open(); r = parse_argv(argc, argv); if (r <= 0) goto finish; r = sd_listen_fds(0); if (r == 0) { in_fd = STDIN_FILENO; out_fd = STDOUT_FILENO; } else if (r == 1) { in_fd = SD_LISTEN_FDS_START; out_fd = SD_LISTEN_FDS_START; } else { log_error("Illegal number of file descriptors passed\n"); goto finish; } is_unix = sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 && sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0; r = sd_bus_new(&a); if (r < 0) { log_error_errno(r, "Failed to allocate bus: %m"); goto finish; } r = sd_bus_set_address(a, arg_bus_path); if (r < 0) { log_error_errno(r, "Failed to set address to connect to: %m"); goto finish; } r = sd_bus_negotiate_fds(a, is_unix); if (r < 0) { log_error_errno(r, "Failed to set FD negotiation: %m"); goto finish; } r = sd_bus_start(a); if (r < 0) { log_error_errno(r, "Failed to start bus client: %m"); goto finish; } r = sd_bus_get_bus_id(a, &server_id); if (r < 0) { log_error_errno(r, "Failed to get server ID: %m"); goto finish; } r = sd_bus_new(&b); if (r < 0) { log_error_errno(r, "Failed to allocate bus: %m"); goto finish; } r = sd_bus_set_fd(b, in_fd, out_fd); if (r < 0) { log_error_errno(r, "Failed to set fds: %m"); goto finish; } r = sd_bus_set_server(b, 1, server_id); if (r < 0) { log_error_errno(r, "Failed to set server mode: %m"); goto finish; } r = sd_bus_negotiate_fds(b, is_unix); if (r < 0) { log_error_errno(r, "Failed to set FD negotiation: %m"); goto finish; } r = sd_bus_set_anonymous(b, true); if (r < 0) { log_error_errno(r, "Failed to set anonymous authentication: %m"); goto finish; } r = sd_bus_start(b); if (r < 0) { log_error_errno(r, "Failed to start bus client: %m"); goto finish; } for (;;) { _cleanup_(sd_bus_message_unrefp)sd_bus_message *m = NULL; int events_a, events_b, fd; uint64_t timeout_a, timeout_b, t; struct timespec _ts, *ts; r = sd_bus_process(a, &m); if (r < 0) { log_error_errno(r, "Failed to process bus a: %m"); goto finish; } if (m) { r = sd_bus_send(b, m, NULL); if (r < 0) { log_error_errno(r, "Failed to send message: %m"); goto finish; } } if (r > 0) continue; r = sd_bus_process(b, &m); if (r < 0) { /* treat 'connection reset by peer' as clean exit condition */ if (r == -ECONNRESET) r = 0; goto finish; } if (m) { r = sd_bus_send(a, m, NULL); if (r < 0) { log_error_errno(r, "Failed to send message: %m"); goto finish; } } if (r > 0) continue; fd = sd_bus_get_fd(a); if (fd < 0) { log_error_errno(r, "Failed to get fd: %m"); goto finish; } events_a = sd_bus_get_events(a); if (events_a < 0) { log_error_errno(r, "Failed to get events mask: %m"); goto finish; } r = sd_bus_get_timeout(a, &timeout_a); if (r < 0) { log_error_errno(r, "Failed to get timeout: %m"); goto finish; } events_b = sd_bus_get_events(b); if (events_b < 0) { log_error_errno(r, "Failed to get events mask: %m"); goto finish; } r = sd_bus_get_timeout(b, &timeout_b); if (r < 0) { log_error_errno(r, "Failed to get timeout: %m"); goto finish; } t = timeout_a; if (t == (uint64_t) -1 || (timeout_b != (uint64_t) -1 && timeout_b < timeout_a)) t = timeout_b; if (t == (uint64_t) -1) ts = NULL; else { usec_t nw; nw = now(CLOCK_MONOTONIC); if (t > nw) t -= nw; else t = 0; ts = timespec_store(&_ts, t); } { struct pollfd p[3] = { {.fd = fd, .events = events_a, }, {.fd = STDIN_FILENO, .events = events_b & POLLIN, }, {.fd = STDOUT_FILENO, .events = events_b & POLLOUT, }};
/** parses and stores an option */ static error_t parse_opt (int key, char *arg, struct argp_state *state) { struct arguments *arguments = (struct arguments *) state->input; switch (key) { case 'T': arguments->tunnel = 1; arguments->has_work++; break; case 'R': arguments->route = 1; arguments->has_work++; break; case 'D': arguments->discover = 1; break; case 'S': { const char *serverip; const char *name = arguments->eibnetname; EIBnetServer *c; int port = 0; char *a = strdup (OPT_ARG(arg, state, "")); char *b; if (!a) die ("out of memory"); b = strchr (a, ':'); if (b) { *b++ = 0; port = atoi (b); } if (port <= 0) port = 3671; serverip = a; if (!*serverip) serverip = "224.0.23.12"; c = new EIBnetServer (serverip, port, arguments->tunnel, arguments->route, arguments->discover, arguments->l3(), arguments->tracer(), (name && *name) ? name : "knxd"); if (!c->init ()) die ("initialization of the EIBnet/IP server failed"); free (a); arguments->tunnel = false; arguments->route = false; arguments->discover = false; arguments->eibnetname = 0; } break; case 'u': { BaseServer *s; const char *name = OPT_ARG(arg,state,"/run/knx"); s = new LocalServer (arguments->l3(), arguments->tracer(), name); if (!s->init ()) die ("initialisation of the knxd unix protocol failed"); arguments->has_work++; } break; case 'i': { BaseServer *s = NULL; int port = atoi(OPT_ARG(arg,state,"6720")); if (port > 0) s = new InetServer (arguments->l3(), arguments->tracer(), port); if (!s || !s->init ()) die ("initialisation of the knxd inet protocol failed"); arguments->has_work++; } break; case 't': if (arg) { char *x; unsigned long level = strtoul(arg, &x, 0); if (*x) die ("Trace level: '%s' is not a number", arg); arguments->tracer(true)->SetTraceLevel (level); } else arguments->tracer(true)->SetTraceLevel (0); break; case 'f': arguments->tracer(true)->SetErrorLevel (arg ? atoi (arg) : 0); break; case 'e': if (arguments->has_l3 ()) { die ("You need to specify '-e' earlier"); } arguments->addr = readaddr (arg); break; case 'p': arguments->pidfile = arg; break; case 'd': arguments->daemon = OPT_ARG(arg,state,"/dev/null"); break; case 'c': if (!CreateGroupCache (arguments->l3(), arguments->tracer(), true)) die ("initialisation of the group cache failed"); break; case 'n': arguments->eibnetname = (char *)arg; if(arguments->eibnetname[0] == '=') arguments->eibnetname++; if(strlen(arguments->eibnetname) >= 30) die("EIBnetServer/IP name must be shorter than 30 bytes"); break; case OPT_FORCE_BROADCAST: arguments->force_broadcast = true; break; case OPT_STOP_NOW: arguments->stop_now = true; break; case OPT_BACK_TUNNEL_NOQUEUE: arguments->l2opts.flags |= FLAG_B_TUNNEL_NOQUEUE; break; case OPT_BACK_TPUARTS_ACKGROUP: arguments->l2opts.flags |= FLAG_B_TPUARTS_ACKGROUP; break; case OPT_BACK_TPUARTS_ACKINDIVIDUAL: arguments->l2opts.flags |= FLAG_B_TPUARTS_ACKINDIVIDUAL; break; case OPT_BACK_TPUARTS_DISCH_RESET: arguments->l2opts.flags |= FLAG_B_TPUARTS_DISCH_RESET; break; case OPT_BACK_EMI_NOQUEUE: arguments->l2opts.flags |= FLAG_B_EMI_NOQUEUE; break; case 'N': arguments->l2opts.flags |= FLAG_B_NO_MONITOR; break; case ARGP_KEY_ARG: case 'b': { arguments->l2opts.t = arguments->tracer (); Layer2 *l2 = Create (arg, &arguments->l2opts, arguments->l3 ()); if (!l2 || !l2->init ()) die ("initialisation of backend '%s' failed", arg); if (arguments->l2opts.flags) die ("You provided options which '%s' does not recognize", arg); memset(&arguments->l2opts, 0, sizeof(arguments->l2opts)); arguments->has_work++; break; } case ARGP_KEY_FINI: if (arguments->l2opts.flags) die ("You need to use backend flags in front of the affected backend"); #ifdef HAVE_SYSTEMD { BaseServer *s = NULL; const int num_fds = sd_listen_fds(0); if( num_fds < 0 ) die("Error getting fds from systemd."); // zero FDs from systemd is not a bug for( int fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START+num_fds; ++fd ) { if( sd_is_socket(fd, AF_UNSPEC, SOCK_STREAM, 1) <= 0 ) die("Error: socket not of expected type."); s = new SystemdServer(arguments->l3(), arguments->tracer(), fd); if (!s->init ()) die ("initialisation of the systemd socket failed"); arguments->has_work++; } } #endif errno = 0; if (arguments->tunnel || arguments->route || arguments->discover || arguments->eibnetname) die ("Option '-S' starts the multicast server.\n" "-T/-R/-D/-n after or without that option are useless."); if (arguments->l2opts.flags) die ("You provided L2 flags after specifying an L2 interface."); if (arguments->has_work == 0) die ("I know about no interface. Nothing to do. Giving up."); if (arguments->has_work == 1) die ("I only have one interface. Nothing to do. Giving up."); arguments->finish_l3(); break; default: return ARGP_ERR_UNKNOWN; } return 0; }