blob: d9888b924a5e01c693ba45c2f8ee489bddb88aa9 [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
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +080035const size_t buffer_size_max = 100 * 1024;
36
Jeremy Kerr2bd05182016-03-10 16:59:43 +080037struct client {
38 struct poller *poller;
39 int fd;
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +080040 uint8_t *buf;
41 size_t buf_alloc;
42 size_t buf_len;
Jeremy Kerr2bd05182016-03-10 16:59:43 +080043};
44
45struct socket_handler {
46 struct handler handler;
47 struct console *console;
Jeremy Kerr89ea8192016-03-15 17:57:43 +080048 struct poller *poller;
Jeremy Kerr2bd05182016-03-10 16:59:43 +080049 int sd;
50
Jeremy Kerrce0e68b2016-03-18 13:55:46 +080051 struct client **clients;
Jeremy Kerr2bd05182016-03-10 16:59:43 +080052 int n_clients;
53};
54
55static struct socket_handler *to_socket_handler(struct handler *handler)
56{
57 return container_of(handler, struct socket_handler, handler);
58}
59
60static void client_close(struct socket_handler *sh, struct client *client)
61{
62 int idx;
63
64 close(client->fd);
65 if (client->poller)
66 console_unregister_poller(sh->console, client->poller);
67
Jeremy Kerrce0e68b2016-03-18 13:55:46 +080068 for (idx = 0; idx < sh->n_clients; idx++)
69 if (sh->clients[idx] == client)
70 break;
71
72 assert(idx < sh->n_clients);
73
74 free(client);
75 client = NULL;
Jeremy Kerr2bd05182016-03-10 16:59:43 +080076
77 sh->n_clients--;
78 memmove(&sh->clients[idx], &sh->clients[idx+1],
79 sizeof(*sh->clients) * (sh->n_clients - idx));
Joel Stanleyfbff1c62016-03-17 20:32:24 +103080 sh->clients = realloc(sh->clients,
81 sizeof(*sh->clients) * sh->n_clients);
Jeremy Kerr2bd05182016-03-10 16:59:43 +080082}
83
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +080084/* Write data to the client, until error or block.
85 *
86 * Returns -1 on hard failure, otherwise number of bytes written. A zero
87 * return indicates that no bytes were written due to potential block,
88 * but isn't a failure
89 */
Jeremy Kerr68a2ece2017-01-17 13:52:41 +080090static ssize_t client_send_data(struct client *client, uint8_t *buf,
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +080091 size_t len)
92{
93 size_t pos;
94 ssize_t rc;
Jeremy Kerr243cab32017-01-17 13:54:54 +080095 int flags;
96
97 flags = MSG_DONTWAIT | MSG_NOSIGNAL;
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +080098
99 for (pos = 0; pos < len; pos += rc) {
Jeremy Kerr243cab32017-01-17 13:54:54 +0800100 rc = send(client->fd, buf + pos, len - pos, flags);
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800101 if (rc < 0) {
102 if (errno == EAGAIN || errno == EWOULDBLOCK)
103 break;
104
105 if (errno == EINTR)
106 continue;
107
108 return -1;
109 }
110 if (rc == 0)
111 return -1;
112 }
113
114 return pos;
115}
116
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800117static enum poller_ret client_poll(struct handler *handler,
118 int events, void *data)
119{
120 struct socket_handler *sh = to_socket_handler(handler);
121 struct client *client = data;
122 uint8_t buf[4096];
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800123 ssize_t len;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800124 int rc;
125
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800126 if (events & POLLIN) {
Jeremy Kerr68a2ece2017-01-17 13:52:41 +0800127 rc = recv(client->fd, buf, sizeof(buf), MSG_DONTWAIT);
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800128 if (rc <= 0)
129 goto err_close;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800130
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800131 console_data_out(sh->console, buf, rc);
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800132 }
133
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800134 if (events & POLLOUT) {
Jeremy Kerr68a2ece2017-01-17 13:52:41 +0800135 len = client_send_data(client, client->buf, client->buf_len);
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800136 if (len < 0)
137 goto err_close;
138
139 /* consume from the queue */
140 client->buf_len -= len;
141 memmove(client->buf, client->buf + len,
142 client->buf_len);
143 }
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800144
145 return POLLER_OK;
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800146
147err_close:
148 client->poller = NULL;
149 client_close(sh, client);
150 return POLLER_REMOVE;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800151}
152
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800153static int client_queue_data(struct client *client, uint8_t *buf, size_t len)
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800154{
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800155 if (client->buf_len + len > client->buf_alloc) {
156 if (!client->buf_alloc)
157 client->buf_alloc = 2048;
158 client->buf_alloc *= 2;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800159
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800160 if (client->buf_alloc > buffer_size_max)
161 return -1;
162
163 client->buf = realloc(client->buf, client->buf_alloc);
164 }
165
166 memcpy(client->buf + client->buf_len, buf, len);
167 client->buf_len += len;
168 return 0;
169}
170
171static int client_send_or_queue(struct client *client, uint8_t *buf, size_t len)
172{
173 ssize_t rc;
174
Jeremy Kerr68a2ece2017-01-17 13:52:41 +0800175 /* only send if the queue is empty */
Jeremy Kerr9c297af2017-01-17 09:35:21 +0800176 if (!client->buf_len) {
Jeremy Kerr68a2ece2017-01-17 13:52:41 +0800177 rc = client_send_data(client, buf, len);
Jeremy Kerr9c297af2017-01-17 09:35:21 +0800178 if (rc < 0)
179 return -1;
180 } else {
181 rc = 0;
182 }
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800183
184 if ((size_t)rc < len) {
185 rc = client_queue_data(client, buf + rc, len - rc);
186 if (rc)
187 return -1;
188 }
189
190 return 0;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800191}
192
193static enum poller_ret socket_poll(struct handler *handler,
194 int events, void __attribute__((unused)) *data)
195{
196 struct socket_handler *sh = to_socket_handler(handler);
197 struct client *client;
198 int fd, n;
199
200 if (!(events & POLLIN))
201 return POLLER_OK;
202
Jeremy Kerr68a2ece2017-01-17 13:52:41 +0800203 fd = accept(sh->sd, NULL, NULL);
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800204 if (fd < 0)
205 return POLLER_OK;
206
Jeremy Kerrce0e68b2016-03-18 13:55:46 +0800207 client = malloc(sizeof(*client));
208 memset(client, 0, sizeof(*client));
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800209
210 client->fd = fd;
211 client->poller = console_register_poller(sh->console, handler,
212 client_poll, client->fd, POLLIN, client);
213
Jeremy Kerrce0e68b2016-03-18 13:55:46 +0800214 n = sh->n_clients++;
215 sh->clients = realloc(sh->clients,
216 sizeof(*sh->clients) * sh->n_clients);
217 sh->clients[n] = client;
218
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800219 return POLLER_OK;
220
221}
222
Jeremy Kerrd47963e2016-03-16 17:29:55 +0800223static int socket_init(struct handler *handler, struct console *console,
224 struct config *config __attribute__((unused)))
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800225{
226 struct socket_handler *sh = to_socket_handler(handler);
227 struct sockaddr_un addr;
228 int rc;
229
230 sh->console = console;
231 sh->clients = NULL;
232 sh->n_clients = 0;
233
234 sh->sd = socket(AF_UNIX, SOCK_STREAM, 0);
235 if(sh->sd < 0) {
236 warn("Can't create socket");
237 return -1;
238 }
239
240 memset(&addr, 0, sizeof(addr));
241 addr.sun_family = AF_UNIX;
Jeremy Kerr0cff6522016-03-18 09:57:01 +0800242 memcpy(&addr.sun_path, &console_socket_path, console_socket_path_len);
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800243
244 rc = bind(sh->sd, (struct sockaddr *)&addr, sizeof(addr));
245 if (rc) {
246 warn("Can't bind to socket path %s",
247 console_socket_path_readable);
248 return -1;
249 }
250
251 rc = listen(sh->sd, 1);
252 if (rc) {
253 warn("Can't listen for incoming connections");
254 return -1;
255 }
256
Jeremy Kerr89ea8192016-03-15 17:57:43 +0800257 sh->poller = console_register_poller(console, handler, socket_poll,
258 sh->sd, POLLIN, NULL);
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800259
260 return 0;
261}
262
263static int socket_data(struct handler *handler, uint8_t *buf, size_t len)
264{
265 struct socket_handler *sh = to_socket_handler(handler);
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800266 int i, rc;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800267
268 for (i = 0; i < sh->n_clients; i++) {
Jeremy Kerrce0e68b2016-03-18 13:55:46 +0800269 struct client *client = sh->clients[i];
Jeremy Kerr4d80a5b2016-03-18 13:47:43 +0800270 rc = client_send_or_queue(client, buf, len);
271 if (!rc)
272 continue;
273
274 /* if we failed to send data, close the client. This will
275 * remove it from the clients array, so skip back to the item
276 * that has taken its place
277 */
278 client_close(sh, client);
279 i--;
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800280 }
281 return 0;
282}
283
284static void socket_fini(struct handler *handler)
285{
286 struct socket_handler *sh = to_socket_handler(handler);
Jeremy Kerr89ea8192016-03-15 17:57:43 +0800287 int i;
288
289 for (i = 0; i < sh->n_clients; i++)
Jeremy Kerrce0e68b2016-03-18 13:55:46 +0800290 client_close(sh, sh->clients[i]);
Jeremy Kerr89ea8192016-03-15 17:57:43 +0800291
292 if (sh->poller)
293 console_unregister_poller(sh->console, sh->poller);
294
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800295 close(sh->sd);
296}
297
298static struct socket_handler socket_handler = {
299 .handler = {
300 .name = "socket",
301 .init = socket_init,
302 .data_in = socket_data,
303 .fini = socket_fini,
304 },
305};
306
307console_register_handler(&socket_handler.handler);
308