int32_t server_do(server_p srv) { fd_set fdset; int32_t n, fd; assert(srv != NULL); /* Copy cached version of the fd set and call select */ memcpy(&fdset, &srv->fdset, sizeof(fdset)); n = select(srv->maxfd + 1, &fdset, NULL, NULL, NULL); if (n < 0) { if (errno == EINTR) return (0); log_err("Could not select(%d, %p). %s (%d)", srv->maxfd + 1, &fdset, strerror(errno), errno); return (-1); } /* Process descriptors */ for (fd = 0; fd < srv->maxfd + 1 && n > 0; fd ++) { if (!FD_ISSET(fd, &fdset)) continue; assert(srv->fdidx[fd].valid); n --; if (srv->fdidx[fd].server) server_accept_client(srv, fd); else if (server_process_request(srv, fd) != 0) server_close_fd(srv, fd); } return (0); }
/* * Do one server iteration */ bool server_do(server_t *srv) { fd_set fdset; int n, fd; assert(srv != NULL); memcpy(&fdset, &srv->fdset, sizeof(fdset)); n = select(srv->fdmax + 1, &fdset, NULL, NULL, NULL); if (n == -1) { if (errno == EINTR) return true; log_err("Could not select(%d, %p). %s (%d)", srv->fdmax + 1, &fdset, strerror(errno), errno); return false; } for (fd = 0; fd < srv->fdmax + 1 && n > 0; fd++) { if (!FD_ISSET(fd, &fdset)) continue; assert(srv->fdidx[fd].valid); if (srv->fdidx[fd].server) server_accept_client(srv, fd); else if (!server_process_request(srv, fd)) server_close_fd(srv, fd); n--; } return true; }
static void server_mainloop(void) { atexit(server_atexit_handler); fd_set new_readfds, new_writefds; FD_ZERO(&new_readfds); FD_ZERO(&new_writefds); FD_SET(server.socket, &new_readfds); int new_fdmax = server.socket; bool exit_packet_delivered = false; if (server.read_pty) FD_SET_MAX(server.pty, &new_readfds, new_fdmax); while (server.clients || !exit_packet_delivered) { int fdmax = new_fdmax; fd_set readfds = new_readfds; fd_set writefds = new_writefds; FD_SET_MAX(server.socket, &readfds, fdmax); if (select(fdmax+1, &readfds, &writefds, NULL, NULL) == -1) { if (errno == EINTR) continue; die("server-mainloop"); } FD_ZERO(&new_readfds); FD_ZERO(&new_writefds); new_fdmax = server.socket; bool pty_data = false; Packet server_packet, client_packet; if (FD_ISSET(server.socket, &readfds)) server_accept_client(); if (FD_ISSET(server.pty, &readfds)) pty_data = server_read_pty(&server_packet); for (Client **prev_next = &server.clients, *c = server.clients; c;) { if (FD_ISSET(c->socket, &readfds) && server_recv_packet(c, &client_packet)) { switch (client_packet.type) { case MSG_CONTENT: server_write_pty(&client_packet); break; case MSG_ATTACH: c->flags = client_packet.u.i; if (c->flags & CLIENT_LOWPRIORITY) server_sink_client(); break; case MSG_RESIZE: c->state = STATE_ATTACHED; case MSG_REDRAW: if (!(c->flags & CLIENT_READONLY) && (client_packet.type == MSG_REDRAW || c == server.clients)) { debug("server-ioct: TIOCSWINSZ\n"); ioctl(server.pty, TIOCSWINSZ, &client_packet.u.ws); } kill(-server.pid, SIGWINCH); break; case MSG_EXIT: exit_packet_delivered = true; /* fall through */ case MSG_DETACH: c->state = STATE_DISCONNECTED; break; default: /* ignore package */ break; } } if (c->state == STATE_DISCONNECTED) { bool first = (c == server.clients); Client *t = c->next; client_free(c); *prev_next = c = t; if (first && server.clients) { Packet pkt = { .type = MSG_RESIZE, .len = 0, }; server_send_packet(server.clients, &pkt); } else if (!server.clients) { server_mark_socket_exec(false, true); } continue; } FD_SET_MAX(c->socket, &new_readfds, new_fdmax); if (pty_data) server_send_packet(c, &server_packet); if (!server.running) { if (server.exit_status != -1) { Packet pkt = { .type = MSG_EXIT, .u.i = server.exit_status, .len = sizeof(pkt.u.i), }; if (!server_send_packet(c, &pkt)) FD_SET_MAX(c->socket, &new_writefds, new_fdmax); } else { FD_SET_MAX(c->socket, &new_writefds, new_fdmax); } }