1 #define FD_SET_MAX(fd, set, maxfd) do { \
7 static Client
*client_malloc(int socket
) {
8 Client
*c
= calloc(1, sizeof(Client
));
15 static void client_free(Client
*c
) {
16 if (c
&& c
->socket
> 0)
21 static void server_sink_client() {
22 if (!server
.clients
|| !server
.clients
->next
)
24 Client
*target
= server
.clients
;
25 server
.clients
= target
->next
;
26 Client
*dst
= server
.clients
;
33 static void server_mark_socket_exec(bool exec
, bool usr
) {
35 if (stat(sockaddr
.sun_path
, &sb
) == -1)
37 mode_t mode
= sb
.st_mode
;
38 mode_t flag
= usr
? S_IXUSR
: S_IXGRP
;
43 chmod(sockaddr
.sun_path
, mode
);
46 static int server_create_socket(const char *name
) {
47 if (!set_socket_name(&sockaddr
, name
))
49 int fd
= socket(AF_UNIX
, SOCK_STREAM
, 0);
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
);
62 if (listen(fd
, 5) == -1) {
63 unlink(sockaddr
.sun_path
);
71 static int server_set_socket_non_blocking(int sock
) {
73 if ((flags
= fcntl(sock
, F_GETFL
, 0)) == -1)
75 return fcntl(sock
, F_SETFL
, flags
| O_NONBLOCK
);
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
));
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
);
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
)
97 server
.running
= false;
101 static bool server_recv_packet(Client
*c
, Packet
*pkt
) {
102 if (recv_packet(c
->socket
, pkt
)) {
103 print_packet("server-recv:", pkt
);
106 debug("server-recv: FAILED\n");
107 c
->state
= STATE_DISCONNECTED
;
111 static bool server_send_packet(Client
*c
, Packet
*pkt
) {
112 print_packet("server-send:", pkt
);
113 if (send_packet(c
->socket
, pkt
))
116 c
->state
= STATE_DISCONNECTED
;
120 static void server_pty_died_handler(int sig
) {
124 while ((pid
= waitpid(-1, &server
.exit_status
, WNOHANG
)) != 0) {
127 server
.exit_status
= WEXITSTATUS(server
.exit_status
);
128 server_mark_socket_exec(true, false);
131 debug("server pty died: %d\n", server
.exit_status
);
135 static void server_sigterm_handler(int sig
) {
136 exit(EXIT_FAILURE
); /* invoke atexit handler */
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)
143 Client
*c
= client_malloc(newfd
);
147 server_mark_socket_exec(true, true);
149 c
->state
= STATE_CONNECTED
;
150 c
->next
= server
.clients
;
152 server
.read_pty
= true;
156 .len
= sizeof pkt
.u
.l
,
159 server_send_packet(c
, &pkt
);
168 static void server_sigusr1_handler(int sig
) {
169 int socket
= server_create_socket(server
.session_name
);
172 close(server
.socket
);
173 server
.socket
= socket
;
177 static void server_atexit_handler(void) {
178 unlink(sockaddr
.sun_path
);
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;
191 FD_SET_MAX(server
.pty
, &new_readfds
, new_fdmax
);
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
);
199 if (select(fdmax
+1, &readfds
, &writefds
, NULL
, NULL
) == -1) {
202 die("server-mainloop");
205 FD_ZERO(&new_readfds
);
206 FD_ZERO(&new_writefds
);
207 new_fdmax
= server
.socket
;
209 bool pty_data
= false;
211 Packet server_packet
, client_packet
;
213 if (FD_ISSET(server
.socket
, &readfds
))
214 server_accept_client();
216 if (FD_ISSET(server
.pty
, &readfds
))
217 pty_data
= server_read_pty(&server_packet
);
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
) {
223 server_write_pty(&client_packet
);
226 c
->flags
= client_packet
.u
.i
;
227 if (c
->flags
& CLIENT_LOWPRIORITY
)
228 server_sink_client();
231 c
->state
= STATE_ATTACHED
;
232 if (!(c
->flags
& CLIENT_READONLY
) && c
== server
.clients
) {
233 debug("server-ioct: TIOCSWINSZ\n");
234 struct winsize ws
= { 0 };
235 ws
.ws_row
= client_packet
.u
.ws
.rows
;
236 ws
.ws_col
= client_packet
.u
.ws
.cols
;
237 ioctl(server
.pty
, TIOCSWINSZ
, &ws
);
239 kill(-server
.pid
, SIGWINCH
);
242 exit_packet_delivered
= true;
245 c
->state
= STATE_DISCONNECTED
;
247 default: /* ignore package */
252 if (c
->state
== STATE_DISCONNECTED
) {
253 bool first
= (c
== server
.clients
);
257 if (first
&& server
.clients
) {
262 server_send_packet(server
.clients
, &pkt
);
263 } else if (!server
.clients
) {
264 server_mark_socket_exec(false, true);
269 FD_SET_MAX(c
->socket
, &new_readfds
, new_fdmax
);
272 server_send_packet(c
, &server_packet
);
273 if (!server
.running
) {
274 if (server
.exit_status
!= -1) {
277 .u
.i
= server
.exit_status
,
278 .len
= sizeof(pkt
.u
.i
),
280 if (!server_send_packet(c
, &pkt
))
281 FD_SET_MAX(c
->socket
, &new_writefds
, new_fdmax
);
283 FD_SET_MAX(c
->socket
, &new_writefds
, new_fdmax
);
286 prev_next
= &c
->next
;
290 if (server
.running
&& server
.read_pty
)
291 FD_SET_MAX(server
.pty
, &new_readfds
, new_fdmax
);