diff options
author | Mattias Andrée <maandree@operamail.com> | 2015-08-18 20:21:55 +0200 |
---|---|---|
committer | Mattias Andrée <maandree@operamail.com> | 2015-08-18 20:21:55 +0200 |
commit | f053e4c774d0053fe80dc8cf1c43c22c9d77f546 (patch) | |
tree | 392d61bb24adb651d78fbe86f7c54ebea640d9be /src/mds-colour.c | |
parent | typo (diff) | |
download | mds-f053e4c774d0053fe80dc8cf1c43c22c9d77f546.tar.gz mds-f053e4c774d0053fe80dc8cf1c43c22c9d77f546.tar.bz2 mds-f053e4c774d0053fe80dc8cf1c43c22c9d77f546.tar.xz |
beginning of mds-colour
Signed-off-by: Mattias Andrée <maandree@operamail.com>
Diffstat (limited to 'src/mds-colour.c')
-rw-r--r-- | src/mds-colour.c | 323 |
1 files changed, 323 insertions, 0 deletions
diff --git a/src/mds-colour.c b/src/mds-colour.c new file mode 100644 index 0000000..267c0ba --- /dev/null +++ b/src/mds-colour.c @@ -0,0 +1,323 @@ +/** + * mds — A micro-display server + * Copyright © 2014, 2015 Mattias Andrée (maandree@member.fsf.org) + * + * 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 3 of the License, 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, see <http://www.gnu.org/licenses/>. + */ +#include "mds-colour.h" +/* TODO reload settings on SIGUSR2 */ +/* TODO --save-changes */ + +#include <libmdsserver/macros.h> +#include <libmdsserver/util.h> +#include <libmdsserver/mds-message.h> + +#include <errno.h> +#include <inttypes.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#define reconnect_to_display() -1 + + + +#define MDS_COLOUR_VARS_VERSION 0 + + + +/** + * This variable should declared by the actual server implementation. + * It must be configured before `main` is invoked. + * + * This tells the server-base how to behave + */ +server_characteristics_t server_characteristics = + { + .require_privileges = 0, + .require_display = 1, + .require_respawn_info = 0, + .sanity_check_argc = 1, + .fork_for_safety = 0, + .danger_is_deadly = 0 + }; + + + +/** + * Value of the ‘Message ID’ header for the next message + */ +static uint32_t message_id = 1; + +/** + * Buffer for received messages + */ +static mds_message_t received; + +/** + * Whether the server is connected to the display + */ +static int connected = 1; + +/** + * Buffer for sending messages + */ +static char* send_buffer = NULL; + +/** + * The size allocated to `send_buffer` divided by `sizeof(char)` + */ +static size_t send_buffer_size = 0; + + + +/** + * This function will be invoked before `initialise_server` (if not re-exec:ing) + * or before `unmarshal_server` (if re-exec:ing) + * + * @return Non-zero on error + */ +int __attribute__((const)) preinitialise_server(void) +{ + return 0; +} + + +/** + * This function should initialise the server, + * and it not invoked after a re-exec. + * + * @return Non-zero on error + */ +int initialise_server(void) +{ + int stage = 0; + const char* const message = + "Command: intercept\n" + "Message ID: 0\n" + "Length: 62\n" + "\n" + "Command: list-colours\n" + "Command: get-colour\n" + "Command: set-colour\n"; + + fail_if (full_send(message, strlen(message))); + fail_if (server_initialised() < 0); stage++; + fail_if (mds_message_initialise(&received)); + + return 0; + fail: + xperror(*argv); + if (stage == 1) + mds_message_destroy(&received); + return 1; +} + + +/** + * This function will be invoked after `initialise_server` (if not re-exec:ing) + * or after `unmarshal_server` (if re-exec:ing) + * + * @return Non-zero on error + */ +int postinitialise_server(void) +{ + if (connected) + return 0; + + fail_if (reconnect_to_display()); + connected = 1; + return 0; + fail: + mds_message_destroy(&received); + return 1; +} + + +/** + * Calculate the number of bytes that will be stored by `marshal_server` + * + * On failure the program should `abort()` or exit by other means. + * However it should not be possible for this function to fail. + * + * @return The number of bytes that will be stored by `marshal_server` + */ +size_t marshal_server_size(void) +{ + return 2 * sizeof(int) + sizeof(uint32_t) + mds_message_marshal_size(&received); +} + + +/** + * Marshal server implementation specific data into a buffer + * + * @param state_buf The buffer for the marshalled data + * @return Non-zero on error + */ +int marshal_server(char* state_buf) +{ + buf_set_next(state_buf, int, MDS_COLOUR_VARS_VERSION); + buf_set_next(state_buf, int, connected); + buf_set_next(state_buf, uint32_t, message_id); + mds_message_marshal(&received, state_buf); + + mds_message_destroy(&received); + return 0; +} + + +/** + * Unmarshal server implementation specific data and update the servers state accordingly + * + * On critical failure the program should `abort()` or exit by other means. + * That is, do not let `reexec_failure_recover` run successfully, if it unrecoverable + * error has occurred or one severe enough that it is better to simply respawn. + * + * @param state_buf The marshalled data that as not been read already + * @return Non-zero on error + */ +int unmarshal_server(char* state_buf) +{ + /* buf_get_next(state_buf, int, MDS_COLOUR_VARS_VERSION); */ + buf_next(state_buf, int, 1); + buf_get_next(state_buf, int, connected); + buf_get_next(state_buf, uint32_t, message_id); + fail_if (mds_message_unmarshal(&received, state_buf)); + return 0; + fail: + xperror(*argv); + mds_message_destroy(&received); + return -1; +} + + +/** + * Attempt to recover from a re-exec failure that has been + * detected after the server successfully updated it execution image + * + * @return Non-zero on error + */ +int __attribute__((const)) reexec_failure_recover(void) +{ + return -1; +} + + +/** + * Perform the server's mission + * + * @return Non-zero on error + */ +int master_loop(void) +{ + int rc = 1, r; + + while (!reexecing && !terminating) + { + if (danger) + { + danger = 0; + free(send_buffer), send_buffer = NULL; + send_buffer_size = 0; + } + + if (r = mds_message_read(&received, socket_fd), r == 0) + if (r = handle_message(), r == 0) + continue; + + if (r == -2) + { + eprint("corrupt message received, aborting."); + goto done; + } + else if (errno == EINTR) + continue; + else + fail_if (errno != ECONNRESET); + + eprint("lost connection to server."); + mds_message_destroy(&received); + mds_message_initialise(&received); + connected = 0; + fail_if (reconnect_to_display()); + connected = 1; + } + + rc = 0; + goto done; + fail: + xperror(*argv); + done: + if (rc || !reexecing) + mds_message_destroy(&received); + free(send_buffer); + return rc; +} + + +/** + * Handle the received message + * + * @return Zero on success, -1 on error + */ +int handle_message(void) +{ +} + + +/** + * Send a full message even if interrupted + * + * @param message The message to send + * @param length The length of the message + * @return Zero on success, -1 on error + */ +int full_send(const char* message, size_t length) +{ + size_t sent; + + while (length > 0) + { + sent = send_message(socket_fd, message, length); + if (sent > length) + { + eprint("Sent more of a message than exists in the message, aborting."); + return -1; + } + else + fail_if ((sent < length) && (errno != EINTR)); + message += sent; + length -= sent; + } + return 0; + fail: + xperror(*argv); + return -1; +} + + +/** + * This function is called when a signal that + * signals that the system to dump state information + * and statistics has been received + * + * @param signo The signal that has been received + */ +void received_info(int signo) +{ + (void) signo; + iprintf("next message ID: %" PRIu32, message_id); + iprintf("connected: %s", connected ? "yes" : "no"); + iprintf("send buffer size: %zu bytes", send_buffer_size); +} + |