diff options
| author | Ray Strode <rstrode@redhat.com> | 2007-06-03 20:11:58 -0400 |
|---|---|---|
| committer | Ray Strode <rstrode@redhat.com> | 2007-06-03 20:11:58 -0400 |
| commit | ee407ee53bffa7e7c3073237abefd62eb9cd9595 (patch) | |
| tree | 710932bcb7c66908c6ebf8aec2e07b5002f4f7f3 /src | |
| parent | a6f81dcdf95c6be75d2bc4657d23ebb9272e3a2d (diff) | |
| download | plymouth-ee407ee53bffa7e7c3073237abefd62eb9cd9595.tar.gz plymouth-ee407ee53bffa7e7c3073237abefd62eb9cd9595.tar.xz plymouth-ee407ee53bffa7e7c3073237abefd62eb9cd9595.zip | |
add the start of some classes for tracking boot status
Diffstat (limited to 'src')
| -rw-r--r-- | src/ply-boot-client.c | 449 | ||||
| -rw-r--r-- | src/ply-boot-client.h | 57 | ||||
| -rw-r--r-- | src/ply-boot-server.c | 255 | ||||
| -rw-r--r-- | src/ply-boot-server.h | 46 | ||||
| -rw-r--r-- | src/tests/Makefile.am | 1 |
5 files changed, 808 insertions, 0 deletions
diff --git a/src/ply-boot-client.c b/src/ply-boot-client.c new file mode 100644 index 0000000..ebcd76f --- /dev/null +++ b/src/ply-boot-client.c @@ -0,0 +1,449 @@ +/* ply-boot-client.h - APIs for talking to the boot status daemon + * + * Copyright (C) 2007 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by: Ray Strode <rstrode@redhat.com> + */ +#include "config.h" +#include "ply-boot-client.h" + +#include <assert.h> +#include <errno.h> +#include <stdint.h> +#include <stdlib.h> +#include <unistd.h> + +#include "ply-event-loop.h" +#include "ply-list.h" +#include "ply-logger.h" +#include "ply-utils.h" + +struct _ply_boot_client +{ + ply_event_loop_t *loop; + ply_fd_watch_t *daemon_can_take_request_watch; + ply_fd_watch_t *daemon_has_reply_watch; + ply_list_t *requests_to_send; + ply_list_t *requests_waiting_for_replies; + int socket_fd; + + ply_boot_client_disconnect_handler_t disconnect_handler; + void *disconnect_handler_user_data; + + uint32_t is_connected : 1; +}; + +typedef struct +{ + ply_boot_client_t *client; + char *string; + ply_boot_client_response_handler_t handler; + ply_boot_client_response_handler_t failed_handler; + void *user_data; +} ply_boot_client_request_t; + +static void ply_boot_client_cancel_request (ply_boot_client_t *client, + ply_boot_client_request_t *request); + + +ply_boot_client_t * +ply_boot_client_new (void) +{ + ply_boot_client_t *client; + + client = calloc (1, sizeof (ply_boot_client_t)); + client->daemon_can_take_request_watch = NULL; + client->daemon_has_reply_watch = NULL; + client->requests_to_send = ply_list_new (); + client->requests_waiting_for_replies = ply_list_new (); + client->loop = NULL; + client->is_connected = false; + client->disconnect_handler = NULL; + client->disconnect_handler_user_data = NULL; + + return client; +} + +static void +ply_boot_client_cancel_requests (ply_boot_client_t *client) +{ + ply_list_node_t *node; + + node = ply_list_get_first_node (client->requests_to_send); + while (node != NULL) + { + ply_boot_client_request_t *request; + + request = (ply_boot_client_request_t *) ply_list_node_get_data (node); + + ply_boot_client_cancel_request (client, request); + + node = ply_list_get_next_node (client->requests_to_send, node); + } + + node = ply_list_get_first_node (client->requests_waiting_for_replies); + while (node != NULL) + { + ply_boot_client_request_t *request; + + request = (ply_boot_client_request_t *) ply_list_node_get_data (node); + + ply_boot_client_cancel_request (client, request); + + node = ply_list_get_next_node (client->requests_waiting_for_replies, node); + } +} + +void +ply_boot_client_free (ply_boot_client_t *client) +{ + if (client == NULL) + return; + + ply_boot_client_cancel_requests (client); + + ply_list_free (client->requests_to_send); + ply_list_free (client->requests_waiting_for_replies); + + free (client); +} + +bool +ply_boot_client_connect (ply_boot_client_t *client, + ply_boot_client_disconnect_handler_t disconnect_handler, + void *user_data) +{ + assert (client != NULL); + assert (!client->is_connected); + assert (client->disconnect_handler == NULL); + assert (client->disconnect_handler_user_data == NULL); + + client->socket_fd = + ply_connect_to_unix_socket (PLY_BOOT_PROTOCOL_SOCKET_PATH, true); + + if (client->socket_fd < 0) + return false; + + client->disconnect_handler = disconnect_handler; + client->disconnect_handler_user_data = user_data; + + client->is_connected = true; + return true; +} + +static ply_boot_client_request_t * +ply_boot_client_request_new (ply_boot_client_t *client, + const char *request_string, + ply_boot_client_response_handler_t handler, + ply_boot_client_response_handler_t failed_handler, + void *user_data) +{ + ply_boot_client_request_t *request; + + assert (client != NULL); + assert (request_string != NULL); + assert (handler != NULL); + + request = calloc (1, sizeof (ply_boot_client_request_t)); + request->client = client; + request->string = strdup (request_string); + request->handler = handler; + request->failed_handler = failed_handler; + request->user_data = user_data; + + return request; +} + +static void +ply_boot_client_request_free (ply_boot_client_request_t *request) +{ + if (request == NULL) + return; + free (request->string); + free (request); +} + +static void +ply_boot_client_cancel_request (ply_boot_client_t *client, + ply_boot_client_request_t *request) +{ + if (request->failed_handler != NULL) + request->failed_handler (request->user_data, request->client); + + ply_boot_client_request_free (request); +} + +static void +ply_boot_client_process_incoming_replies (ply_boot_client_t *client) +{ + ply_list_node_t *request_node; + ply_boot_client_request_t *request; + uint8_t byte[2] = ""; + + assert (client != NULL); + + if (ply_list_get_length (client->requests_waiting_for_replies) == 0) + { + ply_error ("received unexpected response from boot status daemon"); + return; + } + + request_node = ply_list_get_first_node (client->requests_waiting_for_replies); + assert (request_node != NULL); + + request = (ply_boot_client_request_t *) ply_list_node_get_data (request_node); + assert (request != NULL); + + if (!ply_read (client->socket_fd, byte, sizeof (uint8_t))) + { + if (request->failed_handler != NULL) + request->failed_handler (request->user_data, client); + ply_list_remove_node (client->requests_waiting_for_replies, request_node); + return; + } + + if (memcmp (byte, PLY_BOOT_PROTOCOL_RESPONSE_TYPE_ACK, sizeof (uint8_t)) != 0) + { + if (request->failed_handler != NULL) + request->failed_handler (request->user_data, client); + ply_list_remove_node (client->requests_waiting_for_replies, request_node); + return; + } + + request->handler (request->user_data, client); + ply_list_remove_node (client->requests_waiting_for_replies, request_node); + + if (ply_list_get_length (client->requests_waiting_for_replies) == 0) + { + ply_event_loop_stop_watching_fd (client->loop, + client->daemon_has_reply_watch); + client->daemon_has_reply_watch = NULL; + } +} + +static bool +ply_boot_client_send_request (ply_boot_client_t *client, + ply_boot_client_request_t *request) +{ + if (!ply_write (client->socket_fd, request->string, + strlen (request->string))) + { + ply_boot_client_cancel_request (client, request); + return false; + } + + if (client->daemon_has_reply_watch == NULL) + { + assert (ply_list_get_length (client->requests_waiting_for_replies) == 0); + client->daemon_has_reply_watch = + ply_event_loop_watch_fd (client->loop, client->socket_fd, + PLY_EVENT_LOOP_FD_STATUS_HAS_DATA, + (ply_event_handler_t) + ply_boot_client_process_incoming_replies, + NULL, client); + } + + return true; +} + +static void +ply_boot_client_process_pending_requests (ply_boot_client_t *client) +{ + ply_list_node_t *request_node; + ply_boot_client_request_t *request; + + assert (ply_list_get_length (client->requests_to_send) != 0); + assert (client->daemon_can_take_request_watch != NULL); + + request_node = ply_list_get_first_node (client->requests_to_send); + assert (request_node != NULL); + + request = (ply_boot_client_request_t *) ply_list_node_get_data (request_node); + assert (request != NULL); + + ply_list_remove_node (client->requests_to_send, request_node); + + if (ply_boot_client_send_request (client, request)) + ply_list_append_data (client->requests_waiting_for_replies, request); + + if (ply_list_get_length (client->requests_to_send) == 0) + { + ply_event_loop_stop_watching_fd (client->loop, + client->daemon_can_take_request_watch); + client->daemon_can_take_request_watch = NULL; + } +} + +static void +ply_boot_client_queue_request (ply_boot_client_t *client, + const char *request_string, + ply_boot_client_response_handler_t handler, + ply_boot_client_response_handler_t failed_handler, + void *user_data) +{ + ply_boot_client_request_t *request; + + assert (client != NULL); + assert (client->loop != NULL); + assert (client->socket_fd >= 0); + assert (request_string != NULL); + assert (handler != NULL); + + if (client->daemon_can_take_request_watch == NULL) + { + assert (ply_list_get_length (client->requests_to_send) == 0); + client->daemon_can_take_request_watch = ply_event_loop_watch_fd (client->loop, client->socket_fd, + PLY_EVENT_LOOP_FD_STATUS_CAN_TAKE_DATA, + (ply_event_handler_t) + ply_boot_client_process_pending_requests, + NULL, client); + } + + request = ply_boot_client_request_new (client, request_string, handler, + failed_handler, user_data); + ply_list_append_data (client->requests_to_send, request); +} + +void +ply_boot_client_ping_daemon (ply_boot_client_t *client, + ply_boot_client_response_handler_t handler, + ply_boot_client_response_handler_t failed_handler, + void *user_data) +{ + assert (client != NULL); + + ply_boot_client_queue_request (client, PLY_BOOT_PROTOCOL_REQUEST_TYPE_PING, + handler, failed_handler, user_data); +} + +void +ply_boot_client_disconnect (ply_boot_client_t *client) +{ + assert (client != NULL); + + close (client->socket_fd); + client->socket_fd = -1; + client->is_connected = false; +} + +static void +ply_boot_client_detach_from_event_loop (ply_boot_client_t *client) +{ + assert (client != NULL); + client->loop = NULL; +} + +static void +ply_boot_client_on_hangup (ply_boot_client_t *client) +{ + assert (client != NULL); + ply_boot_client_cancel_requests (client); + + if (client->disconnect_handler != NULL) + client->disconnect_handler (client->disconnect_handler_user_data, + client); +} + +void +ply_boot_client_attach_to_event_loop (ply_boot_client_t *client, + ply_event_loop_t *loop) +{ + assert (client != NULL); + assert (loop != NULL); + assert (client->loop == NULL); + assert (client->socket_fd >= 0); + + client->loop = loop; + + ply_event_loop_watch_fd (client->loop, client->socket_fd, + PLY_EVENT_LOOP_FD_STATUS_NONE, + NULL, + (ply_event_handler_t) ply_boot_client_on_hangup, + client); + + ply_event_loop_watch_for_exit (loop, (ply_event_loop_exit_handler_t) + ply_boot_client_detach_from_event_loop, + client); + +} + +#ifdef PLY_BOOT_CLIENT_ENABLE_TEST + +#include <stdio.h> + +#include "ply-event-loop.h" +#include "ply-boot-client.h" + +static void +on_pinged (ply_event_loop_t *loop) +{ + printf ("PING!\n"); + ply_event_loop_exit (loop, 0); +} + +static void +on_failed (ply_event_loop_t *loop) +{ + printf ("FAILED! %m\n"); + ply_event_loop_exit (loop, 1); +} + +static void +on_disconnect (ply_event_loop_t *loop) +{ + printf ("DISCONNECT!\n"); + ply_event_loop_exit (loop, 1); +} + +int +main (int argc, + char **argv) +{ + ply_event_loop_t *loop; + ply_boot_client_t *client; + int exit_code; + + exit_code = 0; + + loop = ply_event_loop_new (); + + client = ply_boot_client_new (); + + if (!ply_boot_client_connect (client, + (ply_boot_client_disconnect_handler_t) on_disconnect, + loop)) + { + perror ("could not start boot client"); + return errno; + } + + ply_boot_client_attach_to_event_loop (client, loop); + ply_boot_client_ping_daemon (client, + (ply_boot_client_response_handler_t) on_pinged, + (ply_boot_client_response_handler_t) on_failed, + loop); + + exit_code = ply_event_loop_run (loop); + + ply_boot_client_free (client); + + return exit_code; +} + +#endif /* PLY_BOOT_CLIENT_ENABLE_TEST */ +/* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */ diff --git a/src/ply-boot-client.h b/src/ply-boot-client.h new file mode 100644 index 0000000..96d123f --- /dev/null +++ b/src/ply-boot-client.h @@ -0,0 +1,57 @@ +/* ply-boot-client.h - APIs for talking to the boot status daemon + * + * Copyright (C) 2007 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written By: Ray Strode <rstrode@redhat.com> + */ +#ifndef PLY_BOOT_CLIENT_H +#define PLY_BOOT_CLIENT_H + +#include <stdbool.h> +#include <stdint.h> +#include <unistd.h> + +#include "ply-boot-protocol.h" +#include "ply-event-loop.h" + +typedef struct _ply_boot_client ply_boot_client_t; +typedef void (* ply_boot_client_response_handler_t) (void *user_data, + ply_boot_client_t *client); +typedef void (* ply_boot_client_disconnect_handler_t) (void *user_data, + ply_boot_client_t *client); + +#ifndef PLY_HIDE_FUNCTION_DECLARATIONS +ply_boot_client_t *ply_boot_client_new (void); + +void ply_boot_client_free (ply_boot_client_t *client); +bool ply_boot_client_connect (ply_boot_client_t *client, + ply_boot_client_disconnect_handler_t disconnect_handler, + void *user_data); +void ply_boot_client_ping_daemon (ply_boot_client_t *client, + ply_boot_client_response_handler_t handler, + ply_boot_client_response_handler_t failed_handler, + void *user_data); + +void ply_boot_client_disconnect (ply_boot_client_t *client); +void ply_boot_client_attach_to_event_loop (ply_boot_client_t *client, + ply_event_loop_t *loop); + +#endif + +#endif /* PLY_BOOT_CLIENT_H */ +/* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */ diff --git a/src/ply-boot-server.c b/src/ply-boot-server.c new file mode 100644 index 0000000..f1dc4d2 --- /dev/null +++ b/src/ply-boot-server.c @@ -0,0 +1,255 @@ +/* ply-boot-server.c - listens for and processes boot-status events + * + * Copyright (C) 2007 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by: Ray Strode <rstrode@redhat.com> + */ +#include "config.h" +#include "ply-boot-server.h" + +#include <assert.h> +#include <errno.h> +#include <stdint.h> +#include <stdlib.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <unistd.h> + +#include "ply-event-loop.h" +#include "ply-list.h" +#include "ply-logger.h" +#include "ply-utils.h" + +typedef struct +{ + int fd; + ply_fd_watch_t *watch; + ply_boot_server_t *server; +} ply_boot_connection_t; + +struct _ply_boot_server +{ + ply_event_loop_t *loop; + ply_list_t *connections; + int socket_fd; + + uint32_t is_listening : 1; +}; + +ply_boot_server_t * +ply_boot_server_new (void) +{ + ply_boot_server_t *server; + + server = calloc (1, sizeof (ply_boot_server_t)); + server->connections = ply_list_new (); + server->loop = NULL; + server->is_listening = false; + + return server; +} + +void +ply_boot_server_free (ply_boot_server_t *server) +{ + if (server == NULL) + return; + + ply_list_free (server->connections); + free (server); +} + +static ply_boot_connection_t * +ply_boot_connection_new (ply_boot_server_t *server, + int fd) +{ + ply_boot_connection_t *connection; + + connection = calloc (1, sizeof (ply_boot_server_t)); + connection->fd = fd; + connection->server = server; + connection->watch = NULL; + + return connection; +} + +static void +ply_boot_connection_free (ply_boot_connection_t *connection) +{ + if (connection == NULL) + return; + + close (connection->fd); + free (connection); +} + +bool +ply_boot_server_listen (ply_boot_server_t *server) +{ + assert (server != NULL); + + server->socket_fd = + ply_listen_to_unix_socket (PLY_BOOT_PROTOCOL_SOCKET_PATH, true); + + if (server->socket_fd < 0) + return false; + + return true; +} + +void +ply_boot_server_stop_listening (ply_boot_server_t *server) +{ + assert (server != NULL); +} + +static void +ply_boot_connection_on_request (ply_boot_connection_t *connection) +{ + uint8_t byte; + + assert (connection != NULL); + assert (connection->fd >= 0); + + if (read (connection->fd, &byte, sizeof (byte)) != 1) + return; + + ply_write (connection->fd, + PLY_BOOT_PROTOCOL_RESPONSE_TYPE_ACK, + strlen (PLY_BOOT_PROTOCOL_RESPONSE_TYPE_ACK)); +} + +static void +ply_boot_connection_on_hangup (ply_boot_connection_t *connection) +{ + ply_list_node_t *node; + ply_boot_server_t *server; + + assert (connection != NULL); + assert (connection->server != NULL); + + server = connection->server; + + node = ply_list_find_node (server->connections, connection); + + assert (node != NULL); + + ply_boot_connection_free (connection); + ply_list_remove_node (server->connections, node); +} + +static void +ply_boot_server_on_new_connection (ply_boot_server_t *server) +{ + ply_boot_connection_t *connection; + int fd; + + assert (server != NULL); + + fd = accept (server->socket_fd, NULL, NULL); + + if (fd < 0) + return; + + connection = ply_boot_connection_new (server, fd); + + connection->watch = + ply_event_loop_watch_fd (server->loop, fd, + PLY_EVENT_LOOP_FD_STATUS_HAS_DATA, + (ply_event_handler_t) + ply_boot_connection_on_request, + (ply_event_handler_t) + ply_boot_connection_on_hangup, + connection); + + ply_list_append_data (server->connections, connection); +} + +static void +ply_boot_server_on_hangup (ply_boot_server_t *server) +{ + assert (server != NULL); +} + +static void +ply_boot_server_detach_from_event_loop (ply_boot_server_t *server) +{ + assert (server != NULL); + server->loop = NULL; +} + +void +ply_boot_server_attach_to_event_loop (ply_boot_server_t *server, + ply_event_loop_t *loop) +{ + assert (server != NULL); + assert (loop != NULL); + assert (server->loop == NULL); + assert (server->socket_fd >= 0); + + server->loop = loop; + + ply_event_loop_watch_fd (loop, server->socket_fd, + PLY_EVENT_LOOP_FD_STATUS_HAS_DATA, + (ply_event_handler_t) + ply_boot_server_on_new_connection, + (ply_event_handler_t) + ply_boot_server_on_hangup, + server); + ply_event_loop_watch_for_exit (loop, (ply_event_loop_exit_handler_t) + ply_boot_server_detach_from_event_loop, + server); +} + +#ifdef PLY_BOOT_SERVER_ENABLE_TEST + +#include <stdio.h> + +#include "ply-event-loop.h" +#include "ply-boot-server.h" + +int +main (int argc, + char **argv) +{ + ply_event_loop_t *loop; + ply_boot_server_t *server; + int exit_code; + + exit_code = 0; + + loop = ply_event_loop_new (); + + server = ply_boot_server_new (); + + if (!ply_boot_server_listen (server)) + { + perror ("could not start boot status daemon"); + return errno; + } + + ply_boot_server_attach_to_event_loop (server, loop); + exit_code = ply_event_loop_run (loop); + + ply_boot_server_free (server); + + return exit_code; +} + +#endif /* PLY_BOOT_SERVER_ENABLE_TEST */ +/* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */ diff --git a/src/ply-boot-server.h b/src/ply-boot-server.h new file mode 100644 index 0000000..2fdbd32 --- /dev/null +++ b/src/ply-boot-server.h @@ -0,0 +1,46 @@ +/* ply-boot-server.h - APIs for talking to the boot status daemon + * + * Copyright (C) 2007 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written By: Ray Strode <rstrode@redhat.com> + */ +#ifndef PLY_BOOT_SERVER_H +#define PLY_BOOT_SERVER_H + +#include <stdbool.h> +#include <stdint.h> +#include <unistd.h> + +#include "ply-boot-protocol.h" +#include "ply-event-loop.h" + +typedef struct _ply_boot_server ply_boot_server_t; + +#ifndef PLY_HIDE_FUNCTION_DECLARATIONS +ply_boot_server_t *ply_boot_server_new (void); + +void ply_boot_server_free (ply_boot_server_t *server); +bool ply_boot_server_listen (ply_boot_server_t *server); +void ply_boot_server_stop_listening (ply_boot_server_t *server); +void ply_boot_server_attach_to_event_loop (ply_boot_server_t *server, + ply_event_loop_t *loop); + +#endif + +#endif /* PLY_BOOT_SERVER_H */ +/* vim: set ts=4 sw=4 expandtab autoindent cindent cino={.5s,(0: */ diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am index e4d7773..6fa2e10 100644 --- a/src/tests/Makefile.am +++ b/src/tests/Makefile.am @@ -13,5 +13,6 @@ include $(srcdir)/ply-logger-test.am include $(srcdir)/ply-list-test.am include $(srcdir)/ply-event-loop-test.am include $(srcdir)/ply-boot-client-test.am +include $(srcdir)/ply-boot-server-test.am noinst_PROGRAMS = $(TESTS) |
