| Jeremy Kerr | 9326d77 | 2016-03-17 17:15:02 +0800 | [diff] [blame] | 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 | */ | 
| Jeremy Kerr | 2bd0518 | 2016-03-10 16:59:43 +0800 | [diff] [blame] | 16 |  | 
| Jeremy Kerr | 4d80a5b | 2016-03-18 13:47:43 +0800 | [diff] [blame] | 17 | #define _GNU_SOURCE | 
| Jeremy Kerr | ce0e68b | 2016-03-18 13:55:46 +0800 | [diff] [blame] | 18 |  | 
|  | 19 | #include <assert.h> | 
| Jeremy Kerr | 2bd0518 | 2016-03-10 16:59:43 +0800 | [diff] [blame] | 20 | #include <err.h> | 
| Jeremy Kerr | 4d80a5b | 2016-03-18 13:47:43 +0800 | [diff] [blame] | 21 | #include <errno.h> | 
| Jeremy Kerr | 2bd0518 | 2016-03-10 16:59:43 +0800 | [diff] [blame] | 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 |  | 
| Jeremy Kerr | 5708dfb | 2017-01-19 15:11:19 +0800 | [diff] [blame^] | 35 | #define min(a,b) ({				\ | 
|  | 36 | const typeof(a) _a = (a);	\ | 
|  | 37 | const typeof(b) _b = (b);	\ | 
|  | 38 | _a < _b ? _a : _b;		\ | 
|  | 39 | }) | 
|  | 40 |  | 
|  | 41 | const size_t buffer_size = 128 * 1024; | 
| Jeremy Kerr | 4d80a5b | 2016-03-18 13:47:43 +0800 | [diff] [blame] | 42 |  | 
| Jeremy Kerr | 2bd0518 | 2016-03-10 16:59:43 +0800 | [diff] [blame] | 43 | struct client { | 
|  | 44 | struct poller	*poller; | 
|  | 45 | int		fd; | 
| Jeremy Kerr | 5708dfb | 2017-01-19 15:11:19 +0800 | [diff] [blame^] | 46 | size_t		buf_pos; | 
| Jeremy Kerr | 2bd0518 | 2016-03-10 16:59:43 +0800 | [diff] [blame] | 47 | }; | 
|  | 48 |  | 
|  | 49 | struct socket_handler { | 
|  | 50 | struct handler	handler; | 
|  | 51 | struct console	*console; | 
| Jeremy Kerr | 89ea819 | 2016-03-15 17:57:43 +0800 | [diff] [blame] | 52 | struct poller	*poller; | 
| Jeremy Kerr | 2bd0518 | 2016-03-10 16:59:43 +0800 | [diff] [blame] | 53 | int		sd; | 
|  | 54 |  | 
| Jeremy Kerr | 5708dfb | 2017-01-19 15:11:19 +0800 | [diff] [blame^] | 55 | uint8_t		*buf; | 
|  | 56 | size_t		buf_len; | 
|  | 57 |  | 
| Jeremy Kerr | ce0e68b | 2016-03-18 13:55:46 +0800 | [diff] [blame] | 58 | struct client	**clients; | 
| Jeremy Kerr | 2bd0518 | 2016-03-10 16:59:43 +0800 | [diff] [blame] | 59 | int		n_clients; | 
|  | 60 | }; | 
|  | 61 |  | 
|  | 62 | static struct socket_handler *to_socket_handler(struct handler *handler) | 
|  | 63 | { | 
|  | 64 | return container_of(handler, struct socket_handler, handler); | 
|  | 65 | } | 
|  | 66 |  | 
|  | 67 | static void client_close(struct socket_handler *sh, struct client *client) | 
|  | 68 | { | 
|  | 69 | int idx; | 
|  | 70 |  | 
|  | 71 | close(client->fd); | 
|  | 72 | if (client->poller) | 
|  | 73 | console_unregister_poller(sh->console, client->poller); | 
|  | 74 |  | 
| Jeremy Kerr | ce0e68b | 2016-03-18 13:55:46 +0800 | [diff] [blame] | 75 | for (idx = 0; idx < sh->n_clients; idx++) | 
|  | 76 | if (sh->clients[idx] == client) | 
|  | 77 | break; | 
|  | 78 |  | 
|  | 79 | assert(idx < sh->n_clients); | 
|  | 80 |  | 
|  | 81 | free(client); | 
|  | 82 | client = NULL; | 
| Jeremy Kerr | 2bd0518 | 2016-03-10 16:59:43 +0800 | [diff] [blame] | 83 |  | 
|  | 84 | sh->n_clients--; | 
|  | 85 | memmove(&sh->clients[idx], &sh->clients[idx+1], | 
|  | 86 | sizeof(*sh->clients) * (sh->n_clients - idx)); | 
| Joel Stanley | fbff1c6 | 2016-03-17 20:32:24 +1030 | [diff] [blame] | 87 | sh->clients = realloc(sh->clients, | 
|  | 88 | sizeof(*sh->clients) * sh->n_clients); | 
| Jeremy Kerr | 2bd0518 | 2016-03-10 16:59:43 +0800 | [diff] [blame] | 89 | } | 
|  | 90 |  | 
| Jeremy Kerr | 5708dfb | 2017-01-19 15:11:19 +0800 | [diff] [blame^] | 91 | static size_t client_buffer_len(struct socket_handler *sh, | 
|  | 92 | struct client *client) | 
| Jeremy Kerr | 4d80a5b | 2016-03-18 13:47:43 +0800 | [diff] [blame] | 93 | { | 
| Jeremy Kerr | 5708dfb | 2017-01-19 15:11:19 +0800 | [diff] [blame^] | 94 | return sh->buf_len - client->buf_pos; | 
| Jeremy Kerr | 848fc87 | 2017-01-17 13:50:05 +0800 | [diff] [blame] | 95 | } | 
| Jeremy Kerr | 243cab3 | 2017-01-17 13:54:54 +0800 | [diff] [blame] | 96 |  | 
| Jeremy Kerr | 5708dfb | 2017-01-19 15:11:19 +0800 | [diff] [blame^] | 97 | static void *client_buffer_data(struct socket_handler *sh, | 
|  | 98 | struct client *client) | 
| Jeremy Kerr | 848fc87 | 2017-01-17 13:50:05 +0800 | [diff] [blame] | 99 | { | 
| Jeremy Kerr | 5708dfb | 2017-01-19 15:11:19 +0800 | [diff] [blame^] | 100 | return sh->buf + client->buf_pos; | 
| Jeremy Kerr | 848fc87 | 2017-01-17 13:50:05 +0800 | [diff] [blame] | 101 | } | 
|  | 102 |  | 
|  | 103 | static ssize_t send_all(int fd, void *buf, size_t len, bool block) | 
|  | 104 | { | 
|  | 105 | int rc, flags; | 
|  | 106 | size_t pos; | 
|  | 107 |  | 
|  | 108 | flags = MSG_NOSIGNAL; | 
|  | 109 | if (!block) | 
|  | 110 | flags |= MSG_DONTWAIT; | 
| Jeremy Kerr | 4d80a5b | 2016-03-18 13:47:43 +0800 | [diff] [blame] | 111 |  | 
|  | 112 | for (pos = 0; pos < len; pos += rc) { | 
| Jeremy Kerr | 848fc87 | 2017-01-17 13:50:05 +0800 | [diff] [blame] | 113 | rc = send(fd, buf + pos, len - pos, flags); | 
| Jeremy Kerr | 4d80a5b | 2016-03-18 13:47:43 +0800 | [diff] [blame] | 114 | if (rc < 0) { | 
| Jeremy Kerr | 848fc87 | 2017-01-17 13:50:05 +0800 | [diff] [blame] | 115 | if (!block && (errno == EAGAIN || errno == EWOULDBLOCK)) | 
| Jeremy Kerr | 4d80a5b | 2016-03-18 13:47:43 +0800 | [diff] [blame] | 116 | break; | 
|  | 117 |  | 
|  | 118 | if (errno == EINTR) | 
|  | 119 | continue; | 
|  | 120 |  | 
|  | 121 | return -1; | 
|  | 122 | } | 
|  | 123 | if (rc == 0) | 
|  | 124 | return -1; | 
|  | 125 | } | 
|  | 126 |  | 
|  | 127 | return pos; | 
|  | 128 | } | 
|  | 129 |  | 
| Jeremy Kerr | 848fc87 | 2017-01-17 13:50:05 +0800 | [diff] [blame] | 130 | /* Drain the queue to the socket and update the queue buffer. If force_len is | 
|  | 131 | * set, send at least that many bytes from the queue, possibly while blocking | 
|  | 132 | */ | 
| Jeremy Kerr | 5708dfb | 2017-01-19 15:11:19 +0800 | [diff] [blame^] | 133 | static int client_drain_queue(struct socket_handler *sh, | 
|  | 134 | struct client *client, size_t force_len) | 
| Jeremy Kerr | 848fc87 | 2017-01-17 13:50:05 +0800 | [diff] [blame] | 135 | { | 
|  | 136 | ssize_t wlen; | 
|  | 137 | size_t len; | 
|  | 138 | bool block; | 
|  | 139 |  | 
| Jeremy Kerr | 5708dfb | 2017-01-19 15:11:19 +0800 | [diff] [blame^] | 140 | len = client_buffer_len(sh, client); | 
|  | 141 | if (!len) | 
| Jeremy Kerr | 848fc87 | 2017-01-17 13:50:05 +0800 | [diff] [blame] | 142 | return 0; | 
|  | 143 |  | 
|  | 144 | block = false; | 
| Jeremy Kerr | 848fc87 | 2017-01-17 13:50:05 +0800 | [diff] [blame] | 145 | if (force_len) { | 
| Jeremy Kerr | 5708dfb | 2017-01-19 15:11:19 +0800 | [diff] [blame^] | 146 | assert(force_len <= len); | 
| Jeremy Kerr | 848fc87 | 2017-01-17 13:50:05 +0800 | [diff] [blame] | 147 | block = true; | 
|  | 148 | len = force_len; | 
|  | 149 | } | 
|  | 150 |  | 
| Jeremy Kerr | 5708dfb | 2017-01-19 15:11:19 +0800 | [diff] [blame^] | 151 | wlen = send_all(client->fd, client_buffer_data(sh, client), len, block); | 
| Jeremy Kerr | 848fc87 | 2017-01-17 13:50:05 +0800 | [diff] [blame] | 152 | if (wlen < 0) | 
|  | 153 | return -1; | 
|  | 154 |  | 
|  | 155 | if (force_len && wlen < force_len) | 
|  | 156 | return -1; | 
|  | 157 |  | 
| Jeremy Kerr | 5708dfb | 2017-01-19 15:11:19 +0800 | [diff] [blame^] | 158 | client->buf_pos += wlen; | 
|  | 159 | assert(client->buf_pos <= sh->buf_len); | 
| Jeremy Kerr | 848fc87 | 2017-01-17 13:50:05 +0800 | [diff] [blame] | 160 |  | 
|  | 161 | return 0; | 
|  | 162 | } | 
|  | 163 |  | 
| Jeremy Kerr | 2bd0518 | 2016-03-10 16:59:43 +0800 | [diff] [blame] | 164 | static enum poller_ret client_poll(struct handler *handler, | 
|  | 165 | int events, void *data) | 
|  | 166 | { | 
|  | 167 | struct socket_handler *sh = to_socket_handler(handler); | 
|  | 168 | struct client *client = data; | 
|  | 169 | uint8_t buf[4096]; | 
|  | 170 | int rc; | 
|  | 171 |  | 
| Jeremy Kerr | 4d80a5b | 2016-03-18 13:47:43 +0800 | [diff] [blame] | 172 | if (events & POLLIN) { | 
| Jeremy Kerr | 68a2ece | 2017-01-17 13:52:41 +0800 | [diff] [blame] | 173 | rc = recv(client->fd, buf, sizeof(buf), MSG_DONTWAIT); | 
| Jeremy Kerr | 848fc87 | 2017-01-17 13:50:05 +0800 | [diff] [blame] | 174 | if (rc < 0) { | 
|  | 175 | if (errno == EAGAIN || errno == EWOULDBLOCK) | 
|  | 176 | return POLLER_OK; | 
|  | 177 | else | 
|  | 178 | goto err_close; | 
|  | 179 | } | 
|  | 180 | if (rc == 0) | 
| Jeremy Kerr | 4d80a5b | 2016-03-18 13:47:43 +0800 | [diff] [blame] | 181 | goto err_close; | 
| Jeremy Kerr | 2bd0518 | 2016-03-10 16:59:43 +0800 | [diff] [blame] | 182 |  | 
| Jeremy Kerr | 4d80a5b | 2016-03-18 13:47:43 +0800 | [diff] [blame] | 183 | console_data_out(sh->console, buf, rc); | 
| Jeremy Kerr | 2bd0518 | 2016-03-10 16:59:43 +0800 | [diff] [blame] | 184 | } | 
|  | 185 |  | 
| Jeremy Kerr | 4d80a5b | 2016-03-18 13:47:43 +0800 | [diff] [blame] | 186 | if (events & POLLOUT) { | 
| Jeremy Kerr | 5708dfb | 2017-01-19 15:11:19 +0800 | [diff] [blame^] | 187 | rc = client_drain_queue(sh, client, 0); | 
| Jeremy Kerr | 848fc87 | 2017-01-17 13:50:05 +0800 | [diff] [blame] | 188 | if (rc) | 
| Jeremy Kerr | 4d80a5b | 2016-03-18 13:47:43 +0800 | [diff] [blame] | 189 | goto err_close; | 
| Jeremy Kerr | 4d80a5b | 2016-03-18 13:47:43 +0800 | [diff] [blame] | 190 | } | 
| Jeremy Kerr | 2bd0518 | 2016-03-10 16:59:43 +0800 | [diff] [blame] | 191 |  | 
|  | 192 | return POLLER_OK; | 
| Jeremy Kerr | 4d80a5b | 2016-03-18 13:47:43 +0800 | [diff] [blame] | 193 |  | 
|  | 194 | err_close: | 
|  | 195 | client->poller = NULL; | 
|  | 196 | client_close(sh, client); | 
|  | 197 | return POLLER_REMOVE; | 
| Jeremy Kerr | 2bd0518 | 2016-03-10 16:59:43 +0800 | [diff] [blame] | 198 | } | 
|  | 199 |  | 
| Jeremy Kerr | 2bd0518 | 2016-03-10 16:59:43 +0800 | [diff] [blame] | 200 | static enum poller_ret socket_poll(struct handler *handler, | 
|  | 201 | int events, void __attribute__((unused)) *data) | 
|  | 202 | { | 
|  | 203 | struct socket_handler *sh = to_socket_handler(handler); | 
|  | 204 | struct client *client; | 
|  | 205 | int fd, n; | 
|  | 206 |  | 
|  | 207 | if (!(events & POLLIN)) | 
|  | 208 | return POLLER_OK; | 
|  | 209 |  | 
| Jeremy Kerr | 68a2ece | 2017-01-17 13:52:41 +0800 | [diff] [blame] | 210 | fd = accept(sh->sd, NULL, NULL); | 
| Jeremy Kerr | 2bd0518 | 2016-03-10 16:59:43 +0800 | [diff] [blame] | 211 | if (fd < 0) | 
|  | 212 | return POLLER_OK; | 
|  | 213 |  | 
| Jeremy Kerr | ce0e68b | 2016-03-18 13:55:46 +0800 | [diff] [blame] | 214 | client = malloc(sizeof(*client)); | 
|  | 215 | memset(client, 0, sizeof(*client)); | 
| Jeremy Kerr | 2bd0518 | 2016-03-10 16:59:43 +0800 | [diff] [blame] | 216 |  | 
|  | 217 | client->fd = fd; | 
|  | 218 | client->poller = console_register_poller(sh->console, handler, | 
|  | 219 | client_poll, client->fd, POLLIN, client); | 
|  | 220 |  | 
| Jeremy Kerr | ce0e68b | 2016-03-18 13:55:46 +0800 | [diff] [blame] | 221 | n = sh->n_clients++; | 
|  | 222 | sh->clients = realloc(sh->clients, | 
|  | 223 | sizeof(*sh->clients) * sh->n_clients); | 
|  | 224 | sh->clients[n] = client; | 
|  | 225 |  | 
| Jeremy Kerr | 2bd0518 | 2016-03-10 16:59:43 +0800 | [diff] [blame] | 226 | return POLLER_OK; | 
|  | 227 |  | 
|  | 228 | } | 
|  | 229 |  | 
| Jeremy Kerr | d47963e | 2016-03-16 17:29:55 +0800 | [diff] [blame] | 230 | static int socket_init(struct handler *handler, struct console *console, | 
|  | 231 | struct config *config __attribute__((unused))) | 
| Jeremy Kerr | 2bd0518 | 2016-03-10 16:59:43 +0800 | [diff] [blame] | 232 | { | 
|  | 233 | struct socket_handler *sh = to_socket_handler(handler); | 
|  | 234 | struct sockaddr_un addr; | 
|  | 235 | int rc; | 
|  | 236 |  | 
|  | 237 | sh->console = console; | 
|  | 238 | sh->clients = NULL; | 
|  | 239 | sh->n_clients = 0; | 
| Jeremy Kerr | 5708dfb | 2017-01-19 15:11:19 +0800 | [diff] [blame^] | 240 | sh->buf_len = 0; | 
|  | 241 |  | 
|  | 242 | sh->buf = malloc(buffer_size); | 
|  | 243 | if (!sh->buf) { | 
|  | 244 | warn("Can't allocate backlog buffer"); | 
|  | 245 | return -1; | 
|  | 246 | } | 
| Jeremy Kerr | 2bd0518 | 2016-03-10 16:59:43 +0800 | [diff] [blame] | 247 |  | 
|  | 248 | sh->sd = socket(AF_UNIX, SOCK_STREAM, 0); | 
|  | 249 | if(sh->sd < 0) { | 
|  | 250 | warn("Can't create socket"); | 
|  | 251 | return -1; | 
|  | 252 | } | 
|  | 253 |  | 
|  | 254 | memset(&addr, 0, sizeof(addr)); | 
|  | 255 | addr.sun_family = AF_UNIX; | 
| Jeremy Kerr | 0cff652 | 2016-03-18 09:57:01 +0800 | [diff] [blame] | 256 | memcpy(&addr.sun_path, &console_socket_path, console_socket_path_len); | 
| Jeremy Kerr | 2bd0518 | 2016-03-10 16:59:43 +0800 | [diff] [blame] | 257 |  | 
|  | 258 | rc = bind(sh->sd, (struct sockaddr *)&addr, sizeof(addr)); | 
|  | 259 | if (rc) { | 
|  | 260 | warn("Can't bind to socket path %s", | 
|  | 261 | console_socket_path_readable); | 
|  | 262 | return -1; | 
|  | 263 | } | 
|  | 264 |  | 
|  | 265 | rc = listen(sh->sd, 1); | 
|  | 266 | if (rc) { | 
|  | 267 | warn("Can't listen for incoming connections"); | 
|  | 268 | return -1; | 
|  | 269 | } | 
|  | 270 |  | 
| Jeremy Kerr | 89ea819 | 2016-03-15 17:57:43 +0800 | [diff] [blame] | 271 | sh->poller = console_register_poller(console, handler, socket_poll, | 
|  | 272 | sh->sd, POLLIN, NULL); | 
| Jeremy Kerr | 2bd0518 | 2016-03-10 16:59:43 +0800 | [diff] [blame] | 273 |  | 
|  | 274 | return 0; | 
|  | 275 | } | 
|  | 276 |  | 
|  | 277 | static int socket_data(struct handler *handler, uint8_t *buf, size_t len) | 
|  | 278 | { | 
|  | 279 | struct socket_handler *sh = to_socket_handler(handler); | 
| Jeremy Kerr | 5708dfb | 2017-01-19 15:11:19 +0800 | [diff] [blame^] | 280 | struct client *client; | 
|  | 281 | size_t space, min_pos; | 
| Jeremy Kerr | 4d80a5b | 2016-03-18 13:47:43 +0800 | [diff] [blame] | 282 | int i, rc; | 
| Jeremy Kerr | 2bd0518 | 2016-03-10 16:59:43 +0800 | [diff] [blame] | 283 |  | 
| Jeremy Kerr | 5708dfb | 2017-01-19 15:11:19 +0800 | [diff] [blame^] | 284 | space = buffer_size - sh->buf_len; | 
|  | 285 | min_pos = sh->buf_len; | 
| Jeremy Kerr | 4d80a5b | 2016-03-18 13:47:43 +0800 | [diff] [blame] | 286 |  | 
| Jeremy Kerr | 5708dfb | 2017-01-19 15:11:19 +0800 | [diff] [blame^] | 287 | /* Ensure there is at least len bytes available in the global buffer. | 
|  | 288 | * | 
|  | 289 | * The 'space' var tells us how many bytes are available at the tail of | 
|  | 290 | * the buffer. However, if all clients have a non-zero buf_pos, then we | 
|  | 291 | * can drop bytes from the beginning (in the memmove below). So, we | 
|  | 292 | * account for each clients' buf_pos in the space check. | 
|  | 293 | * | 
|  | 294 | * If a client doesn't have sufficient space, perform a blocking write | 
|  | 295 | * to create it. This will result in incrementing client->buf_pos to | 
|  | 296 | * create space. | 
|  | 297 | */ | 
|  | 298 | for (i = 0; i < sh->n_clients; i++) { | 
|  | 299 | ssize_t client_space; | 
|  | 300 |  | 
|  | 301 | client = sh->clients[i]; | 
|  | 302 | client_space = space + client->buf_pos; | 
|  | 303 |  | 
|  | 304 | if (len > client_space) { | 
|  | 305 | /* Blocking send enough to create len bytes of space in | 
|  | 306 | * the global buffer. On success, this will increment | 
|  | 307 | * client->buf_pos by the number of bytes written | 
|  | 308 | */ | 
|  | 309 | rc = client_drain_queue(sh, client, len - client_space); | 
|  | 310 | if (rc) { | 
|  | 311 | client_close(sh, client); | 
|  | 312 | i--; | 
|  | 313 | continue; | 
|  | 314 | } | 
|  | 315 | } | 
|  | 316 |  | 
|  | 317 | min_pos = min(min_pos, client->buf_pos); | 
|  | 318 | } | 
|  | 319 |  | 
|  | 320 | /* avoid pointless copying */ | 
|  | 321 | if (!sh->n_clients) { | 
|  | 322 | sh->buf_len = 0; | 
|  | 323 | return 0; | 
|  | 324 | } | 
|  | 325 |  | 
|  | 326 | /* drop unneeded buffer data... */ | 
|  | 327 | sh->buf_len -= min_pos; | 
|  | 328 | memmove(sh->buf, sh->buf + min_pos, sh->buf_len); | 
|  | 329 |  | 
|  | 330 | /* ... and add new data */ | 
|  | 331 | memcpy(sh->buf + sh->buf_len, buf, len); | 
|  | 332 | sh->buf_len += len; | 
|  | 333 |  | 
|  | 334 | /* now that the queue contains the new data, perform non-blocking send | 
|  | 335 | * to all clients */ | 
|  | 336 | for (i = 0; i < sh->n_clients; i++) { | 
|  | 337 | client = sh->clients[i]; | 
|  | 338 |  | 
|  | 339 | /* We've dropped data in the global buffer, so need to update | 
|  | 340 | * clients' pos pointers to suit the new start of buffer | 
|  | 341 | * data */ | 
|  | 342 | client->buf_pos -= min_pos; | 
|  | 343 | assert(client->buf_pos >= 0); | 
|  | 344 |  | 
|  | 345 | rc = client_drain_queue(sh, client, 0); | 
|  | 346 | if (rc) { | 
|  | 347 | client_close(sh, client); | 
|  | 348 | i--; | 
|  | 349 | continue; | 
|  | 350 | } | 
| Jeremy Kerr | 2bd0518 | 2016-03-10 16:59:43 +0800 | [diff] [blame] | 351 | } | 
|  | 352 | return 0; | 
|  | 353 | } | 
|  | 354 |  | 
|  | 355 | static void socket_fini(struct handler *handler) | 
|  | 356 | { | 
|  | 357 | struct socket_handler *sh = to_socket_handler(handler); | 
| Jeremy Kerr | 89ea819 | 2016-03-15 17:57:43 +0800 | [diff] [blame] | 358 | int i; | 
|  | 359 |  | 
|  | 360 | for (i = 0; i < sh->n_clients; i++) | 
| Jeremy Kerr | ce0e68b | 2016-03-18 13:55:46 +0800 | [diff] [blame] | 361 | client_close(sh, sh->clients[i]); | 
| Jeremy Kerr | 89ea819 | 2016-03-15 17:57:43 +0800 | [diff] [blame] | 362 |  | 
|  | 363 | if (sh->poller) | 
|  | 364 | console_unregister_poller(sh->console, sh->poller); | 
|  | 365 |  | 
| Jeremy Kerr | 2bd0518 | 2016-03-10 16:59:43 +0800 | [diff] [blame] | 366 | close(sh->sd); | 
| Jeremy Kerr | 5708dfb | 2017-01-19 15:11:19 +0800 | [diff] [blame^] | 367 | free(sh->buf); | 
| Jeremy Kerr | 2bd0518 | 2016-03-10 16:59:43 +0800 | [diff] [blame] | 368 | } | 
|  | 369 |  | 
|  | 370 | static struct socket_handler socket_handler = { | 
|  | 371 | .handler = { | 
|  | 372 | .name		= "socket", | 
|  | 373 | .init		= socket_init, | 
|  | 374 | .data_in	= socket_data, | 
|  | 375 | .fini		= socket_fini, | 
|  | 376 | }, | 
|  | 377 | }; | 
|  | 378 |  | 
|  | 379 | console_register_handler(&socket_handler.handler); | 
|  | 380 |  |