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); }
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; }
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; }
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); }