xref: /openbmc/obmc-console/socket-handler.c (revision fcf8541b87c13d4fe02d1fc4812b7f6df92c8c27)
1 /**
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  */
16 
17 #define _GNU_SOURCE
18 
19 #include <assert.h>
20 #include <err.h>
21 #include <errno.h>
22 #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 
35 struct client {
36 	struct socket_handler		*sh;
37 	struct poller			*poller;
38 	struct ringbuffer_consumer	*rbc;
39 	int				fd;
40 	bool				blocked;
41 };
42 
43 struct socket_handler {
44 	struct handler		handler;
45 	struct console		*console;
46 	struct poller		*poller;
47 	int			sd;
48 
49 	struct client		**clients;
50 	int			n_clients;
51 };
52 
53 static struct socket_handler *to_socket_handler(struct handler *handler)
54 {
55 	return container_of(handler, struct socket_handler, handler);
56 }
57 
58 static void client_close(struct client *client)
59 {
60 	struct socket_handler *sh = client->sh;
61 	int idx;
62 
63 	close(client->fd);
64 	if (client->poller)
65 		console_poller_unregister(sh->console, client->poller);
66 
67 	if (client->rbc)
68 		ringbuffer_consumer_unregister(client->rbc);
69 
70 	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;
78 
79 	sh->n_clients--;
80 	memmove(&sh->clients[idx], &sh->clients[idx+1],
81 			sizeof(*sh->clients) * (sh->n_clients - idx));
82 	sh->clients = realloc(sh->clients,
83 			sizeof(*sh->clients) * sh->n_clients);
84 }
85 
86 static void client_set_blocked(struct client *client, bool blocked)
87 {
88 	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 
102 static ssize_t send_all(struct client *client, void *buf,
103 		size_t len, bool block)
104 {
105 	int fd, rc, flags;
106 	size_t pos;
107 
108 	fd = client->fd;
109 
110 	flags = MSG_NOSIGNAL;
111 	if (!block)
112 		flags |= MSG_DONTWAIT;
113 
114 	for (pos = 0; pos < len; pos += rc) {
115 		rc = send(fd, buf + pos, len - pos, flags);
116 		if (rc < 0) {
117 			if (!block && (errno == EAGAIN ||
118 						errno == EWOULDBLOCK)) {
119 				client_set_blocked(client, true);
120 				break;
121 			}
122 
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 
135 /* 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  */
138 static int client_drain_queue(struct client *client, size_t force_len)
139 {
140 	uint8_t *buf;
141 	ssize_t wlen;
142 	size_t len, total_len;
143 	bool block;
144 
145 	total_len = 0;
146 	wlen = 0;
147 	block = !!force_len;
148 
149 	/* if we're already blocked, no need for the write */
150 	if (!block && client->blocked)
151 		return 0;
152 
153 	for (;;) {
154 		len = ringbuffer_dequeue_peek(client->rbc, total_len, &buf);
155 		if (!len)
156 			break;
157 
158 		wlen = send_all(client, buf, len, block);
159 		if (wlen <= 0)
160 			break;
161 
162 		total_len += wlen;
163 
164 		if (force_len && total_len >= force_len)
165 			break;
166 	}
167 
168 	if (wlen < 0)
169 		return -1;
170 
171 	if (force_len && total_len < force_len)
172 		return -1;
173 
174 	ringbuffer_dequeue_commit(client->rbc, total_len);
175 	return 0;
176 }
177 
178 static 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 
194 static 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 
202 	if (events & POLLIN) {
203 		rc = recv(client->fd, buf, sizeof(buf), MSG_DONTWAIT);
204 		if (rc < 0) {
205 			if (errno == EAGAIN || errno == EWOULDBLOCK)
206 				return POLLER_OK;
207 			else
208 				goto err_close;
209 		}
210 		if (rc == 0)
211 			goto err_close;
212 
213 		console_data_out(sh->console, buf, rc);
214 	}
215 
216 	if (events & POLLOUT) {
217 		client_set_blocked(client, false);
218 		rc = client_drain_queue(client, 0);
219 		if (rc)
220 			goto err_close;
221 	}
222 
223 	return POLLER_OK;
224 
225 err_close:
226 	client->poller = NULL;
227 	client_close(client);
228 	return POLLER_REMOVE;
229 }
230 
231 static 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 
241 	fd = accept(sh->sd, NULL, NULL);
242 	if (fd < 0)
243 		return POLLER_OK;
244 
245 	client = malloc(sizeof(*client));
246 	memset(client, 0, sizeof(*client));
247 
248 	client->sh = sh;
249 	client->fd = fd;
250 	client->poller = console_poller_register(sh->console, handler,
251 			client_poll, client->fd, POLLIN, client);
252 	client->rbc = console_ringbuffer_consumer_register(sh->console,
253 			client_ringbuffer_poll, client);
254 
255 	n = sh->n_clients++;
256 	sh->clients = realloc(sh->clients,
257 			sizeof(*sh->clients) * sh->n_clients);
258 	sh->clients[n] = client;
259 
260 	return POLLER_OK;
261 
262 }
263 
264 static int socket_init(struct handler *handler, struct console *console,
265 		struct config *config __attribute__((unused)))
266 {
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;
274 
275 	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;
283 	memcpy(&addr.sun_path, &console_socket_path, console_socket_path_len);
284 
285 	rc = bind(sh->sd, (struct sockaddr *)&addr,
286 			sizeof(addr) - sizeof(addr.sun_path) + console_socket_path_len);
287 	if (rc) {
288 		warn("Can't bind to socket path %s",
289 				console_socket_path_readable);
290 		return -1;
291 	}
292 
293 	rc = listen(sh->sd, 1);
294 	if (rc) {
295 		warn("Can't listen for incoming connections");
296 		return -1;
297 	}
298 
299 	sh->poller = console_poller_register(console, handler, socket_poll,
300 			sh->sd, POLLIN, NULL);
301 
302 	return 0;
303 }
304 
305 static void socket_fini(struct handler *handler)
306 {
307 	struct socket_handler *sh = to_socket_handler(handler);
308 
309 	while (sh->n_clients)
310 		client_close(sh->clients[0]);
311 
312 	if (sh->poller)
313 		console_poller_unregister(sh->console, sh->poller);
314 
315 	close(sh->sd);
316 }
317 
318 static struct socket_handler socket_handler = {
319 	.handler = {
320 		.name		= "socket",
321 		.init		= socket_init,
322 		.fini		= socket_fini,
323 	},
324 };
325 
326 console_handler_register(&socket_handler.handler);
327 
328