Esempio n. 1
0
void
input_parse(struct window_pane *wp)
{
	struct input_ctx	*ictx = &wp->ictx;
	u_char			 ch;

	if (BUFFER_USED(wp->in) == 0)
		return;

	ictx->buf = BUFFER_OUT(wp->in);
	ictx->len = BUFFER_USED(wp->in);
	ictx->off = 0;

	ictx->wp = wp;

	log_debug2("entry; buffer=%zu", ictx->len);

	if (wp->mode == NULL)
		screen_write_start(&ictx->ctx, wp, &wp->base);
	else
		screen_write_start(&ictx->ctx, NULL, &wp->base);

	if (ictx->off != ictx->len)
		wp->window->flags |= WINDOW_ACTIVITY;
	while (ictx->off < ictx->len) {
		ch = ictx->buf[ictx->off++];
		ictx->state(ch, ictx);
	}

	screen_write_stop(&ictx->ctx);

	buffer_remove(wp->in, ictx->len);
}
Esempio n. 2
0
/* Fill buffers from socket based on poll results. */
int
buffer_poll(struct pollfd *pfd, struct buffer *in, struct buffer *out)
{
	ssize_t	n;

	if (pfd->revents & (POLLERR|POLLNVAL|POLLHUP))
		return (-1);
	if (pfd->revents & POLLIN) {
		buffer_ensure(in, BUFSIZ);
		n = read(pfd->fd, BUFFER_IN(in), BUFFER_FREE(in));
		if (n == 0)
			return (-1);
		if (n == -1) {
			if (errno != EINTR && errno != EAGAIN)
				return (-1);
		} else
			buffer_add(in, n);
	}
	if (BUFFER_USED(out) > 0 && pfd->revents & POLLOUT) {
		n = write(pfd->fd, BUFFER_OUT(out), BUFFER_USED(out));
		if (n == -1) {
			if (errno != EINTR && errno != EAGAIN)
				return (-1);
		} else
			buffer_remove(out, n);
	}
	return (0);
}
Esempio n. 3
0
File: io.c Progetto: mbeck-/fdm
/* Write a line to the io write buffer from a va_list. */
void
io_vwriteline(struct io *io, const char *fmt, va_list ap)
{
    int	 n;
    va_list	 aq;

    if (io->error != NULL)
        return;

    IO_DEBUG(io, "in: wr: used=%zu, free=%zu",
             BUFFER_USED(io->wr), BUFFER_FREE(io->wr));

    if (fmt != NULL) {
        va_copy(aq, ap);
        n = xvsnprintf(NULL, 0, fmt, aq);
        va_end(aq);

        buffer_ensure(io->wr, n + 1);
        xvsnprintf(BUFFER_IN(io->wr), n + 1, fmt, ap);
        buffer_add(io->wr, n);
    } else
        n = 0;
    io_write(io, io->eol, strlen(io->eol));

    IO_DEBUG(io, "out: %zu bytes, wr: used=%zu, free=%zu",
             n + strlen(io->eol), BUFFER_USED(io->wr), BUFFER_FREE(io->wr));
}
Esempio n. 4
0
/* Start a job running, if it isn't already. */
int
job_run(struct job *job)
{
	int	nullfd, out[2], mode;

	if (!(job->flags & JOB_DONE))
		return (0);
	job->flags &= ~JOB_DONE;

	if (pipe(out) != 0)
		return (-1);

	switch (job->pid = fork()) {
	case -1:
		return (-1);
	case 0:		/* child */
		sigreset();
		/* XXX environ? */

		if (dup2(out[1], STDOUT_FILENO) == -1)
			fatal("dup2 failed");
		if (out[1] != STDOUT_FILENO)
			close(out[1]);
		close(out[0]);

		nullfd = open(_PATH_DEVNULL, O_RDWR, 0);
		if (nullfd < 0)
			fatal("open failed");
		if (dup2(nullfd, STDIN_FILENO) == -1)
			fatal("dup2 failed");
		if (dup2(nullfd, STDERR_FILENO) == -1)
			fatal("dup2 failed");
		if (nullfd != STDIN_FILENO && nullfd != STDERR_FILENO)
			close(nullfd);

		execl(_PATH_BSHELL, "sh", "-c", job->cmd, (char *) NULL);
		fatal("execl failed");
	default:	/* parent */
		close(out[1]);

		job->fd = out[0];
		if ((mode = fcntl(job->fd, F_GETFL)) == -1)
			fatal("fcntl failed");
		if (fcntl(job->fd, F_SETFL, mode|O_NONBLOCK) == -1)
			fatal("fcntl failed");
		if (fcntl(job->fd, F_SETFD, FD_CLOEXEC) == -1)
			fatal("fcntl failed");

		if (BUFFER_USED(job->out) != 0)
			buffer_remove(job->out, BUFFER_USED(job->out));

		return (0);
	}
}
Esempio n. 5
0
File: io.c Progetto: mbeck-/fdm
/* Write a block to the io write buffer. */
void
io_write(struct io *io, const void *buf, size_t len)
{
    if (io->error != NULL)
        return;

    IO_DEBUG(io, "in: %zu bytes, wr: used=%zu, free=%zu", len,
             BUFFER_USED(io->wr), BUFFER_FREE(io->wr));

    buffer_write(io->wr, buf, len);

    IO_DEBUG(io, "out: %zu bytes, wr: used=%zu, free=%zu", len,
             BUFFER_USED(io->wr), BUFFER_FREE(io->wr));
}
Esempio n. 6
0
File: io.c Progetto: mbeck-/fdm
/* Set up an io for polling. */
int
io_before_poll(struct io *io, struct pollfd *pfd)
{
    /* If io is NULL, don't let poll do anything with this one. */
    if (io == NULL) {
        memset(pfd, 0, sizeof *pfd);
        pfd->fd = -1;
        return (1);
    }

    /* Check for errors or closure. */
    if (io->error != NULL)
        return (-1);
    if (IO_CLOSED(io))
        return (0);

    /* Fill in pollfd. */
    memset(pfd, 0, sizeof *pfd);
    if (io->ssl != NULL)
        pfd->fd = SSL_get_fd(io->ssl);
    else
        pfd->fd = io->fd;
    if (io->rd != NULL)
        pfd->events |= POLLIN;
    if (io->wr != NULL && (BUFFER_USED(io->wr) != 0 ||
                           (io->flags & (IOF_NEEDFILL|IOF_NEEDPUSH|IOF_MUSTWR)) != 0))
        pfd->events |= POLLOUT;

    IO_DEBUG(io, "poll in: 0x%03x", pfd->events);

    return (1);
}
Esempio n. 7
0
File: io.c Progetto: mbeck-/fdm
/* Poll if there is lots of data to write. */
int
io_update(struct io *io, int timeout, char **cause)
{
    if (BUFFER_USED(io->wr) < IO_FLUSHSIZE)
        return (1);

    return (io_poll(io, timeout, cause));
}
Esempio n. 8
0
File: io.c Progetto: mbeck-/fdm
/* Poll until len bytes have been read into the read buffer. */
int
io_wait(struct io *io, size_t len, int timeout, char **cause)
{
    while (BUFFER_USED(io->rd) < len) {
        if (io_poll(io, timeout, cause) != 1)
            return (-1);
    }

    return (0);
}
Esempio n. 9
0
File: io.c Progetto: mbeck-/fdm
/* Poll until all data in the write buffer has been written to the socket. */
int
io_flush(struct io *io, int timeout, char **cause)
{
    while (BUFFER_USED(io->wr) != 0) {
        if (io_poll(io, timeout, cause) != 1)
            return (-1);
    }

    return (0);
}
Esempio n. 10
0
File: io.c Progetto: mbeck-/fdm
/* Return a specific number of bytes from the read buffer, if available. */
int
io_read2(struct io *io, void *buf, size_t len)
{
    if (io->error != NULL)
        return (-1);

    IO_DEBUG(io, "in: %zu bytes, rd: used=%zu, free=%zu", len,
             BUFFER_USED(io->rd), BUFFER_FREE(io->rd));

    if (BUFFER_USED(io->rd) < len)
        return (1);

    buffer_read(io->rd, buf, len);

    IO_DEBUG(io, "out: %zu bytes, rd: used=%zu, free=%zu", len,
             BUFFER_USED(io->rd), BUFFER_FREE(io->rd));

    return (0);
}
Esempio n. 11
0
File: io.c Progetto: mbeck-/fdm
/* Return a specific number of bytes from the read buffer, if available. */
void *
io_read(struct io *io, size_t len)
{
    void	*buf;

    IO_DEBUG(io, "in: %zu bytes, rd: used=%zu, free=%zu", len,
             BUFFER_USED(io->rd), BUFFER_FREE(io->rd));

    if (io->error != NULL)
        return (NULL);

    if (BUFFER_USED(io->rd) < len)
        return (NULL);

    buf = xmalloc(len);
    buffer_read(io->rd, buf, len);

    IO_DEBUG(io, "out: %zu bytes, rd: used=%zu, free=%zu", len,
             BUFFER_USED(io->rd), BUFFER_FREE(io->rd));

    return (buf);
}
Esempio n. 12
0
int
client_msg_dispatch(struct client_ctx *cctx, char **error)
{
	struct hdr		 hdr;
	struct client_msg	*msg;
	u_int		 	 i;

	if (BUFFER_USED(cctx->srv_in) < sizeof hdr)
		return (1);
	memcpy(&hdr, BUFFER_OUT(cctx->srv_in), sizeof hdr);
	if (BUFFER_USED(cctx->srv_in) < (sizeof hdr) + hdr.size)
		return (1);
	buffer_remove(cctx->srv_in, sizeof hdr);

	for (i = 0; i < nitems(client_msg_table); i++) {
		msg = client_msg_table + i;
		if (msg->type == hdr.type) {
			if (msg->fn(&hdr, cctx, error) != 0)
				return (-1);
			return (0);
		}
	}
	fatalx("unexpected message");
}
Esempio n. 13
0
File: io.c Progetto: mbeck-/fdm
/*
 * Return a line from the read buffer. EOL is stripped and the string returned
 * is zero-terminated.
 */
char *
io_readline2(struct io *io, char **buf, size_t *len)
{
    char	*ptr, *base;
    size_t	 size, maxlen, eollen;

    if (io->error != NULL)
        return (NULL);

    maxlen = BUFFER_USED(io->rd);
    if (maxlen > IO_MAXLINELEN)
        maxlen = IO_MAXLINELEN;
    eollen = strlen(io->eol);
    if (BUFFER_USED(io->rd) < eollen)
        return (NULL);

    IO_DEBUG(io, "in: rd: used=%zu, free=%zu",
             BUFFER_USED(io->rd), BUFFER_FREE(io->rd));

    base = ptr = BUFFER_OUT(io->rd);
    for (;;) {
        /* Find the first character in the EOL string. */
        ptr = memchr(ptr, *io->eol, maxlen - (ptr - base));

        if (ptr != NULL) {
            /* Found. Is there enough space for the rest? */
            if (ptr - base + eollen > maxlen) {
                /*
                 * No, this isn't it. Set ptr to NULL to handle
                 * as not found.
                 */
                ptr = NULL;
            } else if (strncmp(ptr, io->eol, eollen) == 0) {
                /* This is an EOL. */
                size = ptr - base;
                break;
            }
        }
        if (ptr == NULL) {
            IO_DEBUG(io,
                     "not found (%zu, %d)", maxlen, IO_CLOSED(io));

            /*
             * Not found within the length searched. If that was
             * the maximum length, this is an error.
             */
            if (maxlen == IO_MAXLINELEN) {
                if (io->error != NULL)
                    xfree(io->error);
                io->error =
                    xstrdup("io: maximum line length exceeded");
                return (NULL);
            }

            /*
             * If the socket has closed, just return all the data
             * (the buffer is known to be at least eollen long).
             */
            if (!IO_CLOSED(io))
                return (NULL);
            size = BUFFER_USED(io->rd);

            ENSURE_FOR(*buf, *len, size, 1);
            buffer_read(io->rd, *buf, size);
            (*buf)[size] = '\0';
            return (*buf);
        }

        /* Start again from the next character. */
        ptr++;
    }

    /* Copy the line and remove it from the buffer. */
    ENSURE_FOR(*buf, *len, size, 1);
    if (size != 0)
        buffer_read(io->rd, *buf, size);
    (*buf)[size] = '\0';

    /* Discard the EOL from the buffer. */
    buffer_remove(io->rd, eollen);

    IO_DEBUG(io, "out: %zu bytes, rd: used=%zu, free=%zu",
             size, BUFFER_USED(io->rd), BUFFER_FREE(io->rd));

    return (*buf);
}
Esempio n. 14
0
int
client_init(char *path, struct client_ctx *cctx, int start_server, int flags)
{
	struct sockaddr_un		sa;
	struct stat			sb;
	struct msg_identify_data	data;
	struct winsize			ws;
	size_t				size;
	int				mode;
	struct buffer		       *b;
	char			       *name;
#ifdef HAVE_SETPROCTITLE
	char		 		rpathbuf[MAXPATHLEN];
#endif

#ifdef HAVE_SETPROCTITLE
	if (realpath(path, rpathbuf) == NULL)
		strlcpy(rpathbuf, path, sizeof rpathbuf);
	setproctitle("client (%s)", rpathbuf);
#endif

	if (lstat(path, &sb) != 0) {
		if (start_server && errno == ENOENT) {
			if ((cctx->srv_fd = server_start(path)) == -1)
				goto start_failed;
			goto server_started;
		}
		goto not_found;
	}
	if (!S_ISSOCK(sb.st_mode)) {
		errno = ENOTSOCK;
		goto not_found;
	}

	memset(&sa, 0, sizeof sa);
	sa.sun_family = AF_UNIX;
	size = strlcpy(sa.sun_path, path, sizeof sa.sun_path);
	if (size >= sizeof sa.sun_path) {
		errno = ENAMETOOLONG;
		goto not_found;
	}

	if ((cctx->srv_fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
		fatal("socket");

	if (connect(
	    cctx->srv_fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) {
		if (errno == ECONNREFUSED) {
			if (unlink(path) != 0 || !start_server)
				goto not_found;
			if ((cctx->srv_fd = server_start(path)) == -1)
				goto start_failed;
			goto server_started;
		}
		goto not_found;
	}

server_started:
	if ((mode = fcntl(cctx->srv_fd, F_GETFL)) == -1)
		fatal("fcntl failed");
	if (fcntl(cctx->srv_fd, F_SETFL, mode|O_NONBLOCK) == -1)
		fatal("fcntl failed");
	cctx->srv_in = buffer_create(BUFSIZ);
	cctx->srv_out = buffer_create(BUFSIZ);

	if (isatty(STDIN_FILENO)) {
		if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == -1)
			fatal("ioctl(TIOCGWINSZ)");
		data.version = PROTOCOL_VERSION;
		data.flags = flags;
		data.sx = ws.ws_col;
		data.sy = ws.ws_row;
		*data.tty = '\0';
		if (getcwd(data.cwd, sizeof data.cwd) == NULL)
			*data.cwd = '\0';

		if ((name = ttyname(STDIN_FILENO)) == NULL)
			fatal("ttyname failed");
		if (strlcpy(data.tty, name, sizeof data.tty) >= sizeof data.tty)
			fatalx("ttyname failed");

		b = buffer_create(BUFSIZ);
		cmd_send_string(b, getenv("TERM"));
		client_write_server2(cctx, MSG_IDENTIFY,
		    &data, sizeof data, BUFFER_OUT(b), BUFFER_USED(b));
		buffer_destroy(b);
	}

	return (0);

start_failed:
	log_warnx("server failed to start");
	return (1);

not_found:
	log_warn("server not found");
	return (1);
}
Esempio n. 15
0
int
client_main(struct client_ctx *cctx)
{
	struct pollfd	 pfd;
	char		*error;
	int		 xtimeout; /* Yay for ncurses namespace! */

	siginit();

	logfile("client");

	error = NULL;
	while (!sigterm) {
		if (sigchld) {
			waitpid(WAIT_ANY, NULL, WNOHANG);
			sigchld = 0;
		}
		if (sigwinch)
			client_handle_winch(cctx);
		if (sigcont) {
			siginit();
			client_write_server(cctx, MSG_WAKEUP, NULL, 0);
			sigcont = 0;
		}

		switch (client_msg_dispatch(cctx, &error)) {
		case -1:
			goto out;
		case 0:
			/* May be more in buffer, don't let poll block. */
			xtimeout = 0;
			break;
		default:
			/* Out of data, poll may block. */
			xtimeout = INFTIM;
			break;
		}

		pfd.fd = cctx->srv_fd;
		pfd.events = POLLIN;
		if (BUFFER_USED(cctx->srv_out) > 0)
			pfd.events |= POLLOUT;

		if (poll(&pfd, 1, xtimeout) == -1) {
			if (errno == EAGAIN || errno == EINTR)
				continue;
			fatal("poll failed");
		}

		if (buffer_poll(&pfd, cctx->srv_in, cctx->srv_out) != 0)
			goto server_dead;
	}

out:
 	if (sigterm) {
 		printf("[terminated]\n");
 		return (1);
 	}

	if (cctx->flags & CCTX_SHUTDOWN) {
		printf("[server exited]\n");
		return (0);
	}

	if (cctx->flags & CCTX_EXIT) {
		printf("[exited]\n");
		return (0);
	}

	if (cctx->flags & CCTX_DETACH) {
		printf("[detached]\n");
		return (0);
	}

	printf("[error: %s]\n", error);
	return (1);

server_dead:
	printf("[lost server]\n");
	return (0);
}
Esempio n. 16
0
int
main(int argc, char **argv)
{
	struct client_ctx	 cctx;
	struct msg_command_data	 cmddata;
	struct buffer		*b;
	struct cmd_list		*cmdlist;
 	struct cmd		*cmd;
	struct pollfd	 	 pfd;
	struct hdr	 	 hdr;
	const char		*shell;
	struct passwd		*pw;
	char			*path, *label, *cause, *home, *pass = NULL;
	char			 cwd[MAXPATHLEN];
	int	 		 retcode, opt, flags, unlock, start_server;

	unlock = flags = 0;
	label = path = NULL;
        while ((opt = getopt(argc, argv, "28df:L:qS:uUVv")) != -1) {
                switch (opt) {
		case '2':
			flags |= IDENTIFY_256COLOURS;
			flags &= ~IDENTIFY_88COLOURS;
			break;
		case '8':
			flags |= IDENTIFY_88COLOURS;
			flags &= ~IDENTIFY_256COLOURS;
			break;
		case 'f':
			cfg_file = xstrdup(optarg);
			break;
		case 'L':
			if (path != NULL) {
				log_warnx("-L and -S cannot be used together");
				exit(1);
			}
			if (label != NULL)
				xfree(label);
			label = xstrdup(optarg);
			break;
		case 'S':
			if (label != NULL) {
				log_warnx("-L and -S cannot be used together");
				exit(1);
			}
			if (path != NULL)
				xfree(path);
			path = xstrdup(optarg);
			break;
		case 'q':
			be_quiet = 1;
			break;
		case 'u':
			flags |= IDENTIFY_UTF8;
			break;
		case 'U':
			unlock = 1;
			break;
		case 'd':
			flags |= IDENTIFY_HASDEFAULTS;
			break;
		case 'v':
			debug_level++;
			break;
		case 'V':
			printf("%s " BUILD "\n", __progname);
			exit(0);
                default:
			usage();
                }
        }
	argc -= optind;
	argv += optind;

	log_open_tty(debug_level);
	siginit();

	options_init(&global_options, NULL);
	options_set_number(&global_options, "bell-action", BELL_ANY);
	options_set_number(&global_options, "buffer-limit", 9);
	options_set_number(&global_options, "display-time", 750);
	options_set_number(&global_options, "history-limit", 2000);
	options_set_number(&global_options, "message-bg", 3);
	options_set_number(&global_options, "message-fg", 0);
	options_set_number(&global_options, "message-attr", GRID_ATTR_REVERSE);
	options_set_number(&global_options, "prefix", META);
	options_set_number(&global_options, "repeat-time", 500);
	options_set_number(&global_options, "set-titles", 1);
	options_set_number(&global_options, "lock-after-time", 0);
	options_set_number(&global_options, "set-remain-on-exit", 0);
	options_set_number(&global_options, "status", 1);
	options_set_number(&global_options, "status-bg", 2);
	options_set_number(&global_options, "status-fg", 0);
	options_set_number(&global_options, "status-attr", GRID_ATTR_REVERSE);
	options_set_number(&global_options, "status-interval", 15);
	options_set_number(&global_options, "status-left-length", 10);
	options_set_number(&global_options, "status-right-length", 40);
	options_set_string(&global_options, "status-left", "[#S]");
	options_set_string(
	    &global_options, "status-right", "\"#24T\" %%H:%%M %%d-%%b-%%y");
	options_set_number(&global_options, "status-keys", MODEKEY_EMACS);
	options_init(&global_window_options, NULL);
	options_set_number(&global_window_options, "aggressive-resize", 0);
	options_set_number(&global_window_options, "clock-mode-colour", 4);
	options_set_number(&global_window_options, "clock-mode-style", 1);
	options_set_number(&global_window_options, "force-height", 0);
	options_set_number(&global_window_options, "force-width", 0);
	options_set_number(&global_window_options, "automatic-rename", 1);
	options_set_number(&global_window_options, "mode-bg", 3);
	options_set_number(&global_window_options, "mode-fg", 0);
	options_set_number(
	    &global_window_options, "mode-attr", GRID_ATTR_REVERSE);
	options_set_number(&global_window_options, "mode-keys", MODEKEY_EMACS);
	options_set_number(&global_window_options, "monitor-activity", 0);
	options_set_number(&global_window_options, "utf8", 0);
	options_set_number(&global_window_options, "xterm-keys", 0);
 	options_set_number(&global_window_options, "remain-on-exit", 0);
	options_set_number(&global_window_options, "window-status-bg", 8);
	options_set_number(&global_window_options, "window-status-fg", 8);
	options_set_number(&global_window_options, "window-status-attr", 0);

	if (cfg_file == NULL) {
		home = getenv("HOME");
		if (home == NULL || *home == '\0') {
			pw = getpwuid(getuid());
			if (pw != NULL)
				home = pw->pw_dir;
			endpwent();
		}
		xasprintf(&cfg_file, "%s/%s", home, DEFAULT_CFG);
		if (access(cfg_file, R_OK) != 0) {
			xfree(cfg_file);
			cfg_file = NULL;
		}
	} else {
		if (access(cfg_file, R_OK) != 0) {
			log_warn("%s", cfg_file);
			exit(1);
		}
	}

	if (label == NULL)
		label = xstrdup("default");
	if (path == NULL && (path = makesockpath(label)) == NULL) {
		log_warn("can't create socket");
		exit(1);
	}
	xfree(label);

	shell = getenv("SHELL");
	if (shell == NULL || *shell == '\0') {
		pw = getpwuid(getuid());
		if (pw != NULL)
			shell = pw->pw_shell;
		endpwent();
		if (shell == NULL || *shell == '\0')
			shell = _PATH_BSHELL;
	}
	options_set_string(
	    &global_options, "default-command", "exec %s", shell);
	

	if (getcwd(cwd, sizeof cwd) == NULL) {
		log_warn("getcwd");
		exit(1);
	}
	options_set_string(&global_options, "default-path", "%s", cwd);

	if (unlock) {
		if (argc != 0) {
			log_warnx("can't specify a command when unlocking");
			exit(1);
		}
		cmdlist = NULL;
		if ((pass = getpass("Password: "******"%s", cause);
				exit(1);
			}
		}
		start_server = 0;
		TAILQ_FOREACH(cmd, cmdlist, qentry) {
			if (cmd->entry->flags & CMD_STARTSERVER) {
				start_server = 1;
				break;
			}
		}
	}
	
 	memset(&cctx, 0, sizeof cctx);
	if (client_init(path, &cctx, start_server, flags) != 0)
		exit(1);
	xfree(path);

	b = buffer_create(BUFSIZ);
	if (unlock) {
		cmd_send_string(b, pass);
		client_write_server(
		    &cctx, MSG_UNLOCK, BUFFER_OUT(b), BUFFER_USED(b));
	} else {
		cmd_list_send(cmdlist, b);
		cmd_list_free(cmdlist);
		client_fill_session(&cmddata);
		client_write_server2(&cctx, MSG_COMMAND,
		    &cmddata, sizeof cmddata, BUFFER_OUT(b), BUFFER_USED(b));
	}
	buffer_destroy(b);

	retcode = 0;
	for (;;) {
		pfd.fd = cctx.srv_fd;
		pfd.events = POLLIN;
		if (BUFFER_USED(cctx.srv_out) > 0)
			pfd.events |= POLLOUT;

		if (poll(&pfd, 1, INFTIM) == -1) {
			if (errno == EAGAIN || errno == EINTR)
				continue;
			fatal("poll failed");
		}

		if (buffer_poll(&pfd, cctx.srv_in, cctx.srv_out) != 0)
			goto out;

	restart:
		if (BUFFER_USED(cctx.srv_in) < sizeof hdr)
			continue;
		memcpy(&hdr, BUFFER_OUT(cctx.srv_in), sizeof hdr);
		if (BUFFER_USED(cctx.srv_in) < (sizeof hdr) + hdr.size)
			continue;
		buffer_remove(cctx.srv_in, sizeof hdr);

		switch (hdr.type) {
		case MSG_EXIT:
		case MSG_SHUTDOWN:
			goto out;
		case MSG_ERROR:
			retcode = 1;
			/* FALLTHROUGH */
		case MSG_PRINT:
			if (hdr.size > INT_MAX - 1)
				fatalx("bad MSG_PRINT size");
			log_info("%.*s",
			    (int) hdr.size, BUFFER_OUT(cctx.srv_in));
			if (hdr.size != 0)
				buffer_remove(cctx.srv_in, hdr.size);
			goto restart;
		case MSG_READY:
			retcode = client_main(&cctx);
			goto out;
		default:
			fatalx("unexpected command");
		}
	}

out:
	options_free(&global_options);
	options_free(&global_window_options);

	close(cctx.srv_fd);
	buffer_destroy(cctx.srv_in);
	buffer_destroy(cctx.srv_out);

#ifdef DEBUG
	xmalloc_report(getpid(), "client");
#endif
	return (retcode);
}
Esempio n. 17
0
File: io.c Progetto: mbeck-/fdm
/* Empty write buffer. */
int
io_push(struct io *io)
{
    ssize_t	n;
    int	error;

    /* If nothing to write, return. */
    if (BUFFER_USED(io->wr) == 0)
        return (1);

    /* Write as much as possible. */
    if (io->ssl == NULL) {
        n = write(io->fd, BUFFER_OUT(io->wr), BUFFER_USED(io->wr));
        IO_DEBUG(io, "write returned %zd (errno=%d)", n, errno);
        if (n == 0 || (n == -1 && errno == EPIPE))
            return (0);
        if (n == -1 && errno != EINTR && errno != EAGAIN) {
            if (io->error != NULL)
                xfree(io->error);
            xasprintf(&io->error, "io: write: %s", strerror(errno));
            return (-1);
        }
    } else {
        n = SSL_write(io->ssl, BUFFER_OUT(io->wr), BUFFER_USED(io->wr));
        IO_DEBUG(io, "SSL_write returned %zd", n);
        if (n == 0)
            return (0);
        if (n < 0) {
            switch (error = SSL_get_error(io->ssl, n)) {
            case SSL_ERROR_WANT_READ:
                io->flags |= IOF_NEEDPUSH;
                break;
            case SSL_ERROR_WANT_WRITE:
                /*
                 * A repeat is certain (buffer still has data)
                 * so this can be ignored
                 */
                break;
            case SSL_ERROR_SYSCALL:
                if (errno == EAGAIN || errno == EINTR)
                    break;
            /* FALLTHROUGH */
            default:
                if (io->error != NULL)
                    xfree(io->error);
                io->error = sslerror2(error, "SSL_write");
                return (-1);
            }
        }
    }

    /* Test for > 0 since SSL_write can return any -ve on error. */
    if (n > 0) {
        IO_DEBUG(io, "wrote %zd bytes", n);

        /* Copy out the duplicate fd. */
        if (io->dup_fd != -1) {
            write(io->dup_fd, "> ", 2);
            write(io->dup_fd, BUFFER_OUT(io->wr), n);
        }

        /* Adjust the buffer size. */
        buffer_remove(io->wr, n);

        /* Reset the need flags. */
        io->flags &= ~IOF_NEEDPUSH;
    }

    return (1);
}