abduco

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | LICENSE

server.c (7463B)


      1 #define FD_SET_MAX(fd, set, maxfd) do { \
      2 		FD_SET(fd, set);        \
      3 		if (fd > maxfd)         \
      4 			maxfd = fd;     \
      5 	} while (0)
      6 
      7 static Client *client_malloc(int socket) {
      8 	Client *c = calloc(1, sizeof(Client));
      9 	if (!c)
     10 		return NULL;
     11 	c->socket = socket;
     12 	return c;
     13 }
     14 
     15 static void client_free(Client *c) {
     16 	if (c && c->socket > 0)
     17 		close(c->socket);
     18 	free(c);
     19 }
     20 
     21 static void server_sink_client() {
     22 	if (!server.clients || !server.clients->next)
     23 		return;
     24 	Client *target = server.clients;
     25 	server.clients = target->next;
     26 	Client *dst = server.clients;
     27 	while (dst->next)
     28 		dst = dst->next;
     29 	target->next = NULL;
     30 	dst->next = target;
     31 }
     32 
     33 static void server_mark_socket_exec(bool exec, bool usr) {
     34 	struct stat sb;
     35 	if (stat(sockaddr.sun_path, &sb) == -1)
     36 		return;
     37 	mode_t mode = sb.st_mode;
     38 	mode_t flag = usr ? S_IXUSR : S_IXGRP;
     39 	if (exec)
     40 		mode |= flag;
     41 	else
     42 		mode &= ~flag;
     43 	chmod(sockaddr.sun_path, mode);
     44 }
     45 
     46 static int server_create_socket(const char *name) {
     47 	if (!set_socket_name(&sockaddr, name))
     48 		return -1;
     49 	int fd = socket(AF_UNIX, SOCK_STREAM, 0);
     50 	if (fd == -1)
     51 		return -1;
     52 	socklen_t socklen = offsetof(struct sockaddr_un, sun_path) + strlen(sockaddr.sun_path) + 1;
     53 	mode_t mask = umask(S_IXUSR|S_IRWXG|S_IRWXO);
     54 	int r = bind(fd, (struct sockaddr*)&sockaddr, socklen);
     55 	umask(mask);
     56 
     57 	if (r == -1) {
     58 		close(fd);
     59 		return -1;
     60 	}
     61 
     62 	if (listen(fd, 5) == -1) {
     63 		unlink(sockaddr.sun_path);
     64 		close(fd);
     65 		return -1;
     66 	}
     67 
     68 	return fd;
     69 }
     70 
     71 static int server_set_socket_non_blocking(int sock) {
     72 	int flags;
     73 	if ((flags = fcntl(sock, F_GETFL, 0)) == -1)
     74 		flags = 0;
     75     	return fcntl(sock, F_SETFL, flags | O_NONBLOCK);
     76 }
     77 
     78 static bool server_read_pty(Packet *pkt) {
     79 	pkt->type = MSG_CONTENT;
     80 	ssize_t len = read(server.pty, pkt->u.msg, sizeof(pkt->u.msg));
     81 	if (len > 0)
     82 		pkt->len = len;
     83 	else if (len == 0)
     84 		server.running = false;
     85 	else if (len == -1 && errno != EAGAIN && errno != EINTR && errno != EWOULDBLOCK)
     86 		server.running = false;
     87 	print_packet("server-read-pty:", pkt);
     88 	return len > 0;
     89 }
     90 
     91 static bool server_write_pty(Packet *pkt) {
     92 	print_packet("server-write-pty:", pkt);
     93 	size_t size = pkt->len;
     94 	if (write_all(server.pty, pkt->u.msg, size) == size)
     95 		return true;
     96 	debug("FAILED\n");
     97 	server.running = false;
     98 	return false;
     99 }
    100 
    101 static bool server_recv_packet(Client *c, Packet *pkt) {
    102 	if (recv_packet(c->socket, pkt)) {
    103 		print_packet("server-recv:", pkt);
    104 		return true;
    105 	}
    106 	debug("server-recv: FAILED\n");
    107 	c->state = STATE_DISCONNECTED;
    108 	return false;
    109 }
    110 
    111 static bool server_send_packet(Client *c, Packet *pkt) {
    112 	print_packet("server-send:", pkt);
    113 	if (send_packet(c->socket, pkt))
    114 		return true;
    115 	debug("FAILED\n");
    116 	c->state = STATE_DISCONNECTED;
    117 	return false;
    118 }
    119 
    120 static void server_pty_died_handler(int sig) {
    121 	int errsv = errno;
    122 	pid_t pid;
    123 
    124 	while ((pid = waitpid(-1, &server.exit_status, WNOHANG)) != 0) {
    125 		if (pid == -1)
    126 			break;
    127 		server.exit_status = WEXITSTATUS(server.exit_status);
    128 		server_mark_socket_exec(true, false);
    129 	}
    130 
    131 	debug("server pty died: %d\n", server.exit_status);
    132 	errno = errsv;
    133 }
    134 
    135 static void server_sigterm_handler(int sig) {
    136 	exit(EXIT_FAILURE); /* invoke atexit handler */
    137 }
    138 
    139 static Client *server_accept_client(void) {
    140 	int newfd = accept(server.socket, NULL, NULL);
    141 	if (newfd == -1 || server_set_socket_non_blocking(newfd) == -1)
    142 		goto error;
    143 	Client *c = client_malloc(newfd);
    144 	if (!c)
    145 		goto error;
    146 	if (!server.clients)
    147 		server_mark_socket_exec(true, true);
    148 	c->socket = newfd;
    149 	c->state = STATE_CONNECTED;
    150 	c->next = server.clients;
    151 	server.clients = c;
    152 	server.read_pty = true;
    153 
    154 	Packet pkt = {
    155 		.type = MSG_PID,
    156 		.len = sizeof pkt.u.l,
    157 		.u.l = getpid(),
    158 	};
    159 	server_send_packet(c, &pkt);
    160 
    161 	return c;
    162 error:
    163 	if (newfd != -1)
    164 		close(newfd);
    165 	return NULL;
    166 }
    167 
    168 static void server_sigusr1_handler(int sig) {
    169 	int socket = server_create_socket(server.session_name);
    170 	if (socket != -1) {
    171 		if (server.socket)
    172 			close(server.socket);
    173 		server.socket = socket;
    174 	}
    175 }
    176 
    177 static void server_atexit_handler(void) {
    178 	unlink(sockaddr.sun_path);
    179 }
    180 
    181 static void server_mainloop(void) {
    182 	atexit(server_atexit_handler);
    183 	fd_set new_readfds, new_writefds;
    184 	FD_ZERO(&new_readfds);
    185 	FD_ZERO(&new_writefds);
    186 	FD_SET(server.socket, &new_readfds);
    187 	int new_fdmax = server.socket;
    188 	bool exit_packet_delivered = false;
    189 
    190 	if (server.read_pty)
    191 		FD_SET_MAX(server.pty, &new_readfds, new_fdmax);
    192 
    193 	while (server.clients || !exit_packet_delivered) {
    194 		int fdmax = new_fdmax;
    195 		fd_set readfds = new_readfds;
    196 		fd_set writefds = new_writefds;
    197 		FD_SET_MAX(server.socket, &readfds, fdmax);
    198 
    199 		if (select(fdmax+1, &readfds, &writefds, NULL, NULL) == -1) {
    200 			if (errno == EINTR)
    201 				continue;
    202 			die("server-mainloop");
    203 		}
    204 
    205 		FD_ZERO(&new_readfds);
    206 		FD_ZERO(&new_writefds);
    207 		new_fdmax = server.socket;
    208 
    209 		bool pty_data = false;
    210 
    211 		Packet server_packet, client_packet;
    212 
    213 		if (FD_ISSET(server.socket, &readfds))
    214 			server_accept_client();
    215 
    216 		if (FD_ISSET(server.pty, &readfds))
    217 			pty_data = server_read_pty(&server_packet);
    218 
    219 		for (Client **prev_next = &server.clients, *c = server.clients; c;) {
    220 			if (FD_ISSET(c->socket, &readfds) && server_recv_packet(c, &client_packet)) {
    221 				switch (client_packet.type) {
    222 				case MSG_CONTENT:
    223 					server_write_pty(&client_packet);
    224 					break;
    225 				case MSG_ATTACH:
    226 					c->flags = client_packet.u.i;
    227 					if (c->flags & CLIENT_MAXPRIORITY) {
    228 						if (server.has_maxprio)
    229 							c->state = STATE_REFUSED;
    230 						else
    231 							server.has_maxprio = 222;
    232 					} else if (c->flags & CLIENT_LOWPRIORITY || server.has_maxprio) {
    233 						server_sink_client();
    234 					}
    235 					break;
    236 				case MSG_RESIZE:
    237 					c->state = STATE_ATTACHED;
    238 					if (!(c->flags & CLIENT_READONLY) && c == server.clients) {
    239 						debug("server-ioct: TIOCSWINSZ\n");
    240 						struct winsize ws = { 0 };
    241 						ws.ws_row = client_packet.u.ws.rows;
    242 						ws.ws_col = client_packet.u.ws.cols;
    243 						ioctl(server.pty, TIOCSWINSZ, &ws);
    244 					}
    245 					kill(-server.pid, SIGWINCH);
    246 					break;
    247 				case MSG_EXIT:
    248 					exit_packet_delivered = true;
    249 					/* fall through */
    250 				case MSG_DETACH:
    251 					c->state = STATE_DISCONNECTED;
    252 					break;
    253 				default: /* ignore package */
    254 					break;
    255 				}
    256 			}
    257 
    258 			if (c->state == STATE_REFUSED) {
    259 				Packet pkt = {
    260 					.type = MSG_REFUSED,
    261 					.u.i = server.has_maxprio,
    262 					.len = sizeof(pkt.u.i),
    263 				};
    264 				if (!server_send_packet(c, &pkt))
    265 					FD_SET_MAX(c->socket, &new_writefds, new_fdmax);
    266 				continue;
    267 			}
    268 
    269 			if (c->state == STATE_DISCONNECTED) {
    270 				bool first = (c == server.clients);
    271 				Client *t = c->next;
    272 				client_free(c);
    273 				*prev_next = c = t;
    274 				if (first && server.clients) {
    275 					Packet pkt = {
    276 						.type = MSG_RESIZE,
    277 						.len = 0,
    278 					};
    279 					server_send_packet(server.clients, &pkt);
    280 				} else if (!server.clients) {
    281 					server.has_maxprio = 0;
    282 					server_mark_socket_exec(false, true);
    283 				}
    284 				continue;
    285 			}
    286 
    287 			FD_SET_MAX(c->socket, &new_readfds, new_fdmax);
    288 
    289 			if (pty_data)
    290 				server_send_packet(c, &server_packet);
    291 			if (!server.running) {
    292 				if (server.exit_status != -1) {
    293 					Packet pkt = {
    294 						.type = MSG_EXIT,
    295 						.u.i = server.exit_status,
    296 						.len = sizeof(pkt.u.i),
    297 					};
    298 					if (!server_send_packet(c, &pkt))
    299 						FD_SET_MAX(c->socket, &new_writefds, new_fdmax);
    300 				} else {
    301 					FD_SET_MAX(c->socket, &new_writefds, new_fdmax);
    302 				}
    303 			}
    304 			prev_next = &c->next;
    305 			c = c->next;
    306 		}
    307 
    308 		if (server.running && server.read_pty)
    309 			FD_SET_MAX(server.pty, &new_readfds, new_fdmax);
    310 	}
    311 
    312 	exit(EXIT_SUCCESS);
    313 }