aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile8
-rw-r--r--src/libmdsserver/linked-list.h2
-rw-r--r--src/mds-base.c22
-rw-r--r--src/mds-base.h41
-rw-r--r--src/mds-server/globals.c6
-rw-r--r--src/mds-server/globals.h29
-rw-r--r--src/mds-server/mds-server.c201
-rw-r--r--src/mds-server/mds-server.h5
-rw-r--r--src/mds-server/reexec.c243
-rw-r--r--src/mds-server/reexec.h54
-rw-r--r--src/mds-server/sending.c6
-rw-r--r--src/mds-server/signals.c65
-rw-r--r--src/mds-server/signals.h31
-rw-r--r--src/mds-server/slavery.c18
-rw-r--r--src/mds-server/slavery.h12
15 files changed, 275 insertions, 468 deletions
diff --git a/Makefile b/Makefile
index 9539a7d..faf08df 100644
--- a/Makefile
+++ b/Makefile
@@ -76,17 +76,17 @@ LIBOBJ = linked-list hash-table fd-table mds-message util
# Build rules.
.PHONY: all
-all: bin/mds bin/mds-server bin/libmdsserver.so obj/mds-base.o
+all: obj/mds-base.o bin/mds bin/mds-server bin/libmdsserver.so
MDS_SERVER_OBJ_ = mds-server interception_condition client multicast \
queued_interception globals signals interceptors \
sending slavery reexec receiving
-MDS_SERVER_OBJ = $(foreach O,$(MDS_SERVER_OBJ_),mds-server/$(O))
+MDS_SERVER_OBJ = obj/mds-base.o $(foreach O,$(MDS_SERVER_OBJ_),obj/mds-server/$(O).o)
-bin/mds-server: $(foreach O,$(MDS_SERVER_OBJ),obj/$(O).o) bin/libmdsserver.so
+bin/mds-server: $(MDS_SERVER_OBJ) bin/libmdsserver.so
mkdir -p $(shell dirname $@)
- $(CC) $(C_FLAGS) -o $@ $(LDS) $(foreach O,$(MDS_SERVER_OBJ),obj/$(O).o)
+ $(CC) $(C_FLAGS) -o $@ $(LDS) $(MDS_SERVER_OBJ)
ifeq ($(DEBUG),y)
mv $@ $@.real
cp test.d/mds-server $@
diff --git a/src/libmdsserver/linked-list.h b/src/libmdsserver/linked-list.h
index 30808fc..5b1a44d 100644
--- a/src/libmdsserver/linked-list.h
+++ b/src/libmdsserver/linked-list.h
@@ -273,7 +273,7 @@ int linked_list_unmarshal(linked_list_t* restrict this, char* restrict data);
* @param node:ssize_t The variable to store the node in at each iteration
*/
#define foreach_linked_list_node(list, node) \
- for (node = list.edge; (node = list.next[node]) != list.edge;)
+ for (node = list.edge; node = list.next[node], node != list.edge;)
#endif
diff --git a/src/mds-base.c b/src/mds-base.c
index 1de8c68..65e5d88 100644
--- a/src/mds-base.c
+++ b/src/mds-base.c
@@ -58,11 +58,14 @@ int socket_fd = -1;
*/
static int parse_cmdline(void)
{
+ int i;
+
#if (LIBEXEC_ARGC_EXTRA_LIMIT < 2)
# error LIBEXEC_ARGC_EXTRA_LIMIT is too small, need at least 2.
#endif
- int i;
+
+ /* Parse command line arguments. */
for (i = 1; i < argc; i++)
{
char* arg = argv[i];
@@ -85,6 +88,12 @@ static int parse_cmdline(void)
is_respawn = 1;
eprint("re-exec performed.");
}
+
+ /* Check that manditory arguments have been specified. */
+ exit_if (is_respawn < 0,
+ eprintf("missing state argument, require either %s or %s.",
+ "--initial-spawn", "--respawn"););
+
return 0;
}
@@ -199,17 +208,18 @@ static int base_marshal(int reexec_fd)
/* Store the state. */
buf_set_next(state_buf_, int, socket_fd);
- marshal_server(state_buf_);
+ fail_if (marshal_server(state_buf_));
/* Send the marshalled data into the file. */
fail_if (full_write(reexec_fd, state_buf, state_n) < 0);
- free(state_buf);
+ free(state_buf);
return 0;
pfail:
perror(*argv);
+ free(state_buf);
return 1;
}
@@ -285,6 +295,9 @@ int main(int argc_, char** argv_)
trap_signals();
+ /* Initialise the server. */
+ try (preinitialise_server());
+
if (is_reexec == 0)
{
if (server_characteristics.require_display)
@@ -300,6 +313,9 @@ int main(int argc_, char** argv_)
try (base_unmarshal());
}
+ /* Initialise the server. */
+ try (postinitialise_server());
+
/* Run the server. */
try (master_loop());
diff --git a/src/mds-base.h b/src/mds-base.h
index 28d7432..e92e73e 100644
--- a/src/mds-base.h
+++ b/src/mds-base.h
@@ -138,6 +138,16 @@ extern void received_terminate(int signo);
/**
* This function should be implemented by the actual server implementation
*
+ * 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
+ */
+extern int preinitialise_server(void);
+
+/**
+ * This function should be implemented by the actual server implementation
+ *
* This function should initialise the server,
* and it not invoked after a re-exec.
*
@@ -148,12 +158,24 @@ extern int initialise_server(void);
/**
* This function should be implemented by the actual server implementation
*
- * Unmarshal server implementation specific data and update the servers state accordingly
+ * This function will be invoked asgter `initialise_server` (if not re-exec:ing)
+ * or after `unmarshal_server` (if re-exec:ing)
*
- * @param state_buf The marshalled data that as not been read already
- * @return Non-zero on error
+ * @return Non-zero on error
*/
-extern int unmarshal_server(char* state_buf);
+extern int postinitialise_server(void);
+
+/**
+ * This function should be implemented by the actual server implementation
+ *
+ * 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`
+ */
+extern size_t marshal_server_size(void) __attribute__((pure));
/**
* This function should be implemented by the actual server implementation
@@ -168,14 +190,12 @@ extern int marshal_server(char* state_buf);
/**
* This function should be implemented by the actual server implementation
*
- * 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.
+ * Unmarshal server implementation specific data and update the servers state accordingly
*
- * @return The number of bytes that will be stored by `marshal_server`
+ * @param state_buf The marshalled data that as not been read already
+ * @return Non-zero on error
*/
-extern size_t marshal_server_size(void);
+extern int unmarshal_server(char* state_buf);
/**
* This function should be implemented by the actual server implementation
@@ -187,7 +207,6 @@ extern size_t marshal_server_size(void);
*/
extern int reexec_failure_recover(void);
-
/**
* This function should be implemented by the actual server implementation
*
diff --git a/src/mds-server/globals.c b/src/mds-server/globals.c
index 0d2c6b6..0f0aa9f 100644
--- a/src/mds-server/globals.c
+++ b/src/mds-server/globals.c
@@ -18,17 +18,11 @@
#include "globals.h"
-int argc;
-char** argv;
-
volatile sig_atomic_t running = 1;
-volatile sig_atomic_t reexecing = 0;
-volatile sig_atomic_t terminating = 0;
size_t running_slaves = 0;
pthread_mutex_t slave_mutex;
pthread_cond_t slave_cond;
-pthread_t master_thread;
fd_table_t client_map;
linked_list_t client_list;
uint64_t next_client_id = 1;
diff --git a/src/mds-server/globals.h b/src/mds-server/globals.h
index 1016ae7..e9465f0 100644
--- a/src/mds-server/globals.h
+++ b/src/mds-server/globals.h
@@ -18,6 +18,8 @@
#ifndef MDS_MDS_SERVER_GLOBALS_H
#define MDS_MDS_SERVER_GLOBALS_H
+#include "../mds-base.h" /* Include here so other do not need to. */
+
#include <libmdsserver/linked-list.h>
#include <libmdsserver/hash-table.h>
@@ -34,32 +36,10 @@
/**
- * Number of elements in `argv`
- */
-extern int argc;
-
-/**
- * Command line arguments
- */
-extern char** argv;
-
-
-/**
* The program run state, 1 when running, 0 when shutting down
*/
extern volatile sig_atomic_t running;
-/**
- * Non-zero when the program is about to re-exec.
- * Most at all times be at least as true as `terminating`.
- */
-extern volatile sig_atomic_t reexecing;
-
-/**
- * Non-zero when the program is about to terminate
- */
-extern volatile sig_atomic_t terminating;
-
/**
* The number of running slaves
@@ -77,11 +57,6 @@ extern pthread_mutex_t slave_mutex;
extern pthread_cond_t slave_cond;
/**
- * The thread that runs the master loop
- */
-extern pthread_t master_thread;
-
-/**
* Map from client socket file descriptor to all information (client_t)
*/
extern fd_table_t client_map;
diff --git a/src/mds-server/mds-server.c b/src/mds-server/mds-server.c
index 3179ee7..b1008cd 100644
--- a/src/mds-server/mds-server.c
+++ b/src/mds-server/mds-server.c
@@ -22,11 +22,9 @@
#include "client.h"
#include "queued_interception.h"
#include "multicast.h"
-#include "signals.h"
#include "interceptors.h"
#include "sending.h"
#include "slavery.h"
-#include "reexec.h"
#include "receiving.h"
#include <libmdsserver/config.h>
@@ -47,19 +45,41 @@
#include <inttypes.h>
+/**
+ * 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 = 0 /* We will service one ourself. */
+ };
+
+
+
+#define __free(I) \
+ if (I > 0) pthread_mutex_destroy(&slave_mutex); \
+ if (I > 1) pthread_cond_destroy(&slave_cond); \
+ if (I > 2) pthread_mutex_destroy(&modify_mutex); \
+ if (I > 3) pthread_cond_destroy(&modify_cond); \
+ if (I >= 4) hash_table_destroy(&modify_map, NULL, NULL); \
+ if (I >= 5) fd_table_destroy(&client_map, NULL, NULL); \
+ if (I >= 6) linked_list_destroy(&client_list)
+
+#define error_if(I, CONDITION) \
+ if (CONDITION) { perror(*argv); __free(I); return 1; }
+
/**
- * Entry point of the server
+ * This function will be invoked before `initialise_server` (if not re-exec:ing)
+ * or before `unmarshal_server` (if re-exec:ing)
*
- * @param argc_ Number of elements in `argv_`
- * @param argv_ Command line arguments
- * @return Non-zero on error
+ * @return Non-zero on error
*/
-int main(int argc_, char** argv_)
+int preinitialise_server(void)
{
- int is_respawn = -1;
- int socket_fd = -1;
- int reexec = 0;
int unparsed_args_ptr = 1;
char* unparsed_args[ARGC_LIMIT + LIBEXEC_ARGC_EXTRA_LIMIT + 1];
int i;
@@ -69,58 +89,27 @@ int main(int argc_, char** argv_)
#endif
- argc = argc_;
- argv = argv_;
-
-
- /* Drop privileges like it's hot. */
- fail_if (drop_privileges());
-
- /* Sanity check the number of command line arguments. */
- exit_if (argc > ARGC_LIMIT + LIBEXEC_ARGC_EXTRA_LIMIT,
- eprint("that number of arguments is ridiculous, I will not allow it."););
-
-
/* Parse command line arguments. */
for (i = 1; i < argc; i++)
{
char* arg = argv[i];
- int v;
- if ((v = strequals(arg, "--initial-spawn")) || /* Initial spawn? */
- strequals(arg, "--respawn")) /* Respawning after crash? */
- {
- exit_if (is_respawn == v,
- eprintf("conflicting arguments %s and %s cannot be combined.",
- "--initial-spawn", "--respawn"););
- is_respawn = !v;
- }
- else if (startswith(arg, "--socket-fd=")) /* Socket file descriptor. */
+ if (startswith(arg, "--socket-fd=")) /* Socket file descriptor. */
{
exit_if (socket_fd != -1,
eprintf("duplicate declaration of %s.", "--socket-fd"););
exit_if (strict_atoi(arg += strlen("--socket-fd="), &socket_fd, 0, INT_MAX) < 0,
eprintf("invalid value for %s: %s.", "--socket-fd", arg););
}
- else if (strequals(arg, "--re-exec")) /* Re-exec state-marshal. */
- reexec = 1;
else if (startswith(arg, "--alarm=")) /* Schedule an alarm signal for forced abort. */
alarm((unsigned)min(atoi(arg + strlen("--alarm=")), 60)); /* At most 1 minute. */
else
- /* Not recognised, it is probably for another server. */
- unparsed_args[unparsed_args_ptr++] = arg;
+ if (!strequals(arg, "--initial-spawn") && !strequals(arg, "--respawn"))
+ /* Not recognised, it is probably for another server. */
+ unparsed_args[unparsed_args_ptr++] = arg;
}
unparsed_args[unparsed_args_ptr] = NULL;
- if (reexec)
- {
- is_respawn = 1;
- eprint("re-exec performed.");
- }
-
/* Check that manditory arguments have been specified. */
- exit_if (is_respawn < 0,
- eprintf("missing state argument, require either %s or %s.",
- "--initial-spawn", "--respawn"););
exit_if (socket_fd < 0,
eprint("missing socket file descriptor argument."););
@@ -142,85 +131,91 @@ int main(int argc_, char** argv_)
}
}
-#define __free(I) \
- if (I >= 0) fd_table_destroy(&client_map, NULL, NULL); \
- if (I >= 1) linked_list_destroy(&client_list); \
- if (I >= 2) pthread_mutex_destroy(&slave_mutex); \
- if (I >= 3) pthread_cond_destroy(&slave_cond); \
- if (I >= 4) pthread_mutex_destroy(&modify_mutex); \
- if (I >= 5) pthread_cond_destroy(&modify_cond); \
- if (I >= 6) hash_table_destroy(&modify_map, NULL, NULL)
-
-#define error_if(I, CONDITION) if (CONDITION) { perror(*argv); __free(I); return 1; }
-
- /* Create list and table of clients. */
- if (reexec == 0)
- {
- error_if (0, fd_table_create(&client_map));
- error_if (1, linked_list_create(&client_list, 32));
- }
-
- /* Store the current thread so it can be killed from elsewhere. */
- master_thread = pthread_self();
-
- /* Set up traps for especially handled signals. */
- error_if (1, trap_signals() < 0);
/* Create mutex and condition for slave counter. */
- error_if (1, (errno = pthread_mutex_init(&slave_mutex, NULL)));
- error_if (2, (errno = pthread_cond_init(&slave_cond, NULL)));
+ error_if (0, (errno = pthread_mutex_init(&slave_mutex, NULL)));
+ error_if (1, (errno = pthread_cond_init(&slave_cond, NULL)));
/* Create mutex, condition and map for message modification. */
- error_if (3, (errno = pthread_mutex_init(&modify_mutex, NULL)));
- error_if (4, (errno = pthread_cond_init(&modify_cond, NULL)));
- error_if (5, hash_table_create(&modify_map));
+ error_if (2, (errno = pthread_mutex_init(&modify_mutex, NULL)));
+ error_if (3, (errno = pthread_cond_init(&modify_cond, NULL)));
+ error_if (4, hash_table_create(&modify_map));
-#undef error_if
+ return 0;
- /* Unmarshal the state of the server. */
- if (reexec)
- complete_reexec(socket_fd);
+ pfail:
+ perror(*argv);
+ return 1;
+}
+
+
+/**
+ * This function should initialise the server,
+ * and it not invoked after a re-exec.
+ *
+ * @return Non-zero on error
+ */
+int initialise_server(void)
+{
+ /* Create list and table of clients. */
+ error_if (5, fd_table_create(&client_map));
+ error_if (6, linked_list_create(&client_list, 32));
+ return 0;
+}
+
+
+/**
+ * This function will be invoked asgter `initialise_server` (if not re-exec:ing)
+ * or after `unmarshal_server` (if re-exec:ing)
+ *
+ * @return Non-zero on error
+ */
+int __attribute__((const)) postinitialise_server(void)
+{
+ /* We do not need to initialise anything else. */
+ return 0;
+}
+
+
+/**
+ * Perform the server's mission
+ *
+ * @return Non-zero on error
+ */
+int master_loop(void)
+{
/* Accepting incoming connections. */
while (running && (terminating == 0))
- if (accept_connection(socket_fd) == 1)
+ if (accept_connection() == 1)
break;
- if (reexecing)
- goto reexec;
-
/* Join with all slaves threads. */
with_mutex (slave_mutex,
while (running_slaves > 0)
pthread_cond_wait(&slave_cond, &slave_mutex););
- /* Release resources. */
- __free(9999);
+ if (reexecing == 0)
+ {
+ /* Release resources. */
+ __free(9999);
+ }
return 0;
-
-#undef __free
-
-
- reexec:
- perform_reexec(reexec);
- /* Returning non-zero is important, otherwise the server cannot
- be respawn if the re-exec fails. */
-
- pfail:
- perror(*argv);
- return 1;
}
+#undef error_if
+#undef __free
+
+
/**
* Accept an incoming and start a slave thread for it
*
- * @param socket_fd The file descriptor of the server socket
- * @return Zero normally, 1 if terminating
+ * @return Zero normally, 1 if terminating
*/
-int accept_connection(int socket_fd)
+int accept_connection(void)
{
pthread_t slave_thread;
int client_fd;
@@ -255,8 +250,8 @@ int accept_connection(int socket_fd)
*/
void* slave_loop(void* data)
{
- int socket_fd = (int)(intptr_t)data;
- size_t information_address = fd_table_get(&client_map, (size_t)socket_fd);
+ int slave_fd = (int)(intptr_t)data;
+ size_t information_address = fd_table_get(&client_map, (size_t)slave_fd);
client_t* information = (client_t*)(void*)information_address;
char* msgbuf = NULL;
char buf[] = "To: all";
@@ -267,7 +262,7 @@ void* slave_loop(void* data)
if (information == NULL) /* Did not re-exec. */
{
/* Initialise the client. */
- fail_if ((information = initialise_client(socket_fd)) == NULL);
+ fail_if ((information = initialise_client(slave_fd)) == NULL);
/* Register client to receive broadcasts. */
add_intercept_condition(information, buf, 0, 0, 0);
@@ -324,7 +319,7 @@ void* slave_loop(void* data)
fail: /* This done on success as well. */
/* Close socket and free resources. */
- close(socket_fd);
+ close(slave_fd);
free(msgbuf);
if (information != NULL)
{
@@ -335,7 +330,7 @@ void* slave_loop(void* data)
/* Unmap client and decrease the slave count. */
with_mutex (slave_mutex,
- fd_table_remove(&client_map, socket_fd);
+ fd_table_remove(&client_map, slave_fd);
running_slaves--;
pthread_cond_signal(&slave_cond););
return NULL;
diff --git a/src/mds-server/mds-server.h b/src/mds-server/mds-server.h
index 19f3044..3bce7ed 100644
--- a/src/mds-server/mds-server.h
+++ b/src/mds-server/mds-server.h
@@ -27,10 +27,9 @@
/**
* Accept an incoming and start a slave thread for it
*
- * @param socket_fd The file descriptor of the server socket
- * @return Zero normally, 1 if terminating
+ * @return Zero normally, 1 if terminating
*/
-int accept_connection(int socket_fd);
+int accept_connection(void);
/**
* Master function for slave threads
diff --git a/src/mds-server/reexec.c b/src/mds-server/reexec.c
index 2b41112..6667a73 100644
--- a/src/mds-server/reexec.c
+++ b/src/mds-server/reexec.c
@@ -15,7 +15,6 @@
* 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 "reexec.h"
#include "globals.h"
#include "client.h"
@@ -41,51 +40,74 @@
#include <string.h>
+
/**
- * Marshal the server's state into a file
+ * 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.
*
- * @param fd The file descriptor
- * @return Negative on error
+ * @return The number of bytes that will be stored by `marshal_server`
*/
-int marshal_server(int fd)
+size_t marshal_server_size(void)
{
size_t list_size = linked_list_marshal_size(&client_list);
size_t map_size = fd_table_marshal_size(&client_map);
size_t list_elements = 0;
size_t state_n = 0;
- char* state_buf = NULL;
- char* state_buf_;
ssize_t node;
-
/* Calculate the grand size of all client information. */
- for (node = client_list.edge;; list_elements++)
+ foreach_linked_list_node (client_list, node)
{
- if ((node = client_list.next[node]) == client_list.edge)
- break;
state_n += client_marshal_size((client_t*)(void*)(client_list.values[node]));
+ list_elements++;
}
/* Add the size of the rest of the program's state. */
state_n += sizeof(int) + sizeof(sig_atomic_t) + 2 * sizeof(uint64_t) + 2 * sizeof(size_t);
state_n += list_elements * sizeof(size_t) + list_size + map_size;
- /* Allocate a buffer for all data. */
- state_buf = state_buf_ = malloc(state_n);
- fail_if (state_buf == NULL);
+ return state_n;
+}
+
+
+/**
+ * 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)
+{
+ size_t list_size = linked_list_marshal_size(&client_list);
+ size_t list_elements = 0;
+ ssize_t node;
+
+
+ /* Release resources. */
+ pthread_mutex_destroy(&slave_mutex);
+ pthread_cond_destroy(&slave_cond);
+ pthread_mutex_destroy(&modify_mutex);
+ pthread_cond_destroy(&modify_cond);
+ hash_table_destroy(&modify_map, NULL, NULL);
+
+ /* Count the number of clients that online. */
+ foreach_linked_list_node (client_list, node)
+ list_elements++;
/* Tell the new version of the program what version of the program it is marshalling. */
- buf_set_next(state_buf_, int, MDS_SERVER_VARS_VERSION);
+ buf_set_next(state_buf, int, MDS_SERVER_VARS_VERSION);
/* Marshal the miscellaneous state data. */
- buf_set_next(state_buf_, sig_atomic_t, running);
- buf_set_next(state_buf_, uint64_t, next_client_id);
- buf_set_next(state_buf_, uint64_t, next_modify_id);
+ buf_set_next(state_buf, sig_atomic_t, running);
+ buf_set_next(state_buf, uint64_t, next_client_id);
+ buf_set_next(state_buf, uint64_t, next_modify_id);
/* Tell the program how large the marshalled client list is and how any clients are marshalled. */
- buf_set_next(state_buf_, size_t, list_size);
- buf_set_next(state_buf_, size_t, list_elements);
+ buf_set_next(state_buf, size_t, list_size);
+ buf_set_next(state_buf, size_t, list_elements);
/* Marshal the clients. */
foreach_linked_list_node (client_list, node)
@@ -96,27 +118,28 @@ int marshal_server(int fd)
client_t* value = (client_t*)(void*)value_address;
/* Marshal the address, it is used the the client list and the client map, that will be marshalled. */
- buf_set_next(state_buf_, size_t, value_address);
+ buf_set_next(state_buf, size_t, value_address);
/* Marshal the client informationation. */
- state_buf_ += client_marshal(value, state_buf_) / sizeof(char);
+ state_buf += client_marshal(value, state_buf) / sizeof(char);
}
/* Marshal the client list. */
- linked_list_marshal(&client_list, state_buf_);
- state_buf_ += list_size / sizeof(char);
+ linked_list_marshal(&client_list, state_buf);
+ state_buf += list_size / sizeof(char);
/* Marshal the client map. */
- fd_table_marshal(&client_map, state_buf_);
+ fd_table_marshal(&client_map, state_buf);
- /* Send the marshalled data into the file. */
- fail_if (full_write(fd, state_buf, state_n) < 0);
- free(state_buf);
- return 0;
+ /* Release resources. */
+ foreach_linked_list_node (client_list, node)
+ {
+ client_t* client = (client_t*)(void*)(client_list.values[node]);
+ client_destroy(client);
+ }
+ fd_table_destroy(&client_map, NULL, NULL);
+ linked_list_destroy(&client_list);
- pfail:
- perror(*argv);
- free(state_buf);
- return -1;
+ return 0;
}
@@ -136,17 +159,16 @@ static size_t unmarshal_remapper(size_t old)
return hash_table_get(&unmarshal_remap_map, old);
}
+
/**
- * Unmarshal the server's state from a file
+ * Unmarshal server implementation specific data and update the servers state accordingly
*
- * @param fd The file descriptor
- * @return Negative on error
+ * @param state_buf The marshalled data that as not been read already
+ * @return Non-zero on error
*/
-int unmarshal_server(int fd)
+int unmarshal_server(char* state_buf)
{
int with_error = 0;
- char* state_buf;
- char* state_buf_;
size_t list_size;
size_t list_elements;
size_t i;
@@ -154,35 +176,27 @@ int unmarshal_server(int fd)
pthread_t slave_thread;
- /* Read the file. */
- if ((state_buf = state_buf_ = full_read(fd)) == NULL)
- {
- perror(*argv);
- return -1;
- }
-
/* Create memory address remapping table. */
if (hash_table_create(&unmarshal_remap_map))
{
perror(*argv);
- free(state_buf);
hash_table_destroy(&unmarshal_remap_map, NULL, NULL);
return -1;
}
/* Get the marshal protocal version. Not needed, there is only the one version right now. */
- /* buf_get(state_buf_, int, 0, MDS_SERVER_VARS_VERSION); */
- buf_next(state_buf_, int, 1);
+ /* buf_get(state_buf, int, 0, MDS_SERVER_VARS_VERSION); */
+ buf_next(state_buf, int, 1);
/* Unmarshal the miscellaneous state data. */
- buf_get_next(state_buf_, sig_atomic_t, running);
- buf_get_next(state_buf_, uint64_t, next_client_id);
- buf_get_next(state_buf_, uint64_t, next_modify_id);
+ buf_get_next(state_buf, sig_atomic_t, running);
+ buf_get_next(state_buf, uint64_t, next_client_id);
+ buf_get_next(state_buf, uint64_t, next_modify_id);
/* Get the marshalled size of the client list and how any clients that are marshalled. */
- buf_get_next(state_buf_, size_t, list_size);
- buf_get_next(state_buf_, size_t, list_elements);
+ buf_get_next(state_buf, size_t, list_size);
+ buf_get_next(state_buf, size_t, list_elements);
/* Unmarshal the clients. */
for (i = 0; i < list_elements; i++)
@@ -196,9 +210,9 @@ int unmarshal_server(int fd)
goto clients_fail;
/* Unmarshal the address, it is used the the client list and the client map, that are also marshalled. */
- buf_get_next(state_buf_, size_t, value_address);
+ buf_get_next(state_buf, size_t, value_address);
/* Unmarshal the client information. */
- n = client_unmarshal(value, state_buf_);
+ n = client_unmarshal(value, state_buf);
if (n == 0)
goto clients_fail;
@@ -208,7 +222,7 @@ int unmarshal_server(int fd)
goto clients_fail;
/* Delayed seeking. */
- state_buf_ += n / sizeof(char);
+ state_buf += n / sizeof(char);
/* On error, seek past all clients. */
@@ -218,29 +232,26 @@ int unmarshal_server(int fd)
with_error = 1;
if (value != NULL)
{
- buf_prev(state_buf_, size_t, 1);
+ buf_prev(state_buf, size_t, 1);
free(value);
}
for (; i < list_elements; i++)
/* There is not need to close the sockets, it is done by
the caller because there are conditions where we cannot
get here anyway. */
- state_buf_ += client_unmarshal_skip(state_buf_) / sizeof(char);
+ state_buf += client_unmarshal_skip(state_buf) / sizeof(char);
break;
}
/* Unmarshal the client list. */
- if (linked_list_unmarshal(&client_list, state_buf_))
+ if (linked_list_unmarshal(&client_list, state_buf))
goto critical_fail;
- state_buf_ += list_size / sizeof(char);
+ state_buf += list_size / sizeof(char);
/* Unmarshal the client map. */
- if (fd_table_unmarshal(&client_map, state_buf_, unmarshal_remapper))
+ if (fd_table_unmarshal(&client_map, state_buf, unmarshal_remapper))
goto critical_fail;
- /* Release the raw data. */
- free(state_buf);
-
/* Remove non-found elements from the fd table. */
#define __bit(I, _OP_) client_map.used[I / 64] _OP_ ((uint64_t)1 << (I % 64))
if (with_error)
@@ -262,116 +273,38 @@ int unmarshal_server(int fd)
{
/* Start the clients. (Errors do not need to be reported.) */
client_t* client = (client_t*)(void*)new_address;
- int socket_fd = client->socket_fd;
+ int slave_fd = client->socket_fd;
/* Increase number of running slaves. */
with_mutex (slave_mutex, running_slaves++;);
/* Start slave thread. */
- create_slave(&slave_thread, socket_fd);
+ create_slave(&slave_thread, slave_fd);
}
}
/* Release the remapping table's resources. */
hash_table_destroy(&unmarshal_remap_map, NULL, NULL);
- return -with_error;
-
- critical_fail:
- perror(*argv);
- abort();
-}
-
-
-/**
- * Marshal and re-execute the server
- *
- * @param reexec Whether the server was previously re-executed
- */
-void perform_reexec(int reexec)
-{
- pid_t pid = getpid();
- int reexec_fd;
- char shm_path[NAME_MAX + 1];
- ssize_t node;
-
- /* Join with all slaves threads. */
- with_mutex (slave_mutex,
- while (running_slaves > 0)
- pthread_cond_wait(&slave_cond, &slave_mutex););
+ return with_error;
- /* Release resources. */
- pthread_mutex_destroy(&slave_mutex);
- pthread_cond_destroy(&slave_cond);
- pthread_mutex_destroy(&modify_mutex);
- pthread_cond_destroy(&modify_cond);
- hash_table_destroy(&modify_map, NULL, NULL);
- /* Marshal the state of the server. */
- xsnprintf(shm_path, SHM_PATH_PATTERN, (unsigned long int)pid);
- reexec_fd = shm_open(shm_path, O_RDWR | O_CREAT | O_EXCL, S_IRWXU);
- if (reexec_fd < 0)
- {
- perror(*argv);
- return;
- }
- fail_if (marshal_server(reexec_fd) < 0);
- close(reexec_fd);
- reexec_fd = -1;
-
- /* Release resources. */
- foreach_linked_list_node (client_list, node)
- {
- client_t* client = (client_t*)(void*)(client_list.values[node]);
- client_destroy(client);
- }
- fd_table_destroy(&client_map, NULL, NULL);
- linked_list_destroy(&client_list);
-
- /* Re-exec the server. */
- reexec_server(argc, argv, reexec);
-
- pfail:
+ critical_fail:
perror(*argv);
- if (reexec_fd >= 0)
- close(reexec_fd);
- shm_unlink(shm_path);
+ abort();
}
/**
- * Attempt to reload the server after a re-execution
+ * Attempt to recover from an re-exec failure that has been
+ * detected after the server successfully updated it execution image
*
- * @param socket_fd The file descriptor of the server socket
+ * @return Non-zero on error
*/
-void complete_reexec(int socket_fd)
+int reexec_failure_recover(void)
{
- pid_t pid = getpid();
- int reexec_fd, r;
- char shm_path[NAME_MAX + 1];
-
- /* Acquire access to marshalled data. */
- xsnprintf(shm_path, SHM_PATH_PATTERN, (unsigned long int)pid);
- reexec_fd = shm_open(shm_path, O_RDONLY, S_IRWXU);
- fail_if (reexec_fd < 0); /* Critical. */
-
- /* Unmarshal state. */
- r = unmarshal_server(reexec_fd);
-
- /* Close and unlink marshalled data. */
- close(reexec_fd);
- shm_unlink(shm_path);
-
- /* Recover after failure. */
- if (r < 0)
- {
- /* Close all files (hopefully sockets) we do not know what they are. */
- close_files((fd > 2) && (fd != socket_fd) && (fd_table_contains_key(&client_map, fd) == 0));
- }
-
- return;
- pfail:
- perror(*argv);
- abort();
+ /* Close all files (hopefully sockets) we do not know what they are. */
+ close_files((fd > 2) && (fd != socket_fd) && (fd_table_contains_key(&client_map, fd) == 0));
+ return 0;
}
diff --git a/src/mds-server/reexec.h b/src/mds-server/reexec.h
deleted file mode 100644
index 266fdfd..0000000
--- a/src/mds-server/reexec.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/**
- * mds — A micro-display server
- * Copyright © 2014 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/>.
- */
-#ifndef MDS_MDS_SERVER_REEXEC_H
-#define MDS_MDS_SERVER_REEXEC_H
-
-
-/**
- * Marshal the server's state into a file
- *
- * @param fd The file descriptor
- * @return Negative on error
- */
-int marshal_server(int fd);
-
-/**
- * Unmarshal the server's state from a file
- *
- * @param fd The file descriptor
- * @return Negative on error
- */
-int unmarshal_server(int fd);
-
-/**
- * Marshal and re-execute the server
- *
- * @param reexec Whether the server was previously re-executed
- */
-void perform_reexec(int reexec);
-
-/**
- * Attempt to reload the server after a re-execution
- *
- * @param socket_fd The file descriptor of the server socket
- */
-void complete_reexec(int socket_fd);
-
-
-#endif
-
diff --git a/src/mds-server/sending.c b/src/mds-server/sending.c
index 8c40cc4..ec29a81 100644
--- a/src/mds-server/sending.c
+++ b/src/mds-server/sending.c
@@ -38,13 +38,13 @@
/**
* Get the client by its socket's file descriptor in a synchronised manner
*
- * @param socket_fd The file descriptor of the client's socket
+ * @param client_fd The file descriptor of the client's socket
* @return The client
*/
-static client_t* client_by_socket(int socket_fd)
+static client_t* client_by_socket(int client_fd)
{
size_t address;
- with_mutex (slave_mutex, address = fd_table_get(&client_map, socket_fd););
+ with_mutex (slave_mutex, address = fd_table_get(&client_map, client_fd););
return (client_t*)(void*)address;
}
diff --git a/src/mds-server/signals.c b/src/mds-server/signals.c
index b16b28a..325fa35 100644
--- a/src/mds-server/signals.c
+++ b/src/mds-server/signals.c
@@ -15,20 +15,16 @@
* 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 "signals.h"
#include "globals.h"
#include "client.h"
#include <libmdsserver/linked-list.h>
#include <libmdsserver/macros.h>
-#include <libmdsserver/util.h>
#include <stdio.h>
-#include <errno.h>
-#include <stdlib.h>
#include <pthread.h>
-#include <signal.h>
+#include <errno.h>
/**
@@ -58,12 +54,14 @@ static void signal_all(int signo)
/**
- * Called with the signal SIGUSR1 is caught.
- * This function should cue a re-exec of the program.
+ * This function is called when a signal that
+ * signals the server to re-exec has been received
*
- * @param signo The caught signal
+ * When this function is invoked, it should set `reexecing` to a non-zero value
+ *
+ * @param signo The signal that has been received
*/
-static void sigusr1_trap(int signo)
+void received_reexec(int signo)
{
if (reexecing == 0)
{
@@ -75,57 +73,20 @@ static void sigusr1_trap(int signo)
/**
- * Called with the signal SIGTERM is caught.
- * This function should cue a termination of the program.
+ * This function is called when a signal that
+ * signals the server to re-exec has been received
*
- * @param signo The caught signal
- */
-static void sigterm_trap(int signo)
-{
- if (terminating == 0)
- {
- terminating = 1;
- eprint("terminate signal received.");
- signal_all(signo);
- }
-}
-
-
-/**
- * Called with the signal SIGINT is caught.
- * This function should cue a termination of the program.
+ * When this function is invoked, it should set `terminating` to a non-zero value
*
- * @param signo The caught signal
+ * @param signo The signal that has been received
*/
-static void sigint_trap(int signo)
+void received_terminate(int signo)
{
if (terminating == 0)
{
terminating = 1;
- eprint("terminal interrupt signal received.");
+ eprint("terminate signal received.");
signal_all(signo);
}
}
-
-/**
- * Set up signal traps for all especially handled signals
- *
- * @return Zero on success, -1 on error
- */
-int trap_signals(void)
-{
- /* Make the server update without all slaves dying on SIGUSR1. */
- fail_if (xsigaction(SIGUSR1, sigusr1_trap) < 0);
-
- /* Implement clean exit on SIGTERM. */
- fail_if (xsigaction(SIGTERM, sigterm_trap) < 0);
-
- /* Implement clean exit on SIGINT. */
- fail_if (xsigaction(SIGINT, sigint_trap) < 0);
-
- return 0;
- pfail:
- return -1;
-}
-
diff --git a/src/mds-server/signals.h b/src/mds-server/signals.h
deleted file mode 100644
index b4a49ed..0000000
--- a/src/mds-server/signals.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/**
- * mds — A micro-display server
- * Copyright © 2014 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/>.
- */
-#ifndef MDS_MDS_SERVER_SIGNALS_H
-#define MDS_MDS_SERVER_SIGNALS_H
-
-
-/**
- * Set up signal traps for all especially handled signals
- *
- * @return Zero on success, -1 on error
- */
-int trap_signals(void);
-
-
-#endif
-
diff --git a/src/mds-server/slavery.c b/src/mds-server/slavery.c
index 627bde0..4b92154 100644
--- a/src/mds-server/slavery.c
+++ b/src/mds-server/slavery.c
@@ -71,13 +71,13 @@ int fetch_message(client_t* client)
/**
* Create, start and detache a slave thread
*
- * @param thread The address at where to store the thread
- * @param socket_fd The file descriptor of the slave's socket
- * @return Zero on success, -1 on error, error message will have been printed
+ * @param thread The address at where to store the thread
+ * @param slave_fd The file descriptor of the slave's socket
+ * @return Zero on success, -1 on error, error message will have been printed
*/
-int create_slave(pthread_t* thread_slot, int socket_fd)
+int create_slave(pthread_t* thread_slot, int slave_fd)
{
- if ((errno = pthread_create(thread_slot, NULL, slave_loop, (void*)(intptr_t)socket_fd)))
+ if ((errno = pthread_create(thread_slot, NULL, slave_loop, (void*)(intptr_t)slave_fd)))
{
perror(*argv);
with_mutex (slave_mutex, running_slaves--;);
@@ -95,10 +95,10 @@ int create_slave(pthread_t* thread_slot, int socket_fd)
/**
* Initialise a client, except for threading
*
- * @param socket_fd The file descriptor of the client's socket
+ * @param client_fd The file descriptor of the client's socket
* @return The client information, NULL on error
*/
-client_t* initialise_client(int socket_fd)
+client_t* initialise_client(int client_fd)
{
ssize_t entry = LINKED_LIST_UNUSED;
int locked = 0;
@@ -117,14 +117,14 @@ client_t* initialise_client(int socket_fd)
fail_if (entry == LINKED_LIST_UNUSED);
/* Add client to table. */
- tmp = fd_table_put(&client_map, socket_fd, (size_t)(void*)information);
+ tmp = fd_table_put(&client_map, client_fd, (size_t)(void*)information);
fail_if ((tmp == 0) && errno);
pthread_mutex_unlock(&slave_mutex);
locked = 0;
/* Fill information table. */
information->list_entry = entry;
- information->socket_fd = socket_fd;
+ information->socket_fd = client_fd;
information->open = 1;
fail_if (mds_message_initialise(&(information->message)));
diff --git a/src/mds-server/slavery.h b/src/mds-server/slavery.h
index 0b94e7d..92144fd 100644
--- a/src/mds-server/slavery.h
+++ b/src/mds-server/slavery.h
@@ -35,19 +35,19 @@ int fetch_message(client_t* client);
/**
* Create, start and detache a slave thread
*
- * @param thread The address at where to store the thread
- * @param socket_fd The file descriptor of the slave's socket
- * @return Zero on success, -1 on error, error message will have been printed
+ * @param thread The address at where to store the thread
+ * @param slave_fd The file descriptor of the slave's socket
+ * @return Zero on success, -1 on error, error message will have been printed
*/
-int create_slave(pthread_t* thread_slot, int socket_fd);
+int create_slave(pthread_t* thread_slot, int slave_fd);
/**
* Initialise a client, except for threading
*
- * @param socket_fd The file descriptor of the client's socket
+ * @param client_fd The file descriptor of the client's socket
* @return The client information, NULL on error
*/
-client_t* initialise_client(int socket_fd);
+client_t* initialise_client(int client_fd);
#endif