blob: c036b5867cf327c6385261e38330a8c5b4803bab [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
Alexander Hansena6b29102024-07-10 15:33:37 +020033#include "console-mux.h"
Jeremy Kerr2bd05182016-03-10 16:59:43 +080034#include "console-server.h"
35
Johnathan Mantey1cecc5d2019-02-28 15:01:46 -080036#define SOCKET_HANDLER_PKT_SIZE 512
37/* Set poll() timeout to 4000 uS, or 4 mS */
38#define SOCKET_HANDLER_PKT_US_TIMEOUT 4000
39
Jeremy Kerr2bd05182016-03-10 16:59:43 +080040struct client {
Andrew Jefferya72711a2023-04-18 18:19:41 +093041 struct socket_handler *sh;
42 struct poller *poller;
43 struct ringbuffer_consumer *rbc;
44 int fd;
45 bool blocked;
Jeremy Kerr2bd05182016-03-10 16:59:43 +080046};
47
48struct socket_handler {
Andrew Jefferya72711a2023-04-18 18:19:41 +093049 struct handler handler;
50 struct console *console;
51 struct poller *poller;
52 int sd;
Jeremy Kerr2bd05182016-03-10 16:59:43 +080053
Andrew Jefferya72711a2023-04-18 18:19:41 +093054 struct client **clients;
55 int n_clients;
Jeremy Kerr2bd05182016-03-10 16:59:43 +080056};
57
Johnathan Mantey1cecc5d2019-02-28 15:01:46 -080058static struct timeval const socket_handler_timeout = {
59 .tv_sec = 0,
60 .tv_usec = SOCKET_HANDLER_PKT_US_TIMEOUT
61};
62
Jeremy Kerr2bd05182016-03-10 16:59:43 +080063static struct socket_handler *to_socket_handler(struct handler *handler)
64{
65 return container_of(handler, struct socket_handler, handler);
66}
67
Jeremy Kerrc9775ce2017-02-07 16:25:34 +080068static void client_close(struct client *client)
Jeremy Kerr2bd05182016-03-10 16:59:43 +080069{
Jeremy Kerrc9775ce2017-02-07 16:25:34 +080070 struct socket_handler *sh = client->sh;
Jeremy Kerr2bd05182016-03-10 16:59:43 +080071 int idx;
72
73 close(client->fd);
Andrew Jeffery2834c5b2023-04-19 12:47:09 +093074 if (client->poller) {
Jeremy Kerr55c97122017-02-07 17:06:46 +080075 console_poller_unregister(sh->console, client->poller);
Andrew Jeffery2834c5b2023-04-19 12:47:09 +093076 }
Jeremy Kerr2bd05182016-03-10 16:59:43 +080077
Andrew Jeffery2834c5b2023-04-19 12:47:09 +093078 if (client->rbc) {
Jeremy Kerrc9775ce2017-02-07 16:25:34 +080079 ringbuffer_consumer_unregister(client->rbc);
Andrew Jeffery2834c5b2023-04-19 12:47:09 +093080 }
Jeremy Kerrc9775ce2017-02-07 16:25:34 +080081
Andrew Jeffery2834c5b2023-04-19 12:47:09 +093082 for (idx = 0; idx < sh->n_clients; idx++) {
83 if (sh->clients[idx] == client) {
Jeremy Kerrce0e68b2016-03-18 13:55:46 +080084 break;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +093085 }
86 }
Jeremy Kerrce0e68b2016-03-18 13:55:46 +080087
88 assert(idx < sh->n_clients);
89
90 free(client);
91 client = NULL;
Jeremy Kerr2bd05182016-03-10 16:59:43 +080092
93 sh->n_clients--;
Andrew Jeffery91b52172023-04-19 12:42:14 +093094 /*
95 * We're managing an array of pointers to aggregates, so don't warn about sizeof() on a
96 * pointer type.
97 */
98 /* NOLINTBEGIN(bugprone-sizeof-expression) */
Andrew Jefferya72711a2023-04-18 18:19:41 +093099 memmove(&sh->clients[idx], &sh->clients[idx + 1],
100 sizeof(*sh->clients) * (sh->n_clients - idx));
Andrew Jeffery7851a392024-07-09 16:30:22 +0930101 if (sh->n_clients == 0) {
102 free(sh->clients);
103 sh->clients = NULL;
104 } else {
105 sh->clients = reallocarray(sh->clients, sh->n_clients,
106 sizeof(*sh->clients));
107 }
Andrew Jeffery91b52172023-04-19 12:42:14 +0930108 /* NOLINTEND(bugprone-sizeof-expression) */
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800109}
110
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800111static void client_set_blocked(struct client *client, bool blocked)
Jeremy Kerr848fc872017-01-17 13:50:05 +0800112{
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800113 int events;
114
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930115 if (client->blocked == blocked) {
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800116 return;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930117 }
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800118
119 client->blocked = blocked;
120
121 events = POLLIN;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930122 if (client->blocked) {
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800123 events |= POLLOUT;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930124 }
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800125
126 console_poller_set_events(client->sh->console, client->poller, events);
127}
128
Andrew Jefferya72711a2023-04-18 18:19:41 +0930129static ssize_t send_all(struct client *client, void *buf, size_t len,
130 bool block)
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800131{
Andrew Jefferyb70f8712023-04-19 12:53:34 +0930132 int fd;
133 int flags;
Andrew Jeffery5c359cc2023-04-18 22:50:07 +0930134 ssize_t rc;
Jeremy Kerr848fc872017-01-17 13:50:05 +0800135 size_t pos;
136
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930137 if (len > SSIZE_MAX) {
Andrew Jeffery5c359cc2023-04-18 22:50:07 +0930138 return -EINVAL;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930139 }
Andrew Jeffery5c359cc2023-04-18 22:50:07 +0930140
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800141 fd = client->fd;
142
Jeremy Kerr848fc872017-01-17 13:50:05 +0800143 flags = MSG_NOSIGNAL;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930144 if (!block) {
Jeremy Kerr848fc872017-01-17 13:50:05 +0800145 flags |= MSG_DONTWAIT;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930146 }
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800147
148 for (pos = 0; pos < len; pos += rc) {
Andrew Jeffery21f4cb42023-04-18 14:38:37 +0930149 rc = send(fd, (char *)buf + pos, len - pos, flags);
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800150 if (rc < 0) {
Andrew Jefferya72711a2023-04-18 18:19:41 +0930151 if (!block &&
152 (errno == EAGAIN || errno == EWOULDBLOCK)) {
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800153 client_set_blocked(client, true);
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800154 break;
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800155 }
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800156
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930157 if (errno == EINTR) {
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800158 continue;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930159 }
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800160
161 return -1;
162 }
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930163 if (rc == 0) {
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800164 return -1;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930165 }
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800166 }
167
Andrew Jeffery5c359cc2023-04-18 22:50:07 +0930168 return (ssize_t)pos;
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800169}
170
Jeremy Kerr848fc872017-01-17 13:50:05 +0800171/* Drain the queue to the socket and update the queue buffer. If force_len is
172 * set, send at least that many bytes from the queue, possibly while blocking
173 */
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800174static int client_drain_queue(struct client *client, size_t force_len)
Jeremy Kerr848fc872017-01-17 13:50:05 +0800175{
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800176 uint8_t *buf;
Jeremy Kerr848fc872017-01-17 13:50:05 +0800177 ssize_t wlen;
Andrew Jefferyb70f8712023-04-19 12:53:34 +0930178 size_t len;
179 size_t total_len;
Jeremy Kerr848fc872017-01-17 13:50:05 +0800180 bool block;
181
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800182 total_len = 0;
183 wlen = 0;
184 block = !!force_len;
Jeremy Kerr848fc872017-01-17 13:50:05 +0800185
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800186 /* if we're already blocked, no need for the write */
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930187 if (!block && client->blocked) {
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800188 return 0;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930189 }
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800190
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800191 for (;;) {
192 len = ringbuffer_dequeue_peek(client->rbc, total_len, &buf);
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930193 if (!len) {
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800194 break;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930195 }
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800196
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800197 wlen = send_all(client, buf, len, block);
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930198 if (wlen <= 0) {
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800199 break;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930200 }
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800201
202 total_len += wlen;
203
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930204 if (force_len && total_len >= force_len) {
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800205 break;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930206 }
Jeremy Kerr848fc872017-01-17 13:50:05 +0800207 }
208
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930209 if (wlen < 0) {
Jeremy Kerr848fc872017-01-17 13:50:05 +0800210 return -1;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930211 }
Jeremy Kerr848fc872017-01-17 13:50:05 +0800212
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930213 if (force_len && total_len < force_len) {
Jeremy Kerr848fc872017-01-17 13:50:05 +0800214 return -1;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930215 }
Jeremy Kerr848fc872017-01-17 13:50:05 +0800216
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800217 ringbuffer_dequeue_commit(client->rbc, total_len);
Jeremy Kerr848fc872017-01-17 13:50:05 +0800218 return 0;
219}
220
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800221static enum ringbuffer_poll_ret client_ringbuffer_poll(void *arg,
Andrew Jefferya72711a2023-04-18 18:19:41 +0930222 size_t force_len)
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800223{
224 struct client *client = arg;
Andrew Jeffery5c359cc2023-04-18 22:50:07 +0930225 size_t len;
226 int rc;
Johnathan Mantey1cecc5d2019-02-28 15:01:46 -0800227
228 len = ringbuffer_len(client->rbc);
229 if (!force_len && (len < SOCKET_HANDLER_PKT_SIZE)) {
230 /* Do nothing until many small requests have accumulated, or
231 * the UART is idle for awhile (as determined by the timeout
232 * value supplied to the poll function call in console_server.c. */
233 console_poller_set_timeout(client->sh->console, client->poller,
234 &socket_handler_timeout);
235 return RINGBUFFER_POLL_OK;
236 }
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800237
238 rc = client_drain_queue(client, force_len);
239 if (rc) {
240 client->rbc = NULL;
241 client_close(client);
242 return RINGBUFFER_POLL_REMOVE;
243 }
244
245 return RINGBUFFER_POLL_OK;
246}
247
Andrew Jefferya72711a2023-04-18 18:19:41 +0930248static enum poller_ret
249client_timeout(struct handler *handler __attribute__((unused)), void *data)
Johnathan Mantey1cecc5d2019-02-28 15:01:46 -0800250{
251 struct client *client = data;
252 int rc = 0;
253
254 if (client->blocked) {
255 /* nothing to do here, we'll call client_drain_queue when
256 * we become unblocked */
257 return POLLER_OK;
258 }
259
260 rc = client_drain_queue(client, 0);
261 if (rc) {
Dan Zhang375786f2025-02-09 16:58:26 +0000262 client->poller = NULL;
Johnathan Mantey1cecc5d2019-02-28 15:01:46 -0800263 client_close(client);
264 return POLLER_REMOVE;
265 }
266
267 return POLLER_OK;
268}
269
Andrew Jefferya72711a2023-04-18 18:19:41 +0930270static enum poller_ret client_poll(struct handler *handler, int events,
271 void *data)
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800272{
273 struct socket_handler *sh = to_socket_handler(handler);
274 struct client *client = data;
275 uint8_t buf[4096];
Andrew Jeffery5c359cc2023-04-18 22:50:07 +0930276 ssize_t rc;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800277
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800278 if (events & POLLIN) {
Jeremy Kerr68a2ece2017-01-17 13:52:41 +0800279 rc = recv(client->fd, buf, sizeof(buf), MSG_DONTWAIT);
Jeremy Kerr848fc872017-01-17 13:50:05 +0800280 if (rc < 0) {
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930281 if (errno == EAGAIN || errno == EWOULDBLOCK) {
Jeremy Kerr848fc872017-01-17 13:50:05 +0800282 return POLLER_OK;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930283 }
Andrew Jeffery0b7b0472023-04-19 12:48:51 +0930284 goto err_close;
Jeremy Kerr848fc872017-01-17 13:50:05 +0800285 }
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930286 if (rc == 0) {
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800287 goto err_close;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930288 }
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800289
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800290 console_data_out(sh->console, buf, rc);
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800291 }
292
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800293 if (events & POLLOUT) {
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800294 client_set_blocked(client, false);
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800295 rc = client_drain_queue(client, 0);
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930296 if (rc) {
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800297 goto err_close;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930298 }
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800299 }
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800300
301 return POLLER_OK;
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800302
303err_close:
304 client->poller = NULL;
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800305 client_close(client);
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800306 return POLLER_REMOVE;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800307}
308
Andrew Jefferya72711a2023-04-18 18:19:41 +0930309static enum poller_ret socket_poll(struct handler *handler, int events,
310 void __attribute__((unused)) * data)
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800311{
312 struct socket_handler *sh = to_socket_handler(handler);
313 struct client *client;
Andrew Jefferyb70f8712023-04-19 12:53:34 +0930314 int fd;
315 int n;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800316
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930317 if (!(events & POLLIN)) {
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800318 return POLLER_OK;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930319 }
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800320
Jeremy Kerr68a2ece2017-01-17 13:52:41 +0800321 fd = accept(sh->sd, NULL, NULL);
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930322 if (fd < 0) {
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800323 return POLLER_OK;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930324 }
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800325
Alexander Hansena6b29102024-07-10 15:33:37 +0200326 console_mux_activate(sh->console);
327
Jeremy Kerrce0e68b2016-03-18 13:55:46 +0800328 client = malloc(sizeof(*client));
329 memset(client, 0, sizeof(*client));
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800330
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800331 client->sh = sh;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800332 client->fd = fd;
Jeremy Kerr55c97122017-02-07 17:06:46 +0800333 client->poller = console_poller_register(sh->console, handler,
Andrew Jefferya72711a2023-04-18 18:19:41 +0930334 client_poll, client_timeout,
335 client->fd, POLLIN, client);
336 client->rbc = console_ringbuffer_consumer_register(
337 sh->console, client_ringbuffer_poll, client);
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800338
Jeremy Kerrce0e68b2016-03-18 13:55:46 +0800339 n = sh->n_clients++;
Andrew Jeffery91b52172023-04-19 12:42:14 +0930340 /*
341 * We're managing an array of pointers to aggregates, so don't warn about sizeof() on a
342 * pointer type.
343 */
344 /* NOLINTBEGIN(bugprone-sizeof-expression) */
Andrew Jefferya72711a2023-04-18 18:19:41 +0930345 sh->clients =
Andrew Jeffery91b52172023-04-19 12:42:14 +0930346 reallocarray(sh->clients, sh->n_clients, sizeof(*sh->clients));
347 /* NOLINTEND(bugprone-sizeof-expression) */
Jeremy Kerrce0e68b2016-03-18 13:55:46 +0800348 sh->clients[n] = client;
349
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800350 return POLLER_OK;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800351}
352
Ninad Palsulebd992c92023-05-09 18:30:01 -0500353/* Create socket pair and register one end as poller/consumer and return
354 * the other end to the caller.
355 * Return file descriptor on success and negative value on error.
356 */
357int dbus_create_socket_consumer(struct console *console)
358{
359 struct socket_handler *sh = NULL;
360 struct client *client;
361 int fds[2];
362 int i;
363 int rc = -1;
364 int n;
365
366 for (i = 0; i < console->n_handlers; i++) {
Jeremy Kerre2826c72024-07-05 10:54:21 +0800367 if (strcmp(console->handlers[i]->type->name, "socket") == 0) {
Ninad Palsulebd992c92023-05-09 18:30:01 -0500368 sh = to_socket_handler(console->handlers[i]);
369 break;
370 }
371 }
372
373 if (!sh) {
374 return -ENOSYS;
375 }
376
377 /* Create a socketpair */
378 rc = socketpair(AF_UNIX, SOCK_STREAM, 0, fds);
379 if (rc < 0) {
380 warn("Failed to create socket pair");
381 return -errno;
382 }
383
384 client = malloc(sizeof(*client));
385 if (client == NULL) {
386 warnx("Failed to allocate client structure.");
387 rc = -ENOMEM;
388 goto close_fds;
389 }
390 memset(client, 0, sizeof(*client));
391
392 client->sh = sh;
393 client->fd = fds[0];
394 client->poller = console_poller_register(sh->console, &sh->handler,
395 client_poll, client_timeout,
396 client->fd, POLLIN, client);
397 client->rbc = console_ringbuffer_consumer_register(
398 sh->console, client_ringbuffer_poll, client);
399 if (client->rbc == NULL) {
400 warnx("Failed to register a consumer.\n");
401 rc = -ENOMEM;
402 goto free_client;
403 }
404
405 n = sh->n_clients++;
406
407 /*
408 * We're managing an array of pointers to aggregates, so don't warn about
409 * sizeof() on a pointer type.
410 */
411 /* NOLINTBEGIN(bugprone-sizeof-expression) */
412 sh->clients =
413 reallocarray(sh->clients, sh->n_clients, sizeof(*sh->clients));
414 /* NOLINTEND(bugprone-sizeof-expression) */
415 sh->clients[n] = client;
416
417 /* Return the second FD to caller. */
418 return fds[1];
419
420free_client:
421 free(client);
422close_fds:
423 close(fds[0]);
424 close(fds[1]);
425 return rc;
426}
427
Jeremy Kerre2826c72024-07-05 10:54:21 +0800428static struct handler *socket_init(const struct handler_type *type
429 __attribute__((unused)),
430 struct console *console,
431 struct config *config
432 __attribute__((unused)))
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800433{
Jeremy Kerre2826c72024-07-05 10:54:21 +0800434 struct socket_handler *sh;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800435 struct sockaddr_un addr;
Andrew Jeffery5e7c0782020-02-10 12:12:36 +1030436 size_t addrlen;
437 ssize_t len;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800438 int rc;
439
Jeremy Kerre2826c72024-07-05 10:54:21 +0800440 sh = malloc(sizeof(*sh));
441 if (!sh) {
442 return NULL;
443 }
444
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800445 sh->console = console;
446 sh->clients = NULL;
447 sh->n_clients = 0;
Jeremy Kerr5708dfb2017-01-19 15:11:19 +0800448
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800449 memset(&addr, 0, sizeof(addr));
450 addr.sun_family = AF_UNIX;
Andrew Jeffery954be0f2023-05-03 21:01:59 +0930451 len = console_socket_path(addr.sun_path, console->console_id);
Andrew Jeffery5e7c0782020-02-10 12:12:36 +1030452 if (len < 0) {
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930453 if (errno) {
Andrew Jeffery5e7c0782020-02-10 12:12:36 +1030454 warn("Failed to configure socket: %s", strerror(errno));
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930455 } else {
Andrew Jeffery5e7c0782020-02-10 12:12:36 +1030456 warn("Socket name length exceeds buffer limits");
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930457 }
Jeremy Kerre2826c72024-07-05 10:54:21 +0800458 goto err_free;
Andrew Jeffery5e7c0782020-02-10 12:12:36 +1030459 }
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800460
Jonathan Domancc075302023-03-31 10:20:48 -0700461 /* Try to take a socket from systemd first */
462 if (sd_listen_fds(0) == 1 &&
Andrew Jefferya72711a2023-04-18 18:19:41 +0930463 sd_is_socket_unix(SD_LISTEN_FDS_START, SOCK_STREAM, 1,
464 addr.sun_path, len) > 0) {
Jonathan Domancc075302023-03-31 10:20:48 -0700465 sh->sd = SD_LISTEN_FDS_START;
466 } else {
467 sh->sd = socket(AF_UNIX, SOCK_STREAM, 0);
Andrew Jefferya72711a2023-04-18 18:19:41 +0930468 if (sh->sd < 0) {
Jonathan Domancc075302023-03-31 10:20:48 -0700469 warn("Can't create socket");
Jeremy Kerre2826c72024-07-05 10:54:21 +0800470 goto err_free;
Jonathan Domancc075302023-03-31 10:20:48 -0700471 }
Andrew Jeffery5e7c0782020-02-10 12:12:36 +1030472
Jonathan Domancc075302023-03-31 10:20:48 -0700473 addrlen = sizeof(addr) - sizeof(addr.sun_path) + len;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800474
Jonathan Domancc075302023-03-31 10:20:48 -0700475 rc = bind(sh->sd, (struct sockaddr *)&addr, addrlen);
476 if (rc) {
477 socket_path_t name;
478 console_socket_path_readable(&addr, addrlen, name);
479 warn("Can't bind to socket path %s (terminated at first null)",
Andrew Jefferya72711a2023-04-18 18:19:41 +0930480 name);
Jeremy Kerre2826c72024-07-05 10:54:21 +0800481 goto err_close;
Jonathan Domancc075302023-03-31 10:20:48 -0700482 }
483
484 rc = listen(sh->sd, 1);
485 if (rc) {
486 warn("Can't listen for incoming connections");
Jeremy Kerre2826c72024-07-05 10:54:21 +0800487 goto err_close;
Jonathan Domancc075302023-03-31 10:20:48 -0700488 }
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800489 }
490
Jeremy Kerre2826c72024-07-05 10:54:21 +0800491 sh->poller = console_poller_register(console, &sh->handler, socket_poll,
Andrew Jefferya72711a2023-04-18 18:19:41 +0930492 NULL, sh->sd, POLLIN, NULL);
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800493
Jeremy Kerre2826c72024-07-05 10:54:21 +0800494 return &sh->handler;
495
496err_close:
Andrew Jeffery5e7c0782020-02-10 12:12:36 +1030497 close(sh->sd);
Jeremy Kerre2826c72024-07-05 10:54:21 +0800498err_free:
499 free(sh);
500 return NULL;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800501}
502
Alexander Hansena6b29102024-07-10 15:33:37 +0200503static void socket_deselect(struct handler *handler)
504{
505 struct socket_handler *sh = to_socket_handler(handler);
506
507 while (sh->n_clients) {
508 struct client *c = sh->clients[0];
509 client_drain_queue(c, 0);
510 client_close(c);
511 }
512}
513
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800514static void socket_fini(struct handler *handler)
515{
516 struct socket_handler *sh = to_socket_handler(handler);
Jeremy Kerr89ea8192016-03-15 17:57:43 +0800517
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930518 while (sh->n_clients) {
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800519 client_close(sh->clients[0]);
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930520 }
Jeremy Kerr89ea8192016-03-15 17:57:43 +0800521
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930522 if (sh->poller) {
Jeremy Kerr55c97122017-02-07 17:06:46 +0800523 console_poller_unregister(sh->console, sh->poller);
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930524 }
Jeremy Kerr89ea8192016-03-15 17:57:43 +0800525
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800526 close(sh->sd);
Jeremy Kerre2826c72024-07-05 10:54:21 +0800527 free(sh);
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800528}
529
Jeremy Kerre2826c72024-07-05 10:54:21 +0800530static const struct handler_type socket_handler = {
531 .name = "socket",
532 .init = socket_init,
Alexander Hansena6b29102024-07-10 15:33:37 +0200533 .deselect = socket_deselect,
Jeremy Kerre2826c72024-07-05 10:54:21 +0800534 .fini = socket_fini,
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800535};
536
Jeremy Kerre2826c72024-07-05 10:54:21 +0800537console_handler_register(&socket_handler);