blob: 954c32649d372c6d13db6acaa74cd6dd9415dd34 [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 Jeffery91b52172023-04-19 12:42:14 +093089 /*
90 * We're managing an array of pointers to aggregates, so don't warn about sizeof() on a
91 * pointer type.
92 */
93 /* NOLINTBEGIN(bugprone-sizeof-expression) */
Andrew Jefferya72711a2023-04-18 18:19:41 +093094 memmove(&sh->clients[idx], &sh->clients[idx + 1],
95 sizeof(*sh->clients) * (sh->n_clients - idx));
96 sh->clients =
Andrew Jeffery91b52172023-04-19 12:42:14 +093097 reallocarray(sh->clients, sh->n_clients, sizeof(*sh->clients));
98 /* NOLINTEND(bugprone-sizeof-expression) */
Jeremy Kerr2bd05182016-03-10 16:59:43 +080099}
100
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800101static void client_set_blocked(struct client *client, bool blocked)
Jeremy Kerr848fc872017-01-17 13:50:05 +0800102{
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800103 int events;
104
105 if (client->blocked == blocked)
106 return;
107
108 client->blocked = blocked;
109
110 events = POLLIN;
111 if (client->blocked)
112 events |= POLLOUT;
113
114 console_poller_set_events(client->sh->console, client->poller, events);
115}
116
Andrew Jefferya72711a2023-04-18 18:19:41 +0930117static ssize_t send_all(struct client *client, void *buf, size_t len,
118 bool block)
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800119{
Andrew Jeffery5c359cc2023-04-18 22:50:07 +0930120 int fd, flags;
121 ssize_t rc;
Jeremy Kerr848fc872017-01-17 13:50:05 +0800122 size_t pos;
123
Andrew Jeffery5c359cc2023-04-18 22:50:07 +0930124 if (len > SSIZE_MAX)
125 return -EINVAL;
126
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800127 fd = client->fd;
128
Jeremy Kerr848fc872017-01-17 13:50:05 +0800129 flags = MSG_NOSIGNAL;
130 if (!block)
131 flags |= MSG_DONTWAIT;
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800132
133 for (pos = 0; pos < len; pos += rc) {
Andrew Jeffery21f4cb42023-04-18 14:38:37 +0930134 rc = send(fd, (char *)buf + pos, len - pos, flags);
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800135 if (rc < 0) {
Andrew Jefferya72711a2023-04-18 18:19:41 +0930136 if (!block &&
137 (errno == EAGAIN || errno == EWOULDBLOCK)) {
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800138 client_set_blocked(client, true);
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800139 break;
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800140 }
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800141
142 if (errno == EINTR)
143 continue;
144
145 return -1;
146 }
147 if (rc == 0)
148 return -1;
149 }
150
Andrew Jeffery5c359cc2023-04-18 22:50:07 +0930151 return (ssize_t)pos;
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800152}
153
Jeremy Kerr848fc872017-01-17 13:50:05 +0800154/* Drain the queue to the socket and update the queue buffer. If force_len is
155 * set, send at least that many bytes from the queue, possibly while blocking
156 */
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800157static int client_drain_queue(struct client *client, size_t force_len)
Jeremy Kerr848fc872017-01-17 13:50:05 +0800158{
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800159 uint8_t *buf;
Jeremy Kerr848fc872017-01-17 13:50:05 +0800160 ssize_t wlen;
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800161 size_t len, total_len;
Jeremy Kerr848fc872017-01-17 13:50:05 +0800162 bool block;
163
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800164 total_len = 0;
165 wlen = 0;
166 block = !!force_len;
Jeremy Kerr848fc872017-01-17 13:50:05 +0800167
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800168 /* if we're already blocked, no need for the write */
169 if (!block && client->blocked)
170 return 0;
171
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800172 for (;;) {
173 len = ringbuffer_dequeue_peek(client->rbc, total_len, &buf);
174 if (!len)
175 break;
176
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800177 wlen = send_all(client, buf, len, block);
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800178 if (wlen <= 0)
179 break;
180
181 total_len += wlen;
182
183 if (force_len && total_len >= force_len)
184 break;
Jeremy Kerr848fc872017-01-17 13:50:05 +0800185 }
186
Jeremy Kerr848fc872017-01-17 13:50:05 +0800187 if (wlen < 0)
188 return -1;
189
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800190 if (force_len && total_len < force_len)
Jeremy Kerr848fc872017-01-17 13:50:05 +0800191 return -1;
192
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800193 ringbuffer_dequeue_commit(client->rbc, total_len);
Jeremy Kerr848fc872017-01-17 13:50:05 +0800194 return 0;
195}
196
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800197static enum ringbuffer_poll_ret client_ringbuffer_poll(void *arg,
Andrew Jefferya72711a2023-04-18 18:19:41 +0930198 size_t force_len)
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800199{
200 struct client *client = arg;
Andrew Jeffery5c359cc2023-04-18 22:50:07 +0930201 size_t len;
202 int rc;
Johnathan Mantey1cecc5d2019-02-28 15:01:46 -0800203
204 len = ringbuffer_len(client->rbc);
205 if (!force_len && (len < SOCKET_HANDLER_PKT_SIZE)) {
206 /* Do nothing until many small requests have accumulated, or
207 * the UART is idle for awhile (as determined by the timeout
208 * value supplied to the poll function call in console_server.c. */
209 console_poller_set_timeout(client->sh->console, client->poller,
210 &socket_handler_timeout);
211 return RINGBUFFER_POLL_OK;
212 }
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800213
214 rc = client_drain_queue(client, force_len);
215 if (rc) {
216 client->rbc = NULL;
217 client_close(client);
218 return RINGBUFFER_POLL_REMOVE;
219 }
220
221 return RINGBUFFER_POLL_OK;
222}
223
Andrew Jefferya72711a2023-04-18 18:19:41 +0930224static enum poller_ret
225client_timeout(struct handler *handler __attribute__((unused)), void *data)
Johnathan Mantey1cecc5d2019-02-28 15:01:46 -0800226{
227 struct client *client = data;
228 int rc = 0;
229
230 if (client->blocked) {
231 /* nothing to do here, we'll call client_drain_queue when
232 * we become unblocked */
233 return POLLER_OK;
234 }
235
236 rc = client_drain_queue(client, 0);
237 if (rc) {
238 client_close(client);
239 return POLLER_REMOVE;
240 }
241
242 return POLLER_OK;
243}
244
Andrew Jefferya72711a2023-04-18 18:19:41 +0930245static enum poller_ret client_poll(struct handler *handler, int events,
246 void *data)
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800247{
248 struct socket_handler *sh = to_socket_handler(handler);
249 struct client *client = data;
250 uint8_t buf[4096];
Andrew Jeffery5c359cc2023-04-18 22:50:07 +0930251 ssize_t rc;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800252
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800253 if (events & POLLIN) {
Jeremy Kerr68a2ece2017-01-17 13:52:41 +0800254 rc = recv(client->fd, buf, sizeof(buf), MSG_DONTWAIT);
Jeremy Kerr848fc872017-01-17 13:50:05 +0800255 if (rc < 0) {
256 if (errno == EAGAIN || errno == EWOULDBLOCK)
257 return POLLER_OK;
258 else
259 goto err_close;
260 }
261 if (rc == 0)
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800262 goto err_close;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800263
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800264 console_data_out(sh->console, buf, rc);
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800265 }
266
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800267 if (events & POLLOUT) {
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800268 client_set_blocked(client, false);
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800269 rc = client_drain_queue(client, 0);
Jeremy Kerr848fc872017-01-17 13:50:05 +0800270 if (rc)
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800271 goto err_close;
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800272 }
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800273
274 return POLLER_OK;
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800275
276err_close:
277 client->poller = NULL;
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800278 client_close(client);
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800279 return POLLER_REMOVE;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800280}
281
Andrew Jefferya72711a2023-04-18 18:19:41 +0930282static enum poller_ret socket_poll(struct handler *handler, int events,
283 void __attribute__((unused)) * data)
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800284{
285 struct socket_handler *sh = to_socket_handler(handler);
286 struct client *client;
287 int fd, n;
288
289 if (!(events & POLLIN))
290 return POLLER_OK;
291
Jeremy Kerr68a2ece2017-01-17 13:52:41 +0800292 fd = accept(sh->sd, NULL, NULL);
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800293 if (fd < 0)
294 return POLLER_OK;
295
Jeremy Kerrce0e68b2016-03-18 13:55:46 +0800296 client = malloc(sizeof(*client));
297 memset(client, 0, sizeof(*client));
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800298
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800299 client->sh = sh;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800300 client->fd = fd;
Jeremy Kerr55c97122017-02-07 17:06:46 +0800301 client->poller = console_poller_register(sh->console, handler,
Andrew Jefferya72711a2023-04-18 18:19:41 +0930302 client_poll, client_timeout,
303 client->fd, POLLIN, client);
304 client->rbc = console_ringbuffer_consumer_register(
305 sh->console, client_ringbuffer_poll, client);
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800306
Jeremy Kerrce0e68b2016-03-18 13:55:46 +0800307 n = sh->n_clients++;
Andrew Jeffery91b52172023-04-19 12:42:14 +0930308 /*
309 * We're managing an array of pointers to aggregates, so don't warn about sizeof() on a
310 * pointer type.
311 */
312 /* NOLINTBEGIN(bugprone-sizeof-expression) */
Andrew Jefferya72711a2023-04-18 18:19:41 +0930313 sh->clients =
Andrew Jeffery91b52172023-04-19 12:42:14 +0930314 reallocarray(sh->clients, sh->n_clients, sizeof(*sh->clients));
315 /* NOLINTEND(bugprone-sizeof-expression) */
Jeremy Kerrce0e68b2016-03-18 13:55:46 +0800316 sh->clients[n] = client;
317
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800318 return POLLER_OK;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800319}
320
Jeremy Kerrd47963e2016-03-16 17:29:55 +0800321static int socket_init(struct handler *handler, struct console *console,
Andrew Jefferya72711a2023-04-18 18:19:41 +0930322 struct config *config)
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800323{
324 struct socket_handler *sh = to_socket_handler(handler);
325 struct sockaddr_un addr;
Andrew Jeffery5e7c0782020-02-10 12:12:36 +1030326 size_t addrlen;
327 ssize_t len;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800328 int rc;
329
330 sh->console = console;
331 sh->clients = NULL;
332 sh->n_clients = 0;
Jeremy Kerr5708dfb2017-01-19 15:11:19 +0800333
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800334 memset(&addr, 0, sizeof(addr));
335 addr.sun_family = AF_UNIX;
Andrew Jefferyddf2ab72020-02-10 12:36:09 +1030336 len = console_socket_path(&addr, config_get_value(config, "socket-id"));
Andrew Jeffery5e7c0782020-02-10 12:12:36 +1030337 if (len < 0) {
338 if (errno)
339 warn("Failed to configure socket: %s", strerror(errno));
340 else
341 warn("Socket name length exceeds buffer limits");
Jonathan Domancc075302023-03-31 10:20:48 -0700342 return -1;
Andrew Jeffery5e7c0782020-02-10 12:12:36 +1030343 }
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800344
Jonathan Domancc075302023-03-31 10:20:48 -0700345 /* Try to take a socket from systemd first */
346 if (sd_listen_fds(0) == 1 &&
Andrew Jefferya72711a2023-04-18 18:19:41 +0930347 sd_is_socket_unix(SD_LISTEN_FDS_START, SOCK_STREAM, 1,
348 addr.sun_path, len) > 0) {
Jonathan Domancc075302023-03-31 10:20:48 -0700349 sh->sd = SD_LISTEN_FDS_START;
350 } else {
351 sh->sd = socket(AF_UNIX, SOCK_STREAM, 0);
Andrew Jefferya72711a2023-04-18 18:19:41 +0930352 if (sh->sd < 0) {
Jonathan Domancc075302023-03-31 10:20:48 -0700353 warn("Can't create socket");
354 return -1;
355 }
Andrew Jeffery5e7c0782020-02-10 12:12:36 +1030356
Jonathan Domancc075302023-03-31 10:20:48 -0700357 addrlen = sizeof(addr) - sizeof(addr.sun_path) + len;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800358
Jonathan Domancc075302023-03-31 10:20:48 -0700359 rc = bind(sh->sd, (struct sockaddr *)&addr, addrlen);
360 if (rc) {
361 socket_path_t name;
362 console_socket_path_readable(&addr, addrlen, name);
363 warn("Can't bind to socket path %s (terminated at first null)",
Andrew Jefferya72711a2023-04-18 18:19:41 +0930364 name);
Jonathan Domancc075302023-03-31 10:20:48 -0700365 goto cleanup;
366 }
367
368 rc = listen(sh->sd, 1);
369 if (rc) {
370 warn("Can't listen for incoming connections");
371 goto cleanup;
372 }
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800373 }
374
Jeremy Kerr55c97122017-02-07 17:06:46 +0800375 sh->poller = console_poller_register(console, handler, socket_poll,
Andrew Jefferya72711a2023-04-18 18:19:41 +0930376 NULL, sh->sd, POLLIN, NULL);
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800377
378 return 0;
Andrew Jeffery5e7c0782020-02-10 12:12:36 +1030379cleanup:
380 close(sh->sd);
381 return -1;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800382}
383
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800384static void socket_fini(struct handler *handler)
385{
386 struct socket_handler *sh = to_socket_handler(handler);
Jeremy Kerr89ea8192016-03-15 17:57:43 +0800387
Jeremy Kerrabd8e252017-01-19 15:42:48 +0800388 while (sh->n_clients)
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800389 client_close(sh->clients[0]);
Jeremy Kerr89ea8192016-03-15 17:57:43 +0800390
391 if (sh->poller)
Jeremy Kerr55c97122017-02-07 17:06:46 +0800392 console_poller_unregister(sh->console, sh->poller);
Jeremy Kerr89ea8192016-03-15 17:57:43 +0800393
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800394 close(sh->sd);
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800395}
396
397static struct socket_handler socket_handler = {
398 .handler = {
399 .name = "socket",
400 .init = socket_init,
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800401 .fini = socket_fini,
402 },
403};
404
Jeremy Kerr55c97122017-02-07 17:06:46 +0800405console_handler_register(&socket_handler.handler);