2 * Copyright (c) 2015-2019 Red Hat, Inc.
6 * Author: Jan Friesse (jfriesse@redhat.com)
8 * This software licensed under BSD license, the text of which follows:
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions are met:
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.
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.
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"
51 ipc_socket_poll_loop_set_events_cb(int fd
, short *events
, void *user_data1
, void *user_data2
)
53 struct qdevice_instance
*instance
= (struct qdevice_instance
*)user_data1
;
55 if (qdevice_ipc_is_closed(instance
)) {
56 log(LOG_DEBUG
, "Listening socket is closed");
65 ipc_socket_poll_loop_read_cb(int fd
, void *user_data1
, void *user_data2
)
67 struct qdevice_instance
*instance
= (struct qdevice_instance
*)user_data1
;
68 struct unix_socket_client
*ipc_client
;
70 qdevice_ipc_accept(instance
, &ipc_client
);
76 ipc_socket_poll_loop_err_cb(int fd
, short revents
, void *user_data1
, void *user_data2
)
79 if (revents
!= POLLNVAL
) {
81 * Poll ERR on listening socket is fatal error.
82 * POLL_NVAL is used as a signal to quit poll loop.
84 log(LOG_CRIT
, "POLL_ERR (%u) on listening socket", revents
);
86 log(LOG_DEBUG
, "Listening socket is closed");
96 ipc_client_socket_poll_loop_set_events_cb(int fd
, short *events
, void *user_data1
, void *user_data2
)
98 struct qdevice_instance
*instance
= (struct qdevice_instance
*)user_data1
;
99 struct unix_socket_client
*ipc_client
= (struct unix_socket_client
*)user_data2
;
101 if (ipc_client
->schedule_disconnect
) {
102 qdevice_ipc_client_disconnect(instance
, ipc_client
);
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");
113 if (!ipc_client
->reading_line
&& !ipc_client
->writing_buffer
) {
117 if (ipc_client
->reading_line
) {
121 if (ipc_client
->writing_buffer
) {
129 ipc_client_socket_poll_loop_read_cb(int fd
, void *user_data1
, void *user_data2
)
131 struct qdevice_instance
*instance
= (struct qdevice_instance
*)user_data1
;
132 struct unix_socket_client
*ipc_client
= (struct unix_socket_client
*)user_data2
;
134 if (!ipc_client
->schedule_disconnect
) {
135 qdevice_ipc_io_read(instance
, ipc_client
);
142 ipc_client_socket_poll_loop_write_cb(int fd
, void *user_data1
, void *user_data2
)
144 struct qdevice_instance
*instance
= (struct qdevice_instance
*)user_data1
;
145 struct unix_socket_client
*ipc_client
= (struct unix_socket_client
*)user_data2
;
147 if (!ipc_client
->schedule_disconnect
) {
148 qdevice_ipc_io_write(instance
, ipc_client
);
155 ipc_client_socket_poll_loop_err_cb(int fd
, short revents
, void *user_data1
, void *user_data2
)
157 struct unix_socket_client
*ipc_client
= (struct unix_socket_client
*)user_data2
;
159 if (!ipc_client
->schedule_disconnect
) {
160 log(LOG_DEBUG
, "POLL_ERR (%u) on ipc client socket."
161 " Disconnecting.", revents
);
163 ipc_client
->schedule_disconnect
= 1;
173 qdevice_ipc_init(struct qdevice_instance
*instance
)
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");
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
,
191 ipc_socket_poll_loop_err_cb
, instance
, NULL
) == -1) {
192 log(LOG_ERR
, "Can't add IPC socket to main poll loop");
201 qdevice_ipc_close(struct qdevice_instance
*instance
)
205 res
= unix_socket_ipc_close(&instance
->local_ipc
);
207 log_err(LOG_WARNING
, "Can't close local IPC");
214 qdevice_ipc_is_closed(struct qdevice_instance
*instance
)
217 return (unix_socket_ipc_is_closed(&instance
->local_ipc
));
221 qdevice_ipc_destroy(struct qdevice_instance
*instance
)
224 struct unix_socket_client
*client
;
225 const struct unix_socket_client_list
*ipc_client_list
;
227 ipc_client_list
= &instance
->local_ipc
.clients
;
229 TAILQ_FOREACH(client
, ipc_client_list
, entries
) {
230 free(client
->user_data
);
233 res
= unix_socket_ipc_destroy(&instance
->local_ipc
);
235 log_err(LOG_WARNING
, "Can't destroy local IPC");
242 qdevice_ipc_accept(struct qdevice_instance
*instance
, struct unix_socket_client
**res_client
)
247 accept_res
= unix_socket_ipc_accept(&instance
->local_ipc
, res_client
);
249 switch (accept_res
) {
251 log_err(LOG_ERR
, "Can't accept local IPC connection");
256 log(LOG_ERR
, "Maximum IPC clients reached. Not accepting connection");
261 log(LOG_ERR
, "Can't add client to list");
266 unix_socket_client_read_line(*res_client
, 1);
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");
275 qdevice_ipc_client_disconnect(instance
, *res_client
);
279 memset((*res_client
)->user_data
, 0, sizeof(struct qdevice_ipc_user_data
));
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");
290 qdevice_ipc_client_disconnect(instance
, *res_client
);
300 qdevice_ipc_client_disconnect(struct qdevice_instance
*instance
, struct unix_socket_client
*client
)
303 free(client
->user_data
);
304 unix_socket_ipc_client_disconnect(&instance
->local_ipc
, client
);
308 qdevice_ipc_send_error(struct qdevice_instance
*instance
, struct unix_socket_client
*client
,
309 const char *error_fmt
, ...)
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));
322 unix_socket_client_write_buffer(client
, 1);
324 log(LOG_ERR
, "Can't send ipc error to client (buffer too small)");
327 return (res
? 0 : -1);
331 qdevice_ipc_send_buffer(struct qdevice_instance
*instance
, struct unix_socket_client
*client
)
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)");
337 if (qdevice_ipc_send_error(instance
, client
, "Internal IPC buffer too small") != 0) {
344 unix_socket_client_write_buffer(client
, 1);
350 qdevice_ipc_parse_line(struct qdevice_instance
*instance
, struct unix_socket_client
*client
)
352 struct dynar_simple_lex lex
;
355 struct qdevice_ipc_user_data
*ipc_user_data
;
358 ipc_user_data
= (struct qdevice_ipc_user_data
*)client
->user_data
;
360 dynar_simple_lex_init(&lex
, &client
->receive_buffer
, DYNAR_SIMPLE_LEX_TYPE_PLAIN
);
361 token
= dynar_simple_lex_token_next(&lex
);
366 log(LOG_ERR
, "Can't alloc memory for simple lex");
368 if (qdevice_ipc_send_error(instance
, client
, "Command too long") != 0) {
369 client
->schedule_disconnect
= 1;
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;
381 } else if (strcasecmp(str
, "shutdown") == 0) {
382 log(LOG_DEBUG
, "IPC client requested shutdown");
384 ipc_user_data
->shutdown_requested
= 1;
386 if (qdevice_ipc_send_buffer(instance
, client
) != 0) {
387 client
->schedule_disconnect
= 1;
389 } else if (strcasecmp(str
, "status") == 0) {
390 token
= dynar_simple_lex_token_next(&lex
);
392 if (token
!= NULL
&& (str
= dynar_data(token
), strcmp(str
, "")) != 0) {
393 if (strcasecmp(str
, "verbose") == 0) {
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;
403 if (qdevice_ipc_send_buffer(instance
, client
) != 0) {
404 client
->schedule_disconnect
= 1;
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;
414 dynar_simple_lex_destroy(&lex
);
418 qdevice_ipc_io_read(struct qdevice_instance
*instance
, struct unix_socket_client
*client
)
422 res
= unix_socket_client_io_read(client
);
431 log(LOG_DEBUG
, "IPC client closed connection");
432 client
->schedule_disconnect
= 1;
435 log(LOG_ERR
, "Can't store message from IPC client. Disconnecting client.");
436 client
->schedule_disconnect
= 1;
439 log_err(LOG_ERR
, "Can't receive message from IPC client. Disconnecting client.");
440 client
->schedule_disconnect
= 1;
444 * Full message received
446 unix_socket_client_read_line(client
, 0);
448 qdevice_ipc_parse_line(instance
, client
);
454 qdevice_ipc_io_write(struct qdevice_instance
*instance
, struct unix_socket_client
*client
)
457 struct qdevice_ipc_user_data
*ipc_user_data
;
459 ipc_user_data
= (struct qdevice_ipc_user_data
*)client
->user_data
;
461 res
= unix_socket_client_io_write(client
);
470 log(LOG_DEBUG
, "IPC client closed connection");
471 client
->schedule_disconnect
= 1;
474 log_err(LOG_ERR
, "Can't send message to IPC client. Disconnecting client");
475 client
->schedule_disconnect
= 1;
481 unix_socket_client_write_buffer(client
, 0);
482 client
->schedule_disconnect
= 1;
484 if (ipc_user_data
->shutdown_requested
) {
485 qdevice_ipc_close(instance
);