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 int server_mark_socket_exec(bool exec
) {
23 if (stat(sockaddr
.sun_path
, &sb
) == -1)
25 mode_t mode
= sb
.st_mode
;
30 return chmod(sockaddr
.sun_path
, mode
);
33 static int server_create_socket(const char *name
) {
34 int socket
= create_socket(name
);
37 socklen_t socklen
= offsetof(struct sockaddr_un
, sun_path
) + strlen(sockaddr
.sun_path
) + 1;
38 mode_t mode
= S_IRUSR
|S_IWUSR
;
40 if (bind(socket
, (struct sockaddr
*)&sockaddr
, socklen
) == -1)
42 if (fchmod(socket
, mode
) == -1 && chmod(sockaddr
.sun_path
, mode
) == -1)
44 if (listen(socket
, 5) == -1)
48 unlink(sockaddr
.sun_path
);
52 static int server_set_socket_non_blocking(int sock
) {
54 if ((flags
= fcntl(sock
, F_GETFL
, 0)) == -1)
56 return fcntl(sock
, F_SETFL
, flags
| O_NONBLOCK
);
59 static Client
*server_accept_client() {
60 int newfd
= accept(server
.socket
, NULL
, NULL
);
63 Client
*c
= client_malloc(newfd
);
67 server_mark_socket_exec(true);
68 server_set_socket_non_blocking(newfd
);
70 c
->state
= STATE_CONNECTED
;
71 c
->next
= server
.clients
;
73 server
.read_pty
= true;
77 static bool server_read_pty(Packet
*pkt
) {
78 pkt
->type
= MSG_CONTENT
;
79 ssize_t len
= read(server
.pty
, pkt
->u
.msg
, sizeof(pkt
->u
.msg
));
82 else if (errno
!= EAGAIN
&& errno
!= EINTR
)
83 server
.running
= false;
84 print_packet("server-read-pty:", pkt
);
88 static bool server_write_pty(Packet
*pkt
) {
89 print_packet("server-write-pty:", pkt
);
90 size_t size
= pkt
->len
;
91 if (write_all(server
.pty
, pkt
->u
.msg
, size
) == size
)
94 server
.running
= false;
98 static bool server_recv_packet(Client
*c
, Packet
*pkt
) {
99 if (recv_packet(c
->socket
, pkt
)) {
100 print_packet("server-recv:", pkt
);
103 debug("server-recv: FAILED\n");
104 c
->state
= STATE_DISCONNECTED
;
108 static bool server_send_packet(Client
*c
, Packet
*pkt
) {
109 print_packet("server-send:", pkt
);
110 if (send_packet(c
->socket
, pkt
))
113 c
->state
= STATE_DISCONNECTED
;
117 static void server_pty_died_handler(int sig
) {
121 while ((pid
= waitpid(-1, &server
.exit_status
, WNOHANG
)) != 0) {
124 server
.exit_status
= WEXITSTATUS(server
.exit_status
);
127 debug("server pty died: %d\n", server
.exit_status
);
131 static void server_sigterm_handler(int sig
) {
132 exit(EXIT_FAILURE
); /* invoke atexit handler */
135 static void server_sigusr1_handler(int sig
) {
136 int socket
= server_create_socket(server
.session_name
);
139 close(server
.socket
);
140 server
.socket
= socket
;
144 static void server_atexit_handler() {
145 unlink(sockaddr
.sun_path
);
148 static void server_mainloop() {
149 atexit(server_atexit_handler
);
150 fd_set new_readfds
, new_writefds
;
151 FD_ZERO(&new_readfds
);
152 FD_ZERO(&new_writefds
);
153 FD_SET(server
.socket
, &new_readfds
);
154 int new_fdmax
= server
.socket
;
156 FD_SET_MAX(server
.pty
, &new_readfds
, new_fdmax
);
157 Packet
*exit_pkt
= NULL
;
160 int fdmax
= new_fdmax
;
161 fd_set readfds
= new_readfds
;
162 fd_set writefds
= new_writefds
;
163 FD_SET_MAX(server
.socket
, &readfds
, fdmax
);
165 if (select(fdmax
+1, &readfds
, &writefds
, NULL
, NULL
) == -1) {
168 die("server-mainloop");
171 FD_ZERO(&new_readfds
);
172 FD_ZERO(&new_writefds
);
173 new_fdmax
= server
.socket
;
175 bool pty_data
= false;
177 Packet server_packet
, client_packet
;
179 if (FD_ISSET(server
.socket
, &readfds
))
180 server_accept_client();
182 if (FD_ISSET(server
.pty
, &readfds
))
183 pty_data
= server_read_pty(&server_packet
);
185 if (!server
.running
&& server
.exit_status
!= -1 && server
.clients
) { /* application terminated */
188 .u
.i
= server
.exit_status
,
189 .len
= sizeof(pkt
.u
.i
),
192 server
.exit_status
= -1;
195 for (Client
**prev_next
= &server
.clients
, *c
= server
.clients
; c
;) {
196 if (c
->state
== STATE_DISCONNECTED
) {
197 bool first
= (c
== server
.clients
);
201 if (first
&& server
.clients
) {
206 server_send_packet(server
.clients
, &pkt
);
207 } else if (!server
.clients
) {
208 server_mark_socket_exec(false);
213 if (FD_ISSET(c
->socket
, &readfds
) && server_recv_packet(c
, &client_packet
)) {
214 switch (client_packet
.type
) {
216 server_write_pty(&client_packet
);
219 c
->readonly
= client_packet
.u
.b
;
222 c
->state
= STATE_ATTACHED
;
224 if (!c
->readonly
&& (client_packet
.type
== MSG_REDRAW
|| c
== server
.clients
)) {
225 debug("server-ioct: TIOCSWINSZ\n");
226 ioctl(server
.pty
, TIOCSWINSZ
, &client_packet
.u
.ws
);
228 kill(-server
.pid
, SIGWINCH
);
231 c
->state
= STATE_DETACHED
;
233 default: /* ignore package */
238 FD_SET_MAX(c
->socket
, &new_readfds
, new_fdmax
);
241 server_send_packet(c
, &server_packet
);
243 server_send_packet(c
, exit_pkt
);
245 prev_next
= &c
->next
;
249 if (server
.running
&& server
.read_pty
)
250 FD_SET_MAX(server
.pty
, &new_readfds
, new_fdmax
);