Beispiel #1
0
static void create_listen_socket(server_conf_t *conf)
{
/*  Creates the socket on which to listen for client connections.
 */
    int ld;
    struct sockaddr_in addr;
    const int on = 1;

    if ((ld = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
        log_err(errno, "Unable to create listening socket");
    }
    DPRINTF((9, "Opened listen socket: fd=%d.\n", ld));
    set_fd_nonblocking(ld);
    set_fd_closed_on_exec(ld);

    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(conf->port);

    if (conf->enableLoopBack) {
        addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
    }
    else {
        addr.sin_addr.s_addr = htonl(INADDR_ANY);
    }
    if (setsockopt(ld, SOL_SOCKET, SO_REUSEADDR,
      (const void *) &on, sizeof(on)) < 0) {
        log_err(errno, "Unable to set REUSEADDR socket option");
    }
    if (bind(ld, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
        log_err(errno, "Unable to bind to port %d", conf->port);
    }
    if (listen(ld, 10) < 0) {
        log_err(errno, "Unable to listen on port %d", conf->port);
    }
    conf->ld = ld;
    return;
}
int open_logfile_obj(obj_t *logfile)
{
/*  (Re)opens the specified 'logfile' obj.
 *  Since this logfile can be re-opened after the daemon has chdir()'d,
 *    it must be specified with an absolute pathname.
 *  Returns 0 if the logfile is successfully opened; o/w, returns -1.
 */
    char  dirname[PATH_MAX];
    int   flags;
    char *now;
    char *msg;

    assert(logfile != NULL);
    assert(is_logfile_obj(logfile));
    assert(logfile->name != NULL);
    assert(logfile->name[0] == '/');
    assert(logfile->aux.logfile.console != NULL);
    assert(logfile->aux.logfile.console->name != NULL);

    if (logfile->fd >= 0) {
        if (close(logfile->fd) < 0)     /* log err and continue */
            log_msg(LOG_WARNING, "Unable to close logfile \"%s\": %s",
                logfile->name, strerror(errno));
        logfile->fd = -1;
    }
    /*  Perform conversion specifier expansion.
     */
    if (logfile->aux.logfile.fmtName) {

        char buf[MAX_LINE];

        if (format_obj_string(buf, sizeof(buf),
          logfile->aux.logfile.console,
          logfile->aux.logfile.fmtName) < 0) {
            log_msg(LOG_WARNING,
                "Unable to open logfile for [%s]: filename exceeded buffer",
                logfile->aux.logfile.console->name);
            logfile->fd = -1;
            return(-1);
        }
        free(logfile->name);
        logfile->name = create_string(buf);
    }
    /*  Create intermediate directories.
     */
    if (get_dir_name(logfile->name, dirname, sizeof(dirname))) {
        (void) create_dirs(dirname);
    }
    /*  Only truncate on the initial open if ZeroLogs was enabled.
     */
    flags = O_WRONLY | O_CREAT | O_APPEND | O_NONBLOCK;
    if (logfile->aux.logfile.gotTruncate) {
        logfile->aux.logfile.gotTruncate = 0;
        flags |= O_TRUNC;
    }
    if ((logfile->fd = open(logfile->name, flags, S_IRUSR | S_IWUSR)) < 0) {
        log_msg(LOG_WARNING, "Unable to open logfile \"%s\": %s",
            logfile->name, strerror(errno));
        return(-1);
    }
    if (logfile->aux.logfile.opts.enableLock
            && (get_write_lock(logfile->fd) < 0)) {
        log_msg(LOG_WARNING, "Unable to lock \"%s\"", logfile->name);
        close(logfile->fd);             /* ignore err on close() */
        logfile->fd = -1;
        return(-1);
    }
    logfile->gotEOF = 0;
    set_fd_nonblocking(logfile->fd);    /* redundant, just playing it safe */
    set_fd_closed_on_exec(logfile->fd);

    now = create_long_time_string(0);
    msg = create_format_string("%sConsole [%s] log opened at %s%s",
        CONMAN_MSG_PREFIX, logfile->aux.logfile.console->name, now,
        CONMAN_MSG_SUFFIX);
    write_obj_data(logfile, msg, strlen(msg), 0);
    free(now);
    free(msg);
    /*
     *  Since the above console log message is not marked "informational",
     *    the test in write_obj_data() to re-init the line state will not
     *    be triggered.  Thusly, we re-initialize the line state here.
     */
    logfile->aux.logfile.lineState = CONMAN_LOG_LINE_INIT;

    DPRINTF((9, "Opened [%s] logfile: fd=%d file=%s.\n",
        logfile->aux.logfile.console->name, logfile->fd, logfile->name));
    return(0);
}
Beispiel #3
0
struct worker *
worker_start(EV_P_ struct session *session)
{
    struct worker *w;
    pid_t pid;
    int stdin_fds [2] = {-1, -1};
    int stdout_fds[2] = {-1, -1};
    int stderr_fds[2] = {-1, -1};
    int msgin_fds [2] = {-1, -1};
    int msgout_fds[2] = {-1, -1};

#if WORKER_TIMINGS
    uint64_t _start = now_us();
#endif

    if ((w = calloc(1, sizeof(*w))) == NULL) {
        goto fail;
    }
    w->session = session;
    writeq_init(&w->stdin_writeq);
    writeq_init(&w->msgin_writeq);

    if (pipe(stdin_fds ) < 0 ||
        pipe(stdout_fds) < 0 ||
        pipe(stderr_fds) < 0 ||
        pipe(msgin_fds ) < 0 ||
        pipe(msgout_fds) < 0) {
        LOG_ERRNO("pipe()");
        goto fail;
    }
    maxfd_update(stdin_fds [0]);
    maxfd_update(stdin_fds [1]);
    maxfd_update(stdout_fds[0]);
    maxfd_update(stdout_fds[1]);
    maxfd_update(stderr_fds[0]);
    maxfd_update(stderr_fds[1]);
    maxfd_update(msgin_fds [0]);
    maxfd_update(msgin_fds [1]);
    maxfd_update(msgout_fds[0]);
    maxfd_update(msgout_fds[1]);


    pid = fork();
    if (pid < 0) {
        LOG_ERRNO("fork()");
        goto fail;
    }
    if (pid == 0) {
        /* child. */
        if (dup2(stdin_fds [0], 0) < 0 ||
            dup2(stdout_fds[1], 1) < 0 ||
            dup2(stderr_fds[1], 2) < 0 ||
            dup2(msgin_fds [0], 3) < 0 ||
            dup2(msgout_fds[1], 4) < 0) {
            exit(EXIT_FAILURE);
        }
        maxfd_closeall(5);
        pyenv_child_after_fork();
        exit(EXIT_SUCCESS);
    } else {
        /* parent. */
        close(stdin_fds [0]);
        close(stdout_fds[1]);
        close(stderr_fds[1]);
        close(msgin_fds [0]);
        close(msgout_fds[1]);

        set_fd_nonblocking(stdin_fds [1]);
        set_fd_nonblocking(stdout_fds[0]);
        set_fd_nonblocking(stderr_fds[0]);
        set_fd_nonblocking(msgin_fds [1]);
        set_fd_nonblocking(msgout_fds[0]);

        ev_child_init(&w->child_watcher, worker_exited_cb, pid, 0);
        ev_child_start(EV_A_ &w->child_watcher);

        ev_io_init(&w->stdin_w , worker_write_stdin_cb, stdin_fds [1],
                   EV_WRITE);
        ev_io_init(&w->stdout_w, worker_read_stdout_cb, stdout_fds[0],
                   EV_READ);
        ev_io_init(&w->stderr_w, worker_read_stderr_cb, stderr_fds[0],
                   EV_READ);
        ev_io_init(&w->msgin_w , worker_write_msgin_cb, msgin_fds [1],
                   EV_WRITE);
        ev_io_init(&w->msgout_w, worker_read_msgout_cb, msgout_fds[0],
                   EV_READ);
        ev_io_start(EV_A_ &w->stdout_w);
        ev_io_start(EV_A_ &w->stderr_w);
        ev_io_start(EV_A_ &w->msgout_w);

        LOGF(3, "=== %d: worker started, fds=[%d, %d, %d, %d, %d]\n",
             worker_pid(w), stdin_fds[1], stdout_fds[0], stderr_fds[0],
             msgin_fds[1], msgout_fds[0]);

        w->f_alive = true;
    }
#if WORKER_TIMINGS
    worker_start_time += now_us() - _start;
    worker_start_calls++;
#endif

    return w;

 fail:
    close(stdin_fds [0]);
    close(stdin_fds [1]);
    close(stdout_fds[0]);
    close(stdout_fds[1]);
    close(stderr_fds[0]);
    close(stderr_fds[1]);
    close(msgin_fds [0]);
    close(msgin_fds [1]);
    close(msgout_fds[0]);
    close(msgout_fds[1]);
    free(w);
    return NULL;
}
Beispiel #4
0
int connect_to(int fd, struct addrinfo *ai, double timeout, char *tfo, char *msg, int msg_len, char *msg_accepted)
{
	int rc = -1;
	struct timeval to;
	fd_set wfds;

	/* make fd nonblocking */
	if (set_fd_nonblocking(fd) == -1)
		return RC_INVAL;

	/* wait for connection */
	FD_ZERO(&wfds);
	FD_SET(fd, &wfds);

	to.tv_sec  = (long)(timeout / 1000.0);
	to.tv_usec = (long)(timeout * 1000.0) % 1000000;

	/* connect to peer */
#ifdef TCP_TFO
	if (tfo && *tfo)
	{
		rc = sendto(fd, msg, msg_len, MSG_FASTOPEN, ai -> ai_addr, ai -> ai_addrlen);
		
		if(rc == msg_len)
			*msg_accepted = 1;
		if(errno == 0)
			return RC_OK;
		if(errno == ENOTSUP)
		{
			printf(gettext("TCP TFO Not Supported. Please check if \"/proc/sys/net/ipv4/tcp_fastopen\" is 1. Disabling TFO for now.\n"));
			*tfo = 0;
			goto old_connect;
		}
	}
			
	else
#else
	(void)tfo;
	(void)msg;
	(void)msg_len;
	(void)msg_accepted;
#endif
	{
		int rc = -1;

old_connect:
		rc = connect(fd, ai -> ai_addr, ai -> ai_addrlen);

		if (rc == 0)
		{
			/* connection made, return */
			return RC_OK;
		}

		if (rc == -1)
		{
			/* problem connecting */
			if (errno != EINPROGRESS)
			{
				set_error(gettext("problem connecting to host: %s"), strerror(errno));
				return RC_INVAL;
			}
		}
	}

	if (stop)
		return RC_CTRLC;

	/* wait for connection */
	rc = select(fd + 1, NULL, &wfds, NULL, &to);
	if (rc == 0)
	{
		set_error(gettext("connect time out"));
		return RC_TIMEOUT;	/* timeout */
	}
	else if (rc == -1)
	{
		if (errno == EINTR)
			return RC_CTRLC;/* ^C pressed */

		set_error(gettext("select() failed: %s"), strerror(errno));

		return RC_INVAL;	/* error */
	}
	else
	{
		int optval=0;
		socklen_t optvallen = sizeof optval;

		/* see if the connect succeeded or failed */
		if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &optval, &optvallen) == -1)
		{
			set_error(gettext("getsockopt failed (%s)"), strerror(errno));
			return RC_INVAL;
		}

		/* no error? */
		if (optval == 0)
			return RC_OK;

		/* don't ask */
		errno = optval;
	}

	set_error(gettext("could not connect (%s)"), strerror(errno));

	return RC_INVAL;
}
Beispiel #5
0
int open_serial_obj(obj_t *serial)
{
/*  (Re)opens the specified 'serial' obj.
 *  Returns 0 if the serial console is successfully opened; o/w, returns -1.
 *
 *  FIXME: Check to see if "downed" serial consoles are ever resurrected.
 */
    int fd;
    int flags;
    struct termios tty;

    assert(serial != NULL);
    assert(is_serial_obj(serial));

    if (serial->fd >= 0) {
        write_notify_msg(serial, LOG_INFO,
            "Console [%s] disconnected from \"%s\"",
            serial->name, serial->aux.serial.dev);
        set_tty_mode(&serial->aux.serial.tty, serial->fd);
        if (close(serial->fd) < 0)      /* log err and continue */
            log_msg(LOG_WARNING, "Unable to close [%s] device \"%s\": %s",
                serial->name, serial->aux.serial.dev, strerror(errno));
        serial->fd = -1;
    }
    flags = O_RDWR | O_NONBLOCK | O_NOCTTY;
    if ((fd = open(serial->aux.serial.dev, flags)) < 0) {
        log_msg(LOG_WARNING, "Unable to open [%s] device \"%s\": %s",
            serial->name, serial->aux.serial.dev, strerror(errno));
        goto err;
    }
    if (get_write_lock(fd) < 0) {
        log_msg(LOG_WARNING, "Unable to lock [%s] device \"%s\"",
            serial->name, serial->aux.serial.dev);
        goto err;
    }
    if (!isatty(fd)) {
        log_msg(LOG_WARNING, "[%s] device \"%s\" not a terminal",
            serial->name, serial->aux.serial.dev);
        goto err;
    }
    /*  According to the UNIX Programming FAQ v1.37
     *    <http://www.faqs.org/faqs/unix-faq/programmer/faq/>
     *    (Section 3.6: How to Handle a Serial Port or Modem),
     *    systems seem to differ as to whether a nonblocking
     *    open on a tty will affect subsequent read()s.
     *    Play it safe and be explicit!
     */
    set_fd_nonblocking(fd);
    set_fd_closed_on_exec(fd);
    /*
     *  Note that while the initial state of the console dev's termios
     *    are saved, the 'opts' settings are not.  This is because the
     *    settings do not change until the obj is destroyed, at which time
     *    the termios is reverted back to its initial state.
     *
     *  FIXME: Re-evaluate this thinking since a SIGHUP should attempt
     *         to resurrect "downed" serial objs.
     */
    get_tty_mode(&serial->aux.serial.tty, fd);
    get_tty_raw(&tty, fd);
    set_serial_opts(&tty, serial, &serial->aux.serial.opts);
    set_tty_mode(&tty, fd);
    serial->fd = fd;
    serial->gotEOF = 0;
    /*
     *  Success!
     */
    write_notify_msg(serial, LOG_INFO, "Console [%s] connected to \"%s\"",
        serial->name, serial->aux.serial.dev);
    DPRINTF((9, "Opened [%s] serial: fd=%d dev=%s bps=%d.\n",
        serial->name, serial->fd, serial->aux.serial.dev,
        bps_to_int(serial->aux.serial.opts.bps)));
    return(0);

err:
    if (fd >= 0) {
        close(fd);                      /* ignore errors */
    }
    return(-1);
}
static int connect_unixsock_obj(obj_t *unixsock)
{
/*  Opens a connection to the specified (unixsock) obj.
 *  Returns 0 if the connection is successfully completed; o/w, returns -1.
 */
    unixsock_obj_t     *auxp;
    struct stat         st;
    struct sockaddr_un  saddr;
    int                 rc;

    assert(unixsock != NULL);
    assert(is_unixsock_obj(unixsock));
    assert(unixsock->aux.unixsock.state != CONMAN_UNIXSOCK_UP);
    assert(strlen(unixsock->aux.unixsock.dev) <= max_unixsock_dev_strlen());

    auxp = &(unixsock->aux.unixsock);

    if (auxp->timer >= 0) {
        (void) tpoll_timeout_cancel(tp_global, auxp->timer);
        auxp->timer = -1;
    }

    if (stat(auxp->dev, &st) < 0) {
        log_msg(LOG_DEBUG, "Console [%s] cannot stat device \"%s\": %s",
            unixsock->name, auxp->dev, strerror(errno));
        return(disconnect_unixsock_obj(unixsock));
    }
#ifdef S_ISSOCK
    /*  Danger, Will Robinson!  S_ISSOCK not in POSIX.1-1996.
     *
     *  If this is not defined, connect() will detect the error of the device
     *    not being a socket.
     */
    if (!S_ISSOCK(st.st_mode)) {
        log_msg(LOG_INFO, "Console [%s] device \"%s\" is not a socket",
            unixsock->name, auxp->dev, strerror(errno));
        return(disconnect_unixsock_obj(unixsock));
    }
#endif /* S_ISSOCK */

    memset(&saddr, 0, sizeof(saddr));
    saddr.sun_family = AF_UNIX;
    rc = strlcpy(saddr.sun_path, auxp->dev, sizeof(saddr.sun_path));
    assert(rc < sizeof(saddr.sun_path));

    if ((unixsock->fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
        /*
         *  This error should probably not be considered fatal,
         *    but since it is elsewhere in the code, it is here as well.
         */
        log_err(errno, "Unable to create console [%s] socket", unixsock->name);
    }
    set_fd_nonblocking(unixsock->fd);
    set_fd_closed_on_exec(unixsock->fd);

    /*  FIXME: Check to see if connect() on a nonblocking unix domain socket
     *    can return EINPROGRESS.  I don't think it can.
     */
    if (connect(unixsock->fd,
            (struct sockaddr *) &saddr, sizeof(saddr)) < 0) {
        log_msg(LOG_INFO,
            "Console [%s] cannot connect to device \"%s\": %s",
            unixsock->name, auxp->dev, strerror(errno));
        return(disconnect_unixsock_obj(unixsock));
    }
    /*  Write-locking the unix domain socket appears ineffective.  But since
     *    create_unixsock_obj() already checks for duplicate devices, this is
     *    only an issue if two daemons are trying to simultaneously use the
     *    same local socket.
     */
    unixsock->gotEOF = 0;
    auxp->state = CONMAN_UNIXSOCK_UP;

    /*  Notify linked objs when transitioning into an UP state.
     */
    write_notify_msg(unixsock, LOG_NOTICE, "Console [%s] connected to \"%s\"",
        unixsock->name, auxp->dev);
    DPRINTF((9, "Opened [%s] unixsock: fd=%d dev=%s.\n",
            unixsock->name, unixsock->fd, auxp->dev));

    return(0);
}