blob: d7aaa67dde463098e9aa539fc1e6ec2546a6e7da [file] [log] [blame]
Jeremy Kerr9326d772016-03-17 17:15:02 +08001/**
2 * Copyright © 2016 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Jeremy Kerr2bd05182016-03-10 16:59:43 +080016
Jeremy Kerrce0e68b2016-03-18 13:55:46 +080017#include <assert.h>
Jeremy Kerr2bd05182016-03-10 16:59:43 +080018#include <err.h>
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +080019#include <errno.h>
Andrew Jeffery5c359cc2023-04-18 22:50:07 +093020#include <limits.h>
Jeremy Kerr2bd05182016-03-10 16:59:43 +080021#include <stdbool.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <termios.h>
26#include <unistd.h>
27#include <endian.h>
28
29#include <sys/socket.h>
30#include <sys/un.h>
Jonathan Domancc075302023-03-31 10:20:48 -070031#include <systemd/sd-daemon.h>
Jeremy Kerr2bd05182016-03-10 16:59:43 +080032
33#include "console-server.h"
34
Johnathan Mantey1cecc5d2019-02-28 15:01:46 -080035#define SOCKET_HANDLER_PKT_SIZE 512
36/* Set poll() timeout to 4000 uS, or 4 mS */
37#define SOCKET_HANDLER_PKT_US_TIMEOUT 4000
38
Jeremy Kerr2bd05182016-03-10 16:59:43 +080039struct client {
Andrew Jefferya72711a2023-04-18 18:19:41 +093040 struct socket_handler *sh;
41 struct poller *poller;
42 struct ringbuffer_consumer *rbc;
43 int fd;
44 bool blocked;
Jeremy Kerr2bd05182016-03-10 16:59:43 +080045};
46
47struct socket_handler {
Andrew Jefferya72711a2023-04-18 18:19:41 +093048 struct handler handler;
49 struct console *console;
50 struct poller *poller;
51 int sd;
Jeremy Kerr2bd05182016-03-10 16:59:43 +080052
Andrew Jefferya72711a2023-04-18 18:19:41 +093053 struct client **clients;
54 int n_clients;
Jeremy Kerr2bd05182016-03-10 16:59:43 +080055};
56
Johnathan Mantey1cecc5d2019-02-28 15:01:46 -080057static struct timeval const socket_handler_timeout = {
58 .tv_sec = 0,
59 .tv_usec = SOCKET_HANDLER_PKT_US_TIMEOUT
60};
61
Jeremy Kerr2bd05182016-03-10 16:59:43 +080062static struct socket_handler *to_socket_handler(struct handler *handler)
63{
64 return container_of(handler, struct socket_handler, handler);
65}
66
Jeremy Kerrc9775ce2017-02-07 16:25:34 +080067static void client_close(struct client *client)
Jeremy Kerr2bd05182016-03-10 16:59:43 +080068{
Jeremy Kerrc9775ce2017-02-07 16:25:34 +080069 struct socket_handler *sh = client->sh;
Jeremy Kerr2bd05182016-03-10 16:59:43 +080070 int idx;
71
72 close(client->fd);
73 if (client->poller)
Jeremy Kerr55c97122017-02-07 17:06:46 +080074 console_poller_unregister(sh->console, client->poller);
Jeremy Kerr2bd05182016-03-10 16:59:43 +080075
Jeremy Kerrc9775ce2017-02-07 16:25:34 +080076 if (client->rbc)
77 ringbuffer_consumer_unregister(client->rbc);
78
Jeremy Kerrce0e68b2016-03-18 13:55:46 +080079 for (idx = 0; idx < sh->n_clients; idx++)
80 if (sh->clients[idx] == client)
81 break;
82
83 assert(idx < sh->n_clients);
84
85 free(client);
86 client = NULL;
Jeremy Kerr2bd05182016-03-10 16:59:43 +080087
88 sh->n_clients--;
Andrew Jefferya72711a2023-04-18 18:19:41 +093089 memmove(&sh->clients[idx], &sh->clients[idx + 1],
90 sizeof(*sh->clients) * (sh->n_clients - idx));
91 sh->clients =
92 realloc(sh->clients, sizeof(*sh->clients) * sh->n_clients);
Jeremy Kerr2bd05182016-03-10 16:59:43 +080093}
94
Jeremy Kerr6b1fed22017-02-07 21:40:38 +080095static void client_set_blocked(struct client *client, bool blocked)
Jeremy Kerr848fc872017-01-17 13:50:05 +080096{
Jeremy Kerr6b1fed22017-02-07 21:40:38 +080097 int events;
98
99 if (client->blocked == blocked)
100 return;
101
102 client->blocked = blocked;
103
104 events = POLLIN;
105 if (client->blocked)
106 events |= POLLOUT;
107
108 console_poller_set_events(client->sh->console, client->poller, events);
109}
110
Andrew Jefferya72711a2023-04-18 18:19:41 +0930111static ssize_t send_all(struct client *client, void *buf, size_t len,
112 bool block)
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800113{
Andrew Jeffery5c359cc2023-04-18 22:50:07 +0930114 int fd, flags;
115 ssize_t rc;
Jeremy Kerr848fc872017-01-17 13:50:05 +0800116 size_t pos;
117
Andrew Jeffery5c359cc2023-04-18 22:50:07 +0930118 if (len > SSIZE_MAX)
119 return -EINVAL;
120
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800121 fd = client->fd;
122
Jeremy Kerr848fc872017-01-17 13:50:05 +0800123 flags = MSG_NOSIGNAL;
124 if (!block)
125 flags |= MSG_DONTWAIT;
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800126
127 for (pos = 0; pos < len; pos += rc) {
Andrew Jeffery21f4cb42023-04-18 14:38:37 +0930128 rc = send(fd, (char *)buf + pos, len - pos, flags);
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800129 if (rc < 0) {
Andrew Jefferya72711a2023-04-18 18:19:41 +0930130 if (!block &&
131 (errno == EAGAIN || errno == EWOULDBLOCK)) {
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800132 client_set_blocked(client, true);
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800133 break;
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800134 }
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800135
136 if (errno == EINTR)
137 continue;
138
139 return -1;
140 }
141 if (rc == 0)
142 return -1;
143 }
144
Andrew Jeffery5c359cc2023-04-18 22:50:07 +0930145 return (ssize_t)pos;
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800146}
147
Jeremy Kerr848fc872017-01-17 13:50:05 +0800148/* Drain the queue to the socket and update the queue buffer. If force_len is
149 * set, send at least that many bytes from the queue, possibly while blocking
150 */
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800151static int client_drain_queue(struct client *client, size_t force_len)
Jeremy Kerr848fc872017-01-17 13:50:05 +0800152{
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800153 uint8_t *buf;
Jeremy Kerr848fc872017-01-17 13:50:05 +0800154 ssize_t wlen;
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800155 size_t len, total_len;
Jeremy Kerr848fc872017-01-17 13:50:05 +0800156 bool block;
157
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800158 total_len = 0;
159 wlen = 0;
160 block = !!force_len;
Jeremy Kerr848fc872017-01-17 13:50:05 +0800161
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800162 /* if we're already blocked, no need for the write */
163 if (!block && client->blocked)
164 return 0;
165
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800166 for (;;) {
167 len = ringbuffer_dequeue_peek(client->rbc, total_len, &buf);
168 if (!len)
169 break;
170
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800171 wlen = send_all(client, buf, len, block);
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800172 if (wlen <= 0)
173 break;
174
175 total_len += wlen;
176
177 if (force_len && total_len >= force_len)
178 break;
Jeremy Kerr848fc872017-01-17 13:50:05 +0800179 }
180
Jeremy Kerr848fc872017-01-17 13:50:05 +0800181 if (wlen < 0)
182 return -1;
183
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800184 if (force_len && total_len < force_len)
Jeremy Kerr848fc872017-01-17 13:50:05 +0800185 return -1;
186
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800187 ringbuffer_dequeue_commit(client->rbc, total_len);
Jeremy Kerr848fc872017-01-17 13:50:05 +0800188 return 0;
189}
190
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800191static enum ringbuffer_poll_ret client_ringbuffer_poll(void *arg,
Andrew Jefferya72711a2023-04-18 18:19:41 +0930192 size_t force_len)
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800193{
194 struct client *client = arg;
Andrew Jeffery5c359cc2023-04-18 22:50:07 +0930195 size_t len;
196 int rc;
Johnathan Mantey1cecc5d2019-02-28 15:01:46 -0800197
198 len = ringbuffer_len(client->rbc);
199 if (!force_len && (len < SOCKET_HANDLER_PKT_SIZE)) {
200 /* Do nothing until many small requests have accumulated, or
201 * the UART is idle for awhile (as determined by the timeout
202 * value supplied to the poll function call in console_server.c. */
203 console_poller_set_timeout(client->sh->console, client->poller,
204 &socket_handler_timeout);
205 return RINGBUFFER_POLL_OK;
206 }
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800207
208 rc = client_drain_queue(client, force_len);
209 if (rc) {
210 client->rbc = NULL;
211 client_close(client);
212 return RINGBUFFER_POLL_REMOVE;
213 }
214
215 return RINGBUFFER_POLL_OK;
216}
217
Andrew Jefferya72711a2023-04-18 18:19:41 +0930218static enum poller_ret
219client_timeout(struct handler *handler __attribute__((unused)), void *data)
Johnathan Mantey1cecc5d2019-02-28 15:01:46 -0800220{
221 struct client *client = data;
222 int rc = 0;
223
224 if (client->blocked) {
225 /* nothing to do here, we'll call client_drain_queue when
226 * we become unblocked */
227 return POLLER_OK;
228 }
229
230 rc = client_drain_queue(client, 0);
231 if (rc) {
232 client_close(client);
233 return POLLER_REMOVE;
234 }
235
236 return POLLER_OK;
237}
238
Andrew Jefferya72711a2023-04-18 18:19:41 +0930239static enum poller_ret client_poll(struct handler *handler, int events,
240 void *data)
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800241{
242 struct socket_handler *sh = to_socket_handler(handler);
243 struct client *client = data;
244 uint8_t buf[4096];
Andrew Jeffery5c359cc2023-04-18 22:50:07 +0930245 ssize_t rc;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800246
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800247 if (events & POLLIN) {
Jeremy Kerr68a2ece2017-01-17 13:52:41 +0800248 rc = recv(client->fd, buf, sizeof(buf), MSG_DONTWAIT);
Jeremy Kerr848fc872017-01-17 13:50:05 +0800249 if (rc < 0) {
250 if (errno == EAGAIN || errno == EWOULDBLOCK)
251 return POLLER_OK;
252 else
253 goto err_close;
254 }
255 if (rc == 0)
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800256 goto err_close;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800257
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800258 console_data_out(sh->console, buf, rc);
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800259 }
260
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800261 if (events & POLLOUT) {
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800262 client_set_blocked(client, false);
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800263 rc = client_drain_queue(client, 0);
Jeremy Kerr848fc872017-01-17 13:50:05 +0800264 if (rc)
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800265 goto err_close;
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800266 }
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800267
268 return POLLER_OK;
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800269
270err_close:
271 client->poller = NULL;
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800272 client_close(client);
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800273 return POLLER_REMOVE;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800274}
275
Andrew Jefferya72711a2023-04-18 18:19:41 +0930276static enum poller_ret socket_poll(struct handler *handler, int events,
277 void __attribute__((unused)) * data)
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800278{
279 struct socket_handler *sh = to_socket_handler(handler);
280 struct client *client;
281 int fd, n;
282
283 if (!(events & POLLIN))
284 return POLLER_OK;
285
Jeremy Kerr68a2ece2017-01-17 13:52:41 +0800286 fd = accept(sh->sd, NULL, NULL);
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800287 if (fd < 0)
288 return POLLER_OK;
289
Jeremy Kerrce0e68b2016-03-18 13:55:46 +0800290 client = malloc(sizeof(*client));
291 memset(client, 0, sizeof(*client));
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800292
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800293 client->sh = sh;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800294 client->fd = fd;
Jeremy Kerr55c97122017-02-07 17:06:46 +0800295 client->poller = console_poller_register(sh->console, handler,
Andrew Jefferya72711a2023-04-18 18:19:41 +0930296 client_poll, client_timeout,
297 client->fd, POLLIN, client);
298 client->rbc = console_ringbuffer_consumer_register(
299 sh->console, client_ringbuffer_poll, client);
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800300
Jeremy Kerrce0e68b2016-03-18 13:55:46 +0800301 n = sh->n_clients++;
Andrew Jefferya72711a2023-04-18 18:19:41 +0930302 sh->clients =
303 realloc(sh->clients, sizeof(*sh->clients) * sh->n_clients);
Jeremy Kerrce0e68b2016-03-18 13:55:46 +0800304 sh->clients[n] = client;
305
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800306 return POLLER_OK;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800307}
308
Jeremy Kerrd47963e2016-03-16 17:29:55 +0800309static int socket_init(struct handler *handler, struct console *console,
Andrew Jefferya72711a2023-04-18 18:19:41 +0930310 struct config *config)
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800311{
312 struct socket_handler *sh = to_socket_handler(handler);
313 struct sockaddr_un addr;
Andrew Jeffery5e7c0782020-02-10 12:12:36 +1030314 size_t addrlen;
315 ssize_t len;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800316 int rc;
317
318 sh->console = console;
319 sh->clients = NULL;
320 sh->n_clients = 0;
Jeremy Kerr5708dfb2017-01-19 15:11:19 +0800321
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800322 memset(&addr, 0, sizeof(addr));
323 addr.sun_family = AF_UNIX;
Andrew Jefferyddf2ab72020-02-10 12:36:09 +1030324 len = console_socket_path(&addr, config_get_value(config, "socket-id"));
Andrew Jeffery5e7c0782020-02-10 12:12:36 +1030325 if (len < 0) {
326 if (errno)
327 warn("Failed to configure socket: %s", strerror(errno));
328 else
329 warn("Socket name length exceeds buffer limits");
Jonathan Domancc075302023-03-31 10:20:48 -0700330 return -1;
Andrew Jeffery5e7c0782020-02-10 12:12:36 +1030331 }
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800332
Jonathan Domancc075302023-03-31 10:20:48 -0700333 /* Try to take a socket from systemd first */
334 if (sd_listen_fds(0) == 1 &&
Andrew Jefferya72711a2023-04-18 18:19:41 +0930335 sd_is_socket_unix(SD_LISTEN_FDS_START, SOCK_STREAM, 1,
336 addr.sun_path, len) > 0) {
Jonathan Domancc075302023-03-31 10:20:48 -0700337 sh->sd = SD_LISTEN_FDS_START;
338 } else {
339 sh->sd = socket(AF_UNIX, SOCK_STREAM, 0);
Andrew Jefferya72711a2023-04-18 18:19:41 +0930340 if (sh->sd < 0) {
Jonathan Domancc075302023-03-31 10:20:48 -0700341 warn("Can't create socket");
342 return -1;
343 }
Andrew Jeffery5e7c0782020-02-10 12:12:36 +1030344
Jonathan Domancc075302023-03-31 10:20:48 -0700345 addrlen = sizeof(addr) - sizeof(addr.sun_path) + len;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800346
Jonathan Domancc075302023-03-31 10:20:48 -0700347 rc = bind(sh->sd, (struct sockaddr *)&addr, addrlen);
348 if (rc) {
349 socket_path_t name;
350 console_socket_path_readable(&addr, addrlen, name);
351 warn("Can't bind to socket path %s (terminated at first null)",
Andrew Jefferya72711a2023-04-18 18:19:41 +0930352 name);
Jonathan Domancc075302023-03-31 10:20:48 -0700353 goto cleanup;
354 }
355
356 rc = listen(sh->sd, 1);
357 if (rc) {
358 warn("Can't listen for incoming connections");
359 goto cleanup;
360 }
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800361 }
362
Jeremy Kerr55c97122017-02-07 17:06:46 +0800363 sh->poller = console_poller_register(console, handler, socket_poll,
Andrew Jefferya72711a2023-04-18 18:19:41 +0930364 NULL, sh->sd, POLLIN, NULL);
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800365
366 return 0;
Andrew Jeffery5e7c0782020-02-10 12:12:36 +1030367cleanup:
368 close(sh->sd);
369 return -1;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800370}
371
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800372static void socket_fini(struct handler *handler)
373{
374 struct socket_handler *sh = to_socket_handler(handler);
Jeremy Kerr89ea8192016-03-15 17:57:43 +0800375
Jeremy Kerrabd8e252017-01-19 15:42:48 +0800376 while (sh->n_clients)
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800377 client_close(sh->clients[0]);
Jeremy Kerr89ea8192016-03-15 17:57:43 +0800378
379 if (sh->poller)
Jeremy Kerr55c97122017-02-07 17:06:46 +0800380 console_poller_unregister(sh->console, sh->poller);
Jeremy Kerr89ea8192016-03-15 17:57:43 +0800381
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800382 close(sh->sd);
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800383}
384
385static struct socket_handler socket_handler = {
386 .handler = {
387 .name = "socket",
388 .init = socket_init,
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800389 .fini = socket_fini,
390 },
391};
392
Jeremy Kerr55c97122017-02-07 17:06:46 +0800393console_handler_register(&socket_handler.handler);