=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/tmux/server.c,v retrieving revision 1.59 retrieving revision 1.60 diff -u -r1.59 -r1.60 --- src/usr.bin/tmux/server.c 2009/10/13 06:14:08 1.59 +++ src/usr.bin/tmux/server.c 2009/10/22 19:41:51 1.60 @@ -1,4 +1,4 @@ -/* $OpenBSD: server.c,v 1.59 2009/10/13 06:14:08 nicm Exp $ */ +/* $OpenBSD: server.c,v 1.60 2009/10/22 19:41:51 nicm Exp $ */ /* * Copyright (c) 2007 Nicholas Marriott @@ -47,80 +47,70 @@ /* Mapping of a pollfd to an fd independent of its position in the array. */ struct poll_item { - struct pollfd pfd; + int fd; + int events; + void (*fn)(int, int, void *); + void *data; + RB_ENTRY(poll_item) entry; }; RB_HEAD(poll_items, poll_item) poll_items; int server_poll_cmp(struct poll_item *, struct poll_item *); -struct pollfd *server_poll_lookup(int); -void server_poll_add(int, int); +struct poll_item*server_poll_lookup(int); +void server_poll_add(int, int, void (*)(int, int, void *), void *); struct pollfd *server_poll_flatten(int *); -void server_poll_parse(struct pollfd *); +void server_poll_dispatch(struct pollfd *, int); void server_poll_reset(void); RB_PROTOTYPE(poll_items, poll_item, entry, server_poll_cmp); RB_GENERATE(poll_items, poll_item, entry, server_poll_cmp); -void server_create_client(int); int server_create_socket(void); +void server_callback(int, int, void *); int server_main(int); void server_shutdown(void); int server_should_shutdown(void); void server_child_signal(void); void server_fill_windows(void); -void server_handle_windows(void); void server_fill_clients(void); -void server_handle_clients(void); void server_fill_jobs(void); -void server_handle_jobs(void); -void server_accept_client(int); -void server_handle_client(struct client *); -void server_handle_window(struct window *, struct window_pane *); -int server_check_window_bell(struct session *, struct window *); -int server_check_window_activity(struct session *, - struct window *); -int server_check_window_content(struct session *, struct window *, - struct window_pane *); void server_clean_dead(void); -void server_lost_client(struct client *); -void server_check_window(struct window *); -void server_check_redraw(struct client *); -void server_set_title(struct client *); -void server_check_timers(struct client *); -void server_check_jobs(void); +void server_second_timers(void); void server_lock_server(void); void server_lock_sessions(void); -void server_check_clients(void); -void server_second_timers(void); int server_update_socket(void); int server_poll_cmp(struct poll_item *pitem1, struct poll_item *pitem2) { - return (pitem1->pfd.fd - pitem2->pfd.fd); + return (pitem1->fd - pitem2->fd); } -struct pollfd * -server_poll_lookup(int fd) -{ - struct poll_item pitem; - - pitem.pfd.fd = fd; - return (&RB_FIND(poll_items, &poll_items, &pitem)->pfd); -} - void -server_poll_add(int fd, int events) +server_poll_add(int fd, int events, void (*fn)(int, int, void *), void *data) { struct poll_item *pitem; pitem = xmalloc(sizeof *pitem); - pitem->pfd.fd = fd; - pitem->pfd.events = events; + pitem->fd = fd; + pitem->events = events; + + pitem->fn = fn; + pitem->data = data; + RB_INSERT(poll_items, &poll_items, pitem); } +struct poll_item * +server_poll_lookup(int fd) +{ + struct poll_item pitem; + + pitem.fd = fd; + return (RB_FIND(poll_items, &poll_items, &pitem)); +} + struct pollfd * server_poll_flatten(int *nfds) { @@ -131,23 +121,25 @@ *nfds = 0; RB_FOREACH(pitem, poll_items, &poll_items) { pfds = xrealloc(pfds, (*nfds) + 1, sizeof *pfds); - pfds[*nfds].fd = pitem->pfd.fd; - pfds[*nfds].events = pitem->pfd.events; + pfds[*nfds].fd = pitem->fd; + pfds[*nfds].events = pitem->events; (*nfds)++; } return (pfds); } void -server_poll_parse(struct pollfd *pfds) +server_poll_dispatch(struct pollfd *pfds, int nfds) { struct poll_item *pitem; - int nfds; + struct pollfd *pfd; - nfds = 0; - RB_FOREACH(pitem, poll_items, &poll_items) { - pitem->pfd.revents = pfds[nfds].revents; - nfds++; + while (nfds > 0) { + pfd = &pfds[--nfds]; + if (pfd->revents != 0) { + pitem = server_poll_lookup(pfd->fd); + pitem->fn(pitem->fd, pfd->revents, pitem->data); + } } xfree(pfds); } @@ -164,14 +156,35 @@ } } -/* Create a new client. */ -void -server_create_client(int fd) +/* Create server socket. */ +int +server_create_socket(void) { - struct client *c; - int mode; - u_int i; + struct sockaddr_un sa; + size_t size; + mode_t mask; + int fd, mode; + memset(&sa, 0, sizeof sa); + sa.sun_family = AF_UNIX; + size = strlcpy(sa.sun_path, socket_path, sizeof sa.sun_path); + if (size >= sizeof sa.sun_path) { + errno = ENAMETOOLONG; + fatal("socket failed"); + } + unlink(sa.sun_path); + + if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) + fatal("socket failed"); + + mask = umask(S_IXUSR|S_IRWXG|S_IRWXO); + if (bind(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) + fatal("bind failed"); + umask(mask); + + if (listen(fd, 16) == -1) + fatal("listen failed"); + if ((mode = fcntl(fd, F_GETFL)) == -1) fatal("fcntl failed"); if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1) @@ -179,39 +192,33 @@ if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) fatal("fcntl failed"); - c = xcalloc(1, sizeof *c); - c->references = 0; - imsg_init(&c->ibuf, fd); - - if (gettimeofday(&c->tv, NULL) != 0) - fatal("gettimeofday failed"); + return (fd); +} - ARRAY_INIT(&c->prompt_hdata); +/* Callback for server socket. */ +void +server_callback(int fd, int events, unused void *data) +{ + struct sockaddr_storage sa; + socklen_t slen = sizeof sa; + int newfd; - c->tty.fd = -1; - c->title = NULL; + if (events & (POLLERR|POLLNVAL|POLLHUP)) + fatalx("lost server socket"); + if (!(events & POLLIN)) + return; - c->session = NULL; - c->tty.sx = 80; - c->tty.sy = 24; - - screen_init(&c->status, c->tty.sx, 1, 0); - job_tree_init(&c->status_jobs); - - c->message_string = NULL; - - c->prompt_string = NULL; - c->prompt_buffer = NULL; - c->prompt_index = 0; - - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - if (ARRAY_ITEM(&clients, i) == NULL) { - ARRAY_SET(&clients, i, c); + newfd = accept(fd, (struct sockaddr *) &sa, &slen); + if (newfd == -1) { + if (errno == EAGAIN || errno == EINTR || errno == ECONNABORTED) return; - } + fatal("accept failed"); } - ARRAY_ADD(&clients, c); - log_debug("new client %d", fd); + if (sigterm) { + close(newfd); + return; + } + server_client_create(newfd); } /* Fork new server. */ @@ -267,7 +274,7 @@ setproctitle("server (%s)", rpathbuf); srv_fd = server_create_socket(); - server_create_client(pair[1]); + server_client_create(pair[1]); if (access(SYSTEM_CFG, R_OK) != 0) { if (errno != ENOENT) { @@ -295,50 +302,11 @@ exit(server_main(srv_fd)); } -/* Create server socket. */ -int -server_create_socket(void) -{ - struct sockaddr_un sa; - size_t size; - mode_t mask; - int fd, mode; - - memset(&sa, 0, sizeof sa); - sa.sun_family = AF_UNIX; - size = strlcpy(sa.sun_path, socket_path, sizeof sa.sun_path); - if (size >= sizeof sa.sun_path) { - errno = ENAMETOOLONG; - fatal("socket failed"); - } - unlink(sa.sun_path); - - if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) - fatal("socket failed"); - - mask = umask(S_IXUSR|S_IRWXG|S_IRWXO); - if (bind(fd, (struct sockaddr *) &sa, SUN_LEN(&sa)) == -1) - fatal("bind failed"); - umask(mask); - - if (listen(fd, 16) == -1) - fatal("listen failed"); - - if ((mode = fcntl(fd, F_GETFL)) == -1) - fatal("fcntl failed"); - if (fcntl(fd, F_SETFL, mode|O_NONBLOCK) == -1) - fatal("fcntl failed"); - if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) - fatal("fcntl failed"); - - return (fd); -} - /* Main server loop. */ int server_main(int srv_fd) { - struct pollfd *pfds, *pfd; + struct pollfd *pfds; int nfds, xtimeout; u_int i; time_t now, last; @@ -371,13 +339,9 @@ sigusr1 = 0; } - /* Collect any jobs that have died and process clients. */ - server_check_jobs(); - server_check_clients(); - /* Initialise pollfd array and add server socket. */ server_poll_reset(); - server_poll_add(srv_fd, POLLIN); + server_poll_add(srv_fd, POLLIN, server_callback, NULL); /* Fill window and client sockets. */ server_fill_jobs(); @@ -396,17 +360,8 @@ continue; fatal("poll failed"); } - server_poll_parse(pfds); + server_poll_dispatch(pfds, nfds); - /* Handle server socket. */ - pfd = server_poll_lookup(srv_fd); - if (pfd->revents & (POLLERR|POLLNVAL|POLLHUP)) - fatalx("lost server socket"); - if (pfd->revents & POLLIN) { - server_accept_client(srv_fd); - continue; - } - /* Call second-based timers. */ now = time(NULL); if (now != last) { @@ -414,14 +369,11 @@ server_second_timers(); } - /* Set window names. */ - set_window_names(); + /* Run once-per-loop events. */ + server_job_loop(); + server_window_loop(); + server_client_loop(); - /* Handle window and client sockets. */ - server_handle_jobs(); - server_handle_windows(); - server_handle_clients(); - /* Collect any unset key bindings. */ key_bindings_clean(); @@ -438,7 +390,7 @@ for (i = 0; i < ARRAY_LENGTH(&clients); i++) { if (ARRAY_ITEM(&clients, i) != NULL) - server_lost_client(ARRAY_ITEM(&clients, i)); + server_client_lost(ARRAY_ITEM(&clients, i)); } ARRAY_FREE(&clients); @@ -468,7 +420,7 @@ c = ARRAY_ITEM(&clients, i); if (c != NULL) { if (c->flags & (CLIENT_BAD|CLIENT_SUSPENDED)) - server_lost_client(c); + server_client_lost(c); else server_write_client(c, MSG_SHUTDOWN, NULL, 0); } @@ -571,195 +523,20 @@ events = POLLIN; if (BUFFER_USED(wp->out) > 0) events |= POLLOUT; - server_poll_add(wp->fd, events); + server_poll_add( + wp->fd, events, server_window_callback, wp); if (wp->pipe_fd == -1) continue; events = 0; if (BUFFER_USED(wp->pipe_buf) > 0) events |= POLLOUT; - server_poll_add(wp->pipe_fd, events); + server_poll_add( + wp->pipe_fd, events, server_window_callback, wp); } } } -/* Handle window pollfds. */ -void -server_handle_windows(void) -{ - struct window *w; - struct window_pane *wp; - struct pollfd *pfd; - u_int i; - - for (i = 0; i < ARRAY_LENGTH(&windows); i++) { - w = ARRAY_ITEM(&windows, i); - if (w == NULL) - continue; - - TAILQ_FOREACH(wp, &w->panes, entry) { - if (wp->fd == -1) - continue; - if ((pfd = server_poll_lookup(wp->fd)) == NULL) - continue; - if (buffer_poll(pfd, wp->in, wp->out) != 0) { - close(wp->fd); - wp->fd = -1; - } else - server_handle_window(w, wp); - - if (wp->pipe_fd == -1) - continue; - if ((pfd = server_poll_lookup(wp->pipe_fd)) == NULL) - continue; - if (buffer_poll(pfd, NULL, wp->pipe_buf) != 0) { - buffer_destroy(wp->pipe_buf); - close(wp->pipe_fd); - wp->pipe_fd = -1; - } - } - - server_check_window(w); - } -} - -/* Check clients for redraw and timers. */ -void -server_check_clients(void) -{ - struct client *c; - struct window *w; - struct window_pane *wp; - u_int i; - - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c == NULL || c->session == NULL) - continue; - - server_check_timers(c); - server_check_redraw(c); - } - - /* - * Clear any window redraw flags (will have been redrawn as part of - * client). - */ - for (i = 0; i < ARRAY_LENGTH(&windows); i++) { - w = ARRAY_ITEM(&windows, i); - if (w == NULL) - continue; - - w->flags &= ~WINDOW_REDRAW; - TAILQ_FOREACH(wp, &w->panes, entry) - wp->flags &= ~PANE_REDRAW; - } -} - -/* Check for general redraw on client. */ -void -server_check_redraw(struct client *c) -{ - struct session *s = c->session; - struct window_pane *wp; - int flags, redraw; - - flags = c->tty.flags & TTY_FREEZE; - c->tty.flags &= ~TTY_FREEZE; - - if (c->flags & (CLIENT_REDRAW|CLIENT_STATUS)) { - if (options_get_number(&s->options, "set-titles")) - server_set_title(c); - - if (c->message_string != NULL) - redraw = status_message_redraw(c); - else if (c->prompt_string != NULL) - redraw = status_prompt_redraw(c); - else - redraw = status_redraw(c); - if (!redraw) - c->flags &= ~CLIENT_STATUS; - } - - if (c->flags & CLIENT_REDRAW) { - screen_redraw_screen(c, 0); - c->flags &= ~CLIENT_STATUS; - } else { - TAILQ_FOREACH(wp, &c->session->curw->window->panes, entry) { - if (wp->flags & PANE_REDRAW) - screen_redraw_pane(c, wp); - } - } - - if (c->flags & CLIENT_STATUS) - screen_redraw_screen(c, 1); - - c->tty.flags |= flags; - - c->flags &= ~(CLIENT_REDRAW|CLIENT_STATUS); -} - -/* Set client title. */ -void -server_set_title(struct client *c) -{ - struct session *s = c->session; - const char *template; - char *title; - - template = options_get_string(&s->options, "set-titles-string"); - - title = status_replace(c, template, time(NULL)); - if (c->title == NULL || strcmp(title, c->title) != 0) { - if (c->title != NULL) - xfree(c->title); - c->title = xstrdup(title); - tty_set_title(&c->tty, c->title); - } - xfree(title); -} - -/* Check for timers on client. */ -void -server_check_timers(struct client *c) -{ - struct session *s = c->session; - struct job *job; - struct timeval tv; - u_int interval; - - if (gettimeofday(&tv, NULL) != 0) - fatal("gettimeofday failed"); - - if (c->flags & CLIENT_IDENTIFY && timercmp(&tv, &c->identify_timer, >)) - server_clear_identify(c); - - if (c->message_string != NULL && timercmp(&tv, &c->message_timer, >)) - status_message_clear(c); - - if (c->message_string != NULL || c->prompt_string != NULL) { - /* - * Don't need timed redraw for messages/prompts so bail now. - * The status timer isn't reset when they are redrawn anyway. - */ - return; - } - if (!options_get_number(&s->options, "status")) - return; - - /* Check timer; resolution is only a second so don't be too clever. */ - interval = options_get_number(&s->options, "status-interval"); - if (interval == 0) - return; - if (tv.tv_sec < c->status_timer.tv_sec || - ((u_int) tv.tv_sec) - c->status_timer.tv_sec >= interval) { - /* Run the jobs for this client and schedule for redraw. */ - RB_FOREACH(job, jobs, &c->status_jobs) - job_run(job); - c->flags |= CLIENT_STATUS; - } -} - /* Fill client pollfds. */ void server_fill_clients(void) @@ -777,7 +554,8 @@ events |= POLLIN; if (c->ibuf.w.queued > 0) events |= POLLOUT; - server_poll_add(c->ibuf.fd, events); + server_poll_add( + c->ibuf.fd, events, server_client_callback, c); } if (c != NULL && !(c->flags & CLIENT_SUSPENDED) && @@ -785,7 +563,8 @@ events = POLLIN; if (BUFFER_USED(c->tty.out) > 0) events |= POLLOUT; - server_poll_add(c->tty.fd, events); + server_poll_add( + c->tty.fd, events, server_client_callback, c); } } } @@ -799,328 +578,10 @@ SLIST_FOREACH(job, &all_jobs, lentry) { if (job->fd == -1) continue; - server_poll_add(job->fd, POLLIN); + server_poll_add(job->fd, POLLIN, server_job_callback, job); } } -/* Handle job fds. */ -void -server_handle_jobs(void) -{ - struct job *job; - struct pollfd *pfd; - - SLIST_FOREACH(job, &all_jobs, lentry) { - if (job->fd == -1) - continue; - if ((pfd = server_poll_lookup(job->fd)) == NULL) - continue; - if (buffer_poll(pfd, job->out, NULL) != 0) { - close(job->fd); - job->fd = -1; - } - } -} - -/* Handle job fds. */ -void -server_check_jobs(void) -{ - struct job *job; - -restart: - SLIST_FOREACH(job, &all_jobs, lentry) { - if (job->flags & JOB_DONE || job->fd != -1 || job->pid != -1) - continue; - job->flags |= JOB_DONE; - - if (job->callbackfn != NULL) { - job->callbackfn(job); - goto restart; /* could be freed by callback */ - } - } -} - -/* Handle client pollfds. */ -void -server_handle_clients(void) -{ - struct client *c; - struct pollfd *pfd; - u_int i; - - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - - if (c != NULL) { - if ((pfd = server_poll_lookup(c->ibuf.fd)) == NULL) - continue; - if (pfd->revents & (POLLERR|POLLNVAL|POLLHUP)) { - server_lost_client(c); - continue; - } - - if (pfd->revents & POLLOUT) { - if (msgbuf_write(&c->ibuf.w) < 0) { - server_lost_client(c); - continue; - } - } - - if (c->flags & CLIENT_BAD) { - if (c->ibuf.w.queued == 0) - server_lost_client(c); - continue; - } else if (pfd->revents & POLLIN) { - if (server_msg_dispatch(c) != 0) { - server_lost_client(c); - continue; - } - } - } - - if (c != NULL && !(c->flags & CLIENT_SUSPENDED) && - c->tty.fd != -1 && c->session != NULL) { - if ((pfd = server_poll_lookup(c->tty.fd)) == NULL) - continue; - if (buffer_poll(pfd, c->tty.in, c->tty.out) != 0) - server_lost_client(c); - else - server_handle_client(c); - } - } -} - -/* accept(2) and create new client. */ -void -server_accept_client(int srv_fd) -{ - struct sockaddr_storage sa; - socklen_t slen = sizeof sa; - int fd; - - fd = accept(srv_fd, (struct sockaddr *) &sa, &slen); - if (fd == -1) { - if (errno == EAGAIN || errno == EINTR || errno == ECONNABORTED) - return; - fatal("accept failed"); - } - if (sigterm) { - close(fd); - return; - } - server_create_client(fd); -} - -/* Input data from client. */ -void -server_handle_client(struct client *c) -{ - struct window *w; - struct window_pane *wp; - struct screen *s; - struct options *oo; - struct timeval tv; - struct key_binding *bd; - struct keylist *keylist; - struct mouse_event mouse; - int key, status, xtimeout, mode, isprefix; - u_int i; - - xtimeout = options_get_number(&c->session->options, "repeat-time"); - if (xtimeout != 0 && c->flags & CLIENT_REPEAT) { - if (gettimeofday(&tv, NULL) != 0) - fatal("gettimeofday failed"); - if (timercmp(&tv, &c->repeat_timer, >)) - c->flags &= ~(CLIENT_PREFIX|CLIENT_REPEAT); - } - - /* Process keys. */ - keylist = options_get_data(&c->session->options, "prefix"); - while (tty_keys_next(&c->tty, &key, &mouse) == 0) { - if (c->session == NULL) - return; - - c->session->activity = time(NULL); - w = c->session->curw->window; - wp = w->active; /* could die */ - oo = &c->session->options; - - /* Special case: number keys jump to pane in identify mode. */ - if (c->flags & CLIENT_IDENTIFY && key >= '0' && key <= '9') { - wp = window_pane_at_index(w, key - '0'); - if (wp != NULL && window_pane_visible(wp)) - window_set_active_pane(w, wp); - server_clear_identify(c); - continue; - } - - status_message_clear(c); - server_clear_identify(c); - if (c->prompt_string != NULL) { - status_prompt_key(c, key); - continue; - } - - /* Check for mouse keys. */ - if (key == KEYC_MOUSE) { - if (options_get_number(oo, "mouse-select-pane")) { - window_set_active_at(w, mouse.x, mouse.y); - wp = w->active; - } - window_pane_mouse(wp, c, &mouse); - continue; - } - - /* Is this a prefix key? */ - isprefix = 0; - for (i = 0; i < ARRAY_LENGTH(keylist); i++) { - if (key == ARRAY_ITEM(keylist, i)) { - isprefix = 1; - break; - } - } - - /* No previous prefix key. */ - if (!(c->flags & CLIENT_PREFIX)) { - if (isprefix) - c->flags |= CLIENT_PREFIX; - else { - /* Try as a non-prefix key binding. */ - if ((bd = key_bindings_lookup(key)) == NULL) - window_pane_key(wp, c, key); - else - key_bindings_dispatch(bd, c); - } - continue; - } - - /* Prefix key already pressed. Reset prefix and lookup key. */ - c->flags &= ~CLIENT_PREFIX; - if ((bd = key_bindings_lookup(key | KEYC_PREFIX)) == NULL) { - /* If repeating, treat this as a key, else ignore. */ - if (c->flags & CLIENT_REPEAT) { - c->flags &= ~CLIENT_REPEAT; - if (isprefix) - c->flags |= CLIENT_PREFIX; - else - window_pane_key(wp, c, key); - } - continue; - } - - /* If already repeating, but this key can't repeat, skip it. */ - if (c->flags & CLIENT_REPEAT && !bd->can_repeat) { - c->flags &= ~CLIENT_REPEAT; - if (isprefix) - c->flags |= CLIENT_PREFIX; - else - window_pane_key(wp, c, key); - continue; - } - - /* If this key can repeat, reset the repeat flags and timer. */ - if (xtimeout != 0 && bd->can_repeat) { - c->flags |= CLIENT_PREFIX|CLIENT_REPEAT; - - tv.tv_sec = xtimeout / 1000; - tv.tv_usec = (xtimeout % 1000) * 1000L; - if (gettimeofday(&c->repeat_timer, NULL) != 0) - fatal("gettimeofday failed"); - timeradd(&c->repeat_timer, &tv, &c->repeat_timer); - } - - /* Dispatch the command. */ - key_bindings_dispatch(bd, c); - } - if (c->session == NULL) - return; - w = c->session->curw->window; - wp = w->active; - oo = &c->session->options; - s = wp->screen; - - /* - * Update cursor position and mode settings. The scroll region and - * attributes are cleared across poll(2) as this is the most likely - * time a user may interrupt tmux, for example with ~^Z in ssh(1). This - * is a compromise between excessive resets and likelihood of an - * interrupt. - * - * tty_region/tty_reset/tty_update_mode already take care of not - * resetting things that are already in their default state. - */ - tty_region(&c->tty, 0, c->tty.sy - 1); - - status = options_get_number(oo, "status"); - if (!window_pane_visible(wp) || wp->yoff + s->cy >= c->tty.sy - status) - tty_cursor(&c->tty, 0, 0); - else - tty_cursor(&c->tty, wp->xoff + s->cx, wp->yoff + s->cy); - - mode = s->mode; - if (TAILQ_NEXT(TAILQ_FIRST(&w->panes), entry) != NULL && - options_get_number(oo, "mouse-select-pane")) - mode |= MODE_MOUSE; - tty_update_mode(&c->tty, mode); - tty_reset(&c->tty); -} - -/* Lost a client. */ -void -server_lost_client(struct client *c) -{ - u_int i; - - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - if (ARRAY_ITEM(&clients, i) == c) - ARRAY_SET(&clients, i, NULL); - } - log_debug("lost client %d", c->ibuf.fd); - - /* - * If CLIENT_TERMINAL hasn't been set, then tty_init hasn't been called - * and tty_free might close an unrelated fd. - */ - if (c->flags & CLIENT_TERMINAL) - tty_free(&c->tty); - - screen_free(&c->status); - job_tree_free(&c->status_jobs); - - if (c->title != NULL) - xfree(c->title); - - if (c->message_string != NULL) - xfree(c->message_string); - - if (c->prompt_string != NULL) - xfree(c->prompt_string); - if (c->prompt_buffer != NULL) - xfree(c->prompt_buffer); - for (i = 0; i < ARRAY_LENGTH(&c->prompt_hdata); i++) - xfree(ARRAY_ITEM(&c->prompt_hdata, i)); - ARRAY_FREE(&c->prompt_hdata); - - if (c->cwd != NULL) - xfree(c->cwd); - - close(c->ibuf.fd); - imsg_clear(&c->ibuf); - - for (i = 0; i < ARRAY_LENGTH(&dead_clients); i++) { - if (ARRAY_ITEM(&dead_clients, i) == NULL) { - ARRAY_SET(&dead_clients, i, c); - break; - } - } - if (i == ARRAY_LENGTH(&dead_clients)) - ARRAY_ADD(&dead_clients, c); - c->flags |= CLIENT_DEAD; - - recalculate_sizes(); -} - /* Free dead, unreferenced clients and sessions. */ void server_clean_dead(void) @@ -1146,221 +607,29 @@ } } -/* Handle window data. */ +/* Call any once-per-second timers. */ void -server_handle_window(struct window *w, struct window_pane *wp) +server_second_timers(void) { - struct session *s; - u_int i; - int update; - - window_pane_parse(wp); - - if ((w->flags & (WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_CONTENT)) == 0) - return; - - update = 0; - for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { - s = ARRAY_ITEM(&sessions, i); - if (s == NULL || !session_has(s, w)) - continue; - - update += server_check_window_bell(s, w); - update += server_check_window_activity(s, w); - update += server_check_window_content(s, w, wp); - } - if (update) - server_status_window(w); - - w->flags &= ~(WINDOW_BELL|WINDOW_ACTIVITY|WINDOW_CONTENT); -} - -int -server_check_window_bell(struct session *s, struct window *w) -{ - struct client *c; - u_int i; - int action, visual; - - if (!(w->flags & WINDOW_BELL)) - return (0); - if (session_alert_has_window(s, w, WINDOW_BELL)) - return (0); - session_alert_add(s, w, WINDOW_BELL); - - action = options_get_number(&s->options, "bell-action"); - switch (action) { - case BELL_ANY: - if (s->flags & SESSION_UNATTACHED) - break; - visual = options_get_number(&s->options, "visual-bell"); - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c == NULL || c->session != s) - continue; - if (!visual) { - tty_putcode(&c->tty, TTYC_BEL); - continue; - } - if (c->session->curw->window == w) { - status_message_set(c, "Bell in current window"); - continue; - } - status_message_set(c, "Bell in window %u", - winlink_find_by_window(&s->windows, w)->idx); - } - break; - case BELL_CURRENT: - if (s->flags & SESSION_UNATTACHED) - break; - visual = options_get_number(&s->options, "visual-bell"); - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c == NULL || c->session != s) - continue; - if (c->session->curw->window != w) - continue; - if (!visual) { - tty_putcode(&c->tty, TTYC_BEL); - continue; - } - status_message_set(c, "Bell in current window"); - } - break; - } - return (1); -} - -int -server_check_window_activity(struct session *s, struct window *w) -{ - struct client *c; - u_int i; - - if (!(w->flags & WINDOW_ACTIVITY)) - return (0); - - if (!options_get_number(&w->options, "monitor-activity")) - return (0); - - if (session_alert_has_window(s, w, WINDOW_ACTIVITY)) - return (0); - if (s->curw->window == w) - return (0); - - session_alert_add(s, w, WINDOW_ACTIVITY); - if (s->flags & SESSION_UNATTACHED) - return (0); - if (options_get_number(&s->options, "visual-activity")) { - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c == NULL || c->session != s) - continue; - status_message_set(c, "Activity in window %u", - winlink_find_by_window(&s->windows, w)->idx); - } - } - - return (1); -} - -int -server_check_window_content( - struct session *s, struct window *w, struct window_pane *wp) -{ - struct client *c; - u_int i; - char *found, *ptr; - - if (!(w->flags & WINDOW_ACTIVITY)) /* activity for new content */ - return (0); - - ptr = options_get_string(&w->options, "monitor-content"); - if (ptr == NULL || *ptr == '\0') - return (0); - - if (session_alert_has_window(s, w, WINDOW_CONTENT)) - return (0); - if (s->curw->window == w) - return (0); - - if ((found = window_pane_search(wp, ptr, NULL)) == NULL) - return (0); - xfree(found); - - session_alert_add(s, w, WINDOW_CONTENT); - if (s->flags & SESSION_UNATTACHED) - return (0); - if (options_get_number(&s->options, "visual-content")) { - for (i = 0; i < ARRAY_LENGTH(&clients); i++) { - c = ARRAY_ITEM(&clients, i); - if (c == NULL || c->session != s) - continue; - status_message_set(c, "Content in window %u", - winlink_find_by_window(&s->windows, w)->idx); - } - } - - return (1); -} - -/* Check if window still exists. */ -void -server_check_window(struct window *w) -{ - struct window_pane *wp, *wq; - struct options *oo = &w->options; - struct session *s; - struct winlink *wl; + struct window *w; + struct window_pane *wp; u_int i; - int destroyed; - destroyed = 1; + if (options_get_number(&global_s_options, "lock-server")) + server_lock_server(); + else + server_lock_sessions(); - wp = TAILQ_FIRST(&w->panes); - while (wp != NULL) { - wq = TAILQ_NEXT(wp, entry); - /* - * If the pane has died and the remain-on-exit flag is not set, - * remove the pane; otherwise, if the flag is set, don't allow - * the window to be destroyed (or it'll close when the last - * pane dies). - */ - if (wp->fd == -1 && !options_get_number(oo, "remain-on-exit")) { - layout_close_pane(wp); - window_remove_pane(w, wp); - server_redraw_window(w); - } else - destroyed = 0; - wp = wq; - } - - if (!destroyed) - return; - - for (i = 0; i < ARRAY_LENGTH(&sessions); i++) { - s = ARRAY_ITEM(&sessions, i); - if (s == NULL) + for (i = 0; i < ARRAY_LENGTH(&windows); i++) { + w = ARRAY_ITEM(&windows, i); + if (w == NULL) continue; - if (!session_has(s, w)) - continue; - restart: - /* Detach window and either redraw or kill clients. */ - RB_FOREACH(wl, winlinks, &s->windows) { - if (wl->window != w) - continue; - if (session_detach(s, wl)) { - server_destroy_session_group(s); - break; - } - server_redraw_session(s); - server_status_session_group(s); - goto restart; + TAILQ_FOREACH(wp, &w->panes, entry) { + if (wp->mode != NULL && wp->mode->timer != NULL) + wp->mode->timer(wp); } } - - recalculate_sizes(); } /* Lock the server if ALL sessions have hit the time limit. */ @@ -1414,31 +683,6 @@ if (timeout > 0 && t > s->activity + timeout) { server_lock_session(s); recalculate_sizes(); - } - } -} - -/* Call any once-per-second timers. */ -void -server_second_timers(void) -{ - struct window *w; - struct window_pane *wp; - u_int i; - - if (options_get_number(&global_s_options, "lock-server")) - server_lock_server(); - else - server_lock_sessions(); - - for (i = 0; i < ARRAY_LENGTH(&windows); i++) { - w = ARRAY_ITEM(&windows, i); - if (w == NULL) - continue; - - TAILQ_FOREACH(wp, &w->panes, entry) { - if (wp->mode != NULL && wp->mode->timer != NULL) - wp->mode->timer(wp); } } }