]> git.proxmox.com Git - mirror_corosync-qdevice.git/blob - qdevices/qdevice-ipc.c
qdevice-ipc: Fix dereference bug
[mirror_corosync-qdevice.git] / qdevices / qdevice-ipc.c
1 /*
2 * Copyright (c) 2015-2019 Red Hat, Inc.
3 *
4 * All rights reserved.
5 *
6 * Author: Jan Friesse (jfriesse@redhat.com)
7 *
8 * This software licensed under BSD license, the text of which follows:
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are met:
12 *
13 * - Redistributions of source code must retain the above copyright notice,
14 * this list of conditions and the following disclaimer.
15 * - Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
18 * - Neither the name of the Red Hat, Inc. nor the names of its
19 * contributors may be used to endorse or promote products derived from this
20 * software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
26 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32 * THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35 #include "log.h"
36 #include "qdevice-config.h"
37 #include "qdevice-ipc.h"
38 #include "unix-socket-ipc.h"
39 #include "dynar-simple-lex.h"
40 #include "dynar-str.h"
41 #include "qdevice-ipc-cmd.h"
42
43 /*
44 * Callbacks
45 */
46
47 /*
48 * IPC server socket
49 */
50 static int
51 ipc_socket_poll_loop_set_events_cb(int fd, short *events, void *user_data1, void *user_data2)
52 {
53 struct qdevice_instance *instance = (struct qdevice_instance *)user_data1;
54
55 if (qdevice_ipc_is_closed(instance)) {
56 log(LOG_DEBUG, "Listening socket is closed");
57
58 return (-2);
59 }
60
61 return (0);
62 }
63
64 static int
65 ipc_socket_poll_loop_read_cb(int fd, void *user_data1, void *user_data2)
66 {
67 struct qdevice_instance *instance = (struct qdevice_instance *)user_data1;
68 struct unix_socket_client *ipc_client;
69
70 qdevice_ipc_accept(instance, &ipc_client);
71
72 return (0);
73 }
74
75 static int
76 ipc_socket_poll_loop_err_cb(int fd, short revents, void *user_data1, void *user_data2)
77 {
78
79 if (revents != POLLNVAL) {
80 /*
81 * Poll ERR on listening socket is fatal error.
82 * POLL_NVAL is used as a signal to quit poll loop.
83 */
84 log(LOG_CRIT, "POLL_ERR (%u) on listening socket", revents);
85 } else {
86 log(LOG_DEBUG, "Listening socket is closed");
87 }
88
89 return (-1);
90 }
91
92 /*
93 * IPC client sockets
94 */
95 static int
96 ipc_client_socket_poll_loop_set_events_cb(int fd, short *events, void *user_data1, void *user_data2)
97 {
98 struct qdevice_instance *instance = (struct qdevice_instance *)user_data1;
99 struct unix_socket_client *ipc_client = (struct unix_socket_client *)user_data2;
100
101 if (ipc_client->schedule_disconnect) {
102 qdevice_ipc_client_disconnect(instance, ipc_client);
103
104 if (pr_poll_loop_del_fd(&instance->main_poll_loop, fd) == -1) {
105 log(LOG_ERR, "pr_poll_loop_del_fd for ipc client socket failed");
106
107 return (-2);
108 }
109
110 return (-1);
111 }
112
113 if (!ipc_client->reading_line && !ipc_client->writing_buffer) {
114 return (-1);
115 }
116
117 if (ipc_client->reading_line) {
118 *events |= POLLIN;
119 }
120
121 if (ipc_client->writing_buffer) {
122 *events |= POLLOUT;
123 }
124
125 return (0);
126 }
127
128 static int
129 ipc_client_socket_poll_loop_read_cb(int fd, void *user_data1, void *user_data2)
130 {
131 struct qdevice_instance *instance = (struct qdevice_instance *)user_data1;
132 struct unix_socket_client *ipc_client = (struct unix_socket_client *)user_data2;
133
134 if (!ipc_client->schedule_disconnect) {
135 qdevice_ipc_io_read(instance, ipc_client);
136 }
137
138 return (0);
139 }
140
141 static int
142 ipc_client_socket_poll_loop_write_cb(int fd, void *user_data1, void *user_data2)
143 {
144 struct qdevice_instance *instance = (struct qdevice_instance *)user_data1;
145 struct unix_socket_client *ipc_client = (struct unix_socket_client *)user_data2;
146
147 if (!ipc_client->schedule_disconnect) {
148 qdevice_ipc_io_write(instance, ipc_client);
149 }
150
151 return (0);
152 }
153
154 static int
155 ipc_client_socket_poll_loop_err_cb(int fd, short revents, void *user_data1, void *user_data2)
156 {
157 struct unix_socket_client *ipc_client = (struct unix_socket_client *)user_data2;
158
159 if (!ipc_client->schedule_disconnect) {
160 log(LOG_DEBUG, "POLL_ERR (%u) on ipc client socket."
161 " Disconnecting.", revents);
162
163 ipc_client->schedule_disconnect = 1;
164 }
165
166 return (0);
167 }
168
169 /*
170 * Exported functions
171 */
172 int
173 qdevice_ipc_init(struct qdevice_instance *instance)
174 {
175
176 if (unix_socket_ipc_init(&instance->local_ipc,
177 instance->advanced_settings->local_socket_file,
178 instance->advanced_settings->local_socket_backlog,
179 instance->advanced_settings->ipc_max_clients,
180 instance->advanced_settings->ipc_max_receive_size,
181 instance->advanced_settings->ipc_max_send_size) != 0) {
182 log_err(LOG_ERR, "Can't create unix socket");
183
184 return (-1);
185 }
186
187 if (pr_poll_loop_add_fd(&instance->main_poll_loop, instance->local_ipc.socket, POLLIN,
188 ipc_socket_poll_loop_set_events_cb,
189 ipc_socket_poll_loop_read_cb,
190 NULL,
191 ipc_socket_poll_loop_err_cb, instance, NULL) == -1) {
192 log(LOG_ERR, "Can't add IPC socket to main poll loop");
193
194 return (-1);
195 }
196
197 return (0);
198 }
199
200 int
201 qdevice_ipc_close(struct qdevice_instance *instance)
202 {
203 int res;
204
205 res = unix_socket_ipc_close(&instance->local_ipc);
206 if (res != 0) {
207 log_err(LOG_WARNING, "Can't close local IPC");
208 }
209
210 return (res);
211 }
212
213 int
214 qdevice_ipc_is_closed(struct qdevice_instance *instance)
215 {
216
217 return (unix_socket_ipc_is_closed(&instance->local_ipc));
218 }
219
220 int
221 qdevice_ipc_destroy(struct qdevice_instance *instance)
222 {
223 int res;
224 struct unix_socket_client *client;
225 const struct unix_socket_client_list *ipc_client_list;
226
227 ipc_client_list = &instance->local_ipc.clients;
228
229 TAILQ_FOREACH(client, ipc_client_list, entries) {
230 free(client->user_data);
231 }
232
233 res = unix_socket_ipc_destroy(&instance->local_ipc);
234 if (res != 0) {
235 log_err(LOG_WARNING, "Can't destroy local IPC");
236 }
237
238 return (res);
239 }
240
241 int
242 qdevice_ipc_accept(struct qdevice_instance *instance, struct unix_socket_client **res_client)
243 {
244 int res;
245 int accept_res;
246
247 accept_res = unix_socket_ipc_accept(&instance->local_ipc, res_client);
248
249 switch (accept_res) {
250 case -1:
251 log_err(LOG_ERR, "Can't accept local IPC connection");
252 res = -1;
253 goto return_res;
254 break;
255 case -2:
256 log(LOG_ERR, "Maximum IPC clients reached. Not accepting connection");
257 res = -1;
258 goto return_res;
259 break;
260 case -3:
261 log(LOG_ERR, "Can't add client to list");
262 res = -1;
263 goto return_res;
264 break;
265 default:
266 unix_socket_client_read_line(*res_client, 1);
267 res = 0;
268 break;
269 }
270
271 (*res_client)->user_data = malloc(sizeof(struct qdevice_ipc_user_data));
272 if ((*res_client)->user_data == NULL) {
273 log(LOG_ERR, "Can't alloc IPC client user data");
274 res = -1;
275 qdevice_ipc_client_disconnect(instance, *res_client);
276
277 goto return_res;
278 } else {
279 memset((*res_client)->user_data, 0, sizeof(struct qdevice_ipc_user_data));
280 }
281
282 if (pr_poll_loop_add_fd(&instance->main_poll_loop, (*res_client)->socket, 0,
283 ipc_client_socket_poll_loop_set_events_cb,
284 ipc_client_socket_poll_loop_read_cb,
285 ipc_client_socket_poll_loop_write_cb,
286 ipc_client_socket_poll_loop_err_cb, instance, *res_client) == -1) {
287 log(LOG_ERR, "Can't add IPC client socket to main poll loop");
288 res = -1;
289
290 qdevice_ipc_client_disconnect(instance, *res_client);
291
292 goto return_res;
293 }
294
295 return_res:
296 return (res);
297 }
298
299 void
300 qdevice_ipc_client_disconnect(struct qdevice_instance *instance, struct unix_socket_client *client)
301 {
302
303 free(client->user_data);
304 unix_socket_ipc_client_disconnect(&instance->local_ipc, client);
305 }
306
307 int
308 qdevice_ipc_send_error(struct qdevice_instance *instance, struct unix_socket_client *client,
309 const char *error_fmt, ...)
310 {
311 va_list ap;
312 int res;
313
314 va_start(ap, error_fmt);
315 res = ((dynar_str_cpy(&client->send_buffer, "Error\n") == 0) &&
316 (dynar_str_vcatf(&client->send_buffer, error_fmt, ap) > 0) &&
317 (dynar_str_cat(&client->send_buffer, "\n") == 0));
318
319 va_end(ap);
320
321 if (res) {
322 unix_socket_client_write_buffer(client, 1);
323 } else {
324 log(LOG_ERR, "Can't send ipc error to client (buffer too small)");
325 }
326
327 return (res ? 0 : -1);
328 }
329
330 int
331 qdevice_ipc_send_buffer(struct qdevice_instance *instance, struct unix_socket_client *client)
332 {
333
334 if (dynar_str_prepend(&client->send_buffer, "OK\n") != 0) {
335 log(LOG_ERR, "Can't send ipc message to client (buffer too small)");
336
337 if (qdevice_ipc_send_error(instance, client, "Internal IPC buffer too small") != 0) {
338 return (-1);
339 }
340
341 return (0);
342 }
343
344 unix_socket_client_write_buffer(client, 1);
345
346 return (0);
347 }
348
349 static void
350 qdevice_ipc_parse_line(struct qdevice_instance *instance, struct unix_socket_client *client)
351 {
352 struct dynar_simple_lex lex;
353 struct dynar *token;
354 char *str;
355 struct qdevice_ipc_user_data *ipc_user_data;
356 int verbose;
357
358 ipc_user_data = (struct qdevice_ipc_user_data *)client->user_data;
359
360 dynar_simple_lex_init(&lex, &client->receive_buffer, DYNAR_SIMPLE_LEX_TYPE_PLAIN);
361 token = dynar_simple_lex_token_next(&lex);
362
363 verbose = 0;
364
365 if (token == NULL) {
366 log(LOG_ERR, "Can't alloc memory for simple lex");
367
368 if (qdevice_ipc_send_error(instance, client, "Command too long") != 0) {
369 client->schedule_disconnect = 1;
370 }
371
372 return;
373 }
374
375 str = dynar_data(token);
376 if (strcasecmp(str, "") == 0) {
377 log(LOG_DEBUG, "IPC client doesn't send command");
378 if (qdevice_ipc_send_error(instance, client, "No command specified") != 0) {
379 client->schedule_disconnect = 1;
380 }
381 } else if (strcasecmp(str, "shutdown") == 0) {
382 log(LOG_DEBUG, "IPC client requested shutdown");
383
384 ipc_user_data->shutdown_requested = 1;
385
386 if (qdevice_ipc_send_buffer(instance, client) != 0) {
387 client->schedule_disconnect = 1;
388 }
389 } else if (strcasecmp(str, "status") == 0) {
390 token = dynar_simple_lex_token_next(&lex);
391
392 if (token != NULL && (str = dynar_data(token), strcmp(str, "")) != 0) {
393 if (strcasecmp(str, "verbose") == 0) {
394 verbose = 1;
395 }
396 }
397
398 if (qdevice_ipc_cmd_status(instance, &client->send_buffer, verbose) != 0) {
399 if (qdevice_ipc_send_error(instance, client, "Can't get QDevice status") != 0) {
400 client->schedule_disconnect = 1;
401 }
402 } else {
403 if (qdevice_ipc_send_buffer(instance, client) != 0) {
404 client->schedule_disconnect = 1;
405 }
406 }
407 } else {
408 log(LOG_DEBUG, "IPC client sent unknown command");
409 if (qdevice_ipc_send_error(instance, client, "Unknown command '%s'", str) != 0) {
410 client->schedule_disconnect = 1;
411 }
412 }
413
414 dynar_simple_lex_destroy(&lex);
415 }
416
417 void
418 qdevice_ipc_io_read(struct qdevice_instance *instance, struct unix_socket_client *client)
419 {
420 int res;
421
422 res = unix_socket_client_io_read(client);
423
424 switch (res) {
425 case 0:
426 /*
427 * Partial read
428 */
429 break;
430 case -1:
431 log(LOG_DEBUG, "IPC client closed connection");
432 client->schedule_disconnect = 1;
433 break;
434 case -2:
435 log(LOG_ERR, "Can't store message from IPC client. Disconnecting client.");
436 client->schedule_disconnect = 1;
437 break;
438 case -3:
439 log_err(LOG_ERR, "Can't receive message from IPC client. Disconnecting client.");
440 client->schedule_disconnect = 1;
441 break;
442 case 1:
443 /*
444 * Full message received
445 */
446 unix_socket_client_read_line(client, 0);
447
448 qdevice_ipc_parse_line(instance, client);
449 break;
450 }
451 }
452
453 void
454 qdevice_ipc_io_write(struct qdevice_instance *instance, struct unix_socket_client *client)
455 {
456 int res;
457 struct qdevice_ipc_user_data *ipc_user_data;
458
459 ipc_user_data = (struct qdevice_ipc_user_data *)client->user_data;
460
461 res = unix_socket_client_io_write(client);
462
463 switch (res) {
464 case 0:
465 /*
466 * Partial send
467 */
468 break;
469 case -1:
470 log(LOG_DEBUG, "IPC client closed connection");
471 client->schedule_disconnect = 1;
472 break;
473 case -2:
474 log_err(LOG_ERR, "Can't send message to IPC client. Disconnecting client");
475 client->schedule_disconnect = 1;
476 break;
477 case 1:
478 /*
479 * Full message sent
480 */
481 unix_socket_client_write_buffer(client, 0);
482 client->schedule_disconnect = 1;
483
484 if (ipc_user_data->shutdown_requested) {
485 qdevice_ipc_close(instance);
486 }
487
488 break;
489 }
490 }