blob: a11ab24f0a21dd704ad13a3cc4d7653cced13590 [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>
32
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 {
Jeremy Kerrc9775ce2017-02-07 16:25:34 +080040 struct socket_handler *sh;
41 struct poller *poller;
42 struct ringbuffer_consumer *rbc;
43 int fd;
Jeremy Kerr6b1fed22017-02-07 21:40:38 +080044 bool blocked;
Jeremy Kerr2bd05182016-03-10 16:59:43 +080045};
46
47struct socket_handler {
Jeremy Kerrc9775ce2017-02-07 16:25:34 +080048 struct handler handler;
49 struct console *console;
50 struct poller *poller;
Jeremy Kerrc9775ce2017-02-07 16:25:34 +080051 int sd;
Jeremy Kerr2bd05182016-03-10 16:59:43 +080052
Jeremy Kerrc9775ce2017-02-07 16:25:34 +080053 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--;
89 memmove(&sh->clients[idx], &sh->clients[idx+1],
90 sizeof(*sh->clients) * (sh->n_clients - idx));
Joel Stanleyfbff1c62016-03-17 20:32:24 +103091 sh->clients = realloc(sh->clients,
92 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
111static ssize_t send_all(struct client *client, void *buf,
112 size_t len, bool block)
113{
114 int fd, rc, flags;
Jeremy Kerr848fc872017-01-17 13:50:05 +0800115 size_t pos;
116
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800117 fd = client->fd;
118
Jeremy Kerr848fc872017-01-17 13:50:05 +0800119 flags = MSG_NOSIGNAL;
120 if (!block)
121 flags |= MSG_DONTWAIT;
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800122
123 for (pos = 0; pos < len; pos += rc) {
Jeremy Kerr848fc872017-01-17 13:50:05 +0800124 rc = send(fd, buf + pos, len - pos, flags);
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800125 if (rc < 0) {
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800126 if (!block && (errno == EAGAIN ||
127 errno == EWOULDBLOCK)) {
128 client_set_blocked(client, true);
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800129 break;
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800130 }
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800131
132 if (errno == EINTR)
133 continue;
134
135 return -1;
136 }
137 if (rc == 0)
138 return -1;
139 }
140
141 return pos;
142}
143
Jeremy Kerr848fc872017-01-17 13:50:05 +0800144/* Drain the queue to the socket and update the queue buffer. If force_len is
145 * set, send at least that many bytes from the queue, possibly while blocking
146 */
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800147static int client_drain_queue(struct client *client, size_t force_len)
Jeremy Kerr848fc872017-01-17 13:50:05 +0800148{
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800149 uint8_t *buf;
Jeremy Kerr848fc872017-01-17 13:50:05 +0800150 ssize_t wlen;
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800151 size_t len, total_len;
Jeremy Kerr848fc872017-01-17 13:50:05 +0800152 bool block;
153
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800154 total_len = 0;
155 wlen = 0;
156 block = !!force_len;
Jeremy Kerr848fc872017-01-17 13:50:05 +0800157
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800158 /* if we're already blocked, no need for the write */
159 if (!block && client->blocked)
160 return 0;
161
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800162 for (;;) {
163 len = ringbuffer_dequeue_peek(client->rbc, total_len, &buf);
164 if (!len)
165 break;
166
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800167 wlen = send_all(client, buf, len, block);
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800168 if (wlen <= 0)
169 break;
170
171 total_len += wlen;
172
173 if (force_len && total_len >= force_len)
174 break;
Jeremy Kerr848fc872017-01-17 13:50:05 +0800175 }
176
Jeremy Kerr848fc872017-01-17 13:50:05 +0800177 if (wlen < 0)
178 return -1;
179
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800180 if (force_len && total_len < force_len)
Jeremy Kerr848fc872017-01-17 13:50:05 +0800181 return -1;
182
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800183 ringbuffer_dequeue_commit(client->rbc, total_len);
Jeremy Kerr848fc872017-01-17 13:50:05 +0800184 return 0;
185}
186
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800187static enum ringbuffer_poll_ret client_ringbuffer_poll(void *arg,
188 size_t force_len)
189{
190 struct client *client = arg;
Johnathan Mantey1cecc5d2019-02-28 15:01:46 -0800191 int rc, len;
192
193 len = ringbuffer_len(client->rbc);
194 if (!force_len && (len < SOCKET_HANDLER_PKT_SIZE)) {
195 /* Do nothing until many small requests have accumulated, or
196 * the UART is idle for awhile (as determined by the timeout
197 * value supplied to the poll function call in console_server.c. */
198 console_poller_set_timeout(client->sh->console, client->poller,
199 &socket_handler_timeout);
200 return RINGBUFFER_POLL_OK;
201 }
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800202
203 rc = client_drain_queue(client, force_len);
204 if (rc) {
205 client->rbc = NULL;
206 client_close(client);
207 return RINGBUFFER_POLL_REMOVE;
208 }
209
210 return RINGBUFFER_POLL_OK;
211}
212
Johnathan Mantey1cecc5d2019-02-28 15:01:46 -0800213static enum poller_ret client_timeout(struct handler *handler, void *data)
214{
215 struct client *client = data;
216 int rc = 0;
217
218 if (client->blocked) {
219 /* nothing to do here, we'll call client_drain_queue when
220 * we become unblocked */
221 return POLLER_OK;
222 }
223
224 rc = client_drain_queue(client, 0);
225 if (rc) {
226 client_close(client);
227 return POLLER_REMOVE;
228 }
229
230 return POLLER_OK;
231}
232
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800233static enum poller_ret client_poll(struct handler *handler,
234 int events, void *data)
235{
236 struct socket_handler *sh = to_socket_handler(handler);
237 struct client *client = data;
238 uint8_t buf[4096];
239 int rc;
240
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800241 if (events & POLLIN) {
Jeremy Kerr68a2ece2017-01-17 13:52:41 +0800242 rc = recv(client->fd, buf, sizeof(buf), MSG_DONTWAIT);
Jeremy Kerr848fc872017-01-17 13:50:05 +0800243 if (rc < 0) {
244 if (errno == EAGAIN || errno == EWOULDBLOCK)
245 return POLLER_OK;
246 else
247 goto err_close;
248 }
249 if (rc == 0)
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800250 goto err_close;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800251
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800252 console_data_out(sh->console, buf, rc);
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800253 }
254
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800255 if (events & POLLOUT) {
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800256 client_set_blocked(client, false);
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800257 rc = client_drain_queue(client, 0);
Jeremy Kerr848fc872017-01-17 13:50:05 +0800258 if (rc)
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800259 goto err_close;
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800260 }
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800261
262 return POLLER_OK;
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800263
264err_close:
265 client->poller = NULL;
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800266 client_close(client);
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800267 return POLLER_REMOVE;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800268}
269
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800270static enum poller_ret socket_poll(struct handler *handler,
271 int events, void __attribute__((unused)) *data)
272{
273 struct socket_handler *sh = to_socket_handler(handler);
274 struct client *client;
275 int fd, n;
276
277 if (!(events & POLLIN))
278 return POLLER_OK;
279
Jeremy Kerr68a2ece2017-01-17 13:52:41 +0800280 fd = accept(sh->sd, NULL, NULL);
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800281 if (fd < 0)
282 return POLLER_OK;
283
Jeremy Kerrce0e68b2016-03-18 13:55:46 +0800284 client = malloc(sizeof(*client));
285 memset(client, 0, sizeof(*client));
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800286
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800287 client->sh = sh;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800288 client->fd = fd;
Jeremy Kerr55c97122017-02-07 17:06:46 +0800289 client->poller = console_poller_register(sh->console, handler,
Johnathan Mantey1cecc5d2019-02-28 15:01:46 -0800290 client_poll, client_timeout, client->fd, POLLIN,
291 client);
Jeremy Kerrf733c852017-02-07 18:40:10 +0800292 client->rbc = console_ringbuffer_consumer_register(sh->console,
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800293 client_ringbuffer_poll, client);
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800294
Jeremy Kerrce0e68b2016-03-18 13:55:46 +0800295 n = sh->n_clients++;
296 sh->clients = realloc(sh->clients,
297 sizeof(*sh->clients) * sh->n_clients);
298 sh->clients[n] = client;
299
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800300 return POLLER_OK;
301
302}
303
Jeremy Kerrd47963e2016-03-16 17:29:55 +0800304static int socket_init(struct handler *handler, struct console *console,
Andrew Jefferyddf2ab72020-02-10 12:36:09 +1030305 struct config *config)
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800306{
307 struct socket_handler *sh = to_socket_handler(handler);
308 struct sockaddr_un addr;
Andrew Jeffery5e7c0782020-02-10 12:12:36 +1030309 size_t addrlen;
310 ssize_t len;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800311 int rc;
312
313 sh->console = console;
314 sh->clients = NULL;
315 sh->n_clients = 0;
Jeremy Kerr5708dfb2017-01-19 15:11:19 +0800316
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800317 sh->sd = socket(AF_UNIX, SOCK_STREAM, 0);
318 if(sh->sd < 0) {
319 warn("Can't create socket");
320 return -1;
321 }
322
323 memset(&addr, 0, sizeof(addr));
324 addr.sun_family = AF_UNIX;
Andrew Jefferyddf2ab72020-02-10 12:36:09 +1030325 len = console_socket_path(&addr, config_get_value(config, "socket-id"));
Andrew Jeffery5e7c0782020-02-10 12:12:36 +1030326 if (len < 0) {
327 if (errno)
328 warn("Failed to configure socket: %s", strerror(errno));
329 else
330 warn("Socket name length exceeds buffer limits");
331 goto cleanup;
332 }
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800333
Andrew Jeffery5e7c0782020-02-10 12:12:36 +1030334 addrlen = sizeof(addr) - sizeof(addr.sun_path) + len;
335
336 rc = bind(sh->sd, (struct sockaddr *)&addr, addrlen);
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800337 if (rc) {
Andrew Jeffery5e7c0782020-02-10 12:12:36 +1030338 socket_path_t name;
339 console_socket_path_readable(&addr, addrlen, name);
340 warn("Can't bind to socket path %s (terminated at first null)",
341 name);
342 goto cleanup;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800343 }
344
345 rc = listen(sh->sd, 1);
346 if (rc) {
347 warn("Can't listen for incoming connections");
Andrew Jeffery5e7c0782020-02-10 12:12:36 +1030348 goto cleanup;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800349 }
350
Jeremy Kerr55c97122017-02-07 17:06:46 +0800351 sh->poller = console_poller_register(console, handler, socket_poll,
Johnathan Mantey1cecc5d2019-02-28 15:01:46 -0800352 NULL, sh->sd, POLLIN, NULL);
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800353
354 return 0;
Andrew Jeffery5e7c0782020-02-10 12:12:36 +1030355cleanup:
356 close(sh->sd);
357 return -1;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800358}
359
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800360static void socket_fini(struct handler *handler)
361{
362 struct socket_handler *sh = to_socket_handler(handler);
Jeremy Kerr89ea8192016-03-15 17:57:43 +0800363
Jeremy Kerrabd8e252017-01-19 15:42:48 +0800364 while (sh->n_clients)
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800365 client_close(sh->clients[0]);
Jeremy Kerr89ea8192016-03-15 17:57:43 +0800366
367 if (sh->poller)
Jeremy Kerr55c97122017-02-07 17:06:46 +0800368 console_poller_unregister(sh->console, sh->poller);
Jeremy Kerr89ea8192016-03-15 17:57:43 +0800369
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800370 close(sh->sd);
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800371}
372
373static struct socket_handler socket_handler = {
374 .handler = {
375 .name = "socket",
376 .init = socket_init,
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800377 .fini = socket_fini,
378 },
379};
380
Jeremy Kerr55c97122017-02-07 17:06:46 +0800381console_handler_register(&socket_handler.handler);
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800382