blob: 2e4f5c2be3b12a92d61108c0352c26a6b429f77b [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 Kerrce0e68b2016-03-18 13:55:46 +080017
18#include <assert.h>
Jeremy Kerr2bd05182016-03-10 16:59:43 +080019#include <err.h>
20#include <stdbool.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24#include <termios.h>
25#include <unistd.h>
26#include <endian.h>
27
28#include <sys/socket.h>
29#include <sys/un.h>
30
31#include "console-server.h"
32
33struct client {
34 struct poller *poller;
35 int fd;
36};
37
38struct socket_handler {
39 struct handler handler;
40 struct console *console;
Jeremy Kerr89ea8192016-03-15 17:57:43 +080041 struct poller *poller;
Jeremy Kerr2bd05182016-03-10 16:59:43 +080042 int sd;
43
Jeremy Kerrce0e68b2016-03-18 13:55:46 +080044 struct client **clients;
Jeremy Kerr2bd05182016-03-10 16:59:43 +080045 int n_clients;
46};
47
48static struct socket_handler *to_socket_handler(struct handler *handler)
49{
50 return container_of(handler, struct socket_handler, handler);
51}
52
53static void client_close(struct socket_handler *sh, struct client *client)
54{
55 int idx;
56
57 close(client->fd);
58 if (client->poller)
59 console_unregister_poller(sh->console, client->poller);
60
Jeremy Kerrce0e68b2016-03-18 13:55:46 +080061 for (idx = 0; idx < sh->n_clients; idx++)
62 if (sh->clients[idx] == client)
63 break;
64
65 assert(idx < sh->n_clients);
66
67 free(client);
68 client = NULL;
Jeremy Kerr2bd05182016-03-10 16:59:43 +080069
70 sh->n_clients--;
71 memmove(&sh->clients[idx], &sh->clients[idx+1],
72 sizeof(*sh->clients) * (sh->n_clients - idx));
Joel Stanleyfbff1c62016-03-17 20:32:24 +103073 sh->clients = realloc(sh->clients,
74 sizeof(*sh->clients) * sh->n_clients);
Jeremy Kerr2bd05182016-03-10 16:59:43 +080075}
76
77static enum poller_ret client_poll(struct handler *handler,
78 int events, void *data)
79{
80 struct socket_handler *sh = to_socket_handler(handler);
81 struct client *client = data;
82 uint8_t buf[4096];
83 int rc;
84
85 if (!(events & POLLIN))
86 return POLLER_OK;
87
88 rc = read(client->fd, buf, sizeof(buf));
89 if (rc <= 0) {
90 client->poller = NULL;
91 client_close(sh, client);
92 return POLLER_REMOVE;
93 }
94
95 console_data_out(sh->console, buf, rc);
96
97 return POLLER_OK;
98}
99
100static void client_send_data(struct socket_handler *sh,
101 struct client *client, uint8_t *buf, size_t len)
102{
103 int rc;
104
105 rc = write_buf_to_fd(client->fd, buf, len);
106 if (rc)
107 client_close(sh, client);
108}
109
110static enum poller_ret socket_poll(struct handler *handler,
111 int events, void __attribute__((unused)) *data)
112{
113 struct socket_handler *sh = to_socket_handler(handler);
114 struct client *client;
115 int fd, n;
116
117 if (!(events & POLLIN))
118 return POLLER_OK;
119
120 fd = accept(sh->sd, NULL, NULL);
121 if (fd < 0)
122 return POLLER_OK;
123
Jeremy Kerrce0e68b2016-03-18 13:55:46 +0800124 client = malloc(sizeof(*client));
125 memset(client, 0, sizeof(*client));
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800126
127 client->fd = fd;
128 client->poller = console_register_poller(sh->console, handler,
129 client_poll, client->fd, POLLIN, client);
130
Jeremy Kerrce0e68b2016-03-18 13:55:46 +0800131 n = sh->n_clients++;
132 sh->clients = realloc(sh->clients,
133 sizeof(*sh->clients) * sh->n_clients);
134 sh->clients[n] = client;
135
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800136 return POLLER_OK;
137
138}
139
Jeremy Kerrd47963e2016-03-16 17:29:55 +0800140static int socket_init(struct handler *handler, struct console *console,
141 struct config *config __attribute__((unused)))
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800142{
143 struct socket_handler *sh = to_socket_handler(handler);
144 struct sockaddr_un addr;
145 int rc;
146
147 sh->console = console;
148 sh->clients = NULL;
149 sh->n_clients = 0;
150
151 sh->sd = socket(AF_UNIX, SOCK_STREAM, 0);
152 if(sh->sd < 0) {
153 warn("Can't create socket");
154 return -1;
155 }
156
157 memset(&addr, 0, sizeof(addr));
158 addr.sun_family = AF_UNIX;
Jeremy Kerr0cff6522016-03-18 09:57:01 +0800159 memcpy(&addr.sun_path, &console_socket_path, console_socket_path_len);
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800160
161 rc = bind(sh->sd, (struct sockaddr *)&addr, sizeof(addr));
162 if (rc) {
163 warn("Can't bind to socket path %s",
164 console_socket_path_readable);
165 return -1;
166 }
167
168 rc = listen(sh->sd, 1);
169 if (rc) {
170 warn("Can't listen for incoming connections");
171 return -1;
172 }
173
Jeremy Kerr89ea8192016-03-15 17:57:43 +0800174 sh->poller = console_register_poller(console, handler, socket_poll,
175 sh->sd, POLLIN, NULL);
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800176
177 return 0;
178}
179
180static int socket_data(struct handler *handler, uint8_t *buf, size_t len)
181{
182 struct socket_handler *sh = to_socket_handler(handler);
183 int i;
184
185 for (i = 0; i < sh->n_clients; i++) {
Jeremy Kerrce0e68b2016-03-18 13:55:46 +0800186 struct client *client = sh->clients[i];
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800187 client_send_data(sh, client, buf, len);
188 }
189 return 0;
190}
191
192static void socket_fini(struct handler *handler)
193{
194 struct socket_handler *sh = to_socket_handler(handler);
Jeremy Kerr89ea8192016-03-15 17:57:43 +0800195 int i;
196
197 for (i = 0; i < sh->n_clients; i++)
Jeremy Kerrce0e68b2016-03-18 13:55:46 +0800198 client_close(sh, sh->clients[i]);
Jeremy Kerr89ea8192016-03-15 17:57:43 +0800199
200 if (sh->poller)
201 console_unregister_poller(sh->console, sh->poller);
202
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800203 close(sh->sd);
204}
205
206static struct socket_handler socket_handler = {
207 .handler = {
208 .name = "socket",
209 .init = socket_init,
210 .data_in = socket_data,
211 .fini = socket_fini,
212 },
213};
214
215console_register_handler(&socket_handler.handler);
216