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;
}
Example #2
0
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;
}
Example #3
0
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 */
}
Example #4
0
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;
}
Example #5
0
File: asocket.c Project: zeth/ainod
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;
}
Example #6
0
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);
}
Example #7
0
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 ++;
        }
Example #8
0
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;
}
Example #9
0
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);
}
Example #10
0
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 ;
	}
}
Example #11
0
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;
}
Example #13
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";
}
Example #14
0
File: stunnel.c Project: ssem/rat
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);
}
Example #15
0
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;
}
Example #16
0
/* 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);
    }
}
Example #17
0
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;
}
Example #18
0
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;
}
Example #19
0
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;
}
Example #20
0
/**
 * @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;
}
Example #21
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);
}
Example #22
0
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);
}
Example #24
0
/*! 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;
}
Example #25
0
/**
 * @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;
}
Example #27
0
/*! 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;
}
Example #28
0
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();
    }
}
Example #29
0
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, }};
Example #30
0
/** 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;
}