blob: b10615b9edd30961072ebc41252207d364788cf7 [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 Kerr4d80a5b2016-03-18 13:47:43 +080017#define _GNU_SOURCE
Jeremy Kerrce0e68b2016-03-18 13:55:46 +080018
19#include <assert.h>
Jeremy Kerr2bd05182016-03-10 16:59:43 +080020#include <err.h>
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +080021#include <errno.h>
Jeremy Kerr2bd05182016-03-10 16:59:43 +080022#include <stdbool.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <termios.h>
27#include <unistd.h>
28#include <endian.h>
29
30#include <sys/socket.h>
31#include <sys/un.h>
Jonathan Domancc075302023-03-31 10:20:48 -070032#include <systemd/sd-daemon.h>
Jeremy Kerr2bd05182016-03-10 16:59:43 +080033
34#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);
74 if (client->poller)
Jeremy Kerr55c97122017-02-07 17:06:46 +080075 console_poller_unregister(sh->console, client->poller);
Jeremy Kerr2bd05182016-03-10 16:59:43 +080076
Jeremy Kerrc9775ce2017-02-07 16:25:34 +080077 if (client->rbc)
78 ringbuffer_consumer_unregister(client->rbc);
79
Jeremy Kerrce0e68b2016-03-18 13:55:46 +080080 for (idx = 0; idx < sh->n_clients; idx++)
81 if (sh->clients[idx] == client)
82 break;
83
84 assert(idx < sh->n_clients);
85
86 free(client);
87 client = NULL;
Jeremy Kerr2bd05182016-03-10 16:59:43 +080088
89 sh->n_clients--;
Andrew Jefferya72711a2023-04-18 18:19:41 +093090 memmove(&sh->clients[idx], &sh->clients[idx + 1],
91 sizeof(*sh->clients) * (sh->n_clients - idx));
92 sh->clients =
93 realloc(sh->clients, sizeof(*sh->clients) * sh->n_clients);
Jeremy Kerr2bd05182016-03-10 16:59:43 +080094}
95
Jeremy Kerr6b1fed22017-02-07 21:40:38 +080096static void client_set_blocked(struct client *client, bool blocked)
Jeremy Kerr848fc872017-01-17 13:50:05 +080097{
Jeremy Kerr6b1fed22017-02-07 21:40:38 +080098 int events;
99
100 if (client->blocked == blocked)
101 return;
102
103 client->blocked = blocked;
104
105 events = POLLIN;
106 if (client->blocked)
107 events |= POLLOUT;
108
109 console_poller_set_events(client->sh->console, client->poller, events);
110}
111
Andrew Jefferya72711a2023-04-18 18:19:41 +0930112static ssize_t send_all(struct client *client, void *buf, size_t len,
113 bool block)
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800114{
115 int fd, rc, flags;
Jeremy Kerr848fc872017-01-17 13:50:05 +0800116 size_t pos;
117
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800118 fd = client->fd;
119
Jeremy Kerr848fc872017-01-17 13:50:05 +0800120 flags = MSG_NOSIGNAL;
121 if (!block)
122 flags |= MSG_DONTWAIT;
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800123
124 for (pos = 0; pos < len; pos += rc) {
Andrew Jeffery21f4cb42023-04-18 14:38:37 +0930125 rc = send(fd, (char *)buf + pos, len - pos, flags);
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800126 if (rc < 0) {
Andrew Jefferya72711a2023-04-18 18:19:41 +0930127 if (!block &&
128 (errno == EAGAIN || errno == EWOULDBLOCK)) {
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800129 client_set_blocked(client, true);
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800130 break;
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800131 }
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800132
133 if (errno == EINTR)
134 continue;
135
136 return -1;
137 }
138 if (rc == 0)
139 return -1;
140 }
141
142 return pos;
143}
144
Jeremy Kerr848fc872017-01-17 13:50:05 +0800145/* Drain the queue to the socket and update the queue buffer. If force_len is
146 * set, send at least that many bytes from the queue, possibly while blocking
147 */
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800148static int client_drain_queue(struct client *client, size_t force_len)
Jeremy Kerr848fc872017-01-17 13:50:05 +0800149{
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800150 uint8_t *buf;
Jeremy Kerr848fc872017-01-17 13:50:05 +0800151 ssize_t wlen;
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800152 size_t len, total_len;
Jeremy Kerr848fc872017-01-17 13:50:05 +0800153 bool block;
154
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800155 total_len = 0;
156 wlen = 0;
157 block = !!force_len;
Jeremy Kerr848fc872017-01-17 13:50:05 +0800158
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800159 /* if we're already blocked, no need for the write */
160 if (!block && client->blocked)
161 return 0;
162
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800163 for (;;) {
164 len = ringbuffer_dequeue_peek(client->rbc, total_len, &buf);
165 if (!len)
166 break;
167
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800168 wlen = send_all(client, buf, len, block);
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800169 if (wlen <= 0)
170 break;
171
172 total_len += wlen;
173
174 if (force_len && total_len >= force_len)
175 break;
Jeremy Kerr848fc872017-01-17 13:50:05 +0800176 }
177
Jeremy Kerr848fc872017-01-17 13:50:05 +0800178 if (wlen < 0)
179 return -1;
180
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800181 if (force_len && total_len < force_len)
Jeremy Kerr848fc872017-01-17 13:50:05 +0800182 return -1;
183
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800184 ringbuffer_dequeue_commit(client->rbc, total_len);
Jeremy Kerr848fc872017-01-17 13:50:05 +0800185 return 0;
186}
187
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800188static enum ringbuffer_poll_ret client_ringbuffer_poll(void *arg,
Andrew Jefferya72711a2023-04-18 18:19:41 +0930189 size_t force_len)
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800190{
191 struct client *client = arg;
Johnathan Mantey1cecc5d2019-02-28 15:01:46 -0800192 int rc, len;
193
194 len = ringbuffer_len(client->rbc);
195 if (!force_len && (len < SOCKET_HANDLER_PKT_SIZE)) {
196 /* Do nothing until many small requests have accumulated, or
197 * the UART is idle for awhile (as determined by the timeout
198 * value supplied to the poll function call in console_server.c. */
199 console_poller_set_timeout(client->sh->console, client->poller,
200 &socket_handler_timeout);
201 return RINGBUFFER_POLL_OK;
202 }
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800203
204 rc = client_drain_queue(client, force_len);
205 if (rc) {
206 client->rbc = NULL;
207 client_close(client);
208 return RINGBUFFER_POLL_REMOVE;
209 }
210
211 return RINGBUFFER_POLL_OK;
212}
213
Andrew Jefferya72711a2023-04-18 18:19:41 +0930214static enum poller_ret
215client_timeout(struct handler *handler __attribute__((unused)), void *data)
Johnathan Mantey1cecc5d2019-02-28 15:01:46 -0800216{
217 struct client *client = data;
218 int rc = 0;
219
220 if (client->blocked) {
221 /* nothing to do here, we'll call client_drain_queue when
222 * we become unblocked */
223 return POLLER_OK;
224 }
225
226 rc = client_drain_queue(client, 0);
227 if (rc) {
228 client_close(client);
229 return POLLER_REMOVE;
230 }
231
232 return POLLER_OK;
233}
234
Andrew Jefferya72711a2023-04-18 18:19:41 +0930235static enum poller_ret client_poll(struct handler *handler, int events,
236 void *data)
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800237{
238 struct socket_handler *sh = to_socket_handler(handler);
239 struct client *client = data;
240 uint8_t buf[4096];
241 int rc;
242
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800243 if (events & POLLIN) {
Jeremy Kerr68a2ece2017-01-17 13:52:41 +0800244 rc = recv(client->fd, buf, sizeof(buf), MSG_DONTWAIT);
Jeremy Kerr848fc872017-01-17 13:50:05 +0800245 if (rc < 0) {
246 if (errno == EAGAIN || errno == EWOULDBLOCK)
247 return POLLER_OK;
248 else
249 goto err_close;
250 }
251 if (rc == 0)
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800252 goto err_close;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800253
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800254 console_data_out(sh->console, buf, rc);
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800255 }
256
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800257 if (events & POLLOUT) {
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800258 client_set_blocked(client, false);
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800259 rc = client_drain_queue(client, 0);
Jeremy Kerr848fc872017-01-17 13:50:05 +0800260 if (rc)
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800261 goto err_close;
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800262 }
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800263
264 return POLLER_OK;
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800265
266err_close:
267 client->poller = NULL;
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800268 client_close(client);
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800269 return POLLER_REMOVE;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800270}
271
Andrew Jefferya72711a2023-04-18 18:19:41 +0930272static enum poller_ret socket_poll(struct handler *handler, int events,
273 void __attribute__((unused)) * data)
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800274{
275 struct socket_handler *sh = to_socket_handler(handler);
276 struct client *client;
277 int fd, n;
278
279 if (!(events & POLLIN))
280 return POLLER_OK;
281
Jeremy Kerr68a2ece2017-01-17 13:52:41 +0800282 fd = accept(sh->sd, NULL, NULL);
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800283 if (fd < 0)
284 return POLLER_OK;
285
Jeremy Kerrce0e68b2016-03-18 13:55:46 +0800286 client = malloc(sizeof(*client));
287 memset(client, 0, sizeof(*client));
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800288
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800289 client->sh = sh;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800290 client->fd = fd;
Jeremy Kerr55c97122017-02-07 17:06:46 +0800291 client->poller = console_poller_register(sh->console, handler,
Andrew Jefferya72711a2023-04-18 18:19:41 +0930292 client_poll, client_timeout,
293 client->fd, POLLIN, client);
294 client->rbc = console_ringbuffer_consumer_register(
295 sh->console, client_ringbuffer_poll, client);
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800296
Jeremy Kerrce0e68b2016-03-18 13:55:46 +0800297 n = sh->n_clients++;
Andrew Jefferya72711a2023-04-18 18:19:41 +0930298 sh->clients =
299 realloc(sh->clients, sizeof(*sh->clients) * sh->n_clients);
Jeremy Kerrce0e68b2016-03-18 13:55:46 +0800300 sh->clients[n] = client;
301
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800302 return POLLER_OK;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800303}
304
Jeremy Kerrd47963e2016-03-16 17:29:55 +0800305static int socket_init(struct handler *handler, struct console *console,
Andrew Jefferya72711a2023-04-18 18:19:41 +0930306 struct config *config)
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800307{
308 struct socket_handler *sh = to_socket_handler(handler);
309 struct sockaddr_un addr;
Andrew Jeffery5e7c0782020-02-10 12:12:36 +1030310 size_t addrlen;
311 ssize_t len;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800312 int rc;
313
314 sh->console = console;
315 sh->clients = NULL;
316 sh->n_clients = 0;
Jeremy Kerr5708dfb2017-01-19 15:11:19 +0800317
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800318 memset(&addr, 0, sizeof(addr));
319 addr.sun_family = AF_UNIX;
Andrew Jefferyddf2ab72020-02-10 12:36:09 +1030320 len = console_socket_path(&addr, config_get_value(config, "socket-id"));
Andrew Jeffery5e7c0782020-02-10 12:12:36 +1030321 if (len < 0) {
322 if (errno)
323 warn("Failed to configure socket: %s", strerror(errno));
324 else
325 warn("Socket name length exceeds buffer limits");
Jonathan Domancc075302023-03-31 10:20:48 -0700326 return -1;
Andrew Jeffery5e7c0782020-02-10 12:12:36 +1030327 }
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800328
Jonathan Domancc075302023-03-31 10:20:48 -0700329 /* Try to take a socket from systemd first */
330 if (sd_listen_fds(0) == 1 &&
Andrew Jefferya72711a2023-04-18 18:19:41 +0930331 sd_is_socket_unix(SD_LISTEN_FDS_START, SOCK_STREAM, 1,
332 addr.sun_path, len) > 0) {
Jonathan Domancc075302023-03-31 10:20:48 -0700333 sh->sd = SD_LISTEN_FDS_START;
334 } else {
335 sh->sd = socket(AF_UNIX, SOCK_STREAM, 0);
Andrew Jefferya72711a2023-04-18 18:19:41 +0930336 if (sh->sd < 0) {
Jonathan Domancc075302023-03-31 10:20:48 -0700337 warn("Can't create socket");
338 return -1;
339 }
Andrew Jeffery5e7c0782020-02-10 12:12:36 +1030340
Jonathan Domancc075302023-03-31 10:20:48 -0700341 addrlen = sizeof(addr) - sizeof(addr.sun_path) + len;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800342
Jonathan Domancc075302023-03-31 10:20:48 -0700343 rc = bind(sh->sd, (struct sockaddr *)&addr, addrlen);
344 if (rc) {
345 socket_path_t name;
346 console_socket_path_readable(&addr, addrlen, name);
347 warn("Can't bind to socket path %s (terminated at first null)",
Andrew Jefferya72711a2023-04-18 18:19:41 +0930348 name);
Jonathan Domancc075302023-03-31 10:20:48 -0700349 goto cleanup;
350 }
351
352 rc = listen(sh->sd, 1);
353 if (rc) {
354 warn("Can't listen for incoming connections");
355 goto cleanup;
356 }
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800357 }
358
Jeremy Kerr55c97122017-02-07 17:06:46 +0800359 sh->poller = console_poller_register(console, handler, socket_poll,
Andrew Jefferya72711a2023-04-18 18:19:41 +0930360 NULL, sh->sd, POLLIN, NULL);
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800361
362 return 0;
Andrew Jeffery5e7c0782020-02-10 12:12:36 +1030363cleanup:
364 close(sh->sd);
365 return -1;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800366}
367
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800368static void socket_fini(struct handler *handler)
369{
370 struct socket_handler *sh = to_socket_handler(handler);
Jeremy Kerr89ea8192016-03-15 17:57:43 +0800371
Jeremy Kerrabd8e252017-01-19 15:42:48 +0800372 while (sh->n_clients)
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800373 client_close(sh->clients[0]);
Jeremy Kerr89ea8192016-03-15 17:57:43 +0800374
375 if (sh->poller)
Jeremy Kerr55c97122017-02-07 17:06:46 +0800376 console_poller_unregister(sh->console, sh->poller);
Jeremy Kerr89ea8192016-03-15 17:57:43 +0800377
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800378 close(sh->sd);
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800379}
380
381static struct socket_handler socket_handler = {
382 .handler = {
383 .name = "socket",
384 .init = socket_init,
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800385 .fini = socket_fini,
386 },
387};
388
Jeremy Kerr55c97122017-02-07 17:06:46 +0800389console_handler_register(&socket_handler.handler);