blob: 8e0cebca3b5383af8ff1ed548170fd9d377cd96e [file] [log] [blame]
Jeremy Kerr2bd05182016-03-10 16:59:43 +08001
2#include <err.h>
3#include <stdbool.h>
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7#include <termios.h>
8#include <unistd.h>
9#include <endian.h>
10
11#include <sys/socket.h>
12#include <sys/un.h>
13
14#include "console-server.h"
15
16struct client {
17 struct poller *poller;
18 int fd;
19};
20
21struct socket_handler {
22 struct handler handler;
23 struct console *console;
24 int sd;
25
26 struct client *clients;
27 int n_clients;
28};
29
30static struct socket_handler *to_socket_handler(struct handler *handler)
31{
32 return container_of(handler, struct socket_handler, handler);
33}
34
35static void client_close(struct socket_handler *sh, struct client *client)
36{
37 int idx;
38
39 close(client->fd);
40 if (client->poller)
41 console_unregister_poller(sh->console, client->poller);
42
43 idx = client - sh->clients;
44
45 sh->n_clients--;
46 memmove(&sh->clients[idx], &sh->clients[idx+1],
47 sizeof(*sh->clients) * (sh->n_clients - idx));
48 sh->clients = realloc(sh->clients, sizeof(sh->clients) * sh->n_clients);
49}
50
51static enum poller_ret client_poll(struct handler *handler,
52 int events, void *data)
53{
54 struct socket_handler *sh = to_socket_handler(handler);
55 struct client *client = data;
56 uint8_t buf[4096];
57 int rc;
58
59 if (!(events & POLLIN))
60 return POLLER_OK;
61
62 rc = read(client->fd, buf, sizeof(buf));
63 if (rc <= 0) {
64 client->poller = NULL;
65 client_close(sh, client);
66 return POLLER_REMOVE;
67 }
68
69 console_data_out(sh->console, buf, rc);
70
71 return POLLER_OK;
72}
73
74static void client_send_data(struct socket_handler *sh,
75 struct client *client, uint8_t *buf, size_t len)
76{
77 int rc;
78
79 rc = write_buf_to_fd(client->fd, buf, len);
80 if (rc)
81 client_close(sh, client);
82}
83
84static enum poller_ret socket_poll(struct handler *handler,
85 int events, void __attribute__((unused)) *data)
86{
87 struct socket_handler *sh = to_socket_handler(handler);
88 struct client *client;
89 int fd, n;
90
91 if (!(events & POLLIN))
92 return POLLER_OK;
93
94 fd = accept(sh->sd, NULL, NULL);
95 if (fd < 0)
96 return POLLER_OK;
97
98 n = sh->n_clients++;
99 sh->clients = realloc(sh->clients, sizeof(*client) * sh->n_clients);
100 client = &sh->clients[n];
101
102 client->fd = fd;
103 client->poller = console_register_poller(sh->console, handler,
104 client_poll, client->fd, POLLIN, client);
105
106 return POLLER_OK;
107
108}
109
110static int socket_init(struct handler *handler, struct console *console)
111{
112 struct socket_handler *sh = to_socket_handler(handler);
113 struct sockaddr_un addr;
114 int rc;
115
116 sh->console = console;
117 sh->clients = NULL;
118 sh->n_clients = 0;
119
120 sh->sd = socket(AF_UNIX, SOCK_STREAM, 0);
121 if(sh->sd < 0) {
122 warn("Can't create socket");
123 return -1;
124 }
125
126 memset(&addr, 0, sizeof(addr));
127 addr.sun_family = AF_UNIX;
128 memcpy(addr.sun_path, console_socket_path, console_socket_path_len);
129
130 rc = bind(sh->sd, (struct sockaddr *)&addr, sizeof(addr));
131 if (rc) {
132 warn("Can't bind to socket path %s",
133 console_socket_path_readable);
134 return -1;
135 }
136
137 rc = listen(sh->sd, 1);
138 if (rc) {
139 warn("Can't listen for incoming connections");
140 return -1;
141 }
142
143 console_register_poller(console, handler, socket_poll, sh->sd, POLLIN,
144 NULL);
145
146 return 0;
147}
148
149static int socket_data(struct handler *handler, uint8_t *buf, size_t len)
150{
151 struct socket_handler *sh = to_socket_handler(handler);
152 int i;
153
154 for (i = 0; i < sh->n_clients; i++) {
155 struct client *client = &sh->clients[i];
156 client_send_data(sh, client, buf, len);
157 }
158 return 0;
159}
160
161static void socket_fini(struct handler *handler)
162{
163 struct socket_handler *sh = to_socket_handler(handler);
164 close(sh->sd);
165}
166
167static struct socket_handler socket_handler = {
168 .handler = {
169 .name = "socket",
170 .init = socket_init,
171 .data_in = socket_data,
172 .fini = socket_fini,
173 },
174};
175
176console_register_handler(&socket_handler.handler);
177