blob: 8b915e9a04a09e0679a2bcbf2fc1116d4ac46cb4 [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));
64 sh->clients = realloc(sh->clients, sizeof(sh->clients) * sh->n_clients);
65}
66
67static enum poller_ret client_poll(struct handler *handler,
68 int events, void *data)
69{
70 struct socket_handler *sh = to_socket_handler(handler);
71 struct client *client = data;
72 uint8_t buf[4096];
73 int rc;
74
75 if (!(events & POLLIN))
76 return POLLER_OK;
77
78 rc = read(client->fd, buf, sizeof(buf));
79 if (rc <= 0) {
80 client->poller = NULL;
81 client_close(sh, client);
82 return POLLER_REMOVE;
83 }
84
85 console_data_out(sh->console, buf, rc);
86
87 return POLLER_OK;
88}
89
90static void client_send_data(struct socket_handler *sh,
91 struct client *client, uint8_t *buf, size_t len)
92{
93 int rc;
94
95 rc = write_buf_to_fd(client->fd, buf, len);
96 if (rc)
97 client_close(sh, client);
98}
99
100static enum poller_ret socket_poll(struct handler *handler,
101 int events, void __attribute__((unused)) *data)
102{
103 struct socket_handler *sh = to_socket_handler(handler);
104 struct client *client;
105 int fd, n;
106
107 if (!(events & POLLIN))
108 return POLLER_OK;
109
110 fd = accept(sh->sd, NULL, NULL);
111 if (fd < 0)
112 return POLLER_OK;
113
114 n = sh->n_clients++;
115 sh->clients = realloc(sh->clients, sizeof(*client) * sh->n_clients);
116 client = &sh->clients[n];
117
118 client->fd = fd;
119 client->poller = console_register_poller(sh->console, handler,
120 client_poll, client->fd, POLLIN, client);
121
122 return POLLER_OK;
123
124}
125
Jeremy Kerrd47963e2016-03-16 17:29:55 +0800126static int socket_init(struct handler *handler, struct console *console,
127 struct config *config __attribute__((unused)))
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800128{
129 struct socket_handler *sh = to_socket_handler(handler);
130 struct sockaddr_un addr;
131 int rc;
132
133 sh->console = console;
134 sh->clients = NULL;
135 sh->n_clients = 0;
136
137 sh->sd = socket(AF_UNIX, SOCK_STREAM, 0);
138 if(sh->sd < 0) {
139 warn("Can't create socket");
140 return -1;
141 }
142
143 memset(&addr, 0, sizeof(addr));
144 addr.sun_family = AF_UNIX;
145 memcpy(addr.sun_path, console_socket_path, console_socket_path_len);
146
147 rc = bind(sh->sd, (struct sockaddr *)&addr, sizeof(addr));
148 if (rc) {
149 warn("Can't bind to socket path %s",
150 console_socket_path_readable);
151 return -1;
152 }
153
154 rc = listen(sh->sd, 1);
155 if (rc) {
156 warn("Can't listen for incoming connections");
157 return -1;
158 }
159
Jeremy Kerr89ea8192016-03-15 17:57:43 +0800160 sh->poller = console_register_poller(console, handler, socket_poll,
161 sh->sd, POLLIN, NULL);
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800162
163 return 0;
164}
165
166static int socket_data(struct handler *handler, uint8_t *buf, size_t len)
167{
168 struct socket_handler *sh = to_socket_handler(handler);
169 int i;
170
171 for (i = 0; i < sh->n_clients; i++) {
172 struct client *client = &sh->clients[i];
173 client_send_data(sh, client, buf, len);
174 }
175 return 0;
176}
177
178static void socket_fini(struct handler *handler)
179{
180 struct socket_handler *sh = to_socket_handler(handler);
Jeremy Kerr89ea8192016-03-15 17:57:43 +0800181 int i;
182
183 for (i = 0; i < sh->n_clients; i++)
184 client_close(sh, &sh->clients[i]);
185
186 if (sh->poller)
187 console_unregister_poller(sh->console, sh->poller);
188
Jeremy Kerr2bd05182016-03-10 16:59:43 +0800189 close(sh->sd);
190}
191
192static struct socket_handler socket_handler = {
193 .handler = {
194 .name = "socket",
195 .init = socket_init,
196 .data_in = socket_data,
197 .fini = socket_fini,
198 },
199};
200
201console_register_handler(&socket_handler.handler);
202