blob: 84cd55a4423cad9bf21af968d42f4cc31f97820d [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
35struct client {
Jeremy Kerrc9775ce2017-02-07 16:25:34 +080036 struct socket_handler *sh;
37 struct poller *poller;
38 struct ringbuffer_consumer *rbc;
39 int fd;
Jeremy Kerr6b1fed22017-02-07 21:40:38 +080040 bool blocked;
Jeremy Kerr2bd05182016-03-10 16:59:43 +080041};
42
43struct socket_handler {
Jeremy Kerrc9775ce2017-02-07 16:25:34 +080044 struct handler handler;
45 struct console *console;
46 struct poller *poller;
Jeremy Kerrc9775ce2017-02-07 16:25:34 +080047 int sd;
Jeremy Kerr2bd05182016-03-10 16:59:43 +080048
Jeremy Kerrc9775ce2017-02-07 16:25:34 +080049 struct client **clients;
50 int n_clients;
Jeremy Kerr2bd05182016-03-10 16:59:43 +080051};
52
53static struct socket_handler *to_socket_handler(struct handler *handler)
54{
55 return container_of(handler, struct socket_handler, handler);
56}
57
Jeremy Kerrc9775ce2017-02-07 16:25:34 +080058static void client_close(struct client *client)
Jeremy Kerr2bd05182016-03-10 16:59:43 +080059{
Jeremy Kerrc9775ce2017-02-07 16:25:34 +080060 struct socket_handler *sh = client->sh;
Jeremy Kerr2bd05182016-03-10 16:59:43 +080061 int idx;
62
63 close(client->fd);
64 if (client->poller)
Jeremy Kerr55c97122017-02-07 17:06:46 +080065 console_poller_unregister(sh->console, client->poller);
Jeremy Kerr2bd05182016-03-10 16:59:43 +080066
Jeremy Kerrc9775ce2017-02-07 16:25:34 +080067 if (client->rbc)
68 ringbuffer_consumer_unregister(client->rbc);
69
Jeremy Kerrce0e68b2016-03-18 13:55:46 +080070 for (idx = 0; idx < sh->n_clients; idx++)
71 if (sh->clients[idx] == client)
72 break;
73
74 assert(idx < sh->n_clients);
75
76 free(client);
77 client = NULL;
Jeremy Kerr2bd05182016-03-10 16:59:43 +080078
79 sh->n_clients--;
80 memmove(&sh->clients[idx], &sh->clients[idx+1],
81 sizeof(*sh->clients) * (sh->n_clients - idx));
Joel Stanleyfbff1c62016-03-17 20:32:24 +103082 sh->clients = realloc(sh->clients,
83 sizeof(*sh->clients) * sh->n_clients);
Jeremy Kerr2bd05182016-03-10 16:59:43 +080084}
85
Jeremy Kerr6b1fed22017-02-07 21:40:38 +080086static void client_set_blocked(struct client *client, bool blocked)
Jeremy Kerr848fc872017-01-17 13:50:05 +080087{
Jeremy Kerr6b1fed22017-02-07 21:40:38 +080088 int events;
89
90 if (client->blocked == blocked)
91 return;
92
93 client->blocked = blocked;
94
95 events = POLLIN;
96 if (client->blocked)
97 events |= POLLOUT;
98
99 console_poller_set_events(client->sh->console, client->poller, events);
100}
101
102static ssize_t send_all(struct client *client, void *buf,
103 size_t len, bool block)
104{
105 int fd, rc, flags;
Jeremy Kerr848fc872017-01-17 13:50:05 +0800106 size_t pos;
107
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800108 fd = client->fd;
109
Jeremy Kerr848fc872017-01-17 13:50:05 +0800110 flags = MSG_NOSIGNAL;
111 if (!block)
112 flags |= MSG_DONTWAIT;
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800113
114 for (pos = 0; pos < len; pos += rc) {
Jeremy Kerr848fc872017-01-17 13:50:05 +0800115 rc = send(fd, buf + pos, len - pos, flags);
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800116 if (rc < 0) {
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800117 if (!block && (errno == EAGAIN ||
118 errno == EWOULDBLOCK)) {
119 client_set_blocked(client, true);
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800120 break;
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800121 }
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800122
123 if (errno == EINTR)
124 continue;
125
126 return -1;
127 }
128 if (rc == 0)
129 return -1;
130 }
131
132 return pos;
133}
134
Jeremy Kerr848fc872017-01-17 13:50:05 +0800135/* Drain the queue to the socket and update the queue buffer. If force_len is
136 * set, send at least that many bytes from the queue, possibly while blocking
137 */
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800138static int client_drain_queue(struct client *client, size_t force_len)
Jeremy Kerr848fc872017-01-17 13:50:05 +0800139{
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800140 uint8_t *buf;
Jeremy Kerr848fc872017-01-17 13:50:05 +0800141 ssize_t wlen;
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800142 size_t len, total_len;
Jeremy Kerr848fc872017-01-17 13:50:05 +0800143 bool block;
144
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800145 total_len = 0;
146 wlen = 0;
147 block = !!force_len;
Jeremy Kerr848fc872017-01-17 13:50:05 +0800148
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800149 /* if we're already blocked, no need for the write */
150 if (!block && client->blocked)
151 return 0;
152
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800153 for (;;) {
154 len = ringbuffer_dequeue_peek(client->rbc, total_len, &buf);
155 if (!len)
156 break;
157
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800158 wlen = send_all(client, buf, len, block);
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800159 if (wlen <= 0)
160 break;
161
162 total_len += wlen;
163
164 if (force_len && total_len >= force_len)
165 break;
Jeremy Kerr848fc872017-01-17 13:50:05 +0800166 }
167
Jeremy Kerr848fc872017-01-17 13:50:05 +0800168 if (wlen < 0)
169 return -1;
170
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800171 if (force_len && total_len < force_len)
Jeremy Kerr848fc872017-01-17 13:50:05 +0800172 return -1;
173
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800174 ringbuffer_dequeue_commit(client->rbc, total_len);
Jeremy Kerr848fc872017-01-17 13:50:05 +0800175 return 0;
176}
177
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800178static enum ringbuffer_poll_ret client_ringbuffer_poll(void *arg,
179 size_t force_len)
180{
181 struct client *client = arg;
182 int rc;
183
184 rc = client_drain_queue(client, force_len);
185 if (rc) {
186 client->rbc = NULL;
187 client_close(client);
188 return RINGBUFFER_POLL_REMOVE;
189 }
190
191 return RINGBUFFER_POLL_OK;
192}
193
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800194static enum poller_ret client_poll(struct handler *handler,
195 int events, void *data)
196{
197 struct socket_handler *sh = to_socket_handler(handler);
198 struct client *client = data;
199 uint8_t buf[4096];
200 int rc;
201
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800202 if (events & POLLIN) {
Jeremy Kerr68a2ece2017-01-17 13:52:41 +0800203 rc = recv(client->fd, buf, sizeof(buf), MSG_DONTWAIT);
Jeremy Kerr848fc872017-01-17 13:50:05 +0800204 if (rc < 0) {
205 if (errno == EAGAIN || errno == EWOULDBLOCK)
206 return POLLER_OK;
207 else
208 goto err_close;
209 }
210 if (rc == 0)
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800211 goto err_close;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800212
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800213 console_data_out(sh->console, buf, rc);
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800214 }
215
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800216 if (events & POLLOUT) {
Jeremy Kerr6b1fed22017-02-07 21:40:38 +0800217 client_set_blocked(client, false);
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800218 rc = client_drain_queue(client, 0);
Jeremy Kerr848fc872017-01-17 13:50:05 +0800219 if (rc)
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800220 goto err_close;
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800221 }
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800222
223 return POLLER_OK;
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800224
225err_close:
226 client->poller = NULL;
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800227 client_close(client);
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800228 return POLLER_REMOVE;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800229}
230
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800231static enum poller_ret socket_poll(struct handler *handler,
232 int events, void __attribute__((unused)) *data)
233{
234 struct socket_handler *sh = to_socket_handler(handler);
235 struct client *client;
236 int fd, n;
237
238 if (!(events & POLLIN))
239 return POLLER_OK;
240
Jeremy Kerr68a2ece2017-01-17 13:52:41 +0800241 fd = accept(sh->sd, NULL, NULL);
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800242 if (fd < 0)
243 return POLLER_OK;
244
Jeremy Kerrce0e68b2016-03-18 13:55:46 +0800245 client = malloc(sizeof(*client));
246 memset(client, 0, sizeof(*client));
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800247
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800248 client->sh = sh;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800249 client->fd = fd;
Jeremy Kerr55c97122017-02-07 17:06:46 +0800250 client->poller = console_poller_register(sh->console, handler,
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800251 client_poll, client->fd, POLLIN, client);
Jeremy Kerrf733c852017-02-07 18:40:10 +0800252 client->rbc = console_ringbuffer_consumer_register(sh->console,
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800253 client_ringbuffer_poll, client);
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800254
Jeremy Kerrce0e68b2016-03-18 13:55:46 +0800255 n = sh->n_clients++;
256 sh->clients = realloc(sh->clients,
257 sizeof(*sh->clients) * sh->n_clients);
258 sh->clients[n] = client;
259
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800260 return POLLER_OK;
261
262}
263
Jeremy Kerrd47963e2016-03-16 17:29:55 +0800264static int socket_init(struct handler *handler, struct console *console,
265 struct config *config __attribute__((unused)))
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800266{
267 struct socket_handler *sh = to_socket_handler(handler);
268 struct sockaddr_un addr;
269 int rc;
270
271 sh->console = console;
272 sh->clients = NULL;
273 sh->n_clients = 0;
Jeremy Kerr5708dfb2017-01-19 15:11:19 +0800274
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800275 sh->sd = socket(AF_UNIX, SOCK_STREAM, 0);
276 if(sh->sd < 0) {
277 warn("Can't create socket");
278 return -1;
279 }
280
281 memset(&addr, 0, sizeof(addr));
282 addr.sun_family = AF_UNIX;
Jeremy Kerr0cff6522016-03-18 09:57:01 +0800283 memcpy(&addr.sun_path, &console_socket_path, console_socket_path_len);
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800284
285 rc = bind(sh->sd, (struct sockaddr *)&addr, sizeof(addr));
286 if (rc) {
287 warn("Can't bind to socket path %s",
288 console_socket_path_readable);
289 return -1;
290 }
291
292 rc = listen(sh->sd, 1);
293 if (rc) {
294 warn("Can't listen for incoming connections");
295 return -1;
296 }
297
Jeremy Kerr55c97122017-02-07 17:06:46 +0800298 sh->poller = console_poller_register(console, handler, socket_poll,
Jeremy Kerr89ea8192016-03-15 17:57:43 +0800299 sh->sd, POLLIN, NULL);
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800300
301 return 0;
302}
303
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800304static void socket_fini(struct handler *handler)
305{
306 struct socket_handler *sh = to_socket_handler(handler);
Jeremy Kerr89ea8192016-03-15 17:57:43 +0800307
Jeremy Kerrabd8e252017-01-19 15:42:48 +0800308 while (sh->n_clients)
Jeremy Kerrc9775ce2017-02-07 16:25:34 +0800309 client_close(sh->clients[0]);
Jeremy Kerr89ea8192016-03-15 17:57:43 +0800310
311 if (sh->poller)
Jeremy Kerr55c97122017-02-07 17:06:46 +0800312 console_poller_unregister(sh->console, sh->poller);
Jeremy Kerr89ea8192016-03-15 17:57:43 +0800313
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800314 close(sh->sd);
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800315}
316
317static struct socket_handler socket_handler = {
318 .handler = {
319 .name = "socket",
320 .init = socket_init,
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800321 .fini = socket_fini,
322 },
323};
324
Jeremy Kerr55c97122017-02-07 17:06:46 +0800325console_handler_register(&socket_handler.handler);
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800326