blob: 7be9c71536691ab0fc5fafe74ce6a92d0b5bc973 [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
17#include <err.h>
18#include <stdbool.h>
19#include <stdio.h>
20#include <stdlib.h>
21#include <string.h>
22#include <termios.h>
23#include <unistd.h>
24#include <endian.h>
25
26#include <sys/socket.h>
27#include <sys/un.h>
28
29#include "console-server.h"
30
31struct client {
32 struct poller *poller;
33 int fd;
34};
35
36struct socket_handler {
37 struct handler handler;
38 struct console *console;
Jeremy Kerr89ea8192016-03-15 17:57:43 +080039 struct poller *poller;
Jeremy Kerr2bd05182016-03-10 16:59:43 +080040 int sd;
41
42 struct client *clients;
43 int n_clients;
44};
45
46static struct socket_handler *to_socket_handler(struct handler *handler)
47{
48 return container_of(handler, struct socket_handler, handler);
49}
50
51static void client_close(struct socket_handler *sh, struct client *client)
52{
53 int idx;
54
55 close(client->fd);
56 if (client->poller)
57 console_unregister_poller(sh->console, client->poller);
58
59 idx = client - sh->clients;
60
61 sh->n_clients--;
62 memmove(&sh->clients[idx], &sh->clients[idx+1],
63 sizeof(*sh->clients) * (sh->n_clients - idx));
Joel Stanleyfbff1c62016-03-17 20:32:24 +103064 sh->clients = realloc(sh->clients,
65 sizeof(*sh->clients) * sh->n_clients);
Jeremy Kerr2bd05182016-03-10 16:59:43 +080066}
67
68static enum poller_ret client_poll(struct handler *handler,
69 int events, void *data)
70{
71 struct socket_handler *sh = to_socket_handler(handler);
72 struct client *client = data;
73 uint8_t buf[4096];
74 int rc;
75
76 if (!(events & POLLIN))
77 return POLLER_OK;
78
79 rc = read(client->fd, buf, sizeof(buf));
80 if (rc <= 0) {
81 client->poller = NULL;
82 client_close(sh, client);
83 return POLLER_REMOVE;
84 }
85
86 console_data_out(sh->console, buf, rc);
87
88 return POLLER_OK;
89}
90
91static void client_send_data(struct socket_handler *sh,
92 struct client *client, uint8_t *buf, size_t len)
93{
94 int rc;
95
96 rc = write_buf_to_fd(client->fd, buf, len);
97 if (rc)
98 client_close(sh, client);
99}
100
101static enum poller_ret socket_poll(struct handler *handler,
102 int events, void __attribute__((unused)) *data)
103{
104 struct socket_handler *sh = to_socket_handler(handler);
105 struct client *client;
106 int fd, n;
107
108 if (!(events & POLLIN))
109 return POLLER_OK;
110
111 fd = accept(sh->sd, NULL, NULL);
112 if (fd < 0)
113 return POLLER_OK;
114
115 n = sh->n_clients++;
116 sh->clients = realloc(sh->clients, sizeof(*client) * sh->n_clients);
117 client = &sh->clients[n];
118
119 client->fd = fd;
120 client->poller = console_register_poller(sh->console, handler,
121 client_poll, client->fd, POLLIN, client);
122
123 return POLLER_OK;
124
125}
126
Jeremy Kerrd47963e2016-03-16 17:29:55 +0800127static int socket_init(struct handler *handler, struct console *console,
128 struct config *config __attribute__((unused)))
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800129{
130 struct socket_handler *sh = to_socket_handler(handler);
131 struct sockaddr_un addr;
132 int rc;
133
134 sh->console = console;
135 sh->clients = NULL;
136 sh->n_clients = 0;
137
138 sh->sd = socket(AF_UNIX, SOCK_STREAM, 0);
139 if(sh->sd < 0) {
140 warn("Can't create socket");
141 return -1;
142 }
143
144 memset(&addr, 0, sizeof(addr));
145 addr.sun_family = AF_UNIX;
Jeremy Kerr0cff6522016-03-18 09:57:01 +0800146 memcpy(&addr.sun_path, &console_socket_path, console_socket_path_len);
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800147
148 rc = bind(sh->sd, (struct sockaddr *)&addr, sizeof(addr));
149 if (rc) {
150 warn("Can't bind to socket path %s",
151 console_socket_path_readable);
152 return -1;
153 }
154
155 rc = listen(sh->sd, 1);
156 if (rc) {
157 warn("Can't listen for incoming connections");
158 return -1;
159 }
160
Jeremy Kerr89ea8192016-03-15 17:57:43 +0800161 sh->poller = console_register_poller(console, handler, socket_poll,
162 sh->sd, POLLIN, NULL);
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800163
164 return 0;
165}
166
167static int socket_data(struct handler *handler, uint8_t *buf, size_t len)
168{
169 struct socket_handler *sh = to_socket_handler(handler);
170 int i;
171
172 for (i = 0; i < sh->n_clients; i++) {
173 struct client *client = &sh->clients[i];
174 client_send_data(sh, client, buf, len);
175 }
176 return 0;
177}
178
179static void socket_fini(struct handler *handler)
180{
181 struct socket_handler *sh = to_socket_handler(handler);
Jeremy Kerr89ea8192016-03-15 17:57:43 +0800182 int i;
183
184 for (i = 0; i < sh->n_clients; i++)
185 client_close(sh, &sh->clients[i]);
186
187 if (sh->poller)
188 console_unregister_poller(sh->console, sh->poller);
189
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800190 close(sh->sd);
191}
192
193static struct socket_handler socket_handler = {
194 .handler = {
195 .name = "socket",
196 .init = socket_init,
197 .data_in = socket_data,
198 .fini = socket_fini,
199 },
200};
201
202console_register_handler(&socket_handler.handler);
203